aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorRoman Divacky <rdivacky@FreeBSD.org>2010-05-27 15:17:06 +0000
committerRoman Divacky <rdivacky@FreeBSD.org>2010-05-27 15:17:06 +0000
commitd7279c4c177bca357ef96ff1379fd9bc420bfe83 (patch)
tree3558f327a6f9ab59c5d7a06528d84e1560445247
parentbe17651f5cd2e94922c1b732bc8589e180698193 (diff)
downloadsrc-d7279c4c177bca357ef96ff1379fd9bc420bfe83.tar.gz
src-d7279c4c177bca357ef96ff1379fd9bc420bfe83.zip
Update clang to r104832.vendor/clang/clang-r104832
Notes
Notes: svn path=/vendor/clang/dist/; revision=208600 svn path=/vendor/clang/clang-r104832/; revision=208977; tag=vendor/clang/clang-r104832
-rw-r--r--clang.xcodeproj/project.pbxproj74
-rw-r--r--docs/InternalsManual.html12
-rw-r--r--docs/UsersManual.html48
-rw-r--r--docs/tools/clang.pod25
-rw-r--r--include/clang-c/Index.h169
-rw-r--r--include/clang/AST/ASTConsumer.h12
-rw-r--r--include/clang/AST/ASTContext.h56
-rw-r--r--include/clang/AST/Attr.h39
-rw-r--r--include/clang/AST/CMakeLists.txt5
-rw-r--r--include/clang/AST/CXXInheritance.h2
-rw-r--r--include/clang/AST/CanonicalType.h18
-rw-r--r--include/clang/AST/Decl.h142
-rw-r--r--include/clang/AST/DeclBase.h5
-rw-r--r--include/clang/AST/DeclCXX.h236
-rw-r--r--include/clang/AST/DeclContextInternals.h3
-rw-r--r--include/clang/AST/DeclObjC.h24
-rw-r--r--include/clang/AST/DeclTemplate.h51
-rw-r--r--include/clang/AST/DeclarationName.h5
-rw-r--r--include/clang/AST/Expr.h51
-rw-r--r--include/clang/AST/ExprCXX.h179
-rw-r--r--include/clang/AST/Makefile13
-rw-r--r--include/clang/AST/RecordLayout.h15
-rw-r--r--include/clang/AST/RecursiveASTVisitor.h768
-rw-r--r--include/clang/AST/Stmt.h32
-rw-r--r--include/clang/AST/StmtNodes.td127
-rw-r--r--include/clang/AST/StmtVisitor.h6
-rw-r--r--include/clang/AST/TemplateBase.h6
-rw-r--r--include/clang/AST/TemplateName.h2
-rw-r--r--include/clang/AST/Type.h689
-rw-r--r--include/clang/AST/TypeLoc.h312
-rw-r--r--include/clang/AST/TypeLocBuilder.h14
-rw-r--r--include/clang/AST/TypeNodes.def4
-rw-r--r--include/clang/AST/TypeVisitor.h4
-rw-r--r--include/clang/AST/UnresolvedSet.h8
-rw-r--r--include/clang/Analysis/ProgramPoint.h2
-rw-r--r--include/clang/Basic/Diagnostic.h8
-rw-r--r--include/clang/Basic/Diagnostic.td5
-rw-r--r--include/clang/Basic/DiagnosticASTKinds.td23
-rw-r--r--include/clang/Basic/DiagnosticCategories.td10
-rw-r--r--include/clang/Basic/DiagnosticDriverKinds.td2
-rw-r--r--include/clang/Basic/DiagnosticFrontendKinds.td3
-rw-r--r--include/clang/Basic/DiagnosticGroups.td13
-rw-r--r--include/clang/Basic/DiagnosticLexKinds.td6
-rw-r--r--include/clang/Basic/DiagnosticParseKinds.td22
-rw-r--r--include/clang/Basic/DiagnosticSemaKinds.td193
-rw-r--r--include/clang/Basic/SourceManager.h55
-rw-r--r--include/clang/Basic/TargetInfo.h8
-rw-r--r--include/clang/Basic/TokenKinds.def4
-rw-r--r--include/clang/CMakeLists.txt1
-rw-r--r--include/clang/Checker/PathSensitive/AnalysisManager.h17
-rw-r--r--include/clang/Checker/PathSensitive/GRExprEngine.h2
-rw-r--r--include/clang/Checker/PathSensitive/Store.h14
-rw-r--r--include/clang/CodeGen/CodeGenOptions.h2
-rw-r--r--include/clang/Driver/ArgList.h22
-rw-r--r--include/clang/Driver/CC1AsOptions.h32
-rw-r--r--include/clang/Driver/CC1AsOptions.td71
-rw-r--r--include/clang/Driver/CC1Options.td17
-rw-r--r--include/clang/Driver/CMakeLists.txt6
-rw-r--r--include/clang/Driver/Makefile6
-rw-r--r--include/clang/Driver/Options.td16
-rw-r--r--include/clang/Driver/Tool.h8
-rw-r--r--include/clang/Frontend/AnalysisConsumer.h3
-rw-r--r--include/clang/Frontend/CodeGenAction.h5
-rw-r--r--include/clang/Frontend/CompilerInstance.h2
-rw-r--r--include/clang/Frontend/DeclXML.def112
-rw-r--r--include/clang/Frontend/DiagnosticOptions.h7
-rw-r--r--include/clang/Frontend/DocumentXML.h16
-rw-r--r--include/clang/Frontend/FrontendActions.h10
-rw-r--r--include/clang/Frontend/FrontendOptions.h7
-rw-r--r--include/clang/Frontend/PCHBitCodes.h62
-rw-r--r--include/clang/Frontend/PCHReader.h22
-rw-r--r--include/clang/Frontend/PCHWriter.h18
-rw-r--r--include/clang/Frontend/TypeXML.def47
-rw-r--r--include/clang/Lex/LiteralSupport.h4
-rw-r--r--include/clang/Lex/Preprocessor.h12
-rw-r--r--include/clang/Makefile4
-rw-r--r--include/clang/Parse/Action.h74
-rw-r--r--include/clang/Parse/AttributeList.h2
-rw-r--r--include/clang/Parse/Ownership.h17
-rw-r--r--include/clang/Parse/Parser.h35
-rw-r--r--include/clang/Parse/Scope.h2
-rw-r--r--include/clang/Sema/CodeCompleteConsumer.h98
-rw-r--r--lib/AST/ASTContext.cpp550
-rw-r--r--lib/AST/ASTDiagnostic.cpp139
-rw-r--r--lib/AST/ASTImporter.cpp123
-rw-r--r--lib/AST/AttrImpl.cpp10
-rw-r--r--lib/AST/CMakeLists.txt2
-rw-r--r--lib/AST/CXXInheritance.cpp5
-rw-r--r--lib/AST/Decl.cpp62
-rw-r--r--lib/AST/DeclBase.cpp4
-rw-r--r--lib/AST/DeclCXX.cpp67
-rw-r--r--lib/AST/DeclTemplate.cpp111
-rw-r--r--lib/AST/DeclarationName.cpp44
-rw-r--r--lib/AST/Expr.cpp419
-rw-r--r--lib/AST/ExprCXX.cpp101
-rw-r--r--lib/AST/ExprConstant.cpp1167
-rw-r--r--lib/AST/NestedNameSpecifier.cpp6
-rw-r--r--lib/AST/RecordLayout.cpp7
-rw-r--r--lib/AST/RecordLayoutBuilder.cpp907
-rw-r--r--lib/AST/RecordLayoutBuilder.h170
-rw-r--r--lib/AST/Stmt.cpp10
-rw-r--r--lib/AST/StmtDumper.cpp2
-rw-r--r--lib/AST/StmtPrinter.cpp2
-rw-r--r--lib/AST/StmtProfile.cpp210
-rw-r--r--lib/AST/TemplateBase.cpp42
-rw-r--r--lib/AST/Type.cpp259
-rw-r--r--lib/AST/TypeLoc.cpp59
-rw-r--r--lib/AST/TypePrinter.cpp76
-rw-r--r--lib/Analysis/CFG.cpp18
-rw-r--r--lib/Analysis/CMakeLists.txt2
-rw-r--r--lib/Basic/Diagnostic.cpp37
-rw-r--r--lib/Basic/IdentifierTable.cpp4
-rw-r--r--lib/Basic/SourceManager.cpp131
-rw-r--r--lib/Basic/TargetInfo.cpp1
-rw-r--r--lib/Basic/Targets.cpp5
-rw-r--r--lib/Basic/Version.cpp3
-rw-r--r--lib/Checker/BasicObjCFoundationChecks.cpp4
-rw-r--r--lib/Checker/BasicStore.cpp8
-rw-r--r--lib/Checker/CFRefCount.cpp83
-rw-r--r--lib/Checker/CMakeLists.txt3
-rw-r--r--lib/Checker/CastSizeChecker.cpp82
-rw-r--r--lib/Checker/CheckObjCDealloc.cpp3
-rw-r--r--lib/Checker/FlatStore.cpp4
-rw-r--r--lib/Checker/GRCXXExprEngine.cpp4
-rw-r--r--lib/Checker/GRExprEngine.cpp35
-rw-r--r--lib/Checker/GRExprEngineExperimentalChecks.cpp1
-rw-r--r--lib/Checker/GRExprEngineInternalChecks.h1
-rw-r--r--lib/Checker/GRState.cpp7
-rw-r--r--lib/Checker/LLVMConventionsChecker.cpp2
-rw-r--r--lib/Checker/MallocChecker.cpp5
-rw-r--r--lib/Checker/MemRegion.cpp2
-rw-r--r--lib/Checker/ObjCUnusedIVarsChecker.cpp3
-rw-r--r--lib/Checker/RegionStore.cpp41
-rw-r--r--lib/CodeGen/CGBlocks.cpp483
-rw-r--r--lib/CodeGen/CGBlocks.h46
-rw-r--r--lib/CodeGen/CGBuiltin.cpp70
-rw-r--r--lib/CodeGen/CGCXX.cpp9
-rw-r--r--lib/CodeGen/CGCXXABI.h37
-rw-r--r--lib/CodeGen/CGCall.cpp34
-rw-r--r--lib/CodeGen/CGClass.cpp394
-rw-r--r--lib/CodeGen/CGDebugInfo.cpp246
-rw-r--r--lib/CodeGen/CGDebugInfo.h8
-rw-r--r--lib/CodeGen/CGDecl.cpp108
-rw-r--r--lib/CodeGen/CGDeclCXX.cpp153
-rw-r--r--lib/CodeGen/CGException.cpp74
-rw-r--r--lib/CodeGen/CGExpr.cpp180
-rw-r--r--lib/CodeGen/CGExprAgg.cpp123
-rw-r--r--lib/CodeGen/CGExprCXX.cpp55
-rw-r--r--lib/CodeGen/CGExprConstant.cpp143
-rw-r--r--lib/CodeGen/CGExprScalar.cpp29
-rw-r--r--lib/CodeGen/CGObjC.cpp92
-rw-r--r--lib/CodeGen/CGObjCGNU.cpp67
-rw-r--r--lib/CodeGen/CGObjCMac.cpp58
-rw-r--r--lib/CodeGen/CGObjCRuntime.h2
-rw-r--r--lib/CodeGen/CGRecordLayout.h9
-rw-r--r--lib/CodeGen/CGRecordLayoutBuilder.cpp122
-rw-r--r--lib/CodeGen/CGStmt.cpp31
-rw-r--r--lib/CodeGen/CGVTT.cpp2
-rw-r--r--lib/CodeGen/CGVTables.cpp74
-rw-r--r--lib/CodeGen/CGVTables.h10
-rw-r--r--lib/CodeGen/CMakeLists.txt3
-rw-r--r--lib/CodeGen/CodeGenFunction.cpp22
-rw-r--r--lib/CodeGen/CodeGenFunction.h61
-rw-r--r--lib/CodeGen/CodeGenModule.cpp57
-rw-r--r--lib/CodeGen/CodeGenModule.h27
-rw-r--r--lib/CodeGen/CodeGenTypes.cpp32
-rw-r--r--lib/CodeGen/CodeGenTypes.h8
-rw-r--r--lib/CodeGen/ItaniumCXXABI.cpp39
-rw-r--r--lib/CodeGen/Mangle.cpp113
-rw-r--r--lib/CodeGen/Mangle.h76
-rw-r--r--lib/CodeGen/ModuleBuilder.cpp7
-rw-r--r--lib/CodeGen/TargetInfo.cpp189
-rw-r--r--lib/Driver/ArgList.cpp28
-rw-r--r--lib/Driver/CC1AsOptions.cpp39
-rw-r--r--lib/Driver/CC1Options.cpp2
-rw-r--r--lib/Driver/CMakeLists.txt4
-rw-r--r--lib/Driver/Driver.cpp65
-rw-r--r--lib/Driver/Tool.cpp6
-rw-r--r--lib/Driver/ToolChains.cpp20
-rw-r--r--lib/Driver/ToolChains.h29
-rw-r--r--lib/Driver/Tools.cpp143
-rw-r--r--lib/Driver/Tools.h123
-rw-r--r--lib/Frontend/AnalysisConsumer.cpp4
-rw-r--r--lib/Frontend/BoostConAction.cpp39
-rw-r--r--lib/Frontend/CMakeLists.txt4
-rw-r--r--lib/Frontend/CodeGenAction.cpp15
-rw-r--r--lib/Frontend/CompilerInstance.cpp6
-rw-r--r--lib/Frontend/CompilerInvocation.cpp144
-rw-r--r--lib/Frontend/DeclXML.cpp48
-rw-r--r--lib/Frontend/DocumentXML.cpp29
-rw-r--r--lib/Frontend/InitHeaderSearch.cpp200
-rw-r--r--lib/Frontend/InitPreprocessor.cpp5
-rw-r--r--lib/Frontend/PCHReader.cpp93
-rw-r--r--lib/Frontend/PCHReaderDecl.cpp303
-rw-r--r--lib/Frontend/PCHReaderStmt.cpp140
-rw-r--r--lib/Frontend/PCHWriter.cpp110
-rw-r--r--lib/Frontend/PCHWriterDecl.cpp217
-rw-r--r--lib/Frontend/PCHWriterStmt.cpp120
-rw-r--r--lib/Frontend/PrintParserCallbacks.cpp6
-rw-r--r--lib/Frontend/RewriteObjC.cpp127
-rw-r--r--lib/Frontend/TextDiagnosticPrinter.cpp40
-rw-r--r--lib/Headers/emmintrin.h5
-rw-r--r--lib/Headers/xmmintrin.h3
-rw-r--r--lib/Index/ASTLocation.cpp2
-rw-r--r--lib/Index/Analyzer.cpp8
-rw-r--r--lib/Index/ResolveLocation.cpp29
-rw-r--r--lib/Lex/Lexer.cpp11
-rw-r--r--lib/Lex/LiteralSupport.cpp55
-rw-r--r--lib/Parse/AttributeList.cpp6
-rw-r--r--lib/Parse/MinimalAction.cpp4
-rw-r--r--lib/Parse/ParseDecl.cpp70
-rw-r--r--lib/Parse/ParseDeclCXX.cpp21
-rw-r--r--lib/Parse/ParseExpr.cpp33
-rw-r--r--lib/Parse/ParseExprCXX.cpp140
-rw-r--r--lib/Parse/ParseObjc.cpp58
-rw-r--r--lib/Parse/ParsePragma.cpp53
-rw-r--r--lib/Parse/ParsePragma.h9
-rw-r--r--lib/Parse/ParseStmt.cpp94
-rw-r--r--lib/Parse/ParseTemplate.cpp37
-rw-r--r--lib/Parse/ParseTentative.cpp1
-rw-r--r--lib/Parse/Parser.cpp38
-rw-r--r--lib/Sema/AnalysisBasedWarnings.cpp29
-rw-r--r--lib/Sema/CMakeLists.txt2
-rw-r--r--lib/Sema/CodeCompleteConsumer.cpp67
-rw-r--r--lib/Sema/JumpDiagnostics.cpp378
-rw-r--r--lib/Sema/Sema.cpp43
-rw-r--r--lib/Sema/Sema.h146
-rw-r--r--lib/Sema/SemaAttr.cpp98
-rw-r--r--lib/Sema/SemaCXXCast.cpp25
-rw-r--r--lib/Sema/SemaChecking.cpp406
-rw-r--r--lib/Sema/SemaCodeComplete.cpp555
-rw-r--r--lib/Sema/SemaDecl.cpp263
-rw-r--r--lib/Sema/SemaDeclAttr.cpp68
-rw-r--r--lib/Sema/SemaDeclCXX.cpp605
-rw-r--r--lib/Sema/SemaDeclObjC.cpp52
-rw-r--r--lib/Sema/SemaExceptionSpec.cpp2
-rw-r--r--lib/Sema/SemaExpr.cpp258
-rw-r--r--lib/Sema/SemaExprCXX.cpp153
-rw-r--r--lib/Sema/SemaExprObjC.cpp59
-rw-r--r--lib/Sema/SemaInit.cpp87
-rw-r--r--lib/Sema/SemaInit.h44
-rw-r--r--lib/Sema/SemaLookup.cpp97
-rw-r--r--lib/Sema/SemaObjCProperty.cpp184
-rw-r--r--lib/Sema/SemaOverload.cpp588
-rw-r--r--lib/Sema/SemaOverload.h45
-rw-r--r--lib/Sema/SemaStmt.cpp397
-rw-r--r--lib/Sema/SemaTemplate.cpp286
-rw-r--r--lib/Sema/SemaTemplateDeduction.cpp33
-rw-r--r--lib/Sema/SemaTemplateInstantiate.cpp85
-rw-r--r--lib/Sema/SemaTemplateInstantiateDecl.cpp87
-rw-r--r--lib/Sema/SemaType.cpp242
-rw-r--r--lib/Sema/TreeTransform.h328
-rw-r--r--test/Analysis/dead-stores.c12
-rw-r--r--test/Analysis/inline.c4
-rw-r--r--test/Analysis/inline2.c3
-rw-r--r--test/Analysis/inline3.c3
-rw-r--r--test/Analysis/inline4.c4
-rw-r--r--test/Analysis/malloc.c24
-rw-r--r--test/Analysis/method-call.cpp2
-rw-r--r--test/Analysis/misc-ps-region-store.m19
-rw-r--r--test/Analysis/misc-ps.m14
-rw-r--r--test/Analysis/retain-release.m12
-rw-r--r--test/CXX/class.access/class.friend/p1.cpp2
-rw-r--r--test/CXX/class.access/p4.cpp20
-rw-r--r--test/CXX/dcl.dcl/basic.namespace/namespace.udecl/p8.cpp15
-rw-r--r--test/CXX/expr/expr.post/expr.ref/p3.cpp15
-rw-r--r--test/CXX/temp/temp.decls/temp.friend/p4.cpp10
-rw-r--r--test/CXX/temp/temp.fct.spec/temp.deduct/temp.deduct.call/basic.cpp3
-rw-r--r--test/CXX/temp/temp.fct.spec/temp.deduct/temp.deduct.call/p6.cpp2
-rw-r--r--test/CXX/temp/temp.fct.spec/temp.deduct/temp.deduct.type/p17.cpp6
-rw-r--r--test/CXX/temp/temp.names/p2.cpp13
-rw-r--r--test/CXX/temp/temp.spec/temp.explicit/p2.cpp4
-rw-r--r--test/CXX/temp/temp.spec/temp.explicit/p5.cpp2
-rw-r--r--test/CodeCompletion/call.c2
-rw-r--r--test/CodeCompletion/call.cpp2
-rw-r--r--test/CodeCompletion/ordinary-name.cpp8
-rw-r--r--test/CodeCompletion/truncation.c7
-rw-r--r--test/CodeGen/blocks.c2
-rw-r--r--test/CodeGen/builtins.c32
-rw-r--r--test/CodeGen/complex.c4
-rw-r--r--test/CodeGen/microsoft-call-conv.c50
-rw-r--r--test/CodeGen/stdcall-fastcall.c37
-rw-r--r--test/CodeGenCXX/PR5863-unreachable-block.cpp13
-rw-r--r--test/CodeGenCXX/PR6747.cpp11
-rw-r--r--test/CodeGenCXX/anonymous-namespaces.cpp10
-rw-r--r--test/CodeGenCXX/anonymous-union-member-initializer.cpp44
-rw-r--r--test/CodeGenCXX/array-value-initialize.cpp30
-rw-r--r--test/CodeGenCXX/c99-variable-length-array.cpp27
-rw-r--r--test/CodeGenCXX/class-layout.cpp4
-rw-r--r--test/CodeGenCXX/condition.cpp166
-rw-r--r--test/CodeGenCXX/cxx-apple-kext.cpp2
-rw-r--r--test/CodeGenCXX/destructors.cpp65
-rw-r--r--test/CodeGenCXX/dynamic-cast.cpp15
-rw-r--r--test/CodeGenCXX/dyncast.cpp2
-rw-r--r--test/CodeGenCXX/implicit-copy-constructor.cpp72
-rw-r--r--test/CodeGenCXX/key-function-vtable.cpp11
-rw-r--r--test/CodeGenCXX/mangle-subst-std.cpp44
-rw-r--r--test/CodeGenCXX/nrvo.cpp84
-rw-r--r--test/CodeGenCXX/pointers-to-data-members.cpp68
-rw-r--r--test/CodeGenCXX/references.cpp72
-rw-r--r--test/CodeGenCXX/rtti-linkage.cpp69
-rw-r--r--test/CodeGenCXX/static-init-3.cpp28
-rw-r--r--test/CodeGenCXX/static-init.cpp19
-rw-r--r--test/CodeGenCXX/static-local-in-local-class.cpp12
-rw-r--r--test/CodeGenCXX/template-linkage.cpp20
-rw-r--r--test/CodeGenCXX/threadsafe-statics-exceptions.cpp26
-rw-r--r--test/CodeGenCXX/thunks.cpp112
-rw-r--r--test/CodeGenCXX/virtual-base-destructor-call.cpp1
-rw-r--r--test/CodeGenCXX/virtual-functions-incomplete-types.cpp2
-rw-r--r--test/CodeGenCXX/vtable-layout.cpp1672
-rw-r--r--test/CodeGenCXX/vtable-linkage.cpp94
-rw-r--r--test/CodeGenCXX/x86_32-arguments.cpp96
-rw-r--r--test/CodeGenCXX/x86_64-arguments.cpp8
-rw-r--r--test/CodeGenObjC/atomic-aggregate-property.m1
-rw-r--r--test/CodeGenObjC/blocks-1.m10
-rw-r--r--test/CodeGenObjC/blocks-2.m2
-rw-r--r--test/CodeGenObjC/blocks-ivar-debug.m20
-rw-r--r--test/CodeGenObjC/blocks.m8
-rw-r--r--test/CodeGenObjC/default-property-synthesis.m38
-rw-r--r--test/CodeGenObjC/ivar-layout-64-bitfields.m1
-rw-r--r--test/CodeGenObjC/ivar-layout-64.m6
-rw-r--r--test/CodeGenObjC/ivar-layout-no-optimize.m2
-rw-r--r--test/CodeGenObjC/objc-gc-aggr-assign.m62
-rw-r--r--test/CodeGenObjC/objc2-new-gc-api-strongcast.m4
-rw-r--r--test/CodeGenObjC/objc2-no-write-barrier.m2
-rw-r--r--test/CodeGenObjC/objc2-retain-codegen.m1
-rw-r--r--test/CodeGenObjC/objc2-strong-cast-1.m1
-rw-r--r--test/CodeGenObjC/objc2-strong-cast.m1
-rw-r--r--test/CodeGenObjC/objc2-weak-assign.m2
-rw-r--r--test/CodeGenObjC/objc2-weak-compare.m2
-rw-r--r--test/CodeGenObjC/objc2-weak-ivar-debug.m2
-rw-r--r--test/CodeGenObjC/objc2-weak-ivar.m1
-rw-r--r--test/CodeGenObjC/objc2-write-barrier-2.m4
-rw-r--r--test/CodeGenObjC/objc2-write-barrier-3.m3
-rw-r--r--test/CodeGenObjC/objc2-write-barrier-4.m3
-rw-r--r--test/CodeGenObjC/objc2-write-barrier-5.m3
-rw-r--r--test/CodeGenObjC/objc2-write-barrier.m7
-rw-r--r--test/CodeGenObjC/property-complex.m4
-rw-r--r--test/CodeGenObjC/protocols.m9
-rw-r--r--test/CodeGenObjCXX/encode.mm52
-rw-r--r--test/CodeGenObjCXX/mangle-blocks.mm50
-rw-r--r--test/CodeGenObjCXX/property-objects.mm51
-rw-r--r--test/Coverage/ast-printing.cpp2
-rw-r--r--test/Driver/bindings.c2
-rw-r--r--test/Driver/clang_f_opts.c6
-rw-r--r--test/FixIt/typo.m50
-rw-r--r--test/Index/annotate-tokens-include.c6
-rw-r--r--test/Index/annotate-tokens-include.h1
-rw-r--r--test/Index/annotate-tokens.c78
-rw-r--r--test/Index/annotate-tokens.m272
-rw-r--r--test/Index/c-index-api-loadTU-test.m38
-rw-r--r--test/Index/complete-at-directives.m14
-rw-r--r--test/Index/complete-at-exprstmt.m6
-rw-r--r--test/Index/complete-exprs.c15
-rw-r--r--test/Index/complete-member-access.m4
-rw-r--r--test/Index/complete-recovery.m21
-rw-r--r--test/Index/load-stmts.cpp30
-rw-r--r--test/Index/print-typekind.c20
-rw-r--r--test/Index/properties-class-extensions.m28
-rw-r--r--test/Index/remap-load.c4
-rw-r--r--test/Index/usrs.cpp107
-rw-r--r--test/Index/usrs.m28
-rw-r--r--test/Lexer/gnu_keywords.c8
-rw-r--r--test/Lexer/hexfloat.cpp4
-rw-r--r--test/Makefile2
-rw-r--r--test/Misc/diag-aka-types.cpp10
-rw-r--r--test/PCH/Inputs/namespaces.h27
-rw-r--r--test/PCH/cxx_exprs.cpp4
-rw-r--r--test/PCH/cxx_exprs.h58
-rw-r--r--test/PCH/namespaces.cpp29
-rw-r--r--test/Parser/cxx-undeclared-identifier.cpp6
-rw-r--r--test/Parser/namespaces.cpp8
-rw-r--r--test/Parser/pragma-options.c12
-rw-r--r--test/Parser/recovery.c5
-rw-r--r--test/Parser/switch-recovery.cpp12
-rw-r--r--test/Rewriter/rewrite-block-argument.m33
-rw-r--r--test/Rewriter/rewrite-local-static-id.mm24
-rw-r--r--test/Rewriter/rewrite-no-nextline.mm10
-rw-r--r--test/Sema/attr-sentinel.c8
-rw-r--r--test/Sema/c89.c2
-rw-r--r--test/Sema/compare.c20
-rw-r--r--test/Sema/conditional-expr.c9
-rw-r--r--test/Sema/conversion.c10
-rw-r--r--test/Sema/format-strings.c3
-rw-r--r--test/Sema/init.c14
-rw-r--r--test/Sema/pragma-align-mac68k-unsupported.c4
-rw-r--r--test/Sema/pragma-align-mac68k.c98
-rw-r--r--test/Sema/pragma-pack-and-options-align.c34
-rw-r--r--test/Sema/scope-check.c20
-rw-r--r--test/Sema/switch.c30
-rw-r--r--test/Sema/unused-expr.c8
-rw-r--r--test/SemaCXX/alignof-sizeof-reference.cpp6
-rw-r--r--test/SemaCXX/anonymous-union.cpp34
-rw-r--r--test/SemaCXX/attr-deprecated.cpp126
-rw-r--r--test/SemaCXX/blocks.cpp32
-rw-r--r--test/SemaCXX/c99-variable-length-array.cpp116
-rw-r--r--test/SemaCXX/c99.cpp5
-rw-r--r--test/SemaCXX/class.cpp23
-rw-r--r--test/SemaCXX/compare.cpp20
-rw-r--r--test/SemaCXX/conditional-expr.cpp37
-rw-r--r--test/SemaCXX/constant-expression.cpp4
-rw-r--r--test/SemaCXX/default-assignment-operator.cpp17
-rw-r--r--test/SemaCXX/empty-class-layout.cpp18
-rw-r--r--test/SemaCXX/enum.cpp10
-rw-r--r--test/SemaCXX/flexible-array-test.cpp45
-rw-r--r--test/SemaCXX/i-c-e-cxx.cpp2
-rw-r--r--test/SemaCXX/implicit-virtual-member-functions.cpp4
-rw-r--r--test/SemaCXX/invalid-instantiated-field-decl.cpp35
-rw-r--r--test/SemaCXX/member-pointer.cpp17
-rw-r--r--test/SemaCXX/namespace-alias.cpp20
-rw-r--r--test/SemaCXX/nested-name-spec.cpp16
-rw-r--r--test/SemaCXX/new-delete.cpp15
-rw-r--r--test/SemaCXX/offsetof.cpp2
-rw-r--r--test/SemaCXX/overload-call.cpp30
-rw-r--r--test/SemaCXX/references.cpp15
-rw-r--r--test/SemaCXX/return-noreturn.cpp17
-rw-r--r--test/SemaCXX/scope-check.cpp123
-rw-r--r--test/SemaCXX/switch.cpp19
-rw-r--r--test/SemaCXX/vararg-non-pod.cpp10
-rw-r--r--test/SemaCXX/vector.cpp188
-rw-r--r--test/SemaCXX/virtual-member-functions-key-function.cpp10
-rw-r--r--test/SemaCXX/warn-missing-noreturn.cpp14
-rw-r--r--test/SemaCXX/warn-reorder-ctor-initialization.cpp10
-rw-r--r--test/SemaCXX/warn-weak-vtables.cpp10
-rw-r--r--test/SemaObjC/block-attr.m1
-rw-r--r--test/SemaObjC/error-property-gc-attr.m5
-rw-r--r--test/SemaObjC/method-conflict.m11
-rw-r--r--test/SemaObjC/objc2-warn-weak-decl.m1
-rw-r--r--test/SemaObjC/warn-assign-property-nscopying.m1
-rw-r--r--test/SemaObjC/warn-weak-field.m1
-rw-r--r--test/SemaObjCXX/const-cast.mm13
-rw-r--r--test/SemaObjCXX/conversion-to-objc-pointer-2.mm87
-rw-r--r--test/SemaObjCXX/conversion-to-objc-pointer.mm50
-rw-r--r--test/SemaObjCXX/deduction.mm58
-rw-r--r--test/SemaObjCXX/ivar-construct.mm29
-rw-r--r--test/SemaObjCXX/ivar-struct.mm7
-rw-r--r--test/SemaObjCXX/objc2-merge-gc-attribue-decl.mm51
-rw-r--r--test/SemaObjCXX/static-cast.mm29
-rw-r--r--test/SemaObjCXX/vla.mm2
-rw-r--r--test/SemaObjCXX/void_to_obj.mm15
-rw-r--r--test/SemaTemplate/attributes.cpp8
-rw-r--r--test/SemaTemplate/current-instantiation.cpp13
-rw-r--r--test/SemaTemplate/dependent-base-classes.cpp2
-rw-r--r--test/SemaTemplate/dependent-expr.cpp16
-rw-r--r--test/SemaTemplate/dependent-template-recover.cpp18
-rw-r--r--test/SemaTemplate/dependent-type-identity.cpp16
-rw-r--r--test/SemaTemplate/enum-argument.cpp13
-rw-r--r--test/SemaTemplate/instantiate-anonymous-union.cpp18
-rw-r--r--test/SemaTemplate/instantiate-attr.cpp6
-rw-r--r--test/SemaTemplate/instantiate-complete.cpp29
-rw-r--r--test/SemaTemplate/instantiate-declref-ice.cpp3
-rw-r--r--test/SemaTemplate/instantiate-expr-2.cpp31
-rw-r--r--test/SemaTemplate/instantiate-expr-3.cpp2
-rw-r--r--test/SemaTemplate/instantiate-field.cpp55
-rw-r--r--test/SemaTemplate/instantiate-function-2.cpp10
-rw-r--r--test/SemaTemplate/instantiate-member-pointers.cpp12
-rw-r--r--test/SemaTemplate/instantiate-non-dependent-types.cpp14
-rw-r--r--test/SemaTemplate/instantiate-overload-candidates.cpp21
-rw-r--r--test/SemaTemplate/nested-name-spec-template.cpp7
-rw-r--r--test/SemaTemplate/overload-candidates.cpp40
-rw-r--r--test/SemaTemplate/partial-spec-instantiate.cpp20
-rw-r--r--test/SemaTemplate/temp_explicit.cpp26
-rw-r--r--test/SemaTemplate/template-id-expr.cpp38
-rw-r--r--test/SemaTemplate/unused-variables.cpp21
-rw-r--r--test/SemaTemplate/virtual-member-functions.cpp39
-rw-r--r--tools/c-index-test/c-index-test.c32
-rw-r--r--tools/driver/CMakeLists.txt1
-rw-r--r--tools/driver/cc1_main.cpp6
-rw-r--r--tools/driver/cc1as_main.cpp373
-rw-r--r--tools/driver/driver.cpp21
-rw-r--r--tools/libclang/CIndex.cpp525
-rw-r--r--tools/libclang/CIndexCodeCompletion.cpp51
-rw-r--r--tools/libclang/CIndexUSRs.cpp429
-rw-r--r--tools/libclang/CMakeLists.txt1
-rw-r--r--tools/libclang/CXCursor.cpp10
-rw-r--r--tools/libclang/CXTypes.cpp249
-rw-r--r--tools/libclang/Makefile2
-rw-r--r--tools/libclang/libclang.darwin.exports9
-rw-r--r--tools/libclang/libclang.exports10
-rw-r--r--www/analyzer/annotations.html62
-rw-r--r--www/analyzer/latest_checker.html.incl2
-rw-r--r--www/clang-tutorial.html56
-rw-r--r--www/comparison.html6
-rw-r--r--www/cxx_compatibility.html23
-rw-r--r--www/cxx_status.html2283
-rw-r--r--www/get_started.html5
486 files changed, 22043 insertions, 9947 deletions
diff --git a/clang.xcodeproj/project.pbxproj b/clang.xcodeproj/project.pbxproj
index 6556bb4e6a8c..43733f779378 100644
--- a/clang.xcodeproj/project.pbxproj
+++ b/clang.xcodeproj/project.pbxproj
@@ -441,43 +441,42 @@
1AA963AB10D8576800786C86 /* FullExpr.h */ = {isa = PBXFileReference; fileEncoding = 4; indentWidth = 2; lastKnownFileType = sourcecode.c.h; name = FullExpr.h; path = clang/AST/FullExpr.h; sourceTree = "<group>"; tabWidth = 2; };
1AB290021045858B00FE33D8 /* PartialDiagnostic.h */ = {isa = PBXFileReference; fileEncoding = 4; indentWidth = 2; lastKnownFileType = sourcecode.c.h; path = PartialDiagnostic.h; sourceTree = "<group>"; tabWidth = 2; };
1ABC36930C7A4BDC006DB0AB /* CGBuiltin.cpp */ = {isa = PBXFileReference; fileEncoding = 4; indentWidth = 2; lastKnownFileType = sourcecode.cpp.cpp; name = CGBuiltin.cpp; path = lib/CodeGen/CGBuiltin.cpp; sourceTree = "<group>"; tabWidth = 2; };
- 1ABD23B11182449800A48E65 /* APValue.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = APValue.cpp; sourceTree = "<group>"; };
- 1ABD23B21182449800A48E65 /* ASTConsumer.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = ASTConsumer.cpp; sourceTree = "<group>"; };
- 1ABD23B31182449800A48E65 /* ASTContext.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = ASTContext.cpp; sourceTree = "<group>"; };
- 1ABD23B41182449800A48E65 /* ASTDiagnostic.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = ASTDiagnostic.cpp; sourceTree = "<group>"; };
- 1ABD23B51182449800A48E65 /* ASTImporter.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = ASTImporter.cpp; sourceTree = "<group>"; };
- 1ABD23B61182449800A48E65 /* AttrImpl.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = AttrImpl.cpp; sourceTree = "<group>"; };
- 1ABD23B71182449800A48E65 /* CXXInheritance.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = CXXInheritance.cpp; sourceTree = "<group>"; };
- 1ABD23B81182449800A48E65 /* Decl.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = Decl.cpp; sourceTree = "<group>"; };
- 1ABD23B91182449800A48E65 /* DeclarationName.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = DeclarationName.cpp; sourceTree = "<group>"; };
- 1ABD23BA1182449800A48E65 /* DeclBase.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = DeclBase.cpp; sourceTree = "<group>"; };
- 1ABD23BB1182449800A48E65 /* DeclCXX.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = DeclCXX.cpp; sourceTree = "<group>"; };
- 1ABD23BC1182449800A48E65 /* DeclFriend.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = DeclFriend.cpp; sourceTree = "<group>"; };
- 1ABD23BD1182449800A48E65 /* DeclGroup.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = DeclGroup.cpp; sourceTree = "<group>"; };
- 1ABD23BE1182449800A48E65 /* DeclObjC.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = DeclObjC.cpp; sourceTree = "<group>"; };
- 1ABD23BF1182449800A48E65 /* DeclPrinter.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = DeclPrinter.cpp; sourceTree = "<group>"; };
- 1ABD23C01182449800A48E65 /* DeclTemplate.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = DeclTemplate.cpp; sourceTree = "<group>"; };
- 1ABD23C11182449800A48E65 /* Expr.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = Expr.cpp; sourceTree = "<group>"; };
- 1ABD23C21182449800A48E65 /* ExprConstant.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = ExprConstant.cpp; sourceTree = "<group>"; };
- 1ABD23C31182449800A48E65 /* ExprCXX.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = ExprCXX.cpp; sourceTree = "<group>"; };
- 1ABD23C41182449800A48E65 /* FullExpr.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = FullExpr.cpp; sourceTree = "<group>"; };
- 1ABD23C51182449800A48E65 /* InheritViz.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = InheritViz.cpp; sourceTree = "<group>"; };
- 1ABD23C61182449800A48E65 /* NestedNameSpecifier.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = NestedNameSpecifier.cpp; sourceTree = "<group>"; };
- 1ABD23C71182449800A48E65 /* ParentMap.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = ParentMap.cpp; sourceTree = "<group>"; };
- 1ABD23C81182449800A48E65 /* RecordLayout.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = RecordLayout.cpp; sourceTree = "<group>"; };
- 1ABD23C91182449800A48E65 /* RecordLayoutBuilder.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = RecordLayoutBuilder.cpp; sourceTree = "<group>"; };
- 1ABD23CA1182449800A48E65 /* RecordLayoutBuilder.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = RecordLayoutBuilder.h; sourceTree = "<group>"; };
- 1ABD23CB1182449800A48E65 /* Stmt.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = Stmt.cpp; sourceTree = "<group>"; };
- 1ABD23CC1182449800A48E65 /* StmtDumper.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = StmtDumper.cpp; sourceTree = "<group>"; };
- 1ABD23CD1182449800A48E65 /* StmtIterator.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = StmtIterator.cpp; sourceTree = "<group>"; };
- 1ABD23CE1182449800A48E65 /* StmtPrinter.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = StmtPrinter.cpp; sourceTree = "<group>"; };
- 1ABD23CF1182449800A48E65 /* StmtProfile.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = StmtProfile.cpp; sourceTree = "<group>"; };
- 1ABD23D01182449800A48E65 /* StmtViz.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = StmtViz.cpp; sourceTree = "<group>"; };
- 1ABD23D11182449800A48E65 /* TemplateBase.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = TemplateBase.cpp; sourceTree = "<group>"; };
- 1ABD23D21182449800A48E65 /* TemplateName.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = TemplateName.cpp; sourceTree = "<group>"; };
- 1ABD23D31182449800A48E65 /* Type.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = Type.cpp; sourceTree = "<group>"; };
- 1ABD23D41182449800A48E65 /* TypeLoc.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = TypeLoc.cpp; sourceTree = "<group>"; };
- 1ABD23D51182449800A48E65 /* TypePrinter.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = TypePrinter.cpp; sourceTree = "<group>"; };
+ 1ABD23B11182449800A48E65 /* APValue.cpp */ = {isa = PBXFileReference; fileEncoding = 4; indentWidth = 2; lastKnownFileType = sourcecode.cpp.cpp; path = APValue.cpp; sourceTree = "<group>"; tabWidth = 2; };
+ 1ABD23B21182449800A48E65 /* ASTConsumer.cpp */ = {isa = PBXFileReference; fileEncoding = 4; indentWidth = 2; lastKnownFileType = sourcecode.cpp.cpp; path = ASTConsumer.cpp; sourceTree = "<group>"; tabWidth = 2; };
+ 1ABD23B31182449800A48E65 /* ASTContext.cpp */ = {isa = PBXFileReference; fileEncoding = 4; indentWidth = 2; lastKnownFileType = sourcecode.cpp.cpp; path = ASTContext.cpp; sourceTree = "<group>"; tabWidth = 2; };
+ 1ABD23B41182449800A48E65 /* ASTDiagnostic.cpp */ = {isa = PBXFileReference; fileEncoding = 4; indentWidth = 2; lastKnownFileType = sourcecode.cpp.cpp; path = ASTDiagnostic.cpp; sourceTree = "<group>"; tabWidth = 2; };
+ 1ABD23B51182449800A48E65 /* ASTImporter.cpp */ = {isa = PBXFileReference; fileEncoding = 4; indentWidth = 2; lastKnownFileType = sourcecode.cpp.cpp; path = ASTImporter.cpp; sourceTree = "<group>"; tabWidth = 2; };
+ 1ABD23B61182449800A48E65 /* AttrImpl.cpp */ = {isa = PBXFileReference; fileEncoding = 4; indentWidth = 2; lastKnownFileType = sourcecode.cpp.cpp; path = AttrImpl.cpp; sourceTree = "<group>"; tabWidth = 2; };
+ 1ABD23B71182449800A48E65 /* CXXInheritance.cpp */ = {isa = PBXFileReference; fileEncoding = 4; indentWidth = 2; lastKnownFileType = sourcecode.cpp.cpp; path = CXXInheritance.cpp; sourceTree = "<group>"; tabWidth = 2; };
+ 1ABD23B81182449800A48E65 /* Decl.cpp */ = {isa = PBXFileReference; fileEncoding = 4; indentWidth = 2; lastKnownFileType = sourcecode.cpp.cpp; path = Decl.cpp; sourceTree = "<group>"; tabWidth = 2; };
+ 1ABD23B91182449800A48E65 /* DeclarationName.cpp */ = {isa = PBXFileReference; fileEncoding = 4; indentWidth = 2; lastKnownFileType = sourcecode.cpp.cpp; path = DeclarationName.cpp; sourceTree = "<group>"; tabWidth = 2; };
+ 1ABD23BA1182449800A48E65 /* DeclBase.cpp */ = {isa = PBXFileReference; fileEncoding = 4; indentWidth = 2; lastKnownFileType = sourcecode.cpp.cpp; path = DeclBase.cpp; sourceTree = "<group>"; tabWidth = 2; };
+ 1ABD23BB1182449800A48E65 /* DeclCXX.cpp */ = {isa = PBXFileReference; fileEncoding = 4; indentWidth = 2; lastKnownFileType = sourcecode.cpp.cpp; path = DeclCXX.cpp; sourceTree = "<group>"; tabWidth = 2; };
+ 1ABD23BC1182449800A48E65 /* DeclFriend.cpp */ = {isa = PBXFileReference; fileEncoding = 4; indentWidth = 2; lastKnownFileType = sourcecode.cpp.cpp; path = DeclFriend.cpp; sourceTree = "<group>"; tabWidth = 2; };
+ 1ABD23BD1182449800A48E65 /* DeclGroup.cpp */ = {isa = PBXFileReference; fileEncoding = 4; indentWidth = 2; lastKnownFileType = sourcecode.cpp.cpp; path = DeclGroup.cpp; sourceTree = "<group>"; tabWidth = 2; };
+ 1ABD23BE1182449800A48E65 /* DeclObjC.cpp */ = {isa = PBXFileReference; fileEncoding = 4; indentWidth = 2; lastKnownFileType = sourcecode.cpp.cpp; path = DeclObjC.cpp; sourceTree = "<group>"; tabWidth = 2; };
+ 1ABD23BF1182449800A48E65 /* DeclPrinter.cpp */ = {isa = PBXFileReference; fileEncoding = 4; indentWidth = 2; lastKnownFileType = sourcecode.cpp.cpp; path = DeclPrinter.cpp; sourceTree = "<group>"; tabWidth = 2; };
+ 1ABD23C01182449800A48E65 /* DeclTemplate.cpp */ = {isa = PBXFileReference; fileEncoding = 4; indentWidth = 2; lastKnownFileType = sourcecode.cpp.cpp; path = DeclTemplate.cpp; sourceTree = "<group>"; tabWidth = 2; };
+ 1ABD23C11182449800A48E65 /* Expr.cpp */ = {isa = PBXFileReference; fileEncoding = 4; indentWidth = 2; lastKnownFileType = sourcecode.cpp.cpp; path = Expr.cpp; sourceTree = "<group>"; tabWidth = 2; };
+ 1ABD23C21182449800A48E65 /* ExprConstant.cpp */ = {isa = PBXFileReference; fileEncoding = 4; indentWidth = 2; lastKnownFileType = sourcecode.cpp.cpp; path = ExprConstant.cpp; sourceTree = "<group>"; tabWidth = 2; };
+ 1ABD23C31182449800A48E65 /* ExprCXX.cpp */ = {isa = PBXFileReference; fileEncoding = 4; indentWidth = 2; lastKnownFileType = sourcecode.cpp.cpp; path = ExprCXX.cpp; sourceTree = "<group>"; tabWidth = 2; };
+ 1ABD23C41182449800A48E65 /* FullExpr.cpp */ = {isa = PBXFileReference; fileEncoding = 4; indentWidth = 2; lastKnownFileType = sourcecode.cpp.cpp; path = FullExpr.cpp; sourceTree = "<group>"; tabWidth = 2; };
+ 1ABD23C51182449800A48E65 /* InheritViz.cpp */ = {isa = PBXFileReference; fileEncoding = 4; indentWidth = 2; lastKnownFileType = sourcecode.cpp.cpp; path = InheritViz.cpp; sourceTree = "<group>"; tabWidth = 2; };
+ 1ABD23C61182449800A48E65 /* NestedNameSpecifier.cpp */ = {isa = PBXFileReference; fileEncoding = 4; indentWidth = 2; lastKnownFileType = sourcecode.cpp.cpp; path = NestedNameSpecifier.cpp; sourceTree = "<group>"; tabWidth = 2; };
+ 1ABD23C71182449800A48E65 /* ParentMap.cpp */ = {isa = PBXFileReference; fileEncoding = 4; indentWidth = 2; lastKnownFileType = sourcecode.cpp.cpp; path = ParentMap.cpp; sourceTree = "<group>"; tabWidth = 2; };
+ 1ABD23C81182449800A48E65 /* RecordLayout.cpp */ = {isa = PBXFileReference; fileEncoding = 4; indentWidth = 2; lastKnownFileType = sourcecode.cpp.cpp; path = RecordLayout.cpp; sourceTree = "<group>"; tabWidth = 2; };
+ 1ABD23C91182449800A48E65 /* RecordLayoutBuilder.cpp */ = {isa = PBXFileReference; fileEncoding = 4; indentWidth = 2; lastKnownFileType = sourcecode.cpp.cpp; path = RecordLayoutBuilder.cpp; sourceTree = "<group>"; tabWidth = 2; };
+ 1ABD23CB1182449800A48E65 /* Stmt.cpp */ = {isa = PBXFileReference; fileEncoding = 4; indentWidth = 2; lastKnownFileType = sourcecode.cpp.cpp; path = Stmt.cpp; sourceTree = "<group>"; tabWidth = 2; };
+ 1ABD23CC1182449800A48E65 /* StmtDumper.cpp */ = {isa = PBXFileReference; fileEncoding = 4; indentWidth = 2; lastKnownFileType = sourcecode.cpp.cpp; path = StmtDumper.cpp; sourceTree = "<group>"; tabWidth = 2; };
+ 1ABD23CD1182449800A48E65 /* StmtIterator.cpp */ = {isa = PBXFileReference; fileEncoding = 4; indentWidth = 2; lastKnownFileType = sourcecode.cpp.cpp; path = StmtIterator.cpp; sourceTree = "<group>"; tabWidth = 2; };
+ 1ABD23CE1182449800A48E65 /* StmtPrinter.cpp */ = {isa = PBXFileReference; fileEncoding = 4; indentWidth = 2; lastKnownFileType = sourcecode.cpp.cpp; path = StmtPrinter.cpp; sourceTree = "<group>"; tabWidth = 2; };
+ 1ABD23CF1182449800A48E65 /* StmtProfile.cpp */ = {isa = PBXFileReference; fileEncoding = 4; indentWidth = 2; lastKnownFileType = sourcecode.cpp.cpp; path = StmtProfile.cpp; sourceTree = "<group>"; tabWidth = 2; };
+ 1ABD23D01182449800A48E65 /* StmtViz.cpp */ = {isa = PBXFileReference; fileEncoding = 4; indentWidth = 2; lastKnownFileType = sourcecode.cpp.cpp; path = StmtViz.cpp; sourceTree = "<group>"; tabWidth = 2; };
+ 1ABD23D11182449800A48E65 /* TemplateBase.cpp */ = {isa = PBXFileReference; fileEncoding = 4; indentWidth = 2; lastKnownFileType = sourcecode.cpp.cpp; path = TemplateBase.cpp; sourceTree = "<group>"; tabWidth = 2; };
+ 1ABD23D21182449800A48E65 /* TemplateName.cpp */ = {isa = PBXFileReference; fileEncoding = 4; indentWidth = 2; lastKnownFileType = sourcecode.cpp.cpp; path = TemplateName.cpp; sourceTree = "<group>"; tabWidth = 2; };
+ 1ABD23D31182449800A48E65 /* Type.cpp */ = {isa = PBXFileReference; fileEncoding = 4; indentWidth = 2; lastKnownFileType = sourcecode.cpp.cpp; path = Type.cpp; sourceTree = "<group>"; tabWidth = 2; };
+ 1ABD23D41182449800A48E65 /* TypeLoc.cpp */ = {isa = PBXFileReference; fileEncoding = 4; indentWidth = 2; lastKnownFileType = sourcecode.cpp.cpp; path = TypeLoc.cpp; sourceTree = "<group>"; tabWidth = 2; };
+ 1ABD23D51182449800A48E65 /* TypePrinter.cpp */ = {isa = PBXFileReference; fileEncoding = 4; indentWidth = 2; lastKnownFileType = sourcecode.cpp.cpp; path = TypePrinter.cpp; sourceTree = "<group>"; tabWidth = 2; };
1ACB57DB1105820D0047B991 /* CompilerInstance.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = CompilerInstance.cpp; path = lib/Frontend/CompilerInstance.cpp; sourceTree = "<group>"; };
1ACB57DC1105820D0047B991 /* CompilerInvocation.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = CompilerInvocation.cpp; path = lib/Frontend/CompilerInvocation.cpp; sourceTree = "<group>"; };
1ACB57DD1105820D0047B991 /* DeclXML.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = DeclXML.cpp; path = lib/Frontend/DeclXML.cpp; sourceTree = "<group>"; };
@@ -1494,7 +1493,6 @@
1ABD23C71182449800A48E65 /* ParentMap.cpp */,
1ABD23C81182449800A48E65 /* RecordLayout.cpp */,
1ABD23C91182449800A48E65 /* RecordLayoutBuilder.cpp */,
- 1ABD23CA1182449800A48E65 /* RecordLayoutBuilder.h */,
1ABD23CB1182449800A48E65 /* Stmt.cpp */,
1ABD23CC1182449800A48E65 /* StmtDumper.cpp */,
1ABD23CD1182449800A48E65 /* StmtIterator.cpp */,
diff --git a/docs/InternalsManual.html b/docs/InternalsManual.html
index daec6b019415..5ef5dd842a6d 100644
--- a/docs/InternalsManual.html
+++ b/docs/InternalsManual.html
@@ -532,12 +532,12 @@ source code of the program. Important design points include:</p>
</ol>
<p>In practice, the SourceLocation works together with the SourceManager class
-to encode two pieces of information about a location: it's spelling location
-and it's instantiation location. For most tokens, these will be the same. However,
-for a macro expansion (or tokens that came from a _Pragma directive) these will
-describe the location of the characters corresponding to the token and the
-location where the token was used (i.e. the macro instantiation point or the
-location of the _Pragma itself).</p>
+to encode two pieces of information about a location: its spelling location
+and its instantiation location. For most tokens, these will be the same.
+However, for a macro expansion (or tokens that came from a _Pragma directive)
+these will describe the location of the characters corresponding to the token
+and the location where the token was used (i.e. the macro instantiation point
+or the location of the _Pragma itself).</p>
<p>The Clang front-end inherently depends on the location of a token being
tracked correctly. If it is ever incorrect, the front-end may get confused and
diff --git a/docs/UsersManual.html b/docs/UsersManual.html
index 7d7f2631ab5e..5c5f6f916cf6 100644
--- a/docs/UsersManual.html
+++ b/docs/UsersManual.html
@@ -36,6 +36,7 @@ td {
<ul>
<li><a href="#diagnostics_display">Controlling How Clang Displays Diagnostics</a></li>
<li><a href="#diagnostics_mappings">Diagnostic Mappings</a></li>
+ <li><a href="#diagnostics_categories">Diagnostic Categories</a><li>
<li><a href="#diagnostics_commandline">Controlling Diagnostics via Command Line Flags</a></li>
<li><a href="#diagnostics_pragmas">Controlling Diagnostics via Pragmas</a></li>
</ul>
@@ -286,6 +287,30 @@ diagnostic. This information tells you the flag needed to enable or disable the
diagnostic, either from the command line or through <a
href="#pragma_GCC_diagnostic">#pragma GCC diagnostic</a>.</dd>
+<!-- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -->
+<dt id="opt_fdiagnostics-show-category"><b>-fdiagnostics-show-category=none/id/name</b>:
+Enable printing category information in diagnostic line.</dt>
+<dd>This option, which defaults to "none",
+controls whether or not Clang prints the category associated with a diagnostic
+when emitting it. Each diagnostic may or many not have an associated category,
+if it has one, it is listed in the diagnostic categorization field of the
+diagnostic line (in the []'s).</p>
+
+<p>For example, a format string warning will produce these three renditions
+based on the setting of this option:</p>
+
+<pre>
+ t.c:3:11: warning: conversion specifies type 'char *' but the argument has type 'int' [-Wformat]
+ t.c:3:11: warning: conversion specifies type 'char *' but the argument has type 'int' [-Wformat<b>,1</b>]
+ t.c:3:11: warning: conversion specifies type 'char *' but the argument has type 'int' [-Wformat<b>,Format String</b>]
+</pre>
+
+<p>This category can be used by clients that want to group diagnostics by
+category, so it should be a high level category. We want dozens of these, not
+hundreds or thousands of them.</p>
+</dd>
+
+
<!-- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -->
<dt id="opt_fdiagnostics-fixit-info"><b>-f[no-]diagnostics-fixit-info</b>:
@@ -393,6 +418,10 @@ it:</p>
<li>An option that indicates how to control the diagnostic (for diagnostics that
support it) [<a
href="#opt_fdiagnostics-show-option">-fdiagnostics-show-option</a>].</li>
+<li>A <a href="#diagnostics_categories">high-level category</a> for the
+ diagnostic for clients that want to group diagnostics by class (for
+ diagnostics that support it) [<a
+ href="#opt_fdiagnostics-show-category">-fdiagnostics-show-category</a>].</li>
<li>The line of source code that the issue occurs on, along with a caret and
ranges that indicate the important locations [<a
href="opt_fcaret-diagnostics">-fcaret-diagnostics</a>].</li>
@@ -407,6 +436,7 @@ it:</p>
<p>For more information please see <a href="#cl_diag_formatting">Formatting of
Diagnostics</a>.</p>
+
<h4 id="diagnostics_mappings">Diagnostic Mappings</h4>
<p>All diagnostics are mapped into one of these 5 classes:</p>
@@ -420,7 +450,23 @@ Diagnostics</a>.</p>
<li>Fatal</li>
</ul></p>
-<h4 id="diagnostics_commandline">Controlling Diagnostics via Command Line Flags</h4>
+<h4 id="diagnostics_categories">Diagnostic Categories</h4>
+
+<p>Though not shown by default, diagnostics may each be associated with a
+ high-level category. This category is intended to make it possible to triage
+ builds that produce a large number of errors or warnings in a grouped way.
+</p>
+
+<p>Categories are not shown by default, but they can be turned on with the
+<a href="#opt_fdiagnostics-show-category">-fdiagnostics-show-category</a> option.
+When set to "<tt>name</tt>", the category is printed textually in the diagnostic
+output. When it is set to "<tt>id</tt>", a category number is printed. The
+mapping of category names to category id's can be obtained by running '<tt>clang
+ --print-diagnostic-categories</tt>'.
+</p>
+
+<h4 id="diagnostics_commandline">Controlling Diagnostics via Command Line
+ Flags</h4>
<p>-W flags, -pedantic, etc</p>
diff --git a/docs/tools/clang.pod b/docs/tools/clang.pod
index 42cf8fa2d711..0c1ab574d535 100644
--- a/docs/tools/clang.pod
+++ b/docs/tools/clang.pod
@@ -50,10 +50,13 @@ parse errors. The output of this stage is an "Abstract Syntax Tree" (AST).
=item B<Code Generation and Optimization>
This stage translates an AST into low-level intermediate code (known as "LLVM
-IR") and ultimately to machine code (depending on the optimization level). This
-phase is responsible for optimizing the generated code and handling
-target-specfic code generation. The output of this stage is typically called a
-".s" file or "assembly" file.
+IR") and ultimately to machine code. This phase is responsible for optimizing
+the generated code and handling target-specfic code generation. The output of
+this stage is typically called a ".s" file or "assembly" file.
+
+Clang also supports the use of an integrated assembler, in which the code
+generator produces object files directly. This avoids the overhead of generating
+the ".s" file and of calling the target assembler.
=item B<Assembler>
@@ -325,17 +328,21 @@ Pass I<arg> to the assembler.
=item B<-Xclang> I<arg>
-Pass I<arg> to the clang compiler.
+Pass I<arg> to the clang compiler frontend.
=item B<-Xlinker> I<arg>
Pass I<arg> to the linker.
+=item B<-mllvm> I<arg>
+
+Pass I<arg> to the LLVM backend.
+
=item B<-Xpreprocessor> I<arg>
Pass I<arg> to the preprocessor.
-=item B<-o> I<file>
+=item B<-o> I<file>
Write output to I<file>.
@@ -359,6 +366,12 @@ Print the paths used for finding libraries and programs.
Save intermediate compilation results.
+=item B<-integrated-as> B<-no-integrated-as>
+
+Used to enable and disable, respectively, the use of the integrated
+assembler. Whether the integrated assembler is on by default is target
+dependent.
+
=item B<-time>
Time individual commands.
diff --git a/include/clang-c/Index.h b/include/clang-c/Index.h
index 1bf5a4688a2c..86926bd683ba 100644
--- a/include/clang-c/Index.h
+++ b/include/clang-c/Index.h
@@ -343,6 +343,12 @@ CINDEX_LINKAGE CXSourceLocation clang_getRangeStart(CXSourceRange range);
CINDEX_LINKAGE CXSourceLocation clang_getRangeEnd(CXSourceRange range);
/**
+ * \brief Determine if the source location occurs within the main file
+ * of the translation unit (as opposed to an included header).
+ */
+CINDEX_LINKAGE unsigned clang_isFromMainFile(CXSourceLocation loc);
+
+/**
* @}
*/
@@ -648,7 +654,6 @@ CINDEX_LINKAGE void clang_disposeTranslationUnit(CXTranslationUnit);
*/
enum CXCursorKind {
/* Declarations */
- CXCursor_FirstDecl = 1,
/**
* \brief A declaration whose specific kind is not exposed via this
* interface.
@@ -700,11 +705,15 @@ enum CXCursorKind {
CXCursor_ObjCCategoryImplDecl = 19,
/** \brief A typedef */
CXCursor_TypedefDecl = 20,
-
/** \brief A C++ class method. */
CXCursor_CXXMethod = 21,
+ /** \brief A C++ namespace. */
+ CXCursor_Namespace = 22,
+ /** \brief A linkage specification, e.g. 'extern "C"'. */
+ CXCursor_LinkageSpec = 23,
- CXCursor_LastDecl = 21,
+ CXCursor_FirstDecl = CXCursor_UnexposedDecl,
+ CXCursor_LastDecl = CXCursor_LinkageSpec,
/* References */
CXCursor_FirstRef = 40, /* Decl references */
@@ -807,7 +816,8 @@ enum CXCursorKind {
CXCursor_IBActionAttr = 401,
CXCursor_IBOutletAttr = 402,
- CXCursor_LastAttr = CXCursor_IBOutletAttr,
+ CXCursor_IBOutletCollectionAttr = 403,
+ CXCursor_LastAttr = CXCursor_IBOutletCollectionAttr,
/* Preprocessing */
CXCursor_PreprocessingDirective = 500,
@@ -1021,6 +1031,124 @@ CINDEX_LINKAGE CXSourceRange clang_getCursorExtent(CXCursor);
*/
/**
+ * \defgroup CINDEX_TYPES Type information for CXCursors
+ *
+ * @{
+ */
+
+/**
+ * \brief Describes the kind of type
+ */
+enum CXTypeKind {
+ /**
+ * \brief Reprents an invalid type (e.g., where no type is available).
+ */
+ CXType_Invalid = 0,
+
+ /**
+ * \brief A type whose specific kind is not exposed via this
+ * interface.
+ */
+ CXType_Unexposed = 1,
+
+ /* Builtin types */
+ CXType_Void = 2,
+ CXType_Bool = 3,
+ CXType_Char_U = 4,
+ CXType_UChar = 5,
+ CXType_Char16 = 6,
+ CXType_Char32 = 7,
+ CXType_UShort = 8,
+ CXType_UInt = 9,
+ CXType_ULong = 10,
+ CXType_ULongLong = 11,
+ CXType_UInt128 = 12,
+ CXType_Char_S = 13,
+ CXType_SChar = 14,
+ CXType_WChar = 15,
+ CXType_Short = 16,
+ CXType_Int = 17,
+ CXType_Long = 18,
+ CXType_LongLong = 19,
+ CXType_Int128 = 20,
+ CXType_Float = 21,
+ CXType_Double = 22,
+ CXType_LongDouble = 23,
+ CXType_NullPtr = 24,
+ CXType_Overload = 25,
+ CXType_Dependent = 26,
+ CXType_ObjCId = 27,
+ CXType_ObjCClass = 28,
+ CXType_ObjCSel = 29,
+ CXType_FirstBuiltin = CXType_Void,
+ CXType_LastBuiltin = CXType_ObjCSel,
+
+ CXType_Complex = 100,
+ CXType_Pointer = 101,
+ CXType_BlockPointer = 102,
+ CXType_LValueReference = 103,
+ CXType_RValueReference = 104,
+ CXType_Record = 105,
+ CXType_Enum = 106,
+ CXType_Typedef = 107,
+ CXType_ObjCInterface = 108,
+ CXType_ObjCObjectPointer = 109
+};
+
+/**
+ * \brief The type of an element in the abstract syntax tree.
+ *
+ */
+typedef struct {
+ enum CXTypeKind kind;
+ void *data[2];
+} CXType;
+
+/**
+ * \brief Retrieve the type of a CXCursor (if any).
+ */
+CINDEX_LINKAGE CXType clang_getCursorType(CXCursor C);
+
+/**
+ * \determine Determine whether two CXTypes represent the same type.
+ *
+ * \returns non-zero if the CXTypes represent the same type and
+ zero otherwise.
+ */
+CINDEX_LINKAGE unsigned clang_equalTypes(CXType A, CXType B);
+
+/**
+ * \brief Return the canonical type for a CXType.
+ *
+ * Clang's type system explicitly models typedefs and all the ways
+ * a specific type can be represented. The canonical type is the underlying
+ * type with all the "sugar" removed. For example, if 'T' is a typedef
+ * for 'int', the canonical type for 'T' would be 'int'.
+ */
+CINDEX_LINKAGE CXType clang_getCanonicalType(CXType T);
+
+/**
+ * \brief For pointer types, returns the type of the pointee.
+ *
+ */
+CINDEX_LINKAGE CXType clang_getPointeeType(CXType T);
+
+/**
+ * \brief Return the cursor for the declaration of the given type.
+ */
+CINDEX_LINKAGE CXCursor clang_getTypeDeclaration(CXType T);
+
+
+/**
+ * \brief Retrieve the spelling of a given CXTypeKind.
+ */
+CINDEX_LINKAGE CXString clang_getTypeKindSpelling(enum CXTypeKind K);
+
+/**
+ * @}
+ */
+
+/**
* \defgroup CINDEX_CURSOR_TRAVERSAL Traversing the AST with cursors
*
* These routines provide the ability to traverse the abstract syntax tree
@@ -1220,6 +1348,24 @@ CINDEX_LINKAGE unsigned clang_isCursorDefinition(CXCursor);
*/
/**
+ * \defgroup CINDEX_CPP C++ AST introspection
+ *
+ * The routines in this group provide access information in the ASTs specific
+ * to C++ language features.
+ *
+ * @{
+ */
+
+/**
+ * \brief Determine if a C++ member function is declared 'static'.
+ */
+CINDEX_LINKAGE unsigned clang_CXXMethod_isStatic(CXCursor C);
+
+/**
+ * @}
+ */
+
+/**
* \defgroup CINDEX_LEX Token extraction and manipulation
*
* The routines in this group provide access to the tokens within a
@@ -1649,6 +1795,21 @@ CINDEX_LINKAGE unsigned
clang_getNumCompletionChunks(CXCompletionString completion_string);
/**
+ * \brief Determine the priority of this code completion.
+ *
+ * The priority of a code completion indicates how likely it is that this
+ * particular completion is the completion that the user will select. The
+ * priority is selected by various internal heuristics.
+ *
+ * \param completion_string The completion string to query.
+ *
+ * \returns The priority of this completion string. Smaller values indicate
+ * higher-priority (more likely) completions.
+ */
+CINDEX_LINKAGE unsigned
+clang_getCompletionPriority(CXCompletionString completion_string);
+
+/**
* \brief Contains the results of code-completion.
*
* This data structure contains the results of code completion, as
diff --git a/include/clang/AST/ASTConsumer.h b/include/clang/AST/ASTConsumer.h
index 53bb785c49d2..06113954fc48 100644
--- a/include/clang/AST/ASTConsumer.h
+++ b/include/clang/AST/ASTConsumer.h
@@ -16,6 +16,7 @@
namespace clang {
class ASTContext;
+ class CXXRecordDecl;
class DeclGroupRef;
class TagDecl;
class HandleTagDeclDefinition;
@@ -68,6 +69,17 @@ public:
/// modified by the introduction of an implicit zero initializer.
virtual void CompleteTentativeDefinition(VarDecl *D) {}
+ /// \brief Callback involved at the end of a translation unit to
+ /// notify the consumer that a vtable for the given C++ class is
+ /// required.
+ ///
+ /// \param RD The class whose vtable was used.
+ ///
+ /// \param DefinitionRequired Whether a definition of this vtable is
+ /// required in this translation unit; otherwise, it is only needed if
+ /// it was actually used.
+ virtual void HandleVTable(CXXRecordDecl *RD, bool DefinitionRequired) {}
+
/// PrintStats - If desired, print any statistics.
virtual void PrintStats() {}
diff --git a/include/clang/AST/ASTContext.h b/include/clang/AST/ASTContext.h
index f8a8f179ae58..87a12cde2ad2 100644
--- a/include/clang/AST/ASTContext.h
+++ b/include/clang/AST/ASTContext.h
@@ -96,11 +96,10 @@ class ASTContext {
llvm::FoldingSet<TemplateTypeParmType> TemplateTypeParmTypes;
llvm::FoldingSet<SubstTemplateTypeParmType> SubstTemplateTypeParmTypes;
llvm::FoldingSet<TemplateSpecializationType> TemplateSpecializationTypes;
- llvm::FoldingSet<QualifiedNameType> QualifiedNameTypes;
+ llvm::FoldingSet<ElaboratedType> ElaboratedTypes;
llvm::FoldingSet<DependentNameType> DependentNameTypes;
- llvm::FoldingSet<ObjCInterfaceType> ObjCInterfaceTypes;
+ llvm::FoldingSet<ObjCObjectTypeImpl> ObjCObjectTypes;
llvm::FoldingSet<ObjCObjectPointerType> ObjCObjectPointerTypes;
- llvm::FoldingSet<ElaboratedType> ElaboratedTypes;
llvm::FoldingSet<QualifiedTemplateName> QualifiedTemplateNames;
llvm::FoldingSet<DependentTemplateName> DependentTemplateNames;
@@ -483,7 +482,7 @@ public:
/// This gets the struct used to keep track of pointer to blocks, complete
/// with captured variables.
QualType getBlockParmType(bool BlockHasCopyDispose,
- llvm::SmallVector<const Expr *, 8> &BDRDs);
+ llvm::SmallVectorImpl<const Expr *> &Layout);
/// This builds the struct used for __block variables.
QualType BuildByRefType(const char *DeclName, QualType Ty);
@@ -613,8 +612,9 @@ public:
const TemplateArgumentListInfo &Args,
QualType Canon = QualType());
- QualType getQualifiedNameType(NestedNameSpecifier *NNS,
- QualType NamedType);
+ QualType getElaboratedType(ElaboratedTypeKeyword Keyword,
+ NestedNameSpecifier *NNS,
+ QualType NamedType);
QualType getDependentNameType(ElaboratedTypeKeyword Keyword,
NestedNameSpecifier *NNS,
const IdentifierInfo *Name,
@@ -623,19 +623,16 @@ public:
NestedNameSpecifier *NNS,
const TemplateSpecializationType *TemplateId,
QualType Canon = QualType());
- QualType getElaboratedType(QualType UnderlyingType,
- ElaboratedType::TagKind Tag);
- QualType getObjCInterfaceType(const ObjCInterfaceDecl *Decl,
- ObjCProtocolDecl **Protocols = 0,
- unsigned NumProtocols = 0);
+ QualType getObjCInterfaceType(const ObjCInterfaceDecl *Decl);
+
+ QualType getObjCObjectType(QualType Base,
+ ObjCProtocolDecl * const *Protocols,
+ unsigned NumProtocols);
- /// getObjCObjectPointerType - Return a ObjCObjectPointerType type for the
- /// given interface decl and the conforming protocol list.
- QualType getObjCObjectPointerType(QualType OIT,
- ObjCProtocolDecl **ProtocolList = 0,
- unsigned NumProtocols = 0,
- unsigned Quals = 0);
+ /// getObjCObjectPointerType - Return a ObjCObjectPointerType type
+ /// for the given ObjCObjectType.
+ QualType getObjCObjectPointerType(QualType OIT);
/// getTypeOfType - GCC extension.
QualType getTypeOfExprType(Expr *e);
@@ -913,6 +910,9 @@ public:
CharUnits getTypeAlignInChars(QualType T);
CharUnits getTypeAlignInChars(const Type *T);
+ std::pair<CharUnits, CharUnits> getTypeInfoInChars(const Type *T);
+ std::pair<CharUnits, CharUnits> getTypeInfoInChars(QualType T);
+
/// getPreferredTypeAlign - Return the "preferred" alignment of the specified
/// type for the current target in bits. This can be different than the ABI
/// alignment in cases where it is beneficial for performance to overalign
@@ -1184,8 +1184,8 @@ public:
// Check the safety of assignment from LHS to RHS
bool canAssignObjCInterfaces(const ObjCObjectPointerType *LHSOPT,
const ObjCObjectPointerType *RHSOPT);
- bool canAssignObjCInterfaces(const ObjCInterfaceType *LHS,
- const ObjCInterfaceType *RHS);
+ bool canAssignObjCInterfaces(const ObjCObjectType *LHS,
+ const ObjCObjectType *RHS);
bool canAssignObjCInterfacesInBlockPointer(
const ObjCObjectPointerType *LHSOPT,
const ObjCObjectPointerType *RHSOPT);
@@ -1196,6 +1196,8 @@ public:
// Functions for calculating composite types
QualType mergeTypes(QualType, QualType, bool OfBlockPointer=false);
QualType mergeFunctionTypes(QualType, QualType, bool OfBlockPointer=false);
+
+ QualType mergeObjCGCQualifiers(QualType, QualType);
/// UsualArithmeticConversionsType - handles the various conversions
/// that are common to binary operators (C99 6.3.1.8, C++ [expr]p9)
@@ -1270,6 +1272,15 @@ public:
TypeSourceInfo *
getTrivialTypeSourceInfo(QualType T, SourceLocation Loc = SourceLocation());
+ /// \brief Add a deallocation callback that will be invoked when the
+ /// ASTContext is destroyed.
+ ///
+ /// \brief Callback A callback function that will be invoked on destruction.
+ ///
+ /// \brief Data Pointer data that will be provided to the callback function
+ /// when it is called.
+ void AddDeallocation(void (*Callback)(void*), void *Data);
+
private:
ASTContext(const ASTContext&); // DO NOT IMPLEMENT
void operator=(const ASTContext&); // DO NOT IMPLEMENT
@@ -1284,16 +1295,21 @@ private:
const FieldDecl *Field,
bool OutermostType = false,
bool EncodingProperty = false);
-
+
const ASTRecordLayout &getObjCLayout(const ObjCInterfaceDecl *D,
const ObjCImplementationDecl *Impl);
private:
+ /// \brief A set of deallocations that should be performed when the
+ /// ASTContext is destroyed.
+ llvm::SmallVector<std::pair<void (*)(void*), void *>, 16> Deallocations;
+
// 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.
llvm::PointerIntPair<StoredDeclsMap*,1> LastSDM;
friend class DeclContext;
+ friend class DeclarationNameTable;
void ReleaseDeclContextMaps();
};
diff --git a/include/clang/AST/Attr.h b/include/clang/AST/Attr.h
index 19744931762b..3240e50b0787 100644
--- a/include/clang/AST/Attr.h
+++ b/include/clang/AST/Attr.h
@@ -23,9 +23,10 @@ using llvm::dyn_cast;
namespace clang {
class ASTContext;
+ class IdentifierInfo;
+ class ObjCInterfaceDecl;
}
-
// Defined in ASTContext.h
void *operator new(size_t Bytes, clang::ASTContext &C,
size_t Alignment = 16) throw ();
@@ -44,6 +45,7 @@ public:
enum Kind {
Alias,
Aligned,
+ AlignMac68k,
AlwaysInline,
AnalyzerNoReturn, // Clang-specific.
Annotate,
@@ -63,8 +65,10 @@ public:
GNUInline,
Hiding,
IBOutletKind, // Clang-specific. Use "Kind" suffix to not conflict w/ macro.
+ IBOutletCollectionKind, // Clang-specific.
IBActionKind, // Clang-specific. Use "Kind" suffix to not conflict w/ macro.
Malloc,
+ MaxFieldAlignment,
NoDebug,
NoInline,
NonNull,
@@ -79,13 +83,13 @@ public:
NSReturnsNotRetained, // Clang/Checker-specific.
Overloadable, // Clang-specific
Packed,
- PragmaPack,
Pure,
Regparm,
ReqdWorkGroupSize, // OpenCL-specific
Section,
Sentinel,
StdCall,
+ ThisCall,
TransparentUnion,
Unavailable,
Unused,
@@ -183,11 +187,14 @@ public: \
DEF_SIMPLE_ATTR(Packed);
-class PragmaPackAttr : public Attr {
+/// \brief Attribute for specifying a maximum field alignment; this is only
+/// valid on record decls.
+class MaxFieldAlignmentAttr : public Attr {
unsigned Alignment;
public:
- PragmaPackAttr(unsigned alignment) : Attr(PragmaPack), Alignment(alignment) {}
+ MaxFieldAlignmentAttr(unsigned alignment)
+ : Attr(MaxFieldAlignment), Alignment(alignment) {}
/// getAlignment - The specified alignment in bits.
unsigned getAlignment() const { return Alignment; }
@@ -196,11 +203,13 @@ public:
// Implement isa/cast/dyncast/etc.
static bool classof(const Attr *A) {
- return A->getKind() == PragmaPack;
+ return A->getKind() == MaxFieldAlignment;
}
- static bool classof(const PragmaPackAttr *A) { return true; }
+ static bool classof(const MaxFieldAlignmentAttr *A) { return true; }
};
+DEF_SIMPLE_ATTR(AlignMac68k);
+
class AlignedAttr : public Attr {
unsigned Alignment;
public:
@@ -317,6 +326,23 @@ public:
static bool classof(const IBOutletAttr *A) { return true; }
};
+class IBOutletCollectionAttr : public Attr {
+ const ObjCInterfaceDecl *D;
+public:
+ IBOutletCollectionAttr(const ObjCInterfaceDecl *d = 0)
+ : Attr(IBOutletCollectionKind), D(d) {}
+
+ const ObjCInterfaceDecl *getClass() const { return D; }
+
+ virtual Attr *clone(ASTContext &C) const;
+
+ // Implement isa/cast/dyncast/etc.
+ static bool classof(const Attr *A) {
+ return A->getKind() == IBOutletCollectionKind;
+ }
+ static bool classof(const IBOutletCollectionAttr *A) { return true; }
+};
+
class IBActionAttr : public Attr {
public:
IBActionAttr() : Attr(IBActionKind) {}
@@ -457,6 +483,7 @@ public:
DEF_SIMPLE_ATTR(FastCall);
DEF_SIMPLE_ATTR(StdCall);
+DEF_SIMPLE_ATTR(ThisCall);
DEF_SIMPLE_ATTR(CDecl);
DEF_SIMPLE_ATTR(TransparentUnion);
DEF_SIMPLE_ATTR(ObjCNSObject);
diff --git a/include/clang/AST/CMakeLists.txt b/include/clang/AST/CMakeLists.txt
new file mode 100644
index 000000000000..c24ea06aa024
--- /dev/null
+++ b/include/clang/AST/CMakeLists.txt
@@ -0,0 +1,5 @@
+set(LLVM_TARGET_DEFINITIONS StmtNodes.td)
+tablegen(StmtNodes.inc
+ -gen-clang-stmt-nodes)
+add_custom_target(ClangStmtNodes
+ DEPENDS StmtNodes.inc)
diff --git a/include/clang/AST/CXXInheritance.h b/include/clang/AST/CXXInheritance.h
index edd633e8e140..5a84e404a1b6 100644
--- a/include/clang/AST/CXXInheritance.h
+++ b/include/clang/AST/CXXInheritance.h
@@ -196,7 +196,7 @@ public:
/// \brief Determine whether the path from the most-derived type to the
/// given base type is ambiguous (i.e., it refers to multiple subobjects of
/// the same base type).
- bool isAmbiguous(QualType BaseType);
+ bool isAmbiguous(CanQualType BaseType);
/// \brief Whether we are finding multiple paths to detect ambiguities.
bool isFindingAmbiguities() const { return FindAmbiguities; }
diff --git a/include/clang/AST/CanonicalType.h b/include/clang/AST/CanonicalType.h
index 93dcad751221..4afb81dd05eb 100644
--- a/include/clang/AST/CanonicalType.h
+++ b/include/clang/AST/CanonicalType.h
@@ -643,6 +643,24 @@ struct CanProxyAdaptor<TemplateTypeParmType>
};
template<>
+struct CanProxyAdaptor<ObjCObjectType>
+ : public CanProxyBase<ObjCObjectType> {
+ LLVM_CLANG_CANPROXY_TYPE_ACCESSOR(getBaseType)
+ LLVM_CLANG_CANPROXY_SIMPLE_ACCESSOR(const ObjCInterfaceDecl *,
+ getInterface)
+ LLVM_CLANG_CANPROXY_SIMPLE_ACCESSOR(bool, isObjCUnqualifiedId)
+ LLVM_CLANG_CANPROXY_SIMPLE_ACCESSOR(bool, isObjCUnqualifiedClass)
+ LLVM_CLANG_CANPROXY_SIMPLE_ACCESSOR(bool, isObjCQualifiedId)
+ LLVM_CLANG_CANPROXY_SIMPLE_ACCESSOR(bool, isObjCQualifiedClass)
+
+ typedef ObjCObjectPointerType::qual_iterator qual_iterator;
+ LLVM_CLANG_CANPROXY_SIMPLE_ACCESSOR(qual_iterator, qual_begin)
+ LLVM_CLANG_CANPROXY_SIMPLE_ACCESSOR(qual_iterator, qual_end)
+ LLVM_CLANG_CANPROXY_SIMPLE_ACCESSOR(bool, qual_empty)
+ LLVM_CLANG_CANPROXY_SIMPLE_ACCESSOR(unsigned, getNumProtocols)
+};
+
+template<>
struct CanProxyAdaptor<ObjCObjectPointerType>
: public CanProxyBase<ObjCObjectPointerType> {
LLVM_CLANG_CANPROXY_TYPE_ACCESSOR(getPointeeType)
diff --git a/include/clang/AST/Decl.h b/include/clang/AST/Decl.h
index 834c9a0c563f..7d5b66e02a28 100644
--- a/include/clang/AST/Decl.h
+++ b/include/clang/AST/Decl.h
@@ -55,7 +55,7 @@ public:
QualType getType() const { return Ty; }
/// \brief Return the TypeLoc wrapper for the type source info.
- TypeLoc getTypeLoc() const;
+ TypeLoc getTypeLoc() const; // implemented in TypeLoc.h
};
/// TranslationUnitDecl - The top declaration context.
@@ -138,6 +138,8 @@ public:
// FIXME: Deprecated, move clients to getName().
std::string getNameAsString() const { return Name.getAsString(); }
+ void printName(llvm::raw_ostream &os) const { return Name.printName(os); }
+
/// getDeclName - Get the actual, stored name of the declaration,
/// which may be a special name.
DeclarationName getDeclName() const { return Name; }
@@ -265,18 +267,25 @@ public:
// \brief Returns true if this is an anonymous namespace declaration.
//
// For example:
+ /// \code
// namespace {
// ...
// };
+ // \endcode
// q.v. C++ [namespace.unnamed]
bool isAnonymousNamespace() const {
return !getIdentifier();
}
+ /// \brief Return the next extended namespace declaration or null if this
+ /// is none.
NamespaceDecl *getNextNamespace() { return NextNamespace; }
const NamespaceDecl *getNextNamespace() const { return NextNamespace; }
+
+ /// \brief Set the next extended namespace declaration.
void setNextNamespace(NamespaceDecl *ND) { NextNamespace = ND; }
+ /// \brief Get the original (first) namespace declaration.
NamespaceDecl *getOriginalNamespace() const {
if (OrigOrAnonNamespace.getInt())
return const_cast<NamespaceDecl *>(this);
@@ -284,6 +293,14 @@ public:
return OrigOrAnonNamespace.getPointer();
}
+ /// \brief Return true if this declaration is an original (first) declaration
+ /// of the namespace. This is false for non-original (subsequent) namespace
+ /// declarations and anonymous namespaces.
+ bool isOriginalNamespace() const {
+ return getOriginalNamespace() == this;
+ }
+
+ /// \brief Set the original (first) namespace declaration.
void setOriginalNamespace(NamespaceDecl *ND) {
if (ND != this) {
OrigOrAnonNamespace.setPointer(ND);
@@ -502,6 +519,10 @@ private:
/// or an Objective-C @catch statement.
bool ExceptionVar : 1;
+ /// \brief Whether this local variable could be allocated in the return
+ /// slot of its function, enabling the named return value optimization (NRVO).
+ bool NRVOVariable : 1;
+
friend class StmtIteratorBase;
protected:
VarDecl(Kind DK, DeclContext *DC, SourceLocation L, IdentifierInfo *Id,
@@ -509,7 +530,7 @@ protected:
StorageClass SCAsWritten)
: DeclaratorDecl(DK, DC, L, Id, T, TInfo), Init(),
ThreadSpecified(false), HasCXXDirectInit(false),
- DeclaredInCondition(false), ExceptionVar(false) {
+ DeclaredInCondition(false), ExceptionVar(false), NRVOVariable(false) {
SClass = SC;
SClassAsWritten = SCAsWritten;
}
@@ -852,6 +873,19 @@ public:
}
void setExceptionVariable(bool EV) { ExceptionVar = EV; }
+ /// \brief Determine whether this local variable can be used with the named
+ /// return value optimization (NRVO).
+ ///
+ /// The named return value optimization (NRVO) works by marking certain
+ /// non-volatile local variables of class type as NRVO objects. These
+ /// locals can be allocated within the return slot of their containing
+ /// function, in which case there is no need to copy the object to the
+ /// return slot when returning from the function. Within the function body,
+ /// each return that returns the NRVO object will have this variable as its
+ /// NRVO candidate.
+ bool isNRVOVariable() const { return NRVOVariable; }
+ void setNRVOVariable(bool NRVO) { NRVOVariable = NRVO; }
+
/// \brief If this variable is an instantiated static data member of a
/// class template specialization, returns the templated static data member
/// from which it was instantiated.
@@ -1390,6 +1424,16 @@ public:
/// returns NULL.
const TemplateArgumentList *getTemplateSpecializationArgs() const;
+ /// \brief Retrieve the template argument list as written in the sources,
+ /// if any.
+ ///
+ /// If this function declaration is not a function template specialization
+ /// or if it had no explicit template argument list, returns NULL.
+ /// Note that it an explicit template argument list may be written empty,
+ /// e.g., template<> void foo<>(char* s);
+ const TemplateArgumentListInfo*
+ getTemplateSpecializationArgsAsWritten() const;
+
/// \brief Specify that this function declaration is actually a function
/// template specialization.
///
@@ -1409,7 +1453,8 @@ public:
void setFunctionTemplateSpecialization(FunctionTemplateDecl *Template,
const TemplateArgumentList *TemplateArgs,
void *InsertPos,
- TemplateSpecializationKind TSK = TSK_ImplicitInstantiation);
+ TemplateSpecializationKind TSK = TSK_ImplicitInstantiation,
+ const TemplateArgumentListInfo *TemplateArgsAsWritten = 0);
/// \brief Specifies that this function declaration is actually a
/// dependent function template specialization.
@@ -1593,7 +1638,19 @@ class TypedefDecl : public TypeDecl, public Redeclarable<TypedefDecl> {
: TypeDecl(Typedef, DC, L, Id), TInfo(TInfo) {}
virtual ~TypedefDecl();
+
+protected:
+ typedef Redeclarable<TypedefDecl> redeclarable_base;
+ virtual TypedefDecl *getNextRedeclaration() { return RedeclLink.getNext(); }
+
public:
+ typedef redeclarable_base::redecl_iterator redecl_iterator;
+ redecl_iterator redecls_begin() const {
+ return redeclarable_base::redecls_begin();
+ }
+ redecl_iterator redecls_end() const {
+ return redeclarable_base::redecls_end();
+ }
static TypedefDecl *Create(ASTContext &C, DeclContext *DC,
SourceLocation L, IdentifierInfo *Id,
@@ -1631,11 +1688,7 @@ class TagDecl
: public TypeDecl, public DeclContext, public Redeclarable<TagDecl> {
public:
// This is really ugly.
- typedef ElaboratedType::TagKind TagKind;
- static const TagKind TK_struct = ElaboratedType::TK_struct;
- static const TagKind TK_union = ElaboratedType::TK_union;
- static const TagKind TK_class = ElaboratedType::TK_class;
- static const TagKind TK_enum = ElaboratedType::TK_enum;
+ typedef TagTypeKind TagKind;
private:
// FIXME: This can be packed into the bitfields in Decl.
@@ -1651,6 +1704,12 @@ private:
/// in the syntax of a declarator.
bool IsEmbeddedInDeclarator : 1;
+protected:
+ // These are used by (and only defined for) EnumDecl.
+ unsigned NumPositiveBits : 8;
+ unsigned NumNegativeBits : 8;
+
+private:
SourceLocation TagKeywordLoc;
SourceLocation RBraceLoc;
@@ -1680,7 +1739,8 @@ protected:
TagDecl *PrevDecl, SourceLocation TKL = SourceLocation())
: TypeDecl(DK, DC, L, Id), DeclContext(DK), TagKeywordLoc(TKL),
TypedefDeclOrQualifier((TypedefDecl*) 0) {
- assert((DK != Enum || TK == TK_enum) &&"EnumDecl not matched with TK_enum");
+ assert((DK != Enum || TK == TTK_Enum) &&
+ "EnumDecl not matched with TTK_Enum");
TagDeclKind = TK;
IsDefinition = false;
IsEmbeddedInDeclarator = false;
@@ -1753,30 +1813,26 @@ public:
void setDefinition(bool V) { IsDefinition = V; }
const char *getKindName() const {
- return ElaboratedType::getNameForTagKind(getTagKind());
+ return TypeWithKeyword::getTagTypeKindName(getTagKind());
}
- /// getTagKindForTypeSpec - Converts a type specifier (DeclSpec::TST)
- /// into a tag kind. It is an error to provide a type specifier
- /// which *isn't* a tag kind here.
- static TagKind getTagKindForTypeSpec(unsigned TypeSpec);
-
TagKind getTagKind() const {
return TagKind(TagDeclKind);
}
void setTagKind(TagKind TK) { TagDeclKind = TK; }
- bool isStruct() const { return getTagKind() == TK_struct; }
- bool isClass() const { return getTagKind() == TK_class; }
- bool isUnion() const { return getTagKind() == TK_union; }
- bool isEnum() const { return getTagKind() == TK_enum; }
+ bool isStruct() const { return getTagKind() == TTK_Struct; }
+ bool isClass() const { return getTagKind() == TTK_Class; }
+ bool isUnion() const { return getTagKind() == TTK_Union; }
+ bool isEnum() const { return getTagKind() == TTK_Enum; }
TypedefDecl *getTypedefForAnonDecl() const {
return hasExtInfo() ? 0 : TypedefDeclOrQualifier.get<TypedefDecl*>();
}
- void setTypedefForAnonDecl(TypedefDecl *TDD) { TypedefDeclOrQualifier = TDD; }
-
+
+ void setTypedefForAnonDecl(TypedefDecl *TDD);
+
NestedNameSpecifier *getQualifier() const {
return hasExtInfo() ? TypedefDeclOrQualifier.get<ExtInfo*>()->NNS : 0;
}
@@ -1820,9 +1876,16 @@ class EnumDecl : public TagDecl {
/// enumeration declared within the template.
EnumDecl *InstantiatedFrom;
+ // The number of positive and negative bits required by the
+ // enumerators are stored in the SubclassBits field.
+ enum {
+ NumBitsWidth = 8,
+ NumBitsMask = (1 << NumBitsWidth) - 1
+ };
+
EnumDecl(DeclContext *DC, SourceLocation L,
IdentifierInfo *Id, EnumDecl *PrevDecl, SourceLocation TKL)
- : TagDecl(Enum, TK_enum, DC, L, Id, PrevDecl, TKL), InstantiatedFrom(0) {
+ : TagDecl(Enum, TTK_Enum, DC, L, Id, PrevDecl, TKL), InstantiatedFrom(0) {
IntegerType = QualType();
}
public:
@@ -1845,7 +1908,9 @@ public:
/// added (via DeclContext::addDecl). NewType is the new underlying
/// type of the enumeration type.
void completeDefinition(QualType NewType,
- QualType PromotionType);
+ QualType PromotionType,
+ unsigned NumPositiveBits,
+ unsigned NumNegativeBits);
// enumerator_iterator - Iterates through the enumerators of this
// enumeration.
@@ -1873,6 +1938,32 @@ public:
/// \brief Set the underlying integer type.
void setIntegerType(QualType T) { IntegerType = T; }
+ /// \brief Returns the width in bits requred to store all the
+ /// non-negative enumerators of this enum.
+ unsigned getNumPositiveBits() const {
+ return NumPositiveBits;
+ }
+ void setNumPositiveBits(unsigned Num) {
+ NumPositiveBits = Num;
+ assert(NumPositiveBits == Num && "can't store this bitcount");
+ }
+
+ /// \brief Returns the width in bits requred to store all the
+ /// negative enumerators of this enum. These widths include
+ /// the rightmost leading 1; that is:
+ ///
+ /// MOST NEGATIVE ENUMERATOR PATTERN NUM NEGATIVE BITS
+ /// ------------------------ ------- -----------------
+ /// -1 1111111 1
+ /// -10 1110110 5
+ /// -101 1001011 8
+ unsigned getNumNegativeBits() const {
+ return NumNegativeBits;
+ }
+ void setNumNegativeBits(unsigned Num) {
+ NumNegativeBits = Num;
+ }
+
/// \brief Returns the enumeration (declared within the template)
/// from which this enumeration type was instantiated, or NULL if
/// this enumeration was not instantiated from any template.
@@ -1942,6 +2033,11 @@ public:
AnonymousStructOrUnion = Anon;
}
+ ValueDecl *getAnonymousStructOrUnionObject();
+ const ValueDecl *getAnonymousStructOrUnionObject() const {
+ return const_cast<RecordDecl*>(this)->getAnonymousStructOrUnionObject();
+ }
+
bool hasObjectMember() const { return HasObjectMember; }
void setHasObjectMember (bool val) { HasObjectMember = val; }
diff --git a/include/clang/AST/DeclBase.h b/include/clang/AST/DeclBase.h
index a9b948eee546..c15aeef14ba6 100644
--- a/include/clang/AST/DeclBase.h
+++ b/include/clang/AST/DeclBase.h
@@ -76,6 +76,11 @@ public:
#include "clang/AST/DeclNodes.def"
};
+ /// \brief A placeholder type used to construct an empty shell of a
+ /// decl-derived type that will be filled in later (e.g., by some
+ /// deserialization method).
+ struct EmptyShell { };
+
/// IdentifierNamespace - The different namespaces in which
/// declarations may appear. According to C99 6.2.3, there are
/// four namespaces, labels, tags, members and ordinary
diff --git a/include/clang/AST/DeclCXX.h b/include/clang/AST/DeclCXX.h
index aa649c811115..c19c200f265d 100644
--- a/include/clang/AST/DeclCXX.h
+++ b/include/clang/AST/DeclCXX.h
@@ -1061,10 +1061,6 @@ class CXXBaseOrMemberInitializer {
/// In above example, BaseOrMember holds the field decl. for anonymous union
/// and AnonUnionMember holds field decl for au_i1.
FieldDecl *AnonUnionMember;
-
- /// IsVirtual - If the initializer is a base initializer, this keeps track
- /// of whether the base is virtual or not.
- bool IsVirtual;
/// LParenLoc - Location of the left paren of the ctor-initializer.
SourceLocation LParenLoc;
@@ -1072,6 +1068,28 @@ class CXXBaseOrMemberInitializer {
/// RParenLoc - Location of the right paren of the ctor-initializer.
SourceLocation RParenLoc;
+ /// IsVirtual - If the initializer is a base initializer, this keeps track
+ /// of whether the base is virtual or not.
+ bool IsVirtual : 1;
+
+ /// IsWritten - Whether or not the initializer is explicitly written
+ /// in the sources.
+ bool IsWritten : 1;
+ /// SourceOrderOrNumArrayIndices - If IsWritten is true, then this
+ /// number keeps track of the textual order of this initializer in the
+ /// original sources, counting from 0; otherwise, if IsWritten is false,
+ /// it stores the number of array index variables stored after this
+ /// object in memory.
+ unsigned SourceOrderOrNumArrayIndices : 14;
+
+ CXXBaseOrMemberInitializer(ASTContext &Context,
+ FieldDecl *Member, SourceLocation MemberLoc,
+ SourceLocation L,
+ Expr *Init,
+ SourceLocation R,
+ VarDecl **Indices,
+ unsigned NumIndices);
+
public:
/// CXXBaseOrMemberInitializer - Creates a new base-class initializer.
explicit
@@ -1089,6 +1107,17 @@ public:
Expr *Init,
SourceLocation R);
+ /// \brief Creates a new member initializer that optionally contains
+ /// array indices used to describe an elementwise initialization.
+ static CXXBaseOrMemberInitializer *Create(ASTContext &Context,
+ FieldDecl *Member,
+ SourceLocation MemberLoc,
+ SourceLocation L,
+ Expr *Init,
+ SourceLocation R,
+ VarDecl **Indices,
+ unsigned NumIndices);
+
/// \brief Destroy the base or member initializer.
void Destroy(ASTContext &Context);
@@ -1146,6 +1175,30 @@ public:
/// \brief Determine the source range covering the entire initializer.
SourceRange getSourceRange() const;
+
+ /// isWritten - Returns true if this initializer is explicitly written
+ /// in the source code.
+ bool isWritten() const { return IsWritten; }
+
+ /// \brief Return the source position of the initializer, counting from 0.
+ /// If the initializer was implicit, -1 is returned.
+ int getSourceOrder() const {
+ return IsWritten ? static_cast<int>(SourceOrderOrNumArrayIndices) : -1;
+ }
+
+ /// \brief Set the source order of this initializer. This method can only
+ /// be called once for each initializer; it cannot be called on an
+ /// initializer having a positive number of (implicit) array indices.
+ void setSourceOrder(int pos) {
+ assert(!IsWritten &&
+ "calling twice setSourceOrder() on the same initializer");
+ assert(SourceOrderOrNumArrayIndices == 0 &&
+ "setSourceOrder() used when there are implicit array indices");
+ assert(pos >= 0 &&
+ "setSourceOrder() used to make an initializer implicit");
+ IsWritten = true;
+ SourceOrderOrNumArrayIndices = static_cast<unsigned>(pos);
+ }
FieldDecl *getAnonUnionMember() const {
return AnonUnionMember;
@@ -1154,9 +1207,31 @@ public:
AnonUnionMember = anonMember;
}
+
SourceLocation getLParenLoc() const { return LParenLoc; }
SourceLocation getRParenLoc() const { return RParenLoc; }
+ /// \brief Determine the number of implicit array indices used while
+ /// described an array member initialization.
+ unsigned getNumArrayIndices() const {
+ return IsWritten ? 0 : SourceOrderOrNumArrayIndices;
+ }
+
+ /// \brief Retrieve a particular array index variable used to
+ /// describe an array member initialization.
+ VarDecl *getArrayIndex(unsigned I) {
+ assert(I < getNumArrayIndices() && "Out of bounds member array index");
+ return reinterpret_cast<VarDecl **>(this + 1)[I];
+ }
+ const VarDecl *getArrayIndex(unsigned I) const {
+ assert(I < getNumArrayIndices() && "Out of bounds member array index");
+ return reinterpret_cast<const VarDecl * const *>(this + 1)[I];
+ }
+ void setArrayIndex(unsigned I, VarDecl *Index) {
+ assert(I < getNumArrayIndices() && "Out of bounds member array index");
+ reinterpret_cast<VarDecl **>(this + 1)[I] = Index;
+ }
+
Expr *getInit() { return static_cast<Expr *>(Init); }
};
@@ -1201,6 +1276,7 @@ class CXXConstructorDecl : public CXXMethodDecl {
virtual void Destroy(ASTContext& C);
public:
+ static CXXConstructorDecl *Create(ASTContext &C, EmptyShell Empty);
static CXXConstructorDecl *Create(ASTContext &C, CXXRecordDecl *RD,
SourceLocation L, DeclarationName N,
QualType T, TypeSourceInfo *TInfo,
@@ -1343,6 +1419,7 @@ class CXXDestructorDecl : public CXXMethodDecl {
}
public:
+ static CXXDestructorDecl *Create(ASTContext& C, EmptyShell Empty);
static CXXDestructorDecl *Create(ASTContext &C, CXXRecordDecl *RD,
SourceLocation L, DeclarationName N,
QualType T, bool isInline,
@@ -1398,6 +1475,7 @@ class CXXConversionDecl : public CXXMethodDecl {
IsExplicitSpecified(isExplicitSpecified) { }
public:
+ static CXXConversionDecl *Create(ASTContext &C, EmptyShell Empty);
static CXXConversionDecl *Create(ASTContext &C, CXXRecordDecl *RD,
SourceLocation L, DeclarationName N,
QualType T, TypeSourceInfo *TInfo,
@@ -1438,8 +1516,10 @@ public:
/// ASTs and cannot be changed without altering that abi. To help
/// ensure a stable abi for this, we choose the DW_LANG_ encodings
/// from the dwarf standard.
- enum LanguageIDs { lang_c = /* DW_LANG_C */ 0x0002,
- lang_cxx = /* DW_LANG_C_plus_plus */ 0x0004 };
+ enum LanguageIDs {
+ lang_c = /* DW_LANG_C */ 0x0002,
+ lang_cxx = /* DW_LANG_C_plus_plus */ 0x0004
+ };
private:
/// Language - The language for this linkage specification.
LanguageIDs Language;
@@ -1457,12 +1537,20 @@ public:
SourceLocation L, LanguageIDs Lang,
bool Braces);
+ /// \brief Return the language specified by this linkage specification.
LanguageIDs getLanguage() const { return Language; }
- /// hasBraces - Determines whether this linkage specification had
- /// braces in its syntactic form.
+ /// \brief Set the language specified by this linkage specification.
+ void setLanguage(LanguageIDs L) { Language = L; }
+
+ /// \brief Determines whether this linkage specification had braces in
+ /// its syntactic form.
bool hasBraces() const { return HadBraces; }
+ /// \brief Set whether this linkage specification has braces in its
+ /// syntactic form.
+ void setHasBraces(bool B) { HadBraces = B; }
+
static bool classof(const Decl *D) { return classofKind(D->getKind()); }
static bool classof(const LinkageSpecDecl *D) { return true; }
static bool classofKind(Kind K) { return K == LinkageSpec; }
@@ -1528,13 +1616,21 @@ class UsingDirectiveDecl : public NamedDecl {
public:
/// \brief Retrieve the source range of the nested-name-specifier
- /// that qualifiers the namespace name.
+ /// that qualifies the namespace name.
SourceRange getQualifierRange() const { return QualifierRange; }
+ /// \brief Set the source range of the nested-name-specifier that
+ /// qualifies the namespace name.
+ void setQualifierRange(SourceRange R) { QualifierRange = R; }
+
/// \brief Retrieve the nested-name-specifier that qualifies the
/// name of the namespace.
NestedNameSpecifier *getQualifier() const { return Qualifier; }
+ /// \brief Set the nested-name-specifier that qualifes the name of the
+ /// namespace.
+ void setQualifier(NestedNameSpecifier *NNS) { Qualifier = NNS; }
+
NamedDecl *getNominatedNamespaceAsWritten() { return NominatedNamespace; }
const NamedDecl *getNominatedNamespaceAsWritten() const {
return NominatedNamespace;
@@ -1547,17 +1643,32 @@ public:
return const_cast<UsingDirectiveDecl*>(this)->getNominatedNamespace();
}
- /// getCommonAncestor - returns common ancestor context of using-directive,
- /// and nominated by it namespace.
+ /// setNominatedNamespace - Set the namespace nominataed by the
+ /// using-directive.
+ void setNominatedNamespace(NamedDecl* NS);
+
+ /// \brief Returns the common ancestor context of this using-directive and
+ /// its nominated namespace.
DeclContext *getCommonAncestor() { return CommonAncestor; }
const DeclContext *getCommonAncestor() const { return CommonAncestor; }
+ /// \brief Set the common ancestor context of this using-directive and its
+ /// nominated namespace.
+ void setCommonAncestor(DeclContext* Cxt) { CommonAncestor = Cxt; }
+
+ // FIXME: Could omit 'Key' in name.
/// getNamespaceKeyLocation - Returns location of namespace keyword.
SourceLocation getNamespaceKeyLocation() const { return NamespaceLoc; }
+ /// setNamespaceKeyLocation - Set the the location of the namespacekeyword.
+ void setNamespaceKeyLocation(SourceLocation L) { NamespaceLoc = L; }
+
/// getIdentLocation - Returns location of identifier.
SourceLocation getIdentLocation() const { return IdentLoc; }
+ /// setIdentLocation - set the location of the identifier.
+ void setIdentLocation(SourceLocation L) { IdentLoc = L; }
+
static UsingDirectiveDecl *Create(ASTContext &C, DeclContext *DC,
SourceLocation L,
SourceLocation NamespaceLoc,
@@ -1591,7 +1702,7 @@ class NamespaceAliasDecl : public NamedDecl {
/// name, if any.
NestedNameSpecifier *Qualifier;
- /// IdentLoc - Location of namespace identifier.
+ /// IdentLoc - Location of namespace identifier. Accessed by TargetNameLoc.
SourceLocation IdentLoc;
/// Namespace - The Decl that this alias points to. Can either be a
@@ -1612,10 +1723,19 @@ public:
/// that qualifiers the namespace name.
SourceRange getQualifierRange() const { return QualifierRange; }
+ /// \brief Set the source range of the nested-name-specifier that qualifies
+ /// the namespace name.
+ void setQualifierRange(SourceRange R) { QualifierRange = R; }
+
/// \brief Retrieve the nested-name-specifier that qualifies the
/// name of the namespace.
NestedNameSpecifier *getQualifier() const { return Qualifier; }
+ /// \brief Set the nested-name-specifier that qualifies the name of the
+ /// namespace.
+ void setQualifier(NestedNameSpecifier *NNS) { Qualifier = NNS; }
+
+ /// \brief Retrieve the namespace declaration aliased by this directive.
NamespaceDecl *getNamespace() {
if (NamespaceAliasDecl *AD = dyn_cast<NamespaceAliasDecl>(Namespace))
return AD->getNamespace();
@@ -1631,16 +1751,31 @@ public:
/// "namespace foo = ns::bar;".
SourceLocation getAliasLoc() const { return AliasLoc; }
+ /// Set the location o;f the alias name, e.e., 'foo' in
+ /// "namespace foo = ns::bar;".
+ void setAliasLoc(SourceLocation L) { AliasLoc = L; }
+
/// Returns the location of the 'namespace' keyword.
SourceLocation getNamespaceLoc() const { return getLocation(); }
/// Returns the location of the identifier in the named namespace.
SourceLocation getTargetNameLoc() const { return IdentLoc; }
+ /// Set the location of the identifier in the named namespace.
+ void setTargetNameLoc(SourceLocation L) { IdentLoc = L; }
+
/// \brief Retrieve the namespace that this alias refers to, which
/// may either be a NamespaceDecl or a NamespaceAliasDecl.
NamedDecl *getAliasedNamespace() const { return Namespace; }
+ /// \brief Set the namespace or namespace alias pointed to by this
+ /// alias decl.
+ void setAliasedNamespace(NamedDecl *ND) {
+ assert((isa<NamespaceAliasDecl>(ND) || isa<NamespaceDecl>(ND)) &&
+ "expecting namespace or namespace alias decl");
+ Namespace = ND;
+ }
+
static NamespaceAliasDecl *Create(ASTContext &C, DeclContext *DC,
SourceLocation L, SourceLocation AliasLoc,
IdentifierInfo *Alias,
@@ -1687,16 +1822,20 @@ public:
return new (C) UsingShadowDecl(DC, Loc, Using, Target);
}
- /// Gets the underlying declaration which has been brought into the
+ /// \brief Gets the underlying declaration which has been brought into the
/// local scope.
- NamedDecl *getTargetDecl() const {
- return Underlying;
- }
+ NamedDecl *getTargetDecl() const { return Underlying; }
- /// Gets the using declaration to which this declaration is tied.
- UsingDecl *getUsingDecl() const {
- return Using;
- }
+ /// \brief Sets the underlying declaration which has been brought into the
+ /// local scope.
+ void setTargetDecl(NamedDecl* ND) { Underlying = ND; }
+
+ /// \brief Gets the using declaration to which this declaration is tied.
+ UsingDecl *getUsingDecl() const { return Using; }
+
+ /// \brief Sets the using declaration that introduces this target
+ /// declaration.
+ void setUsingDecl(UsingDecl* UD) { Using = UD; }
static bool classof(const Decl *D) { return classofKind(D->getKind()); }
static bool classof(const UsingShadowDecl *D) { return true; }
@@ -1733,21 +1872,39 @@ class UsingDecl : public NamedDecl {
}
public:
+ // FIXME: Should be const?
/// \brief Returns the source range that covers the nested-name-specifier
/// preceding the namespace name.
SourceRange getNestedNameRange() { return NestedNameRange; }
- /// \brief Returns the source location of the "using" location itself.
+ /// \brief Set the source range of the nested-name-specifier.
+ void setNestedNameRange(SourceRange R) { NestedNameRange = R; }
+
+ // FIXME; Should be const?
+ // FIXME: Naming is inconsistent with other get*Loc functions.
+ /// \brief Returns the source location of the "using" keyword.
SourceLocation getUsingLocation() { return UsingLocation; }
- /// \brief Get target nested name declaration.
+ /// \brief Set the source location of the 'using' keyword.
+ void setUsingLocation(SourceLocation L) { UsingLocation = L; }
+
+
+ /// \brief Get the target nested name declaration.
NestedNameSpecifier* getTargetNestedNameDecl() {
return TargetNestedName;
}
- /// isTypeName - Return true if using decl has 'typename'.
+ /// \brief Set the target nested name declaration.
+ void setTargetNestedNameDecl(NestedNameSpecifier *NNS) {
+ TargetNestedName = NNS;
+ }
+
+ /// \brief Return true if the using declaration has 'typename'.
bool isTypeName() const { return IsTypeName; }
+ /// \brief Sets whether the using declaration has 'typename'.
+ void setTypeName(bool TN) { IsTypeName = TN; }
+
typedef llvm::SmallPtrSet<UsingShadowDecl*,8>::const_iterator shadow_iterator;
shadow_iterator shadow_begin() const { return Shadows.begin(); }
shadow_iterator shadow_end() const { return Shadows.end(); }
@@ -1765,6 +1922,12 @@ public:
}
}
+ /// \brief Return the number of shadowed declarations associated with this
+ /// using declaration.
+ unsigned getNumShadowDecls() const {
+ return Shadows.size();
+ }
+
static UsingDecl *Create(ASTContext &C, DeclContext *DC,
SourceLocation IdentL, SourceRange NNR, SourceLocation UsingL,
NestedNameSpecifier* TargetNNS, DeclarationName Name, bool IsTypeNameArg);
@@ -1807,14 +1970,26 @@ public:
/// preceding the namespace name.
SourceRange getTargetNestedNameRange() const { return TargetNestedNameRange; }
+ /// \brief Set the source range coverting the nested-name-specifier preceding
+ /// the namespace name.
+ void setTargetNestedNameRange(SourceRange R) { TargetNestedNameRange = R; }
+
/// \brief Get target nested name declaration.
NestedNameSpecifier* getTargetNestedNameSpecifier() {
return TargetNestedNameSpecifier;
}
+ /// \brief Set the nested name declaration.
+ void setTargetNestedNameSpecifier(NestedNameSpecifier* NNS) {
+ TargetNestedNameSpecifier = NNS;
+ }
+
/// \brief Returns the source location of the 'using' keyword.
SourceLocation getUsingLoc() const { return UsingLocation; }
+ /// \brief Set the source location of the 'using' keyword.
+ void setUsingLoc(SourceLocation L) { UsingLocation = L; }
+
static UnresolvedUsingValueDecl *
Create(ASTContext &C, DeclContext *DC, SourceLocation UsingLoc,
SourceRange TargetNNR, NestedNameSpecifier *TargetNNS,
@@ -1861,17 +2036,32 @@ public:
/// preceding the namespace name.
SourceRange getTargetNestedNameRange() const { return TargetNestedNameRange; }
+ /// \brief Set the source range coverting the nested-name-specifier preceding
+ /// the namespace name.
+ void setTargetNestedNameRange(SourceRange R) { TargetNestedNameRange = R; }
+
/// \brief Get target nested name declaration.
NestedNameSpecifier* getTargetNestedNameSpecifier() {
return TargetNestedNameSpecifier;
}
+ /// \brief Set the nested name declaration.
+ void setTargetNestedNameSpecifier(NestedNameSpecifier* NNS) {
+ TargetNestedNameSpecifier = NNS;
+ }
+
/// \brief Returns the source location of the 'using' keyword.
SourceLocation getUsingLoc() const { return UsingLocation; }
+ /// \brief Set the source location of the 'using' keyword.
+ void setUsingLoc(SourceLocation L) { UsingLocation = L; }
+
/// \brief Returns the source location of the 'typename' keyword.
SourceLocation getTypenameLoc() const { return TypenameLocation; }
+ /// \brief Set the source location of the 'typename' keyword.
+ void setTypenameLoc(SourceLocation L) { TypenameLocation = L; }
+
static UnresolvedUsingTypenameDecl *
Create(ASTContext &C, DeclContext *DC, SourceLocation UsingLoc,
SourceLocation TypenameLoc,
diff --git a/include/clang/AST/DeclContextInternals.h b/include/clang/AST/DeclContextInternals.h
index 2a4b12ac2eaf..9602b677fca5 100644
--- a/include/clang/AST/DeclContextInternals.h
+++ b/include/clang/AST/DeclContextInternals.h
@@ -156,7 +156,8 @@ public:
/// represents.
DeclContext::lookup_result getLookupResult(ASTContext &Context) {
if (isNull())
- return DeclContext::lookup_result(0, 0);
+ return DeclContext::lookup_result(DeclContext::lookup_iterator(0),
+ DeclContext::lookup_iterator(0));
if (hasDeclarationIDs())
materializeDecls(Context);
diff --git a/include/clang/AST/DeclObjC.h b/include/clang/AST/DeclObjC.h
index e34ec9ffcdf0..97d165696aad 100644
--- a/include/clang/AST/DeclObjC.h
+++ b/include/clang/AST/DeclObjC.h
@@ -1421,13 +1421,21 @@ private:
/// Null for @dynamic. Required for @synthesize.
ObjCIvarDecl *PropertyIvarDecl;
+
+ /// Null for @dynamic. Non-null if property must be copy-constructed in getter
+ Expr *GetterCXXConstructor;
+
+ /// Null for @dynamic. Non-null if property has assignment operator to call
+ /// in Setter synthesis.
+ Expr *SetterCXXAssignment;
ObjCPropertyImplDecl(DeclContext *DC, SourceLocation atLoc, SourceLocation L,
ObjCPropertyDecl *property,
Kind PK,
ObjCIvarDecl *ivarDecl)
: Decl(ObjCPropertyImpl, DC, L), AtLoc(atLoc),
- PropertyDecl(property), PropertyIvarDecl(ivarDecl) {
+ PropertyDecl(property), PropertyIvarDecl(ivarDecl),
+ GetterCXXConstructor(0), SetterCXXAssignment(0) {
assert (PK == Dynamic || PropertyIvarDecl);
}
@@ -1457,7 +1465,21 @@ public:
return PropertyIvarDecl;
}
void setPropertyIvarDecl(ObjCIvarDecl *Ivar) { PropertyIvarDecl = Ivar; }
+
+ Expr *getGetterCXXConstructor() const {
+ return GetterCXXConstructor;
+ }
+ void setGetterCXXConstructor(Expr *getterCXXConstructor) {
+ GetterCXXConstructor = getterCXXConstructor;
+ }
+ Expr *getSetterCXXAssignment() const {
+ return SetterCXXAssignment;
+ }
+ void setSetterCXXAssignment(Expr *setterCXXAssignment) {
+ SetterCXXAssignment = setterCXXAssignment;
+ }
+
static bool classof(const Decl *D) { return classofKind(D->getKind()); }
static bool classof(const ObjCPropertyImplDecl *D) { return true; }
static bool classofKind(Decl::Kind K) { return K == ObjCPropertyImpl; }
diff --git a/include/clang/AST/DeclTemplate.h b/include/clang/AST/DeclTemplate.h
index 1ec38bacb51f..b7b90b14adfd 100644
--- a/include/clang/AST/DeclTemplate.h
+++ b/include/clang/AST/DeclTemplate.h
@@ -112,7 +112,7 @@ class TemplateArgumentListBuilder {
unsigned MaxStructuredArgs;
unsigned NumStructuredArgs;
- TemplateArgument *FlatArgs;
+ llvm::SmallVector<TemplateArgument, 4> FlatArgs;
unsigned MaxFlatArgs;
unsigned NumFlatArgs;
@@ -127,18 +127,12 @@ public:
MaxFlatArgs(std::max(MaxStructuredArgs, NumTemplateArgs)), NumFlatArgs(0),
AddingToPack(false), PackBeginIndex(0) { }
- void Append(const TemplateArgument& Arg);
+ void Append(const TemplateArgument &Arg);
void BeginPack();
void EndPack();
- void ReleaseArgs();
-
- unsigned flatSize() const {
- return NumFlatArgs;
- }
- const TemplateArgument *getFlatArguments() const {
- return FlatArgs;
- }
+ unsigned flatSize() const { return FlatArgs.size(); }
+ const TemplateArgument *getFlatArguments() const { return FlatArgs.data(); }
unsigned structuredSize() const {
// If we don't have any structured args, just reuse the flat size.
@@ -165,7 +159,7 @@ class TemplateArgumentList {
/// \brief The template argument list.
///
/// The integer value will be non-zero to indicate that this
- /// template argument list does not own the pointer.
+ /// template argument list does own the pointer.
llvm::PointerIntPair<const TemplateArgument *, 1> FlatArguments;
/// \brief The number of template arguments in this template
@@ -175,14 +169,28 @@ class TemplateArgumentList {
llvm::PointerIntPair<const TemplateArgument *, 1> StructuredArguments;
unsigned NumStructuredArguments;
+ TemplateArgumentList(const TemplateArgumentList &Other); // DO NOT IMPL
+ void operator=(const TemplateArgumentList &Other); // DO NOT IMPL
public:
+ /// TemplateArgumentList - If this constructor is passed "true" for 'TakeArgs'
+ /// it copies them into a locally new[]'d array. If passed "false", then it
+ /// just references the array passed in. This is only safe if the builder
+ /// outlives it, but saves a copy.
TemplateArgumentList(ASTContext &Context,
TemplateArgumentListBuilder &Builder,
bool TakeArgs);
- /// \brief Produces a shallow copy of the given template argument list
- TemplateArgumentList(const TemplateArgumentList &Other);
+ /// Produces a shallow copy of the given template argument list. This
+ /// assumes that the input argument list outlives it. This takes the list as
+ /// a pointer to avoid looking like a copy constructor, since this really
+ /// really isn't safe to use that way.
+ explicit TemplateArgumentList(const TemplateArgumentList *Other);
+ /// Used to release the memory associated with a TemplateArgumentList
+ /// object. FIXME: This is currently not called anywhere, but the
+ /// memory will still be freed when using a BumpPtrAllocator.
+ void Destroy(ASTContext &C);
+
~TemplateArgumentList();
/// \brief Retrieve the template argument at a given index.
@@ -280,6 +288,9 @@ public:
/// specialization from the function template.
const TemplateArgumentList *TemplateArguments;
+ /// \brief The template arguments as written in the sources, if provided.
+ const TemplateArgumentListInfo *TemplateArgumentsAsWritten;
+
/// \brief The point at which this function template specialization was
/// first instantiated.
SourceLocation PointOfInstantiation;
@@ -454,6 +465,8 @@ public:
/// Declaration of a template function.
class FunctionTemplateDecl : public TemplateDecl {
+ static void DeallocateCommon(void *Ptr);
+
protected:
/// \brief Data that is common to all of the declarations of a given
/// function template.
@@ -862,7 +875,7 @@ class ClassTemplateSpecializationDecl
unsigned SpecializationKind : 3;
protected:
- ClassTemplateSpecializationDecl(ASTContext &Context, Kind DK,
+ ClassTemplateSpecializationDecl(ASTContext &Context, Kind DK, TagKind TK,
DeclContext *DC, SourceLocation L,
ClassTemplateDecl *SpecializedTemplate,
TemplateArgumentListBuilder &Builder,
@@ -870,7 +883,7 @@ protected:
public:
static ClassTemplateSpecializationDecl *
- Create(ASTContext &Context, DeclContext *DC, SourceLocation L,
+ Create(ASTContext &Context, TagKind TK, DeclContext *DC, SourceLocation L,
ClassTemplateDecl *SpecializedTemplate,
TemplateArgumentListBuilder &Builder,
ClassTemplateSpecializationDecl *PrevDecl);
@@ -1024,7 +1037,7 @@ class ClassTemplatePartialSpecializationDecl
llvm::PointerIntPair<ClassTemplatePartialSpecializationDecl *, 1, bool>
InstantiatedFromMember;
- ClassTemplatePartialSpecializationDecl(ASTContext &Context,
+ ClassTemplatePartialSpecializationDecl(ASTContext &Context, TagKind TK,
DeclContext *DC, SourceLocation L,
TemplateParameterList *Params,
ClassTemplateDecl *SpecializedTemplate,
@@ -1035,7 +1048,7 @@ class ClassTemplatePartialSpecializationDecl
unsigned SequenceNumber)
: ClassTemplateSpecializationDecl(Context,
ClassTemplatePartialSpecialization,
- DC, L, SpecializedTemplate, Builder,
+ TK, DC, L, SpecializedTemplate, Builder,
PrevDecl),
TemplateParams(Params), ArgsAsWritten(ArgInfos),
NumArgsAsWritten(NumArgInfos), SequenceNumber(SequenceNumber),
@@ -1043,7 +1056,7 @@ class ClassTemplatePartialSpecializationDecl
public:
static ClassTemplatePartialSpecializationDecl *
- Create(ASTContext &Context, DeclContext *DC, SourceLocation L,
+ Create(ASTContext &Context, TagKind TK,DeclContext *DC, SourceLocation L,
TemplateParameterList *Params,
ClassTemplateDecl *SpecializedTemplate,
TemplateArgumentListBuilder &Builder,
@@ -1158,6 +1171,8 @@ public:
/// Declaration of a class template.
class ClassTemplateDecl : public TemplateDecl {
+ static void DeallocateCommon(void *Ptr);
+
protected:
/// \brief Data that is common to all of the declarations of a given
/// class template.
diff --git a/include/clang/AST/DeclarationName.h b/include/clang/AST/DeclarationName.h
index 94017865d4c6..8a771d513c42 100644
--- a/include/clang/AST/DeclarationName.h
+++ b/include/clang/AST/DeclarationName.h
@@ -314,15 +314,16 @@ inline bool operator>=(DeclarationName LHS, DeclarationName RHS) {
/// retrieved using its member functions (e.g.,
/// getCXXConstructorName).
class DeclarationNameTable {
+ ASTContext &Ctx;
void *CXXSpecialNamesImpl; // Actually a FoldingSet<CXXSpecialName> *
CXXOperatorIdName *CXXOperatorNames; // Operator names
- void *CXXLiteralOperatorNames; // Actually a FoldingSet<...> *
+ void *CXXLiteralOperatorNames; // Actually a CXXOperatorIdName*
DeclarationNameTable(const DeclarationNameTable&); // NONCOPYABLE
DeclarationNameTable& operator=(const DeclarationNameTable&); // NONCOPYABLE
public:
- DeclarationNameTable();
+ DeclarationNameTable(ASTContext &C);
~DeclarationNameTable();
/// getIdentifier - Create a declaration name that is a simple
diff --git a/include/clang/AST/Expr.h b/include/clang/AST/Expr.h
index 2946e464a7cf..66639e2ef733 100644
--- a/include/clang/AST/Expr.h
+++ b/include/clang/AST/Expr.h
@@ -51,6 +51,7 @@ typedef UsuallyTinyPtrVector<const CXXBaseSpecifier> CXXBaseSpecifierArray;
class Expr : public Stmt {
QualType TR;
+ virtual void ANCHOR(); // key function.
protected:
/// TypeDependent - Whether this expression is type-dependent
/// (C++ [temp.dep.expr]).
@@ -247,6 +248,15 @@ public:
SourceLocation DiagLoc;
EvalResult() : HasSideEffects(false), Diag(0), DiagExpr(0) {}
+
+ // isGlobalLValue - Return true if the evaluated lvalue expression
+ // is global.
+ bool isGlobalLValue() const;
+ // hasSideEffects - Return true if the evaluated expression has
+ // side effects.
+ bool hasSideEffects() const {
+ return HasSideEffects;
+ }
};
/// Evaluate - Return true if this is a constant which we can fold using
@@ -255,10 +265,6 @@ public:
/// in Result.
bool Evaluate(EvalResult &Result, ASTContext &Ctx) const;
- /// EvaluateAsAny - The same as Evaluate, except that it also succeeds on
- /// stack based objects.
- bool EvaluateAsAny(EvalResult &Result, ASTContext &Ctx) const;
-
/// EvaluateAsBooleanCondition - Return true if this is a constant
/// which we we can fold and convert to a boolean condition using
/// any crazy technique that we want to.
@@ -282,8 +288,7 @@ public:
/// with link time known address.
bool EvaluateAsLValue(EvalResult &Result, ASTContext &Ctx) const;
- /// EvaluateAsAnyLValue - The same as EvaluateAsLValue, except that it
- /// also succeeds on stack based, immutable address lvalues.
+ /// EvaluateAsLValue - Evaluate an expression to see if it's a lvalue.
bool EvaluateAsAnyLValue(EvalResult &Result, ASTContext &Ctx) const;
/// \brief Enumeration used to describe how \c isNullPointerConstant()
@@ -321,6 +326,10 @@ public:
/// or CastExprs, returning their operand.
Expr *IgnoreParenCasts();
+ /// IgnoreParenImpCasts - Ignore parentheses and implicit casts. Strip off any
+ /// ParenExpr or ImplicitCastExprs, returning their operand.
+ Expr *IgnoreParenImpCasts();
+
/// IgnoreParenNoopCasts - Ignore parentheses and casts that do not change the
/// value (including ptr->int casts of the same size). Strip off any
/// ParenExpr or CastExprs, returning their operand.
@@ -1468,13 +1477,10 @@ public:
}
static bool classof(const Stmt *T) {
- return T->getStmtClass() == CallExprClass ||
- T->getStmtClass() == CXXOperatorCallExprClass ||
- T->getStmtClass() == CXXMemberCallExprClass;
+ return T->getStmtClass() >= firstCallExprConstant &&
+ T->getStmtClass() <= lastCallExprConstant;
}
static bool classof(const CallExpr *) { return true; }
- static bool classof(const CXXOperatorCallExpr *) { return true; }
- static bool classof(const CXXMemberCallExpr *) { return true; }
// Iterators
virtual child_iterator child_begin();
@@ -1933,14 +1939,8 @@ public:
const CXXBaseSpecifierArray& getBasePath() const { return BasePath; }
static bool classof(const Stmt *T) {
- StmtClass SC = T->getStmtClass();
- if (SC >= CXXStaticCastExprClass && SC <= CXXFunctionalCastExprClass)
- return true;
-
- if (SC >= ImplicitCastExprClass && SC <= CStyleCastExprClass)
- return true;
-
- return false;
+ return T->getStmtClass() >= firstCastExprConstant &&
+ T->getStmtClass() <= lastCastExprConstant;
}
static bool classof(const CastExpr *) { return true; }
@@ -2037,13 +2037,8 @@ public:
QualType getTypeAsWritten() const { return TInfo->getType(); }
static bool classof(const Stmt *T) {
- StmtClass SC = T->getStmtClass();
- if (SC >= CStyleCastExprClass && SC <= CStyleCastExprClass)
- return true;
- if (SC >= CXXStaticCastExprClass && SC <= CXXFunctionalCastExprClass)
- return true;
-
- return false;
+ return T->getStmtClass() >= firstExplicitCastExprConstant &&
+ T->getStmtClass() <= lastExplicitCastExprConstant;
}
static bool classof(const ExplicitCastExpr *) { return true; }
};
@@ -2198,8 +2193,8 @@ public:
bool isShiftAssignOp() const { return Opc == ShlAssign || Opc == ShrAssign; }
static bool classof(const Stmt *S) {
- return S->getStmtClass() == BinaryOperatorClass ||
- S->getStmtClass() == CompoundAssignOperatorClass;
+ return S->getStmtClass() >= firstBinaryOperatorConstant &&
+ S->getStmtClass() <= lastBinaryOperatorConstant;
}
static bool classof(const BinaryOperator *) { return true; }
diff --git a/include/clang/AST/ExprCXX.h b/include/clang/AST/ExprCXX.h
index f9ca78ad292d..0c493f36df09 100644
--- a/include/clang/AST/ExprCXX.h
+++ b/include/clang/AST/ExprCXX.h
@@ -88,10 +88,13 @@ public:
/// the object argument).
class CXXMemberCallExpr : public CallExpr {
public:
- CXXMemberCallExpr(ASTContext& C, Expr *fn, Expr **args, unsigned numargs,
+ CXXMemberCallExpr(ASTContext &C, Expr *fn, Expr **args, unsigned numargs,
QualType t, SourceLocation rparenloc)
: CallExpr(C, CXXMemberCallExprClass, fn, args, numargs, t, rparenloc) {}
+ CXXMemberCallExpr(ASTContext &C, EmptyShell Empty)
+ : CallExpr(C, CXXMemberCallExprClass, Empty) { }
+
/// getImplicitObjectArgument - Retrieves the implicit object
/// argument for the member call. For example, in "x.f(5)", this
/// operation would return "x".
@@ -318,6 +321,14 @@ public:
Operand->isTypeDependent() || Operand->isValueDependent()),
Operand(Operand), Range(R) { }
+ CXXTypeidExpr(EmptyShell Empty, bool isExpr)
+ : Expr(CXXTypeidExprClass, Empty) {
+ if (isExpr)
+ Operand = (Expr*)0;
+ else
+ Operand = (TypeSourceInfo*)0;
+ }
+
bool isTypeOperand() const { return Operand.is<TypeSourceInfo *>(); }
/// \brief Retrieves the type operand of this typeid() expression after
@@ -329,15 +340,25 @@ public:
assert(isTypeOperand() && "Cannot call getTypeOperand for typeid(expr)");
return Operand.get<TypeSourceInfo *>();
}
+
+ void setTypeOperandSourceInfo(TypeSourceInfo *TSI) {
+ assert(isTypeOperand() && "Cannot call getTypeOperand for typeid(expr)");
+ Operand = TSI;
+ }
- Expr* getExprOperand() const {
+ Expr *getExprOperand() const {
assert(!isTypeOperand() && "Cannot call getExprOperand for typeid(type)");
return static_cast<Expr*>(Operand.get<Stmt *>());
}
-
- virtual SourceRange getSourceRange() const {
- return Range;
+
+ void setExprOperand(Expr *E) {
+ assert(!isTypeOperand() && "Cannot call getExprOperand for typeid(type)");
+ Operand = E;
}
+
+ virtual SourceRange getSourceRange() const { return Range; }
+ void setSourceRange(SourceRange R) { Range = R; }
+
static bool classof(const Stmt *T) {
return T->getStmtClass() == CXXTypeidExprClass;
}
@@ -371,6 +392,11 @@ public:
Type->isDependentType(), Type->isDependentType()),
Loc(L), Implicit(isImplicit) { }
+ CXXThisExpr(EmptyShell Empty) : Expr(CXXThisExprClass, Empty) {}
+
+ SourceLocation getLocation() const { return Loc; }
+ void setLocation(SourceLocation L) { Loc = L; }
+
virtual SourceRange getSourceRange() const { return SourceRange(Loc); }
bool isImplicit() const { return Implicit; }
@@ -399,6 +425,8 @@ public:
// can by null, if the optional expression to throw isn't present.
CXXThrowExpr(Expr *expr, QualType Ty, SourceLocation l) :
Expr(CXXThrowExprClass, Ty, false, false), Op(expr), ThrowLoc(l) {}
+ CXXThrowExpr(EmptyShell Empty) : Expr(CXXThrowExprClass, Empty) {}
+
const Expr *getSubExpr() const { return cast_or_null<Expr>(Op); }
Expr *getSubExpr() { return cast_or_null<Expr>(Op); }
void setSubExpr(Expr *E) { Op = E; }
@@ -448,8 +476,7 @@ protected:
CXXDefaultArgExpr(StmtClass SC, SourceLocation Loc, ParmVarDecl *param,
Expr *SubExpr)
- : Expr(SC, SubExpr->getType(), false, false), Param(param, true), Loc(Loc)
- {
+ : Expr(SC, SubExpr->getType(), false, false), Param(param, true), Loc(Loc) {
*reinterpret_cast<Expr **>(this + 1) = SubExpr;
}
@@ -457,6 +484,9 @@ protected:
virtual void DoDestroy(ASTContext &C);
public:
+ CXXDefaultArgExpr(EmptyShell Empty) : Expr(CXXDefaultArgExprClass, Empty) {}
+
+
// Param is the parameter whose default argument is used by this
// expression.
static CXXDefaultArgExpr *Create(ASTContext &C, SourceLocation Loc,
@@ -475,6 +505,9 @@ public:
const ParmVarDecl *getParam() const { return Param.getPointer(); }
ParmVarDecl *getParam() { return Param.getPointer(); }
+ /// isExprStored - Return true if this expression owns the expression.
+ bool isExprStored() const { return Param.getInt(); }
+
// Retrieve the actual argument to the function call.
const Expr *getExpr() const {
if (Param.getInt())
@@ -486,10 +519,16 @@ public:
return *reinterpret_cast<Expr **> (this + 1);
return getParam()->getDefaultArg();
}
+
+ void setExpr(Expr *E) {
+ Param.setInt(true);
+ Param.setPointer((ParmVarDecl*)E);
+ }
/// \brief Retrieve the location where this default argument was actually
/// used.
SourceLocation getUsedLocation() const { return Loc; }
+ void setUsedLocation(SourceLocation L) { Loc = L; }
virtual SourceRange getSourceRange() const {
// Default argument expressions have no representation in the
@@ -525,8 +564,20 @@ public:
const CXXDestructorDecl *getDestructor() const { return Destructor; }
};
-/// CXXBindTemporaryExpr - Represents binding an expression to a temporary,
-/// so its destructor can be called later.
+/// \brief Represents binding an expression to a temporary.
+///
+/// This ensures the destructor is called for the temporary. It should only be
+/// needed for non-POD, non-trivially destructable class types. For example:
+///
+/// \code
+/// struct S {
+/// S() { } // User defined constructor makes S non-POD.
+/// ~S() { } // User defined destructor makes it non-trivial.
+/// };
+/// void test() {
+/// const S &s_ref = S(); // Requires a CXXBindTemporaryExpr.
+/// }
+/// \endcode
class CXXBindTemporaryExpr : public Expr {
CXXTemporary *Temp;
@@ -541,11 +592,15 @@ protected:
virtual void DoDestroy(ASTContext &C);
public:
+ CXXBindTemporaryExpr(EmptyShell Empty)
+ : Expr(CXXBindTemporaryExprClass, Empty), Temp(0), SubExpr(0) {}
+
static CXXBindTemporaryExpr *Create(ASTContext &C, CXXTemporary *Temp,
Expr* SubExpr);
CXXTemporary *getTemporary() { return Temp; }
const CXXTemporary *getTemporary() const { return Temp; }
+ void setTemporary(CXXTemporary *T) { Temp = T; }
const Expr *getSubExpr() const { return cast<Expr>(SubExpr); }
Expr *getSubExpr() { return cast<Expr>(SubExpr); }
@@ -572,8 +627,8 @@ public:
/// const int &i = 10;
///
/// a bind reference expression is inserted to indicate that 10 is bound to
-/// a reference. (Ans also that a temporary needs to be created to hold the
-/// value).
+/// a reference, and that a temporary needs to be created to hold the
+/// value.
class CXXBindReferenceExpr : public Expr {
// SubExpr - The expression being bound.
Stmt *SubExpr;
@@ -827,10 +882,15 @@ public:
SourceLocation rParenLoc ) :
Expr(CXXZeroInitValueExprClass, ty, false, false),
TyBeginLoc(tyBeginLoc), RParenLoc(rParenLoc) {}
+ explicit CXXZeroInitValueExpr(EmptyShell Shell)
+ : Expr(CXXZeroInitValueExprClass, Shell) { }
SourceLocation getTypeBeginLoc() const { return TyBeginLoc; }
SourceLocation getRParenLoc() const { return RParenLoc; }
+ void setTypeBeginLoc(SourceLocation L) { TyBeginLoc = L; }
+ void setRParenLoc(SourceLocation L) { RParenLoc = L; }
+
/// @brief Whether this initialization expression was
/// implicitly-generated.
bool isImplicit() const {
@@ -891,6 +951,11 @@ public:
Expr **constructorArgs, unsigned numConsArgs,
FunctionDecl *operatorDelete, QualType ty,
SourceLocation startLoc, SourceLocation endLoc);
+ explicit CXXNewExpr(EmptyShell Shell)
+ : Expr(CXXNewExprClass, Shell), SubExprs(0) { }
+
+ void AllocateArgsArray(ASTContext &C, bool isArray, unsigned numPlaceArgs,
+ unsigned numConsArgs);
virtual void DoDestroy(ASTContext &C);
@@ -900,8 +965,11 @@ public:
}
FunctionDecl *getOperatorNew() const { return OperatorNew; }
+ void setOperatorNew(FunctionDecl *D) { OperatorNew = D; }
FunctionDecl *getOperatorDelete() const { return OperatorDelete; }
+ void setOperatorDelete(FunctionDecl *D) { OperatorDelete = D; }
CXXConstructorDecl *getConstructor() const { return Constructor; }
+ void setConstructor(CXXConstructorDecl *D) { Constructor = D; }
bool isArray() const { return Array; }
Expr *getArraySize() {
@@ -922,8 +990,11 @@ public:
}
bool isGlobalNew() const { return GlobalNew; }
+ void setGlobalNew(bool V) { GlobalNew = V; }
bool isParenTypeId() const { return ParenTypeId; }
+ void setParenTypeId(bool V) { ParenTypeId = V; }
bool hasInitializer() const { return Initializer; }
+ void setHasInitializer(bool V) { Initializer = V; }
unsigned getNumConstructorArgs() const { return NumConstructorArgs; }
Expr *getConstructorArg(unsigned i) {
@@ -963,7 +1034,21 @@ public:
const_arg_iterator constructor_arg_end() const {
return SubExprs + Array + getNumPlacementArgs() + getNumConstructorArgs();
}
+
+ typedef Stmt **raw_arg_iterator;
+ raw_arg_iterator raw_arg_begin() { return SubExprs; }
+ raw_arg_iterator raw_arg_end() {
+ return SubExprs + Array + getNumPlacementArgs() + getNumConstructorArgs();
+ }
+ const_arg_iterator raw_arg_begin() const { return SubExprs; }
+ const_arg_iterator raw_arg_end() const { return constructor_arg_end(); }
+
+ SourceLocation getStartLoc() const { return StartLoc; }
+ void setStartLoc(SourceLocation L) { StartLoc = L; }
+ SourceLocation getEndLoc() const { return EndLoc; }
+ void setEndLoc(SourceLocation L) { EndLoc = L; }
+
virtual SourceRange getSourceRange() const {
return SourceRange(StartLoc, EndLoc);
}
@@ -1260,7 +1345,9 @@ class OverloadExpr : public Expr {
/// The results. These are undesugared, which is to say, they may
/// include UsingShadowDecls. Access is relative to the naming
/// class.
- UnresolvedSet<4> Results;
+ // FIXME: Allocate this data after the OverloadExpr subclass.
+ DeclAccessPair *Results;
+ unsigned NumResults;
/// The common name of these declarations.
DeclarationName Name;
@@ -1278,14 +1365,11 @@ class OverloadExpr : public Expr {
bool HasExplicitTemplateArgs;
protected:
- OverloadExpr(StmtClass K, QualType T, bool Dependent,
+ OverloadExpr(StmtClass K, ASTContext &C, QualType T, bool Dependent,
NestedNameSpecifier *Qualifier, SourceRange QRange,
DeclarationName Name, SourceLocation NameLoc,
- bool HasTemplateArgs)
- : Expr(K, T, Dependent, Dependent),
- Name(Name), Qualifier(Qualifier), QualifierRange(QRange),
- NameLoc(NameLoc), HasExplicitTemplateArgs(HasTemplateArgs)
- {}
+ bool HasTemplateArgs,
+ UnresolvedSetIterator Begin, UnresolvedSetIterator End);
public:
/// Computes whether an unresolved lookup on the given declarations
@@ -1309,22 +1393,17 @@ public:
return llvm::PointerIntPair<OverloadExpr*,1>(cast<OverloadExpr>(E), op);
}
- void addDecls(UnresolvedSetIterator Begin, UnresolvedSetIterator End) {
- Results.append(Begin, End);
- }
-
/// Gets the naming class of this lookup, if any.
CXXRecordDecl *getNamingClass() const;
typedef UnresolvedSetImpl::iterator decls_iterator;
- decls_iterator decls_begin() const { return Results.begin(); }
- decls_iterator decls_end() const { return Results.end(); }
-
- /// Gets the decls as an unresolved set.
- const UnresolvedSetImpl &getDecls() { return Results; }
+ decls_iterator decls_begin() const { return UnresolvedSetIterator(Results); }
+ decls_iterator decls_end() const {
+ return UnresolvedSetIterator(Results + NumResults);
+ }
/// Gets the number of declarations in the unresolved set.
- unsigned getNumDecls() const { return Results.size(); }
+ unsigned getNumDecls() const { return NumResults; }
/// Gets the name looked up.
DeclarationName getName() const { return Name; }
@@ -1390,12 +1469,14 @@ class UnresolvedLookupExpr : public OverloadExpr {
/// against the qualified-lookup bits.
CXXRecordDecl *NamingClass;
- UnresolvedLookupExpr(QualType T, bool Dependent, CXXRecordDecl *NamingClass,
+ UnresolvedLookupExpr(ASTContext &C, QualType T, bool Dependent,
+ CXXRecordDecl *NamingClass,
NestedNameSpecifier *Qualifier, SourceRange QRange,
DeclarationName Name, SourceLocation NameLoc,
- bool RequiresADL, bool Overloaded, bool HasTemplateArgs)
- : OverloadExpr(UnresolvedLookupExprClass, T, Dependent, Qualifier, QRange,
- Name, NameLoc, HasTemplateArgs),
+ bool RequiresADL, bool Overloaded, bool HasTemplateArgs,
+ UnresolvedSetIterator Begin, UnresolvedSetIterator End)
+ : OverloadExpr(UnresolvedLookupExprClass, C, T, Dependent, Qualifier,
+ QRange, Name, NameLoc, HasTemplateArgs, Begin, End),
RequiresADL(RequiresADL), Overloaded(Overloaded), NamingClass(NamingClass)
{}
@@ -1407,11 +1488,15 @@ public:
SourceRange QualifierRange,
DeclarationName Name,
SourceLocation NameLoc,
- bool ADL, bool Overloaded) {
- return new(C) UnresolvedLookupExpr(Dependent ? C.DependentTy : C.OverloadTy,
+ bool ADL, bool Overloaded,
+ UnresolvedSetIterator Begin,
+ UnresolvedSetIterator End) {
+ return new(C) UnresolvedLookupExpr(C,
+ Dependent ? C.DependentTy : C.OverloadTy,
Dependent, NamingClass,
Qualifier, QualifierRange,
- Name, NameLoc, ADL, Overloaded, false);
+ Name, NameLoc, ADL, Overloaded, false,
+ Begin, End);
}
static UnresolvedLookupExpr *Create(ASTContext &C,
@@ -1422,7 +1507,9 @@ public:
DeclarationName Name,
SourceLocation NameLoc,
bool ADL,
- const TemplateArgumentListInfo &Args);
+ const TemplateArgumentListInfo &Args,
+ UnresolvedSetIterator Begin,
+ UnresolvedSetIterator End);
/// True if this declaration should be extended by
/// argument-dependent lookup.
@@ -1611,7 +1698,7 @@ class CXXExprWithTemporaries : public Expr {
CXXTemporary **Temps;
unsigned NumTemps;
- CXXExprWithTemporaries(Expr *SubExpr, CXXTemporary **Temps,
+ CXXExprWithTemporaries(ASTContext &C, Expr *SubExpr, CXXTemporary **Temps,
unsigned NumTemps);
~CXXExprWithTemporaries();
@@ -1619,11 +1706,17 @@ protected:
virtual void DoDestroy(ASTContext &C);
public:
+ CXXExprWithTemporaries(EmptyShell Empty)
+ : Expr(CXXExprWithTemporariesClass, Empty),
+ SubExpr(0), Temps(0), NumTemps(0) {}
+
static CXXExprWithTemporaries *Create(ASTContext &C, Expr *SubExpr,
CXXTemporary **Temps,
unsigned NumTemps);
unsigned getNumTemporaries() const { return NumTemps; }
+ void setNumTemporaries(ASTContext &C, unsigned N);
+
CXXTemporary *getTemporary(unsigned i) {
assert(i < NumTemps && "Index out of range");
return Temps[i];
@@ -1631,6 +1724,10 @@ public:
const CXXTemporary *getTemporary(unsigned i) const {
return const_cast<CXXExprWithTemporaries*>(this)->getTemporary(i);
}
+ void setTemporary(unsigned i, CXXTemporary *T) {
+ assert(i < NumTemps && "Index out of range");
+ Temps[i] = T;
+ }
Expr *getSubExpr() { return cast<Expr>(SubExpr); }
const Expr *getSubExpr() const { return cast<Expr>(SubExpr); }
@@ -2020,7 +2117,7 @@ class UnresolvedMemberExpr : public OverloadExpr {
/// \brief The location of the '->' or '.' operator.
SourceLocation OperatorLoc;
- UnresolvedMemberExpr(QualType T, bool Dependent,
+ UnresolvedMemberExpr(ASTContext &C, QualType T, bool Dependent,
bool HasUnresolvedUsing,
Expr *Base, QualType BaseType, bool IsArrow,
SourceLocation OperatorLoc,
@@ -2028,7 +2125,8 @@ class UnresolvedMemberExpr : public OverloadExpr {
SourceRange QualifierRange,
DeclarationName Member,
SourceLocation MemberLoc,
- const TemplateArgumentListInfo *TemplateArgs);
+ const TemplateArgumentListInfo *TemplateArgs,
+ UnresolvedSetIterator Begin, UnresolvedSetIterator End);
public:
static UnresolvedMemberExpr *
@@ -2039,7 +2137,8 @@ public:
SourceRange QualifierRange,
DeclarationName Member,
SourceLocation MemberLoc,
- const TemplateArgumentListInfo *TemplateArgs);
+ const TemplateArgumentListInfo *TemplateArgs,
+ UnresolvedSetIterator Begin, UnresolvedSetIterator End);
/// \brief True if this is an implicit access, i.e. one in which the
/// member being accessed was not written in the source. The source
diff --git a/include/clang/AST/Makefile b/include/clang/AST/Makefile
new file mode 100644
index 000000000000..a25977cad621
--- /dev/null
+++ b/include/clang/AST/Makefile
@@ -0,0 +1,13 @@
+LEVEL = ../../../../..
+BUILT_SOURCES = StmtNodes.inc
+
+TABLEGEN_INC_FILES_COMMON = 1
+
+include $(LEVEL)/Makefile.common
+
+INPUT_TDS = $(PROJ_SRC_DIR)/StmtNodes.td
+
+$(ObjDir)/StmtNodes.inc.tmp : StmtNodes.td $(TBLGEN) $(ObjDir)/.dir
+ $(Echo) "Building Clang statement node tables with tblgen"
+ $(Verb) $(TableGen) -gen-clang-stmt-nodes -o $(call SYSPATH, $@) $<
+
diff --git a/include/clang/AST/RecordLayout.h b/include/clang/AST/RecordLayout.h
index e78476ef51bb..2b3229e8fae9 100644
--- a/include/clang/AST/RecordLayout.h
+++ b/include/clang/AST/RecordLayout.h
@@ -109,6 +109,11 @@ private:
/// which is the alignment of the object without virtual bases.
uint64_t NonVirtualAlign;
+ /// SizeOfLargestEmptySubobject - The size of the largest empty subobject
+ /// (either a base or a member). Will be zero if the class doesn't contain
+ /// any empty subobjects.
+ uint64_t SizeOfLargestEmptySubobject;
+
/// PrimaryBase - The primary base info for this record.
PrimaryBaseInfo PrimaryBase;
@@ -127,7 +132,6 @@ private:
CXXRecordLayoutInfo *CXXInfo;
friend class ASTContext;
- friend class ASTRecordLayoutBuilder;
ASTRecordLayout(ASTContext &Ctx, uint64_t size, unsigned alignment,
unsigned datasize, const uint64_t *fieldoffsets,
@@ -139,7 +143,9 @@ private:
uint64_t size, unsigned alignment, uint64_t datasize,
const uint64_t *fieldoffsets, unsigned fieldcount,
uint64_t nonvirtualsize, unsigned nonvirtualalign,
- const PrimaryBaseInfo &PrimaryBase,
+ uint64_t SizeOfLargestEmptySubobject,
+ const CXXRecordDecl *PrimaryBase,
+ bool PrimaryBaseIsVirtual,
const BaseOffsetsMapTy& BaseOffsets,
const BaseOffsetsMapTy& VBaseOffsets);
@@ -222,6 +228,11 @@ public:
return CXXInfo->VBaseOffsets[VBase];
}
+ uint64_t getSizeOfLargestEmptySubobject() const {
+ assert(CXXInfo && "Record layout does not have C++ specific info!");
+ return CXXInfo->SizeOfLargestEmptySubobject;
+ }
+
primary_base_info_iterator primary_base_begin() const {
assert(CXXInfo && "Record layout does not have C++ specific info!");
diff --git a/include/clang/AST/RecursiveASTVisitor.h b/include/clang/AST/RecursiveASTVisitor.h
new file mode 100644
index 000000000000..07865e0eb3f1
--- /dev/null
+++ b/include/clang/AST/RecursiveASTVisitor.h
@@ -0,0 +1,768 @@
+//===--- RecursiveASTVisitor.h - Recursive AST Visitor ----------*- C++ -*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+//
+// This file defines the RecursiveASTVisitor interface, which recursively
+// traverses the entire AST.
+//
+//===----------------------------------------------------------------------===//
+#ifndef LLVM_CLANG_AST_RECURSIVEASTVISITOR_H
+#define LLVM_CLANG_AST_RECURSIVEASTVISITOR_H
+
+#include "clang/AST/Decl.h"
+#include "clang/AST/DeclCXX.h"
+#include "clang/AST/DeclFriend.h"
+#include "clang/AST/DeclObjC.h"
+#include "clang/AST/DeclTemplate.h"
+#include "clang/AST/Expr.h"
+#include "clang/AST/ExprCXX.h"
+#include "clang/AST/ExprObjC.h"
+#include "clang/AST/NestedNameSpecifier.h"
+#include "clang/AST/Stmt.h"
+#include "clang/AST/StmtCXX.h"
+#include "clang/AST/StmtObjC.h"
+#include "clang/AST/TemplateBase.h"
+#include "clang/AST/TemplateName.h"
+#include "clang/AST/Type.h"
+
+namespace clang {
+
+#define DISPATCH(NAME, CLASS, Var) \
+return getDerived().Visit ## NAME(static_cast<CLASS*>(Var))
+
+// We use preprocessor meta-programming to generate the Visit*()
+// methods for all subclasses of Stmt, Decl, and Type. Some of the
+// generated definitions, however, need to be customized. The
+// meta-programming technique we use doesn't let us select which
+// methods to generate. Therefore we have to generate ALL of them in
+// a helper class RecursiveASTVisitorImpl, and override the ones we
+// don't like in a child class RecursiveASTVisitor (C++ doesn't allow
+// overriding a method in the same class).
+//
+// Do not use this class directly - use RecursiveASTVisitor instead.
+template<typename Derived>
+class RecursiveASTVisitorImpl {
+public:
+ /// \brief Return a reference to the derived class.
+ Derived &getDerived() { return *static_cast<Derived*>(this); }
+
+ /// \brief Recursively visit a statement or expression, by
+ /// dispatching to Visit*() based on the argument's dynamic type.
+ /// This is NOT meant to be overridden by a subclass.
+ ///
+ /// \returns true if the visitation was terminated early, false
+ /// otherwise (including when the argument is NULL).
+ bool Visit(Stmt *S);
+
+ /// \brief Recursively visit a type, by dispatching to
+ /// Visit*Type() based on the argument's getTypeClass() property.
+ /// This is NOT meant to be overridden by a subclass.
+ ///
+ /// \returns true if the visitation was terminated early, false
+ /// otherwise (including when the argument is a Null type).
+ bool Visit(QualType T);
+
+ /// \brief Recursively visit a declaration, by dispatching to
+ /// Visit*Decl() based on the argument's dynamic type. This is
+ /// NOT meant to be overridden by a subclass.
+ ///
+ /// \returns true if the visitation was terminated early, false
+ /// otherwise (including when the argument is NULL).
+ bool Visit(Decl *D);
+
+ /// \brief Recursively visit a C++ nested-name-specifier.
+ ///
+ /// \returns true if the visitation was terminated early, false otherwise.
+ bool VisitNestedNameSpecifier(NestedNameSpecifier *NNS);
+
+ /// \brief Recursively visit a template name.
+ ///
+ /// \returns true if the visitation was terminated early, false otherwise.
+ bool VisitTemplateName(TemplateName Template);
+
+ /// \brief Recursively visit a template argument.
+ ///
+ /// \returns true if the visitation was terminated early, false otherwise.
+ bool VisitTemplateArgument(const TemplateArgument &Arg);
+
+ /// \brief Recursively visit a set of template arguments.
+ ///
+ /// \returns true if the visitation was terminated early, false otherwise.
+ bool VisitTemplateArguments(const TemplateArgument *Args, unsigned NumArgs);
+
+ // If the implementation chooses not to implement a certain visit method, fall
+ // back on VisitExpr or whatever else is the superclass.
+#define STMT(CLASS, PARENT) \
+bool Visit ## CLASS(CLASS *S) { DISPATCH(PARENT, PARENT, S); }
+#include "clang/AST/StmtNodes.inc"
+
+ // If the implementation doesn't implement binary operator methods, fall back
+ // on VisitBinaryOperator.
+#define BINOP_FALLBACK(NAME) \
+bool VisitBin ## NAME(BinaryOperator *S) { \
+DISPATCH(BinaryOperator, BinaryOperator, S); \
+}
+ BINOP_FALLBACK(PtrMemD) BINOP_FALLBACK(PtrMemI)
+ BINOP_FALLBACK(Mul) BINOP_FALLBACK(Div) BINOP_FALLBACK(Rem)
+ BINOP_FALLBACK(Add) BINOP_FALLBACK(Sub) BINOP_FALLBACK(Shl)
+ BINOP_FALLBACK(Shr)
+
+ BINOP_FALLBACK(LT) BINOP_FALLBACK(GT) BINOP_FALLBACK(LE)
+ BINOP_FALLBACK(GE) BINOP_FALLBACK(EQ) BINOP_FALLBACK(NE)
+ BINOP_FALLBACK(And) BINOP_FALLBACK(Xor) BINOP_FALLBACK(Or)
+ BINOP_FALLBACK(LAnd) BINOP_FALLBACK(LOr)
+
+ BINOP_FALLBACK(Assign)
+ BINOP_FALLBACK(Comma)
+#undef BINOP_FALLBACK
+
+ // If the implementation doesn't implement compound assignment operator
+ // methods, fall back on VisitCompoundAssignOperator.
+#define CAO_FALLBACK(NAME) \
+bool VisitBin ## NAME(CompoundAssignOperator *S) { \
+DISPATCH(CompoundAssignOperator, CompoundAssignOperator, S); \
+}
+ CAO_FALLBACK(MulAssign) CAO_FALLBACK(DivAssign) CAO_FALLBACK(RemAssign)
+ CAO_FALLBACK(AddAssign) CAO_FALLBACK(SubAssign) CAO_FALLBACK(ShlAssign)
+ CAO_FALLBACK(ShrAssign) CAO_FALLBACK(AndAssign) CAO_FALLBACK(OrAssign)
+ CAO_FALLBACK(XorAssign)
+#undef CAO_FALLBACK
+
+ // If the implementation doesn't implement unary operator methods, fall back
+ // on VisitUnaryOperator.
+#define UNARYOP_FALLBACK(NAME) \
+bool VisitUnary ## NAME(UnaryOperator *S) { \
+DISPATCH(UnaryOperator, UnaryOperator, S); \
+}
+ UNARYOP_FALLBACK(PostInc) UNARYOP_FALLBACK(PostDec)
+ UNARYOP_FALLBACK(PreInc) UNARYOP_FALLBACK(PreDec)
+ UNARYOP_FALLBACK(AddrOf) UNARYOP_FALLBACK(Deref)
+
+ UNARYOP_FALLBACK(Plus) UNARYOP_FALLBACK(Minus)
+ UNARYOP_FALLBACK(Not) UNARYOP_FALLBACK(LNot)
+ UNARYOP_FALLBACK(Real) UNARYOP_FALLBACK(Imag)
+ UNARYOP_FALLBACK(Extension) UNARYOP_FALLBACK(OffsetOf)
+#undef UNARYOP_FALLBACK
+
+ /// \brief Basis for statement and expression visitation, which
+ /// visits all of the substatements and subexpressions.
+ ///
+ /// The relation between Visit(Stmt *S) and this method is that
+ /// the former dispatches to Visit*() based on S's dynamic type,
+ /// which forwards the call up the inheritance chain until
+ /// reaching VisitStmt(), which then calls Visit() on each
+ /// substatement/subexpression.
+ bool VisitStmt(Stmt *S);
+
+ /// \brief Basis for type visitation, which by default does nothing.
+ ///
+ /// The relation between Visit(QualType T) and this method is
+ /// that the former dispatches to Visit*Type(), which forwards the
+ /// call up the inheritance chain until reaching VisitType().
+ bool VisitType(Type *T);
+
+#define TYPE(Class, Base) \
+ bool Visit##Class##Type(Class##Type *T);
+#include "clang/AST/TypeNodes.def"
+
+ /// \brief Basis for declaration and definition visitation, which
+ /// visits all of the subnodes.
+ ///
+ /// The relation between Visit(Decl *) and this method is that the
+ /// former dispatches to Visit*Decl(), which forwards the call up
+ /// the inheritance chain until reaching VisitDecl().
+ bool VisitDecl(Decl *D);
+
+#define DECL(Class, Base) \
+ bool Visit##Class##Decl(Class##Decl *D) { \
+ return getDerived().Visit##Base(D); \
+ }
+#define ABSTRACT_DECL(Class, Base) DECL(Class, Base)
+#include "clang/AST/DeclNodes.def"
+};
+
+template<typename Derived>
+bool RecursiveASTVisitorImpl<Derived>::Visit(Stmt *S) {
+ if (!S)
+ return false;
+
+ // If we have a binary expr, dispatch to the subcode of the binop. A smart
+ // optimizer (e.g. LLVM) will fold this comparison into the switch stmt
+ // below.
+ if (BinaryOperator *BinOp = dyn_cast<BinaryOperator>(S)) {
+ switch (BinOp->getOpcode()) {
+ case BinaryOperator::PtrMemD: DISPATCH(BinPtrMemD, BinaryOperator, S);
+ case BinaryOperator::PtrMemI: DISPATCH(BinPtrMemI, BinaryOperator, S);
+ case BinaryOperator::Mul: DISPATCH(BinMul, BinaryOperator, S);
+ case BinaryOperator::Div: DISPATCH(BinDiv, BinaryOperator, S);
+ case BinaryOperator::Rem: DISPATCH(BinRem, BinaryOperator, S);
+ case BinaryOperator::Add: DISPATCH(BinAdd, BinaryOperator, S);
+ case BinaryOperator::Sub: DISPATCH(BinSub, BinaryOperator, S);
+ case BinaryOperator::Shl: DISPATCH(BinShl, BinaryOperator, S);
+ case BinaryOperator::Shr: DISPATCH(BinShr, BinaryOperator, S);
+
+ case BinaryOperator::LT: DISPATCH(BinLT, BinaryOperator, S);
+ case BinaryOperator::GT: DISPATCH(BinGT, BinaryOperator, S);
+ case BinaryOperator::LE: DISPATCH(BinLE, BinaryOperator, S);
+ case BinaryOperator::GE: DISPATCH(BinGE, BinaryOperator, S);
+ case BinaryOperator::EQ: DISPATCH(BinEQ, BinaryOperator, S);
+ case BinaryOperator::NE: DISPATCH(BinNE, BinaryOperator, S);
+
+ case BinaryOperator::And: DISPATCH(BinAnd, BinaryOperator, S);
+ case BinaryOperator::Xor: DISPATCH(BinXor, BinaryOperator, S);
+ case BinaryOperator::Or : DISPATCH(BinOr, BinaryOperator, S);
+ case BinaryOperator::LAnd: DISPATCH(BinLAnd, BinaryOperator, S);
+ case BinaryOperator::LOr : DISPATCH(BinLOr, BinaryOperator, S);
+ case BinaryOperator::Assign: DISPATCH(BinAssign, BinaryOperator, S);
+ case BinaryOperator::MulAssign:
+ DISPATCH(BinMulAssign, CompoundAssignOperator, S);
+ case BinaryOperator::DivAssign:
+ DISPATCH(BinDivAssign, CompoundAssignOperator, S);
+ case BinaryOperator::RemAssign:
+ DISPATCH(BinRemAssign, CompoundAssignOperator, S);
+ case BinaryOperator::AddAssign:
+ DISPATCH(BinAddAssign, CompoundAssignOperator, S);
+ case BinaryOperator::SubAssign:
+ DISPATCH(BinSubAssign, CompoundAssignOperator, S);
+ case BinaryOperator::ShlAssign:
+ DISPATCH(BinShlAssign, CompoundAssignOperator, S);
+ case BinaryOperator::ShrAssign:
+ DISPATCH(BinShrAssign, CompoundAssignOperator, S);
+ case BinaryOperator::AndAssign:
+ DISPATCH(BinAndAssign, CompoundAssignOperator, S);
+ case BinaryOperator::OrAssign:
+ DISPATCH(BinOrAssign, CompoundAssignOperator, S);
+ case BinaryOperator::XorAssign:
+ DISPATCH(BinXorAssign, CompoundAssignOperator, S);
+ case BinaryOperator::Comma: DISPATCH(BinComma, BinaryOperator, S);
+ }
+ } else if (UnaryOperator *UnOp = dyn_cast<UnaryOperator>(S)) {
+ switch (UnOp->getOpcode()) {
+ case UnaryOperator::PostInc: DISPATCH(UnaryPostInc, UnaryOperator, S);
+ case UnaryOperator::PostDec: DISPATCH(UnaryPostDec, UnaryOperator, S);
+ case UnaryOperator::PreInc: DISPATCH(UnaryPreInc, UnaryOperator, S);
+ case UnaryOperator::PreDec: DISPATCH(UnaryPreDec, UnaryOperator, S);
+ case UnaryOperator::AddrOf: DISPATCH(UnaryAddrOf, UnaryOperator, S);
+ case UnaryOperator::Deref: DISPATCH(UnaryDeref, UnaryOperator, S);
+ case UnaryOperator::Plus: DISPATCH(UnaryPlus, UnaryOperator, S);
+ case UnaryOperator::Minus: DISPATCH(UnaryMinus, UnaryOperator, S);
+ case UnaryOperator::Not: DISPATCH(UnaryNot, UnaryOperator, S);
+ case UnaryOperator::LNot: DISPATCH(UnaryLNot, UnaryOperator, S);
+ case UnaryOperator::Real: DISPATCH(UnaryReal, UnaryOperator, S);
+ case UnaryOperator::Imag: DISPATCH(UnaryImag, UnaryOperator, S);
+ case UnaryOperator::Extension: DISPATCH(UnaryExtension, UnaryOperator, S);
+ case UnaryOperator::OffsetOf: DISPATCH(UnaryOffsetOf, UnaryOperator, S);
+ }
+ }
+
+ // Top switch stmt: dispatch to VisitFooStmt for each FooStmt.
+ switch (S->getStmtClass()) {
+ case Stmt::NoStmtClass: break;
+#define ABSTRACT_STMT(STMT)
+#define STMT(CLASS, PARENT) \
+case Stmt::CLASS ## Class: DISPATCH(CLASS, CLASS, S);
+#include "clang/AST/StmtNodes.inc"
+ }
+
+ return false;
+}
+
+template<typename Derived>
+bool RecursiveASTVisitorImpl<Derived>::Visit(QualType T) {
+ if (T.isNull())
+ return false;
+
+ switch (T->getTypeClass()) {
+#define ABSTRACT_TYPE(Class, Base)
+#define TYPE(Class, Base) \
+ case Type::Class: DISPATCH(Class##Type, Class##Type, T.getTypePtr());
+#include "clang/AST/TypeNodes.def"
+ }
+
+ return false;
+}
+
+template<typename Derived>
+bool RecursiveASTVisitorImpl<Derived>::Visit(Decl *D) {
+ if (!D)
+ return false;
+
+ switch (D->getKind()) {
+#define ABSTRACT_DECL(Class, Base)
+#define DECL(Class, Base) \
+ case Decl::Class: DISPATCH(Class##Decl, Class##Decl, D);
+#include "clang/AST/DeclNodes.def"
+ }
+
+ return false;
+}
+
+template<typename Derived>
+bool RecursiveASTVisitorImpl<Derived>::VisitNestedNameSpecifier(
+ NestedNameSpecifier *NNS) {
+ if (NNS->getPrefix() &&
+ getDerived().VisitNestedNameSpecifier(NNS->getPrefix()))
+ return true;
+
+ switch (NNS->getKind()) {
+ case NestedNameSpecifier::Identifier:
+ case NestedNameSpecifier::Namespace:
+ case NestedNameSpecifier::Global:
+ return false;
+
+ case NestedNameSpecifier::TypeSpec:
+ case NestedNameSpecifier::TypeSpecWithTemplate:
+ return Visit(QualType(NNS->getAsType(), 0));
+ }
+
+ return false;
+}
+
+template<typename Derived>
+bool RecursiveASTVisitorImpl<Derived>::VisitTemplateName(TemplateName Template) {
+ if (DependentTemplateName *DTN = Template.getAsDependentTemplateName())
+ return DTN->getQualifier() &&
+ getDerived().VisitNestedNameSpecifier(DTN->getQualifier());
+
+ if (QualifiedTemplateName *QTN = Template.getAsQualifiedTemplateName())
+ return getDerived().VisitNestedNameSpecifier(QTN->getQualifier());
+
+ return false;
+}
+
+template<typename Derived>
+bool RecursiveASTVisitorImpl<Derived>::VisitTemplateArgument(
+ const TemplateArgument &Arg) {
+ switch (Arg.getKind()) {
+ case TemplateArgument::Null:
+ case TemplateArgument::Declaration:
+ case TemplateArgument::Integral:
+ return false;
+
+ case TemplateArgument::Type:
+ return Visit(Arg.getAsType());
+
+ case TemplateArgument::Template:
+ return getDerived().VisitTemplateName(Arg.getAsTemplate());
+
+ case TemplateArgument::Expression:
+ return getDerived().Visit(Arg.getAsExpr());
+
+ case TemplateArgument::Pack:
+ return getDerived().VisitTemplateArguments(Arg.pack_begin(),
+ Arg.pack_size());
+ }
+
+ return false;
+}
+
+template<typename Derived>
+bool RecursiveASTVisitorImpl<Derived>::VisitTemplateArguments(
+ const TemplateArgument *Args,
+ unsigned NumArgs) {
+ for (unsigned I = 0; I != NumArgs; ++I)
+ if (getDerived().VisitTemplateArgument(Args[I]))
+ return true;
+
+ return false;
+}
+
+template<typename Derived>
+bool RecursiveASTVisitorImpl<Derived>::VisitStmt(Stmt *Node) {
+ for (Stmt::child_iterator C = Node->child_begin(), CEnd = Node->child_end();
+ C != CEnd; ++C) {
+ if (Visit(*C))
+ return true;
+ }
+
+ return false;
+}
+
+template<typename Derived>
+bool RecursiveASTVisitorImpl<Derived>::VisitType(Type *T) {
+ return false;
+}
+
+template<typename Derived>
+bool RecursiveASTVisitorImpl<Derived>::VisitBuiltinType(BuiltinType *T) {
+ return getDerived().VisitType(T);
+}
+
+template<typename Derived>
+bool RecursiveASTVisitorImpl<Derived>::VisitComplexType(ComplexType *T) {
+ if (Visit(T->getElementType()))
+ return true;
+
+ return getDerived().VisitType(T);
+}
+
+template<typename Derived>
+bool RecursiveASTVisitorImpl<Derived>::VisitPointerType(PointerType *T) {
+ if (Visit(T->getPointeeType()))
+ return true;
+
+ return getDerived().VisitType(T);
+}
+
+template<typename Derived>
+bool RecursiveASTVisitorImpl<Derived>::VisitBlockPointerType(
+ BlockPointerType *T) {
+ if (Visit(T->getPointeeType()))
+ return true;
+
+ return getDerived().VisitType(T);
+}
+
+template<typename Derived>
+bool RecursiveASTVisitorImpl<Derived>::VisitReferenceType(ReferenceType *T) {
+ if (Visit(T->getPointeeType()))
+ return true;
+
+ return getDerived().VisitType(T);
+}
+
+template<typename Derived>
+bool RecursiveASTVisitorImpl<Derived>::VisitLValueReferenceType(
+ LValueReferenceType *T) {
+ return getDerived().VisitReferenceType(T);
+}
+
+template<typename Derived>
+bool RecursiveASTVisitorImpl<Derived>::VisitRValueReferenceType(
+ RValueReferenceType *T) {
+ return getDerived().VisitReferenceType(T);
+}
+
+template<typename Derived>
+bool RecursiveASTVisitorImpl<Derived>::VisitMemberPointerType(
+ MemberPointerType *T) {
+ if (Visit(QualType(T->getClass(), 0)) || Visit(T->getPointeeType()))
+ return true;
+
+ return getDerived().VisitType(T);
+}
+
+template<typename Derived>
+bool RecursiveASTVisitorImpl<Derived>::VisitArrayType(ArrayType *T) {
+ if (Visit(T->getElementType()))
+ return true;
+
+ return getDerived().VisitType(T);
+}
+
+template<typename Derived>
+bool RecursiveASTVisitorImpl<Derived>::VisitConstantArrayType(
+ ConstantArrayType *T) {
+ return getDerived().VisitArrayType(T);
+}
+
+template<typename Derived>
+bool RecursiveASTVisitorImpl<Derived>::VisitIncompleteArrayType(
+ IncompleteArrayType *T) {
+ return getDerived().VisitArrayType(T);
+}
+
+template<typename Derived>
+bool RecursiveASTVisitorImpl<Derived>::VisitVariableArrayType(
+ VariableArrayType *T) {
+ if (Visit(T->getSizeExpr()))
+ return true;
+
+ return getDerived().VisitArrayType(T);
+}
+
+template<typename Derived>
+bool RecursiveASTVisitorImpl<Derived>::VisitDependentSizedArrayType(
+ DependentSizedArrayType *T) {
+ if (T->getSizeExpr() && Visit(T->getSizeExpr()))
+ return true;
+
+ return getDerived().VisitArrayType(T);
+}
+
+template<typename Derived>
+bool RecursiveASTVisitorImpl<Derived>::VisitDependentSizedExtVectorType(
+ DependentSizedExtVectorType *T) {
+ if ((T->getSizeExpr() && Visit(T->getSizeExpr())) ||
+ Visit(T->getElementType()))
+ return true;
+
+ return getDerived().VisitType(T);
+}
+
+template<typename Derived>
+bool RecursiveASTVisitorImpl<Derived>::VisitVectorType(VectorType *T) {
+ if (Visit(T->getElementType()))
+ return true;
+
+ return getDerived().VisitType(T);
+}
+
+template<typename Derived>
+bool RecursiveASTVisitorImpl<Derived>::VisitExtVectorType(ExtVectorType *T) {
+ return getDerived().VisitVectorType(T);
+}
+
+template<typename Derived>
+bool RecursiveASTVisitorImpl<Derived>::VisitFunctionType(FunctionType *T) {
+ if (Visit(T->getResultType()))
+ return true;
+
+ return getDerived().VisitType(T);
+}
+
+template<typename Derived>
+bool RecursiveASTVisitorImpl<Derived>::VisitFunctionNoProtoType(
+ FunctionNoProtoType *T) {
+ return getDerived().VisitFunctionType(T);
+}
+
+template<typename Derived>
+bool RecursiveASTVisitorImpl<Derived>::VisitFunctionProtoType(
+ FunctionProtoType *T) {
+ for (FunctionProtoType::arg_type_iterator A = T->arg_type_begin(),
+ AEnd = T->arg_type_end();
+ A != AEnd; ++A) {
+ if (Visit(*A))
+ return true;
+ }
+
+ for (FunctionProtoType::exception_iterator E = T->exception_begin(),
+ EEnd = T->exception_end();
+ E != EEnd; ++E) {
+ if (Visit(*E))
+ return true;
+ }
+
+ return getDerived().VisitFunctionType(T);
+}
+
+template<typename Derived>
+bool RecursiveASTVisitorImpl<Derived>::VisitUnresolvedUsingType(
+ UnresolvedUsingType *T) {
+ return getDerived().VisitType(T);
+}
+
+template<typename Derived>
+bool RecursiveASTVisitorImpl<Derived>::VisitTypedefType(TypedefType *T) {
+ return getDerived().VisitType(T);
+}
+
+template<typename Derived>
+bool RecursiveASTVisitorImpl<Derived>::VisitTypeOfExprType(TypeOfExprType *T) {
+ if (Visit(T->getUnderlyingExpr()))
+ return true;
+
+ return getDerived().VisitType(T);
+}
+
+template<typename Derived>
+bool RecursiveASTVisitorImpl<Derived>::VisitTypeOfType(TypeOfType *T) {
+ if (Visit(T->getUnderlyingType()))
+ return true;
+
+ return getDerived().VisitType(T);
+}
+
+template<typename Derived>
+bool RecursiveASTVisitorImpl<Derived>::VisitDecltypeType(DecltypeType *T) {
+ if (Visit(T->getUnderlyingExpr()))
+ return true;
+
+ return getDerived().VisitType(T);
+}
+
+template<typename Derived>
+bool RecursiveASTVisitorImpl<Derived>::VisitTagType(TagType *T) {
+ return getDerived().VisitType(T);
+}
+
+template<typename Derived>
+bool RecursiveASTVisitorImpl<Derived>::VisitRecordType(RecordType *T) {
+ return getDerived().VisitTagType(T);
+}
+
+template<typename Derived>
+bool RecursiveASTVisitorImpl<Derived>::VisitEnumType(EnumType *T) {
+ return getDerived().VisitType(T);
+}
+
+template<typename Derived>
+bool RecursiveASTVisitorImpl<Derived>::VisitTemplateTypeParmType(
+ TemplateTypeParmType *T) {
+ return getDerived().VisitType(T);
+}
+
+template<typename Derived>
+bool RecursiveASTVisitorImpl<Derived>::VisitSubstTemplateTypeParmType(
+ SubstTemplateTypeParmType *T) {
+ return getDerived().VisitType(T);
+}
+
+template<typename Derived>
+bool RecursiveASTVisitorImpl<Derived>::VisitTemplateSpecializationType(
+ TemplateSpecializationType *T) {
+ if (getDerived().VisitTemplateName(T->getTemplateName()) ||
+ getDerived().VisitTemplateArguments(T->getArgs(), T->getNumArgs()))
+ return true;
+
+ return getDerived().VisitType(T);
+}
+
+template<typename Derived>
+bool RecursiveASTVisitorImpl<Derived>::VisitInjectedClassNameType(
+ InjectedClassNameType *T) {
+ return getDerived().VisitType(T);
+}
+
+template<typename Derived>
+bool RecursiveASTVisitorImpl<Derived>::VisitElaboratedType(ElaboratedType *T) {
+ if (T->getQualifier() &&
+ getDerived().VisitNestedNameSpecifier(T->getQualifier()))
+ return true;
+ if (Visit(T->getNamedType()))
+ return true;
+
+ return getDerived().VisitType(T);
+}
+
+template<typename Derived>
+bool RecursiveASTVisitorImpl<Derived>::VisitDependentNameType(
+ DependentNameType *T) {
+ if (T->getQualifier() &&
+ getDerived().VisitNestedNameSpecifier(T->getQualifier()))
+ return true;
+
+ if (T->getTemplateId() &&
+ getDerived().VisitTemplateSpecializationType(
+ const_cast<TemplateSpecializationType *>(T->getTemplateId())))
+ return true;
+
+ return getDerived().VisitType(T);
+}
+
+template<typename Derived>
+bool RecursiveASTVisitorImpl<Derived>::VisitObjCInterfaceType(
+ ObjCInterfaceType *T) {
+ return getDerived().VisitObjCObjectType(T);
+}
+
+template<typename Derived>
+bool RecursiveASTVisitorImpl<Derived>::VisitObjCObjectType(ObjCObjectType *T) {
+ // We have to watch out here because an ObjCInterfaceType's base
+ // type is itself.
+ if (T->getBaseType().getTypePtr() != T)
+ if (Visit(T->getBaseType()))
+ return true;
+
+ return getDerived().VisitType(T);
+}
+
+template<typename Derived>
+bool RecursiveASTVisitorImpl<Derived>::VisitObjCObjectPointerType(
+ ObjCObjectPointerType *T) {
+ if (Visit(T->getPointeeType()))
+ return true;
+
+ return getDerived().VisitType(T);
+}
+
+template<typename Derived>
+bool RecursiveASTVisitorImpl<Derived>::VisitDecl(Decl *D) {
+ if (DeclContext *DC = dyn_cast<DeclContext>(D)) {
+ for (DeclContext::decl_iterator Child = DC->decls_begin(),
+ ChildEnd = DC->decls_end();
+ Child != ChildEnd; ++Child)
+ if (Visit(*Child))
+ return true;
+
+ return false;
+ }
+
+ return false;
+}
+
+/// \brief A visitor that recursively walks the entire Clang AST.
+///
+/// Clients of this visitor should subclass the visitor (providing
+/// themselves as the template argument, using the curiously
+/// recurring template pattern) and override any of the Visit*
+/// methods (except Visit()) for declaration, type, statement,
+/// expression, or other AST nodes where the visitor should customize
+/// behavior. Returning "true" from one of these overridden functions
+/// will abort the entire traversal. An overridden Visit* method
+/// will not descend further into the AST for that node unless
+/// Base::Visit* is called.
+template<typename Derived>
+class RecursiveASTVisitor : public RecursiveASTVisitorImpl<Derived> {
+ typedef RecursiveASTVisitorImpl<Derived> Impl;
+public:
+ typedef RecursiveASTVisitor<Derived> Base;
+
+ bool VisitDeclaratorDecl(DeclaratorDecl *D);
+ bool VisitFunctionDecl(FunctionDecl *D);
+ bool VisitVarDecl(VarDecl *D);
+ bool VisitBlockDecl(BlockDecl *D);
+ bool VisitDeclStmt(DeclStmt *S);
+ bool VisitFunctionType(FunctionType *F);
+ bool VisitFunctionProtoType(FunctionProtoType *F);
+};
+
+#define DEFINE_VISIT(Type, Name, Statement) \
+ template<typename Derived> \
+ bool RecursiveASTVisitor<Derived>::Visit ## Type (Type *Name) { \
+ if (Impl::Visit ## Type (Name)) return true; \
+ { Statement; } \
+ return false; \
+ }
+
+DEFINE_VISIT(DeclaratorDecl, D, {
+ if (TypeSourceInfo *TInfo = D->getTypeSourceInfo())
+ return this->Visit(TInfo->getType());
+ })
+
+DEFINE_VISIT(FunctionDecl, D, {
+ if (D->isThisDeclarationADefinition())
+ return this->Visit(D->getBody());
+ })
+
+DEFINE_VISIT(VarDecl, D, return this->Visit(D->getInit()))
+
+DEFINE_VISIT(BlockDecl, D, return this->Visit(D->getBody()))
+
+DEFINE_VISIT(DeclStmt, S, {
+ for (DeclStmt::decl_iterator I = S->decl_begin(), E = S->decl_end();
+ I != E; ++I) {
+ if (this->Visit(*I))
+ return true;
+ }
+ })
+
+// FunctionType is the common base class of FunctionNoProtoType (a
+// K&R-style function declaration that has no information about
+// its arguments) and FunctionProtoType.
+DEFINE_VISIT(FunctionType, F, return this->Visit(F->getResultType()))
+
+DEFINE_VISIT(FunctionProtoType, F, {
+ for (unsigned i = 0; i != F->getNumArgs(); ++i) {
+ if (this->Visit(F->getArgType(i)))
+ return true;
+ }
+ for (unsigned i = 0; i != F->getNumExceptions(); ++i) {
+ if (this->Visit(F->getExceptionType(i)))
+ return true;
+ }
+ })
+
+#undef DEFINE_VISIT
+
+#undef DISPATCH
+
+} // end namespace clang
+
+#endif // LLVM_CLANG_AST_RECURSIVEASTVISITOR_H
diff --git a/include/clang/AST/Stmt.h b/include/clang/AST/Stmt.h
index 0b68a4007363..9deae1561586 100644
--- a/include/clang/AST/Stmt.h
+++ b/include/clang/AST/Stmt.h
@@ -98,12 +98,14 @@ public:
enum StmtClass {
NoStmtClass = 0,
#define STMT(CLASS, PARENT) CLASS##Class,
-#define FIRST_STMT(CLASS) firstStmtConstant = CLASS##Class,
-#define LAST_STMT(CLASS) lastStmtConstant = CLASS##Class,
-#define FIRST_EXPR(CLASS) firstExprConstant = CLASS##Class,
-#define LAST_EXPR(CLASS) lastExprConstant = CLASS##Class
-#define ABSTRACT_EXPR(CLASS, PARENT)
-#include "clang/AST/StmtNodes.def"
+#define STMT_RANGE(BASE, FIRST, LAST) \
+ first##BASE##Constant = FIRST##Class, \
+ last##BASE##Constant = LAST##Class,
+#define LAST_STMT_RANGE(BASE, FIRST, LAST) \
+ first##BASE##Constant = FIRST##Class, \
+ last##BASE##Constant = LAST##Class
+#define ABSTRACT_STMT(STMT)
+#include "clang/AST/StmtNodes.inc"
};
private:
/// \brief The statement class.
@@ -1083,9 +1085,15 @@ public:
class ReturnStmt : public Stmt {
Stmt *RetExpr;
SourceLocation RetLoc;
+ const VarDecl *NRVOCandidate;
+
public:
- ReturnStmt(SourceLocation RL, Expr *E = 0) : Stmt(ReturnStmtClass),
- RetExpr((Stmt*) E), RetLoc(RL) {}
+ ReturnStmt(SourceLocation RL)
+ : Stmt(ReturnStmtClass), RetExpr(0), RetLoc(RL), NRVOCandidate(0) { }
+
+ ReturnStmt(SourceLocation RL, Expr *E, const VarDecl *NRVOCandidate)
+ : Stmt(ReturnStmtClass), RetExpr((Stmt*) E), RetLoc(RL),
+ NRVOCandidate(NRVOCandidate) {}
/// \brief Build an empty return expression.
explicit ReturnStmt(EmptyShell Empty) : Stmt(ReturnStmtClass, Empty) { }
@@ -1097,6 +1105,14 @@ public:
SourceLocation getReturnLoc() const { return RetLoc; }
void setReturnLoc(SourceLocation L) { RetLoc = L; }
+ /// \brief Retrieve the variable that might be used for the named return
+ /// value optimization.
+ ///
+ /// The optimization itself can only be performed if the variable is
+ /// also marked as an NRVO object.
+ const VarDecl *getNRVOCandidate() const { return NRVOCandidate; }
+ void setNRVOCandidate(const VarDecl *Var) { NRVOCandidate = Var; }
+
virtual SourceRange getSourceRange() const;
static bool classof(const Stmt *T) {
diff --git a/include/clang/AST/StmtNodes.td b/include/clang/AST/StmtNodes.td
new file mode 100644
index 000000000000..60c94a609b4a
--- /dev/null
+++ b/include/clang/AST/StmtNodes.td
@@ -0,0 +1,127 @@
+class Stmt<bit abstract = 0> {
+ bit Abstract = abstract;
+}
+
+class DStmt<Stmt base, bit abstract = 0> : Stmt<abstract> {
+ Stmt Base = base;
+}
+
+// Statements
+def NullStmt : Stmt;
+def CompoundStmt : Stmt;
+def LabelStmt : Stmt;
+def IfStmt : Stmt;
+def SwitchStmt : Stmt;
+def WhileStmt : Stmt;
+def DoStmt : Stmt;
+def ForStmt : Stmt;
+def GotoStmt : Stmt;
+def IndirectGotoStmt : Stmt;
+def ContinueStmt : Stmt;
+def BreakStmt : Stmt;
+def ReturnStmt : Stmt;
+def DeclStmt : Stmt;
+def SwitchCase : Stmt;
+def CaseStmt : DStmt<SwitchCase>;
+def DefaultStmt : DStmt<SwitchCase>;
+
+// GNU Extensions
+def AsmStmt : Stmt;
+
+// Obj-C statements
+def ObjCAtTryStmt : Stmt;
+def ObjCAtCatchStmt : Stmt;
+def ObjCAtFinallyStmt : Stmt;
+def ObjCAtThrowStmt : Stmt;
+def ObjCAtSynchronizedStmt : Stmt;
+def ObjCForCollectionStmt : Stmt;
+
+// C++ statments
+def CXXCatchStmt : Stmt;
+def CXXTryStmt : Stmt;
+
+// Expressions
+def Expr : Stmt<1>;
+def PredefinedExpr : DStmt<Expr>;
+def DeclRefExpr : DStmt<Expr>;
+def IntegerLiteral : DStmt<Expr>;
+def FloatingLiteral : DStmt<Expr>;
+def ImaginaryLiteral : DStmt<Expr>;
+def StringLiteral : DStmt<Expr>;
+def CharacterLiteral : DStmt<Expr>;
+def ParenExpr : DStmt<Expr>;
+def UnaryOperator : DStmt<Expr>;
+def OffsetOfExpr : DStmt<Expr>;
+def SizeOfAlignOfExpr : DStmt<Expr>;
+def ArraySubscriptExpr : DStmt<Expr>;
+def CallExpr : DStmt<Expr>;
+def MemberExpr : DStmt<Expr>;
+def CastExpr : DStmt<Expr, 1>;
+def BinaryOperator : DStmt<Expr>;
+def CompoundAssignOperator : DStmt<BinaryOperator>;
+def ConditionalOperator : DStmt<Expr>;
+def ImplicitCastExpr : DStmt<CastExpr>;
+def ExplicitCastExpr : DStmt<CastExpr, 1>;
+def CStyleCastExpr : DStmt<ExplicitCastExpr>;
+def CompoundLiteralExpr : DStmt<Expr>;
+def ExtVectorElementExpr : DStmt<Expr>;
+def InitListExpr : DStmt<Expr>;
+def DesignatedInitExpr : DStmt<Expr>;
+def ImplicitValueInitExpr : DStmt<Expr>;
+def ParenListExpr : DStmt<Expr>;
+def VAArgExpr : DStmt<Expr>;
+
+// GNU Extensions.
+def AddrLabelExpr : DStmt<Expr>;
+def StmtExpr : DStmt<Expr>;
+def TypesCompatibleExpr : DStmt<Expr>;
+def ChooseExpr : DStmt<Expr>;
+def GNUNullExpr : DStmt<Expr>;
+
+// C++ Expressions.
+def CXXOperatorCallExpr : DStmt<CallExpr>;
+def CXXMemberCallExpr : DStmt<CallExpr>;
+def CXXNamedCastExpr : DStmt<ExplicitCastExpr, 1>;
+def CXXStaticCastExpr : DStmt<CXXNamedCastExpr>;
+def CXXDynamicCastExpr : DStmt<CXXNamedCastExpr>;
+def CXXReinterpretCastExpr : DStmt<CXXNamedCastExpr>;
+def CXXConstCastExpr : DStmt<CXXNamedCastExpr>;
+def CXXFunctionalCastExpr : DStmt<ExplicitCastExpr>;
+def CXXTypeidExpr : DStmt<Expr>;
+def CXXBoolLiteralExpr : DStmt<Expr>;
+def CXXNullPtrLiteralExpr : DStmt<Expr>;
+def CXXThisExpr : DStmt<Expr>;
+def CXXThrowExpr : DStmt<Expr>;
+def CXXDefaultArgExpr : DStmt<Expr>;
+def CXXZeroInitValueExpr : DStmt<Expr>;
+def CXXNewExpr : DStmt<Expr>;
+def CXXDeleteExpr : DStmt<Expr>;
+def CXXPseudoDestructorExpr : DStmt<Expr>;
+def UnresolvedLookupExpr : DStmt<Expr>;
+def UnaryTypeTraitExpr : DStmt<Expr>;
+def DependentScopeDeclRefExpr : DStmt<Expr>;
+def CXXConstructExpr : DStmt<Expr>;
+def CXXBindTemporaryExpr : DStmt<Expr>;
+def CXXBindReferenceExpr : DStmt<Expr>;
+def CXXExprWithTemporaries : DStmt<Expr>;
+def CXXTemporaryObjectExpr : DStmt<CXXConstructExpr>;
+def CXXUnresolvedConstructExpr : DStmt<Expr>;
+def CXXDependentScopeMemberExpr : DStmt<Expr>;
+def UnresolvedMemberExpr : DStmt<Expr>;
+
+// Obj-C Expressions.
+def ObjCStringLiteral : DStmt<Expr>;
+def ObjCEncodeExpr : DStmt<Expr>;
+def ObjCMessageExpr : DStmt<Expr>;
+def ObjCSelectorExpr : DStmt<Expr>;
+def ObjCProtocolExpr : DStmt<Expr>;
+def ObjCIvarRefExpr : DStmt<Expr>;
+def ObjCPropertyRefExpr : DStmt<Expr>;
+def ObjCImplicitSetterGetterRefExpr : DStmt<Expr>;
+def ObjCSuperExpr : DStmt<Expr>;
+def ObjCIsaExpr : DStmt<Expr>;
+
+// Clang Extensions.
+def ShuffleVectorExpr : DStmt<Expr>;
+def BlockExpr : DStmt<Expr>;
+def BlockDeclRefExpr : DStmt<Expr>;
diff --git a/include/clang/AST/StmtVisitor.h b/include/clang/AST/StmtVisitor.h
index 4986f08ac124..8078451fa31f 100644
--- a/include/clang/AST/StmtVisitor.h
+++ b/include/clang/AST/StmtVisitor.h
@@ -105,10 +105,10 @@ public:
// Top switch stmt: dispatch to VisitFooStmt for each FooStmt.
switch (S->getStmtClass()) {
default: assert(0 && "Unknown stmt kind!");
-#define ABSTRACT_EXPR(CLASS, PARENT)
+#define ABSTRACT_STMT(STMT)
#define STMT(CLASS, PARENT) \
case Stmt::CLASS ## Class: DISPATCH(CLASS, CLASS);
-#include "clang/AST/StmtNodes.def"
+#include "clang/AST/StmtNodes.inc"
}
}
@@ -116,7 +116,7 @@ public:
// back on VisitExpr or whatever else is the superclass.
#define STMT(CLASS, PARENT) \
RetTy Visit ## CLASS(CLASS *S) { DISPATCH(PARENT, PARENT); }
-#include "clang/AST/StmtNodes.def"
+#include "clang/AST/StmtNodes.inc"
// If the implementation doesn't implement binary operator methods, fall back
// on VisitBinaryOperator.
diff --git a/include/clang/AST/TemplateBase.h b/include/clang/AST/TemplateBase.h
index 50a100c6af13..8b38001bd104 100644
--- a/include/clang/AST/TemplateBase.h
+++ b/include/clang/AST/TemplateBase.h
@@ -28,6 +28,7 @@ namespace llvm {
namespace clang {
class Decl;
+class DiagnosticBuilder;
class Expr;
class TypeSourceInfo;
@@ -473,6 +474,9 @@ public:
}
};
-}
+const DiagnosticBuilder &operator<<(const DiagnosticBuilder &DB,
+ const TemplateArgument &Arg);
+
+} // end namespace clang
#endif
diff --git a/include/clang/AST/TemplateName.h b/include/clang/AST/TemplateName.h
index f3de9fa011bc..2e3b6df0549b 100644
--- a/include/clang/AST/TemplateName.h
+++ b/include/clang/AST/TemplateName.h
@@ -188,7 +188,7 @@ const DiagnosticBuilder &operator<<(const DiagnosticBuilder &DB,
/// declaration for "vector". The QualifiedTemplateName class is only
/// used to provide "sugar" for template names that were expressed
/// with a qualified name, and has no semantic meaning. In this
-/// manner, it is to TemplateName what QualifiedNameType is to Type,
+/// manner, it is to TemplateName what ElaboratedType is to Type,
/// providing extra syntactic sugar for downstream clients.
class QualifiedTemplateName : public llvm::FoldingSetNode {
/// \brief The nested name specifier that qualifies the template name.
diff --git a/include/clang/AST/Type.h b/include/clang/AST/Type.h
index 030c74c64089..c24bddb30082 100644
--- a/include/clang/AST/Type.h
+++ b/include/clang/AST/Type.h
@@ -92,7 +92,7 @@ namespace clang {
class TemplateArgumentLoc;
class TemplateArgumentListInfo;
class Type;
- class QualifiedNameType;
+ class ElaboratedType;
struct PrintingPolicy;
template <typename> class CanQual;
@@ -396,7 +396,8 @@ enum CallingConv {
CC_Default,
CC_C, // __attribute__((cdecl))
CC_X86StdCall, // __attribute__((stdcall))
- CC_X86FastCall // __attribute__((fastcall))
+ CC_X86FastCall, // __attribute__((fastcall))
+ CC_X86ThisCall // __attribute__((thiscall))
};
@@ -755,6 +756,9 @@ public:
};
private:
+ Type(const Type&); // DO NOT IMPLEMENT.
+ void operator=(const Type&); // DO NOT IMPLEMENT.
+
QualType CanonicalType;
/// TypeClass bitfield - Enum that specifies what subclass this belongs to.
@@ -764,15 +768,25 @@ private:
/// Note that this should stay at the end of the ivars for Type so that
/// subclasses can pack their bitfields into the same word.
bool Dependent : 1;
-
- Type(const Type&); // DO NOT IMPLEMENT.
- void operator=(const Type&); // DO NOT IMPLEMENT.
+
+ /// \brief Whether the linkage of this type is already known.
+ mutable bool LinkageKnown : 1;
+
+ /// \brief Linkage of this type.
+ mutable unsigned CachedLinkage : 2;
+
protected:
+ /// \brief Compute the linkage of this type.
+ virtual Linkage getLinkageImpl() const;
+
+ enum { BitsRemainingInType = 20 };
+
// silence VC++ warning C4355: 'this' : used in base member initializer list
Type *this_() { return this; }
Type(TypeClass tc, QualType Canonical, bool dependent)
: CanonicalType(Canonical.isNull() ? QualType(this_(), 0) : Canonical),
- TC(tc), Dependent(dependent) {}
+ TC(tc), Dependent(dependent), LinkageKnown(false),
+ CachedLinkage(NoLinkage) {}
virtual ~Type() {}
virtual void Destroy(ASTContext& C);
friend class ASTContext;
@@ -879,7 +893,7 @@ public:
bool isObjCObjectPointerType() const; // Pointer to *any* ObjC object.
// FIXME: change this to 'raw' interface type, so we can used 'interface' type
// for the common case.
- bool isObjCInterfaceType() const; // NSString or NSString<foo>
+ bool isObjCObjectType() const; // NSString or typeof(*(id)0)
bool isObjCQualifiedInterfaceType() const; // NSString<foo>
bool isObjCQualifiedIdType() const; // id<foo>
bool isObjCQualifiedClassType() const; // Class<foo>
@@ -920,7 +934,7 @@ public:
// for object declared using an interface.
const ObjCObjectPointerType *getAsObjCInterfacePointerType() const;
const ObjCObjectPointerType *getAsObjCQualifiedIdType() const;
- const ObjCInterfaceType *getAsObjCQualifiedInterfaceType() const;
+ const ObjCObjectType *getAsObjCQualifiedInterfaceType() const;
const CXXRecordDecl *getCXXRecordDeclForPointerType() const;
/// \brief Retrieves the CXXRecordDecl that this type refers to, either
@@ -935,10 +949,6 @@ public:
// immediately following this class.
template <typename T> const T *getAs() const;
- /// getAsPointerToObjCInterfaceType - If this is a pointer to an ObjC
- /// interface, return the interface type, otherwise return null.
- const ObjCInterfaceType *getAsPointerToObjCInterfaceType() const;
-
/// getArrayElementTypeNoTypeQual - If this is an array type, return the
/// element type of the array, potentially with type qualifiers missing.
/// This method should never be used when type qualifiers are meaningful.
@@ -977,10 +987,13 @@ public:
/// set of type specifiers.
bool isSpecifierType() const;
- const char *getTypeClassName() const;
-
/// \brief Determine the linkage of this type.
- virtual Linkage getLinkage() const;
+ Linkage getLinkage() const;
+
+ /// \brief Note that the linkage is no longer known.
+ void ClearLinkageCache();
+
+ const char *getTypeClassName() const;
QualType getCanonicalTypeInternal() const {
return CanonicalType;
@@ -1040,12 +1053,25 @@ public:
UndeducedAuto, // In C++0x, this represents the type of an auto variable
// that has not been deduced yet.
- ObjCId, // This represents the ObjC 'id' type.
- ObjCClass, // This represents the ObjC 'Class' type.
+
+ /// The primitive Objective C 'id' type. The type pointed to by the
+ /// user-visible 'id' type. Only ever shows up in an AST as the base
+ /// type of an ObjCObjectType.
+ ObjCId,
+
+ /// The primitive Objective C 'Class' type. The type pointed to by the
+ /// user-visible 'Class' type. Only ever shows up in an AST as the
+ /// base type of an ObjCObjectType.
+ ObjCClass,
+
ObjCSel // This represents the ObjC 'SEL' type.
};
private:
Kind TypeKind;
+
+protected:
+ virtual Linkage getLinkageImpl() const;
+
public:
BuiltinType(Kind K)
: Type(Builtin, QualType(), /*Dependent=*/(K == Dependent)),
@@ -1073,8 +1099,6 @@ public:
return TypeKind >= Float && TypeKind <= LongDouble;
}
- virtual Linkage getLinkage() const;
-
static bool classof(const Type *T) { return T->getTypeClass() == Builtin; }
static bool classof(const BuiltinType *) { return true; }
};
@@ -1089,6 +1113,10 @@ class ComplexType : public Type, public llvm::FoldingSetNode {
ElementType(Element) {
}
friend class ASTContext; // ASTContext creates these.
+
+protected:
+ virtual Linkage getLinkageImpl() const;
+
public:
QualType getElementType() const { return ElementType; }
@@ -1102,8 +1130,6 @@ public:
ID.AddPointer(Element.getAsOpaquePtr());
}
- virtual Linkage getLinkage() const;
-
static bool classof(const Type *T) { return T->getTypeClass() == Complex; }
static bool classof(const ComplexType *) { return true; }
};
@@ -1117,6 +1143,10 @@ class PointerType : public Type, public llvm::FoldingSetNode {
Type(Pointer, CanonicalPtr, Pointee->isDependentType()), PointeeType(Pointee) {
}
friend class ASTContext; // ASTContext creates these.
+
+protected:
+ virtual Linkage getLinkageImpl() const;
+
public:
QualType getPointeeType() const { return PointeeType; }
@@ -1131,8 +1161,6 @@ public:
ID.AddPointer(Pointee.getAsOpaquePtr());
}
- virtual Linkage getLinkage() const;
-
static bool classof(const Type *T) { return T->getTypeClass() == Pointer; }
static bool classof(const PointerType *) { return true; }
};
@@ -1148,6 +1176,10 @@ class BlockPointerType : public Type, public llvm::FoldingSetNode {
PointeeType(Pointee) {
}
friend class ASTContext; // ASTContext creates these.
+
+protected:
+ virtual Linkage getLinkageImpl() const;
+
public:
// Get the pointee type. Pointee is required to always be a function type.
@@ -1163,8 +1195,6 @@ public:
ID.AddPointer(Pointee.getAsOpaquePtr());
}
- virtual Linkage getLinkage() const;
-
static bool classof(const Type *T) {
return T->getTypeClass() == BlockPointer;
}
@@ -1200,6 +1230,9 @@ protected:
PointeeType(Referencee), SpelledAsLValue(SpelledAsLValue),
InnerRef(Referencee->isReferenceType()) {
}
+
+ virtual Linkage getLinkageImpl() const;
+
public:
bool isSpelledAsLValue() const { return SpelledAsLValue; }
bool isInnerRef() const { return InnerRef; }
@@ -1223,8 +1256,6 @@ public:
ID.AddBoolean(SpelledAsLValue);
}
- virtual Linkage getLinkage() const;
-
static bool classof(const Type *T) {
return T->getTypeClass() == LValueReference ||
T->getTypeClass() == RValueReference;
@@ -1281,6 +1312,10 @@ class MemberPointerType : public Type, public llvm::FoldingSetNode {
PointeeType(Pointee), Class(Cls) {
}
friend class ASTContext; // ASTContext creates these.
+
+protected:
+ virtual Linkage getLinkageImpl() const;
+
public:
QualType getPointeeType() const { return PointeeType; }
@@ -1299,8 +1334,6 @@ public:
ID.AddPointer(Class);
}
- virtual Linkage getLinkage() const;
-
static bool classof(const Type *T) {
return T->getTypeClass() == MemberPointer;
}
@@ -1342,6 +1375,9 @@ protected:
ElementType(et), SizeModifier(sm), IndexTypeQuals(tq) {}
friend class ASTContext; // ASTContext creates these.
+
+ virtual Linkage getLinkageImpl() const;
+
public:
QualType getElementType() const { return ElementType; }
ArraySizeModifier getSizeModifier() const {
@@ -1352,8 +1388,6 @@ public:
}
unsigned getIndexTypeCVRQualifiers() const { return IndexTypeQuals; }
- virtual Linkage getLinkage() const;
-
static bool classof(const Type *T) {
return T->getTypeClass() == ConstantArray ||
T->getTypeClass() == VariableArray ||
@@ -1629,6 +1663,9 @@ protected:
: Type(tc, canonType, vecType->isDependentType()), ElementType(vecType),
NumElements(nElements), AltiVec(isAltiVec), Pixel(isPixel) {}
friend class ASTContext; // ASTContext creates these.
+
+ virtual Linkage getLinkageImpl() const;
+
public:
QualType getElementType() const { return ElementType; }
@@ -1655,8 +1692,6 @@ public:
ID.AddBoolean(isPixel);
}
- virtual Linkage getLinkage() const;
-
static bool classof(const Type *T) {
return T->getTypeClass() == Vector || T->getTypeClass() == ExtVector;
}
@@ -1733,6 +1768,8 @@ public:
/// class of FunctionNoProtoType and FunctionProtoType.
///
class FunctionType : public Type {
+ virtual void ANCHOR(); // Key function for FunctionType.
+
/// SubClassData - This field is owned by the subclass, put here to pack
/// tightly with the ivars in Type.
bool SubClassData : 1;
@@ -1753,7 +1790,7 @@ class FunctionType : public Type {
unsigned RegParm : 3;
/// CallConv - The calling convention used by the function.
- unsigned CallConv : 2;
+ unsigned CallConv : 3;
// The type returned by the function.
QualType ResultType;
@@ -1821,7 +1858,7 @@ class FunctionType : public Type {
// The value passed to __attribute__((regparm(x)))
unsigned RegParm;
// The calling convention as specified via
- // __attribute__((cdecl|stdcall||fastcall))
+ // __attribute__((cdecl|stdcall|fastcall|thiscall))
CallingConv CC;
};
@@ -1862,6 +1899,10 @@ class FunctionNoProtoType : public FunctionType, public llvm::FoldingSetNode {
: FunctionType(FunctionNoProto, Result, false, 0, Canonical,
/*Dependent=*/false, Info) {}
friend class ASTContext; // ASTContext creates these.
+
+protected:
+ virtual Linkage getLinkageImpl() const;
+
public:
// No additional state past what FunctionType provides.
@@ -1879,8 +1920,6 @@ public:
ID.AddPointer(ResultType.getAsOpaquePtr());
}
- virtual Linkage getLinkage() const;
-
static bool classof(const Type *T) {
return T->getTypeClass() == FunctionNoProto;
}
@@ -1944,6 +1983,9 @@ class FunctionProtoType : public FunctionType, public llvm::FoldingSetNode {
friend class ASTContext; // ASTContext creates these.
+protected:
+ virtual Linkage getLinkageImpl() const;
+
public:
unsigned getNumArgs() const { return NumArgs; }
QualType getArgType(unsigned i) const {
@@ -1984,8 +2026,6 @@ public:
bool isSugared() const { return false; }
QualType desugar() const { return QualType(this, 0); }
- virtual Linkage getLinkage() const;
-
static bool classof(const Type *T) {
return T->getTypeClass() == FunctionProto;
}
@@ -2190,6 +2230,8 @@ class TagType : public Type {
protected:
TagType(TypeClass TC, const TagDecl *D, QualType can);
+ virtual Linkage getLinkageImpl() const;
+
public:
TagDecl *getDecl() const { return decl.getPointer(); }
@@ -2198,8 +2240,6 @@ public:
bool isBeingDefined() const { return decl.getInt(); }
void setBeingDefined(bool Def) const { decl.setInt(Def? 1 : 0); }
- virtual Linkage getLinkage() const;
-
static bool classof(const Type *T) {
return T->getTypeClass() >= TagFirst && T->getTypeClass() <= TagLast;
}
@@ -2264,68 +2304,6 @@ public:
static bool classof(const EnumType *) { return true; }
};
-/// ElaboratedType - A non-canonical type used to represents uses of
-/// elaborated type specifiers in C++. For example:
-///
-/// void foo(union MyUnion);
-/// ^^^^^^^^^^^^^
-///
-/// At the moment, for efficiency we do not create elaborated types in
-/// C, since outside of typedefs all references to structs would
-/// necessarily be elaborated.
-class ElaboratedType : public Type, public llvm::FoldingSetNode {
-public:
- enum TagKind {
- TK_struct,
- TK_union,
- TK_class,
- TK_enum
- };
-
-private:
- /// The tag that was used in this elaborated type specifier.
- TagKind Tag;
-
- /// The underlying type.
- QualType UnderlyingType;
-
- explicit ElaboratedType(QualType Ty, TagKind Tag, QualType Canon)
- : Type(Elaborated, Canon, Canon->isDependentType()),
- Tag(Tag), UnderlyingType(Ty) { }
- friend class ASTContext; // ASTContext creates these.
-
-public:
- TagKind getTagKind() const { return Tag; }
- QualType getUnderlyingType() const { return UnderlyingType; }
-
- /// \brief Remove a single level of sugar.
- QualType desugar() const { return getUnderlyingType(); }
-
- /// \brief Returns whether this type directly provides sugar.
- bool isSugared() const { return true; }
-
- static const char *getNameForTagKind(TagKind Kind) {
- switch (Kind) {
- default: assert(0 && "Unknown TagKind!");
- case TK_struct: return "struct";
- case TK_union: return "union";
- case TK_class: return "class";
- case TK_enum: return "enum";
- }
- }
-
- void Profile(llvm::FoldingSetNodeID &ID) {
- Profile(ID, getUnderlyingType(), getTagKind());
- }
- static void Profile(llvm::FoldingSetNodeID &ID, QualType T, TagKind Tag) {
- ID.AddPointer(T.getAsOpaquePtr());
- ID.AddInteger(Tag);
- }
-
- static bool classof(const ElaboratedType*) { return true; }
- static bool classof(const Type *T) { return T->getTypeClass() == Elaborated; }
-};
-
class TemplateTypeParmType : public Type, public llvm::FoldingSetNode {
unsigned Depth : 15;
unsigned Index : 16;
@@ -2592,46 +2570,116 @@ public:
static bool classof(const InjectedClassNameType *T) { return true; }
};
+/// \brief The kind of a tag type.
+enum TagTypeKind {
+ /// \brief The "struct" keyword.
+ TTK_Struct,
+ /// \brief The "union" keyword.
+ TTK_Union,
+ /// \brief The "class" keyword.
+ TTK_Class,
+ /// \brief The "enum" keyword.
+ TTK_Enum
+};
+
/// \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 "class" keyword introduces the elaborated-type-specifier.
+ ETK_Class,
/// \brief The "enum" keyword introduces the elaborated-type-specifier.
- ETK_Enum
+ ETK_Enum,
+ /// \brief The "typename" keyword precedes the qualified type name, e.g.,
+ /// \c typename T::type.
+ ETK_Typename,
+ /// \brief No keyword precedes the qualified type name.
+ ETK_None
};
-
-/// \brief Represents a type that was referred to via a qualified
-/// name, e.g., N::M::type.
+
+/// A helper class for Type nodes having an ElaboratedTypeKeyword.
+/// The keyword in stored in the free bits of the base class.
+/// Also provides a few static helpers for converting and printing
+/// elaborated type keyword and tag type kind enumerations.
+class TypeWithKeyword : public Type {
+ /// Keyword - Encodes an ElaboratedTypeKeyword enumeration constant.
+ unsigned Keyword : 3;
+
+protected:
+ TypeWithKeyword(ElaboratedTypeKeyword Keyword, TypeClass tc,
+ QualType Canonical, bool dependent)
+ : Type(tc, Canonical, dependent), Keyword(Keyword) {}
+
+public:
+ virtual ~TypeWithKeyword(); // pin vtable to Type.cpp
+
+ ElaboratedTypeKeyword getKeyword() const {
+ return static_cast<ElaboratedTypeKeyword>(Keyword);
+ }
+
+ /// getKeywordForTypeSpec - Converts a type specifier (DeclSpec::TST)
+ /// into an elaborated type keyword.
+ static ElaboratedTypeKeyword getKeywordForTypeSpec(unsigned TypeSpec);
+
+ /// getTagTypeKindForTypeSpec - Converts a type specifier (DeclSpec::TST)
+ /// into a tag type kind. It is an error to provide a type specifier
+ /// which *isn't* a tag kind here.
+ static TagTypeKind getTagTypeKindForTypeSpec(unsigned TypeSpec);
+
+ /// getKeywordForTagDeclKind - Converts a TagTypeKind into an
+ /// elaborated type keyword.
+ static ElaboratedTypeKeyword getKeywordForTagTypeKind(TagTypeKind Tag);
+
+ /// getTagTypeKindForKeyword - Converts an elaborated type keyword into
+ // a TagTypeKind. It is an error to provide an elaborated type keyword
+ /// which *isn't* a tag kind here.
+ static TagTypeKind getTagTypeKindForKeyword(ElaboratedTypeKeyword Keyword);
+
+ static bool KeywordIsTagTypeKind(ElaboratedTypeKeyword Keyword);
+
+ static const char *getKeywordName(ElaboratedTypeKeyword Keyword);
+
+ static const char *getTagTypeKindName(TagTypeKind Kind) {
+ return getKeywordName(getKeywordForTagTypeKind(Kind));
+ }
+
+ class CannotCastToThisType {};
+ static CannotCastToThisType classof(const Type *);
+};
+
+/// \brief Represents a type that was referred to using an elaborated type
+/// keyword, e.g., struct S, or via a qualified name, e.g., N::M::type,
+/// or both.
///
/// This type is used to keep track of a type name as written in the
-/// source code, including any nested-name-specifiers. The type itself
-/// is always "sugar", used to express what was written in the source
-/// code but containing no additional semantic information.
-class QualifiedNameType : public Type, public llvm::FoldingSetNode {
+/// source code, including tag keywords and any nested-name-specifiers.
+/// The type itself is always "sugar", used to express what was written
+/// in the source code but containing no additional semantic information.
+class ElaboratedType : public TypeWithKeyword, public llvm::FoldingSetNode {
+
/// \brief The nested name specifier containing the qualifier.
NestedNameSpecifier *NNS;
/// \brief The type that this qualified name refers to.
QualType NamedType;
- QualifiedNameType(NestedNameSpecifier *NNS, QualType NamedType,
- QualType CanonType)
- : Type(QualifiedName, CanonType, NamedType->isDependentType()),
- NNS(NNS), NamedType(NamedType) { }
+ ElaboratedType(ElaboratedTypeKeyword Keyword, NestedNameSpecifier *NNS,
+ QualType NamedType, QualType CanonType)
+ : TypeWithKeyword(Keyword, Elaborated, CanonType,
+ NamedType->isDependentType()),
+ NNS(NNS), NamedType(NamedType) {
+ assert(!(Keyword == ETK_None && NNS == 0) &&
+ "ElaboratedType cannot have elaborated type keyword "
+ "and name qualifier both null.");
+ }
friend class ASTContext; // ASTContext creates these
public:
+
/// \brief Retrieve the qualification on this type.
NestedNameSpecifier *getQualifier() const { return NNS; }
@@ -2645,19 +2693,20 @@ public:
bool isSugared() const { return true; }
void Profile(llvm::FoldingSetNodeID &ID) {
- Profile(ID, NNS, NamedType);
+ Profile(ID, getKeyword(), NNS, NamedType);
}
- static void Profile(llvm::FoldingSetNodeID &ID, NestedNameSpecifier *NNS,
- QualType NamedType) {
+ static void Profile(llvm::FoldingSetNodeID &ID, ElaboratedTypeKeyword Keyword,
+ NestedNameSpecifier *NNS, QualType NamedType) {
+ ID.AddInteger(Keyword);
ID.AddPointer(NNS);
NamedType.Profile(ID);
}
static bool classof(const Type *T) {
- return T->getTypeClass() == QualifiedName;
+ return T->getTypeClass() == Elaborated;
}
- static bool classof(const QualifiedNameType *T) { return true; }
+ static bool classof(const ElaboratedType *T) { return true; }
};
/// \brief Represents a qualified type name for which the type name is
@@ -2669,10 +2718,8 @@ public:
/// 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;
-
+class DependentNameType : public TypeWithKeyword, public llvm::FoldingSetNode {
+
/// \brief The nested name specifier containing the qualifier.
NestedNameSpecifier *NNS;
@@ -2684,16 +2731,16 @@ class DependentNameType : public Type, public llvm::FoldingSetNode {
DependentNameType(ElaboratedTypeKeyword Keyword, NestedNameSpecifier *NNS,
const IdentifierInfo *Name, QualType CanonType)
- : Type(DependentName, CanonType, true),
- Keyword(Keyword), NNS(NNS), Name(Name) {
+ : TypeWithKeyword(Keyword, DependentName, CanonType, true),
+ NNS(NNS), Name(Name) {
assert(NNS->isDependent() &&
"DependentNameType requires a dependent nested-name-specifier");
}
DependentNameType(ElaboratedTypeKeyword Keyword, NestedNameSpecifier *NNS,
const TemplateSpecializationType *Ty, QualType CanonType)
- : Type(DependentName, CanonType, true),
- Keyword(Keyword), NNS(NNS), Name(Ty) {
+ : TypeWithKeyword(Keyword, DependentName, CanonType, true),
+ NNS(NNS), Name(Ty) {
assert(NNS->isDependent() &&
"DependentNameType requires a dependent nested-name-specifier");
}
@@ -2701,9 +2748,7 @@ class DependentNameType : public Type, public llvm::FoldingSetNode {
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; }
@@ -2727,7 +2772,7 @@ public:
QualType desugar() const { return QualType(this, 0); }
void Profile(llvm::FoldingSetNodeID &ID) {
- Profile(ID, Keyword, NNS, Name);
+ Profile(ID, getKeyword(), NNS, Name);
}
static void Profile(llvm::FoldingSetNodeID &ID, ElaboratedTypeKeyword Keyword,
@@ -2743,153 +2788,333 @@ public:
static bool classof(const DependentNameType *T) { return true; }
};
-/// ObjCInterfaceType - Interfaces are the core concept in Objective-C for
-/// object oriented design. They basically correspond to C++ classes. There
-/// are two kinds of interface types, normal interfaces like "NSString" and
-/// qualified interfaces, which are qualified with a protocol list like
-/// "NSString<NSCopyable, NSAmazing>".
-class ObjCInterfaceType : public Type, public llvm::FoldingSetNode {
- ObjCInterfaceDecl *Decl;
+/// ObjCObjectType - Represents a class type in Objective C.
+/// Every Objective C type is a combination of a base type and a
+/// list of protocols.
+///
+/// Given the following declarations:
+/// @class C;
+/// @protocol P;
+///
+/// 'C' is an ObjCInterfaceType C. It is sugar for an ObjCObjectType
+/// with base C and no protocols.
+///
+/// 'C<P>' is an ObjCObjectType with base C and protocol list [P].
+///
+/// 'id' is a TypedefType which is sugar for an ObjCPointerType whose
+/// pointee is an ObjCObjectType with base BuiltinType::ObjCIdType
+/// and no protocols.
+///
+/// 'id<P>' is an ObjCPointerType whose pointee is an ObjCObjecType
+/// with base BuiltinType::ObjCIdType and protocol list [P]. Eventually
+/// this should get its own sugar class to better represent the source.
+class ObjCObjectType : public Type {
+ // Pad the bit count up so that NumProtocols is 2-byte aligned
+ unsigned : BitsRemainingInType - 16;
+
+ /// \brief The number of protocols stored after the
+ /// ObjCObjectPointerType node.
+ ///
+ /// These protocols are those written directly on the type. If
+ /// protocol qualifiers ever become additive, the iterators will
+ /// get kindof complicated.
+ ///
+ /// In the canonical object type, these are sorted alphabetically
+ /// and uniqued.
+ unsigned NumProtocols : 16;
- /// \brief The number of protocols stored after the ObjCInterfaceType node.
- /// The list of protocols is sorted on protocol name. No protocol is enterred
- /// more than once.
- unsigned NumProtocols;
+ /// Either a BuiltinType or an InterfaceType or sugar for either.
+ QualType BaseType;
- ObjCInterfaceType(QualType Canonical, ObjCInterfaceDecl *D,
- ObjCProtocolDecl **Protos, unsigned NumP);
- friend class ASTContext; // ASTContext creates these.
+ ObjCProtocolDecl * const *getProtocolStorage() const {
+ return const_cast<ObjCObjectType*>(this)->getProtocolStorage();
+ }
+
+ ObjCProtocolDecl **getProtocolStorage();
+
+protected:
+ ObjCObjectType(QualType Canonical, QualType Base,
+ ObjCProtocolDecl * const *Protocols, unsigned NumProtocols);
+
+ enum Nonce_ObjCInterface { Nonce_ObjCInterface };
+ ObjCObjectType(enum Nonce_ObjCInterface)
+ : Type(ObjCInterface, QualType(), false),
+ NumProtocols(0),
+ BaseType(QualType(this_(), 0)) {}
+
+protected:
+ Linkage getLinkageImpl() const; // key function
+
public:
- void Destroy(ASTContext& C);
+ /// getBaseType - Gets the base type of this object type. This is
+ /// always (possibly sugar for) one of:
+ /// - the 'id' builtin type (as opposed to the 'id' type visible to the
+ /// user, which is a typedef for an ObjCPointerType)
+ /// - the 'Class' builtin type (same caveat)
+ /// - an ObjCObjectType (currently always an ObjCInterfaceType)
+ QualType getBaseType() const { return BaseType; }
+
+ bool isObjCId() const {
+ return getBaseType()->isSpecificBuiltinType(BuiltinType::ObjCId);
+ }
+ bool isObjCClass() const {
+ return getBaseType()->isSpecificBuiltinType(BuiltinType::ObjCClass);
+ }
+ bool isObjCUnqualifiedId() const { return qual_empty() && isObjCId(); }
+ bool isObjCUnqualifiedClass() const { return qual_empty() && isObjCClass(); }
+ bool isObjCUnqualifiedIdOrClass() const {
+ if (!qual_empty()) return false;
+ if (const BuiltinType *T = getBaseType()->getAs<BuiltinType>())
+ return T->getKind() == BuiltinType::ObjCId ||
+ T->getKind() == BuiltinType::ObjCClass;
+ return false;
+ }
+ bool isObjCQualifiedId() const { return !qual_empty() && isObjCId(); }
+ bool isObjCQualifiedClass() const { return !qual_empty() && isObjCClass(); }
- ObjCInterfaceDecl *getDecl() const { return Decl; }
+ /// Gets the interface declaration for this object type, if the base type
+ /// really is an interface.
+ ObjCInterfaceDecl *getInterface() const;
+
+ typedef ObjCProtocolDecl * const *qual_iterator;
+
+ qual_iterator qual_begin() const { return getProtocolStorage(); }
+ qual_iterator qual_end() const { return qual_begin() + getNumProtocols(); }
+
+ bool qual_empty() const { return getNumProtocols() == 0; }
/// getNumProtocols - Return the number of qualifying protocols in this
/// interface type, or 0 if there are none.
unsigned getNumProtocols() const { return NumProtocols; }
- /// \brief Retrieve the Ith protocol.
+ /// \brief Fetch a protocol by index.
ObjCProtocolDecl *getProtocol(unsigned I) const {
assert(I < getNumProtocols() && "Out-of-range protocol access");
return qual_begin()[I];
}
- /// qual_iterator and friends: this provides access to the (potentially empty)
- /// list of protocols qualifying this interface.
- typedef ObjCProtocolDecl* const * qual_iterator;
- qual_iterator qual_begin() const {
- return reinterpret_cast<qual_iterator>(this + 1);
- }
- qual_iterator qual_end() const {
- return qual_begin() + NumProtocols;
- }
- bool qual_empty() const { return NumProtocols == 0; }
-
bool isSugared() const { return false; }
QualType desugar() const { return QualType(this, 0); }
+ static bool classof(const Type *T) {
+ return T->getTypeClass() == ObjCObject ||
+ T->getTypeClass() == ObjCInterface;
+ }
+ static bool classof(const ObjCObjectType *) { return true; }
+};
+
+/// ObjCObjectTypeImpl - A class providing a concrete implementation
+/// of ObjCObjectType, so as to not increase the footprint of
+/// ObjCInterfaceType. Code outside of ASTContext and the core type
+/// system should not reference this type.
+class ObjCObjectTypeImpl : public ObjCObjectType, public llvm::FoldingSetNode {
+ friend class ASTContext;
+
+ // If anyone adds fields here, ObjCObjectType::getProtocolStorage()
+ // will need to be modified.
+
+ ObjCObjectTypeImpl(QualType Canonical, QualType Base,
+ ObjCProtocolDecl * const *Protocols,
+ unsigned NumProtocols)
+ : ObjCObjectType(Canonical, Base, Protocols, NumProtocols) {}
+
+public:
+ void Destroy(ASTContext& C); // key function
+
void Profile(llvm::FoldingSetNodeID &ID);
static void Profile(llvm::FoldingSetNodeID &ID,
- const ObjCInterfaceDecl *Decl,
- ObjCProtocolDecl * const *protocols,
- unsigned NumProtocols);
+ QualType Base,
+ ObjCProtocolDecl *const *protocols,
+ unsigned NumProtocols);
+};
- virtual Linkage getLinkage() const;
+inline ObjCProtocolDecl **ObjCObjectType::getProtocolStorage() {
+ return reinterpret_cast<ObjCProtocolDecl**>(
+ static_cast<ObjCObjectTypeImpl*>(this) + 1);
+}
+
+/// ObjCInterfaceType - Interfaces are the core concept in Objective-C for
+/// object oriented design. They basically correspond to C++ classes. There
+/// are two kinds of interface types, normal interfaces like "NSString" and
+/// qualified interfaces, which are qualified with a protocol list like
+/// "NSString<NSCopyable, NSAmazing>".
+///
+/// ObjCInterfaceType guarantees the following properties when considered
+/// as a subtype of its superclass, ObjCObjectType:
+/// - There are no protocol qualifiers. To reinforce this, code which
+/// tries to invoke the protocol methods via an ObjCInterfaceType will
+/// fail to compile.
+/// - It is its own base type. That is, if T is an ObjCInterfaceType*,
+/// T->getBaseType() == QualType(T, 0).
+class ObjCInterfaceType : public ObjCObjectType {
+ ObjCInterfaceDecl *Decl;
+
+ ObjCInterfaceType(const ObjCInterfaceDecl *D)
+ : ObjCObjectType(Nonce_ObjCInterface),
+ Decl(const_cast<ObjCInterfaceDecl*>(D)) {}
+ friend class ASTContext; // ASTContext creates these.
+public:
+ void Destroy(ASTContext& C); // key function
+
+ /// getDecl - Get the declaration of this interface.
+ ObjCInterfaceDecl *getDecl() const { return Decl; }
+
+ bool isSugared() const { return false; }
+ QualType desugar() const { return QualType(this, 0); }
static bool classof(const Type *T) {
return T->getTypeClass() == ObjCInterface;
}
static bool classof(const ObjCInterfaceType *) { return true; }
+
+ // Nonsense to "hide" certain members of ObjCObjectType within this
+ // class. People asking for protocols on an ObjCInterfaceType are
+ // not going to get what they want: ObjCInterfaceTypes are
+ // guaranteed to have no protocols.
+ enum {
+ qual_iterator,
+ qual_begin,
+ qual_end,
+ getNumProtocols,
+ getProtocol
+ };
};
-/// ObjCObjectPointerType - Used to represent 'id', 'Interface *', 'id <p>',
-/// and 'Interface <p> *'.
+inline ObjCInterfaceDecl *ObjCObjectType::getInterface() const {
+ if (const ObjCInterfaceType *T =
+ getBaseType()->getAs<ObjCInterfaceType>())
+ return T->getDecl();
+ return 0;
+}
+
+/// ObjCObjectPointerType - Used to represent a pointer to an
+/// Objective C object. These are constructed from pointer
+/// declarators when the pointee type is an ObjCObjectType (or sugar
+/// for one). In addition, the 'id' and 'Class' types are typedefs
+/// for these, and the protocol-qualified types 'id<P>' and 'Class<P>'
+/// are translated into these.
///
-/// Duplicate protocols are removed and protocol list is canonicalized to be in
-/// alphabetical order.
+/// Pointers to pointers to Objective C objects are still PointerTypes;
+/// only the first level of pointer gets it own type implementation.
class ObjCObjectPointerType : public Type, public llvm::FoldingSetNode {
- QualType PointeeType; // A builtin or interface type.
-
- /// \brief The number of protocols stored after the ObjCObjectPointerType
- /// node.
- ///
- /// The list of protocols is sorted on protocol name. No protocol is enterred
- /// more than once.
- unsigned NumProtocols;
+ QualType PointeeType;
- ObjCObjectPointerType(QualType Canonical, QualType T,
- ObjCProtocolDecl **Protos, unsigned NumP);
+ ObjCObjectPointerType(QualType Canonical, QualType Pointee)
+ : Type(ObjCObjectPointer, Canonical, false),
+ PointeeType(Pointee) {}
friend class ASTContext; // ASTContext creates these.
+protected:
+ virtual Linkage getLinkageImpl() const;
+
public:
void Destroy(ASTContext& C);
- // Get the pointee type. Pointee will either be:
- // - a built-in type (for 'id' and 'Class').
- // - an interface type (for user-defined types).
- // - a TypedefType whose canonical type is an interface (as in 'T' below).
- // For example: typedef NSObject T; T *var;
+ /// getPointeeType - Gets the type pointed to by this ObjC pointer.
+ /// The result will always be an ObjCObjectType or sugar thereof.
QualType getPointeeType() const { return PointeeType; }
+ /// getObjCObjectType - Gets the type pointed to by this ObjC
+ /// pointer. This method always returns non-null.
+ ///
+ /// This method is equivalent to getPointeeType() except that
+ /// it discards any typedefs (or other sugar) between this
+ /// type and the "outermost" object type. So for:
+ /// @class A; @protocol P; @protocol Q;
+ /// typedef A<P> AP;
+ /// typedef A A1;
+ /// typedef A1<P> A1P;
+ /// typedef A1P<Q> A1PQ;
+ /// For 'A*', getObjectType() will return 'A'.
+ /// For 'A<P>*', getObjectType() will return 'A<P>'.
+ /// For 'AP*', getObjectType() will return 'A<P>'.
+ /// For 'A1*', getObjectType() will return 'A'.
+ /// For 'A1<P>*', getObjectType() will return 'A1<P>'.
+ /// For 'A1P*', getObjectType() will return 'A1<P>'.
+ /// For 'A1PQ*', getObjectType() will return 'A1<Q>', because
+ /// adding protocols to a protocol-qualified base discards the
+ /// old qualifiers (for now). But if it didn't, getObjectType()
+ /// would return 'A1P<Q>' (and we'd have to make iterating over
+ /// qualifiers more complicated).
+ const ObjCObjectType *getObjectType() const {
+ return PointeeType->getAs<ObjCObjectType>();
+ }
+
+ /// getInterfaceType - If this pointer points to an Objective C
+ /// @interface type, gets the type for that interface. Any protocol
+ /// qualifiers on the interface are ignored.
+ ///
+ /// \return null if the base type for this pointer is 'id' or 'Class'
const ObjCInterfaceType *getInterfaceType() const {
- return PointeeType->getAs<ObjCInterfaceType>();
+ return getObjectType()->getBaseType()->getAs<ObjCInterfaceType>();
}
- /// getInterfaceDecl - returns an interface decl for user-defined types.
+
+ /// getInterfaceDecl - If this pointer points to an Objective @interface
+ /// type, gets the declaration for that interface.
+ ///
+ /// \return null if the base type for this pointer is 'id' or 'Class'
ObjCInterfaceDecl *getInterfaceDecl() const {
- return getInterfaceType() ? getInterfaceType()->getDecl() : 0;
+ return getObjectType()->getInterface();
}
- /// isObjCIdType - true for "id".
+
+ /// isObjCIdType - True if this is equivalent to the 'id' type, i.e. if
+ /// its object type is the primitive 'id' type with no protocols.
bool isObjCIdType() const {
- return getPointeeType()->isSpecificBuiltinType(BuiltinType::ObjCId) &&
- !NumProtocols;
+ return getObjectType()->isObjCUnqualifiedId();
}
- /// isObjCClassType - true for "Class".
+
+ /// isObjCClassType - True if this is equivalent to the 'Class' type,
+ /// i.e. if its object tive is the primitive 'Class' type with no protocols.
bool isObjCClassType() const {
- return getPointeeType()->isSpecificBuiltinType(BuiltinType::ObjCClass) &&
- !NumProtocols;
+ return getObjectType()->isObjCUnqualifiedClass();
}
- /// isObjCQualifiedIdType - true for "id <p>".
+ /// isObjCQualifiedIdType - True if this is equivalent to 'id<P>' for some
+ /// non-empty set of protocols.
bool isObjCQualifiedIdType() const {
- return getPointeeType()->isSpecificBuiltinType(BuiltinType::ObjCId) &&
- NumProtocols;
+ return getObjectType()->isObjCQualifiedId();
}
- /// isObjCQualifiedClassType - true for "Class <p>".
+
+ /// isObjCQualifiedClassType - True if this is equivalent to 'Class<P>' for
+ /// some non-empty set of protocols.
bool isObjCQualifiedClassType() const {
- return getPointeeType()->isSpecificBuiltinType(BuiltinType::ObjCClass) &&
- NumProtocols;
+ return getObjectType()->isObjCQualifiedClass();
}
- /// qual_iterator and friends: this provides access to the (potentially empty)
- /// list of protocols qualifying this interface.
- typedef ObjCProtocolDecl* const * qual_iterator;
+
+ /// An iterator over the qualifiers on the object type. Provided
+ /// for convenience. This will always iterate over the full set of
+ /// protocols on a type, not just those provided directly.
+ typedef ObjCObjectType::qual_iterator qual_iterator;
qual_iterator qual_begin() const {
- return reinterpret_cast<qual_iterator> (this + 1);
+ return getObjectType()->qual_begin();
}
- qual_iterator qual_end() const {
- return qual_begin() + NumProtocols;
+ qual_iterator qual_end() const {
+ return getObjectType()->qual_end();
}
- bool qual_empty() const { return NumProtocols == 0; }
+ bool qual_empty() const { return getObjectType()->qual_empty(); }
- /// getNumProtocols - Return the number of qualifying protocols in this
- /// interface type, or 0 if there are none.
- unsigned getNumProtocols() const { return NumProtocols; }
+ /// getNumProtocols - Return the number of qualifying protocols on
+ /// the object type.
+ unsigned getNumProtocols() const {
+ return getObjectType()->getNumProtocols();
+ }
- /// \brief Retrieve the Ith protocol.
+ /// \brief Retrieve a qualifying protocol by index on the object
+ /// type.
ObjCProtocolDecl *getProtocol(unsigned I) const {
- assert(I < getNumProtocols() && "Out-of-range protocol access");
- return qual_begin()[I];
+ return getObjectType()->getProtocol(I);
}
bool isSugared() const { return false; }
QualType desugar() const { return QualType(this, 0); }
- virtual Linkage getLinkage() const;
-
- void Profile(llvm::FoldingSetNodeID &ID);
- static void Profile(llvm::FoldingSetNodeID &ID, QualType T,
- ObjCProtocolDecl *const *protocols,
- unsigned NumProtocols);
+ void Profile(llvm::FoldingSetNodeID &ID) {
+ Profile(ID, getPointeeType());
+ }
+ static void Profile(llvm::FoldingSetNodeID &ID, QualType T) {
+ ID.AddPointer(T.getAsOpaquePtr());
+ }
static bool classof(const Type *T) {
return T->getTypeClass() == ObjCObjectPointer;
}
@@ -3128,12 +3353,6 @@ inline QualType QualType::getNonReferenceType() const {
return *this;
}
-inline const ObjCInterfaceType *Type::getAsPointerToObjCInterfaceType() const {
- if (const PointerType *PT = getAs<PointerType>())
- return PT->getPointeeType()->getAs<ObjCInterfaceType>();
- return 0;
-}
-
inline bool Type::isFunctionType() const {
return isa<FunctionType>(CanonicalType);
}
@@ -3200,8 +3419,8 @@ inline bool Type::isExtVectorType() const {
inline bool Type::isObjCObjectPointerType() const {
return isa<ObjCObjectPointerType>(CanonicalType);
}
-inline bool Type::isObjCInterfaceType() const {
- return isa<ObjCInterfaceType>(CanonicalType);
+inline bool Type::isObjCObjectType() const {
+ return isa<ObjCObjectType>(CanonicalType);
}
inline bool Type::isObjCQualifiedIdType() const {
if (const ObjCObjectPointerType *OPT = getAs<ObjCObjectPointerType>())
@@ -3250,13 +3469,11 @@ inline bool Type::isOverloadableType() const {
inline bool Type::hasPointerRepresentation() const {
return (isPointerType() || isReferenceType() || isBlockPointerType() ||
- isObjCInterfaceType() || isObjCObjectPointerType() ||
- isObjCQualifiedInterfaceType() || isNullPtrType());
+ isObjCObjectPointerType() || isNullPtrType());
}
inline bool Type::hasObjCPointerRepresentation() const {
- return (isObjCInterfaceType() || isObjCObjectPointerType() ||
- isObjCQualifiedInterfaceType());
+ return isObjCObjectPointerType();
}
/// Insertion operator for diagnostics. This allows sending QualType's into a
diff --git a/include/clang/AST/TypeLoc.h b/include/clang/AST/TypeLoc.h
index a51da7474d37..f988f0e33b39 100644
--- a/include/clang/AST/TypeLoc.h
+++ b/include/clang/AST/TypeLoc.h
@@ -15,6 +15,7 @@
#define LLVM_CLANG_AST_TYPELOC_H
#include "clang/AST/Type.h"
+#include "clang/AST/Decl.h"
#include "clang/AST/TemplateBase.h"
#include "clang/Basic/Specifiers.h"
@@ -84,21 +85,20 @@ public:
return Data;
}
+ /// \brief Get the begin source location.
+ SourceLocation getBeginLoc() const;
+
+ /// \brief Get the end source location.
+ SourceLocation getEndLoc() const;
+
/// \brief Get the full source range.
- SourceRange getFullSourceRange() const {
- SourceLocation End = getSourceRange().getEnd();
- TypeLoc Cur = *this;
- while (true) {
- TypeLoc Next = Cur.getNextTypeLoc();
- if (Next.isNull()) break;
- Cur = Next;
- }
- return SourceRange(Cur.getSourceRange().getBegin(), End);
+ SourceRange getSourceRange() const {
+ return SourceRange(getBeginLoc(), getEndLoc());
}
/// \brief Get the local source range.
- SourceRange getSourceRange() const {
- return getSourceRangeImpl(*this);
+ SourceRange getLocalSourceRange() const {
+ return getLocalSourceRangeImpl(*this);
}
/// \brief Returns the size of the type source info data block.
@@ -137,9 +137,14 @@ public:
private:
static void initializeImpl(TypeLoc TL, SourceLocation Loc);
static TypeLoc getNextTypeLocImpl(TypeLoc TL);
- static SourceRange getSourceRangeImpl(TypeLoc TL);
+ static SourceRange getLocalSourceRangeImpl(TypeLoc TL);
};
+/// \brief Return the TypeLoc for a type source info.
+inline TypeLoc TypeSourceInfo::getTypeLoc() const {
+ return TypeLoc(Ty, (void*)(this + 1));
+}
+
/// \brief Wrapper of type source information for a type with
/// no direct quqlaifiers.
class UnqualTypeLoc : public TypeLoc {
@@ -168,7 +173,7 @@ public:
/// type qualifiers.
class QualifiedTypeLoc : public TypeLoc {
public:
- SourceRange getSourceRange() const {
+ SourceRange getLocalSourceRange() const {
return SourceRange();
}
@@ -263,6 +268,16 @@ public:
return TypeClass::classof(Ty);
}
+ static bool classof(const TypeLoc *TL) {
+ return Derived::classofType(TL->getTypePtr());
+ }
+ static bool classof(const UnqualTypeLoc *TL) {
+ return Derived::classofType(TL->getTypePtr());
+ }
+ static bool classof(const Derived *TL) {
+ return true;
+ }
+
TypeLoc getNextTypeLoc() const {
return getNextTypeLoc(asDerived()->getInnerType());
}
@@ -361,7 +376,7 @@ public:
void setNameLoc(SourceLocation Loc) {
this->getLocalData()->NameLoc = Loc;
}
- SourceRange getSourceRange() const {
+ SourceRange getLocalSourceRange() const {
return SourceRange(getNameLoc(), getNameLoc());
}
void initializeLocal(SourceLocation Loc) {
@@ -413,7 +428,7 @@ public:
return needsExtraLocalData() ? sizeof(WrittenBuiltinSpecs) : 0;
}
- SourceRange getSourceRange() const {
+ SourceRange getLocalSourceRange() const {
return SourceRange(getBuiltinLoc(), getBuiltinLoc());
}
@@ -553,6 +568,7 @@ class SubstTemplateTypeParmTypeLoc :
struct ObjCProtocolListLocInfo {
SourceLocation LAngleLoc;
SourceLocation RAngleLoc;
+ bool HasBaseTypeAsWritten;
};
// A helper class for defining ObjC TypeLocs that can qualified with
@@ -560,24 +576,15 @@ struct ObjCProtocolListLocInfo {
//
// TypeClass basically has to be either ObjCInterfaceType or
// ObjCObjectPointerType.
-template <class Derived, class TypeClass, class LocalData>
-class ObjCProtocolListTypeLoc : public ConcreteTypeLoc<UnqualTypeLoc,
- Derived,
- TypeClass,
- LocalData> {
+class ObjCObjectTypeLoc : public ConcreteTypeLoc<UnqualTypeLoc,
+ ObjCObjectTypeLoc,
+ ObjCObjectType,
+ ObjCProtocolListLocInfo> {
// SourceLocations are stored after Info, one for each Protocol.
SourceLocation *getProtocolLocArray() const {
return (SourceLocation*) this->getExtraLocalData();
}
-protected:
- void initializeLocalBase(SourceLocation Loc) {
- setLAngleLoc(Loc);
- setRAngleLoc(Loc);
- for (unsigned i = 0, e = getNumProtocols(); i != e; ++i)
- setProtocolLoc(i, Loc);
- }
-
public:
SourceLocation getLAngleLoc() const {
return this->getLocalData()->LAngleLoc;
@@ -611,29 +618,49 @@ public:
return *(this->getTypePtr()->qual_begin() + i);
}
- SourceRange getSourceRange() const {
+ bool hasBaseTypeAsWritten() const {
+ return getLocalData()->HasBaseTypeAsWritten;
+ }
+
+ void setHasBaseTypeAsWritten(bool HasBaseType) {
+ getLocalData()->HasBaseTypeAsWritten = HasBaseType;
+ }
+
+ TypeLoc getBaseLoc() const {
+ return getInnerTypeLoc();
+ }
+
+ SourceRange getLocalSourceRange() const {
return SourceRange(getLAngleLoc(), getRAngleLoc());
}
void initializeLocal(SourceLocation Loc) {
- initializeLocalBase(Loc);
+ setHasBaseTypeAsWritten(true);
+ setLAngleLoc(Loc);
+ setRAngleLoc(Loc);
+ for (unsigned i = 0, e = getNumProtocols(); i != e; ++i)
+ setProtocolLoc(i, Loc);
}
unsigned getExtraLocalDataSize() const {
return this->getNumProtocols() * sizeof(SourceLocation);
}
+
+ QualType getInnerType() const {
+ return getTypePtr()->getBaseType();
+ }
};
-struct ObjCInterfaceLocInfo : ObjCProtocolListLocInfo {
+struct ObjCInterfaceLocInfo {
SourceLocation NameLoc;
};
/// \brief Wrapper for source info for ObjC interfaces.
-class ObjCInterfaceTypeLoc :
- public ObjCProtocolListTypeLoc<ObjCInterfaceTypeLoc,
- ObjCInterfaceType,
- ObjCInterfaceLocInfo> {
+class ObjCInterfaceTypeLoc : public ConcreteTypeLoc<UnqualTypeLoc,
+ ObjCInterfaceTypeLoc,
+ ObjCInterfaceType,
+ ObjCInterfaceLocInfo> {
public:
ObjCInterfaceDecl *getIFaceDecl() const {
return getTypePtr()->getDecl();
@@ -647,85 +674,16 @@ public:
getLocalData()->NameLoc = Loc;
}
- SourceRange getSourceRange() const {
- if (getNumProtocols())
- return SourceRange(getNameLoc(), getRAngleLoc());
- else
- return SourceRange(getNameLoc(), getNameLoc());
+ SourceRange getLocalSourceRange() const {
+ return SourceRange(getNameLoc());
}
void initializeLocal(SourceLocation Loc) {
- initializeLocalBase(Loc);
setNameLoc(Loc);
}
};
-struct ObjCObjectPointerLocInfo : ObjCProtocolListLocInfo {
- SourceLocation StarLoc;
- bool HasProtocols;
- bool HasBaseType;
-};
-
-/// Wraps an ObjCPointerType with source location information. Note
-/// that not all ObjCPointerTypes actually have a star location; nor
-/// are protocol locations necessarily written in the source just
-/// because they're present on the type.
-class ObjCObjectPointerTypeLoc :
- public ObjCProtocolListTypeLoc<ObjCObjectPointerTypeLoc,
- ObjCObjectPointerType,
- ObjCObjectPointerLocInfo> {
-public:
- bool hasProtocolsAsWritten() const {
- return getLocalData()->HasProtocols;
- }
-
- void setHasProtocolsAsWritten(bool HasProtocols) {
- getLocalData()->HasProtocols = HasProtocols;
- }
-
- bool hasBaseTypeAsWritten() const {
- return getLocalData()->HasBaseType;
- }
-
- void setHasBaseTypeAsWritten(bool HasBaseType) {
- getLocalData()->HasBaseType = HasBaseType;
- }
-
- SourceLocation getStarLoc() const {
- return getLocalData()->StarLoc;
- }
-
- void setStarLoc(SourceLocation Loc) {
- getLocalData()->StarLoc = Loc;
- }
-
- SourceRange getSourceRange() const {
- // Being written with protocols is incompatible with being written
- // with a star.
- if (hasProtocolsAsWritten())
- return SourceRange(getLAngleLoc(), getRAngleLoc());
- else
- return SourceRange(getStarLoc(), getStarLoc());
- }
-
- void initializeLocal(SourceLocation Loc) {
- initializeLocalBase(Loc);
- setHasProtocolsAsWritten(false);
- setHasBaseTypeAsWritten(false);
- setStarLoc(Loc);
- }
-
- TypeLoc getBaseTypeLoc() const {
- return getInnerTypeLoc();
- }
-
- QualType getInnerType() const {
- return getTypePtr()->getPointeeType();
- }
-};
-
-
struct PointerLikeLocInfo {
SourceLocation StarLoc;
};
@@ -746,7 +704,7 @@ public:
return this->getInnerTypeLoc();
}
- SourceRange getSourceRange() const {
+ SourceRange getLocalSourceRange() const {
return SourceRange(getSigilLoc(), getSigilLoc());
}
@@ -798,6 +756,20 @@ public:
}
};
+/// Wraps an ObjCPointerType with source location information.
+class ObjCObjectPointerTypeLoc :
+ public PointerLikeTypeLoc<ObjCObjectPointerTypeLoc,
+ ObjCObjectPointerType> {
+public:
+ SourceLocation getStarLoc() const {
+ return getSigilLoc();
+ }
+
+ void setStarLoc(SourceLocation Loc) {
+ setSigilLoc(Loc);
+ }
+};
+
class ReferenceTypeLoc : public PointerLikeTypeLoc<ReferenceTypeLoc,
ReferenceType> {
@@ -871,13 +843,11 @@ public:
ParmVarDecl *getArg(unsigned i) const { return getParmArray()[i]; }
void setArg(unsigned i, ParmVarDecl *VD) { getParmArray()[i] = VD; }
- TypeLoc getArgLoc(unsigned i) const;
-
TypeLoc getResultLoc() const {
return getInnerTypeLoc();
}
- SourceRange getSourceRange() const {
+ SourceRange getLocalSourceRange() const {
return SourceRange(getLParenLoc(), getRParenLoc());
}
@@ -950,7 +920,7 @@ public:
return getInnerTypeLoc();
}
- SourceRange getSourceRange() const {
+ SourceRange getLocalSourceRange() const {
return SourceRange(getLBracketLoc(), getRBracketLoc());
}
@@ -1055,7 +1025,7 @@ public:
memcpy(Data, Loc.Data, size);
}
- SourceRange getSourceRange() const {
+ SourceRange getLocalSourceRange() const {
return SourceRange(getTemplateNameLoc(), getRAngleLoc());
}
@@ -1183,7 +1153,7 @@ public:
setRParenLoc(range.getEnd());
}
- SourceRange getSourceRange() const {
+ SourceRange getLocalSourceRange() const {
return SourceRange(getTypeofLoc(), getRParenLoc());
}
@@ -1204,7 +1174,7 @@ public:
// Reimplemented to account for GNU/C++ extension
// typeof unary-expression
// where there are no parentheses.
- SourceRange getSourceRange() const;
+ SourceRange getLocalSourceRange() const;
};
class TypeOfTypeLoc
@@ -1227,24 +1197,110 @@ class DecltypeTypeLoc : public InheritingConcreteTypeLoc<TypeSpecTypeLoc,
DecltypeType> {
};
-// FIXME: location of the tag keyword.
-class ElaboratedTypeLoc : public InheritingConcreteTypeLoc<TypeSpecTypeLoc,
- ElaboratedTypeLoc,
- ElaboratedType> {
+struct ElaboratedLocInfo {
+ SourceLocation KeywordLoc;
+ SourceRange QualifierRange;
};
-// FIXME: locations for the nested name specifier; at the very least,
-// a SourceRange.
-class QualifiedNameTypeLoc :
- public InheritingConcreteTypeLoc<TypeSpecTypeLoc,
- QualifiedNameTypeLoc,
- QualifiedNameType> {
+class ElaboratedTypeLoc : public ConcreteTypeLoc<UnqualTypeLoc,
+ ElaboratedTypeLoc,
+ ElaboratedType,
+ ElaboratedLocInfo> {
+public:
+ SourceLocation getKeywordLoc() const {
+ return this->getLocalData()->KeywordLoc;
+ }
+ void setKeywordLoc(SourceLocation Loc) {
+ this->getLocalData()->KeywordLoc = Loc;
+ }
+
+ SourceRange getQualifierRange() const {
+ return this->getLocalData()->QualifierRange;
+ }
+ void setQualifierRange(SourceRange Range) {
+ this->getLocalData()->QualifierRange = Range;
+ }
+
+ SourceRange getLocalSourceRange() const {
+ if (getKeywordLoc().isValid())
+ if (getQualifierRange().getEnd().isValid())
+ return SourceRange(getKeywordLoc(), getQualifierRange().getEnd());
+ else
+ return SourceRange(getKeywordLoc());
+ else
+ return getQualifierRange();
+ }
+
+ void initializeLocal(SourceLocation Loc) {
+ setKeywordLoc(Loc);
+ setQualifierRange(SourceRange(Loc));
+ }
+
+ TypeLoc getNamedTypeLoc() const {
+ return getInnerTypeLoc();
+ }
+
+ QualType getInnerType() const {
+ return getTypePtr()->getNamedType();
+ }
+
+ void copy(ElaboratedTypeLoc Loc) {
+ unsigned size = getFullDataSize();
+ assert(size == Loc.getFullDataSize());
+ memcpy(Data, Loc.Data, size);
+ }
};
-// FIXME: locations for the typename keyword and nested name specifier.
-class DependentNameTypeLoc : public InheritingConcreteTypeLoc<TypeSpecTypeLoc,
- DependentNameTypeLoc,
- DependentNameType> {
+struct DependentNameLocInfo {
+ SourceLocation KeywordLoc;
+ SourceRange QualifierRange;
+ SourceLocation NameLoc;
+};
+
+class DependentNameTypeLoc : public ConcreteTypeLoc<UnqualTypeLoc,
+ DependentNameTypeLoc,
+ DependentNameType,
+ DependentNameLocInfo> {
+public:
+ SourceLocation getKeywordLoc() const {
+ return this->getLocalData()->KeywordLoc;
+ }
+ void setKeywordLoc(SourceLocation Loc) {
+ this->getLocalData()->KeywordLoc = Loc;
+ }
+
+ SourceRange getQualifierRange() const {
+ return this->getLocalData()->QualifierRange;
+ }
+ void setQualifierRange(SourceRange Range) {
+ this->getLocalData()->QualifierRange = Range;
+ }
+
+ SourceLocation getNameLoc() const {
+ return this->getLocalData()->NameLoc;
+ }
+ void setNameLoc(SourceLocation Loc) {
+ this->getLocalData()->NameLoc = Loc;
+ }
+
+ SourceRange getLocalSourceRange() const {
+ if (getKeywordLoc().isValid())
+ return SourceRange(getKeywordLoc(), getNameLoc());
+ else
+ return SourceRange(getQualifierRange().getBegin(), getNameLoc());
+ }
+
+ void copy(DependentNameTypeLoc Loc) {
+ unsigned size = getFullDataSize();
+ assert(size == Loc.getFullDataSize());
+ memcpy(Data, Loc.Data, size);
+ }
+
+ void initializeLocal(SourceLocation Loc) {
+ setKeywordLoc(Loc);
+ setQualifierRange(SourceRange(Loc));
+ setNameLoc(Loc);
+ }
};
}
diff --git a/include/clang/AST/TypeLocBuilder.h b/include/clang/AST/TypeLocBuilder.h
index c3b1c68b1fb6..e729488e4313 100644
--- a/include/clang/AST/TypeLocBuilder.h
+++ b/include/clang/AST/TypeLocBuilder.h
@@ -59,6 +59,20 @@ class TypeLocBuilder {
grow(Requested);
}
+ /// Pushes a copy of the given TypeLoc onto this builder. The builder
+ /// must be empty for this to work.
+ void pushFullCopy(TypeLoc L) {
+#ifndef NDEBUG
+ assert(LastTy.isNull() && "pushing copy on non-empty TypeLocBuilder");
+ LastTy = L.getNextTypeLoc().getType();
+#endif
+ assert(Index == Capacity && "pushing copy on non-empty TypeLocBuilder");
+
+ unsigned Size = L.getFullDataSize();
+ TypeLoc Copy = pushImpl(L.getType(), Size);
+ memcpy(Copy.getOpaqueData(), L.getOpaqueData(), Size);
+ }
+
/// Pushes space for a typespec TypeLoc. Invalidates any TypeLocs
/// previously retrieved from this builder.
TypeSpecTypeLoc pushTypeSpec(QualType T) {
diff --git a/include/clang/AST/TypeNodes.def b/include/clang/AST/TypeNodes.def
index c665073025f7..02508af67dd8 100644
--- a/include/clang/AST/TypeNodes.def
+++ b/include/clang/AST/TypeNodes.def
@@ -90,10 +90,10 @@ NON_CANONICAL_TYPE(Elaborated, Type)
DEPENDENT_TYPE(TemplateTypeParm, Type)
NON_CANONICAL_TYPE(SubstTemplateTypeParm, Type)
NON_CANONICAL_UNLESS_DEPENDENT_TYPE(TemplateSpecialization, Type)
-NON_CANONICAL_TYPE(QualifiedName, Type)
DEPENDENT_TYPE(InjectedClassName, Type)
DEPENDENT_TYPE(DependentName, Type)
-TYPE(ObjCInterface, Type)
+TYPE(ObjCObject, Type)
+TYPE(ObjCInterface, ObjCObjectType)
TYPE(ObjCObjectPointer, Type)
#ifdef LAST_TYPE
diff --git a/include/clang/AST/TypeVisitor.h b/include/clang/AST/TypeVisitor.h
index 19f7f42a897a..5c9c5285a248 100644
--- a/include/clang/AST/TypeVisitor.h
+++ b/include/clang/AST/TypeVisitor.h
@@ -1,4 +1,4 @@
-//===--- TypeVisitor.h - Visitor for Stmt subclasses ------------*- C++ -*-===//
+//===--- TypeVisitor.h - Visitor for Type subclasses ------------*- C++ -*-===//
//
// The LLVM Compiler Infrastructure
//
@@ -25,7 +25,7 @@ template<typename ImplClass, typename RetTy=void>
class TypeVisitor {
public:
RetTy Visit(Type *T) {
- // Top switch stmt: dispatch to VisitFooStmt for each FooStmt.
+ // Top switch stmt: dispatch to VisitFooType for each FooType.
switch (T->getTypeClass()) {
default: assert(0 && "Unknown type class!");
#define ABSTRACT_TYPE(CLASS, PARENT)
diff --git a/include/clang/AST/UnresolvedSet.h b/include/clang/AST/UnresolvedSet.h
index cbe00827d00a..a548b0b704d1 100644
--- a/include/clang/AST/UnresolvedSet.h
+++ b/include/clang/AST/UnresolvedSet.h
@@ -31,9 +31,13 @@ private:
IteratorTy ir;
friend class UnresolvedSetImpl;
+ friend class OverloadExpr;
explicit UnresolvedSetIterator(DeclsTy::iterator ir) : ir(ir) {}
explicit UnresolvedSetIterator(DeclsTy::const_iterator ir) :
ir(const_cast<DeclsTy::iterator>(ir)) {}
+
+ IteratorTy getIterator() const { return ir; }
+
public:
UnresolvedSetIterator() {}
@@ -81,9 +85,7 @@ public:
bool operator>(const UnresolvedSetIterator &o) const { return ir > o.ir; }
};
-/// UnresolvedSet - A set of unresolved declarations. This is needed
-/// in a lot of places, but isn't really worth breaking into its own
-/// header right now.
+/// UnresolvedSet - A set of unresolved declarations.
class UnresolvedSetImpl {
typedef UnresolvedSetIterator::DeclsTy DeclsTy;
diff --git a/include/clang/Analysis/ProgramPoint.h b/include/clang/Analysis/ProgramPoint.h
index fb8d4d5ff53a..075838d45e5c 100644
--- a/include/clang/Analysis/ProgramPoint.h
+++ b/include/clang/Analysis/ProgramPoint.h
@@ -59,7 +59,7 @@ private:
protected:
ProgramPoint(const void* P, Kind k, const LocationContext *l,
const void *tag = 0)
- : Data(P, NULL), K(k), L(l), Tag(tag) {}
+ : Data(P, static_cast<const void*>(NULL)), K(k), L(l), Tag(tag) {}
ProgramPoint(const void* P1, const void* P2, Kind k, const LocationContext *l,
const void *tag = 0)
diff --git a/include/clang/Basic/Diagnostic.h b/include/clang/Basic/Diagnostic.h
index 6b2912e2e8c2..62f06edb7785 100644
--- a/include/clang/Basic/Diagnostic.h
+++ b/include/clang/Basic/Diagnostic.h
@@ -423,6 +423,14 @@ public:
/// the diagnostic, this returns null.
static const char *getWarningOptionForDiag(unsigned DiagID);
+ /// getWarningOptionForDiag - Return the category number that a specified
+ /// DiagID belongs to, or 0 if no category.
+ static unsigned getCategoryNumberForDiag(unsigned DiagID);
+
+ /// getCategoryNameFromID - Given a category ID, return the name of the
+ /// category.
+ static const char *getCategoryNameFromID(unsigned CategoryID);
+
/// \brief Enumeration describing how the the emission of a diagnostic should
/// be treated when it occurs during C++ template argument deduction.
enum SFINAEResponse {
diff --git a/include/clang/Basic/Diagnostic.td b/include/clang/Basic/Diagnostic.td
index f6b5d9c5b308..fabf9ebb4498 100644
--- a/include/clang/Basic/Diagnostic.td
+++ b/include/clang/Basic/Diagnostic.td
@@ -42,7 +42,10 @@ class InGroup<DiagGroup G> { DiagGroup Group = G; }
//class IsGroup<string Name> { DiagGroup Group = DiagGroup<Name>; }
-// This defines the diagnostic groups that have references to them.
+// This defines all of the named diagnostic categories.
+include "DiagnosticCategories.td"
+
+// This defines all of the named diagnostic groups.
include "DiagnosticGroups.td"
diff --git a/include/clang/Basic/DiagnosticASTKinds.td b/include/clang/Basic/DiagnosticASTKinds.td
index cc89c7caec3c..d755d99e6be5 100644
--- a/include/clang/Basic/DiagnosticASTKinds.td
+++ b/include/clang/Basic/DiagnosticASTKinds.td
@@ -14,17 +14,20 @@ let Component = "AST" in {
def note_expr_divide_by_zero : Note<"division by zero">;
// inline asm related.
-def err_asm_invalid_escape : Error<
- "invalid %% escape in inline assembly string">;
-def err_asm_unknown_symbolic_operand_name : Error<
- "unknown symbolic operand name in inline assembly string">;
+let CategoryName = "Inline Assembly Issue" in {
+ def err_asm_invalid_escape : Error<
+ "invalid %% escape in inline assembly string">;
+ def err_asm_unknown_symbolic_operand_name : Error<
+ "unknown symbolic operand name in inline assembly string">;
+
+ def err_asm_unterminated_symbolic_operand_name : Error<
+ "unterminated symbolic operand name in inline assembly string">;
+ def err_asm_empty_symbolic_operand_name : Error<
+ "empty symbolic operand name in inline assembly string">;
+ def err_asm_invalid_operand_number : Error<
+ "invalid operand number in inline asm string">;
+}
-def err_asm_unterminated_symbolic_operand_name : Error<
- "unterminated symbolic operand name in inline assembly string">;
-def err_asm_empty_symbolic_operand_name : Error<
- "empty symbolic operand name in inline assembly string">;
-def err_asm_invalid_operand_number : Error<
- "invalid operand number in inline asm string">;
// Importing ASTs
def err_odr_variable_type_inconsistent : Error<
diff --git a/include/clang/Basic/DiagnosticCategories.td b/include/clang/Basic/DiagnosticCategories.td
new file mode 100644
index 000000000000..a02fbdf93fc3
--- /dev/null
+++ b/include/clang/Basic/DiagnosticCategories.td
@@ -0,0 +1,10 @@
+//==--- DiagnosticCategories.td - Diagnostic Category Definitions ---------===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+class CatInlineAsm : DiagCategory<"Inline Assembly Issue">;
diff --git a/include/clang/Basic/DiagnosticDriverKinds.td b/include/clang/Basic/DiagnosticDriverKinds.td
index 3b7272e5acc5..f4a31cc5766c 100644
--- a/include/clang/Basic/DiagnosticDriverKinds.td
+++ b/include/clang/Basic/DiagnosticDriverKinds.td
@@ -49,6 +49,8 @@ def err_drv_no_ast_support : Error<
"'%0': unable to use AST files with this tool">;
def err_drv_clang_unsupported : Error<
"the clang compiler does not support '%0'">;
+def err_drv_clang_unsupported_opt_cxx_darwin_i386 : Error<
+ "the clang compiler does not support '%0' for C++ on Darwin/i386">;
def err_drv_command_failed : Error<
"%0 command failed with exit code %1 (use -v to see invocation)">;
def err_drv_command_signalled : Error<
diff --git a/include/clang/Basic/DiagnosticFrontendKinds.td b/include/clang/Basic/DiagnosticFrontendKinds.td
index b73103067017..c7cad7395c0b 100644
--- a/include/clang/Basic/DiagnosticFrontendKinds.td
+++ b/include/clang/Basic/DiagnosticFrontendKinds.td
@@ -16,7 +16,8 @@ def err_fe_error_backend : Error<"error in backend: %0">, DefaultFatal;
def err_fe_invalid_ast_file : Error<"invalid AST file: '%0'">, DefaultFatal;
def err_fe_invalid_ast_action : Error<"invalid action for AST input">,
DefaultFatal;
-def err_fe_inline_asm : Error<"%0">; // Error generated by the backend.
+// Error generated by the backend.
+def err_fe_inline_asm : Error<"%0">, CatInlineAsm;
def note_fe_inline_asm_here : Note<"generated from here">;
def err_fe_invalid_code_complete_file : Error<
"cannot locate code-completion file %0">, DefaultFatal;
diff --git a/include/clang/Basic/DiagnosticGroups.td b/include/clang/Basic/DiagnosticGroups.td
index 1012e91baa77..b79bf8e2edbe 100644
--- a/include/clang/Basic/DiagnosticGroups.td
+++ b/include/clang/Basic/DiagnosticGroups.td
@@ -40,6 +40,9 @@ def ExtraTokens : DiagGroup<"extra-tokens">;
def FormatExtraArgs : DiagGroup<"format-extra-args">;
def FormatZeroLength : DiagGroup<"format-zero-length">;
+def CXXHexFloats : DiagGroup<"c++-hex-floats">;
+
+def : DiagGroup<"c++0x-compat", [CXXHexFloats]>;
def FourByteMultiChar : DiagGroup<"four-char-constants">;
def : DiagGroup<"idiomatic-parentheses">;
def : DiagGroup<"import">;
@@ -120,6 +123,7 @@ def SuperSubClassMismatch : DiagGroup<"super-class-method-mismatch">;
def : DiagGroup<"variadic-macros">;
def VariadicMacros : DiagGroup<"variadic-macros">;
def VectorConversions : DiagGroup<"vector-conversions">; // clang specific
+def VLA : DiagGroup<"vla">;
def VolatileRegisterVar : DiagGroup<"volatile-register-var">;
def : DiagGroup<"write-strings">;
def CharSubscript : DiagGroup<"char-subscripts">;
@@ -134,16 +138,17 @@ def Parentheses : DiagGroup<"parentheses", [DiagGroup<"idiomatic-parentheses">]>
// legacy reasons.
def Conversion : DiagGroup<"conversion",
[DiagGroup<"shorten-64-to-32">]>,
- DiagCategory<"Value Conversion">;
+ DiagCategory<"Value Conversion Issue">;
def Unused : DiagGroup<"unused",
[UnusedArgument, UnusedFunction, UnusedLabel,
// UnusedParameter, (matches GCC's behavior)
- UnusedValue, UnusedVariable]>;
+ UnusedValue, UnusedVariable]>,
+ DiagCategory<"Unused Entity Issue">;
// Format settings.
def Format : DiagGroup<"format", [FormatExtraArgs, FormatZeroLength, NonNull]>,
- DiagCategory<"Format String">;
+ DiagCategory<"Format String Issue">;
def FormatSecurity : DiagGroup<"format-security", [Format]>;
def FormatNonLiteral : DiagGroup<"format-nonliteral", [FormatSecurity]>;
def FormatY2K : DiagGroup<"format-y2k", [Format]>;
@@ -190,4 +195,4 @@ def NonGCC : DiagGroup<"non-gcc",
[SignCompare, Conversion, LiteralRange]>;
// A warning group for warnings about GCC extensions.
-def GNU : DiagGroup<"gnu", [GNUDesignator]>;
+def GNU : DiagGroup<"gnu", [GNUDesignator, VLA]>;
diff --git a/include/clang/Basic/DiagnosticLexKinds.td b/include/clang/Basic/DiagnosticLexKinds.td
index 3f765bdfb3b7..848e85c8ba41 100644
--- a/include/clang/Basic/DiagnosticLexKinds.td
+++ b/include/clang/Basic/DiagnosticLexKinds.td
@@ -11,7 +11,7 @@
// Lexer Diagnostics
//===----------------------------------------------------------------------===//
-let Component = "Lex" in {
+let Component = "Lex", CategoryName = "Lexical or Preprocessor Issue" in {
def null_in_string : Warning<"null character(s) preserved in string literal">;
def null_in_char : Warning<"null character(s) preserved in character literal">;
@@ -84,9 +84,9 @@ def err_exponent_has_no_digits : Error<"exponent has no digits">;
def ext_imaginary_constant : Extension<"imaginary constants are an extension">;
def err_hexconstant_requires_exponent : Error<
"hexadecimal floating constants require an exponent">;
-def ext_hexconstant_cplusplus : ExtWarn<
+def ext_hexconstant_cplusplus : Extension<
"hexadecimal floating constants are a C99 feature that is incompatible with "
- "C++0x">;
+ "C++0x">, InGroup<CXXHexFloats>;
def ext_hexconstant_invalid : Extension<
"hexadecimal floating constants are a C99 feature">;
def ext_binary_literal : Extension<
diff --git a/include/clang/Basic/DiagnosticParseKinds.td b/include/clang/Basic/DiagnosticParseKinds.td
index 27958515462a..934bd0db1e01 100644
--- a/include/clang/Basic/DiagnosticParseKinds.td
+++ b/include/clang/Basic/DiagnosticParseKinds.td
@@ -13,9 +13,12 @@
let Component = "Parse" in {
-def w_asm_qualifier_ignored : Warning<"ignored %0 qualifier on asm">;
+def w_asm_qualifier_ignored : Warning<"ignored %0 qualifier on asm">,
+ CatInlineAsm;
def warn_file_asm_volatile : Warning<
- "meaningless 'volatile' on asm outside function">;
+ "meaningless 'volatile' on asm outside function">, CatInlineAsm;
+
+let CategoryName = "Parse Issue" in {
def ext_empty_source_file : Extension<"ISO C forbids an empty source file">;
def ext_top_level_semi : Extension<
@@ -119,6 +122,8 @@ def err_expected_semi_after_namespace_name : Error<
"expected ';' after namespace name">;
def err_unexpected_namespace_attributes_alias : Error<
"attributes can not be specified on namespace alias">;
+def err_namespace_nonnamespace_scope : Error<
+ "namespaces can only be defined in global or namespace scope">;
def err_expected_semi_after_attribute_list : Error<
"expected ';' after attribute list">;
def err_expected_semi_after_static_assert : Error<
@@ -129,7 +134,7 @@ def err_label_end_of_compound_statement : Error<
"label at end of compound statement: expected statement">;
def err_expected_string_literal : Error<"expected string literal">;
def err_expected_asm_operand : Error<
- "expected string literal or '[' for asm operand">;
+ "expected string literal or '[' for asm operand">, CatInlineAsm;
def err_expected_selector_for_method : Error<
"expected selector for Objective-C method">;
def err_expected_property_name : Error<"expected property name">;
@@ -311,6 +316,9 @@ def err_explicit_instantiation_with_definition : Error<
"'template' keyword">;
def err_enum_template : Error<"enumeration cannot be a template">;
+def err_missing_dependent_template_keyword : Error<
+ "use 'template' keyword to treat '%0' as a dependent template name">;
+
// Constructor template diagnostics.
def err_out_of_line_constructor_template_id : Error<
"out-of-line constructor for %0 cannot have template arguments">;
@@ -355,6 +363,13 @@ def warn_pragma_expected_identifier : Warning<
"expected identifier in '#pragma %0' - ignored">;
def warn_pragma_extra_tokens_at_eol : Warning<
"extra tokens at end of '#pragma %0' - ignored">;
+// - #pragma options
+def warn_pragma_options_expected_align : Warning<
+ "expected 'align' following '#pragma options' - ignored">;
+def warn_pragma_options_expected_equal : Warning<
+ "expected '=' following '#pragma options align' - ignored">;
+def warn_pragma_options_invalid_option : Warning<
+ "invalid alignment option in '#pragma options align' - ignored">;
// - #pragma pack
def warn_pragma_pack_invalid_action : Warning<
"unknown action for '#pragma pack' - ignored">;
@@ -368,4 +383,5 @@ def warn_pragma_unused_expected_var : Warning<
def warn_pragma_unused_expected_punc : Warning<
"expected ')' or ',' in '#pragma unused'">;
+} // end of Parse Issue category.
} // end of Parser diagnostics
diff --git a/include/clang/Basic/DiagnosticSemaKinds.td b/include/clang/Basic/DiagnosticSemaKinds.td
index 6b40820da814..0ba31aee2ff5 100644
--- a/include/clang/Basic/DiagnosticSemaKinds.td
+++ b/include/clang/Basic/DiagnosticSemaKinds.td
@@ -12,6 +12,7 @@
//===----------------------------------------------------------------------===//
let Component = "Sema" in {
+let CategoryName = "Semantic Issue" in {
// Constant expressions
def err_expr_not_ice : Error<
@@ -36,6 +37,28 @@ def warn_float_underflow : Warning<
"magnitude of floating-point constant too small for type %0; minimum is %1">,
InGroup<LiteralRange>;
+// C99 variable-length arrays
+def ext_vla : Extension<
+ "variable length arrays are a C99 feature, accepted as an extension">,
+ InGroup<VLA>;
+def err_vla_non_pod : Error<"variable length array of non-POD element type %0">;
+def err_vla_in_sfinae : Error<
+ "variable length array cannot be formed during template argument deduction">;
+def err_array_star_in_function_definition : Error<
+ "variable length array must be bound in function definition">;
+def err_vla_decl_in_file_scope : Error<
+ "variable length array declaration not allowed at file scope">;
+def err_vla_decl_has_static_storage : Error<
+ "variable length array declaration can not have 'static' storage duration">;
+def err_vla_decl_has_extern_linkage : Error<
+ "variable length array declaration can not have 'extern' linkage">;
+
+// C99 variably modified types
+def err_variably_modified_template_arg : Error<
+ "variably modified type %0 cannot be used as a template argument">;
+def err_variably_modified_nontype_template_param : Error<
+ "non-type template parameter of variably modified type %0">;
+
// C99 Designated Initializers
def err_array_designator_negative : Error<
"array designator value '%0' is negative">;
@@ -71,11 +94,6 @@ def ext_flexible_array_init : Extension<
"flexible array initialization is a GNU extension">, InGroup<GNU>;
// Declarations.
-def ext_vla : Extension<
- "variable length arrays are a C99 feature, accepted as an extension">;
-def err_vla_cxx : Error<
- "variable length arrays are not permitted in C++">;
-
def ext_anon_param_requires_type_specifier : Extension<
"type specifier required for unnamed parameter, defaults to int">;
def err_bad_variable_name : Error<
@@ -89,8 +107,6 @@ def warn_unused_exception_param : Warning<"unused exception parameter %0">,
InGroup<UnusedExceptionParameter>, DefaultIgnore;
def warn_decl_in_param_list : Warning<
"declaration of %0 will not be visible outside of this function">;
-def err_array_star_in_function_definition : Error<
- "variable length array must be bound in function definition">;
def warn_unused_function : Warning<"unused function %0">,
InGroup<UnusedFunction>, DefaultIgnore;
@@ -220,6 +236,12 @@ def err_object_cannot_be_passed_returned_by_value : Error<
"interface type %1 cannot be %select{returned|passed}0 by value"
"; did you forget * in %1">;
def warn_enum_value_overflow : Warning<"overflow in enumeration value">;
+def warn_pragma_options_align_unsupported_option : Warning<
+ "unsupported alignment option in '#pragma options align'">;
+def warn_pragma_options_align_reset_failed : Warning<
+ "#pragma options align=reset failed: %0">;
+def err_pragma_options_align_mac68k_target_unsupported : Error<
+ "mac68k alignment pragma is not supported on this target">;
def warn_pragma_pack_invalid_alignment : Warning<
"expected #pragma pack parameter to be '1', '2', '4', '8', or '16'">;
// Follow the MSVC implementation.
@@ -293,6 +315,8 @@ def warn_conflicting_ret_types : Warning<
def warn_conflicting_param_types : Warning<
"conflicting parameter types in implementation of %0: %1 vs %2">;
+def warn_conflicting_variadic :Warning<
+ "conflicting variadic declaration of method and its implementation">;
def warn_implements_nscopying : Warning<
"default assign attribute on property %0 which implements "
@@ -503,6 +527,10 @@ def err_access_copy_field :
def err_access_copy_base :
Error<"base class %0 has %select{private|protected}1 copy constructor">,
NoSFINAE;
+def err_access_dtor_ivar :
+ Error<"instance variable of type %0 has %select{private|protected}1 "
+ "destructor">,
+ NoSFINAE;
def note_previous_access_declaration : Note<
"previously declared '%1' here">;
def err_access_outside_class : Error<
@@ -709,6 +737,7 @@ def note_uninit_reference_member : Note<
"uninitialized reference member is here">;
def warn_field_is_uninit : Warning<"field is uninitialized when used here">,
InGroup<DiagGroup<"uninitialized">>;
+def err_init_incomplete_type : Error<"initialization of incomplete type %0">;
def err_temp_copy_no_viable : Error<
"no viable constructor %select{copying variable|copying parameter|"
@@ -883,6 +912,12 @@ def warn_impcast_float_precision : Warning<
def warn_impcast_float_integer : Warning<
"implicit cast turns floating-point number into integer: %0 to %1">,
InGroup<DiagGroup<"conversion">>, DefaultIgnore;
+def warn_impcast_integer_sign : Warning<
+ "implicit cast changes signedness: %0 to %1">,
+ InGroup<DiagGroup<"conversion">>, DefaultIgnore;
+def warn_impcast_integer_sign_conditional : Warning<
+ "operand of ? changes signedness: %0 to %1">,
+ InGroup<DiagGroup<"conversion">>, DefaultIgnore;
def warn_impcast_integer_precision : Warning<
"implicit cast loses integer precision: %0 to %1">,
InGroup<DiagGroup<"conversion">>, DefaultIgnore;
@@ -951,8 +986,7 @@ def err_attribute_regparm_invalid_number : Error<
// Clang-Specific Attributes
def err_attribute_iboutlet : Error<
- "iboutlet attribute can only be applied to instance variables or "
- "properties">;
+ "%0 attribute can only be applied to instance variables or properties">;
def err_attribute_ibaction: Error<
"ibaction attribute can only be applied to Objective-C instance methods">;
def err_attribute_overloadable_not_function : Error<
@@ -1054,15 +1088,29 @@ def note_ovl_candidate_bad_deduction : Note<
"candidate template ignored: failed template argument deduction">;
def note_ovl_candidate_incomplete_deduction : Note<"candidate template ignored: "
"couldn't infer template argument %0">;
-
+def note_ovl_candidate_inconsistent_deduction : Note<
+ "candidate template ignored: deduced conflicting %select{types|values|"
+ "templates}0 for parameter %1 (%2 vs. %3)">;
+def note_ovl_candidate_explicit_arg_mismatch_named : Note<
+ "candidate template ignored: invalid explicitly-specified argument "
+ "for template parameter %0">;
+def note_ovl_candidate_explicit_arg_mismatch_unnamed : Note<
+ "candidate template ignored: invalid explicitly-specified argument "
+ "for %ordinal0 template parameter">;
+def note_ovl_candidate_instantiation_depth : Note<
+ "candidate template ignored: substitution exceeded maximum template "
+ "instantiation depth">;
+def note_ovl_candidate_substitution_failure : Note<
+ "candidate template ignored: substitution failure %0">;
+
// Note that we don't treat templates differently for this diagnostic.
def note_ovl_candidate_arity : Note<"candidate "
"%select{function|function|constructor|function|function|constructor|"
"constructor (the implicit default constructor)|"
"constructor (the implicit copy constructor)|"
- "function (the implicit copy assignment operator)}0 not viable: requires"
- "%select{ at least| at most|}2 %3 argument%s3, but %4 %plural{1:was|:were}4 "
- "provided">;
+ "function (the implicit copy assignment operator)}0 %select{|template }1"
+ "not viable: requires%select{ at least| at most|}2 %3 argument%s3, but %4 "
+ "%plural{1:was|:were}4 provided">;
def note_ovl_candidate_deleted : Note<
"candidate %select{function|function|constructor|"
@@ -1484,6 +1532,12 @@ def err_explicit_instantiation_out_of_scope : Error<
"explicit instantiation of %0 not in a namespace enclosing %1">;
def err_explicit_instantiation_must_be_global : Error<
"explicit instantiation of %0 must occur at global scope">;
+def warn_explicit_instantiation_out_of_scope_0x : Warning<
+ "explicit instantiation of %0 not in a namespace enclosing %1">,
+ InGroup<DiagGroup<"-Wc++0x-compat"> >;
+def warn_explicit_instantiation_must_be_global_0x : Warning<
+ "explicit instantiation of %0 must occur at global scope">,
+ InGroup<DiagGroup<"-Wc++0x-compat"> >;
def err_explicit_instantiation_requires_name : Error<
"explicit instantiation declaration requires a name">;
@@ -1512,6 +1566,9 @@ def err_explicit_instantiation_without_qualified_id_quals : Error<
"qualifier in explicit instantiation of '%0%1' requires a template-id">;
def err_explicit_instantiation_unqualified_wrong_namespace : Error<
"explicit instantiation of %q0 must occur in %1">;
+def warn_explicit_instantiation_unqualified_wrong_namespace_0x : Warning<
+ "explicit instantiation of %q0 must occur in %1">,
+ InGroup<DiagGroup<"c++0x-compat"> >;
def err_explicit_instantiation_undefined_member : Error<
"explicit instantiation of undefined %select{member class|member function|"
"static data member}0 %1 of class template %2">;
@@ -1631,12 +1688,6 @@ def warn_enumerator_too_large : Warning<
def warn_illegal_constant_array_size : Extension<
"size of static array must be an integer constant expression">;
-def err_vla_decl_in_file_scope : Error<
- "variable length array declaration not allowed at file scope">;
-def err_vla_decl_has_static_storage : Error<
- "variable length array declaration can not have 'static' storage duration">;
-def err_vla_decl_has_extern_linkage : Error<
- "variable length array declaration can not have 'extern' linkage">;
def err_vm_decl_in_file_scope : Error<
"variably modified type declaration not allowed at file scope">;
def err_vm_decl_has_extern_linkage : Error<
@@ -1725,20 +1776,20 @@ def err_undeclared_label_use : Error<"use of undeclared label '%0'">;
def err_goto_into_protected_scope : Error<"illegal goto into protected scope">;
def err_switch_into_protected_scope : Error<
"illegal switch case into protected scope">;
-def err_indirect_goto_in_protected_scope : Warning<
- "illegal indirect goto in protected scope, unknown effect on scopes">,
- InGroup<DiagGroup<"label-address-scope">>;
-def err_addr_of_label_in_protected_scope : Warning<
- "address taken of label in protected scope, jump to it would have "
- "unknown effect on scope">, InGroup<DiagGroup<"label-address-scope">>;
+def err_indirect_goto_without_addrlabel : Error<
+ "indirect goto in function with no address-of-label expressions">;
+def warn_indirect_goto_in_protected_scope : Warning<
+ "indirect goto might cross protected scopes">,
+ InGroup<DiagGroup<"label-address-scope">>;
+def note_indirect_goto_target : Note<"possible target of indirect goto">;
def note_protected_by_variable_init : Note<
"jump bypasses variable initialization">;
+def note_protected_by_cleanup : Note<
+ "jump bypasses initialization of variable with __attribute__((cleanup))">;
def note_protected_by_vla_typedef : Note<
"jump bypasses initialization of VLA typedef">;
def note_protected_by_vla : Note<
"jump bypasses initialization of variable length array">;
-def note_protected_by_cleanup : Note<
- "jump bypasses initialization of declaration with __attribute__((cleanup))">;
def note_protected_by_objc_try : Note<
"jump bypasses initialization of @try block">;
def note_protected_by_objc_catch : Note<
@@ -1754,6 +1805,25 @@ def note_protected_by_cxx_catch : Note<
def note_protected_by___block : Note<
"jump bypasses setup of __block variable">;
+def note_exits_cleanup : Note<
+ "jump exits scope of variable with __attribute__((cleanup))">;
+def note_exits_dtor : Note<
+ "jump exits scope of variable with non-trivial destructor">;
+def note_exits___block : Note<
+ "jump exits scope of __block variable">;
+def note_exits_objc_try : Note<
+ "jump exits @try block">;
+def note_exits_objc_catch : Note<
+ "jump exits @catch block">;
+def note_exits_objc_finally : Note<
+ "jump exits @finally block">;
+def note_exits_objc_synchronized : Note<
+ "jump exits @synchronized block">;
+def note_exits_cxx_try : Note<
+ "jump exits try block">;
+def note_exits_cxx_catch : Note<
+ "jump exits catch block">;
+
def err_func_returning_array_function : Error<
"function cannot return %select{array|function}0 type %1">;
def err_field_declared_as_function : Error<"field %0 declared as a function">;
@@ -1764,6 +1834,8 @@ def ext_variable_sized_type_in_struct : ExtWarn<
def err_flexible_array_empty_struct : Error<
"flexible array %0 not allowed in otherwise empty struct">;
+def err_flexible_array_has_nonpod_type : Error<
+ "flexible array member %0 of non-POD element type %1">;
def ext_flexible_array_in_struct : Extension<
"%0 may not be nested in a struct due to flexible array member">;
def ext_flexible_array_in_array : Extension<
@@ -1806,6 +1878,9 @@ def err_func_def_incomplete_result : Error<
// Expressions.
def ext_sizeof_function_type : Extension<
"invalid application of 'sizeof' to a function type">, InGroup<PointerArith>;
+def err_sizeof_alignof_overloaded_function_type : Error<
+ "invalid application of '%select{sizeof|__alignof}0' to an overloaded "
+ "function">;
def ext_sizeof_void_type : Extension<
"invalid application of '%0' to a void type">, InGroup<PointerArith>;
def err_sizeof_alignof_incomplete_type : Error<
@@ -2196,6 +2271,8 @@ def err_default_init_const : Error<
"default initialization of an object of const type %0"
"%select{| requires a user-provided default constructor}1">;
def err_delete_operand : Error<"cannot delete expression of type %0">;
+def ext_delete_void_ptr_operand : ExtWarn<
+ "cannot delete expression with pointer-to-'void' type %0">;
def err_ambiguous_delete_operand : Error<"ambiguous conversion of delete "
"expression of type %0 to a pointer">;
def warn_delete_incomplete : Warning<
@@ -2293,7 +2370,9 @@ def err_cannot_form_pointer_to_member_of_reference_type : Error<
"cannot form a pointer-to-member to member %0 of reference type %1">;
def err_incomplete_object_call : Error<
"incomplete type in call to object of type %0">;
-
+def err_incomplete_pointer_to_member_return : Error<
+ "incomplete return type %0 of pointer-to-member constant">;
+
def warn_condition_is_assignment : Warning<"using the result of an "
"assignment as a condition without parentheses">,
InGroup<Parentheses>;
@@ -2510,31 +2589,35 @@ 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'">;
-def err_asm_invalid_lvalue_in_output : Error<"invalid lvalue in asm output">;
-def err_asm_invalid_output_constraint : Error<
- "invalid output constraint '%0' in asm">;
-def err_asm_invalid_lvalue_in_input : Error<
- "invalid lvalue in asm input for constraint '%0'">;
-def err_asm_invalid_input_constraint : Error<
- "invalid input constraint '%0' in asm">;
-def err_asm_invalid_type_in_input : Error<
- "invalid type %0 in asm input for constraint '%1'">;
-def err_asm_tying_incompatible_types : Error<
- "unsupported inline asm: input with type %0 matching output with type %1">;
-def err_asm_unknown_register_name : Error<"unknown register name '%0' in asm">;
-def err_invalid_asm_cast_lvalue : Error<
- "invalid use of a cast in a inline asm context requiring an l-value: "
- "remove the cast or build with -fheinous-gnu-extensions">;
-
-def warn_invalid_asm_cast_lvalue : Warning<
- "invalid use of a cast in a inline asm context requiring an l-value: "
- "accepted due to -fheinous-gnu-extensions, but clang may remove support "
- "for this in the future">;
+} // End of general sema category.
+// inline asm.
+let CategoryName = "Inline Assembly Issue" in {
+ def err_asm_wide_character : Error<"wide string is invalid in 'asm'">;
+ def err_asm_invalid_lvalue_in_output : Error<"invalid lvalue in asm output">;
+ def err_asm_invalid_output_constraint : Error<
+ "invalid output constraint '%0' in asm">;
+ def err_asm_invalid_lvalue_in_input : Error<
+ "invalid lvalue in asm input for constraint '%0'">;
+ def err_asm_invalid_input_constraint : Error<
+ "invalid input constraint '%0' in asm">;
+ def err_asm_invalid_type_in_input : Error<
+ "invalid type %0 in asm input for constraint '%1'">;
+ def err_asm_tying_incompatible_types : Error<
+ "unsupported inline asm: input with type %0 matching output with type %1">;
+ def err_asm_unknown_register_name : Error<"unknown register name '%0' in asm">;
+ def err_invalid_asm_cast_lvalue : Error<
+ "invalid use of a cast in a inline asm context requiring an l-value: "
+ "remove the cast or build with -fheinous-gnu-extensions">;
+
+ def warn_invalid_asm_cast_lvalue : Warning<
+ "invalid use of a cast in a inline asm context requiring an l-value: "
+ "accepted due to -fheinous-gnu-extensions, but clang may remove support "
+ "for this in the future">;
+}
+
+let CategoryName = "Semantic Issue" in {
def err_invalid_conversion_between_vectors : Error<
"invalid conversion between vector type %0 and %1 of different size">;
@@ -2842,9 +2925,11 @@ def warn_case_value_overflow : Warning<
InGroup<DiagGroup<"switch">>;
def err_duplicate_case : Error<"duplicate case value '%0'">;
def warn_case_empty_range : Warning<"empty case range specified">;
+def warn_missing_case_for_condition :
+ Warning<"no case matching constant switch condition '%0'">;
def warn_missing_cases : Warning<"enumeration value %0 not handled in switch">,
InGroup<DiagGroup<"switch-enum"> >;
-def not_in_enum : Warning<"case value not in enumerated type %0">,
+def warn_not_in_enum : Warning<"case value not in enumerated type %0">,
InGroup<DiagGroup<"switch-enum"> >;
def err_typecheck_statement_requires_scalar : Error<
"statement requires expression of scalar type (%0 invalid)">;
@@ -3010,6 +3095,6 @@ def err_undeclared_protocol_suggest : Error<
def note_base_class_specified_here : Note<
"base class %0 specified here">;
-}
-
+} // end of sema category
+} // end of sema component.
diff --git a/include/clang/Basic/SourceManager.h b/include/clang/Basic/SourceManager.h
index 930fb52873eb..6a4be4609433 100644
--- a/include/clang/Basic/SourceManager.h
+++ b/include/clang/Basic/SourceManager.h
@@ -280,6 +280,57 @@ public:
/// \brief Read the source location entry with index ID.
virtual void ReadSLocEntry(unsigned ID) = 0;
};
+
+
+/// IsBeforeInTranslationUnitCache - This class holds the cache used by
+/// isBeforeInTranslationUnit. The cache structure is complex enough to be
+/// worth breaking out of SourceManager.
+class IsBeforeInTranslationUnitCache {
+ /// L/R QueryFID - These are the FID's of the cached query. If these match up
+ /// with a subsequent query, the result can be reused.
+ FileID LQueryFID, RQueryFID;
+
+ /// CommonFID - This is the file found in common between the two #include
+ /// traces. It is the nearest common ancestor of the #include tree.
+ FileID CommonFID;
+
+ /// L/R CommonOffset - This is the offset of the previous query in CommonFID.
+ /// Usually, this represents the location of the #include for QueryFID, but if
+ /// LQueryFID is a parent of RQueryFID (or vise versa) then these can be a
+ /// random token in the parent.
+ unsigned LCommonOffset, RCommonOffset;
+public:
+
+ /// isCacheValid - Return true if the currently cached values match up with
+ /// the specified LHS/RHS query. If not, we can't use the cache.
+ bool isCacheValid(FileID LHS, FileID RHS) const {
+ return LQueryFID == LHS && RQueryFID == RHS;
+ }
+
+ /// getCachedResult - If the cache is valid, compute the result given the
+ /// specified offsets in the LHS/RHS FID's.
+ bool getCachedResult(unsigned LOffset, unsigned ROffset) const {
+ // If one of the query files is the common file, use the offset. Otherwise,
+ // use the #include loc in the common file.
+ if (LQueryFID != CommonFID) LOffset = LCommonOffset;
+ if (RQueryFID != CommonFID) ROffset = RCommonOffset;
+ return LOffset < ROffset;
+ }
+
+ // Set up a new query.
+ void setQueryFIDs(FileID LHS, FileID RHS) {
+ LQueryFID = LHS;
+ RQueryFID = RHS;
+ }
+
+ void setCommonLoc(FileID commonFID, unsigned lCommonOffset,
+ unsigned rCommonOffset) {
+ CommonFID = commonFID;
+ LCommonOffset = lCommonOffset;
+ RCommonOffset = rCommonOffset;
+ }
+
+};
/// SourceManager - This file handles loading and caching of source files into
/// memory. This object owns the MemoryBuffer objects for all of the loaded
@@ -347,9 +398,7 @@ class SourceManager {
mutable unsigned NumLinearScans, NumBinaryProbes;
// Cache results for the isBeforeInTranslationUnit method.
- mutable FileID LastLFIDForBeforeTUCheck;
- mutable FileID LastRFIDForBeforeTUCheck;
- mutable bool LastResForBeforeTUCheck;
+ mutable IsBeforeInTranslationUnitCache IsBeforeInTUCache;
// SourceManager doesn't support copy construction.
explicit SourceManager(const SourceManager&);
diff --git a/include/clang/Basic/TargetInfo.h b/include/clang/Basic/TargetInfo.h
index 19987508baf3..00fd9b92e13e 100644
--- a/include/clang/Basic/TargetInfo.h
+++ b/include/clang/Basic/TargetInfo.h
@@ -58,6 +58,8 @@ protected:
const llvm::fltSemantics *FloatFormat, *DoubleFormat, *LongDoubleFormat;
unsigned char RegParmMax, SSERegParmMax;
+ unsigned HasAlignMac68kSupport : 1;
+
// TargetInfo Constructor. Default initializes all fields.
TargetInfo(const std::string &T);
@@ -210,6 +212,12 @@ public:
return UseBitFieldTypeAlignment;
}
+ /// hasAlignMac68kSupport - Check whether this target support '#pragma options
+ /// align=mac68k'.
+ bool hasAlignMac68kSupport() const {
+ return HasAlignMac68kSupport;
+ }
+
/// getTypeName - Return the user string for the specified integer type enum.
/// For example, SignedShort -> "short".
static const char *getTypeName(IntType T);
diff --git a/include/clang/Basic/TokenKinds.def b/include/clang/Basic/TokenKinds.def
index 52e83f4045ef..b16b82854b1c 100644
--- a/include/clang/Basic/TokenKinds.def
+++ b/include/clang/Basic/TokenKinds.def
@@ -220,7 +220,7 @@ KEYWORD(unsigned , KEYALL)
KEYWORD(void , KEYALL)
KEYWORD(volatile , KEYALL)
KEYWORD(while , KEYALL)
-KEYWORD(_Bool , KEYALL)
+KEYWORD(_Bool , KEYNOMS)
KEYWORD(_Complex , KEYALL)
KEYWORD(_Imaginary , KEYALL)
KEYWORD(__func__ , KEYALL)
@@ -336,6 +336,7 @@ KEYWORD(__declspec , KEYALL)
KEYWORD(__cdecl , KEYALL)
KEYWORD(__stdcall , KEYALL)
KEYWORD(__fastcall , KEYALL)
+KEYWORD(__thiscall , KEYALL)
KEYWORD(__forceinline , KEYALL)
// Altivec Extension.
@@ -372,6 +373,7 @@ ALIAS("_asm" , asm , KEYMS)
ALIAS("_cdecl" , __cdecl , KEYMS)
ALIAS("_fastcall" , __fastcall , KEYMS)
ALIAS("_stdcall" , __stdcall , KEYMS)
+ALIAS("_thiscall" , __thiscall , KEYMS)
//===----------------------------------------------------------------------===//
// Objective-C @-preceeded keywords.
diff --git a/include/clang/CMakeLists.txt b/include/clang/CMakeLists.txt
index 61d2bf602d9a..c2880481a2e9 100644
--- a/include/clang/CMakeLists.txt
+++ b/include/clang/CMakeLists.txt
@@ -1,2 +1,3 @@
+add_subdirectory(AST)
add_subdirectory(Basic)
add_subdirectory(Driver)
diff --git a/include/clang/Checker/PathSensitive/AnalysisManager.h b/include/clang/Checker/PathSensitive/AnalysisManager.h
index 0c59d7b572a4..3c7cb68c0943 100644
--- a/include/clang/Checker/PathSensitive/AnalysisManager.h
+++ b/include/clang/Checker/PathSensitive/AnalysisManager.h
@@ -37,8 +37,12 @@ class AnalysisManager : public BugReporterData {
enum AnalysisScope { ScopeTU, ScopeDecl } AScope;
+ // The maximum number of exploded nodes the analyzer will generate.
unsigned MaxNodes;
+ // The maximum number of times the analyzer will go through a loop.
+ unsigned MaxLoop;
+
bool VisualizeEGDot;
bool VisualizeEGUbi;
bool PurgeDead;
@@ -52,19 +56,22 @@ class AnalysisManager : public BugReporterData {
// bifurcates paths.
bool EagerlyAssume;
bool TrimGraph;
+ bool InlineCall;
public:
AnalysisManager(ASTContext &ctx, Diagnostic &diags,
const LangOptions &lang, PathDiagnosticClient *pd,
StoreManagerCreator storemgr,
ConstraintManagerCreator constraintmgr, unsigned maxnodes,
- bool vizdot, bool vizubi, bool purge, bool eager, bool trim)
+ unsigned maxloop,
+ bool vizdot, bool vizubi, bool purge, bool eager, bool trim,
+ bool inlinecall)
: Ctx(ctx), Diags(diags), LangInfo(lang), PD(pd),
CreateStoreMgr(storemgr), CreateConstraintMgr(constraintmgr),
- AScope(ScopeDecl), MaxNodes(maxnodes),
+ AScope(ScopeDecl), MaxNodes(maxnodes), MaxLoop(maxloop),
VisualizeEGDot(vizdot), VisualizeEGUbi(vizubi), PurgeDead(purge),
- EagerlyAssume(eager), TrimGraph(trim) {}
+ EagerlyAssume(eager), TrimGraph(trim), InlineCall(inlinecall) {}
~AnalysisManager() { FlushDiagnostics(); }
@@ -108,6 +115,8 @@ public:
unsigned getMaxNodes() const { return MaxNodes; }
+ unsigned getMaxLoop() const { return MaxLoop; }
+
bool shouldVisualizeGraphviz() const { return VisualizeEGDot; }
bool shouldVisualizeUbigraph() const { return VisualizeEGUbi; }
@@ -122,6 +131,8 @@ public:
bool shouldEagerlyAssume() const { return EagerlyAssume; }
+ bool shouldInlineCall() const { return InlineCall; }
+
CFG *getCFG(Decl const *D) {
return AnaCtxMgr.getContext(D)->getCFG();
}
diff --git a/include/clang/Checker/PathSensitive/GRExprEngine.h b/include/clang/Checker/PathSensitive/GRExprEngine.h
index f04ca75084b7..ac407f6933c8 100644
--- a/include/clang/Checker/PathSensitive/GRExprEngine.h
+++ b/include/clang/Checker/PathSensitive/GRExprEngine.h
@@ -456,6 +456,8 @@ private:
void EvalLocation(ExplodedNodeSet &Dst, Stmt *S, ExplodedNode* Pred,
const GRState* St, SVal location,
const void *tag, bool isLoad);
+
+ bool InlineCall(ExplodedNodeSet &Dst, const CallExpr *CE, ExplodedNode *Pred);
};
} // end clang namespace
diff --git a/include/clang/Checker/PathSensitive/Store.h b/include/clang/Checker/PathSensitive/Store.h
index 41d7c2bd713e..f3155b9aacd4 100644
--- a/include/clang/Checker/PathSensitive/Store.h
+++ b/include/clang/Checker/PathSensitive/Store.h
@@ -18,6 +18,7 @@
#include "clang/Checker/PathSensitive/SVals.h"
#include "clang/Checker/PathSensitive/ValueManager.h"
#include "llvm/ADT/DenseSet.h"
+#include "llvm/ADT/Optional.h"
namespace clang {
@@ -143,9 +144,9 @@ public:
return UnknownVal();
}
- virtual Store RemoveDeadBindings(Store store, Stmt* Loc,
- const StackFrameContext *LCtx,
- SymbolReaper& SymReaper,
+ virtual const GRState *RemoveDeadBindings(GRState &state, Stmt* Loc,
+ const StackFrameContext *LCtx,
+ SymbolReaper& SymReaper,
llvm::SmallVectorImpl<const MemRegion*>& RegionRoots) = 0;
virtual Store BindDecl(Store store, const VarRegion *VR, SVal initVal) = 0;
@@ -167,10 +168,15 @@ public:
// FIXME: Make out-of-line.
virtual const GRState *setExtent(const GRState *state,
- const MemRegion *region, SVal extent) {
+ const MemRegion *region, SVal extent) {
return state;
}
+ virtual llvm::Optional<SVal> getExtent(const GRState *state,
+ const MemRegion *R) {
+ return llvm::Optional<SVal>();
+ }
+
/// EnterStackFrame - Let the StoreManager to do something when execution
/// engine is about to execute into a callee.
virtual const GRState *EnterStackFrame(const GRState *state,
diff --git a/include/clang/CodeGen/CodeGenOptions.h b/include/clang/CodeGen/CodeGenOptions.h
index 54d3ba03f3f0..6241230ffb45 100644
--- a/include/clang/CodeGen/CodeGenOptions.h
+++ b/include/clang/CodeGen/CodeGenOptions.h
@@ -54,6 +54,7 @@ public:
unsigned ObjCDispatchMethod : 2; /// Method of Objective-C dispatch to use.
unsigned OptimizationLevel : 3; /// The -O[0-4] option specified.
unsigned OptimizeSize : 1; /// If -Os is specified.
+ unsigned RelaxAll : 1; /// Relax all machine code instructions.
unsigned SoftFloat : 1; /// -soft-float.
unsigned TimePasses : 1; /// Set when -ftime-report is enabled.
unsigned UnitAtATime : 1; /// Unused. For mirroring GCC optimization
@@ -108,6 +109,7 @@ public:
ObjCDispatchMethod = Legacy;
OptimizationLevel = 0;
OptimizeSize = 0;
+ RelaxAll = 0;
SoftFloat = 0;
TimePasses = 0;
UnitAtATime = 1;
diff --git a/include/clang/Driver/ArgList.h b/include/clang/Driver/ArgList.h
index 0a8eaeaf238f..7a14ae84d466 100644
--- a/include/clang/Driver/ArgList.h
+++ b/include/clang/Driver/ArgList.h
@@ -17,12 +17,15 @@
#include <list>
#include <string>
+#include <vector>
namespace llvm {
class Twine;
}
namespace clang {
+ class Diagnostic;
+
namespace driver {
class Arg;
class ArgList;
@@ -175,6 +178,25 @@ namespace driver {
/// getArgString - Return the input argument string at \arg Index.
virtual const char *getArgString(unsigned Index) const = 0;
+
+ /// @}
+ /// @name Argument Lookup Utilities
+ /// @{
+
+ /// getLastArgValue - Return the value of the last argument, or a default.
+ llvm::StringRef getLastArgValue(OptSpecifier Id,
+ llvm::StringRef Default = "") const;
+
+ /// getLastArgValue - Return the value of the last argument as an integer,
+ /// or a default. Emits an error if the argument is given, but non-integral.
+ int getLastArgIntValue(OptSpecifier Id, int Default,
+ Diagnostic &Diags) const;
+
+ /// getAllArgValues - Get the values of all instances of the given argument
+ /// as strings.
+ std::vector<std::string> getAllArgValues(OptSpecifier Id) const;
+
+ /// @}
/// @name Translation Utilities
/// @{
diff --git a/include/clang/Driver/CC1AsOptions.h b/include/clang/Driver/CC1AsOptions.h
new file mode 100644
index 000000000000..05082132cee4
--- /dev/null
+++ b/include/clang/Driver/CC1AsOptions.h
@@ -0,0 +1,32 @@
+//===--- CC1AsOptions.h - Clang Assembler Options Table ---------*- C++ -*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef CLANG_DRIVER_CC1ASOPTIONS_H
+#define CLANG_DRIVER_CC1ASOPTIONS_H
+
+namespace clang {
+namespace driver {
+ class OptTable;
+
+namespace cc1asoptions {
+ enum ID {
+ OPT_INVALID = 0, // This is not an option ID.
+#define OPTION(NAME, ID, KIND, GROUP, ALIAS, FLAGS, PARAM, \
+ HELPTEXT, METAVAR) OPT_##ID,
+#include "clang/Driver/CC1AsOptions.inc"
+ LastOption
+#undef OPTION
+ };
+}
+
+ OptTable *createCC1AsOptTable();
+}
+}
+
+#endif
diff --git a/include/clang/Driver/CC1AsOptions.td b/include/clang/Driver/CC1AsOptions.td
new file mode 100644
index 000000000000..5c08dc630551
--- /dev/null
+++ b/include/clang/Driver/CC1AsOptions.td
@@ -0,0 +1,71 @@
+//===--- CC1AsOptions.td - Options for clang -cc1as -----------------------===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+//
+// This file defines the options accepted by clang -cc1as.
+//
+//===----------------------------------------------------------------------===//
+
+// Include the common option parsing interfaces.
+include "OptParser.td"
+
+//===----------------------------------------------------------------------===//
+// Target Options
+//===----------------------------------------------------------------------===//
+
+def triple : Separate<"-triple">,
+ HelpText<"Specify target triple (e.g. x86_64-pc-linux-gnu)">;
+
+//===----------------------------------------------------------------------===//
+// Language Options
+//===----------------------------------------------------------------------===//
+
+def I : JoinedOrSeparate<"-I">, MetaVarName<"<directory>">,
+ HelpText<"Add directory to include search path">;
+def n : Flag<"-n">,
+ HelpText<"Don't automatically start assembly file with a text section">;
+
+//===----------------------------------------------------------------------===//
+// Frontend Options
+//===----------------------------------------------------------------------===//
+
+def o : Separate<"-o">, MetaVarName<"<path>">, HelpText<"Specify output file">;
+
+def filetype : Separate<"-filetype">,
+ HelpText<"Specify the output file type ('asm', 'null', or 'obj')">;
+
+def help : Flag<"-help">,
+ HelpText<"Print this help text">;
+def _help : Flag<"--help">, Alias<help>;
+
+def version : Flag<"-version">,
+ HelpText<"Print the assembler version">;
+def _version : Flag<"--version">, Alias<version>;
+
+// Generic forwarding to LLVM options. This should only be used for debugging
+// and experimental features.
+def mllvm : Separate<"-mllvm">,
+ HelpText<"Additional arguments to forward to LLVM's option processing">;
+
+//===----------------------------------------------------------------------===//
+// Transliterate Options
+//===----------------------------------------------------------------------===//
+
+def output_asm_variant : Separate<"-output-asm-variant">,
+ HelpText<"Select the asm variant index to use for output">;
+def show_encoding : Flag<"-show-encoding">,
+ HelpText<"Show instruction encoding information in transliterate mode">;
+def show_inst : Flag<"-show-inst">,
+ HelpText<"Show internal instruction representation in transliterate mode">;
+
+//===----------------------------------------------------------------------===//
+// Assemble Options
+//===----------------------------------------------------------------------===//
+
+def relax_all : Flag<"-relax-all">,
+ HelpText<"Relax all fixups (for performance testing)">;
diff --git a/include/clang/Driver/CC1Options.td b/include/clang/Driver/CC1Options.td
index 0badeb9efa54..fd8322b84370 100644
--- a/include/clang/Driver/CC1Options.td
+++ b/include/clang/Driver/CC1Options.td
@@ -56,8 +56,6 @@ def analysis_ObjCMemChecker : Flag<"-analyzer-check-objc-mem">,
HelpText<"Run the [Core] Foundation reference count checker">;
def analysis_WarnSizeofPointer : Flag<"-warn-sizeof-pointer">,
HelpText<"Warn about unintended use of sizeof() on pointer expressions">;
-def analysis_InlineCall : Flag<"-inline-call">,
- HelpText<"Experimental transfer function inlining callees when its definition is available.">;
def analyzer_store : Separate<"-analyzer-store">,
HelpText<"Source Code Analysis - Abstract Memory Store Models">;
@@ -97,8 +95,12 @@ def analyzer_viz_egraph_graphviz : Flag<"-analyzer-viz-egraph-graphviz">,
HelpText<"Display exploded graph using GraphViz">;
def analyzer_viz_egraph_ubigraph : Flag<"-analyzer-viz-egraph-ubigraph">,
HelpText<"Display exploded graph using Ubigraph">;
+def analyzer_inline_call : Flag<"-analyzer-inline-call">,
+ HelpText<"Experimental transfer function inlining callees when its definition is available.">;
def analyzer_max_nodes : Separate<"-analyzer-max-nodes">,
HelpText<"The maximum number of nodes the analyzer can generate">;
+def analyzer_max_loop : Separate<"-analyzer-max-loop">,
+ HelpText<"The maximum number of times the analyzer will go through a loop">;
//===----------------------------------------------------------------------===//
// CodeGen Options
@@ -145,6 +147,8 @@ def mno_zero_initialized_in_bss : Flag<"-mno-zero-initialized-in-bss">,
HelpText<"Do not put zero initialized data in the BSS">;
def msoft_float : Flag<"-msoft-float">,
HelpText<"Use software floating point">;
+def mrelax_all : Flag<"-mrelax-all">,
+ HelpText<"Relax all machine instructions">;
def mrelocation_model : Separate<"-mrelocation-model">,
HelpText<"The relocation model to use">;
def munwind_tables : Flag<"-munwind-tables">,
@@ -196,6 +200,9 @@ def fdiagnostics_print_source_range_info : Flag<"-fdiagnostics-print-source-rang
HelpText<"Print source range spans in numeric form">;
def fdiagnostics_show_option : Flag<"-fdiagnostics-show-option">,
HelpText<"Print diagnostic name with mappable diagnostics">;
+def fdiagnostics_show_category : Separate<"-fdiagnostics-show-category">,
+ HelpText<"Print diagnostic category">;
+
def ftabstop : Separate<"-ftabstop">, MetaVarName<"<N>">,
HelpText<"Set the tab stop distance.">;
def ferror_limit : Separate<"-ferror-limit">, MetaVarName<"<N>">,
@@ -238,6 +245,8 @@ def no_code_completion_debug_printer : Flag<"-no-code-completion-debug-printer">
HelpText<"Don't use the \"debug\" code-completion print">;
def code_completion_macros : Flag<"-code-completion-macros">,
HelpText<"Include macros in code-completion results">;
+def code_completion_patterns : Flag<"-code-completion-patterns">,
+ HelpText<"Include code patterns in code-completion results">;
def disable_free : Flag<"-disable-free">,
HelpText<"Disable freeing of memory on exit">;
def help : Flag<"-help">,
@@ -293,6 +302,8 @@ def ast_dump : Flag<"-ast-dump">,
HelpText<"Build ASTs and then debug dump them">;
def ast_view : Flag<"-ast-view">,
HelpText<"Build ASTs and view them with GraphViz">;
+def boostcon : Flag<"-boostcon">,
+ HelpText<"BoostCon workshop mode">;
def print_decl_contexts : Flag<"-print-decl-contexts">,
HelpText<"Print DeclContexts and their Decls">;
def emit_pth : Flag<"-emit-pth">,
@@ -307,6 +318,8 @@ def emit_llvm_bc : Flag<"-emit-llvm-bc">,
HelpText<"Build ASTs then convert to LLVM, emit .bc file">;
def emit_llvm_only : Flag<"-emit-llvm-only">,
HelpText<"Build ASTs and convert to LLVM, discarding output">;
+def emit_codegen_only : Flag<"-emit-codegen-only">,
+ HelpText<"Generate machine code, but discard output">;
def emit_obj : Flag<"-emit-obj">,
HelpText<"Emit native object files">;
def rewrite_test : Flag<"-rewrite-test">,
diff --git a/include/clang/Driver/CMakeLists.txt b/include/clang/Driver/CMakeLists.txt
index ed9825b59df5..99be53ffc72b 100644
--- a/include/clang/Driver/CMakeLists.txt
+++ b/include/clang/Driver/CMakeLists.txt
@@ -9,3 +9,9 @@ tablegen(CC1Options.inc
-gen-opt-parser-defs)
add_custom_target(ClangCC1Options
DEPENDS CC1Options.inc)
+
+set(LLVM_TARGET_DEFINITIONS CC1AsOptions.td)
+tablegen(CC1AsOptions.inc
+ -gen-opt-parser-defs)
+add_custom_target(ClangCC1AsOptions
+ DEPENDS CC1AsOptions.inc)
diff --git a/include/clang/Driver/Makefile b/include/clang/Driver/Makefile
index 18f3e58d7db4..b462aaa24bc9 100644
--- a/include/clang/Driver/Makefile
+++ b/include/clang/Driver/Makefile
@@ -1,5 +1,5 @@
LEVEL = ../../../../..
-BUILT_SOURCES = Options.inc CC1Options.inc
+BUILT_SOURCES = Options.inc CC1Options.inc CC1AsOptions.inc
TABLEGEN_INC_FILES_COMMON = 1
@@ -13,4 +13,6 @@ $(ObjDir)/CC1Options.inc.tmp : CC1Options.td OptParser.td $(TBLGEN) $(ObjDir)/.d
$(Echo) "Building Clang CC1 Option tables with tblgen"
$(Verb) $(TableGen) -gen-opt-parser-defs -o $(call SYSPATH, $@) $<
-
+$(ObjDir)/CC1AsOptions.inc.tmp : CC1AsOptions.td OptParser.td $(TBLGEN) $(ObjDir)/.dir
+ $(Echo) "Building Clang CC1 Assembler Option tables with tblgen"
+ $(Verb) $(TableGen) -gen-opt-parser-defs -o $(call SYSPATH, $@) $<
diff --git a/include/clang/Driver/Options.td b/include/clang/Driver/Options.td
index f6e69e045444..a9a52c01f45b 100644
--- a/include/clang/Driver/Options.td
+++ b/include/clang/Driver/Options.td
@@ -139,6 +139,7 @@ def MQ : JoinedOrSeparate<"-MQ">, Group<M_Group>;
def MT : JoinedOrSeparate<"-MT">, Group<M_Group>;
def Mach : Flag<"-Mach">;
def M : Flag<"-M">, Group<M_Group>;
+def O0 : Joined<"-O0">, Group<O_Group>;
def O4 : Joined<"-O4">, Group<O_Group>;
def ObjCXX : Flag<"-ObjC++">, Flags<[DriverOption]>,
HelpText<"Treat source input files as Objective-C++ inputs">;
@@ -231,6 +232,7 @@ def fPIC : Flag<"-fPIC">, Group<f_Group>;
def fPIE : Flag<"-fPIE">, Group<f_Group>;
def faccess_control : Flag<"-faccess-control">, Group<f_Group>;
def fapple_kext : Flag<"-fapple-kext">, Group<f_Group>;
+def fasm : Flag<"-fasm">, Group<f_Group>;
def fasm_blocks : Flag<"-fasm-blocks">, Group<clang_ignored_f_Group>;
def fassume_sane_operator_new : Flag<"-fassume-sane-operator-new">, Group<f_Group>;
def fastcp : Flag<"-fastcp">, Group<f_Group>;
@@ -257,6 +259,7 @@ def fdiagnostics_binary : Flag<"-fdiagnostics-binary">, Group<f_Group>, Flags<[H
def fdiagnostics_fixit_info : Flag<"-fdiagnostics-fixit-info">, Group<f_Group>;
def fdiagnostics_print_source_range_info : Flag<"-fdiagnostics-print-source-range-info">, Group<f_Group>;
def fdiagnostics_show_option : Flag<"-fdiagnostics-show-option">, Group<f_Group>;
+def fdiagnostics_show_category_EQ : Joined<"-fdiagnostics-show-category=">, Group<f_Group>;
def fdollars_in_identifiers : Flag<"-fdollars-in-identifiers">, Group<f_Group>;
def feliminate_unused_debug_symbols : Flag<"-feliminate-unused-debug-symbols">, Group<f_Group>;
def femit_all_decls : Flag<"-femit-all-decls">, Group<f_Group>;
@@ -265,10 +268,7 @@ def fexceptions : Flag<"-fexceptions">, Group<f_Group>;
def fextdirs_EQ : Joined<"-fextdirs=">, Group<f_Group>;
def fhosted : Flag<"-fhosted">, Group<f_Group>;
def ffreestanding : Flag<"-ffreestanding">, Group<f_Group>;
-
def fgnu_keywords : Flag<"-fgnu-keywords">, Group<f_Group>;
-def fasm : Flag<"-fasm">, Alias<fgnu_keywords>;
-
def fgnu_runtime : Flag<"-fgnu-runtime">, Group<f_Group>;
def fheinous_gnu_extensions : Flag<"-fheinous-gnu-extensions">;
def filelist : Separate<"-filelist">, Flags<[LinkerInput]>;
@@ -291,6 +291,7 @@ def fmudflap : Flag<"-fmudflap">, Group<f_Group>;
def fnested_functions : Flag<"-fnested-functions">, Group<f_Group>;
def fnext_runtime : Flag<"-fnext-runtime">, Group<f_Group>;
def fno_access_control : Flag<"-fno-access-control">, Group<f_Group>;
+def fno_asm : Flag<"-fno-asm">, Group<f_Group>;
def fno_asynchronous_unwind_tables : Flag<"-fno-asynchronous-unwind-tables">, Group<f_Group>;
def fno_assume_sane_operator_new : Flag<"-fno-assume-sane-operator-new">, Group<f_Group>;
def fno_blocks : Flag<"-fno-blocks">, Group<f_Group>;
@@ -306,10 +307,7 @@ def fno_diagnostics_show_option : Flag<"-fno-diagnostics-show-option">, Group<f_
def fno_dollars_in_identifiers : Flag<"-fno-dollars-in-identifiers">, Group<f_Group>;
def fno_eliminate_unused_debug_symbols : Flag<"-fno-eliminate-unused-debug-symbols">, Group<f_Group>;
def fno_exceptions : Flag<"-fno-exceptions">, Group<f_Group>;
-
def fno_gnu_keywords : Flag<"-fno-gnu-keywords">, Group<f_Group>;
-def fno_asm : Flag<"-fno-asm">, Alias<fno_gnu_keywords>;
-
def fno_inline_functions : Flag<"-fno-inline-functions">, Group<clang_ignored_f_Group>;
def fno_inline : Flag<"-fno-inline">, Group<clang_ignored_f_Group>;
def fno_keep_inline_functions : Flag<"-fno-keep-inline-functions">, Group<clang_ignored_f_Group>;
@@ -329,6 +327,7 @@ def fno_threadsafe_statics : Flag<"-fno-threadsafe-statics">, Group<f_Group>;
def fno_use_cxa_atexit : Flag<"-fno-use-cxa-atexit">, Group<f_Group>;
def fno_unit_at_a_time : Flag<"-fno-unit-at-a-time">, Group<f_Group>;
def fno_unwind_tables : Flag<"-fno-unwind-tables">, Group<f_Group>;
+def fno_verbose_asm : Flag<"-fno-verbose-asm">, Group<f_Group>;
def fno_working_directory : Flag<"-fno-working-directory">, Group<f_Group>;
def fno_zero_initialized_in_bss : Flag<"-fno-zero-initialized-in-bss">, Group<f_Group>;
def fobjc_abi_version_EQ : Joined<"-fobjc-abi-version=">, Group<f_Group>;
@@ -384,6 +383,8 @@ def fverbose_asm : Flag<"-fverbose-asm">, Group<f_Group>;
def fvisibility_EQ : Joined<"-fvisibility=">, Group<f_Group>;
def fwritable_strings : Flag<"-fwritable-strings">, Group<f_Group>;
def fzero_initialized_in_bss : Flag<"-fzero-initialized-in-bss">, Group<f_Group>;
+def ffunction_sections: Flag <"-ffunction-sections">, Group<f_Group>;
+def fdata_sections : Flag <"-fdata-sections">, Group<f_Group>;
def f : Joined<"-f">, Group<f_Group>;
def g0 : Joined<"-g0">, Group<g_Group>;
def g3 : Joined<"-g3">, Group<g_Group>;
@@ -436,6 +437,7 @@ def mno_constant_cfstrings : Flag<"-mno-constant-cfstrings">, Group<m_Group>;
def mno_mmx : Flag<"-mno-mmx">, Group<m_x86_Features_Group>;
def mno_pascal_strings : Flag<"-mno-pascal-strings">, Group<m_Group>;
def mno_red_zone : Flag<"-mno-red-zone">, Group<m_Group>;
+def mno_relax_all : Flag<"-mno-relax-all">, Group<m_Group>;
def mno_soft_float : Flag<"-mno-soft-float">, Group<m_Group>;
def mno_sse2 : Flag<"-mno-sse2">, Group<m_x86_Features_Group>;
def mno_sse3 : Flag<"-mno-sse3">, Group<m_x86_Features_Group>;
@@ -453,6 +455,7 @@ def marm : Flag<"-marm">, Alias<mno_thumb>;
def mno_warn_nonportable_cfstrings : Flag<"-mno-warn-nonportable-cfstrings">, Group<m_Group>;
def mpascal_strings : Flag<"-mpascal-strings">, Group<m_Group>;
def mred_zone : Flag<"-mred-zone">, Group<m_Group>;
+def mrelax_all : Flag<"-mrelax-all">, Group<m_Group>;
def msoft_float : Flag<"-msoft-float">, Group<m_Group>;
def msse2 : Flag<"-msse2">, Group<m_x86_Features_Group>;
def msse3 : Flag<"-msse3">, Group<m_x86_Features_Group>;
@@ -667,6 +670,7 @@ def _pipe : Flag<"--pipe">, Alias<pipe>, Flags<[DriverOption]>;
def _prefix_EQ : Joined<"--prefix=">, Alias<B>, Flags<[RenderSeparate]>;
def _prefix : Separate<"--prefix">, Alias<B>;
def _preprocess : Flag<"--preprocess">, Alias<E>;
+def _print_diagnostic_categories : Flag<"--print-diagnostic-categories">;
def _print_file_name_EQ : Joined<"--print-file-name=">, Alias<print_file_name_EQ>;
def _print_file_name : Separate<"--print-file-name">, Alias<print_file_name_EQ>;
def _print_libgcc_file_name : Flag<"--print-libgcc-file-name">, Alias<print_libgcc_file_name>;
diff --git a/include/clang/Driver/Tool.h b/include/clang/Driver/Tool.h
index ef77206c6593..4368a81e3a41 100644
--- a/include/clang/Driver/Tool.h
+++ b/include/clang/Driver/Tool.h
@@ -30,17 +30,23 @@ class Tool {
/// The tool name (for debugging).
const char *Name;
+ /// The human readable name for the tool, for use in diagnostics.
+ const char *ShortName;
+
/// The tool chain this tool is a part of.
const ToolChain &TheToolChain;
public:
- Tool(const char *Name, const ToolChain &TC);
+ Tool(const char *Name, const char *ShortName,
+ const ToolChain &TC);
public:
virtual ~Tool();
const char *getName() const { return Name; }
+ const char *getShortName() const { return ShortName; }
+
const ToolChain &getToolChain() const { return TheToolChain; }
virtual bool acceptsPipedInput() const = 0;
diff --git a/include/clang/Frontend/AnalysisConsumer.h b/include/clang/Frontend/AnalysisConsumer.h
index 3341bb01f0fa..2cbdf368a893 100644
--- a/include/clang/Frontend/AnalysisConsumer.h
+++ b/include/clang/Frontend/AnalysisConsumer.h
@@ -61,6 +61,7 @@ public:
AnalysisDiagClients AnalysisDiagOpt;
std::string AnalyzeSpecificFunction;
unsigned MaxNodes;
+ unsigned MaxLoop;
unsigned AnalyzeAll : 1;
unsigned AnalyzerDisplayProgress : 1;
unsigned AnalyzeNestedBlocks : 1;
@@ -71,6 +72,8 @@ public:
unsigned VisualizeEGUbi : 1;
unsigned EnableExperimentalChecks : 1;
unsigned EnableExperimentalInternalChecks : 1;
+ unsigned InlineCall : 1;
+
public:
AnalyzerOptions() {
AnalysisStoreOpt = BasicStoreModel;
diff --git a/include/clang/Frontend/CodeGenAction.h b/include/clang/Frontend/CodeGenAction.h
index a1e3c42075b6..dfc117a0b06c 100644
--- a/include/clang/Frontend/CodeGenAction.h
+++ b/include/clang/Frontend/CodeGenAction.h
@@ -57,6 +57,11 @@ public:
EmitLLVMOnlyAction();
};
+class EmitCodeGenOnlyAction : public CodeGenAction {
+public:
+ EmitCodeGenOnlyAction();
+};
+
class EmitObjAction : public CodeGenAction {
public:
EmitObjAction();
diff --git a/include/clang/Frontend/CompilerInstance.h b/include/clang/Frontend/CompilerInstance.h
index 36720c9d1462..06dc8004a652 100644
--- a/include/clang/Frontend/CompilerInstance.h
+++ b/include/clang/Frontend/CompilerInstance.h
@@ -519,7 +519,7 @@ public:
createCodeCompletionConsumer(Preprocessor &PP, const std::string &Filename,
unsigned Line, unsigned Column,
bool UseDebugPrinter, bool ShowMacros,
- llvm::raw_ostream &OS);
+ bool ShowCodePatterns, llvm::raw_ostream &OS);
/// Create the frontend timer and replace any existing one with it.
void createFrontendTimer();
diff --git a/include/clang/Frontend/DeclXML.def b/include/clang/Frontend/DeclXML.def
index e839a8c4c772..16551ee03e1f 100644
--- a/include/clang/Frontend/DeclXML.def
+++ b/include/clang/Frontend/DeclXML.def
@@ -84,6 +84,7 @@
NODE_XML(Decl, "FIXME_Decl")
ATTRIBUTE_FILE_LOCATION_XML
+ ATTRIBUTE_XML(getDeclKindName(), "unhandled_decl_name")
END_NODE_XML
NODE_XML(FunctionDecl, "Function")
@@ -106,7 +107,7 @@ NODE_XML(FunctionDecl, "Function")
SUB_NODE_FN_BODY_XML
END_NODE_XML
-NODE_XML(CXXMethodDecl, "CXXMethodDecl")
+NODE_XML(CXXMethodDecl, "CXXMethod")
ID_ATTRIBUTE_XML
ATTRIBUTE_FILE_LOCATION_XML
ATTRIBUTE_XML(getDeclContext(), "context")
@@ -116,6 +117,79 @@ NODE_XML(CXXMethodDecl, "CXXMethodDecl")
ATTRIBUTE_OPT_XML(isInlineSpecified(), "inline")
ATTRIBUTE_OPT_XML(isStatic(), "static")
ATTRIBUTE_OPT_XML(isVirtual(), "virtual")
+ ATTRIBUTE_ENUM_OPT_XML(getAccess(), "access")
+ ENUM_XML(AS_none, "")
+ ENUM_XML(AS_public, "public")
+ ENUM_XML(AS_protected, "protected")
+ ENUM_XML(AS_private, "private")
+ END_ENUM_XML
+ ATTRIBUTE_XML(getNumParams(), "num_args")
+ SUB_NODE_SEQUENCE_XML(ParmVarDecl)
+ SUB_NODE_FN_BODY_XML
+END_NODE_XML
+
+NODE_XML(CXXConstructorDecl, "CXXConstructor")
+ ID_ATTRIBUTE_XML
+ ATTRIBUTE_FILE_LOCATION_XML
+ ATTRIBUTE_XML(getDeclContext(), "context")
+ ATTRIBUTE_XML(getNameAsString(), "name")
+ TYPE_ATTRIBUTE_XML(getType()->getAs<FunctionType>()->getResultType())
+ ATTRIBUTE_XML(getType()->getAs<FunctionType>(), "function_type")
+ ATTRIBUTE_OPT_XML(isExplicit(), "is_explicit")
+ ATTRIBUTE_OPT_XML(isDefaultConstructor(), "is_default_ctor")
+ ATTRIBUTE_OPT_XML(isCopyConstructor(), "is_copy_ctor")
+ ATTRIBUTE_OPT_XML(isInlineSpecified(), "inline")
+ ATTRIBUTE_OPT_XML(isStatic(), "static")
+ ATTRIBUTE_OPT_XML(isVirtual(), "virtual")
+ ATTRIBUTE_ENUM_OPT_XML(getAccess(), "access")
+ ENUM_XML(AS_none, "")
+ ENUM_XML(AS_public, "public")
+ ENUM_XML(AS_protected, "protected")
+ ENUM_XML(AS_private, "private")
+ END_ENUM_XML
+ ATTRIBUTE_XML(getNumParams(), "num_args")
+ SUB_NODE_SEQUENCE_XML(ParmVarDecl)
+ SUB_NODE_FN_BODY_XML
+END_NODE_XML
+
+NODE_XML(CXXDestructorDecl, "CXXDestructor")
+ ID_ATTRIBUTE_XML
+ ATTRIBUTE_FILE_LOCATION_XML
+ ATTRIBUTE_XML(getDeclContext(), "context")
+ ATTRIBUTE_XML(getNameAsString(), "name")
+ TYPE_ATTRIBUTE_XML(getType()->getAs<FunctionType>()->getResultType())
+ ATTRIBUTE_XML(getType()->getAs<FunctionType>(), "function_type")
+ ATTRIBUTE_OPT_XML(isInlineSpecified(), "inline")
+ ATTRIBUTE_OPT_XML(isStatic(), "static")
+ ATTRIBUTE_OPT_XML(isVirtual(), "virtual")
+ ATTRIBUTE_ENUM_OPT_XML(getAccess(), "access")
+ ENUM_XML(AS_none, "")
+ ENUM_XML(AS_public, "public")
+ ENUM_XML(AS_protected, "protected")
+ ENUM_XML(AS_private, "private")
+ END_ENUM_XML
+ ATTRIBUTE_XML(getNumParams(), "num_args")
+ SUB_NODE_SEQUENCE_XML(ParmVarDecl)
+ SUB_NODE_FN_BODY_XML
+END_NODE_XML
+
+NODE_XML(CXXConversionDecl, "CXXConversion")
+ ID_ATTRIBUTE_XML
+ ATTRIBUTE_FILE_LOCATION_XML
+ ATTRIBUTE_XML(getDeclContext(), "context")
+ ATTRIBUTE_XML(getNameAsString(), "name")
+ TYPE_ATTRIBUTE_XML(getType()->getAs<FunctionType>()->getResultType())
+ ATTRIBUTE_XML(getType()->getAs<FunctionType>(), "function_type")
+ ATTRIBUTE_OPT_XML(isExplicit(), "is_explicit")
+ ATTRIBUTE_OPT_XML(isInlineSpecified(), "inline")
+ ATTRIBUTE_OPT_XML(isStatic(), "static")
+ ATTRIBUTE_OPT_XML(isVirtual(), "virtual")
+ ATTRIBUTE_ENUM_OPT_XML(getAccess(), "access")
+ ENUM_XML(AS_none, "")
+ ENUM_XML(AS_public, "public")
+ ENUM_XML(AS_protected, "protected")
+ ENUM_XML(AS_private, "private")
+ END_ENUM_XML
ATTRIBUTE_XML(getNumParams(), "num_args")
SUB_NODE_SEQUENCE_XML(ParmVarDecl)
SUB_NODE_FN_BODY_XML
@@ -126,6 +200,7 @@ NODE_XML(NamespaceDecl, "Namespace")
ATTRIBUTE_FILE_LOCATION_XML
ATTRIBUTE_XML(getDeclContext(), "context")
ATTRIBUTE_XML(getNameAsString(), "name")
+ SUB_NODE_SEQUENCE_XML(DeclContext)
END_NODE_XML
NODE_XML(UsingDirectiveDecl, "UsingDirective")
@@ -189,6 +264,12 @@ NODE_XML(FieldDecl, "Field")
ATTRIBUTE_XML(getNameAsString(), "name")
TYPE_ATTRIBUTE_XML(getType())
ATTRIBUTE_OPT_XML(isMutable(), "mutable")
+ ATTRIBUTE_ENUM_OPT_XML(getAccess(), "access")
+ ENUM_XML(AS_none, "")
+ ENUM_XML(AS_public, "public")
+ ENUM_XML(AS_protected, "protected")
+ ENUM_XML(AS_private, "private")
+ END_ENUM_XML
ATTRIBUTE_OPT_XML(isBitField(), "bitfield")
SUB_NODE_OPT_XML(Expr) // init expr of a bit field
END_NODE_XML
@@ -237,6 +318,35 @@ NODE_XML(LinkageSpecDecl, "LinkageSpec")
END_ENUM_XML
END_NODE_XML
+NODE_XML(TemplateDecl, "Template")
+ ID_ATTRIBUTE_XML
+ ATTRIBUTE_FILE_LOCATION_XML
+ ATTRIBUTE_XML(getDeclContext(), "context")
+ ATTRIBUTE_XML(getNameAsString(), "name")
+END_NODE_XML
+
+NODE_XML(TemplateTypeParmDecl, "TemplateTypeParm")
+ ID_ATTRIBUTE_XML
+ ATTRIBUTE_FILE_LOCATION_XML
+ ATTRIBUTE_XML(getDeclContext(), "context")
+ ATTRIBUTE_XML(getNameAsString(), "name")
+END_NODE_XML
+
+NODE_XML(UsingShadowDecl, "UsingShadow")
+ ID_ATTRIBUTE_XML
+ ATTRIBUTE_FILE_LOCATION_XML
+ ATTRIBUTE_XML(getDeclContext(), "context")
+ ATTRIBUTE_XML(getTargetDecl(), "target_decl")
+ ATTRIBUTE_XML(getUsingDecl(), "using_decl")
+END_NODE_XML
+
+NODE_XML(UsingDecl, "Using")
+ ID_ATTRIBUTE_XML
+ ATTRIBUTE_FILE_LOCATION_XML
+ ATTRIBUTE_XML(getDeclContext(), "context")
+ ATTRIBUTE_XML(getTargetNestedNameDecl(), "target_nested_namespace_decl")
+ ATTRIBUTE_XML(isTypeName(), "is_typename")
+END_NODE_XML
//===----------------------------------------------------------------------===//
#undef NODE_XML
diff --git a/include/clang/Frontend/DiagnosticOptions.h b/include/clang/Frontend/DiagnosticOptions.h
index b4f147bde7b7..8eb66e57da92 100644
--- a/include/clang/Frontend/DiagnosticOptions.h
+++ b/include/clang/Frontend/DiagnosticOptions.h
@@ -30,6 +30,8 @@ public:
unsigned ShowSourceRanges : 1; /// Show source ranges in numeric form.
unsigned ShowOptionNames : 1; /// Show the diagnostic name for mappable
/// diagnostics.
+ unsigned ShowCategories : 2; /// Show categories: 0 -> none, 1 -> Number,
+ /// 2 -> Full Name.
unsigned ShowColors : 1; /// Show diagnostics with ANSI color sequences.
unsigned VerifyDiagnostics: 1; /// Check that diagnostics match the expected
/// diagnostics, indicated by markers in the
@@ -74,12 +76,13 @@ public:
ShowFixits = 1;
ShowLocation = 1;
ShowOptionNames = 0;
+ ShowCategories = 0;
ShowSourceRanges = 0;
VerifyDiagnostics = 0;
BinaryOutput = 0;
ErrorLimit = 0;
- TemplateBacktraceLimit = 0;
- MacroBacktraceLimit = 0;
+ TemplateBacktraceLimit = DefaultTemplateBacktraceLimit;
+ MacroBacktraceLimit = DefaultMacroBacktraceLimit;
}
};
diff --git a/include/clang/Frontend/DocumentXML.h b/include/clang/Frontend/DocumentXML.h
index 6693ddbac57d..73d892105f21 100644
--- a/include/clang/Frontend/DocumentXML.h
+++ b/include/clang/Frontend/DocumentXML.h
@@ -114,6 +114,7 @@ private:
void addPtrAttribute(const char* pName, const NamedDecl* D);
void addPtrAttribute(const char* pName, const DeclContext* D);
void addPtrAttribute(const char* pName, const NamespaceDecl* D); // disambiguation
+ void addPtrAttribute(const char* pName, const NestedNameSpecifier* N);
void addPtrAttribute(const char* pName, const LabelStmt* L);
void addPtrAttribute(const char* pName, const char* text);
@@ -145,12 +146,23 @@ inline void DocumentXML::initialize(ASTContext &Context) {
//---------------------------------------------------------
template<class T>
inline void DocumentXML::addAttribute(const char* pName, const T& value) {
- Out << ' ' << pName << "=\"" << value << "\"";
+ std::string repr;
+ {
+ llvm::raw_string_ostream buf(repr);
+ buf << value;
+ buf.flush();
+ }
+
+ Out << ' ' << pName << "=\""
+ << DocumentXML::escapeString(repr.c_str(), repr.size())
+ << "\"";
}
//---------------------------------------------------------
inline void DocumentXML::addPtrAttribute(const char* pName, const char* text) {
- Out << ' ' << pName << "=\"" << text << "\"";
+ Out << ' ' << pName << "=\""
+ << DocumentXML::escapeString(text, strlen(text))
+ << "\"";
}
//---------------------------------------------------------
diff --git a/include/clang/Frontend/FrontendActions.h b/include/clang/Frontend/FrontendActions.h
index 3ddd77dc39e0..cee1c1d2be77 100644
--- a/include/clang/Frontend/FrontendActions.h
+++ b/include/clang/Frontend/FrontendActions.h
@@ -75,12 +75,10 @@ protected:
};
class FixItAction : public ASTFrontendAction {
-private:
+protected:
llvm::OwningPtr<FixItRewriter> Rewriter;
llvm::OwningPtr<FixItPathRewriter> PathRewriter;
-protected:
-
virtual ASTConsumer *CreateASTConsumer(CompilerInstance &CI,
llvm::StringRef InFile);
@@ -133,6 +131,12 @@ public:
virtual bool hasCodeCompletionSupport() const { return true; }
};
+class BoostConAction : public SyntaxOnlyAction {
+protected:
+ virtual ASTConsumer *CreateASTConsumer(CompilerInstance &CI,
+ llvm::StringRef InFile);
+};
+
/**
* \brief Frontend action adaptor that merges ASTs together.
*
diff --git a/include/clang/Frontend/FrontendOptions.h b/include/clang/Frontend/FrontendOptions.h
index 60512edd6c1f..c43e68000952 100644
--- a/include/clang/Frontend/FrontendOptions.h
+++ b/include/clang/Frontend/FrontendOptions.h
@@ -23,13 +23,15 @@ namespace frontend {
ASTPrint, ///< Parse ASTs and print them.
ASTPrintXML, ///< Parse ASTs and print them in XML.
ASTView, ///< Parse ASTs and view them in Graphviz.
+ BoostCon, ///< BoostCon mode.
DumpRawTokens, ///< Dump out raw tokens.
DumpTokens, ///< Dump out preprocessed tokens.
EmitAssembly, ///< Emit a .s file.
EmitBC, ///< Emit a .bc file.
EmitHTML, ///< Translate input source into HTML.
EmitLLVM, ///< Emit a .ll file.
- EmitLLVMOnly, ///< Generate LLVM IR, but do not
+ EmitLLVMOnly, ///< Generate LLVM IR, but do not emit anything.
+ EmitCodeGenOnly, ///< Generate machine code, but don't emit anything.
EmitObj, ///< Emit a .o file.
FixIt, ///< Parse and apply any fixits to the source.
GeneratePCH, ///< Generate pre-compiled header.
@@ -77,6 +79,8 @@ public:
unsigned ShowHelp : 1; ///< Show the -help text.
unsigned ShowMacrosInCodeCompletion : 1; ///< Show macros in code completion
/// results.
+ unsigned ShowCodePatternsInCodeCompletion : 1; ///< Show code patterns in code
+ /// completion results.
unsigned ShowStats : 1; ///< Show frontend performance
/// metrics and statistics.
unsigned ShowTimers : 1; ///< Show timers for individual
@@ -123,6 +127,7 @@ public:
RelocatablePCH = 0;
ShowHelp = 0;
ShowMacrosInCodeCompletion = 0;
+ ShowCodePatternsInCodeCompletion = 0;
ShowStats = 0;
ShowTimers = 0;
ShowVersion = 0;
diff --git a/include/clang/Frontend/PCHBitCodes.h b/include/clang/Frontend/PCHBitCodes.h
index 1640afb4122a..2493cfd47d1e 100644
--- a/include/clang/Frontend/PCHBitCodes.h
+++ b/include/clang/Frontend/PCHBitCodes.h
@@ -415,7 +415,9 @@ namespace clang {
/// \brief An UnresolvedUsingType record.
TYPE_UNRESOLVED_USING = 26,
/// \brief An InjectedClassNameType record.
- TYPE_INJECTED_CLASS_NAME = 27
+ TYPE_INJECTED_CLASS_NAME = 27,
+ /// \brief An ObjCObjectType record.
+ TYPE_OBJC_OBJECT = 28
};
/// \brief The type IDs for special types constructed by semantic
@@ -534,8 +536,46 @@ namespace clang {
/// IDs. This data is used when performing qualified name lookup
/// into a DeclContext via DeclContext::lookup.
DECL_CONTEXT_VISIBLE,
- /// \brief A NamespaceDecl record.
- DECL_NAMESPACE
+ /// \brief A NamespaceDecl rcord.
+ DECL_NAMESPACE,
+ /// \brief A NamespaceAliasDecl record.
+ DECL_NAMESPACE_ALIAS,
+ /// \brief A UsingDecl record.
+ DECL_USING,
+ /// \brief A UsingShadowDecl record.
+ DECL_USING_SHADOW,
+ /// \brief A UsingDirecitveDecl record.
+ DECL_USING_DIRECTIVE,
+ /// \brief An UnresolvedUsingValueDecl record.
+ DECL_UNRESOLVED_USING_VALUE,
+ /// \brief An UnresolvedUsingTypenameDecl record.
+ DECL_UNRESOLVED_USING_TYPENAME,
+ /// \brief A LinkageSpecDecl record.
+ DECL_LINKAGE_SPEC,
+ /// \brief A CXXRecordDecl record.
+ DECL_CXX_RECORD,
+ /// \brief A CXXMethodDecl record.
+ DECL_CXX_METHOD,
+ /// \brief A CXXConstructorDecl record.
+ DECL_CXX_CONSTRUCTOR,
+ /// \brief A CXXDestructorDecl record.
+ DECL_CXX_DESTRUCTOR,
+ /// \brief A CXXConversionDecl record.
+ DECL_CXX_CONVERSION,
+
+ // FIXME: Implement serialization for these decl types. This just
+ // allocates the order in which
+ DECL_FRIEND,
+ DECL_FRIEND_TEMPLATE,
+ DECL_TEMPLATE,
+ DECL_CLASS_TEMPLATE,
+ DECL_CLASS_TEMPLATE_SPECIALIZATION,
+ DECL_CLASS_TEMPLATE_PARTIAL_SPECIALIZATION,
+ DECL_FUNCTION_TEMPLATE,
+ DECL_TEMPLATE_TYPE_PARM,
+ DECL_NON_TYPE_TEMPLATE_PARM,
+ DECL_TEMPLATE_TEMPLATE_PARM,
+ DECL_STATIC_ASSERT
};
/// \brief Record codes for each kind of statement or expression.
@@ -692,6 +732,8 @@ namespace clang {
/// \brief A CXXOperatorCallExpr record.
EXPR_CXX_OPERATOR_CALL,
+ /// \brief A CXXMemberCallExpr record.
+ EXPR_CXX_MEMBER_CALL,
/// \brief A CXXConstructExpr record.
EXPR_CXX_CONSTRUCT,
// \brief A CXXStaticCastExpr record.
@@ -706,8 +748,18 @@ namespace clang {
EXPR_CXX_FUNCTIONAL_CAST,
// \brief A CXXBoolLiteralExpr record.
EXPR_CXX_BOOL_LITERAL,
- // \brief A CXXNullPtrLiteralExpr record.
- EXPR_CXX_NULL_PTR_LITERAL
+ EXPR_CXX_NULL_PTR_LITERAL, // CXXNullPtrLiteralExpr
+ EXPR_CXX_TYPEID_EXPR, // CXXTypeidExpr (of expr).
+ EXPR_CXX_TYPEID_TYPE, // CXXTypeidExpr (of type).
+ EXPR_CXX_THIS, // CXXThisExpr
+ EXPR_CXX_THROW, // CXXThrowExpr
+ EXPR_CXX_DEFAULT_ARG, // CXXDefaultArgExpr
+ EXPR_CXX_BIND_TEMPORARY, // CXXBindTemporaryExpr
+ //
+ EXPR_CXX_ZERO_INIT_VALUE, // CXXZeroInitValueExpr
+ EXPR_CXX_NEW, // CXXNewExpr
+
+ EXPR_CXX_EXPR_WITH_TEMPORARIES // CXXExprWithTemporaries
};
/// \brief The kinds of designators that can occur in a
diff --git a/include/clang/Frontend/PCHReader.h b/include/clang/Frontend/PCHReader.h
index c2352301caa0..e144738236ea 100644
--- a/include/clang/Frontend/PCHReader.h
+++ b/include/clang/Frontend/PCHReader.h
@@ -52,6 +52,9 @@ class ASTContext;
class Attr;
class Decl;
class DeclContext;
+class NestedNameSpecifier;
+class CXXBaseSpecifier;
+class CXXBaseOrMemberInitializer;
class GotoStmt;
class LabelStmt;
class MacroDefinition;
@@ -649,8 +652,8 @@ public:
/// declarations with this name are visible from translation unit scope, their
/// declarations will be deserialized and introduced into the declaration
/// chain of the identifier.
- virtual IdentifierInfo* get(const char *NameStart, const char *NameEnd);
- IdentifierInfo* get(llvm::StringRef Name) {
+ virtual IdentifierInfo *get(const char *NameStart, const char *NameEnd);
+ IdentifierInfo *get(llvm::StringRef Name) {
return get(Name.begin(), Name.end());
}
@@ -694,8 +697,21 @@ public:
Selector GetSelector(const RecordData &Record, unsigned &Idx) {
return DecodeSelector(Record[Idx++]);
}
+
+ /// \brief Read a declaration name.
DeclarationName ReadDeclarationName(const RecordData &Record, unsigned &Idx);
+ NestedNameSpecifier *ReadNestedNameSpecifier(const RecordData &Record,
+ unsigned &Idx);
+
+ /// \brief Read a source location.
+ SourceLocation ReadSourceLocation(const RecordData &Record, unsigned& Idx) {
+ return SourceLocation::getFromRawEncoding(Record[Idx++]);
+ }
+
+ /// \brief Read a source range.
+ SourceRange ReadSourceRange(const RecordData &Record, unsigned& Idx);
+
/// \brief Read an integral value
llvm::APInt ReadAPInt(const RecordData &Record, unsigned &Idx);
@@ -708,6 +724,8 @@ public:
// \brief Read a string
std::string ReadString(const RecordData &Record, unsigned &Idx);
+ CXXTemporary *ReadCXXTemporary(const RecordData &Record, unsigned &Idx);
+
/// \brief Reads attributes from the current stream position.
Attr *ReadAttributes();
diff --git a/include/clang/Frontend/PCHWriter.h b/include/clang/Frontend/PCHWriter.h
index e006de524ca3..85f53b9e0302 100644
--- a/include/clang/Frontend/PCHWriter.h
+++ b/include/clang/Frontend/PCHWriter.h
@@ -32,6 +32,9 @@ namespace llvm {
namespace clang {
class ASTContext;
+class NestedNameSpecifier;
+class CXXBaseSpecifier;
+class CXXBaseOrMemberInitializer;
class LabelStmt;
class MacroDefinition;
class MemorizeStatCalls;
@@ -251,6 +254,9 @@ public:
/// \brief Emit a source location.
void AddSourceLocation(SourceLocation Loc, RecordData &Record);
+ /// \brief Emit a source range.
+ void AddSourceRange(SourceRange Range, RecordData &Record);
+
/// \brief Emit an integral value.
void AddAPInt(const llvm::APInt &Value, RecordData &Record);
@@ -260,12 +266,15 @@ public:
/// \brief Emit a floating-point value.
void AddAPFloat(const llvm::APFloat &Value, RecordData &Record);
- /// \brief Emit a reference to an identifier
+ /// \brief Emit a reference to an identifier.
void AddIdentifierRef(const IdentifierInfo *II, RecordData &Record);
- /// \brief Emit a Selector (which is a smart pointer reference)
- void AddSelectorRef(const Selector, RecordData &Record);
+ /// \brief Emit a Selector (which is a smart pointer reference).
+ void AddSelectorRef(Selector, RecordData &Record);
+ /// \brief Emit a CXXTemporary.
+ void AddCXXTemporary(const CXXTemporary *Temp, RecordData &Record);
+
/// \brief Get the unique number used to refer to the given
/// identifier.
pch::IdentID getIdentifierRef(const IdentifierInfo *II);
@@ -304,6 +313,9 @@ public:
/// \brief Emit a declaration name.
void AddDeclarationName(DeclarationName Name, RecordData &Record);
+ /// \brief Emit a nested name specifier.
+ void AddNestedNameSpecifier(NestedNameSpecifier *NNS, RecordData &Record);
+
/// \brief Add a string to the given record.
void AddString(const std::string &Str, RecordData &Record);
diff --git a/include/clang/Frontend/TypeXML.def b/include/clang/Frontend/TypeXML.def
index 3add99a941c4..069d718d9def 100644
--- a/include/clang/Frontend/TypeXML.def
+++ b/include/clang/Frontend/TypeXML.def
@@ -61,6 +61,10 @@
# define CONTEXT_ATTRIBUTE_XML( FN ) ATTRIBUTE_XML(FN, "context")
#endif
+NODE_XML(Type, "FIXME_Type")
+ ID_ATTRIBUTE_XML
+ ATTRIBUTE_XML(getTypeClassName(), "unhandled_type_name")
+END_NODE_XML
NODE_XML(QualType, "CvQualifiedType")
ID_ATTRIBUTE_XML
@@ -207,9 +211,9 @@ NODE_XML(RecordType, "Record")
ID_ATTRIBUTE_XML
ATTRIBUTE_XML(getDecl()->getNameAsString(), "name") // string
ATTRIBUTE_ENUM_XML(getDecl()->getTagKind(), "kind")
- ENUM_XML(TagDecl::TK_struct, "struct")
- ENUM_XML(TagDecl::TK_union, "union")
- ENUM_XML(TagDecl::TK_class, "class")
+ ENUM_XML(TTK_Struct, "struct")
+ ENUM_XML(TTK_Union, "union")
+ ENUM_XML(TTK_Class, "class")
END_ENUM_XML
CONTEXT_ATTRIBUTE_XML(getDecl()->getDeclContext())
END_NODE_XML
@@ -228,11 +232,23 @@ NODE_XML(TemplateSpecializationType, "TemplateSpecializationType")
ID_ATTRIBUTE_XML
END_NODE_XML
-NODE_XML(QualifiedNameType, "QualifiedNameType")
+NODE_XML(ElaboratedType, "ElaboratedType")
ID_ATTRIBUTE_XML
+ ATTRIBUTE_ENUM_XML(getKeyword(), "keyword")
+ ENUM_XML(ETK_None, "none")
+ ENUM_XML(ETK_Typename, "typename")
+ ENUM_XML(ETK_Struct, "struct")
+ ENUM_XML(ETK_Union, "union")
+ ENUM_XML(ETK_Class, "class")
+ ENUM_XML(ETK_Enum, "enum")
+ END_ENUM_XML
TYPE_ATTRIBUTE_XML(getNamedType())
END_NODE_XML
+NODE_XML(InjectedClassNameType, "InjectedClassNameType")
+ ID_ATTRIBUTE_XML
+END_NODE_XML
+
NODE_XML(DependentNameType, "DependentNameType")
ID_ATTRIBUTE_XML
END_NODE_XML
@@ -245,6 +261,29 @@ NODE_XML(ObjCObjectPointerType, "ObjCObjectPointerType")
ID_ATTRIBUTE_XML
END_NODE_XML
+NODE_XML(SubstTemplateTypeParmType, "SubstTemplateTypeParm")
+ ID_ATTRIBUTE_XML
+END_NODE_XML
+
+NODE_XML(DependentSizedExtVectorType, "DependentSizedExtVector")
+ ID_ATTRIBUTE_XML
+END_NODE_XML
+
+NODE_XML(UnresolvedUsingType, "UnresolvedUsing")
+ ID_ATTRIBUTE_XML
+END_NODE_XML
+
+NODE_XML(DependentTypeOfExprType, "DependentTypeOfExpr")
+ ID_ATTRIBUTE_XML
+END_NODE_XML
+
+NODE_XML(DecltypeType, "Decltype")
+ ID_ATTRIBUTE_XML
+END_NODE_XML
+
+NODE_XML(DependentDecltypeType, "DependentDecltype")
+ ID_ATTRIBUTE_XML
+END_NODE_XML
//===----------------------------------------------------------------------===//
#undef NODE_XML
diff --git a/include/clang/Lex/LiteralSupport.h b/include/clang/Lex/LiteralSupport.h
index 2334d728f6e3..ba46fb18a68a 100644
--- a/include/clang/Lex/LiteralSupport.h
+++ b/include/clang/Lex/LiteralSupport.h
@@ -147,7 +147,7 @@ class StringLiteralParser {
char *ResultPtr; // cursor
public:
StringLiteralParser(const Token *StringToks, unsigned NumStringToks,
- Preprocessor &PP);
+ Preprocessor &PP, bool Complain = true);
bool hadError;
bool AnyWide;
bool Pascal;
@@ -164,7 +164,7 @@ public:
/// specified byte of the string data represented by Token. This handles
/// advancing over escape sequences in the string.
static unsigned getOffsetOfStringByte(const Token &TheTok, unsigned ByteNo,
- Preprocessor &PP);
+ Preprocessor &PP, bool Complain = true);
};
} // end namespace clang
diff --git a/include/clang/Lex/Preprocessor.h b/include/clang/Lex/Preprocessor.h
index 20d9fc50e49f..f01b3afc45f5 100644
--- a/include/clang/Lex/Preprocessor.h
+++ b/include/clang/Lex/Preprocessor.h
@@ -290,8 +290,8 @@ public:
/// expansions going on at the time.
PreprocessorLexer *getCurrentLexer() const { return CurPPLexer; }
- /// getCurrentFileLexer - Return the current file lexer being lexed from. Note
- /// that this ignores any potentially active macro expansions and _Pragma
+ /// getCurrentFileLexer - Return the current file lexer being lexed from.
+ /// Note that this ignores any potentially active macro expansions and _Pragma
/// expansions going on at the time.
PreprocessorLexer *getCurrentFileLexer() const;
@@ -753,9 +753,9 @@ public:
/// #include FOO
/// because in this case, "<a/b.h>" is returned as 7 tokens, not one.
///
- /// This code concatenates and consumes tokens up to the '>' token. It returns
- /// false if the > was found, otherwise it returns true if it finds and consumes
- /// the EOM marker.
+ /// This code concatenates and consumes tokens up to the '>' token. It
+ /// returns false if the > was found, otherwise it returns true if it finds
+ /// and consumes the EOM marker.
bool ConcatenateIncludeName(llvm::SmallString<128> &FilenameBuffer);
private:
@@ -900,8 +900,6 @@ private:
// Macro handling.
void HandleDefineDirective(Token &Tok);
void HandleUndefDirective(Token &Tok);
- // HandleAssertDirective(Token &Tok);
- // HandleUnassertDirective(Token &Tok);
// Conditional Inclusion.
void HandleIfdefDirective(Token &Tok, bool isIfndef,
diff --git a/include/clang/Makefile b/include/clang/Makefile
index d76e0a9c63ba..6abe375d5e97 100644
--- a/include/clang/Makefile
+++ b/include/clang/Makefile
@@ -1,5 +1,5 @@
LEVEL = ../../../..
-DIRS := Basic Driver
+DIRS := AST Basic Driver
include $(LEVEL)/Makefile.common
@@ -10,7 +10,7 @@ install-local::
cd $(PROJ_SRC_ROOT)/tools/clang/include && \
for hdr in `find clang -type f '!' '(' -name '*~' \
-o -name '.#*' -o -name '*.in' -o -name '*.txt' \
- -o -name 'Makefile' -o -name '*.td' ')' -print \
+ -o -name 'Makefile' -o -name '*.td' -o -name '*.orig' ')' -print \
| grep -v CVS | grep -v .svn | grep -v .dir` ; do \
instdir=$(DESTDIR)`dirname "$(PROJ_includedir)/$$hdr"` ; \
if test \! -d "$$instdir" ; then \
diff --git a/include/clang/Parse/Action.h b/include/clang/Parse/Action.h
index 3d68d80ef9f0..e21da81a8aa8 100644
--- a/include/clang/Parse/Action.h
+++ b/include/clang/Parse/Action.h
@@ -105,12 +105,19 @@ public:
class FullExprArg {
public:
+ FullExprArg(ActionBase &actions) : Expr(actions) { }
+
// FIXME: The const_cast here is ugly. RValue references would make this
// much nicer (or we could duplicate a bunch of the move semantics
// emulation code from Ownership.h).
FullExprArg(const FullExprArg& Other)
: Expr(move(const_cast<FullExprArg&>(Other).Expr)) {}
+ FullExprArg &operator=(const FullExprArg& Other) {
+ Expr.operator=(move(const_cast<FullExprArg&>(Other).Expr));
+ return *this;
+ }
+
OwningExprResult release() {
return move(Expr);
}
@@ -279,13 +286,18 @@ public:
/// \param Template if the name does refer to a template, the declaration
/// of the template that the name refers to.
///
+ /// \param MemberOfUnknownSpecialization Will be set true if the resulting
+ /// member would be a member of an unknown specialization, in which case this
+ /// lookup cannot possibly pass at this time.
+ ///
/// \returns the kind of template that this name refers to.
virtual TemplateNameKind isTemplateName(Scope *S,
CXXScopeSpec &SS,
UnqualifiedId &Name,
TypeTy *ObjectType,
bool EnteringContext,
- TemplateTy &Template) = 0;
+ TemplateTy &Template,
+ bool &MemberOfUnknownSpecialization) = 0;
/// \brief Action called as part of error recovery when the parser has
/// determined that the given name must refer to a template, but
@@ -566,7 +578,9 @@ public:
/// ParsedFreeStandingDeclSpec - This method is invoked when a declspec with
/// no declarator (e.g. "struct foo;") is parsed.
- virtual DeclPtrTy ParsedFreeStandingDeclSpec(Scope *S, DeclSpec &DS) {
+ virtual DeclPtrTy ParsedFreeStandingDeclSpec(Scope *S,
+ AccessSpecifier Access,
+ DeclSpec &DS) {
return DeclPtrTy();
}
@@ -826,21 +840,19 @@ public:
/// \brief Parsed the start of a "switch" statement.
///
+ /// \param SwitchLoc The location of the "switch" keyword.
+ ///
/// \param Cond if the "switch" condition was parsed as an expression,
/// the expression itself.
///
/// \param CondVar if the "switch" condition was parsed as a condition
/// variable, the condition variable itself.
- virtual OwningStmtResult ActOnStartOfSwitchStmt(FullExprArg Cond,
+ virtual OwningStmtResult ActOnStartOfSwitchStmt(SourceLocation SwitchLoc,
+ ExprArg Cond,
DeclPtrTy CondVar) {
return StmtEmpty();
}
- /// ActOnSwitchBodyError - This is called if there is an error parsing the
- /// body of the switch stmt instead of ActOnFinishSwitchStmt.
- virtual void ActOnSwitchBodyError(SourceLocation SwitchLoc, StmtArg Switch,
- StmtArg Body) {}
-
virtual OwningStmtResult ActOnFinishSwitchStmt(SourceLocation SwitchLoc,
StmtArg Switch, StmtArg Body) {
return StmtEmpty();
@@ -1609,6 +1621,22 @@ public:
return DeclResult();
}
+ /// \brief Parsed an expression that will be handled as the condition in
+ /// an if/while/for statement.
+ ///
+ /// This routine handles the conversion of the expression to 'bool'.
+ ///
+ /// \param S The scope in which the expression occurs.
+ ///
+ /// \param Loc The location of the construct that requires the conversion to
+ /// a boolean value.
+ ///
+ /// \param SubExpr The expression that is being converted to bool.
+ virtual OwningExprResult ActOnBooleanCondition(Scope *S, SourceLocation Loc,
+ ExprArg SubExpr) {
+ return move(SubExpr);
+ }
+
/// ActOnCXXNew - Parsed a C++ 'new' expression. UseGlobal is true if the
/// new was qualified (::new). In a full new like
/// @code new (p1, p2) type(c1, c2) @endcode
@@ -2303,6 +2331,7 @@ public:
}
// ActOnPropertyImplDecl - called for every property implementation
virtual DeclPtrTy ActOnPropertyImplDecl(
+ Scope *S,
SourceLocation AtLoc, // location of the @synthesize/@dynamic
SourceLocation PropertyNameLoc, // location for the property name
bool ImplKind, // true for @synthesize, false for
@@ -2346,7 +2375,7 @@ public:
// protocols, categories), the parser passes all methods/properties.
// For class implementations, these values default to 0. For implementations,
// methods are processed incrementally (by ActOnMethodDeclaration above).
- virtual void ActOnAtEnd(SourceRange AtEnd,
+ virtual void ActOnAtEnd(Scope *S, SourceRange AtEnd,
DeclPtrTy classDecl,
DeclPtrTy *allMethods = 0,
unsigned allNum = 0,
@@ -2535,6 +2564,21 @@ public:
//===---------------------------- Pragmas -------------------------------===//
+ enum PragmaOptionsAlignKind {
+ POAK_Natural, // #pragma options align=natural
+ POAK_Power, // #pragma options align=power
+ POAK_Mac68k, // #pragma options align=mac68k
+ POAK_Reset // #pragma options align=reset
+ };
+
+ /// ActOnPragmaOptionsAlign - Called on well formed #pragma options
+ /// align={...}.
+ virtual void ActOnPragmaOptionsAlign(PragmaOptionsAlignKind Kind,
+ SourceLocation PragmaLoc,
+ SourceLocation KindLoc) {
+ return;
+ }
+
enum PragmaPackKind {
PPK_Default, // #pragma pack([n])
PPK_Show, // #pragma pack(show), only supported by MSVC.
@@ -2620,9 +2664,13 @@ public:
/// \brief Code completion occurs at the beginning of the
/// initialization statement (or expression) in a for loop.
CCC_ForInit,
- /// \brief Code completion ocurs within the condition of an if,
+ /// \brief Code completion occurs within the condition of an if,
/// while, switch, or for statement.
- CCC_Condition
+ CCC_Condition,
+ /// \brief Code completion occurs within the body of a function on a
+ /// recovery path, where we do not have a specific handle on our position
+ /// in the grammar.
+ CCC_RecoveryInFunction
};
/// \brief Code completion for an ordinary name that occurs within the given
@@ -3003,7 +3051,9 @@ public:
UnqualifiedId &Name,
TypeTy *ObjectType,
bool EnteringContext,
- TemplateTy &Template);
+ TemplateTy &Template,
+ bool &MemberOfUnknownSpecialization);
+
/// ActOnDeclarator - If this is a typedef declarator, we modify the
/// IdentifierInfo::FETokenInfo field to keep track of this fact, until S is
diff --git a/include/clang/Parse/AttributeList.h b/include/clang/Parse/AttributeList.h
index 12512f33c761..1e6d3ab9760d 100644
--- a/include/clang/Parse/AttributeList.h
+++ b/include/clang/Parse/AttributeList.h
@@ -55,6 +55,7 @@ public:
enum Kind { // Please keep this list alphabetized.
AT_IBAction, // Clang-specific.
AT_IBOutlet, // Clang-specific.
+ AT_IBOutletCollection, // Clang-specific.
AT_address_space,
AT_alias,
AT_aligned,
@@ -102,6 +103,7 @@ public:
AT_section,
AT_sentinel,
AT_stdcall,
+ AT_thiscall,
AT_transparent_union,
AT_unavailable,
AT_unused,
diff --git a/include/clang/Parse/Ownership.h b/include/clang/Parse/Ownership.h
index 5eb9635f06a1..e9a20b7872b5 100644
--- a/include/clang/Parse/Ownership.h
+++ b/include/clang/Parse/Ownership.h
@@ -166,7 +166,7 @@ namespace llvm {
// conversions.
// Flip this switch to measure performance impact of the smart pointers.
-//#define DISABLE_SMART_POINTERS
+// #define DISABLE_SMART_POINTERS
namespace llvm {
template<>
@@ -403,8 +403,10 @@ namespace clang {
friend class moving::ASTResultMover<Destroyer>;
+#if !(defined(_MSC_VER) && _MSC_VER >= 1600)
ASTOwningResult(ASTOwningResult&); // DO NOT IMPLEMENT
ASTOwningResult& operator =(ASTOwningResult&); // DO NOT IMPLEMENT
+#endif
void destroy() {
if (Ptr) {
@@ -444,6 +446,19 @@ namespace clang {
return *this;
}
+#if defined(_MSC_VER) && _MSC_VER >= 1600
+ // Emulated move semantics don't work with msvc.
+ ASTOwningResult(ASTOwningResult &&mover)
+ : ActionInv(mover.ActionInv),
+ Ptr(mover.Ptr) {
+ mover.Ptr = 0;
+ }
+ ASTOwningResult &operator=(ASTOwningResult &&mover) {
+ *this = moving::ASTResultMover<Destroyer>(mover);
+ return *this;
+ }
+#endif
+
/// Assignment from a raw pointer. Takes ownership - beware!
ASTOwningResult &operator=(void *raw) {
destroy();
diff --git a/include/clang/Parse/Parser.h b/include/clang/Parse/Parser.h
index 42a41d6d3028..8081c2492b2f 100644
--- a/include/clang/Parse/Parser.h
+++ b/include/clang/Parse/Parser.h
@@ -110,6 +110,7 @@ class Parser {
IdentifierInfo *Ident_vector;
IdentifierInfo *Ident_pixel;
+ llvm::OwningPtr<PragmaHandler> OptionsHandler;
llvm::OwningPtr<PragmaHandler> PackHandler;
llvm::OwningPtr<PragmaHandler> UnusedHandler;
llvm::OwningPtr<PragmaHandler> WeakHandler;
@@ -234,6 +235,11 @@ private:
assert(!isTokenStringLiteral() && !isTokenParen() && !isTokenBracket() &&
!isTokenBrace() &&
"Should consume special tokens with Consume*Token");
+ if (Tok.is(tok::code_completion)) {
+ CodeCompletionRecovery();
+ return ConsumeCodeCompletionToken();
+ }
+
PrevTokLocation = Tok.getLocation();
PP.Lex(Tok);
return PrevTokLocation;
@@ -308,6 +314,22 @@ private:
return PrevTokLocation;
}
+ /// \brief Consume the current code-completion token.
+ ///
+ /// This routine should be called to consume the code-completion token once
+ /// a code-completion action has already been invoked.
+ SourceLocation ConsumeCodeCompletionToken() {
+ assert(Tok.is(tok::code_completion));
+ PrevTokLocation = Tok.getLocation();
+ PP.Lex(Tok);
+ return PrevTokLocation;
+ }
+
+ ///\ brief When we are consuming a code-completion token within having
+ /// matched specific position in the grammar, provide code-completion results
+ /// based on context.
+ void CodeCompletionRecovery();
+
/// GetLookAheadToken - This peeks ahead N tokens and returns that token
/// without consuming any tokens. LookAhead(0) returns 'Tok', LookAhead(1)
/// returns the token after Tok, etc.
@@ -1004,7 +1026,8 @@ private:
//===--------------------------------------------------------------------===//
// C++ if/switch/while condition expression.
- bool ParseCXXCondition(OwningExprResult &ExprResult, DeclPtrTy &DeclResult);
+ bool ParseCXXCondition(OwningExprResult &ExprResult, DeclPtrTy &DeclResult,
+ SourceLocation Loc, bool ConvertToBoolean);
//===--------------------------------------------------------------------===//
// C++ types
@@ -1060,7 +1083,9 @@ private:
bool isStmtExpr = false);
OwningStmtResult ParseCompoundStatementBody(bool isStmtExpr = false);
bool ParseParenExprOrCondition(OwningExprResult &ExprResult,
- DeclPtrTy &DeclResult);
+ DeclPtrTy &DeclResult,
+ SourceLocation Loc,
+ bool ConvertToBoolean);
OwningStmtResult ParseIfStatement(AttributeList *Attr);
OwningStmtResult ParseSwitchStatement(AttributeList *Attr);
OwningStmtResult ParseWhileStatement(AttributeList *Attr);
@@ -1348,6 +1373,8 @@ private:
AttributeList *AttrList = 0,
bool RequiresArg = false);
void ParseFunctionDeclaratorIdentifierList(SourceLocation LParenLoc,
+ IdentifierInfo *FirstIdent,
+ SourceLocation FirstIdentLoc,
Declarator &D);
void ParseBracketDeclarator(Declarator &D);
@@ -1403,7 +1430,8 @@ private:
bool EnteringContext,
TypeTy *ObjectType,
UnqualifiedId &Id,
- bool AssumeTemplateId = false);
+ bool AssumeTemplateId,
+ SourceLocation TemplateKWLoc);
bool ParseUnqualifiedIdOperator(CXXScopeSpec &SS, bool EnteringContext,
TypeTy *ObjectType,
UnqualifiedId &Result);
@@ -1457,6 +1485,7 @@ private:
SourceLocation TemplateKWLoc = SourceLocation(),
bool AllowTypeAnnotation = true);
void AnnotateTemplateIdTokenAsType(const CXXScopeSpec *SS = 0);
+ bool IsTemplateArgumentList(unsigned Skip = 0);
bool ParseTemplateArgumentList(TemplateArgList &TemplateArgs);
ParsedTemplateArgument ParseTemplateTemplateArgument();
ParsedTemplateArgument ParseTemplateArgument();
diff --git a/include/clang/Parse/Scope.h b/include/clang/Parse/Scope.h
index d7a0e3583ca5..023f40d3957c 100644
--- a/include/clang/Parse/Scope.h
+++ b/include/clang/Parse/Scope.h
@@ -74,7 +74,7 @@ public:
/// It always has FnScope and DeclScope set as well.
ObjCMethodScope = 0x400,
- /// ElseScope - This scoep corresponds to an 'else' scope of an if/then/else
+ /// ElseScope - This scope corresponds to an 'else' scope of an if/then/else
/// statement.
ElseScope = 0x800
};
diff --git a/include/clang/Sema/CodeCompleteConsumer.h b/include/clang/Sema/CodeCompleteConsumer.h
index 348917a7d034..1f1c0cc11325 100644
--- a/include/clang/Sema/CodeCompleteConsumer.h
+++ b/include/clang/Sema/CodeCompleteConsumer.h
@@ -24,6 +24,41 @@ class raw_ostream;
namespace clang {
+/// \brief Default priority values for code-completion results based
+/// on their kind.
+enum {
+ /// \brief Priority for a declaration that is in the local scope.
+ CCP_LocalDeclaration = 8,
+ /// \brief Priority for a member declaration found from the current
+ /// method or member function.
+ CCP_MemberDeclaration = 20,
+ /// \brief Priority for a language keyword (that isn't any of the other
+ /// categories).
+ CCP_Keyword = 30,
+ /// \brief Priority for a code pattern.
+ CCP_CodePattern = 30,
+ /// \brief Priority for a type.
+ CCP_Type = 40,
+ /// \brief Priority for a non-type declaration.
+ CCP_Declaration = 50,
+ /// \brief Priority for a constant value (e.g., enumerator).
+ CCP_Constant = 60,
+ /// \brief Priority for a preprocessor macro.
+ CCP_Macro = 70,
+ /// \brief Priority for a nested-name-specifier.
+ CCP_NestedNameSpecifier = 75,
+ /// \brief Priority for a result that isn't likely to be what the user wants,
+ /// but is included for completeness.
+ CCP_Unlikely = 80
+};
+
+/// \brief Priority value deltas that are applied to code-completion results
+/// based on the context of the result.
+enum {
+ /// \brief The result is in a base class.
+ CCD_InBaseClass = 2
+};
+
class FunctionDecl;
class FunctionType;
class FunctionTemplateDecl;
@@ -156,13 +191,14 @@ private:
public:
CodeCompletionString() { }
- ~CodeCompletionString();
+ ~CodeCompletionString() { clear(); }
typedef llvm::SmallVector<Chunk, 4>::const_iterator iterator;
iterator begin() const { return Chunks.begin(); }
iterator end() const { return Chunks.end(); }
bool empty() const { return Chunks.empty(); }
unsigned size() const { return Chunks.size(); }
+ void clear();
Chunk &operator[](unsigned I) {
assert(I < size() && "Chunk index out-of-range");
@@ -232,8 +268,9 @@ public:
void Serialize(llvm::raw_ostream &OS) const;
/// \brief Deserialize a code-completion string from the given string.
- static CodeCompletionString *Deserialize(const char *&Str,
- const char *StrEnd);
+ ///
+ /// \returns true if successful, false otherwise.
+ bool Deserialize(const char *&Str, const char *StrEnd);
};
llvm::raw_ostream &operator<<(llvm::raw_ostream &OS,
@@ -246,6 +283,10 @@ protected:
/// \brief Whether to include macros in the code-completion results.
bool IncludeMacros;
+ /// \brief Whether to include code patterns (such as for loops) within
+ /// the completion results.
+ bool IncludeCodePatterns;
+
/// \brief Whether the output format for the code-completion consumer is
/// binary.
bool OutputIsBinary;
@@ -280,8 +321,11 @@ public:
/// \brief When Kind == RK_Macro, the identifier that refers to a macro.
IdentifierInfo *Macro;
};
-
- /// \brief Specifiers which parameter (of a function, Objective-C method,
+
+ /// \brief The priority of this particular code-completion result.
+ unsigned Priority;
+
+ /// \brief Specifies which parameter (of a function, Objective-C method,
/// macro, etc.) we should start with when formatting the result.
unsigned StartParameter;
@@ -309,29 +353,30 @@ public:
NestedNameSpecifier *Qualifier = 0,
bool QualifierIsInformative = false)
: Kind(RK_Declaration), Declaration(Declaration),
- StartParameter(0), Hidden(false),
- QualifierIsInformative(QualifierIsInformative),
+ Priority(getPriorityFromDecl(Declaration)), StartParameter(0),
+ Hidden(false), QualifierIsInformative(QualifierIsInformative),
StartsNestedNameSpecifier(false), AllParametersAreInformative(false),
- Qualifier(Qualifier) { }
+ Qualifier(Qualifier) {
+ }
/// \brief Build a result that refers to a keyword or symbol.
- Result(const char *Keyword)
- : Kind(RK_Keyword), Keyword(Keyword), StartParameter(0),
- Hidden(false), QualifierIsInformative(0),
+ Result(const char *Keyword, unsigned Priority = CCP_Keyword)
+ : Kind(RK_Keyword), Keyword(Keyword), Priority(Priority),
+ StartParameter(0), Hidden(false), QualifierIsInformative(0),
StartsNestedNameSpecifier(false), AllParametersAreInformative(false),
Qualifier(0) { }
/// \brief Build a result that refers to a macro.
- Result(IdentifierInfo *Macro)
- : Kind(RK_Macro), Macro(Macro), StartParameter(0),
+ Result(IdentifierInfo *Macro, unsigned Priority = CCP_Macro)
+ : Kind(RK_Macro), Macro(Macro), Priority(Priority), StartParameter(0),
Hidden(false), QualifierIsInformative(0),
StartsNestedNameSpecifier(false), AllParametersAreInformative(false),
Qualifier(0) { }
/// \brief Build a result that refers to a pattern.
- Result(CodeCompletionString *Pattern)
- : Kind(RK_Pattern), Pattern(Pattern), StartParameter(0),
- Hidden(false), QualifierIsInformative(0),
+ Result(CodeCompletionString *Pattern, unsigned Priority = CCP_CodePattern)
+ : Kind(RK_Pattern), Pattern(Pattern), Priority(Priority),
+ StartParameter(0), Hidden(false), QualifierIsInformative(0),
StartsNestedNameSpecifier(false), AllParametersAreInformative(false),
Qualifier(0) { }
@@ -352,6 +397,9 @@ public:
CodeCompletionString *CreateCodeCompletionString(Sema &S);
void Destroy();
+
+ /// brief Determine a base priority for the given declaration.
+ static unsigned getPriorityFromDecl(NamedDecl *ND);
};
class OverloadCandidate {
@@ -420,12 +468,17 @@ public:
CodeCompleteConsumer() : IncludeMacros(false), OutputIsBinary(false) { }
- CodeCompleteConsumer(bool IncludeMacros, bool OutputIsBinary)
- : IncludeMacros(IncludeMacros), OutputIsBinary(OutputIsBinary) { }
+ CodeCompleteConsumer(bool IncludeMacros, bool IncludeCodePatterns,
+ bool OutputIsBinary)
+ : IncludeMacros(IncludeMacros), IncludeCodePatterns(IncludeCodePatterns),
+ OutputIsBinary(OutputIsBinary) { }
/// \brief Whether the code-completion consumer wants to see macros.
bool includeMacros() const { return IncludeMacros; }
+ /// \brief Whether the code-completion consumer wants to see code patterns.
+ bool includeCodePatterns() const { return IncludeCodePatterns; }
+
/// \brief Determine whether the output of this consumer is binary.
bool isOutputBinary() const { return OutputIsBinary; }
@@ -461,9 +514,9 @@ class PrintingCodeCompleteConsumer : public CodeCompleteConsumer {
public:
/// \brief Create a new printing code-completion consumer that prints its
/// results to the given raw output stream.
- PrintingCodeCompleteConsumer(bool IncludeMacros,
+ PrintingCodeCompleteConsumer(bool IncludeMacros, bool IncludeCodePatterns,
llvm::raw_ostream &OS)
- : CodeCompleteConsumer(IncludeMacros, false), OS(OS) { }
+ : CodeCompleteConsumer(IncludeMacros, IncludeCodePatterns, false), OS(OS) {}
/// \brief Prints the finalized code-completion results.
virtual void ProcessCodeCompleteResults(Sema &S, Result *Results,
@@ -484,8 +537,9 @@ public:
/// \brief Create a new CIndex code-completion consumer that prints its
/// results to the given raw output stream in a format readable to the CIndex
/// library.
- CIndexCodeCompleteConsumer(bool IncludeMacros, llvm::raw_ostream &OS)
- : CodeCompleteConsumer(IncludeMacros, true), OS(OS) { }
+ CIndexCodeCompleteConsumer(bool IncludeMacros, bool IncludeCodePatterns,
+ llvm::raw_ostream &OS)
+ : CodeCompleteConsumer(IncludeMacros, IncludeCodePatterns, true), OS(OS) {}
/// \brief Prints the finalized code-completion results.
virtual void ProcessCodeCompleteResults(Sema &S, Result *Results,
diff --git a/lib/AST/ASTContext.cpp b/lib/AST/ASTContext.cpp
index eea727deb44d..851f8d1c68bf 100644
--- a/lib/AST/ASTContext.cpp
+++ b/lib/AST/ASTContext.cpp
@@ -18,6 +18,7 @@
#include "clang/AST/DeclTemplate.h"
#include "clang/AST/TypeLoc.h"
#include "clang/AST/Expr.h"
+#include "clang/AST/ExprCXX.h"
#include "clang/AST/ExternalASTSource.h"
#include "clang/AST/RecordLayout.h"
#include "clang/Basic/Builtins.h"
@@ -27,7 +28,6 @@
#include "llvm/ADT/StringExtras.h"
#include "llvm/Support/MathExtras.h"
#include "llvm/Support/raw_ostream.h"
-#include "RecordLayoutBuilder.h"
using namespace clang;
@@ -46,7 +46,9 @@ 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),
+ DeclarationNames(*this),
+ ExternalSource(0), PrintingPolicy(LOpts),
LastSDM(0, 0) {
ObjCIdRedefinitionType = QualType();
ObjCClassRedefinitionType = QualType();
@@ -61,6 +63,12 @@ ASTContext::~ASTContext() {
// FIXME: Is this the ideal solution?
ReleaseDeclContextMaps();
+ if (!FreeMemory) {
+ // Call all of the deallocation functions.
+ for (unsigned I = 0, N = Deallocations.size(); I != N; ++I)
+ Deallocations[I].first(Deallocations[I].second);
+ }
+
// Release all of the memory associated with overridden C++ methods.
for (llvm::DenseMap<const CXXMethodDecl *, CXXMethodVector>::iterator
OM = OverriddenMethods.begin(), OMEnd = OverriddenMethods.end();
@@ -111,6 +119,10 @@ ASTContext::~ASTContext() {
TUDecl->Destroy(*this);
}
+void ASTContext::AddDeallocation(void (*Callback)(void*), void *Data) {
+ Deallocations.push_back(std::make_pair(Callback, Data));
+}
+
void
ASTContext::setExternalSource(llvm::OwningPtr<ExternalASTSource> &Source) {
ExternalSource.reset(Source.take());
@@ -419,6 +431,18 @@ CharUnits ASTContext::getDeclAlign(const Decl *D, bool RefAsPointee) {
return CharUnits::fromQuantity(Align / Target.getCharWidth());
}
+std::pair<CharUnits, CharUnits>
+ASTContext::getTypeInfoInChars(const Type *T) {
+ std::pair<uint64_t, unsigned> Info = getTypeInfo(T);
+ return std::make_pair(CharUnits::fromQuantity(Info.first / getCharWidth()),
+ CharUnits::fromQuantity(Info.second / getCharWidth()));
+}
+
+std::pair<CharUnits, CharUnits>
+ASTContext::getTypeInfoInChars(QualType T) {
+ return getTypeInfoInChars(T.getTypePtr());
+}
+
/// getTypeSize - Return the size of the specified type, in bits. This method
/// does not work on incomplete types.
///
@@ -593,6 +617,8 @@ ASTContext::getTypeInfo(const Type *T) {
Align = EltInfo.second;
break;
}
+ case Type::ObjCObject:
+ return getTypeInfo(cast<ObjCObjectType>(T)->getBaseType().getTypePtr());
case Type::ObjCInterface: {
const ObjCInterfaceType *ObjCI = cast<ObjCInterfaceType>(T);
const ASTRecordLayout &Layout = getASTObjCInterfaceLayout(ObjCI->getDecl());
@@ -624,10 +650,6 @@ ASTContext::getTypeInfo(const Type *T) {
return getTypeInfo(cast<SubstTemplateTypeParmType>(T)->
getReplacementType().getTypePtr());
- case Type::Elaborated:
- return getTypeInfo(cast<ElaboratedType>(T)->getUnderlyingType()
- .getTypePtr());
-
case Type::Typedef: {
const TypedefDecl *Typedef = cast<TypedefType>(T)->getDecl();
if (const AlignedAttr *Aligned = Typedef->getAttr<AlignedAttr>()) {
@@ -650,8 +672,8 @@ ASTContext::getTypeInfo(const Type *T) {
return getTypeInfo(cast<DecltypeType>(T)->getUnderlyingExpr()->getType()
.getTypePtr());
- case Type::QualifiedName:
- return getTypeInfo(cast<QualifiedNameType>(T)->getNamedType().getTypePtr());
+ case Type::Elaborated:
+ return getTypeInfo(cast<ElaboratedType>(T)->getNamedType().getTypePtr());
case Type::TemplateSpecialization:
assert(getCanonicalType(T) != T &&
@@ -875,40 +897,6 @@ TypeSourceInfo *ASTContext::getTrivialTypeSourceInfo(QualType T,
return DI;
}
-/// getInterfaceLayoutImpl - Get or compute information about the
-/// layout of the given interface.
-///
-/// \param Impl - If given, also include the layout of the interface's
-/// implementation. This may differ by including synthesized ivars.
-const ASTRecordLayout &
-ASTContext::getObjCLayout(const ObjCInterfaceDecl *D,
- const ObjCImplementationDecl *Impl) {
- assert(!D->isForwardDecl() && "Invalid interface decl!");
-
- // Look up this layout, if already laid out, return what we have.
- ObjCContainerDecl *Key =
- Impl ? (ObjCContainerDecl*) Impl : (ObjCContainerDecl*) D;
- if (const ASTRecordLayout *Entry = ObjCLayouts[Key])
- return *Entry;
-
- // Add in synthesized ivar count if laying out an implementation.
- if (Impl) {
- 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
- // frequently.
- if (SynthCount == 0)
- return getObjCLayout(D, 0);
- }
-
- const ASTRecordLayout *NewEntry =
- ASTRecordLayoutBuilder::ComputeLayout(*this, D, Impl);
- ObjCLayouts[Key] = NewEntry;
-
- return *NewEntry;
-}
-
const ASTRecordLayout &
ASTContext::getASTObjCInterfaceLayout(const ObjCInterfaceDecl *D) {
return getObjCLayout(D, 0);
@@ -919,45 +907,6 @@ ASTContext::getASTObjCImplementationLayout(const ObjCImplementationDecl *D) {
return getObjCLayout(D->getClassInterface(), D);
}
-/// getASTRecordLayout - Get or compute information about the layout of the
-/// specified record (struct/union/class), which indicates its size and field
-/// position information.
-const ASTRecordLayout &ASTContext::getASTRecordLayout(const RecordDecl *D) {
- D = D->getDefinition();
- assert(D && "Cannot get layout of forward declarations!");
-
- // Look up this layout, if already laid out, return what we have.
- // Note that we can't save a reference to the entry because this function
- // is recursive.
- const ASTRecordLayout *Entry = ASTRecordLayouts[D];
- if (Entry) return *Entry;
-
- const ASTRecordLayout *NewEntry =
- ASTRecordLayoutBuilder::ComputeLayout(*this, D);
- ASTRecordLayouts[D] = NewEntry;
-
- if (getLangOptions().DumpRecordLayouts) {
- llvm::errs() << "\n*** Dumping AST Record Layout\n";
- DumpRecordLayout(D, llvm::errs());
- }
-
- return *NewEntry;
-}
-
-const CXXMethodDecl *ASTContext::getKeyFunction(const CXXRecordDecl *RD) {
- RD = cast<CXXRecordDecl>(RD->getDefinition());
- assert(RD && "Cannot get key function for forward declarations!");
-
- const CXXMethodDecl *&Entry = KeyFunctions[RD];
- if (!Entry)
- Entry = ASTRecordLayoutBuilder::ComputeKeyFunction(RD);
- else
- assert(Entry == ASTRecordLayoutBuilder::ComputeKeyFunction(RD) &&
- "Key function changed!");
-
- return Entry;
-}
-
//===----------------------------------------------------------------------===//
// Type creation/memoization methods
//===----------------------------------------------------------------------===//
@@ -1343,9 +1292,17 @@ QualType ASTContext::getVariableArrayType(QualType EltTy,
SourceRange Brackets) {
// Since we don't unique expressions, it isn't possible to unique VLA's
// that have an expression provided for their size.
-
+ QualType CanonType;
+
+ if (!EltTy.isCanonical()) {
+ if (NumElts)
+ NumElts->Retain();
+ CanonType = getVariableArrayType(getCanonicalType(EltTy), NumElts, ASM,
+ EltTypeQuals, Brackets);
+ }
+
VariableArrayType *New = new(*this, TypeAlignment)
- VariableArrayType(EltTy, QualType(), NumElts, ASM, EltTypeQuals, Brackets);
+ VariableArrayType(EltTy, CanonType, NumElts, ASM, EltTypeQuals, Brackets);
VariableArrayTypes.push_back(New);
Types.push_back(New);
@@ -1694,10 +1651,6 @@ QualType ASTContext::getTypeDeclTypeSlow(const TypeDecl *Decl) {
if (const TypedefDecl *Typedef = dyn_cast<TypedefDecl>(Decl))
return getTypedefType(Typedef);
- if (const ObjCInterfaceDecl *ObjCInterface
- = dyn_cast<ObjCInterfaceDecl>(Decl))
- return getObjCInterfaceType(ObjCInterface);
-
assert(!isa<TemplateTypeParmDecl>(Decl) &&
"Template type parameter types are always available.");
@@ -1888,29 +1841,28 @@ ASTContext::getTemplateSpecializationType(TemplateName Template,
}
QualType
-ASTContext::getQualifiedNameType(NestedNameSpecifier *NNS,
- QualType NamedType) {
+ASTContext::getElaboratedType(ElaboratedTypeKeyword Keyword,
+ NestedNameSpecifier *NNS,
+ QualType NamedType) {
llvm::FoldingSetNodeID ID;
- QualifiedNameType::Profile(ID, NNS, NamedType);
+ ElaboratedType::Profile(ID, Keyword, NNS, NamedType);
void *InsertPos = 0;
- QualifiedNameType *T
- = QualifiedNameTypes.FindNodeOrInsertPos(ID, InsertPos);
+ ElaboratedType *T = ElaboratedTypes.FindNodeOrInsertPos(ID, InsertPos);
if (T)
return QualType(T, 0);
QualType Canon = NamedType;
if (!Canon.isCanonical()) {
Canon = getCanonicalType(NamedType);
- QualifiedNameType *CheckT
- = QualifiedNameTypes.FindNodeOrInsertPos(ID, InsertPos);
- assert(!CheckT && "Qualified name canonical type broken");
+ ElaboratedType *CheckT = ElaboratedTypes.FindNodeOrInsertPos(ID, InsertPos);
+ assert(!CheckT && "Elaborated canonical type broken");
(void)CheckT;
}
- T = new (*this) QualifiedNameType(NNS, NamedType, Canon);
+ T = new (*this) ElaboratedType(Keyword, NNS, NamedType, Canon);
Types.push_back(T);
- QualifiedNameTypes.InsertNode(T, InsertPos);
+ ElaboratedTypes.InsertNode(T, InsertPos);
return QualType(T, 0);
}
@@ -1987,30 +1939,6 @@ ASTContext::getDependentNameType(ElaboratedTypeKeyword Keyword,
return QualType(T, 0);
}
-QualType
-ASTContext::getElaboratedType(QualType UnderlyingType,
- ElaboratedType::TagKind Tag) {
- llvm::FoldingSetNodeID ID;
- ElaboratedType::Profile(ID, UnderlyingType, Tag);
-
- void *InsertPos = 0;
- ElaboratedType *T = ElaboratedTypes.FindNodeOrInsertPos(ID, InsertPos);
- if (T)
- return QualType(T, 0);
-
- QualType Canon = UnderlyingType;
- if (!Canon.isCanonical()) {
- Canon = getCanonicalType(Canon);
- ElaboratedType *CheckT = ElaboratedTypes.FindNodeOrInsertPos(ID, InsertPos);
- assert(!CheckT && "Elaborated canonical type is broken"); (void)CheckT;
- }
-
- T = new (*this) ElaboratedType(UnderlyingType, Tag, Canon);
- Types.push_back(T);
- ElaboratedTypes.InsertNode(T, InsertPos);
- return QualType(T, 0);
-}
-
/// CmpProtocolNames - Comparison predicate for sorting protocols
/// alphabetically.
static bool CmpProtocolNames(const ObjCProtocolDecl *LHS,
@@ -2018,7 +1946,7 @@ static bool CmpProtocolNames(const ObjCProtocolDecl *LHS,
return LHS->getDeclName() < RHS->getDeclName();
}
-static bool areSortedAndUniqued(ObjCProtocolDecl **Protocols,
+static bool areSortedAndUniqued(ObjCProtocolDecl * const *Protocols,
unsigned NumProtocols) {
if (NumProtocols == 0) return true;
@@ -2040,96 +1968,98 @@ static void SortAndUniqueProtocols(ObjCProtocolDecl **Protocols,
NumProtocols = ProtocolsEnd-Protocols;
}
-/// getObjCObjectPointerType - Return a ObjCObjectPointerType type for
-/// the given interface decl and the conforming protocol list.
-QualType ASTContext::getObjCObjectPointerType(QualType InterfaceT,
- ObjCProtocolDecl **Protocols,
- unsigned NumProtocols,
- unsigned Quals) {
- llvm::FoldingSetNodeID ID;
- ObjCObjectPointerType::Profile(ID, InterfaceT, Protocols, NumProtocols);
- Qualifiers Qs = Qualifiers::fromCVRMask(Quals);
+QualType ASTContext::getObjCObjectType(QualType BaseType,
+ ObjCProtocolDecl * const *Protocols,
+ unsigned NumProtocols) {
+ // If the base type is an interface and there aren't any protocols
+ // to add, then the interface type will do just fine.
+ if (!NumProtocols && isa<ObjCInterfaceType>(BaseType))
+ return BaseType;
+ // Look in the folding set for an existing type.
+ llvm::FoldingSetNodeID ID;
+ ObjCObjectTypeImpl::Profile(ID, BaseType, Protocols, NumProtocols);
void *InsertPos = 0;
- if (ObjCObjectPointerType *QT =
- ObjCObjectPointerTypes.FindNodeOrInsertPos(ID, InsertPos))
- return getQualifiedType(QualType(QT, 0), Qs);
+ if (ObjCObjectType *QT = ObjCObjectTypes.FindNodeOrInsertPos(ID, InsertPos))
+ return QualType(QT, 0);
- // Sort the protocol list alphabetically to canonicalize it.
+ // Build the canonical type, which has the canonical base type and
+ // a sorted-and-uniqued list of protocols.
QualType Canonical;
- if (!InterfaceT.isCanonical() ||
- !areSortedAndUniqued(Protocols, NumProtocols)) {
- if (!areSortedAndUniqued(Protocols, NumProtocols)) {
+ bool ProtocolsSorted = areSortedAndUniqued(Protocols, NumProtocols);
+ if (!ProtocolsSorted || !BaseType.isCanonical()) {
+ if (!ProtocolsSorted) {
llvm::SmallVector<ObjCProtocolDecl*, 8> Sorted(Protocols,
Protocols + NumProtocols);
unsigned UniqueCount = NumProtocols;
SortAndUniqueProtocols(&Sorted[0], UniqueCount);
-
- Canonical = getObjCObjectPointerType(getCanonicalType(InterfaceT),
- &Sorted[0], UniqueCount);
+ Canonical = getObjCObjectType(getCanonicalType(BaseType),
+ &Sorted[0], UniqueCount);
} else {
- Canonical = getObjCObjectPointerType(getCanonicalType(InterfaceT),
- Protocols, NumProtocols);
+ Canonical = getObjCObjectType(getCanonicalType(BaseType),
+ Protocols, NumProtocols);
}
// Regenerate InsertPos.
- ObjCObjectPointerTypes.FindNodeOrInsertPos(ID, InsertPos);
+ ObjCObjectTypes.FindNodeOrInsertPos(ID, InsertPos);
}
- // No match.
- unsigned Size = sizeof(ObjCObjectPointerType)
- + NumProtocols * sizeof(ObjCProtocolDecl *);
+ unsigned Size = sizeof(ObjCObjectTypeImpl);
+ Size += NumProtocols * sizeof(ObjCProtocolDecl *);
void *Mem = Allocate(Size, TypeAlignment);
- ObjCObjectPointerType *QType = new (Mem) ObjCObjectPointerType(Canonical,
- InterfaceT,
- Protocols,
- NumProtocols);
+ ObjCObjectTypeImpl *T =
+ new (Mem) ObjCObjectTypeImpl(Canonical, BaseType, Protocols, NumProtocols);
- Types.push_back(QType);
- ObjCObjectPointerTypes.InsertNode(QType, InsertPos);
- return getQualifiedType(QualType(QType, 0), Qs);
+ Types.push_back(T);
+ ObjCObjectTypes.InsertNode(T, InsertPos);
+ return QualType(T, 0);
}
-/// getObjCInterfaceType - Return the unique reference to the type for the
-/// specified ObjC interface decl. The list of protocols is optional.
-QualType ASTContext::getObjCInterfaceType(const ObjCInterfaceDecl *Decl,
- ObjCProtocolDecl **Protocols, unsigned NumProtocols) {
+/// getObjCObjectPointerType - Return a ObjCObjectPointerType type for
+/// the given object type.
+QualType ASTContext::getObjCObjectPointerType(QualType ObjectT) {
llvm::FoldingSetNodeID ID;
- ObjCInterfaceType::Profile(ID, Decl, Protocols, NumProtocols);
+ ObjCObjectPointerType::Profile(ID, ObjectT);
void *InsertPos = 0;
- if (ObjCInterfaceType *QT =
- ObjCInterfaceTypes.FindNodeOrInsertPos(ID, InsertPos))
+ if (ObjCObjectPointerType *QT =
+ ObjCObjectPointerTypes.FindNodeOrInsertPos(ID, InsertPos))
return QualType(QT, 0);
- // Sort the protocol list alphabetically to canonicalize it.
+ // Find the canonical object type.
QualType Canonical;
- if (NumProtocols && !areSortedAndUniqued(Protocols, NumProtocols)) {
- llvm::SmallVector<ObjCProtocolDecl*, 8> Sorted(Protocols,
- Protocols + NumProtocols);
-
- unsigned UniqueCount = NumProtocols;
- SortAndUniqueProtocols(&Sorted[0], UniqueCount);
+ if (!ObjectT.isCanonical()) {
+ Canonical = getObjCObjectPointerType(getCanonicalType(ObjectT));
- Canonical = getObjCInterfaceType(Decl, &Sorted[0], UniqueCount);
-
- ObjCInterfaceTypes.FindNodeOrInsertPos(ID, InsertPos);
+ // Regenerate InsertPos.
+ ObjCObjectPointerTypes.FindNodeOrInsertPos(ID, InsertPos);
}
- unsigned Size = sizeof(ObjCInterfaceType)
- + NumProtocols * sizeof(ObjCProtocolDecl *);
- void *Mem = Allocate(Size, TypeAlignment);
- ObjCInterfaceType *QType = new (Mem) ObjCInterfaceType(Canonical,
- const_cast<ObjCInterfaceDecl*>(Decl),
- Protocols,
- NumProtocols);
+ // No match.
+ void *Mem = Allocate(sizeof(ObjCObjectPointerType), TypeAlignment);
+ ObjCObjectPointerType *QType =
+ new (Mem) ObjCObjectPointerType(Canonical, ObjectT);
Types.push_back(QType);
- ObjCInterfaceTypes.InsertNode(QType, InsertPos);
+ ObjCObjectPointerTypes.InsertNode(QType, InsertPos);
return QualType(QType, 0);
}
+/// getObjCInterfaceType - Return the unique reference to the type for the
+/// specified ObjC interface decl. The list of protocols is optional.
+QualType ASTContext::getObjCInterfaceType(const ObjCInterfaceDecl *Decl) {
+ if (Decl->TypeForDecl)
+ return QualType(Decl->TypeForDecl, 0);
+
+ // FIXME: redeclarations?
+ void *Mem = Allocate(sizeof(ObjCInterfaceType), TypeAlignment);
+ ObjCInterfaceType *T = new (Mem) ObjCInterfaceType(Decl);
+ Decl->TypeForDecl = T;
+ Types.push_back(T);
+ return QualType(T, 0);
+}
+
/// getTypeOfExprType - Unlike many "get<Type>" functions, we can't unique
/// TypeOfExprType AST's (since expression's are never shared). For example,
/// multiple declarations that refer to "typeof(x)" all contain different
@@ -2362,26 +2292,35 @@ CanQualType ASTContext::getCanonicalType(QualType T) {
QualType ASTContext::getUnqualifiedArrayType(QualType T,
Qualifiers &Quals) {
Quals = T.getQualifiers();
- if (!isa<ArrayType>(T)) {
+ const ArrayType *AT = getAsArrayType(T);
+ if (!AT) {
return T.getUnqualifiedType();
}
- const ArrayType *AT = cast<ArrayType>(T);
QualType Elt = AT->getElementType();
QualType UnqualElt = getUnqualifiedArrayType(Elt, Quals);
if (Elt == UnqualElt)
return T;
- if (const ConstantArrayType *CAT = dyn_cast<ConstantArrayType>(T)) {
+ if (const ConstantArrayType *CAT = dyn_cast<ConstantArrayType>(AT)) {
return getConstantArrayType(UnqualElt, CAT->getSize(),
CAT->getSizeModifier(), 0);
}
- if (const IncompleteArrayType *IAT = dyn_cast<IncompleteArrayType>(T)) {
+ if (const IncompleteArrayType *IAT = dyn_cast<IncompleteArrayType>(AT)) {
return getIncompleteArrayType(UnqualElt, IAT->getSizeModifier(), 0);
}
- const DependentSizedArrayType *DSAT = cast<DependentSizedArrayType>(T);
+ if (const VariableArrayType *VAT = dyn_cast<VariableArrayType>(AT)) {
+ return getVariableArrayType(UnqualElt,
+ VAT->getSizeExpr() ?
+ VAT->getSizeExpr()->Retain() : 0,
+ VAT->getSizeModifier(),
+ VAT->getIndexTypeCVRQualifiers(),
+ VAT->getBracketsRange());
+ }
+
+ const DependentSizedArrayType *DSAT = cast<DependentSizedArrayType>(AT);
return getDependentSizedArrayType(UnqualElt, DSAT->getSizeExpr()->Retain(),
DSAT->getSizeModifier(), 0,
SourceRange());
@@ -2716,6 +2655,9 @@ unsigned ASTContext::getIntegerRank(Type *T) {
/// \returns the type this bit-field will promote to, or NULL if no
/// promotion occurs.
QualType ASTContext::isPromotableBitField(Expr *E) {
+ if (E->isTypeDependent() || E->isValueDependent())
+ return QualType();
+
FieldDecl *Field = E->getBitField();
if (!Field)
return QualType();
@@ -2811,7 +2753,7 @@ CreateRecordDecl(ASTContext &Ctx, RecordDecl::TagKind TK, DeclContext *DC,
QualType ASTContext::getCFConstantStringType() {
if (!CFConstantStringTypeDecl) {
CFConstantStringTypeDecl =
- CreateRecordDecl(*this, TagDecl::TK_struct, TUDecl, SourceLocation(),
+ CreateRecordDecl(*this, TTK_Struct, TUDecl, SourceLocation(),
&Idents.get("NSConstantString"));
CFConstantStringTypeDecl->startDefinition();
@@ -2853,7 +2795,7 @@ void ASTContext::setCFConstantStringType(QualType T) {
QualType ASTContext::getNSConstantStringType() {
if (!NSConstantStringTypeDecl) {
NSConstantStringTypeDecl =
- CreateRecordDecl(*this, TagDecl::TK_struct, TUDecl, SourceLocation(),
+ CreateRecordDecl(*this, TTK_Struct, TUDecl, SourceLocation(),
&Idents.get("__builtin_NSString"));
NSConstantStringTypeDecl->startDefinition();
@@ -2892,7 +2834,7 @@ void ASTContext::setNSConstantStringType(QualType T) {
QualType ASTContext::getObjCFastEnumerationStateType() {
if (!ObjCFastEnumerationStateTypeDecl) {
ObjCFastEnumerationStateTypeDecl =
- CreateRecordDecl(*this, TagDecl::TK_struct, TUDecl, SourceLocation(),
+ CreateRecordDecl(*this, TTK_Struct, TUDecl, SourceLocation(),
&Idents.get("__objcFastEnumerationState"));
ObjCFastEnumerationStateTypeDecl->startDefinition();
@@ -2927,7 +2869,7 @@ QualType ASTContext::getBlockDescriptorType() {
RecordDecl *T;
// FIXME: Needs the FlagAppleBlock bit.
- T = CreateRecordDecl(*this, TagDecl::TK_struct, TUDecl, SourceLocation(),
+ T = CreateRecordDecl(*this, TTK_Struct, TUDecl, SourceLocation(),
&Idents.get("__block_descriptor"));
T->startDefinition();
@@ -2972,7 +2914,7 @@ QualType ASTContext::getBlockDescriptorExtendedType() {
RecordDecl *T;
// FIXME: Needs the FlagAppleBlock bit.
- T = CreateRecordDecl(*this, TagDecl::TK_struct, TUDecl, SourceLocation(),
+ T = CreateRecordDecl(*this, TTK_Struct, TUDecl, SourceLocation(),
&Idents.get("__block_descriptor_withcopydispose"));
T->startDefinition();
@@ -3044,7 +2986,7 @@ QualType ASTContext::BuildByRefType(const char *DeclName, QualType Ty) {
llvm::raw_svector_ostream(Name) << "__Block_byref_" <<
++UniqueBlockByRefTypeID << '_' << DeclName;
RecordDecl *T;
- T = CreateRecordDecl(*this, TagDecl::TK_struct, TUDecl, SourceLocation(),
+ T = CreateRecordDecl(*this, TTK_Struct, TUDecl, SourceLocation(),
&Idents.get(Name.str()));
T->startDefinition();
QualType Int32Ty = IntTy;
@@ -3088,14 +3030,15 @@ QualType ASTContext::BuildByRefType(const char *DeclName, QualType Ty) {
QualType ASTContext::getBlockParmType(
bool BlockHasCopyDispose,
- llvm::SmallVector<const Expr *, 8> &BlockDeclRefDecls) {
+ llvm::SmallVectorImpl<const Expr *> &Layout) {
+
// FIXME: Move up
static unsigned int UniqueBlockParmTypeID = 0;
llvm::SmallString<36> Name;
llvm::raw_svector_ostream(Name) << "__block_literal_"
<< ++UniqueBlockParmTypeID;
RecordDecl *T;
- T = CreateRecordDecl(*this, TagDecl::TK_struct, TUDecl, SourceLocation(),
+ T = CreateRecordDecl(*this, TTK_Struct, TUDecl, SourceLocation(),
&Idents.get(Name.str()));
T->startDefinition();
QualType FieldTypes[] = {
@@ -3125,22 +3068,28 @@ QualType ASTContext::getBlockParmType(
T->addDecl(Field);
}
- for (size_t i = 0; i < BlockDeclRefDecls.size(); ++i) {
- const Expr *E = BlockDeclRefDecls[i];
- const BlockDeclRefExpr *BDRE = dyn_cast<BlockDeclRefExpr>(E);
- clang::IdentifierInfo *Name = 0;
- if (BDRE) {
+ for (unsigned i = 0; i < Layout.size(); ++i) {
+ const Expr *E = Layout[i];
+
+ QualType FieldType = E->getType();
+ IdentifierInfo *FieldName = 0;
+ if (isa<CXXThisExpr>(E)) {
+ FieldName = &Idents.get("this");
+ } else if (const BlockDeclRefExpr *BDRE = dyn_cast<BlockDeclRefExpr>(E)) {
const ValueDecl *D = BDRE->getDecl();
- Name = &Idents.get(D->getName());
+ FieldName = D->getIdentifier();
+ if (BDRE->isByRef())
+ FieldType = BuildByRefType(D->getNameAsCString(), FieldType);
+ } else {
+ // Padding.
+ assert(isa<ConstantArrayType>(FieldType) &&
+ isa<DeclRefExpr>(E) &&
+ !cast<DeclRefExpr>(E)->getDecl()->getDeclName() &&
+ "doesn't match characteristics of padding decl");
}
- QualType FieldType = E->getType();
-
- if (BDRE && BDRE->isByRef())
- FieldType = BuildByRefType(BDRE->getDecl()->getNameAsCString(),
- FieldType);
FieldDecl *Field = FieldDecl::Create(*this, T, SourceLocation(),
- Name, FieldType, /*TInfo=*/0,
+ FieldName, FieldType, /*TInfo=*/0,
/*BitWidth=*/0, /*Mutable=*/false);
Field->setAccess(AS_public);
T->addDecl(Field);
@@ -3593,6 +3542,17 @@ void ASTContext::getObjCEncodingForTypeImpl(QualType T, std::string& S,
// Anonymous structures print as '?'
if (const IdentifierInfo *II = RDecl->getIdentifier()) {
S += II->getName();
+ if (ClassTemplateSpecializationDecl *Spec
+ = dyn_cast<ClassTemplateSpecializationDecl>(RDecl)) {
+ const TemplateArgumentList &TemplateArgs = Spec->getTemplateArgs();
+ std::string TemplateArgsStr
+ = TemplateSpecializationType::PrintTemplateArgumentList(
+ TemplateArgs.getFlatArgumentList(),
+ TemplateArgs.flat_size(),
+ (*this).PrintingPolicy);
+
+ S += TemplateArgsStr;
+ }
} else {
S += '?';
}
@@ -3636,6 +3596,10 @@ void ASTContext::getObjCEncodingForTypeImpl(QualType T, std::string& S,
return;
}
+ // Ignore protocol qualifiers when mangling at this level.
+ if (const ObjCObjectType *OT = T->getAs<ObjCObjectType>())
+ T = OT->getBaseType();
+
if (const ObjCInterfaceType *OIT = T->getAs<ObjCInterfaceType>()) {
// @encode(class_name)
ObjCInterfaceDecl *OI = OIT->getDecl();
@@ -3718,6 +3682,11 @@ void ASTContext::getObjCEncodingForTypeImpl(QualType T, std::string& S,
return;
}
+ // gcc just blithely ignores member pointers.
+ // TODO: maybe there should be a mangling for these
+ if (T->getAs<MemberPointerType>())
+ return;
+
assert(0 && "@encode for type not implemented!");
}
@@ -4106,18 +4075,21 @@ bool ASTContext::ObjCQualifiedIdTypesAreCompatible(QualType lhs, QualType rhs,
///
bool ASTContext::canAssignObjCInterfaces(const ObjCObjectPointerType *LHSOPT,
const ObjCObjectPointerType *RHSOPT) {
+ const ObjCObjectType* LHS = LHSOPT->getObjectType();
+ const ObjCObjectType* RHS = RHSOPT->getObjectType();
+
// If either type represents the built-in 'id' or 'Class' types, return true.
- if (LHSOPT->isObjCBuiltinType() || RHSOPT->isObjCBuiltinType())
+ if (LHS->isObjCUnqualifiedIdOrClass() ||
+ RHS->isObjCUnqualifiedIdOrClass())
return true;
- if (LHSOPT->isObjCQualifiedIdType() || RHSOPT->isObjCQualifiedIdType())
+ if (LHS->isObjCQualifiedId() || RHS->isObjCQualifiedId())
return ObjCQualifiedIdTypesAreCompatible(QualType(LHSOPT,0),
QualType(RHSOPT,0),
false);
- const ObjCInterfaceType* LHS = LHSOPT->getInterfaceType();
- const ObjCInterfaceType* RHS = RHSOPT->getInterfaceType();
- if (LHS && RHS) // We have 2 user-defined types.
+ // If we have 2 user-defined types, fall into that path.
+ if (LHS->getInterface() && RHS->getInterface())
return canAssignObjCInterfaces(LHS, RHS);
return false;
@@ -4168,8 +4140,10 @@ void getIntersectionOfProtocols(ASTContext &Context,
const ObjCObjectPointerType *RHSOPT,
llvm::SmallVectorImpl<ObjCProtocolDecl *> &IntersectionOfProtocols) {
- const ObjCInterfaceType* LHS = LHSOPT->getInterfaceType();
- const ObjCInterfaceType* RHS = RHSOPT->getInterfaceType();
+ const ObjCObjectType* LHS = LHSOPT->getObjectType();
+ const ObjCObjectType* RHS = RHSOPT->getObjectType();
+ assert(LHS->getInterface() && "LHS must have an interface base");
+ assert(RHS->getInterface() && "RHS must have an interface base");
llvm::SmallPtrSet<ObjCProtocolDecl *, 8> InheritedProtocolSet;
unsigned LHSNumProtocols = LHS->getNumProtocols();
@@ -4177,7 +4151,8 @@ void getIntersectionOfProtocols(ASTContext &Context,
InheritedProtocolSet.insert(LHS->qual_begin(), LHS->qual_end());
else {
llvm::SmallPtrSet<ObjCProtocolDecl *, 8> LHSInheritedProtocols;
- Context.CollectInheritedProtocols(LHS->getDecl(), LHSInheritedProtocols);
+ Context.CollectInheritedProtocols(LHS->getInterface(),
+ LHSInheritedProtocols);
InheritedProtocolSet.insert(LHSInheritedProtocols.begin(),
LHSInheritedProtocols.end());
}
@@ -4192,7 +4167,8 @@ void getIntersectionOfProtocols(ASTContext &Context,
}
else {
llvm::SmallPtrSet<ObjCProtocolDecl *, 8> RHSInheritedProtocols;
- Context.CollectInheritedProtocols(RHS->getDecl(), RHSInheritedProtocols);
+ Context.CollectInheritedProtocols(RHS->getInterface(),
+ RHSInheritedProtocols);
for (llvm::SmallPtrSet<ObjCProtocolDecl*,8>::iterator I =
RHSInheritedProtocols.begin(),
E = RHSInheritedProtocols.end(); I != E; ++I)
@@ -4206,37 +4182,40 @@ void getIntersectionOfProtocols(ASTContext &Context,
/// last type comparison in a ?-exp of ObjC pointer types before a
/// warning is issued. So, its invokation is extremely rare.
QualType ASTContext::areCommonBaseCompatible(
- const ObjCObjectPointerType *LHSOPT,
- const ObjCObjectPointerType *RHSOPT) {
- const ObjCInterfaceType* LHS = LHSOPT->getInterfaceType();
- const ObjCInterfaceType* RHS = RHSOPT->getInterfaceType();
- if (!LHS || !RHS)
+ const ObjCObjectPointerType *Lptr,
+ const ObjCObjectPointerType *Rptr) {
+ const ObjCObjectType *LHS = Lptr->getObjectType();
+ const ObjCObjectType *RHS = Rptr->getObjectType();
+ const ObjCInterfaceDecl* LDecl = LHS->getInterface();
+ const ObjCInterfaceDecl* RDecl = RHS->getInterface();
+ if (!LDecl || !RDecl)
return QualType();
- while (const ObjCInterfaceDecl *LHSIDecl = LHS->getDecl()->getSuperClass()) {
- QualType LHSTy = getObjCInterfaceType(LHSIDecl);
- LHS = LHSTy->getAs<ObjCInterfaceType>();
+ while ((LDecl = LDecl->getSuperClass())) {
+ LHS = cast<ObjCInterfaceType>(getObjCInterfaceType(LDecl));
if (canAssignObjCInterfaces(LHS, RHS)) {
- llvm::SmallVector<ObjCProtocolDecl *, 8> IntersectionOfProtocols;
- getIntersectionOfProtocols(*this,
- LHSOPT, RHSOPT, IntersectionOfProtocols);
- if (IntersectionOfProtocols.empty())
- LHSTy = getObjCObjectPointerType(LHSTy);
- else
- LHSTy = getObjCObjectPointerType(LHSTy, &IntersectionOfProtocols[0],
- IntersectionOfProtocols.size());
- return LHSTy;
+ llvm::SmallVector<ObjCProtocolDecl *, 8> Protocols;
+ getIntersectionOfProtocols(*this, Lptr, Rptr, Protocols);
+
+ QualType Result = QualType(LHS, 0);
+ if (!Protocols.empty())
+ Result = getObjCObjectType(Result, Protocols.data(), Protocols.size());
+ Result = getObjCObjectPointerType(Result);
+ return Result;
}
}
return QualType();
}
-bool ASTContext::canAssignObjCInterfaces(const ObjCInterfaceType *LHS,
- const ObjCInterfaceType *RHS) {
+bool ASTContext::canAssignObjCInterfaces(const ObjCObjectType *LHS,
+ const ObjCObjectType *RHS) {
+ assert(LHS->getInterface() && "LHS is not an interface type");
+ assert(RHS->getInterface() && "RHS is not an interface type");
+
// Verify that the base decls are compatible: the RHS must be a subclass of
// the LHS.
- if (!LHS->getDecl()->isSuperClassOf(RHS->getDecl()))
+ if (!LHS->getInterface()->isSuperClassOf(RHS->getInterface()))
return false;
// RHS must have a superset of the protocols in the LHS. If the LHS is not
@@ -4249,15 +4228,15 @@ bool ASTContext::canAssignObjCInterfaces(const ObjCInterfaceType *LHS,
if (RHS->getNumProtocols() == 0)
return true; // FIXME: should return false!
- for (ObjCInterfaceType::qual_iterator LHSPI = LHS->qual_begin(),
- LHSPE = LHS->qual_end();
+ for (ObjCObjectType::qual_iterator LHSPI = LHS->qual_begin(),
+ LHSPE = LHS->qual_end();
LHSPI != LHSPE; LHSPI++) {
bool RHSImplementsProtocol = false;
// If the RHS doesn't implement the protocol on the left, the types
// are incompatible.
- for (ObjCInterfaceType::qual_iterator RHSPI = RHS->qual_begin(),
- RHSPE = RHS->qual_end();
+ for (ObjCObjectType::qual_iterator RHSPI = RHS->qual_begin(),
+ RHSPE = RHS->qual_end();
RHSPI != RHSPE; RHSPI++) {
if ((*RHSPI)->lookupProtocolNamed((*LHSPI)->getIdentifier())) {
RHSImplementsProtocol = true;
@@ -4483,6 +4462,10 @@ QualType ASTContext::mergeTypes(QualType LHS, QualType RHS,
if (RHSClass == Type::VariableArray || RHSClass == Type::IncompleteArray)
RHSClass = Type::ConstantArray;
+ // ObjCInterfaces are just specialized ObjCObjects.
+ if (LHSClass == Type::ObjCInterface) LHSClass = Type::ObjCObject;
+ if (RHSClass == Type::ObjCInterface) RHSClass = Type::ObjCObject;
+
// Canonicalize ExtVector -> Vector.
if (LHSClass == Type::ExtVector) LHSClass = Type::Vector;
if (RHSClass == Type::ExtVector) RHSClass = Type::Vector;
@@ -4522,6 +4505,7 @@ QualType ASTContext::mergeTypes(QualType LHS, QualType RHS,
assert(false && "C++ should never be in mergeTypes");
return QualType();
+ case Type::ObjCInterface:
case Type::IncompleteArray:
case Type::VariableArray:
case Type::FunctionProto:
@@ -4614,14 +4598,13 @@ QualType ASTContext::mergeTypes(QualType LHS, QualType RHS,
RHSCan->getAs<VectorType>()))
return LHS;
return QualType();
- case Type::ObjCInterface: {
- // Check if the interfaces are assignment compatible.
+ case Type::ObjCObject: {
+ // Check if the types are assignment compatible.
// FIXME: This should be type compatibility, e.g. whether
// "LHS x; RHS x;" at global scope is legal.
- const ObjCInterfaceType* LHSIface = LHS->getAs<ObjCInterfaceType>();
- const ObjCInterfaceType* RHSIface = RHS->getAs<ObjCInterfaceType>();
- if (LHSIface && RHSIface &&
- canAssignObjCInterfaces(LHSIface, RHSIface))
+ const ObjCObjectType* LHSIface = LHS->getAs<ObjCObjectType>();
+ const ObjCObjectType* RHSIface = RHS->getAs<ObjCObjectType>();
+ if (canAssignObjCInterfaces(LHSIface, RHSIface))
return LHS;
return QualType();
@@ -4645,6 +4628,87 @@ QualType ASTContext::mergeTypes(QualType LHS, QualType RHS,
return QualType();
}
+/// mergeObjCGCQualifiers - This routine merges ObjC's GC attribute of 'LHS' and
+/// 'RHS' attributes and returns the merged version; including for function
+/// return types.
+QualType ASTContext::mergeObjCGCQualifiers(QualType LHS, QualType RHS) {
+ QualType LHSCan = getCanonicalType(LHS),
+ RHSCan = getCanonicalType(RHS);
+ // If two types are identical, they are compatible.
+ if (LHSCan == RHSCan)
+ return LHS;
+ if (RHSCan->isFunctionType()) {
+ if (!LHSCan->isFunctionType())
+ return QualType();
+ QualType OldReturnType =
+ cast<FunctionType>(RHSCan.getTypePtr())->getResultType();
+ QualType NewReturnType =
+ cast<FunctionType>(LHSCan.getTypePtr())->getResultType();
+ QualType ResReturnType =
+ mergeObjCGCQualifiers(NewReturnType, OldReturnType);
+ if (ResReturnType.isNull())
+ return QualType();
+ if (ResReturnType == NewReturnType || ResReturnType == OldReturnType) {
+ // id foo(); ... __strong id foo(); or: __strong id foo(); ... id foo();
+ // In either case, use OldReturnType to build the new function type.
+ const FunctionType *F = LHS->getAs<FunctionType>();
+ if (const FunctionProtoType *FPT = cast<FunctionProtoType>(F)) {
+ FunctionType::ExtInfo Info = getFunctionExtInfo(LHS);
+ QualType ResultType
+ = getFunctionType(OldReturnType, FPT->arg_type_begin(),
+ FPT->getNumArgs(), FPT->isVariadic(),
+ FPT->getTypeQuals(),
+ FPT->hasExceptionSpec(),
+ FPT->hasAnyExceptionSpec(),
+ FPT->getNumExceptions(),
+ FPT->exception_begin(),
+ Info);
+ return ResultType;
+ }
+ }
+ return QualType();
+ }
+
+ // If the qualifiers are different, the types can still be merged.
+ Qualifiers LQuals = LHSCan.getLocalQualifiers();
+ Qualifiers RQuals = RHSCan.getLocalQualifiers();
+ if (LQuals != RQuals) {
+ // If any of these qualifiers are different, we have a type mismatch.
+ if (LQuals.getCVRQualifiers() != RQuals.getCVRQualifiers() ||
+ LQuals.getAddressSpace() != RQuals.getAddressSpace())
+ return QualType();
+
+ // Exactly one GC qualifier difference is allowed: __strong is
+ // okay if the other type has no GC qualifier but is an Objective
+ // C object pointer (i.e. implicitly strong by default). We fix
+ // this by pretending that the unqualified type was actually
+ // qualified __strong.
+ Qualifiers::GC GC_L = LQuals.getObjCGCAttr();
+ Qualifiers::GC GC_R = RQuals.getObjCGCAttr();
+ assert((GC_L != GC_R) && "unequal qualifier sets had only equal elements");
+
+ if (GC_L == Qualifiers::Weak || GC_R == Qualifiers::Weak)
+ return QualType();
+
+ if (GC_L == Qualifiers::Strong)
+ return LHS;
+ if (GC_R == Qualifiers::Strong)
+ return RHS;
+ return QualType();
+ }
+
+ if (LHSCan->isObjCObjectPointerType() && RHSCan->isObjCObjectPointerType()) {
+ QualType LHSBaseQT = LHS->getAs<ObjCObjectPointerType>()->getPointeeType();
+ QualType RHSBaseQT = RHS->getAs<ObjCObjectPointerType>()->getPointeeType();
+ QualType ResQT = mergeObjCGCQualifiers(LHSBaseQT, RHSBaseQT);
+ if (ResQT == LHSBaseQT)
+ return LHS;
+ if (ResQT == RHSBaseQT)
+ return RHS;
+ }
+ return QualType();
+}
+
//===----------------------------------------------------------------------===//
// Integer Predicates
//===----------------------------------------------------------------------===//
diff --git a/lib/AST/ASTDiagnostic.cpp b/lib/AST/ASTDiagnostic.cpp
index e4cd2a9c1053..0d609bfa6d39 100644
--- a/lib/AST/ASTDiagnostic.cpp
+++ b/lib/AST/ASTDiagnostic.cpp
@@ -19,65 +19,41 @@
using namespace clang;
-/// Determines whether we should have an a.k.a. clause when
-/// pretty-printing a type. There are three main criteria:
-///
-/// 1) Some types provide very minimal sugar that doesn't impede the
-/// user's understanding --- for example, elaborated type
-/// specifiers. If this is all the sugar we see, we don't want an
-/// a.k.a. clause.
-/// 2) Some types are technically sugared but are much more familiar
-/// when seen in their sugared form --- for example, va_list,
-/// vector types, and the magic Objective C types. We don't
-/// want to desugar these, even if we do produce an a.k.a. clause.
-/// 3) Some types may have already been desugared previously in this diagnostic.
-/// if this is the case, doing another "aka" would just be clutter.
-///
-static bool ShouldAKA(ASTContext &Context, QualType QT,
- const Diagnostic::ArgumentValue *PrevArgs,
- unsigned NumPrevArgs,
- QualType &DesugaredQT) {
- QualType InputTy = QT;
-
- bool AKA = false;
- QualifierCollector Qc;
-
+// Returns a desugared version of the QualType, and marks ShouldAKA as true
+// whenever we remove significant sugar from the type.
+static QualType Desugar(ASTContext &Context, QualType QT, bool &ShouldAKA) {
+ QualifierCollector QC;
+
while (true) {
- const Type *Ty = Qc.strip(QT);
-
+ const Type *Ty = QC.strip(QT);
+
// Don't aka just because we saw an elaborated type...
if (isa<ElaboratedType>(Ty)) {
QT = cast<ElaboratedType>(Ty)->desugar();
continue;
}
-
- // ...or a qualified name type...
- if (isa<QualifiedNameType>(Ty)) {
- QT = cast<QualifiedNameType>(Ty)->desugar();
- continue;
- }
// ...or a substituted template type parameter.
if (isa<SubstTemplateTypeParmType>(Ty)) {
QT = cast<SubstTemplateTypeParmType>(Ty)->desugar();
continue;
}
-
+
// Don't desugar template specializations.
if (isa<TemplateSpecializationType>(Ty))
break;
-
+
// Don't desugar magic Objective-C types.
if (QualType(Ty,0) == Context.getObjCIdType() ||
QualType(Ty,0) == Context.getObjCClassType() ||
QualType(Ty,0) == Context.getObjCSelType() ||
QualType(Ty,0) == Context.getObjCProtoType())
break;
-
+
// Don't desugar va_list.
if (QualType(Ty,0) == Context.getBuiltinVaListType())
break;
-
+
// Otherwise, do a single-step desugar.
QualType Underlying;
bool IsSugar = false;
@@ -94,50 +70,56 @@ break; \
}
#include "clang/AST/TypeNodes.def"
}
-
+
// If it wasn't sugared, we're done.
if (!IsSugar)
break;
-
+
// If the desugared type is a vector type, we don't want to expand
// it, it will turn into an attribute mess. People want their "vec4".
if (isa<VectorType>(Underlying))
break;
-
+
// Don't desugar through the primary typedef of an anonymous type.
if (isa<TagType>(Underlying) && isa<TypedefType>(QT))
if (cast<TagType>(Underlying)->getDecl()->getTypedefForAnonDecl() ==
cast<TypedefType>(QT)->getDecl())
break;
-
- // Otherwise, we're tearing through something opaque; note that
- // we'll eventually need an a.k.a. clause and keep going.
- AKA = true;
+
+ // Record that we actually looked through an opaque type here.
+ ShouldAKA = true;
QT = Underlying;
- continue;
}
-
- // If we never tore through opaque sugar, don't print aka.
- if (!AKA) return false;
-
- // If we did, check to see if we already desugared this type in this
- // diagnostic. If so, don't do it again.
- for (unsigned i = 0; i != NumPrevArgs; ++i) {
- // TODO: Handle ak_declcontext case.
- if (PrevArgs[i].first == Diagnostic::ak_qualtype) {
- void *Ptr = (void*)PrevArgs[i].second;
- QualType PrevTy(QualType::getFromOpaquePtr(Ptr));
- if (PrevTy == InputTy)
- return false;
- }
+
+ // If we have a pointer-like type, desugar the pointee as well.
+ // FIXME: Handle other pointer-like types.
+ if (const PointerType *Ty = QT->getAs<PointerType>()) {
+ QT = Context.getPointerType(Desugar(Context, Ty->getPointeeType(),
+ ShouldAKA));
+ } else if (const LValueReferenceType *Ty = QT->getAs<LValueReferenceType>()) {
+ QT = Context.getLValueReferenceType(Desugar(Context, Ty->getPointeeType(),
+ ShouldAKA));
}
-
- DesugaredQT = Qc.apply(QT);
- return true;
+
+ return QC.apply(QT);
}
/// \brief Convert the given type to a string suitable for printing as part of
-/// a diagnostic.
+/// a diagnostic.
+///
+/// There are three main criteria when determining whether we should have an
+/// a.k.a. clause when pretty-printing a type:
+///
+/// 1) Some types provide very minimal sugar that doesn't impede the
+/// user's understanding --- for example, elaborated type
+/// specifiers. If this is all the sugar we see, we don't want an
+/// a.k.a. clause.
+/// 2) Some types are technically sugared but are much more familiar
+/// when seen in their sugared form --- for example, va_list,
+/// vector types, and the magic Objective C types. We don't
+/// want to desugar these, even if we do produce an a.k.a. clause.
+/// 3) Some types may have already been desugared previously in this diagnostic.
+/// if this is the case, doing another "aka" would just be clutter.
///
/// \param Context the context in which the type was allocated
/// \param Ty the type to print
@@ -147,18 +129,35 @@ ConvertTypeToDiagnosticString(ASTContext &Context, QualType Ty,
unsigned NumPrevArgs) {
// FIXME: Playing with std::string is really slow.
std::string S = Ty.getAsString(Context.PrintingPolicy);
-
+
+ // Check to see if we already desugared this type in this
+ // diagnostic. If so, don't do it again.
+ bool Repeated = false;
+ for (unsigned i = 0; i != NumPrevArgs; ++i) {
+ // TODO: Handle ak_declcontext case.
+ if (PrevArgs[i].first == Diagnostic::ak_qualtype) {
+ void *Ptr = (void*)PrevArgs[i].second;
+ QualType PrevTy(QualType::getFromOpaquePtr(Ptr));
+ if (PrevTy == Ty) {
+ Repeated = true;
+ break;
+ }
+ }
+ }
+
// Consider producing an a.k.a. clause if removing all the direct
// sugar gives us something "significantly different".
-
- QualType DesugaredTy;
- if (ShouldAKA(Context, Ty, PrevArgs, NumPrevArgs, DesugaredTy)) {
- S = "'"+S+"' (aka '";
- S += DesugaredTy.getAsString(Context.PrintingPolicy);
- S += "')";
- return S;
+ if (!Repeated) {
+ bool ShouldAKA = false;
+ QualType DesugaredTy = Desugar(Context, Ty, ShouldAKA);
+ if (ShouldAKA) {
+ S = "'"+S+"' (aka '";
+ S += DesugaredTy.getAsString(Context.PrintingPolicy);
+ S += "')";
+ return S;
+ }
}
-
+
S = "'" + S + "'";
return S;
}
diff --git a/lib/AST/ASTImporter.cpp b/lib/AST/ASTImporter.cpp
index ae09d7978ea5..6ed08d1e1e29 100644
--- a/lib/AST/ASTImporter.cpp
+++ b/lib/AST/ASTImporter.cpp
@@ -68,13 +68,13 @@ namespace {
// FIXME: DependentDecltypeType
QualType VisitRecordType(RecordType *T);
QualType VisitEnumType(EnumType *T);
- QualType VisitElaboratedType(ElaboratedType *T);
// FIXME: TemplateTypeParmType
// FIXME: SubstTemplateTypeParmType
// FIXME: TemplateSpecializationType
- QualType VisitQualifiedNameType(QualifiedNameType *T);
+ QualType VisitElaboratedType(ElaboratedType *T);
// FIXME: DependentNameType
QualType VisitObjCInterfaceType(ObjCInterfaceType *T);
+ QualType VisitObjCObjectType(ObjCObjectType *T);
QualType VisitObjCObjectPointerType(ObjCObjectPointerType *T);
// Importing declarations
@@ -532,19 +532,7 @@ static bool IsStructurallyEquivalent(StructuralEquivalenceContext &Context,
cast<TagType>(T2)->getDecl()))
return false;
break;
-
- case Type::Elaborated: {
- const ElaboratedType *Elab1 = cast<ElaboratedType>(T1);
- const ElaboratedType *Elab2 = cast<ElaboratedType>(T2);
- if (Elab1->getTagKind() != Elab2->getTagKind())
- return false;
- if (!IsStructurallyEquivalent(Context,
- Elab1->getUnderlyingType(),
- Elab2->getUnderlyingType()))
- return false;
- break;
- }
-
+
case Type::TemplateTypeParm: {
const TemplateTypeParmType *Parm1 = cast<TemplateTypeParmType>(T1);
const TemplateTypeParmType *Parm2 = cast<TemplateTypeParmType>(T2);
@@ -594,16 +582,19 @@ static bool IsStructurallyEquivalent(StructuralEquivalenceContext &Context,
break;
}
- case Type::QualifiedName: {
- const QualifiedNameType *Qual1 = cast<QualifiedNameType>(T1);
- const QualifiedNameType *Qual2 = cast<QualifiedNameType>(T2);
+ case Type::Elaborated: {
+ const ElaboratedType *Elab1 = cast<ElaboratedType>(T1);
+ const ElaboratedType *Elab2 = cast<ElaboratedType>(T2);
+ // CHECKME: what if a keyword is ETK_None or ETK_typename ?
+ if (Elab1->getKeyword() != Elab2->getKeyword())
+ return false;
if (!IsStructurallyEquivalent(Context,
- Qual1->getQualifier(),
- Qual2->getQualifier()))
+ Elab1->getQualifier(),
+ Elab2->getQualifier()))
return false;
if (!IsStructurallyEquivalent(Context,
- Qual1->getNamedType(),
- Qual2->getNamedType()))
+ Elab1->getNamedType(),
+ Elab2->getNamedType()))
return false;
break;
}
@@ -642,12 +633,22 @@ static bool IsStructurallyEquivalent(StructuralEquivalenceContext &Context,
if (!IsStructurallyEquivalent(Context,
Iface1->getDecl(), Iface2->getDecl()))
return false;
- if (Iface1->getNumProtocols() != Iface2->getNumProtocols())
+ break;
+ }
+
+ case Type::ObjCObject: {
+ const ObjCObjectType *Obj1 = cast<ObjCObjectType>(T1);
+ const ObjCObjectType *Obj2 = cast<ObjCObjectType>(T2);
+ if (!IsStructurallyEquivalent(Context,
+ Obj1->getBaseType(),
+ Obj2->getBaseType()))
+ return false;
+ if (Obj1->getNumProtocols() != Obj2->getNumProtocols())
return false;
- for (unsigned I = 0, N = Iface1->getNumProtocols(); I != N; ++I) {
+ for (unsigned I = 0, N = Obj1->getNumProtocols(); I != N; ++I) {
if (!IsStructurallyEquivalent(Context,
- Iface1->getProtocol(I),
- Iface2->getProtocol(I)))
+ Obj1->getProtocol(I),
+ Obj2->getProtocol(I)))
return false;
}
break;
@@ -660,14 +661,6 @@ static bool IsStructurallyEquivalent(StructuralEquivalenceContext &Context,
Ptr1->getPointeeType(),
Ptr2->getPointeeType()))
return false;
- if (Ptr1->getNumProtocols() != Ptr2->getNumProtocols())
- return false;
- for (unsigned I = 0, N = Ptr1->getNumProtocols(); I != N; ++I) {
- if (!IsStructurallyEquivalent(Context,
- Ptr1->getProtocol(I),
- Ptr2->getProtocol(I)))
- return false;
- }
break;
}
@@ -1293,24 +1286,20 @@ QualType ASTNodeImporter::VisitEnumType(EnumType *T) {
}
QualType ASTNodeImporter::VisitElaboratedType(ElaboratedType *T) {
- QualType ToUnderlyingType = Importer.Import(T->getUnderlyingType());
- if (ToUnderlyingType.isNull())
- return QualType();
-
- return Importer.getToContext().getElaboratedType(ToUnderlyingType,
- T->getTagKind());
-}
-
-QualType ASTNodeImporter::VisitQualifiedNameType(QualifiedNameType *T) {
- NestedNameSpecifier *ToQualifier = Importer.Import(T->getQualifier());
- if (!ToQualifier)
- return QualType();
+ NestedNameSpecifier *ToQualifier = 0;
+ // Note: the qualifier in an ElaboratedType is optional.
+ if (T->getQualifier()) {
+ ToQualifier = Importer.Import(T->getQualifier());
+ if (!ToQualifier)
+ return QualType();
+ }
QualType ToNamedType = Importer.Import(T->getNamedType());
if (ToNamedType.isNull())
return QualType();
- return Importer.getToContext().getQualifiedNameType(ToQualifier, ToNamedType);
+ return Importer.getToContext().getElaboratedType(T->getKeyword(),
+ ToQualifier, ToNamedType);
}
QualType ASTNodeImporter::VisitObjCInterfaceType(ObjCInterfaceType *T) {
@@ -1319,8 +1308,16 @@ QualType ASTNodeImporter::VisitObjCInterfaceType(ObjCInterfaceType *T) {
if (!Class)
return QualType();
+ return Importer.getToContext().getObjCInterfaceType(Class);
+}
+
+QualType ASTNodeImporter::VisitObjCObjectType(ObjCObjectType *T) {
+ QualType ToBaseType = Importer.Import(T->getBaseType());
+ if (ToBaseType.isNull())
+ return QualType();
+
llvm::SmallVector<ObjCProtocolDecl *, 4> Protocols;
- for (ObjCInterfaceType::qual_iterator P = T->qual_begin(),
+ for (ObjCObjectType::qual_iterator P = T->qual_begin(),
PEnd = T->qual_end();
P != PEnd; ++P) {
ObjCProtocolDecl *Protocol
@@ -1330,9 +1327,9 @@ QualType ASTNodeImporter::VisitObjCInterfaceType(ObjCInterfaceType *T) {
Protocols.push_back(Protocol);
}
- return Importer.getToContext().getObjCInterfaceType(Class,
- Protocols.data(),
- Protocols.size());
+ return Importer.getToContext().getObjCObjectType(ToBaseType,
+ Protocols.data(),
+ Protocols.size());
}
QualType ASTNodeImporter::VisitObjCObjectPointerType(ObjCObjectPointerType *T) {
@@ -1340,20 +1337,7 @@ QualType ASTNodeImporter::VisitObjCObjectPointerType(ObjCObjectPointerType *T) {
if (ToPointeeType.isNull())
return QualType();
- llvm::SmallVector<ObjCProtocolDecl *, 4> Protocols;
- for (ObjCObjectPointerType::qual_iterator P = T->qual_begin(),
- PEnd = T->qual_end();
- P != PEnd; ++P) {
- ObjCProtocolDecl *Protocol
- = dyn_cast_or_null<ObjCProtocolDecl>(Importer.Import(*P));
- if (!Protocol)
- return QualType();
- Protocols.push_back(Protocol);
- }
-
- return Importer.getToContext().getObjCObjectPointerType(ToPointeeType,
- Protocols.data(),
- Protocols.size());
+ return Importer.getToContext().getObjCObjectPointerType(ToPointeeType);
}
//----------------------------------------------------------------------------
@@ -1617,7 +1601,12 @@ Decl *ASTNodeImporter::VisitEnumDecl(EnumDecl *D) {
D2->startDefinition();
ImportDeclContext(D);
- D2->completeDefinition(T, ToPromotionType);
+
+ // FIXME: we might need to merge the number of positive or negative bits
+ // if the enumerator lists don't match.
+ D2->completeDefinition(T, ToPromotionType,
+ D->getNumPositiveBits(),
+ D->getNumNegativeBits());
}
return D2;
@@ -2961,7 +2950,7 @@ TypeSourceInfo *ASTImporter::Import(TypeSourceInfo *FromTSI) {
return 0;
return ToContext.getTrivialTypeSourceInfo(T,
- FromTSI->getTypeLoc().getFullSourceRange().getBegin());
+ FromTSI->getTypeLoc().getSourceRange().getBegin());
}
Decl *ASTImporter::Import(Decl *FromD) {
diff --git a/lib/AST/AttrImpl.cpp b/lib/AST/AttrImpl.cpp
index 423aa065e57c..0fab22caced8 100644
--- a/lib/AST/AttrImpl.cpp
+++ b/lib/AST/AttrImpl.cpp
@@ -74,6 +74,7 @@ void NonNullAttr::Destroy(ASTContext &C) {
// FIXME: Can we use variadic macro to define DEF_SIMPLE_ATTR_CLONE for
// "non-simple" classes?
+DEF_SIMPLE_ATTR_CLONE(AlignMac68k)
DEF_SIMPLE_ATTR_CLONE(AlwaysInline)
DEF_SIMPLE_ATTR_CLONE(AnalyzerNoReturn)
DEF_SIMPLE_ATTR_CLONE(BaseCheck)
@@ -100,6 +101,7 @@ DEF_SIMPLE_ATTR_CLONE(Override)
DEF_SIMPLE_ATTR_CLONE(Packed)
DEF_SIMPLE_ATTR_CLONE(Pure)
DEF_SIMPLE_ATTR_CLONE(StdCall)
+DEF_SIMPLE_ATTR_CLONE(ThisCall)
DEF_SIMPLE_ATTR_CLONE(TransparentUnion)
DEF_SIMPLE_ATTR_CLONE(Unavailable)
DEF_SIMPLE_ATTR_CLONE(Unused)
@@ -110,8 +112,8 @@ DEF_SIMPLE_ATTR_CLONE(WeakImport)
DEF_SIMPLE_ATTR_CLONE(WeakRef)
DEF_SIMPLE_ATTR_CLONE(X86ForceAlignArgPointer)
-Attr* PragmaPackAttr::clone(ASTContext &C) const {
- return ::new (C) PragmaPackAttr(Alignment);
+Attr* MaxFieldAlignmentAttr::clone(ASTContext &C) const {
+ return ::new (C) MaxFieldAlignmentAttr(Alignment);
}
Attr* AlignedAttr::clone(ASTContext &C) const {
@@ -142,6 +144,10 @@ Attr *IBOutletAttr::clone(ASTContext &C) const {
return ::new (C) IBOutletAttr;
}
+Attr *IBOutletCollectionAttr::clone(ASTContext &C) const {
+ return ::new (C) IBOutletCollectionAttr(D);
+}
+
Attr *IBActionAttr::clone(ASTContext &C) const {
return ::new (C) IBActionAttr;
}
diff --git a/lib/AST/CMakeLists.txt b/lib/AST/CMakeLists.txt
index 91aaddc9a481..bce3646feedb 100644
--- a/lib/AST/CMakeLists.txt
+++ b/lib/AST/CMakeLists.txt
@@ -39,4 +39,4 @@ add_clang_library(clangAST
TypePrinter.cpp
)
-add_dependencies(clangAST ClangDiagnosticAST)
+add_dependencies(clangAST ClangDiagnosticAST ClangStmtNodes)
diff --git a/lib/AST/CXXInheritance.cpp b/lib/AST/CXXInheritance.cpp
index a9f223045864..d616e42e0076 100644
--- a/lib/AST/CXXInheritance.cpp
+++ b/lib/AST/CXXInheritance.cpp
@@ -49,9 +49,8 @@ CXXBasePaths::decl_iterator CXXBasePaths::found_decls_end() {
/// ambiguous, i.e., there are two or more paths that refer to
/// different base class subobjects of the same type. BaseType must be
/// an unqualified, canonical class type.
-bool CXXBasePaths::isAmbiguous(QualType BaseType) {
- assert(BaseType.isCanonical() && "Base type must be the canonical type");
- assert(BaseType.hasQualifiers() == 0 && "Base type must be unqualified");
+bool CXXBasePaths::isAmbiguous(CanQualType BaseType) {
+ BaseType = BaseType.getUnqualifiedType();
std::pair<bool, unsigned>& Subobjects = ClassSubobjects[BaseType];
return Subobjects.second + (Subobjects.first? 1 : 0) > 1;
}
diff --git a/lib/AST/Decl.cpp b/lib/AST/Decl.cpp
index ffe49671d8a3..ffdcb471d082 100644
--- a/lib/AST/Decl.cpp
+++ b/lib/AST/Decl.cpp
@@ -23,16 +23,11 @@
#include "clang/AST/PrettyPrinter.h"
#include "clang/Basic/Builtins.h"
#include "clang/Basic/IdentifierTable.h"
-#include "clang/Parse/DeclSpec.h"
+#include "clang/Basic/Specifiers.h"
#include "llvm/Support/ErrorHandling.h"
using namespace clang;
-/// \brief Return the TypeLoc wrapper for the type source info.
-TypeLoc TypeSourceInfo::getTypeLoc() const {
- return TypeLoc(Ty, (void*)(this + 1));
-}
-
//===----------------------------------------------------------------------===//
// NamedDecl Implementation
//===----------------------------------------------------------------------===//
@@ -541,7 +536,7 @@ SourceLocation DeclaratorDecl::getTypeSpecStartLoc() const {
while (true) {
TypeLoc NextTL = TL.getNextTypeLoc();
if (!NextTL)
- return TL.getSourceRange().getBegin();
+ return TL.getLocalSourceRange().getBegin();
TL = NextTL;
}
}
@@ -1224,9 +1219,8 @@ FunctionDecl::setInstantiationOfMemberFunction(FunctionDecl *FD,
}
bool FunctionDecl::isImplicitlyInstantiable() const {
- // If this function already has a definition or is invalid, it can't be
- // implicitly instantiated.
- if (isInvalidDecl() || getBody())
+ // If the function is invalid, it can't be implicitly instantiated.
+ if (isInvalidDecl())
return false;
switch (getTemplateSpecializationKind()) {
@@ -1295,11 +1289,22 @@ FunctionDecl::getTemplateSpecializationArgs() const {
return 0;
}
+const TemplateArgumentListInfo *
+FunctionDecl::getTemplateSpecializationArgsAsWritten() const {
+ if (FunctionTemplateSpecializationInfo *Info
+ = TemplateOrSpecialization
+ .dyn_cast<FunctionTemplateSpecializationInfo*>()) {
+ return Info->TemplateArgumentsAsWritten;
+ }
+ return 0;
+}
+
void
FunctionDecl::setFunctionTemplateSpecialization(FunctionTemplateDecl *Template,
const TemplateArgumentList *TemplateArgs,
void *InsertPos,
- TemplateSpecializationKind TSK) {
+ TemplateSpecializationKind TSK,
+ const TemplateArgumentListInfo *TemplateArgsAsWritten) {
assert(TSK != TSK_Undeclared &&
"Must specify the type of function template specialization");
FunctionTemplateSpecializationInfo *Info
@@ -1311,6 +1316,7 @@ FunctionDecl::setFunctionTemplateSpecialization(FunctionTemplateDecl *Template,
Info->Template.setPointer(Template);
Info->Template.setInt(TSK - 1);
Info->TemplateArguments = TemplateArgs;
+ Info->TemplateArgumentsAsWritten = TemplateArgsAsWritten;
TemplateOrSpecialization = Info;
// Insert this function template specialization into the set of known
@@ -1475,6 +1481,12 @@ TagDecl* TagDecl::getCanonicalDecl() {
return getFirstDeclaration();
}
+void TagDecl::setTypedefForAnonDecl(TypedefDecl *TDD) {
+ TypedefDeclOrQualifier = TDD;
+ if (TypeForDecl)
+ TypeForDecl->ClearLinkageCache();
+}
+
void TagDecl::startDefinition() {
if (TagType *TagT = const_cast<TagType *>(TypeForDecl->getAs<TagType>())) {
TagT->decl.setPointer(this);
@@ -1509,6 +1521,7 @@ void TagDecl::completeDefinition() {
TypeForDecl->getAs<InjectedClassNameType>())) {
assert(Injected->Decl == this &&
"Attempt to redefine a class template definition?");
+ (void)Injected;
}
}
@@ -1524,16 +1537,6 @@ TagDecl* TagDecl::getDefinition() const {
return 0;
}
-TagDecl::TagKind TagDecl::getTagKindForTypeSpec(unsigned TypeSpec) {
- switch (TypeSpec) {
- default: llvm_unreachable("unexpected type specifier");
- case DeclSpec::TST_struct: return TK_struct;
- case DeclSpec::TST_class: return TK_class;
- case DeclSpec::TST_union: return TK_union;
- case DeclSpec::TST_enum: return TK_enum;
- }
-}
-
void TagDecl::setQualifierInfo(NestedNameSpecifier *Qualifier,
SourceRange QualifierRange) {
if (Qualifier) {
@@ -1571,10 +1574,14 @@ void EnumDecl::Destroy(ASTContext& C) {
}
void EnumDecl::completeDefinition(QualType NewType,
- QualType NewPromotionType) {
+ QualType NewPromotionType,
+ unsigned NumPositiveBits,
+ unsigned NumNegativeBits) {
assert(!isDefinition() && "Cannot redefine enums!");
IntegerType = NewType;
PromotionType = NewPromotionType;
+ setNumPositiveBits(NumPositiveBits);
+ setNumNegativeBits(NumNegativeBits);
TagDecl::completeDefinition();
}
@@ -1620,6 +1627,17 @@ void RecordDecl::completeDefinition() {
TagDecl::completeDefinition();
}
+ValueDecl *RecordDecl::getAnonymousStructOrUnionObject() {
+ // Force the decl chain to come into existence properly.
+ if (!getNextDeclInContext()) getParent()->decls_begin();
+
+ assert(isAnonymousStructOrUnion());
+ ValueDecl *D = cast<ValueDecl>(getNextDeclInContext());
+ assert(D->getType()->isRecordType());
+ assert(D->getType()->getAs<RecordType>()->getDecl() == this);
+ return D;
+}
+
//===----------------------------------------------------------------------===//
// BlockDecl Implementation
//===----------------------------------------------------------------------===//
diff --git a/lib/AST/DeclBase.cpp b/lib/AST/DeclBase.cpp
index b5aec0c5125c..42a372632099 100644
--- a/lib/AST/DeclBase.cpp
+++ b/lib/AST/DeclBase.cpp
@@ -811,12 +811,12 @@ DeclContext::lookup(DeclarationName Name) {
buildLookup(this);
if (!LookupPtr)
- return lookup_result(0, 0);
+ return lookup_result(lookup_iterator(0), lookup_iterator(0));
}
StoredDeclsMap::iterator Pos = LookupPtr->find(Name);
if (Pos == LookupPtr->end())
- return lookup_result(0, 0);
+ return lookup_result(lookup_iterator(0), lookup_iterator(0));
return Pos->second.getLookupResult(getParentASTContext());
}
diff --git a/lib/AST/DeclCXX.cpp b/lib/AST/DeclCXX.cpp
index 68f4a821e689..cd7afd98b63d 100644
--- a/lib/AST/DeclCXX.cpp
+++ b/lib/AST/DeclCXX.cpp
@@ -137,7 +137,7 @@ CXXRecordDecl::setBases(CXXBaseSpecifier const * const *Bases,
data().VBases[I] =
CXXBaseSpecifier(VBaseClassDecl->getSourceRange(), true,
- VBaseClassDecl->getTagKind() == RecordDecl::TK_class,
+ VBaseClassDecl->getTagKind() == TTK_Class,
VBases[I]->getAccessSpecifier(), VBaseType);
}
}
@@ -700,8 +700,9 @@ CXXBaseOrMemberInitializer::
CXXBaseOrMemberInitializer(ASTContext &Context,
TypeSourceInfo *TInfo, bool IsVirtual,
SourceLocation L, Expr *Init, SourceLocation R)
- : BaseOrMember(TInfo), Init(Init), AnonUnionMember(0), IsVirtual(IsVirtual),
- LParenLoc(L), RParenLoc(R)
+ : BaseOrMember(TInfo), Init(Init), AnonUnionMember(0),
+ LParenLoc(L), RParenLoc(R), IsVirtual(IsVirtual), IsWritten(false),
+ SourceOrderOrNumArrayIndices(0)
{
}
@@ -709,14 +710,46 @@ CXXBaseOrMemberInitializer::
CXXBaseOrMemberInitializer(ASTContext &Context,
FieldDecl *Member, SourceLocation MemberLoc,
SourceLocation L, Expr *Init, SourceLocation R)
+ : BaseOrMember(Member), MemberLocation(MemberLoc), Init(Init),
+ AnonUnionMember(0), LParenLoc(L), RParenLoc(R), IsVirtual(false),
+ IsWritten(false), SourceOrderOrNumArrayIndices(0)
+{
+}
+
+CXXBaseOrMemberInitializer::
+CXXBaseOrMemberInitializer(ASTContext &Context,
+ FieldDecl *Member, SourceLocation MemberLoc,
+ SourceLocation L, Expr *Init, SourceLocation R,
+ VarDecl **Indices,
+ unsigned NumIndices)
: BaseOrMember(Member), MemberLocation(MemberLoc), Init(Init),
- AnonUnionMember(0), LParenLoc(L), RParenLoc(R)
+ AnonUnionMember(0), LParenLoc(L), RParenLoc(R), IsVirtual(false),
+ IsWritten(false), SourceOrderOrNumArrayIndices(NumIndices)
{
+ VarDecl **MyIndices = reinterpret_cast<VarDecl **> (this + 1);
+ memcpy(MyIndices, Indices, NumIndices * sizeof(VarDecl *));
+}
+
+CXXBaseOrMemberInitializer *
+CXXBaseOrMemberInitializer::Create(ASTContext &Context,
+ FieldDecl *Member,
+ SourceLocation MemberLoc,
+ SourceLocation L,
+ Expr *Init,
+ SourceLocation R,
+ VarDecl **Indices,
+ unsigned NumIndices) {
+ void *Mem = Context.Allocate(sizeof(CXXBaseOrMemberInitializer) +
+ sizeof(VarDecl *) * NumIndices,
+ llvm::alignof<CXXBaseOrMemberInitializer>());
+ return new (Mem) CXXBaseOrMemberInitializer(Context, Member, MemberLoc,
+ L, Init, R, Indices, NumIndices);
}
void CXXBaseOrMemberInitializer::Destroy(ASTContext &Context) {
if (Init)
Init->Destroy(Context);
+ // FIXME: Destroy indices
this->~CXXBaseOrMemberInitializer();
}
@@ -745,7 +778,7 @@ SourceLocation CXXBaseOrMemberInitializer::getSourceLocation() const {
if (isMemberInitializer())
return getMemberLocation();
- return getBaseClassLoc().getSourceRange().getBegin();
+ return getBaseClassLoc().getLocalSourceRange().getBegin();
}
SourceRange CXXBaseOrMemberInitializer::getSourceRange() const {
@@ -753,6 +786,12 @@ SourceRange CXXBaseOrMemberInitializer::getSourceRange() const {
}
CXXConstructorDecl *
+CXXConstructorDecl::Create(ASTContext &C, EmptyShell Empty) {
+ return new (C) CXXConstructorDecl(0, SourceLocation(), DeclarationName(),
+ QualType(), 0, false, false, false);
+}
+
+CXXConstructorDecl *
CXXConstructorDecl::Create(ASTContext &C, CXXRecordDecl *RD,
SourceLocation L, DeclarationName N,
QualType T, TypeSourceInfo *TInfo,
@@ -855,6 +894,12 @@ bool CXXConstructorDecl::isCopyConstructorLikeSpecialization() const {
}
CXXDestructorDecl *
+CXXDestructorDecl::Create(ASTContext &C, EmptyShell Empty) {
+ return new (C) CXXDestructorDecl(0, SourceLocation(), DeclarationName(),
+ QualType(), false, false);
+}
+
+CXXDestructorDecl *
CXXDestructorDecl::Create(ASTContext &C, CXXRecordDecl *RD,
SourceLocation L, DeclarationName N,
QualType T, bool isInline,
@@ -871,6 +916,12 @@ CXXConstructorDecl::Destroy(ASTContext& C) {
}
CXXConversionDecl *
+CXXConversionDecl::Create(ASTContext &C, EmptyShell Empty) {
+ return new (C) CXXConversionDecl(0, SourceLocation(), DeclarationName(),
+ QualType(), 0, false, false);
+}
+
+CXXConversionDecl *
CXXConversionDecl::Create(ASTContext &C, CXXRecordDecl *RD,
SourceLocation L, DeclarationName N,
QualType T, TypeSourceInfo *TInfo,
@@ -908,6 +959,12 @@ NamespaceDecl *UsingDirectiveDecl::getNominatedNamespace() {
return cast_or_null<NamespaceDecl>(NominatedNamespace);
}
+void UsingDirectiveDecl::setNominatedNamespace(NamedDecl* ND) {
+ assert((isa<NamespaceDecl>(ND) || isa<NamespaceAliasDecl>(ND)) &&
+ "expected a NamespaceDecl or NamespaceAliasDecl");
+ NominatedNamespace = ND;
+}
+
NamespaceAliasDecl *NamespaceAliasDecl::Create(ASTContext &C, DeclContext *DC,
SourceLocation L,
SourceLocation AliasLoc,
diff --git a/lib/AST/DeclTemplate.cpp b/lib/AST/DeclTemplate.cpp
index c498dea17703..26e291c94f64 100644
--- a/lib/AST/DeclTemplate.cpp
+++ b/lib/AST/DeclTemplate.cpp
@@ -94,6 +94,10 @@ TemplateDecl::~TemplateDecl() {
// FunctionTemplateDecl Implementation
//===----------------------------------------------------------------------===//
+void FunctionTemplateDecl::DeallocateCommon(void *Ptr) {
+ static_cast<Common *>(Ptr)->~Common();
+}
+
FunctionTemplateDecl *FunctionTemplateDecl::Create(ASTContext &C,
DeclContext *DC,
SourceLocation L,
@@ -129,8 +133,9 @@ FunctionTemplateDecl::Common *FunctionTemplateDecl::getCommonPtr() {
First = First->getPreviousDeclaration();
if (First->CommonOrPrev.isNull()) {
- // FIXME: Allocate with the ASTContext
- First->CommonOrPrev = new Common;
+ Common *CommonPtr = new (getASTContext()) Common;
+ getASTContext().AddDeallocation(DeallocateCommon, CommonPtr);
+ First->CommonOrPrev = CommonPtr;
}
return First->CommonOrPrev.get<Common*>();
}
@@ -139,6 +144,10 @@ FunctionTemplateDecl::Common *FunctionTemplateDecl::getCommonPtr() {
// ClassTemplateDecl Implementation
//===----------------------------------------------------------------------===//
+void ClassTemplateDecl::DeallocateCommon(void *Ptr) {
+ static_cast<Common *>(Ptr)->~Common();
+}
+
ClassTemplateDecl *ClassTemplateDecl::getCanonicalDecl() {
ClassTemplateDecl *Template = this;
while (Template->getPreviousDeclaration())
@@ -156,8 +165,10 @@ ClassTemplateDecl *ClassTemplateDecl::Create(ASTContext &C,
Common *CommonPtr;
if (PrevDecl)
CommonPtr = PrevDecl->CommonPtr;
- else
+ else {
CommonPtr = new (C) Common;
+ C.AddDeallocation(DeallocateCommon, CommonPtr);
+ }
return new (C) ClassTemplateDecl(DC, L, Name, Params, Decl, PrevDecl,
CommonPtr);
@@ -259,7 +270,7 @@ TemplateTypeParmDecl::Create(ASTContext &C, DeclContext *DC,
}
SourceLocation TemplateTypeParmDecl::getDefaultArgumentLoc() const {
- return DefaultArgument->getTypeLoc().getFullSourceRange().getBegin();
+ return DefaultArgument->getTypeLoc().getSourceRange().getBegin();
}
unsigned TemplateTypeParmDecl::getDepth() const {
@@ -303,22 +314,14 @@ TemplateTemplateParmDecl::Create(ASTContext &C, DeclContext *DC,
// TemplateArgumentListBuilder Implementation
//===----------------------------------------------------------------------===//
-void TemplateArgumentListBuilder::Append(const TemplateArgument& Arg) {
- switch (Arg.getKind()) {
- default: break;
- case TemplateArgument::Type:
- assert(Arg.getAsType().isCanonical() && "Type must be canonical!");
- break;
- }
-
- assert(NumFlatArgs < MaxFlatArgs && "Argument list builder is full!");
+void TemplateArgumentListBuilder::Append(const TemplateArgument &Arg) {
+ assert((Arg.getKind() != TemplateArgument::Type ||
+ Arg.getAsType().isCanonical()) && "Type must be canonical!");
+ assert(FlatArgs.size() < MaxFlatArgs && "Argument list builder is full!");
assert(!StructuredArgs &&
"Can't append arguments when an argument pack has been added!");
- if (!FlatArgs)
- FlatArgs = new TemplateArgument[MaxFlatArgs];
-
- FlatArgs[NumFlatArgs++] = Arg;
+ FlatArgs.push_back(Arg);
}
void TemplateArgumentListBuilder::BeginPack() {
@@ -326,7 +329,7 @@ void TemplateArgumentListBuilder::BeginPack() {
assert(!StructuredArgs && "Argument list already contains a pack!");
AddingToPack = true;
- PackBeginIndex = NumFlatArgs;
+ PackBeginIndex = FlatArgs.size();
}
void TemplateArgumentListBuilder::EndPack() {
@@ -335,6 +338,7 @@ void TemplateArgumentListBuilder::EndPack() {
AddingToPack = false;
+ // FIXME: This is a memory leak!
StructuredArgs = new TemplateArgument[MaxStructuredArgs];
// First copy the flat entries over to the list (if any)
@@ -346,22 +350,14 @@ void TemplateArgumentListBuilder::EndPack() {
// Next, set the pack.
TemplateArgument *PackArgs = 0;
unsigned NumPackArgs = NumFlatArgs - PackBeginIndex;
+ // FIXME: NumPackArgs shouldn't be negative here???
if (NumPackArgs)
- PackArgs = &FlatArgs[PackBeginIndex];
+ PackArgs = FlatArgs.data()+PackBeginIndex;
StructuredArgs[NumStructuredArgs++].setArgumentPack(PackArgs, NumPackArgs,
/*CopyArgs=*/false);
}
-void TemplateArgumentListBuilder::ReleaseArgs() {
- FlatArgs = 0;
- NumFlatArgs = 0;
- MaxFlatArgs = 0;
- StructuredArgs = 0;
- NumStructuredArgs = 0;
- MaxStructuredArgs = 0;
-}
-
//===----------------------------------------------------------------------===//
// TemplateArgumentList Implementation
//===----------------------------------------------------------------------===//
@@ -376,35 +372,56 @@ TemplateArgumentList::TemplateArgumentList(ASTContext &Context,
if (!TakeArgs)
return;
- if (Builder.getStructuredArguments() == Builder.getFlatArguments())
+ // If this does take ownership of the arguments, then we have to new them
+ // and copy over.
+ TemplateArgument *NewArgs =
+ new (Context) TemplateArgument[Builder.flatSize()];
+ std::copy(Builder.getFlatArguments(),
+ Builder.getFlatArguments()+Builder.flatSize(), NewArgs);
+ FlatArguments.setPointer(NewArgs);
+
+ // Just reuse the structured and flat arguments array if possible.
+ if (Builder.getStructuredArguments() == Builder.getFlatArguments()) {
+ StructuredArguments.setPointer(NewArgs);
StructuredArguments.setInt(0);
- Builder.ReleaseArgs();
+ } else {
+ TemplateArgument *NewSArgs =
+ new (Context) TemplateArgument[Builder.flatSize()];
+ std::copy(Builder.getFlatArguments(),
+ Builder.getFlatArguments()+Builder.flatSize(), NewSArgs);
+ StructuredArguments.setPointer(NewSArgs);
+ }
}
-TemplateArgumentList::TemplateArgumentList(const TemplateArgumentList &Other)
- : FlatArguments(Other.FlatArguments.getPointer(), 1),
- NumFlatArguments(Other.flat_size()),
- StructuredArguments(Other.StructuredArguments.getPointer(), 1),
- NumStructuredArguments(Other.NumStructuredArguments) { }
+/// Produces a shallow copy of the given template argument list. This
+/// assumes that the input argument list outlives it. This takes the list as
+/// a pointer to avoid looking like a copy constructor, since this really
+/// really isn't safe to use that way.
+TemplateArgumentList::TemplateArgumentList(const TemplateArgumentList *Other)
+ : FlatArguments(Other->FlatArguments.getPointer(), false),
+ NumFlatArguments(Other->flat_size()),
+ StructuredArguments(Other->StructuredArguments.getPointer(), false),
+ NumStructuredArguments(Other->NumStructuredArguments) { }
-TemplateArgumentList::~TemplateArgumentList() {
- // FIXME: Deallocate template arguments
+void TemplateArgumentList::Destroy(ASTContext &C) {
+ if (FlatArguments.getInt())
+ C.Deallocate((void*)FlatArguments.getPointer());
+ if (StructuredArguments.getInt())
+ C.Deallocate((void*)StructuredArguments.getPointer());
}
+TemplateArgumentList::~TemplateArgumentList() {}
+
//===----------------------------------------------------------------------===//
// ClassTemplateSpecializationDecl Implementation
//===----------------------------------------------------------------------===//
ClassTemplateSpecializationDecl::
-ClassTemplateSpecializationDecl(ASTContext &Context, Kind DK,
+ClassTemplateSpecializationDecl(ASTContext &Context, Kind DK, TagKind TK,
DeclContext *DC, SourceLocation L,
ClassTemplateDecl *SpecializedTemplate,
TemplateArgumentListBuilder &Builder,
ClassTemplateSpecializationDecl *PrevDecl)
- : CXXRecordDecl(DK,
- SpecializedTemplate->getTemplatedDecl()->getTagKind(),
- DC, L,
- // FIXME: Should we use DeclarationName for the name of
- // class template specializations?
+ : CXXRecordDecl(DK, TK, DC, L,
SpecializedTemplate->getIdentifier(),
PrevDecl),
SpecializedTemplate(SpecializedTemplate),
@@ -414,7 +431,7 @@ ClassTemplateSpecializationDecl(ASTContext &Context, Kind DK,
}
ClassTemplateSpecializationDecl *
-ClassTemplateSpecializationDecl::Create(ASTContext &Context,
+ClassTemplateSpecializationDecl::Create(ASTContext &Context, TagKind TK,
DeclContext *DC, SourceLocation L,
ClassTemplateDecl *SpecializedTemplate,
TemplateArgumentListBuilder &Builder,
@@ -422,7 +439,7 @@ ClassTemplateSpecializationDecl::Create(ASTContext &Context,
ClassTemplateSpecializationDecl *Result
= new (Context)ClassTemplateSpecializationDecl(Context,
ClassTemplateSpecialization,
- DC, L,
+ TK, DC, L,
SpecializedTemplate,
Builder,
PrevDecl);
@@ -464,7 +481,7 @@ ClassTemplateSpecializationDecl::getSpecializedTemplate() const {
//===----------------------------------------------------------------------===//
ClassTemplatePartialSpecializationDecl *
ClassTemplatePartialSpecializationDecl::
-Create(ASTContext &Context, DeclContext *DC, SourceLocation L,
+Create(ASTContext &Context, TagKind TK,DeclContext *DC, SourceLocation L,
TemplateParameterList *Params,
ClassTemplateDecl *SpecializedTemplate,
TemplateArgumentListBuilder &Builder,
@@ -478,7 +495,7 @@ Create(ASTContext &Context, DeclContext *DC, SourceLocation L,
ClonedArgs[I] = ArgInfos[I];
ClassTemplatePartialSpecializationDecl *Result
- = new (Context)ClassTemplatePartialSpecializationDecl(Context,
+ = new (Context)ClassTemplatePartialSpecializationDecl(Context, TK,
DC, L, Params,
SpecializedTemplate,
Builder,
diff --git a/lib/AST/DeclarationName.cpp b/lib/AST/DeclarationName.cpp
index 4f85fca53868..343d403e76ad 100644
--- a/lib/AST/DeclarationName.cpp
+++ b/lib/AST/DeclarationName.cpp
@@ -11,10 +11,11 @@
// classes.
//
//===----------------------------------------------------------------------===//
+#include "clang/AST/ASTContext.h"
+#include "clang/AST/Decl.h"
#include "clang/AST/DeclarationName.h"
#include "clang/AST/Type.h"
#include "clang/AST/TypeOrdering.h"
-#include "clang/AST/Decl.h"
#include "clang/Basic/IdentifierTable.h"
#include "llvm/ADT/DenseMap.h"
#include "llvm/ADT/FoldingSet.h"
@@ -383,12 +384,12 @@ void DeclarationName::dump() const {
llvm::errs() << '\n';
}
-DeclarationNameTable::DeclarationNameTable() {
+DeclarationNameTable::DeclarationNameTable(ASTContext &C) : Ctx(C) {
CXXSpecialNamesImpl = new llvm::FoldingSet<CXXSpecialName>;
CXXLiteralOperatorNames = new llvm::FoldingSet<CXXLiteralOperatorIdName>;
// Initialize the overloaded operator names.
- CXXOperatorNames = new CXXOperatorIdName[NUM_OVERLOADED_OPERATORS];
+ CXXOperatorNames = new (Ctx) CXXOperatorIdName[NUM_OVERLOADED_OPERATORS];
for (unsigned Op = 0; Op < NUM_OVERLOADED_OPERATORS; ++Op) {
CXXOperatorNames[Op].ExtraKindOrNumArgs
= Op + DeclarationNameExtra::CXXConversionFunction;
@@ -399,29 +400,32 @@ DeclarationNameTable::DeclarationNameTable() {
DeclarationNameTable::~DeclarationNameTable() {
llvm::FoldingSet<CXXSpecialName> *SpecialNames =
static_cast<llvm::FoldingSet<CXXSpecialName>*>(CXXSpecialNamesImpl);
- llvm::FoldingSetIterator<CXXSpecialName>
- SI = SpecialNames->begin(), SE = SpecialNames->end();
+ llvm::FoldingSet<CXXLiteralOperatorIdName> *LiteralNames
+ = static_cast<llvm::FoldingSet<CXXLiteralOperatorIdName>*>
+ (CXXLiteralOperatorNames);
- while (SI != SE) {
- CXXSpecialName *n = &*SI++;
- delete n;
- }
+ if (Ctx.FreeMemory) {
+ llvm::FoldingSetIterator<CXXSpecialName>
+ SI = SpecialNames->begin(), SE = SpecialNames->end();
+ while (SI != SE) {
+ CXXSpecialName *n = &*SI++;
+ Ctx.Deallocate(n);
+ }
- llvm::FoldingSet<CXXLiteralOperatorIdName> *LiteralNames
- = static_cast<llvm::FoldingSet<CXXLiteralOperatorIdName>*>
- (CXXLiteralOperatorNames);
- llvm::FoldingSetIterator<CXXLiteralOperatorIdName>
- LI = LiteralNames->begin(), LE = LiteralNames->end();
+ llvm::FoldingSetIterator<CXXLiteralOperatorIdName>
+ LI = LiteralNames->begin(), LE = LiteralNames->end();
+
+ while (LI != LE) {
+ CXXLiteralOperatorIdName *n = &*LI++;
+ Ctx.Deallocate(n);
+ }
- while (LI != LE) {
- CXXLiteralOperatorIdName *n = &*LI++;
- delete n;
+ Ctx.Deallocate(CXXOperatorNames);
}
delete SpecialNames;
delete LiteralNames;
- delete [] CXXOperatorNames;
}
DeclarationName
@@ -459,7 +463,7 @@ DeclarationNameTable::getCXXSpecialName(DeclarationName::NameKind Kind,
if (CXXSpecialName *Name = SpecialNames->FindNodeOrInsertPos(ID, InsertPos))
return DeclarationName(Name);
- CXXSpecialName *SpecialName = new CXXSpecialName;
+ CXXSpecialName *SpecialName = new (Ctx) CXXSpecialName;
SpecialName->ExtraKindOrNumArgs = EKind;
SpecialName->Type = Ty;
SpecialName->FETokenInfo = 0;
@@ -487,7 +491,7 @@ DeclarationNameTable::getCXXLiteralOperatorName(IdentifierInfo *II) {
LiteralNames->FindNodeOrInsertPos(ID, InsertPos))
return DeclarationName (Name);
- CXXLiteralOperatorIdName *LiteralName = new CXXLiteralOperatorIdName;
+ CXXLiteralOperatorIdName *LiteralName = new (Ctx) CXXLiteralOperatorIdName;
LiteralName->ExtraKindOrNumArgs = DeclarationNameExtra::CXXLiteralOperator;
LiteralName->ID = II;
diff --git a/lib/AST/Expr.cpp b/lib/AST/Expr.cpp
index 00662a53afed..c38cec32c3b2 100644
--- a/lib/AST/Expr.cpp
+++ b/lib/AST/Expr.cpp
@@ -27,6 +27,8 @@
#include <algorithm>
using namespace clang;
+void Expr::ANCHOR() {} // key function for Expr class.
+
/// isKnownToHaveBooleanValue - Return true if this is an integer expression
/// that is known to return 0 or 1. This happens for _Bool/bool expressions
/// but also int expressions which are produced by things like comparisons in
@@ -161,8 +163,19 @@ void DeclRefExpr::computeDependence() {
if (const Expr *Init = Var->getAnyInitializer())
if (Init->isValueDependent())
ValueDependent = true;
- }
- }
+ }
+ // (VD) - FIXME: Missing from the standard:
+ // - a member function or a static data member of the current
+ // instantiation
+ else if (Var->isStaticDataMember() &&
+ Var->getDeclContext()->isDependentContext())
+ ValueDependent = true;
+ }
+ // (VD) - FIXME: Missing from the standard:
+ // - a member function or a static data member of the current
+ // instantiation
+ else if (isa<CXXMethodDecl>(D) && D->getDeclContext()->isDependentContext())
+ ValueDependent = true;
// (TD) - a nested-name-specifier or a qualified-id that names a
// member of an unknown specialization.
// (handled by DependentScopeDeclRefExpr)
@@ -976,6 +989,7 @@ bool Expr::isUnusedResultAWarning(SourceLocation &Loc, SourceRange &R1,
return true;
}
case CompoundAssignOperatorClass:
+ case VAArgExprClass:
return false;
case ConditionalOperatorClass: {
@@ -1557,6 +1571,18 @@ Expr *Expr::IgnoreParenCasts() {
}
}
+Expr *Expr::IgnoreParenImpCasts() {
+ Expr *E = this;
+ while (true) {
+ if (ParenExpr *P = dyn_cast<ParenExpr>(E))
+ E = P->getSubExpr();
+ else if (ImplicitCastExpr *P = dyn_cast<ImplicitCastExpr>(E))
+ E = P->getSubExpr();
+ else
+ return E;
+ }
+}
+
/// IgnoreParenNoopCasts - Ignore parentheses and casts that do not change the
/// value (including ptr->int casts of the same size). Strip off any
/// ParenExpr or CastExprs, returning their operand.
@@ -1757,385 +1783,6 @@ bool Expr::isConstantInitializer(ASTContext &Ctx) const {
return isEvaluatable(Ctx);
}
-/// isIntegerConstantExpr - this recursive routine will test if an expression is
-/// an integer constant expression.
-
-/// FIXME: Pass up a reason why! Invalid operation in i-c-e, division by zero,
-/// comma, etc
-///
-/// FIXME: Handle offsetof. Two things to do: Handle GCC's __builtin_offsetof
-/// to support gcc 4.0+ and handle the idiom GCC recognizes with a null pointer
-/// cast+dereference.
-
-// CheckICE - This function does the fundamental ICE checking: the returned
-// ICEDiag contains a Val of 0, 1, or 2, and a possibly null SourceLocation.
-// Note that to reduce code duplication, this helper does no evaluation
-// itself; the caller checks whether the expression is evaluatable, and
-// in the rare cases where CheckICE actually cares about the evaluated
-// value, it calls into Evalute.
-//
-// Meanings of Val:
-// 0: This expression is an ICE if it can be evaluated by Evaluate.
-// 1: This expression is not an ICE, but if it isn't evaluated, it's
-// a legal subexpression for an ICE. This return value is used to handle
-// the comma operator in C99 mode.
-// 2: This expression is not an ICE, and is not a legal subexpression for one.
-
-struct ICEDiag {
- unsigned Val;
- SourceLocation Loc;
-
- public:
- ICEDiag(unsigned v, SourceLocation l) : Val(v), Loc(l) {}
- ICEDiag() : Val(0) {}
-};
-
-ICEDiag NoDiag() { return ICEDiag(); }
-
-static ICEDiag CheckEvalInICE(const Expr* E, ASTContext &Ctx) {
- Expr::EvalResult EVResult;
- if (!E->Evaluate(EVResult, Ctx) || EVResult.HasSideEffects ||
- !EVResult.Val.isInt()) {
- return ICEDiag(2, E->getLocStart());
- }
- return NoDiag();
-}
-
-static ICEDiag CheckICE(const Expr* E, ASTContext &Ctx) {
- assert(!E->isValueDependent() && "Should not see value dependent exprs!");
- if (!E->getType()->isIntegralType()) {
- return ICEDiag(2, E->getLocStart());
- }
-
- switch (E->getStmtClass()) {
-#define STMT(Node, Base) case Expr::Node##Class:
-#define EXPR(Node, Base)
-#include "clang/AST/StmtNodes.def"
- case Expr::PredefinedExprClass:
- case Expr::FloatingLiteralClass:
- case Expr::ImaginaryLiteralClass:
- case Expr::StringLiteralClass:
- case Expr::ArraySubscriptExprClass:
- case Expr::MemberExprClass:
- case Expr::CompoundAssignOperatorClass:
- case Expr::CompoundLiteralExprClass:
- case Expr::ExtVectorElementExprClass:
- case Expr::InitListExprClass:
- case Expr::DesignatedInitExprClass:
- case Expr::ImplicitValueInitExprClass:
- case Expr::ParenListExprClass:
- case Expr::VAArgExprClass:
- case Expr::AddrLabelExprClass:
- case Expr::StmtExprClass:
- case Expr::CXXMemberCallExprClass:
- case Expr::CXXDynamicCastExprClass:
- case Expr::CXXTypeidExprClass:
- case Expr::CXXNullPtrLiteralExprClass:
- case Expr::CXXThisExprClass:
- case Expr::CXXThrowExprClass:
- case Expr::CXXNewExprClass:
- case Expr::CXXDeleteExprClass:
- case Expr::CXXPseudoDestructorExprClass:
- case Expr::UnresolvedLookupExprClass:
- case Expr::DependentScopeDeclRefExprClass:
- case Expr::CXXConstructExprClass:
- case Expr::CXXBindTemporaryExprClass:
- case Expr::CXXBindReferenceExprClass:
- case Expr::CXXExprWithTemporariesClass:
- case Expr::CXXTemporaryObjectExprClass:
- case Expr::CXXUnresolvedConstructExprClass:
- case Expr::CXXDependentScopeMemberExprClass:
- case Expr::UnresolvedMemberExprClass:
- case Expr::ObjCStringLiteralClass:
- case Expr::ObjCEncodeExprClass:
- case Expr::ObjCMessageExprClass:
- case Expr::ObjCSelectorExprClass:
- case Expr::ObjCProtocolExprClass:
- case Expr::ObjCIvarRefExprClass:
- case Expr::ObjCPropertyRefExprClass:
- case Expr::ObjCImplicitSetterGetterRefExprClass:
- case Expr::ObjCSuperExprClass:
- case Expr::ObjCIsaExprClass:
- case Expr::ShuffleVectorExprClass:
- case Expr::BlockExprClass:
- case Expr::BlockDeclRefExprClass:
- case Expr::NoStmtClass:
- return ICEDiag(2, E->getLocStart());
-
- case Expr::GNUNullExprClass:
- // GCC considers the GNU __null value to be an integral constant expression.
- return NoDiag();
-
- case Expr::ParenExprClass:
- return CheckICE(cast<ParenExpr>(E)->getSubExpr(), Ctx);
- case Expr::IntegerLiteralClass:
- case Expr::CharacterLiteralClass:
- case Expr::CXXBoolLiteralExprClass:
- case Expr::CXXZeroInitValueExprClass:
- case Expr::TypesCompatibleExprClass:
- case Expr::UnaryTypeTraitExprClass:
- return NoDiag();
- case Expr::CallExprClass:
- case Expr::CXXOperatorCallExprClass: {
- const CallExpr *CE = cast<CallExpr>(E);
- if (CE->isBuiltinCall(Ctx))
- return CheckEvalInICE(E, Ctx);
- return ICEDiag(2, E->getLocStart());
- }
- case Expr::DeclRefExprClass:
- if (isa<EnumConstantDecl>(cast<DeclRefExpr>(E)->getDecl()))
- return NoDiag();
- if (Ctx.getLangOptions().CPlusPlus &&
- E->getType().getCVRQualifiers() == Qualifiers::Const) {
- const NamedDecl *D = cast<DeclRefExpr>(E)->getDecl();
-
- // Parameter variables are never constants. Without this check,
- // getAnyInitializer() can find a default argument, which leads
- // to chaos.
- if (isa<ParmVarDecl>(D))
- return ICEDiag(2, cast<DeclRefExpr>(E)->getLocation());
-
- // C++ 7.1.5.1p2
- // A variable of non-volatile const-qualified integral or enumeration
- // type initialized by an ICE can be used in ICEs.
- if (const VarDecl *Dcl = dyn_cast<VarDecl>(D)) {
- Qualifiers Quals = Ctx.getCanonicalType(Dcl->getType()).getQualifiers();
- if (Quals.hasVolatile() || !Quals.hasConst())
- return ICEDiag(2, cast<DeclRefExpr>(E)->getLocation());
-
- // Look for a declaration of this variable that has an initializer.
- const VarDecl *ID = 0;
- const Expr *Init = Dcl->getAnyInitializer(ID);
- if (Init) {
- if (ID->isInitKnownICE()) {
- // We have already checked whether this subexpression is an
- // integral constant expression.
- if (ID->isInitICE())
- return NoDiag();
- else
- return ICEDiag(2, cast<DeclRefExpr>(E)->getLocation());
- }
-
- // It's an ICE whether or not the definition we found is
- // out-of-line. See DR 721 and the discussion in Clang PR
- // 6206 for details.
-
- if (Dcl->isCheckingICE()) {
- return ICEDiag(2, cast<DeclRefExpr>(E)->getLocation());
- }
-
- Dcl->setCheckingICE();
- ICEDiag Result = CheckICE(Init, Ctx);
- // Cache the result of the ICE test.
- Dcl->setInitKnownICE(Result.Val == 0);
- return Result;
- }
- }
- }
- return ICEDiag(2, E->getLocStart());
- case Expr::UnaryOperatorClass: {
- const UnaryOperator *Exp = cast<UnaryOperator>(E);
- switch (Exp->getOpcode()) {
- case UnaryOperator::PostInc:
- case UnaryOperator::PostDec:
- case UnaryOperator::PreInc:
- case UnaryOperator::PreDec:
- case UnaryOperator::AddrOf:
- case UnaryOperator::Deref:
- return ICEDiag(2, E->getLocStart());
- case UnaryOperator::Extension:
- case UnaryOperator::LNot:
- case UnaryOperator::Plus:
- case UnaryOperator::Minus:
- case UnaryOperator::Not:
- case UnaryOperator::Real:
- case UnaryOperator::Imag:
- return CheckICE(Exp->getSubExpr(), Ctx);
- case UnaryOperator::OffsetOf:
- break;
- }
-
- // OffsetOf falls through here.
- }
- case Expr::OffsetOfExprClass: {
- // Note that per C99, offsetof must be an ICE. And AFAIK, using
- // Evaluate matches the proposed gcc behavior for cases like
- // "offsetof(struct s{int x[4];}, x[!.0])". This doesn't affect
- // compliance: we should warn earlier for offsetof expressions with
- // array subscripts that aren't ICEs, and if the array subscripts
- // are ICEs, the value of the offsetof must be an integer constant.
- return CheckEvalInICE(E, Ctx);
- }
- case Expr::SizeOfAlignOfExprClass: {
- const SizeOfAlignOfExpr *Exp = cast<SizeOfAlignOfExpr>(E);
- if (Exp->isSizeOf() && Exp->getTypeOfArgument()->isVariableArrayType())
- return ICEDiag(2, E->getLocStart());
- return NoDiag();
- }
- case Expr::BinaryOperatorClass: {
- const BinaryOperator *Exp = cast<BinaryOperator>(E);
- switch (Exp->getOpcode()) {
- case BinaryOperator::PtrMemD:
- case BinaryOperator::PtrMemI:
- case BinaryOperator::Assign:
- case BinaryOperator::MulAssign:
- case BinaryOperator::DivAssign:
- case BinaryOperator::RemAssign:
- case BinaryOperator::AddAssign:
- case BinaryOperator::SubAssign:
- case BinaryOperator::ShlAssign:
- case BinaryOperator::ShrAssign:
- case BinaryOperator::AndAssign:
- case BinaryOperator::XorAssign:
- case BinaryOperator::OrAssign:
- return ICEDiag(2, E->getLocStart());
-
- case BinaryOperator::Mul:
- case BinaryOperator::Div:
- case BinaryOperator::Rem:
- case BinaryOperator::Add:
- case BinaryOperator::Sub:
- case BinaryOperator::Shl:
- case BinaryOperator::Shr:
- case BinaryOperator::LT:
- case BinaryOperator::GT:
- case BinaryOperator::LE:
- case BinaryOperator::GE:
- case BinaryOperator::EQ:
- case BinaryOperator::NE:
- case BinaryOperator::And:
- case BinaryOperator::Xor:
- case BinaryOperator::Or:
- case BinaryOperator::Comma: {
- ICEDiag LHSResult = CheckICE(Exp->getLHS(), Ctx);
- ICEDiag RHSResult = CheckICE(Exp->getRHS(), Ctx);
- if (Exp->getOpcode() == BinaryOperator::Div ||
- Exp->getOpcode() == BinaryOperator::Rem) {
- // Evaluate gives an error for undefined Div/Rem, so make sure
- // we don't evaluate one.
- if (LHSResult.Val != 2 && RHSResult.Val != 2) {
- llvm::APSInt REval = Exp->getRHS()->EvaluateAsInt(Ctx);
- if (REval == 0)
- return ICEDiag(1, E->getLocStart());
- if (REval.isSigned() && REval.isAllOnesValue()) {
- llvm::APSInt LEval = Exp->getLHS()->EvaluateAsInt(Ctx);
- if (LEval.isMinSignedValue())
- return ICEDiag(1, E->getLocStart());
- }
- }
- }
- if (Exp->getOpcode() == BinaryOperator::Comma) {
- if (Ctx.getLangOptions().C99) {
- // C99 6.6p3 introduces a strange edge case: comma can be in an ICE
- // if it isn't evaluated.
- if (LHSResult.Val == 0 && RHSResult.Val == 0)
- return ICEDiag(1, E->getLocStart());
- } else {
- // In both C89 and C++, commas in ICEs are illegal.
- return ICEDiag(2, E->getLocStart());
- }
- }
- if (LHSResult.Val >= RHSResult.Val)
- return LHSResult;
- return RHSResult;
- }
- case BinaryOperator::LAnd:
- case BinaryOperator::LOr: {
- ICEDiag LHSResult = CheckICE(Exp->getLHS(), Ctx);
- ICEDiag RHSResult = CheckICE(Exp->getRHS(), Ctx);
- if (LHSResult.Val == 0 && RHSResult.Val == 1) {
- // Rare case where the RHS has a comma "side-effect"; we need
- // to actually check the condition to see whether the side
- // with the comma is evaluated.
- if ((Exp->getOpcode() == BinaryOperator::LAnd) !=
- (Exp->getLHS()->EvaluateAsInt(Ctx) == 0))
- return RHSResult;
- return NoDiag();
- }
-
- if (LHSResult.Val >= RHSResult.Val)
- return LHSResult;
- return RHSResult;
- }
- }
- }
- case Expr::ImplicitCastExprClass:
- case Expr::CStyleCastExprClass:
- case Expr::CXXFunctionalCastExprClass:
- case Expr::CXXStaticCastExprClass:
- case Expr::CXXReinterpretCastExprClass:
- case Expr::CXXConstCastExprClass: {
- const Expr *SubExpr = cast<CastExpr>(E)->getSubExpr();
- if (SubExpr->getType()->isIntegralType())
- return CheckICE(SubExpr, Ctx);
- if (isa<FloatingLiteral>(SubExpr->IgnoreParens()))
- return NoDiag();
- return ICEDiag(2, E->getLocStart());
- }
- case Expr::ConditionalOperatorClass: {
- const ConditionalOperator *Exp = cast<ConditionalOperator>(E);
- // If the condition (ignoring parens) is a __builtin_constant_p call,
- // then only the true side is actually considered in an integer constant
- // expression, and it is fully evaluated. This is an important GNU
- // extension. See GCC PR38377 for discussion.
- if (const CallExpr *CallCE
- = dyn_cast<CallExpr>(Exp->getCond()->IgnoreParenCasts()))
- if (CallCE->isBuiltinCall(Ctx) == Builtin::BI__builtin_constant_p) {
- Expr::EvalResult EVResult;
- if (!E->Evaluate(EVResult, Ctx) || EVResult.HasSideEffects ||
- !EVResult.Val.isInt()) {
- return ICEDiag(2, E->getLocStart());
- }
- return NoDiag();
- }
- ICEDiag CondResult = CheckICE(Exp->getCond(), Ctx);
- ICEDiag TrueResult = CheckICE(Exp->getTrueExpr(), Ctx);
- ICEDiag FalseResult = CheckICE(Exp->getFalseExpr(), Ctx);
- if (CondResult.Val == 2)
- return CondResult;
- if (TrueResult.Val == 2)
- return TrueResult;
- if (FalseResult.Val == 2)
- return FalseResult;
- if (CondResult.Val == 1)
- return CondResult;
- if (TrueResult.Val == 0 && FalseResult.Val == 0)
- return NoDiag();
- // Rare case where the diagnostics depend on which side is evaluated
- // Note that if we get here, CondResult is 0, and at least one of
- // TrueResult and FalseResult is non-zero.
- if (Exp->getCond()->EvaluateAsInt(Ctx) == 0) {
- return FalseResult;
- }
- return TrueResult;
- }
- case Expr::CXXDefaultArgExprClass:
- return CheckICE(cast<CXXDefaultArgExpr>(E)->getExpr(), Ctx);
- case Expr::ChooseExprClass: {
- return CheckICE(cast<ChooseExpr>(E)->getChosenSubExpr(Ctx), Ctx);
- }
- }
-
- // Silence a GCC warning
- return ICEDiag(2, E->getLocStart());
-}
-
-bool Expr::isIntegerConstantExpr(llvm::APSInt &Result, ASTContext &Ctx,
- SourceLocation *Loc, bool isEvaluated) const {
- ICEDiag d = CheckICE(this, Ctx);
- if (d.Val != 0) {
- if (Loc) *Loc = d.Loc;
- return false;
- }
- EvalResult EvalResult;
- if (!Evaluate(EvalResult, Ctx))
- llvm_unreachable("ICE cannot be evaluated!");
- assert(!EvalResult.HasSideEffects && "ICE with side effects!");
- assert(EvalResult.Val.isInt() && "ICE that isn't integer!");
- Result = EvalResult.Val.getInt();
- return true;
-}
-
/// isNullPointerConstant - C99 6.3.2.3p3 - Return true if this is either an
/// integer constant expression with the value zero, or if this is one that is
/// cast to void*.
@@ -2433,9 +2080,9 @@ ObjCInterfaceDecl *ObjCMessageExpr::getReceiverInterface() const {
break;
case Class:
- if (const ObjCInterfaceType *Iface
- = getClassReceiver()->getAs<ObjCInterfaceType>())
- return Iface->getDecl();
+ if (const ObjCObjectType *Ty
+ = getClassReceiver()->getAs<ObjCObjectType>())
+ return Ty->getInterface();
break;
case SuperInstance:
@@ -2712,7 +2359,9 @@ Stmt::child_iterator ObjCPropertyRefExpr::child_end() { return &Base+1; }
// ObjCImplicitSetterGetterRefExpr
Stmt::child_iterator ObjCImplicitSetterGetterRefExpr::child_begin() {
- return &Base;
+ // If this is accessing a class member, skip that entry.
+ if (Base) return &Base;
+ return &Base+1;
}
Stmt::child_iterator ObjCImplicitSetterGetterRefExpr::child_end() {
return &Base+1;
diff --git a/lib/AST/ExprCXX.cpp b/lib/AST/ExprCXX.cpp
index 2e03beb0f050..d1a2b261f26b 100644
--- a/lib/AST/ExprCXX.cpp
+++ b/lib/AST/ExprCXX.cpp
@@ -92,12 +92,11 @@ CXXNewExpr::CXXNewExpr(ASTContext &C, bool globalNew, FunctionDecl *operatorNew,
SourceLocation startLoc, SourceLocation endLoc)
: Expr(CXXNewExprClass, ty, ty->isDependentType(), ty->isDependentType()),
GlobalNew(globalNew), ParenTypeId(parenTypeId),
- Initializer(initializer), Array(arraySize), NumPlacementArgs(numPlaceArgs),
- NumConstructorArgs(numConsArgs), OperatorNew(operatorNew),
+ Initializer(initializer), SubExprs(0), OperatorNew(operatorNew),
OperatorDelete(operatorDelete), Constructor(constructor),
StartLoc(startLoc), EndLoc(endLoc) {
- unsigned TotalSize = Array + NumPlacementArgs + NumConstructorArgs;
- SubExprs = new (C) Stmt*[TotalSize];
+
+ AllocateArgsArray(C, arraySize != 0, numPlaceArgs, numConsArgs);
unsigned i = 0;
if (Array)
SubExprs[i++] = arraySize;
@@ -105,9 +104,20 @@ CXXNewExpr::CXXNewExpr(ASTContext &C, bool globalNew, FunctionDecl *operatorNew,
SubExprs[i++] = placementArgs[j];
for (unsigned j = 0; j < NumConstructorArgs; ++j)
SubExprs[i++] = constructorArgs[j];
- assert(i == TotalSize);
}
+void CXXNewExpr::AllocateArgsArray(ASTContext &C, bool isArray,
+ unsigned numPlaceArgs, unsigned numConsArgs){
+ assert(SubExprs == 0 && "SubExprs already allocated");
+ Array = isArray;
+ NumPlacementArgs = numPlaceArgs;
+ NumConstructorArgs = numConsArgs;
+
+ unsigned TotalSize = Array + NumPlacementArgs + NumConstructorArgs;
+ SubExprs = new (C) Stmt*[TotalSize];
+}
+
+
void CXXNewExpr::DoDestroy(ASTContext &C) {
DestroyChildren(C);
if (SubExprs)
@@ -134,7 +144,7 @@ Stmt::child_iterator CXXPseudoDestructorExpr::child_end() {
PseudoDestructorTypeStorage::PseudoDestructorTypeStorage(TypeSourceInfo *Info)
: Type(Info)
{
- Location = Info->getTypeLoc().getSourceRange().getBegin();
+ Location = Info->getTypeLoc().getLocalSourceRange().getBegin();
}
QualType CXXPseudoDestructorExpr::getDestroyedType() const {
@@ -147,7 +157,7 @@ QualType CXXPseudoDestructorExpr::getDestroyedType() const {
SourceRange CXXPseudoDestructorExpr::getSourceRange() const {
SourceLocation End = DestroyedType.getLocation();
if (TypeSourceInfo *TInfo = DestroyedType.getTypeSourceInfo())
- End = TInfo->getTypeLoc().getSourceRange().getEnd();
+ End = TInfo->getTypeLoc().getLocalSourceRange().getEnd();
return SourceRange(Base->getLocStart(), End);
}
@@ -159,23 +169,47 @@ UnresolvedLookupExpr::Create(ASTContext &C, bool Dependent,
NestedNameSpecifier *Qualifier,
SourceRange QualifierRange, DeclarationName Name,
SourceLocation NameLoc, bool ADL,
- const TemplateArgumentListInfo &Args)
+ const TemplateArgumentListInfo &Args,
+ UnresolvedSetIterator Begin,
+ UnresolvedSetIterator End)
{
void *Mem = C.Allocate(sizeof(UnresolvedLookupExpr) +
ExplicitTemplateArgumentList::sizeFor(Args));
UnresolvedLookupExpr *ULE
- = new (Mem) UnresolvedLookupExpr(Dependent ? C.DependentTy : C.OverloadTy,
+ = new (Mem) UnresolvedLookupExpr(C,
+ Dependent ? C.DependentTy : C.OverloadTy,
Dependent, NamingClass,
Qualifier, QualifierRange,
Name, NameLoc, ADL,
/*Overload*/ true,
- /*ExplicitTemplateArgs*/ true);
+ /*ExplicitTemplateArgs*/ true,
+ Begin, End);
reinterpret_cast<ExplicitTemplateArgumentList*>(ULE+1)->initializeFrom(Args);
return ULE;
}
+OverloadExpr::OverloadExpr(StmtClass K, ASTContext &C, QualType T,
+ bool Dependent, NestedNameSpecifier *Qualifier,
+ SourceRange QRange, DeclarationName Name,
+ SourceLocation NameLoc, bool HasTemplateArgs,
+ UnresolvedSetIterator Begin,
+ UnresolvedSetIterator End)
+ : Expr(K, T, Dependent, Dependent),
+ Results(0), NumResults(End - Begin), Name(Name), Qualifier(Qualifier),
+ QualifierRange(QRange), NameLoc(NameLoc),
+ HasExplicitTemplateArgs(HasTemplateArgs)
+{
+ if (NumResults) {
+ Results = static_cast<DeclAccessPair *>(
+ C.Allocate(sizeof(DeclAccessPair) * NumResults,
+ llvm::alignof<DeclAccessPair>()));
+ memcpy(Results, &*Begin.getIterator(),
+ (End - Begin) * sizeof(DeclAccessPair));
+ }
+}
+
bool OverloadExpr::ComputeDependence(UnresolvedSetIterator Begin,
UnresolvedSetIterator End,
const TemplateArgumentListInfo *Args) {
@@ -517,35 +551,43 @@ void CXXConstructExpr::DoDestroy(ASTContext &C) {
C.Deallocate(this);
}
-CXXExprWithTemporaries::CXXExprWithTemporaries(Expr *subexpr,
+CXXExprWithTemporaries::CXXExprWithTemporaries(ASTContext &C,
+ Expr *subexpr,
CXXTemporary **temps,
unsigned numtemps)
-: Expr(CXXExprWithTemporariesClass, subexpr->getType(),
+ : Expr(CXXExprWithTemporariesClass, subexpr->getType(),
subexpr->isTypeDependent(), subexpr->isValueDependent()),
- SubExpr(subexpr), Temps(0), NumTemps(numtemps) {
- if (NumTemps > 0) {
- Temps = new CXXTemporary*[NumTemps];
- for (unsigned i = 0; i < NumTemps; ++i)
+ SubExpr(subexpr), Temps(0), NumTemps(0) {
+ if (numtemps) {
+ setNumTemporaries(C, numtemps);
+ for (unsigned i = 0; i != numtemps; ++i)
Temps[i] = temps[i];
}
}
+void CXXExprWithTemporaries::setNumTemporaries(ASTContext &C, unsigned N) {
+ assert(Temps == 0 && "Cannot resize with this");
+ NumTemps = N;
+ Temps = new (C) CXXTemporary*[NumTemps];
+}
+
+
CXXExprWithTemporaries *CXXExprWithTemporaries::Create(ASTContext &C,
Expr *SubExpr,
CXXTemporary **Temps,
unsigned NumTemps) {
- return new (C) CXXExprWithTemporaries(SubExpr, Temps, NumTemps);
+ return new (C) CXXExprWithTemporaries(C, SubExpr, Temps, NumTemps);
}
void CXXExprWithTemporaries::DoDestroy(ASTContext &C) {
DestroyChildren(C);
+ if (Temps)
+ C.Deallocate(Temps);
this->~CXXExprWithTemporaries();
C.Deallocate(this);
}
-CXXExprWithTemporaries::~CXXExprWithTemporaries() {
- delete[] Temps;
-}
+CXXExprWithTemporaries::~CXXExprWithTemporaries() {}
// CXXBindTemporaryExpr
Stmt::child_iterator CXXBindTemporaryExpr::child_begin() {
@@ -682,7 +724,8 @@ Stmt::child_iterator CXXDependentScopeMemberExpr::child_end() {
return child_iterator(&Base + 1);
}
-UnresolvedMemberExpr::UnresolvedMemberExpr(QualType T, bool Dependent,
+UnresolvedMemberExpr::UnresolvedMemberExpr(ASTContext &C, QualType T,
+ bool Dependent,
bool HasUnresolvedUsing,
Expr *Base, QualType BaseType,
bool IsArrow,
@@ -691,10 +734,12 @@ UnresolvedMemberExpr::UnresolvedMemberExpr(QualType T, bool Dependent,
SourceRange QualifierRange,
DeclarationName MemberName,
SourceLocation MemberLoc,
- const TemplateArgumentListInfo *TemplateArgs)
- : OverloadExpr(UnresolvedMemberExprClass, T, Dependent,
+ const TemplateArgumentListInfo *TemplateArgs,
+ UnresolvedSetIterator Begin,
+ UnresolvedSetIterator End)
+ : OverloadExpr(UnresolvedMemberExprClass, C, T, Dependent,
Qualifier, QualifierRange, MemberName, MemberLoc,
- TemplateArgs != 0),
+ TemplateArgs != 0, Begin, End),
IsArrow(IsArrow), HasUnresolvedUsing(HasUnresolvedUsing),
Base(Base), BaseType(BaseType), OperatorLoc(OperatorLoc) {
if (TemplateArgs)
@@ -710,17 +755,19 @@ UnresolvedMemberExpr::Create(ASTContext &C, bool Dependent,
SourceRange QualifierRange,
DeclarationName Member,
SourceLocation MemberLoc,
- const TemplateArgumentListInfo *TemplateArgs) {
+ const TemplateArgumentListInfo *TemplateArgs,
+ UnresolvedSetIterator Begin,
+ UnresolvedSetIterator End) {
std::size_t size = sizeof(UnresolvedMemberExpr);
if (TemplateArgs)
size += ExplicitTemplateArgumentList::sizeFor(*TemplateArgs);
void *Mem = C.Allocate(size, llvm::alignof<UnresolvedMemberExpr>());
- return new (Mem) UnresolvedMemberExpr(
+ return new (Mem) UnresolvedMemberExpr(C,
Dependent ? C.DependentTy : C.OverloadTy,
Dependent, HasUnresolvedUsing, Base, BaseType,
IsArrow, OperatorLoc, Qualifier, QualifierRange,
- Member, MemberLoc, TemplateArgs);
+ Member, MemberLoc, TemplateArgs, Begin, End);
}
CXXRecordDecl *UnresolvedMemberExpr::getNamingClass() const {
diff --git a/lib/AST/ExprConstant.cpp b/lib/AST/ExprConstant.cpp
index c1a42d88fffa..dc614018ec2b 100644
--- a/lib/AST/ExprConstant.cpp
+++ b/lib/AST/ExprConstant.cpp
@@ -48,31 +48,110 @@ struct EvalInfo {
/// EvalResult - Contains information about the evaluation.
Expr::EvalResult &EvalResult;
- /// AnyLValue - Stack based LValue results are not discarded.
- bool AnyLValue;
-
- EvalInfo(ASTContext &ctx, Expr::EvalResult& evalresult,
- bool anylvalue = false)
- : Ctx(ctx), EvalResult(evalresult), AnyLValue(anylvalue) {}
+ EvalInfo(ASTContext &ctx, Expr::EvalResult& evalresult)
+ : Ctx(ctx), EvalResult(evalresult) {}
};
+namespace {
+ struct ComplexValue {
+ private:
+ bool IsInt;
-static bool EvaluateLValue(const Expr *E, APValue &Result, EvalInfo &Info);
-static bool EvaluatePointer(const Expr *E, APValue &Result, EvalInfo &Info);
+ public:
+ APSInt IntReal, IntImag;
+ APFloat FloatReal, FloatImag;
+
+ ComplexValue() : FloatReal(APFloat::Bogus), FloatImag(APFloat::Bogus) {}
+
+ void makeComplexFloat() { IsInt = false; }
+ bool isComplexFloat() const { return !IsInt; }
+ APFloat &getComplexFloatReal() { return FloatReal; }
+ APFloat &getComplexFloatImag() { return FloatImag; }
+
+ void makeComplexInt() { IsInt = true; }
+ bool isComplexInt() const { return IsInt; }
+ APSInt &getComplexIntReal() { return IntReal; }
+ APSInt &getComplexIntImag() { return IntImag; }
+
+ void moveInto(APValue &v) {
+ if (isComplexFloat())
+ v = APValue(FloatReal, FloatImag);
+ else
+ v = APValue(IntReal, IntImag);
+ }
+ };
+
+ struct LValue {
+ Expr *Base;
+ CharUnits Offset;
+
+ Expr *getLValueBase() { return Base; }
+ CharUnits getLValueOffset() { return Offset; }
+
+ void moveInto(APValue &v) {
+ v = APValue(Base, Offset);
+ }
+ };
+}
+
+static bool EvaluateLValue(const Expr *E, LValue &Result, EvalInfo &Info);
+static bool EvaluatePointer(const Expr *E, LValue &Result, EvalInfo &Info);
static bool EvaluateInteger(const Expr *E, APSInt &Result, EvalInfo &Info);
static bool EvaluateIntegerOrLValue(const Expr *E, APValue &Result,
EvalInfo &Info);
static bool EvaluateFloat(const Expr *E, APFloat &Result, EvalInfo &Info);
-static bool EvaluateComplex(const Expr *E, APValue &Result, EvalInfo &Info);
+static bool EvaluateComplex(const Expr *E, ComplexValue &Res, EvalInfo &Info);
//===----------------------------------------------------------------------===//
// Misc utilities
//===----------------------------------------------------------------------===//
-static bool EvalPointerValueAsBool(APValue& Value, bool& Result) {
- // FIXME: Is this accurate for all kinds of bases? If not, what would
- // the check look like?
- Result = Value.getLValueBase() || !Value.getLValueOffset().isZero();
+static bool IsGlobalLValue(const Expr* E) {
+ if (!E) return true;
+
+ if (const DeclRefExpr *DRE = dyn_cast<DeclRefExpr>(E)) {
+ if (isa<FunctionDecl>(DRE->getDecl()))
+ return true;
+ if (const VarDecl *VD = dyn_cast<VarDecl>(DRE->getDecl()))
+ return VD->hasGlobalStorage();
+ return false;
+ }
+
+ if (const CompoundLiteralExpr *CLE = dyn_cast<CompoundLiteralExpr>(E))
+ return CLE->isFileScope();
+
+ return true;
+}
+
+static bool EvalPointerValueAsBool(LValue& Value, bool& Result) {
+ const Expr* Base = Value.Base;
+
+ // A null base expression indicates a null pointer. These are always
+ // evaluatable, and they are false unless the offset is zero.
+ if (!Base) {
+ Result = !Value.Offset.isZero();
+ return true;
+ }
+
+ // Require the base expression to be a global l-value.
+ if (!IsGlobalLValue(Base)) return false;
+
+ // We have a non-null base expression. These are generally known to
+ // be true, but if it'a decl-ref to a weak symbol it can be null at
+ // runtime.
+ Result = true;
+
+ const DeclRefExpr* DeclRef = dyn_cast<DeclRefExpr>(Base);
+ if (!DeclRef)
+ return true;
+
+ // If it's a weak symbol, it isn't constant-evaluable.
+ const ValueDecl* Decl = DeclRef->getDecl();
+ if (Decl->hasAttr<WeakAttr>() ||
+ Decl->hasAttr<WeakRefAttr>() ||
+ Decl->hasAttr<WeakImportAttr>())
+ return false;
+
return true;
}
@@ -91,12 +170,12 @@ static bool HandleConversionToBool(const Expr* E, bool& Result,
Result = !FloatResult.isZero();
return true;
} else if (E->getType()->hasPointerRepresentation()) {
- APValue PointerResult;
+ LValue PointerResult;
if (!EvaluatePointer(E, PointerResult, Info))
return false;
return EvalPointerValueAsBool(PointerResult, Result);
} else if (E->getType()->isAnyComplexType()) {
- APValue ComplexResult;
+ ComplexValue ComplexResult;
if (!EvaluateComplex(E, ComplexResult, Info))
return false;
if (ComplexResult.isComplexFloat()) {
@@ -221,34 +300,42 @@ public:
//===----------------------------------------------------------------------===//
namespace {
class LValueExprEvaluator
- : public StmtVisitor<LValueExprEvaluator, APValue> {
+ : public StmtVisitor<LValueExprEvaluator, bool> {
EvalInfo &Info;
+ LValue &Result;
+
+ bool Success(Expr *E) {
+ Result.Base = E;
+ Result.Offset = CharUnits::Zero();
+ return true;
+ }
public:
- LValueExprEvaluator(EvalInfo &info) : Info(info) {}
+ LValueExprEvaluator(EvalInfo &info, LValue &Result) :
+ Info(info), Result(Result) {}
- APValue VisitStmt(Stmt *S) {
- return APValue();
+ bool VisitStmt(Stmt *S) {
+ return false;
}
- APValue VisitParenExpr(ParenExpr *E) { return Visit(E->getSubExpr()); }
- APValue VisitDeclRefExpr(DeclRefExpr *E);
- APValue VisitPredefinedExpr(PredefinedExpr *E) { return APValue(E); }
- APValue VisitCompoundLiteralExpr(CompoundLiteralExpr *E);
- APValue VisitMemberExpr(MemberExpr *E);
- APValue VisitStringLiteral(StringLiteral *E) { return APValue(E); }
- APValue VisitObjCEncodeExpr(ObjCEncodeExpr *E) { return APValue(E); }
- APValue VisitArraySubscriptExpr(ArraySubscriptExpr *E);
- APValue VisitUnaryDeref(UnaryOperator *E);
- APValue VisitUnaryExtension(const UnaryOperator *E)
+ bool VisitParenExpr(ParenExpr *E) { return Visit(E->getSubExpr()); }
+ bool VisitDeclRefExpr(DeclRefExpr *E);
+ bool VisitPredefinedExpr(PredefinedExpr *E) { return Success(E); }
+ bool VisitCompoundLiteralExpr(CompoundLiteralExpr *E);
+ bool VisitMemberExpr(MemberExpr *E);
+ bool VisitStringLiteral(StringLiteral *E) { return Success(E); }
+ bool VisitObjCEncodeExpr(ObjCEncodeExpr *E) { return Success(E); }
+ bool VisitArraySubscriptExpr(ArraySubscriptExpr *E);
+ bool VisitUnaryDeref(UnaryOperator *E);
+ bool VisitUnaryExtension(const UnaryOperator *E)
{ return Visit(E->getSubExpr()); }
- APValue VisitChooseExpr(const ChooseExpr *E)
+ bool VisitChooseExpr(const ChooseExpr *E)
{ return Visit(E->getChosenSubExpr(Info.Ctx)); }
- APValue VisitCastExpr(CastExpr *E) {
+ bool VisitCastExpr(CastExpr *E) {
switch (E->getCastKind()) {
default:
- return APValue();
+ return false;
case CastExpr::CK_NoOp:
return Visit(E->getSubExpr());
@@ -258,44 +345,41 @@ public:
};
} // end anonymous namespace
-static bool EvaluateLValue(const Expr* E, APValue& Result, EvalInfo &Info) {
- Result = LValueExprEvaluator(Info).Visit(const_cast<Expr*>(E));
- return Result.isLValue();
+static bool EvaluateLValue(const Expr* E, LValue& Result, EvalInfo &Info) {
+ return LValueExprEvaluator(Info, Result).Visit(const_cast<Expr*>(E));
}
-APValue LValueExprEvaluator::VisitDeclRefExpr(DeclRefExpr *E) {
+bool LValueExprEvaluator::VisitDeclRefExpr(DeclRefExpr *E) {
if (isa<FunctionDecl>(E->getDecl())) {
- return APValue(E);
+ return Success(E);
} else if (VarDecl* VD = dyn_cast<VarDecl>(E->getDecl())) {
- if (!Info.AnyLValue && !VD->hasGlobalStorage())
- return APValue();
if (!VD->getType()->isReferenceType())
- return APValue(E);
+ return Success(E);
+ // Reference parameters can refer to anything even if they have an
+ // "initializer" in the form of a default argument.
+ if (isa<ParmVarDecl>(VD))
+ return false;
// FIXME: Check whether VD might be overridden!
if (const Expr *Init = VD->getAnyInitializer())
return Visit(const_cast<Expr *>(Init));
}
- return APValue();
+ return false;
}
-APValue LValueExprEvaluator::VisitCompoundLiteralExpr(CompoundLiteralExpr *E) {
- if (!Info.AnyLValue && !E->isFileScope())
- return APValue();
- return APValue(E);
+bool LValueExprEvaluator::VisitCompoundLiteralExpr(CompoundLiteralExpr *E) {
+ return Success(E);
}
-APValue LValueExprEvaluator::VisitMemberExpr(MemberExpr *E) {
- APValue result;
+bool LValueExprEvaluator::VisitMemberExpr(MemberExpr *E) {
QualType Ty;
if (E->isArrow()) {
- if (!EvaluatePointer(E->getBase(), result, Info))
- return APValue();
+ if (!EvaluatePointer(E->getBase(), Result, Info))
+ return false;
Ty = E->getBase()->getType()->getAs<PointerType>()->getPointeeType();
} else {
- result = Visit(E->getBase());
- if (result.isUninit())
- return APValue();
+ if (!Visit(E->getBase()))
+ return false;
Ty = E->getBase()->getType();
}
@@ -304,10 +388,10 @@ APValue LValueExprEvaluator::VisitMemberExpr(MemberExpr *E) {
FieldDecl *FD = dyn_cast<FieldDecl>(E->getMemberDecl());
if (!FD) // FIXME: deal with other kinds of member expressions
- return APValue();
+ return false;
if (FD->getType()->isReferenceType())
- return APValue();
+ return false;
// FIXME: This is linear time.
unsigned i = 0;
@@ -318,36 +402,25 @@ APValue LValueExprEvaluator::VisitMemberExpr(MemberExpr *E) {
break;
}
- result.setLValue(result.getLValueBase(),
- result.getLValueOffset() +
- CharUnits::fromQuantity(RL.getFieldOffset(i) / 8));
-
- return result;
+ Result.Offset += CharUnits::fromQuantity(RL.getFieldOffset(i) / 8);
+ return true;
}
-APValue LValueExprEvaluator::VisitArraySubscriptExpr(ArraySubscriptExpr *E) {
- APValue Result;
-
+bool LValueExprEvaluator::VisitArraySubscriptExpr(ArraySubscriptExpr *E) {
if (!EvaluatePointer(E->getBase(), Result, Info))
- return APValue();
+ return false;
APSInt Index;
if (!EvaluateInteger(E->getIdx(), Index, Info))
- return APValue();
+ return false;
CharUnits ElementSize = Info.Ctx.getTypeSizeInChars(E->getType());
-
- CharUnits Offset = Index.getSExtValue() * ElementSize;
- Result.setLValue(Result.getLValueBase(),
- Result.getLValueOffset() + Offset);
- return Result;
+ Result.Offset += Index.getSExtValue() * ElementSize;
+ return true;
}
-APValue LValueExprEvaluator::VisitUnaryDeref(UnaryOperator *E) {
- APValue Result;
- if (!EvaluatePointer(E->getSubExpr(), Result, Info))
- return APValue();
- return Result;
+bool LValueExprEvaluator::VisitUnaryDeref(UnaryOperator *E) {
+ return EvaluatePointer(E->getSubExpr(), Result, Info);
}
//===----------------------------------------------------------------------===//
@@ -356,104 +429,103 @@ APValue LValueExprEvaluator::VisitUnaryDeref(UnaryOperator *E) {
namespace {
class PointerExprEvaluator
- : public StmtVisitor<PointerExprEvaluator, APValue> {
+ : public StmtVisitor<PointerExprEvaluator, bool> {
EvalInfo &Info;
+ LValue &Result;
+
+ bool Success(Expr *E) {
+ Result.Base = E;
+ Result.Offset = CharUnits::Zero();
+ return true;
+ }
public:
- PointerExprEvaluator(EvalInfo &info) : Info(info) {}
+ PointerExprEvaluator(EvalInfo &info, LValue &Result)
+ : Info(info), Result(Result) {}
- APValue VisitStmt(Stmt *S) {
- return APValue();
+ bool VisitStmt(Stmt *S) {
+ return false;
}
- APValue VisitParenExpr(ParenExpr *E) { return Visit(E->getSubExpr()); }
+ bool VisitParenExpr(ParenExpr *E) { return Visit(E->getSubExpr()); }
- APValue VisitBinaryOperator(const BinaryOperator *E);
- APValue VisitCastExpr(CastExpr* E);
- APValue VisitUnaryExtension(const UnaryOperator *E)
+ bool VisitBinaryOperator(const BinaryOperator *E);
+ bool VisitCastExpr(CastExpr* E);
+ bool VisitUnaryExtension(const UnaryOperator *E)
{ return Visit(E->getSubExpr()); }
- APValue VisitUnaryAddrOf(const UnaryOperator *E);
- APValue VisitObjCStringLiteral(ObjCStringLiteral *E)
- { return APValue(E); }
- APValue VisitAddrLabelExpr(AddrLabelExpr *E)
- { return APValue(E); }
- APValue VisitCallExpr(CallExpr *E);
- APValue VisitBlockExpr(BlockExpr *E) {
+ bool VisitUnaryAddrOf(const UnaryOperator *E);
+ bool VisitObjCStringLiteral(ObjCStringLiteral *E)
+ { return Success(E); }
+ bool VisitAddrLabelExpr(AddrLabelExpr *E)
+ { return Success(E); }
+ bool VisitCallExpr(CallExpr *E);
+ bool VisitBlockExpr(BlockExpr *E) {
if (!E->hasBlockDeclRefExprs())
- return APValue(E);
- return APValue();
+ return Success(E);
+ return false;
}
- APValue VisitImplicitValueInitExpr(ImplicitValueInitExpr *E)
- { return APValue((Expr*)0); }
- APValue VisitConditionalOperator(ConditionalOperator *E);
- APValue VisitChooseExpr(ChooseExpr *E)
+ bool VisitImplicitValueInitExpr(ImplicitValueInitExpr *E)
+ { return Success((Expr*)0); }
+ bool VisitConditionalOperator(ConditionalOperator *E);
+ bool VisitChooseExpr(ChooseExpr *E)
{ return Visit(E->getChosenSubExpr(Info.Ctx)); }
- APValue VisitCXXNullPtrLiteralExpr(CXXNullPtrLiteralExpr *E)
- { return APValue((Expr*)0); }
+ bool VisitCXXNullPtrLiteralExpr(CXXNullPtrLiteralExpr *E)
+ { return Success((Expr*)0); }
// FIXME: Missing: @protocol, @selector
};
} // end anonymous namespace
-static bool EvaluatePointer(const Expr* E, APValue& Result, EvalInfo &Info) {
- if (!E->getType()->hasPointerRepresentation())
- return false;
- Result = PointerExprEvaluator(Info).Visit(const_cast<Expr*>(E));
- return Result.isLValue();
+static bool EvaluatePointer(const Expr* E, LValue& Result, EvalInfo &Info) {
+ assert(E->getType()->hasPointerRepresentation());
+ return PointerExprEvaluator(Info, Result).Visit(const_cast<Expr*>(E));
}
-APValue PointerExprEvaluator::VisitBinaryOperator(const BinaryOperator *E) {
+bool PointerExprEvaluator::VisitBinaryOperator(const BinaryOperator *E) {
if (E->getOpcode() != BinaryOperator::Add &&
E->getOpcode() != BinaryOperator::Sub)
- return APValue();
+ return false;
const Expr *PExp = E->getLHS();
const Expr *IExp = E->getRHS();
if (IExp->getType()->isPointerType())
std::swap(PExp, IExp);
- APValue ResultLValue;
- if (!EvaluatePointer(PExp, ResultLValue, Info))
- return APValue();
+ if (!EvaluatePointer(PExp, Result, Info))
+ return false;
- llvm::APSInt AdditionalOffset;
- if (!EvaluateInteger(IExp, AdditionalOffset, Info))
- return APValue();
+ llvm::APSInt Offset;
+ if (!EvaluateInteger(IExp, Offset, Info))
+ return false;
+ int64_t AdditionalOffset
+ = Offset.isSigned() ? Offset.getSExtValue()
+ : static_cast<int64_t>(Offset.getZExtValue());
// Compute the new offset in the appropriate width.
QualType PointeeType =
PExp->getType()->getAs<PointerType>()->getPointeeType();
- llvm::APSInt SizeOfPointee(AdditionalOffset);
+ CharUnits SizeOfPointee;
// Explicitly handle GNU void* and function pointer arithmetic extensions.
if (PointeeType->isVoidType() || PointeeType->isFunctionType())
- SizeOfPointee = 1;
+ SizeOfPointee = CharUnits::One();
else
- SizeOfPointee = Info.Ctx.getTypeSizeInChars(PointeeType).getQuantity();
+ SizeOfPointee = Info.Ctx.getTypeSizeInChars(PointeeType);
- llvm::APSInt Offset(AdditionalOffset);
- Offset = ResultLValue.getLValueOffset().getQuantity();
if (E->getOpcode() == BinaryOperator::Add)
- Offset += AdditionalOffset * SizeOfPointee;
+ Result.Offset += AdditionalOffset * SizeOfPointee;
else
- Offset -= AdditionalOffset * SizeOfPointee;
+ Result.Offset -= AdditionalOffset * SizeOfPointee;
- // Sign extend prior to converting back to a char unit.
- if (Offset.getBitWidth() < 64)
- Offset.extend(64);
- return APValue(ResultLValue.getLValueBase(),
- CharUnits::fromQuantity(Offset.getLimitedValue()));
+ return true;
}
-APValue PointerExprEvaluator::VisitUnaryAddrOf(const UnaryOperator *E) {
- APValue result;
- if (EvaluateLValue(E->getSubExpr(), result, Info))
- return result;
- return APValue();
+bool PointerExprEvaluator::VisitUnaryAddrOf(const UnaryOperator *E) {
+ return EvaluateLValue(E->getSubExpr(), Result, Info);
}
-APValue PointerExprEvaluator::VisitCastExpr(CastExpr* E) {
+bool PointerExprEvaluator::VisitCastExpr(CastExpr* E) {
Expr* SubExpr = E->getSubExpr();
switch (E->getCastKind()) {
@@ -471,18 +543,20 @@ APValue PointerExprEvaluator::VisitCastExpr(CastExpr* E) {
return Visit(SubExpr);
if (SubExpr->getType()->isIntegralType()) {
- APValue Result;
- if (!EvaluateIntegerOrLValue(SubExpr, Result, Info))
+ APValue Value;
+ if (!EvaluateIntegerOrLValue(SubExpr, Value, Info))
break;
- if (Result.isInt()) {
- Result.getInt().extOrTrunc((unsigned)Info.Ctx.getTypeSize(E->getType()));
- return APValue(0,
- CharUnits::fromQuantity(Result.getInt().getZExtValue()));
+ if (Value.isInt()) {
+ Value.getInt().extOrTrunc((unsigned)Info.Ctx.getTypeSize(E->getType()));
+ Result.Base = 0;
+ Result.Offset = CharUnits::fromQuantity(Value.getInt().getZExtValue());
+ return true;
+ } else {
+ Result.Base = Value.getLValueBase();
+ Result.Offset = Value.getLValueOffset();
+ return true;
}
-
- // Cast is of an lvalue, no need to change value.
- return Result;
}
break;
}
@@ -494,51 +568,46 @@ APValue PointerExprEvaluator::VisitCastExpr(CastExpr* E) {
return Visit(SubExpr);
case CastExpr::CK_IntegralToPointer: {
- APValue Result;
- if (!EvaluateIntegerOrLValue(SubExpr, Result, Info))
+ APValue Value;
+ if (!EvaluateIntegerOrLValue(SubExpr, Value, Info))
break;
- if (Result.isInt()) {
- Result.getInt().extOrTrunc((unsigned)Info.Ctx.getTypeSize(E->getType()));
- return APValue(0,
- CharUnits::fromQuantity(Result.getInt().getZExtValue()));
+ if (Value.isInt()) {
+ Value.getInt().extOrTrunc((unsigned)Info.Ctx.getTypeSize(E->getType()));
+ Result.Base = 0;
+ Result.Offset = CharUnits::fromQuantity(Value.getInt().getZExtValue());
+ return true;
+ } else {
+ // Cast is of an lvalue, no need to change value.
+ Result.Base = Value.getLValueBase();
+ Result.Offset = Value.getLValueOffset();
+ return true;
}
-
- // Cast is of an lvalue, no need to change value.
- return Result;
}
case CastExpr::CK_ArrayToPointerDecay:
- case CastExpr::CK_FunctionToPointerDecay: {
- APValue Result;
- if (EvaluateLValue(SubExpr, Result, Info))
- return Result;
- break;
- }
+ case CastExpr::CK_FunctionToPointerDecay:
+ return EvaluateLValue(SubExpr, Result, Info);
}
- return APValue();
+ return false;
}
-APValue PointerExprEvaluator::VisitCallExpr(CallExpr *E) {
+bool PointerExprEvaluator::VisitCallExpr(CallExpr *E) {
if (E->isBuiltinCall(Info.Ctx) ==
Builtin::BI__builtin___CFStringMakeConstantString ||
E->isBuiltinCall(Info.Ctx) ==
Builtin::BI__builtin___NSStringMakeConstantString)
- return APValue(E);
- return APValue();
+ return Success(E);
+ return false;
}
-APValue PointerExprEvaluator::VisitConditionalOperator(ConditionalOperator *E) {
+bool PointerExprEvaluator::VisitConditionalOperator(ConditionalOperator *E) {
bool BoolResult;
if (!HandleConversionToBool(E->getCond(), BoolResult, Info))
- return APValue();
+ return false;
Expr* EvalExpr = BoolResult ? E->getTrueExpr() : E->getFalseExpr();
-
- APValue Result;
- if (EvaluatePointer(EvalExpr, Result, Info))
- return Result;
- return APValue();
+ return Visit(EvalExpr);
}
//===----------------------------------------------------------------------===//
@@ -867,18 +936,20 @@ public:
private:
CharUnits GetAlignOfExpr(const Expr *E);
CharUnits GetAlignOfType(QualType T);
+ static QualType GetObjectType(const Expr *E);
+ bool TryEvaluateBuiltinObjectSize(CallExpr *E);
// FIXME: Missing: array subscript of vector, member of vector
};
} // end anonymous namespace
static bool EvaluateIntegerOrLValue(const Expr* E, APValue &Result, EvalInfo &Info) {
- if (!E->getType()->isIntegralType())
- return false;
-
+ assert(E->getType()->isIntegralType());
return IntExprEvaluator(Info, Result).Visit(const_cast<Expr*>(E));
}
static bool EvaluateInteger(const Expr* E, APSInt &Result, EvalInfo &Info) {
+ assert(E->getType()->isIntegralType());
+
APValue Val;
if (!EvaluateIntegerOrLValue(E, Val, Info) || !Val.isInt())
return false;
@@ -984,36 +1055,55 @@ static int EvaluateBuiltinClassifyType(const CallExpr *E) {
return -1;
}
+/// Retrieves the "underlying object type" of the given expression,
+/// as used by __builtin_object_size.
+QualType IntExprEvaluator::GetObjectType(const Expr *E) {
+ if (const DeclRefExpr *DRE = dyn_cast<DeclRefExpr>(E)) {
+ if (const VarDecl *VD = dyn_cast<VarDecl>(DRE->getDecl()))
+ return VD->getType();
+ } else if (isa<CompoundLiteralExpr>(E)) {
+ return E->getType();
+ }
+
+ return QualType();
+}
+
+bool IntExprEvaluator::TryEvaluateBuiltinObjectSize(CallExpr *E) {
+ // TODO: Perhaps we should let LLVM lower this?
+ LValue Base;
+ if (!EvaluatePointer(E->getArg(0), Base, Info))
+ return false;
+
+ // If we can prove the base is null, lower to zero now.
+ const Expr *LVBase = Base.getLValueBase();
+ if (!LVBase) return Success(0, E);
+
+ QualType T = GetObjectType(LVBase);
+ if (T.isNull() ||
+ T->isIncompleteType() ||
+ !T->isObjectType() ||
+ T->isVariablyModifiedType() ||
+ T->isDependentType())
+ return false;
+
+ CharUnits Size = Info.Ctx.getTypeSizeInChars(T);
+ CharUnits Offset = Base.getLValueOffset();
+
+ if (!Offset.isNegative() && Offset <= Size)
+ Size -= Offset;
+ else
+ Size = CharUnits::Zero();
+ return Success(Size.getQuantity(), E);
+}
+
bool IntExprEvaluator::VisitCallExpr(CallExpr *E) {
switch (E->isBuiltinCall(Info.Ctx)) {
default:
return Error(E->getLocStart(), diag::note_invalid_subexpr_in_ice, E);
case Builtin::BI__builtin_object_size: {
- const Expr *Arg = E->getArg(0)->IgnoreParens();
- Expr::EvalResult Base;
-
- // TODO: Perhaps we should let LLVM lower this?
- if (Arg->EvaluateAsAny(Base, Info.Ctx)
- && Base.Val.getKind() == APValue::LValue
- && !Base.HasSideEffects)
- if (const Expr *LVBase = Base.Val.getLValueBase())
- if (const DeclRefExpr *DRE = dyn_cast<DeclRefExpr>(LVBase)) {
- if (const VarDecl *VD = dyn_cast<VarDecl>(DRE->getDecl())) {
- if (!VD->getType()->isIncompleteType()
- && VD->getType()->isObjectType()
- && !VD->getType()->isVariablyModifiedType()
- && !VD->getType()->isDependentType()) {
- CharUnits Size = Info.Ctx.getTypeSizeInChars(VD->getType());
- CharUnits Offset = Base.Val.getLValueOffset();
- if (!Offset.isNegative() && Offset <= Size)
- Size -= Offset;
- else
- Size = CharUnits::Zero();
- return Success(Size.getQuantity(), E);
- }
- }
- }
+ if (TryEvaluateBuiltinObjectSize(E))
+ return true;
// If evaluating the argument has side-effects we can't determine
// the size of the object and lower it to unknown now.
@@ -1098,7 +1188,7 @@ bool IntExprEvaluator::VisitBinaryOperator(const BinaryOperator *E) {
if (LHSTy->isAnyComplexType()) {
assert(RHSTy->isAnyComplexType() && "Invalid comparison");
- APValue LHS, RHS;
+ ComplexValue LHS, RHS;
if (!EvaluateComplex(E->getLHS(), LHS, Info))
return false;
@@ -1173,11 +1263,11 @@ bool IntExprEvaluator::VisitBinaryOperator(const BinaryOperator *E) {
if (LHSTy->isPointerType() && RHSTy->isPointerType()) {
if (E->getOpcode() == BinaryOperator::Sub || E->isEqualityOp()) {
- APValue LHSValue;
+ LValue LHSValue;
if (!EvaluatePointer(E->getLHS(), LHSValue, Info))
return false;
- APValue RHSValue;
+ LValue RHSValue;
if (!EvaluatePointer(E->getRHS(), RHSValue, Info))
return false;
@@ -1463,7 +1553,7 @@ bool IntExprEvaluator::VisitUnaryOperator(const UnaryOperator *E) {
if (E->isOffsetOfOp()) {
// The AST for offsetof is defined in such a way that we can just
// directly Evaluate it as an l-value.
- APValue LV;
+ LValue LV;
if (!EvaluateLValue(E->getSubExpr(), LV, Info))
return false;
if (LV.getLValueBase())
@@ -1538,7 +1628,7 @@ bool IntExprEvaluator::VisitCastExpr(CastExpr *E) {
// FIXME: Clean this up!
if (SrcType->isPointerType()) {
- APValue LV;
+ LValue LV;
if (!EvaluatePointer(SubExpr, LV, Info))
return false;
@@ -1547,7 +1637,7 @@ bool IntExprEvaluator::VisitCastExpr(CastExpr *E) {
if (Info.Ctx.getTypeSize(DestType) != Info.Ctx.getTypeSize(SrcType))
return false;
- Result = LV;
+ LV.moveInto(Result);
return true;
}
@@ -1559,19 +1649,19 @@ bool IntExprEvaluator::VisitCastExpr(CastExpr *E) {
if (SrcType->isArrayType() || SrcType->isFunctionType()) {
// This handles double-conversion cases, where there's both
// an l-value promotion and an implicit conversion to int.
- APValue LV;
+ LValue LV;
if (!EvaluateLValue(SubExpr, LV, Info))
return false;
if (Info.Ctx.getTypeSize(DestType) != Info.Ctx.getTypeSize(Info.Ctx.VoidPtrTy))
return false;
- Result = LV;
+ LV.moveInto(Result);
return true;
}
if (SrcType->isAnyComplexType()) {
- APValue C;
+ ComplexValue C;
if (!EvaluateComplex(SubExpr, C, Info))
return false;
if (C.isComplexFloat())
@@ -1596,7 +1686,7 @@ bool IntExprEvaluator::VisitCastExpr(CastExpr *E) {
bool IntExprEvaluator::VisitUnaryReal(const UnaryOperator *E) {
if (E->getSubExpr()->getType()->isAnyComplexType()) {
- APValue LV;
+ ComplexValue LV;
if (!EvaluateComplex(E->getSubExpr(), LV, Info) || !LV.isComplexInt())
return Error(E->getExprLoc(), diag::note_invalid_subexpr_in_ice, E);
return Success(LV.getComplexIntReal(), E);
@@ -1607,7 +1697,7 @@ bool IntExprEvaluator::VisitUnaryReal(const UnaryOperator *E) {
bool IntExprEvaluator::VisitUnaryImag(const UnaryOperator *E) {
if (E->getSubExpr()->getType()->isComplexIntegerType()) {
- APValue LV;
+ ComplexValue LV;
if (!EvaluateComplex(E->getSubExpr(), LV, Info) || !LV.isComplexInt())
return Error(E->getExprLoc(), diag::note_invalid_subexpr_in_ice, E);
return Success(LV.getComplexIntImag(), E);
@@ -1649,13 +1739,16 @@ public:
{ return Visit(E->getChosenSubExpr(Info.Ctx)); }
bool VisitUnaryExtension(const UnaryOperator *E)
{ return Visit(E->getSubExpr()); }
+ bool VisitUnaryReal(const UnaryOperator *E);
+ bool VisitUnaryImag(const UnaryOperator *E);
- // FIXME: Missing: __real__/__imag__, array subscript of vector,
- // member of vector, ImplicitValueInitExpr
+ // FIXME: Missing: array subscript of vector, member of vector,
+ // ImplicitValueInitExpr
};
} // end anonymous namespace
static bool EvaluateFloat(const Expr* E, APFloat& Result, EvalInfo &Info) {
+ assert(E->getType()->isRealFloatingType());
return FloatExprEvaluator(Info, Result).Visit(const_cast<Expr*>(E));
}
@@ -1736,6 +1829,22 @@ bool FloatExprEvaluator::VisitCallExpr(const CallExpr *E) {
}
}
+bool FloatExprEvaluator::VisitUnaryReal(const UnaryOperator *E) {
+ ComplexValue CV;
+ if (!EvaluateComplex(E->getSubExpr(), CV, Info))
+ return false;
+ Result = CV.FloatReal;
+ return true;
+}
+
+bool FloatExprEvaluator::VisitUnaryImag(const UnaryOperator *E) {
+ ComplexValue CV;
+ if (!EvaluateComplex(E->getSubExpr(), CV, Info))
+ return false;
+ Result = CV.FloatImag;
+ return true;
+}
+
bool FloatExprEvaluator::VisitUnaryOperator(const UnaryOperator *E) {
if (E->getOpcode() == UnaryOperator::Deref)
return false;
@@ -1838,166 +1947,170 @@ bool FloatExprEvaluator::VisitConditionalOperator(ConditionalOperator *E) {
namespace {
class ComplexExprEvaluator
- : public StmtVisitor<ComplexExprEvaluator, APValue> {
+ : public StmtVisitor<ComplexExprEvaluator, bool> {
EvalInfo &Info;
+ ComplexValue &Result;
public:
- ComplexExprEvaluator(EvalInfo &info) : Info(info) {}
+ ComplexExprEvaluator(EvalInfo &info, ComplexValue &Result)
+ : Info(info), Result(Result) {}
//===--------------------------------------------------------------------===//
// Visitor Methods
//===--------------------------------------------------------------------===//
- APValue VisitStmt(Stmt *S) {
- return APValue();
+ bool VisitStmt(Stmt *S) {
+ return false;
}
- APValue VisitParenExpr(ParenExpr *E) { return Visit(E->getSubExpr()); }
+ bool VisitParenExpr(ParenExpr *E) { return Visit(E->getSubExpr()); }
- APValue VisitImaginaryLiteral(ImaginaryLiteral *E) {
+ bool VisitImaginaryLiteral(ImaginaryLiteral *E) {
Expr* SubExpr = E->getSubExpr();
if (SubExpr->getType()->isRealFloatingType()) {
- APFloat Result(0.0);
-
- if (!EvaluateFloat(SubExpr, Result, Info))
- return APValue();
+ Result.makeComplexFloat();
+ APFloat &Imag = Result.FloatImag;
+ if (!EvaluateFloat(SubExpr, Imag, Info))
+ return false;
- return APValue(APFloat(Result.getSemantics(), APFloat::fcZero, false),
- Result);
+ Result.FloatReal = APFloat(Imag.getSemantics());
+ return true;
} else {
assert(SubExpr->getType()->isIntegerType() &&
"Unexpected imaginary literal.");
- llvm::APSInt Result;
- if (!EvaluateInteger(SubExpr, Result, Info))
- return APValue();
+ Result.makeComplexInt();
+ APSInt &Imag = Result.IntImag;
+ if (!EvaluateInteger(SubExpr, Imag, Info))
+ return false;
- llvm::APSInt Zero(Result.getBitWidth(), !Result.isSigned());
- Zero = 0;
- return APValue(Zero, Result);
+ Result.IntReal = APSInt(Imag.getBitWidth(), !Imag.isSigned());
+ return true;
}
}
- APValue VisitCastExpr(CastExpr *E) {
+ bool VisitCastExpr(CastExpr *E) {
Expr* SubExpr = E->getSubExpr();
QualType EltType = E->getType()->getAs<ComplexType>()->getElementType();
QualType SubType = SubExpr->getType();
if (SubType->isRealFloatingType()) {
- APFloat Result(0.0);
-
- if (!EvaluateFloat(SubExpr, Result, Info))
- return APValue();
+ APFloat &Real = Result.FloatReal;
+ if (!EvaluateFloat(SubExpr, Real, Info))
+ return false;
if (EltType->isRealFloatingType()) {
- Result = HandleFloatToFloatCast(EltType, SubType, Result, Info.Ctx);
- return APValue(Result,
- APFloat(Result.getSemantics(), APFloat::fcZero, false));
+ Result.makeComplexFloat();
+ Real = HandleFloatToFloatCast(EltType, SubType, Real, Info.Ctx);
+ Result.FloatImag = APFloat(Real.getSemantics());
+ return true;
} else {
- llvm::APSInt IResult;
- IResult = HandleFloatToIntCast(EltType, SubType, Result, Info.Ctx);
- llvm::APSInt Zero(IResult.getBitWidth(), !IResult.isSigned());
- Zero = 0;
- return APValue(IResult, Zero);
+ Result.makeComplexInt();
+ Result.IntReal = HandleFloatToIntCast(EltType, SubType, Real, Info.Ctx);
+ Result.IntImag = APSInt(Result.IntReal.getBitWidth(),
+ !Result.IntReal.isSigned());
+ return true;
}
} else if (SubType->isIntegerType()) {
- APSInt Result;
-
- if (!EvaluateInteger(SubExpr, Result, Info))
- return APValue();
+ APSInt &Real = Result.IntReal;
+ if (!EvaluateInteger(SubExpr, Real, Info))
+ return false;
if (EltType->isRealFloatingType()) {
- APFloat FResult =
- HandleIntToFloatCast(EltType, SubType, Result, Info.Ctx);
- return APValue(FResult,
- APFloat(FResult.getSemantics(), APFloat::fcZero, false));
+ Result.makeComplexFloat();
+ Result.FloatReal
+ = HandleIntToFloatCast(EltType, SubType, Real, Info.Ctx);
+ Result.FloatImag = APFloat(Result.FloatReal.getSemantics());
+ return true;
} else {
- Result = HandleIntToIntCast(EltType, SubType, Result, Info.Ctx);
- llvm::APSInt Zero(Result.getBitWidth(), !Result.isSigned());
- Zero = 0;
- return APValue(Result, Zero);
+ Result.makeComplexInt();
+ Real = HandleIntToIntCast(EltType, SubType, Real, Info.Ctx);
+ Result.IntImag = APSInt(Real.getBitWidth(), !Real.isSigned());
+ return true;
}
} else if (const ComplexType *CT = SubType->getAs<ComplexType>()) {
- APValue Src;
-
- if (!EvaluateComplex(SubExpr, Src, Info))
- return APValue();
+ if (!Visit(SubExpr))
+ return false;
QualType SrcType = CT->getElementType();
- if (Src.isComplexFloat()) {
+ if (Result.isComplexFloat()) {
if (EltType->isRealFloatingType()) {
- return APValue(HandleFloatToFloatCast(EltType, SrcType,
- Src.getComplexFloatReal(),
- Info.Ctx),
- HandleFloatToFloatCast(EltType, SrcType,
- Src.getComplexFloatImag(),
- Info.Ctx));
+ Result.makeComplexFloat();
+ Result.FloatReal = HandleFloatToFloatCast(EltType, SrcType,
+ Result.FloatReal,
+ Info.Ctx);
+ Result.FloatImag = HandleFloatToFloatCast(EltType, SrcType,
+ Result.FloatImag,
+ Info.Ctx);
+ return true;
} else {
- return APValue(HandleFloatToIntCast(EltType, SrcType,
- Src.getComplexFloatReal(),
- Info.Ctx),
- HandleFloatToIntCast(EltType, SrcType,
- Src.getComplexFloatImag(),
- Info.Ctx));
+ Result.makeComplexInt();
+ Result.IntReal = HandleFloatToIntCast(EltType, SrcType,
+ Result.FloatReal,
+ Info.Ctx);
+ Result.IntImag = HandleFloatToIntCast(EltType, SrcType,
+ Result.FloatImag,
+ Info.Ctx);
+ return true;
}
} else {
- assert(Src.isComplexInt() && "Invalid evaluate result.");
+ assert(Result.isComplexInt() && "Invalid evaluate result.");
if (EltType->isRealFloatingType()) {
- return APValue(HandleIntToFloatCast(EltType, SrcType,
- Src.getComplexIntReal(),
- Info.Ctx),
- HandleIntToFloatCast(EltType, SrcType,
- Src.getComplexIntImag(),
- Info.Ctx));
+ Result.makeComplexFloat();
+ Result.FloatReal = HandleIntToFloatCast(EltType, SrcType,
+ Result.IntReal,
+ Info.Ctx);
+ Result.FloatImag = HandleIntToFloatCast(EltType, SrcType,
+ Result.IntImag,
+ Info.Ctx);
+ return true;
} else {
- return APValue(HandleIntToIntCast(EltType, SrcType,
- Src.getComplexIntReal(),
- Info.Ctx),
- HandleIntToIntCast(EltType, SrcType,
- Src.getComplexIntImag(),
- Info.Ctx));
+ Result.makeComplexInt();
+ Result.IntReal = HandleIntToIntCast(EltType, SrcType,
+ Result.IntReal,
+ Info.Ctx);
+ Result.IntImag = HandleIntToIntCast(EltType, SrcType,
+ Result.IntImag,
+ Info.Ctx);
+ return true;
}
}
}
// FIXME: Handle more casts.
- return APValue();
+ return false;
}
- APValue VisitBinaryOperator(const BinaryOperator *E);
- APValue VisitChooseExpr(const ChooseExpr *E)
+ bool VisitBinaryOperator(const BinaryOperator *E);
+ bool VisitChooseExpr(const ChooseExpr *E)
{ return Visit(E->getChosenSubExpr(Info.Ctx)); }
- APValue VisitUnaryExtension(const UnaryOperator *E)
+ bool VisitUnaryExtension(const UnaryOperator *E)
{ return Visit(E->getSubExpr()); }
// FIXME Missing: unary +/-/~, binary div, ImplicitValueInitExpr,
// conditional ?:, comma
};
} // end anonymous namespace
-static bool EvaluateComplex(const Expr *E, APValue &Result, EvalInfo &Info) {
- Result = ComplexExprEvaluator(Info).Visit(const_cast<Expr*>(E));
- assert((!Result.isComplexFloat() ||
- (&Result.getComplexFloatReal().getSemantics() ==
- &Result.getComplexFloatImag().getSemantics())) &&
- "Invalid complex evaluation.");
- return Result.isComplexFloat() || Result.isComplexInt();
+static bool EvaluateComplex(const Expr *E, ComplexValue &Result,
+ EvalInfo &Info) {
+ assert(E->getType()->isAnyComplexType());
+ return ComplexExprEvaluator(Info, Result).Visit(const_cast<Expr*>(E));
}
-APValue ComplexExprEvaluator::VisitBinaryOperator(const BinaryOperator *E) {
- APValue Result, RHS;
-
- if (!EvaluateComplex(E->getLHS(), Result, Info))
- return APValue();
+bool ComplexExprEvaluator::VisitBinaryOperator(const BinaryOperator *E) {
+ if (!Visit(E->getLHS()))
+ return false;
+ ComplexValue RHS;
if (!EvaluateComplex(E->getRHS(), RHS, Info))
- return APValue();
+ return false;
assert(Result.isComplexFloat() == RHS.isComplexFloat() &&
"Invalid operands to binary operator.");
switch (E->getOpcode()) {
- default: return APValue();
+ default: return false;
case BinaryOperator::Add:
if (Result.isComplexFloat()) {
Result.getComplexFloatReal().add(RHS.getComplexFloatReal(),
@@ -2022,7 +2135,7 @@ APValue ComplexExprEvaluator::VisitBinaryOperator(const BinaryOperator *E) {
break;
case BinaryOperator::Mul:
if (Result.isComplexFloat()) {
- APValue LHS = Result;
+ ComplexValue LHS = Result;
APFloat &LHS_r = LHS.getComplexFloatReal();
APFloat &LHS_i = LHS.getComplexFloatImag();
APFloat &RHS_r = RHS.getComplexFloatReal();
@@ -2042,7 +2155,7 @@ APValue ComplexExprEvaluator::VisitBinaryOperator(const BinaryOperator *E) {
Tmp.multiply(RHS_r, APFloat::rmNearestTiesToEven);
Result.getComplexFloatImag().add(Tmp, APFloat::rmNearestTiesToEven);
} else {
- APValue LHS = Result;
+ ComplexValue LHS = Result;
Result.getComplexIntReal() =
(LHS.getComplexIntReal() * RHS.getComplexIntReal() -
LHS.getComplexIntImag() * RHS.getComplexIntImag());
@@ -2053,7 +2166,7 @@ APValue ComplexExprEvaluator::VisitBinaryOperator(const BinaryOperator *E) {
break;
}
- return Result;
+ return true;
}
//===----------------------------------------------------------------------===//
@@ -2065,53 +2178,32 @@ APValue ComplexExprEvaluator::VisitBinaryOperator(const BinaryOperator *E) {
/// we want to. If this function returns true, it returns the folded constant
/// in Result.
bool Expr::Evaluate(EvalResult &Result, ASTContext &Ctx) const {
+ const Expr *E = this;
EvalInfo Info(Ctx, Result);
-
- if (getType()->isVectorType()) {
- if (!EvaluateVector(this, Result.Val, Info))
+ if (E->getType()->isVectorType()) {
+ if (!EvaluateVector(E, Info.EvalResult.Val, Info))
return false;
- } else if (getType()->isIntegerType()) {
- if (!IntExprEvaluator(Info, Result.Val).Visit(const_cast<Expr*>(this)))
+ } else if (E->getType()->isIntegerType()) {
+ if (!IntExprEvaluator(Info, Info.EvalResult.Val).Visit(const_cast<Expr*>(E)))
return false;
- } else if (getType()->hasPointerRepresentation()) {
- if (!EvaluatePointer(this, Result.Val, Info))
- return false;
- } else if (getType()->isRealFloatingType()) {
- llvm::APFloat f(0.0);
- if (!EvaluateFloat(this, f, Info))
- return false;
-
- Result.Val = APValue(f);
- } else if (getType()->isAnyComplexType()) {
- if (!EvaluateComplex(this, Result.Val, Info))
- return false;
- } else
- return false;
-
- return true;
-}
-
-bool Expr::EvaluateAsAny(EvalResult &Result, ASTContext &Ctx) const {
- EvalInfo Info(Ctx, Result, true);
-
- if (getType()->isVectorType()) {
- if (!EvaluateVector(this, Result.Val, Info))
- return false;
- } else if (getType()->isIntegerType()) {
- if (!IntExprEvaluator(Info, Result.Val).Visit(const_cast<Expr*>(this)))
+ } else if (E->getType()->hasPointerRepresentation()) {
+ LValue LV;
+ if (!EvaluatePointer(E, LV, Info))
return false;
- } else if (getType()->hasPointerRepresentation()) {
- if (!EvaluatePointer(this, Result.Val, Info))
+ if (!IsGlobalLValue(LV.Base))
return false;
- } else if (getType()->isRealFloatingType()) {
- llvm::APFloat f(0.0);
- if (!EvaluateFloat(this, f, Info))
+ LV.moveInto(Info.EvalResult.Val);
+ } else if (E->getType()->isRealFloatingType()) {
+ llvm::APFloat F(0.0);
+ if (!EvaluateFloat(E, F, Info))
return false;
- Result.Val = APValue(f);
- } else if (getType()->isAnyComplexType()) {
- if (!EvaluateComplex(this, Result.Val, Info))
+ Info.EvalResult.Val = APValue(F);
+ } else if (E->getType()->isAnyComplexType()) {
+ ComplexValue C;
+ if (!EvaluateComplex(E, C, Info))
return false;
+ C.moveInto(Info.EvalResult.Val);
} else
return false;
@@ -2128,13 +2220,25 @@ bool Expr::EvaluateAsBooleanCondition(bool &Result, ASTContext &Ctx) const {
bool Expr::EvaluateAsLValue(EvalResult &Result, ASTContext &Ctx) const {
EvalInfo Info(Ctx, Result);
- return EvaluateLValue(this, Result.Val, Info) && !Result.HasSideEffects;
+ LValue LV;
+ if (EvaluateLValue(this, LV, Info) &&
+ !Result.HasSideEffects &&
+ IsGlobalLValue(LV.Base)) {
+ LV.moveInto(Result.Val);
+ return true;
+ }
+ return false;
}
bool Expr::EvaluateAsAnyLValue(EvalResult &Result, ASTContext &Ctx) const {
- EvalInfo Info(Ctx, Result, true);
+ EvalInfo Info(Ctx, Result);
- return EvaluateLValue(this, Result.Val, Info) && !Result.HasSideEffects;
+ LValue LV;
+ if (EvaluateLValue(this, LV, Info)) {
+ LV.moveInto(Result.Val);
+ return true;
+ }
+ return false;
}
/// isEvaluatable - Call Evaluate to see if this expression can be constant
@@ -2159,3 +2263,388 @@ APSInt Expr::EvaluateAsInt(ASTContext &Ctx) const {
return EvalResult.Val.getInt();
}
+
+ bool Expr::EvalResult::isGlobalLValue() const {
+ assert(Val.isLValue());
+ return IsGlobalLValue(Val.getLValueBase());
+ }
+
+
+/// isIntegerConstantExpr - this recursive routine will test if an expression is
+/// an integer constant expression.
+
+/// FIXME: Pass up a reason why! Invalid operation in i-c-e, division by zero,
+/// comma, etc
+///
+/// FIXME: Handle offsetof. Two things to do: Handle GCC's __builtin_offsetof
+/// to support gcc 4.0+ and handle the idiom GCC recognizes with a null pointer
+/// cast+dereference.
+
+// CheckICE - This function does the fundamental ICE checking: the returned
+// ICEDiag contains a Val of 0, 1, or 2, and a possibly null SourceLocation.
+// Note that to reduce code duplication, this helper does no evaluation
+// itself; the caller checks whether the expression is evaluatable, and
+// in the rare cases where CheckICE actually cares about the evaluated
+// value, it calls into Evalute.
+//
+// Meanings of Val:
+// 0: This expression is an ICE if it can be evaluated by Evaluate.
+// 1: This expression is not an ICE, but if it isn't evaluated, it's
+// a legal subexpression for an ICE. This return value is used to handle
+// the comma operator in C99 mode.
+// 2: This expression is not an ICE, and is not a legal subexpression for one.
+
+struct ICEDiag {
+ unsigned Val;
+ SourceLocation Loc;
+
+ public:
+ ICEDiag(unsigned v, SourceLocation l) : Val(v), Loc(l) {}
+ ICEDiag() : Val(0) {}
+};
+
+ICEDiag NoDiag() { return ICEDiag(); }
+
+static ICEDiag CheckEvalInICE(const Expr* E, ASTContext &Ctx) {
+ Expr::EvalResult EVResult;
+ if (!E->Evaluate(EVResult, Ctx) || EVResult.HasSideEffects ||
+ !EVResult.Val.isInt()) {
+ return ICEDiag(2, E->getLocStart());
+ }
+ return NoDiag();
+}
+
+static ICEDiag CheckICE(const Expr* E, ASTContext &Ctx) {
+ assert(!E->isValueDependent() && "Should not see value dependent exprs!");
+ if (!E->getType()->isIntegralType()) {
+ return ICEDiag(2, E->getLocStart());
+ }
+
+ switch (E->getStmtClass()) {
+#define STMT(Node, Base) case Expr::Node##Class:
+#define EXPR(Node, Base)
+#include "clang/AST/StmtNodes.inc"
+ case Expr::PredefinedExprClass:
+ case Expr::FloatingLiteralClass:
+ case Expr::ImaginaryLiteralClass:
+ case Expr::StringLiteralClass:
+ case Expr::ArraySubscriptExprClass:
+ case Expr::MemberExprClass:
+ case Expr::CompoundAssignOperatorClass:
+ case Expr::CompoundLiteralExprClass:
+ case Expr::ExtVectorElementExprClass:
+ case Expr::InitListExprClass:
+ case Expr::DesignatedInitExprClass:
+ case Expr::ImplicitValueInitExprClass:
+ case Expr::ParenListExprClass:
+ case Expr::VAArgExprClass:
+ case Expr::AddrLabelExprClass:
+ case Expr::StmtExprClass:
+ case Expr::CXXMemberCallExprClass:
+ case Expr::CXXDynamicCastExprClass:
+ case Expr::CXXTypeidExprClass:
+ case Expr::CXXNullPtrLiteralExprClass:
+ case Expr::CXXThisExprClass:
+ case Expr::CXXThrowExprClass:
+ case Expr::CXXNewExprClass:
+ case Expr::CXXDeleteExprClass:
+ case Expr::CXXPseudoDestructorExprClass:
+ case Expr::UnresolvedLookupExprClass:
+ case Expr::DependentScopeDeclRefExprClass:
+ case Expr::CXXConstructExprClass:
+ case Expr::CXXBindTemporaryExprClass:
+ case Expr::CXXBindReferenceExprClass:
+ case Expr::CXXExprWithTemporariesClass:
+ case Expr::CXXTemporaryObjectExprClass:
+ case Expr::CXXUnresolvedConstructExprClass:
+ case Expr::CXXDependentScopeMemberExprClass:
+ case Expr::UnresolvedMemberExprClass:
+ case Expr::ObjCStringLiteralClass:
+ case Expr::ObjCEncodeExprClass:
+ case Expr::ObjCMessageExprClass:
+ case Expr::ObjCSelectorExprClass:
+ case Expr::ObjCProtocolExprClass:
+ case Expr::ObjCIvarRefExprClass:
+ case Expr::ObjCPropertyRefExprClass:
+ case Expr::ObjCImplicitSetterGetterRefExprClass:
+ case Expr::ObjCSuperExprClass:
+ case Expr::ObjCIsaExprClass:
+ case Expr::ShuffleVectorExprClass:
+ case Expr::BlockExprClass:
+ case Expr::BlockDeclRefExprClass:
+ case Expr::NoStmtClass:
+ return ICEDiag(2, E->getLocStart());
+
+ case Expr::GNUNullExprClass:
+ // GCC considers the GNU __null value to be an integral constant expression.
+ return NoDiag();
+
+ case Expr::ParenExprClass:
+ return CheckICE(cast<ParenExpr>(E)->getSubExpr(), Ctx);
+ case Expr::IntegerLiteralClass:
+ case Expr::CharacterLiteralClass:
+ case Expr::CXXBoolLiteralExprClass:
+ case Expr::CXXZeroInitValueExprClass:
+ case Expr::TypesCompatibleExprClass:
+ case Expr::UnaryTypeTraitExprClass:
+ return NoDiag();
+ case Expr::CallExprClass:
+ case Expr::CXXOperatorCallExprClass: {
+ const CallExpr *CE = cast<CallExpr>(E);
+ if (CE->isBuiltinCall(Ctx))
+ return CheckEvalInICE(E, Ctx);
+ return ICEDiag(2, E->getLocStart());
+ }
+ case Expr::DeclRefExprClass:
+ if (isa<EnumConstantDecl>(cast<DeclRefExpr>(E)->getDecl()))
+ return NoDiag();
+ if (Ctx.getLangOptions().CPlusPlus &&
+ E->getType().getCVRQualifiers() == Qualifiers::Const) {
+ const NamedDecl *D = cast<DeclRefExpr>(E)->getDecl();
+
+ // Parameter variables are never constants. Without this check,
+ // getAnyInitializer() can find a default argument, which leads
+ // to chaos.
+ if (isa<ParmVarDecl>(D))
+ return ICEDiag(2, cast<DeclRefExpr>(E)->getLocation());
+
+ // C++ 7.1.5.1p2
+ // A variable of non-volatile const-qualified integral or enumeration
+ // type initialized by an ICE can be used in ICEs.
+ if (const VarDecl *Dcl = dyn_cast<VarDecl>(D)) {
+ Qualifiers Quals = Ctx.getCanonicalType(Dcl->getType()).getQualifiers();
+ if (Quals.hasVolatile() || !Quals.hasConst())
+ return ICEDiag(2, cast<DeclRefExpr>(E)->getLocation());
+
+ // Look for a declaration of this variable that has an initializer.
+ const VarDecl *ID = 0;
+ const Expr *Init = Dcl->getAnyInitializer(ID);
+ if (Init) {
+ if (ID->isInitKnownICE()) {
+ // We have already checked whether this subexpression is an
+ // integral constant expression.
+ if (ID->isInitICE())
+ return NoDiag();
+ else
+ return ICEDiag(2, cast<DeclRefExpr>(E)->getLocation());
+ }
+
+ // It's an ICE whether or not the definition we found is
+ // out-of-line. See DR 721 and the discussion in Clang PR
+ // 6206 for details.
+
+ if (Dcl->isCheckingICE()) {
+ return ICEDiag(2, cast<DeclRefExpr>(E)->getLocation());
+ }
+
+ Dcl->setCheckingICE();
+ ICEDiag Result = CheckICE(Init, Ctx);
+ // Cache the result of the ICE test.
+ Dcl->setInitKnownICE(Result.Val == 0);
+ return Result;
+ }
+ }
+ }
+ return ICEDiag(2, E->getLocStart());
+ case Expr::UnaryOperatorClass: {
+ const UnaryOperator *Exp = cast<UnaryOperator>(E);
+ switch (Exp->getOpcode()) {
+ case UnaryOperator::PostInc:
+ case UnaryOperator::PostDec:
+ case UnaryOperator::PreInc:
+ case UnaryOperator::PreDec:
+ case UnaryOperator::AddrOf:
+ case UnaryOperator::Deref:
+ return ICEDiag(2, E->getLocStart());
+ case UnaryOperator::Extension:
+ case UnaryOperator::LNot:
+ case UnaryOperator::Plus:
+ case UnaryOperator::Minus:
+ case UnaryOperator::Not:
+ case UnaryOperator::Real:
+ case UnaryOperator::Imag:
+ return CheckICE(Exp->getSubExpr(), Ctx);
+ case UnaryOperator::OffsetOf:
+ break;
+ }
+
+ // OffsetOf falls through here.
+ }
+ case Expr::OffsetOfExprClass: {
+ // Note that per C99, offsetof must be an ICE. And AFAIK, using
+ // Evaluate matches the proposed gcc behavior for cases like
+ // "offsetof(struct s{int x[4];}, x[!.0])". This doesn't affect
+ // compliance: we should warn earlier for offsetof expressions with
+ // array subscripts that aren't ICEs, and if the array subscripts
+ // are ICEs, the value of the offsetof must be an integer constant.
+ return CheckEvalInICE(E, Ctx);
+ }
+ case Expr::SizeOfAlignOfExprClass: {
+ const SizeOfAlignOfExpr *Exp = cast<SizeOfAlignOfExpr>(E);
+ if (Exp->isSizeOf() && Exp->getTypeOfArgument()->isVariableArrayType())
+ return ICEDiag(2, E->getLocStart());
+ return NoDiag();
+ }
+ case Expr::BinaryOperatorClass: {
+ const BinaryOperator *Exp = cast<BinaryOperator>(E);
+ switch (Exp->getOpcode()) {
+ case BinaryOperator::PtrMemD:
+ case BinaryOperator::PtrMemI:
+ case BinaryOperator::Assign:
+ case BinaryOperator::MulAssign:
+ case BinaryOperator::DivAssign:
+ case BinaryOperator::RemAssign:
+ case BinaryOperator::AddAssign:
+ case BinaryOperator::SubAssign:
+ case BinaryOperator::ShlAssign:
+ case BinaryOperator::ShrAssign:
+ case BinaryOperator::AndAssign:
+ case BinaryOperator::XorAssign:
+ case BinaryOperator::OrAssign:
+ return ICEDiag(2, E->getLocStart());
+
+ case BinaryOperator::Mul:
+ case BinaryOperator::Div:
+ case BinaryOperator::Rem:
+ case BinaryOperator::Add:
+ case BinaryOperator::Sub:
+ case BinaryOperator::Shl:
+ case BinaryOperator::Shr:
+ case BinaryOperator::LT:
+ case BinaryOperator::GT:
+ case BinaryOperator::LE:
+ case BinaryOperator::GE:
+ case BinaryOperator::EQ:
+ case BinaryOperator::NE:
+ case BinaryOperator::And:
+ case BinaryOperator::Xor:
+ case BinaryOperator::Or:
+ case BinaryOperator::Comma: {
+ ICEDiag LHSResult = CheckICE(Exp->getLHS(), Ctx);
+ ICEDiag RHSResult = CheckICE(Exp->getRHS(), Ctx);
+ if (Exp->getOpcode() == BinaryOperator::Div ||
+ Exp->getOpcode() == BinaryOperator::Rem) {
+ // Evaluate gives an error for undefined Div/Rem, so make sure
+ // we don't evaluate one.
+ if (LHSResult.Val != 2 && RHSResult.Val != 2) {
+ llvm::APSInt REval = Exp->getRHS()->EvaluateAsInt(Ctx);
+ if (REval == 0)
+ return ICEDiag(1, E->getLocStart());
+ if (REval.isSigned() && REval.isAllOnesValue()) {
+ llvm::APSInt LEval = Exp->getLHS()->EvaluateAsInt(Ctx);
+ if (LEval.isMinSignedValue())
+ return ICEDiag(1, E->getLocStart());
+ }
+ }
+ }
+ if (Exp->getOpcode() == BinaryOperator::Comma) {
+ if (Ctx.getLangOptions().C99) {
+ // C99 6.6p3 introduces a strange edge case: comma can be in an ICE
+ // if it isn't evaluated.
+ if (LHSResult.Val == 0 && RHSResult.Val == 0)
+ return ICEDiag(1, E->getLocStart());
+ } else {
+ // In both C89 and C++, commas in ICEs are illegal.
+ return ICEDiag(2, E->getLocStart());
+ }
+ }
+ if (LHSResult.Val >= RHSResult.Val)
+ return LHSResult;
+ return RHSResult;
+ }
+ case BinaryOperator::LAnd:
+ case BinaryOperator::LOr: {
+ ICEDiag LHSResult = CheckICE(Exp->getLHS(), Ctx);
+ ICEDiag RHSResult = CheckICE(Exp->getRHS(), Ctx);
+ if (LHSResult.Val == 0 && RHSResult.Val == 1) {
+ // Rare case where the RHS has a comma "side-effect"; we need
+ // to actually check the condition to see whether the side
+ // with the comma is evaluated.
+ if ((Exp->getOpcode() == BinaryOperator::LAnd) !=
+ (Exp->getLHS()->EvaluateAsInt(Ctx) == 0))
+ return RHSResult;
+ return NoDiag();
+ }
+
+ if (LHSResult.Val >= RHSResult.Val)
+ return LHSResult;
+ return RHSResult;
+ }
+ }
+ }
+ case Expr::ImplicitCastExprClass:
+ case Expr::CStyleCastExprClass:
+ case Expr::CXXFunctionalCastExprClass:
+ case Expr::CXXStaticCastExprClass:
+ case Expr::CXXReinterpretCastExprClass:
+ case Expr::CXXConstCastExprClass: {
+ const Expr *SubExpr = cast<CastExpr>(E)->getSubExpr();
+ if (SubExpr->getType()->isIntegralType())
+ return CheckICE(SubExpr, Ctx);
+ if (isa<FloatingLiteral>(SubExpr->IgnoreParens()))
+ return NoDiag();
+ return ICEDiag(2, E->getLocStart());
+ }
+ case Expr::ConditionalOperatorClass: {
+ const ConditionalOperator *Exp = cast<ConditionalOperator>(E);
+ // If the condition (ignoring parens) is a __builtin_constant_p call,
+ // then only the true side is actually considered in an integer constant
+ // expression, and it is fully evaluated. This is an important GNU
+ // extension. See GCC PR38377 for discussion.
+ if (const CallExpr *CallCE
+ = dyn_cast<CallExpr>(Exp->getCond()->IgnoreParenCasts()))
+ if (CallCE->isBuiltinCall(Ctx) == Builtin::BI__builtin_constant_p) {
+ Expr::EvalResult EVResult;
+ if (!E->Evaluate(EVResult, Ctx) || EVResult.HasSideEffects ||
+ !EVResult.Val.isInt()) {
+ return ICEDiag(2, E->getLocStart());
+ }
+ return NoDiag();
+ }
+ ICEDiag CondResult = CheckICE(Exp->getCond(), Ctx);
+ ICEDiag TrueResult = CheckICE(Exp->getTrueExpr(), Ctx);
+ ICEDiag FalseResult = CheckICE(Exp->getFalseExpr(), Ctx);
+ if (CondResult.Val == 2)
+ return CondResult;
+ if (TrueResult.Val == 2)
+ return TrueResult;
+ if (FalseResult.Val == 2)
+ return FalseResult;
+ if (CondResult.Val == 1)
+ return CondResult;
+ if (TrueResult.Val == 0 && FalseResult.Val == 0)
+ return NoDiag();
+ // Rare case where the diagnostics depend on which side is evaluated
+ // Note that if we get here, CondResult is 0, and at least one of
+ // TrueResult and FalseResult is non-zero.
+ if (Exp->getCond()->EvaluateAsInt(Ctx) == 0) {
+ return FalseResult;
+ }
+ return TrueResult;
+ }
+ case Expr::CXXDefaultArgExprClass:
+ return CheckICE(cast<CXXDefaultArgExpr>(E)->getExpr(), Ctx);
+ case Expr::ChooseExprClass: {
+ return CheckICE(cast<ChooseExpr>(E)->getChosenSubExpr(Ctx), Ctx);
+ }
+ }
+
+ // Silence a GCC warning
+ return ICEDiag(2, E->getLocStart());
+}
+
+bool Expr::isIntegerConstantExpr(llvm::APSInt &Result, ASTContext &Ctx,
+ SourceLocation *Loc, bool isEvaluated) const {
+ ICEDiag d = CheckICE(this, Ctx);
+ if (d.Val != 0) {
+ if (Loc) *Loc = d.Loc;
+ return false;
+ }
+ EvalResult EvalResult;
+ if (!Evaluate(EvalResult, Ctx))
+ llvm_unreachable("ICE cannot be evaluated!");
+ assert(!EvalResult.HasSideEffects && "ICE with side effects!");
+ assert(EvalResult.Val.isInt() && "ICE that isn't integer!");
+ Result = EvalResult.Val.getInt();
+ return true;
+}
diff --git a/lib/AST/NestedNameSpecifier.cpp b/lib/AST/NestedNameSpecifier.cpp
index 45518e98bc15..d6594cdfd02f 100644
--- a/lib/AST/NestedNameSpecifier.cpp
+++ b/lib/AST/NestedNameSpecifier.cpp
@@ -145,14 +145,14 @@ NestedNameSpecifier::print(llvm::raw_ostream &OS,
InnerPolicy.SuppressScope = true;
// Nested-name-specifiers are intended to contain minimally-qualified
- // types. An actual QualifiedNameType will not occur, since we'll store
+ // types. An actual ElaboratedType will not occur, since we'll store
// just the type that is referred to in the nested-name-specifier (e.g.,
// a TypedefType, TagType, etc.). However, when we are dealing with
// dependent template-id types (e.g., Outer<T>::template Inner<U>),
// the type requires its own nested-name-specifier for uniqueness, so we
// suppress that nested-name-specifier during printing.
- assert(!isa<QualifiedNameType>(T) &&
- "Qualified name type in nested-name-specifier");
+ assert(!isa<ElaboratedType>(T) &&
+ "Elaborated type in nested-name-specifier");
if (const TemplateSpecializationType *SpecType
= dyn_cast<TemplateSpecializationType>(T)) {
// Print the template name without its corresponding
diff --git a/lib/AST/RecordLayout.cpp b/lib/AST/RecordLayout.cpp
index ade2483722ef..262c4597f846 100644
--- a/lib/AST/RecordLayout.cpp
+++ b/lib/AST/RecordLayout.cpp
@@ -44,7 +44,9 @@ ASTRecordLayout::ASTRecordLayout(ASTContext &Ctx,
unsigned fieldcount,
uint64_t nonvirtualsize,
unsigned nonvirtualalign,
- const PrimaryBaseInfo &PrimaryBase,
+ uint64_t SizeOfLargestEmptySubobject,
+ const CXXRecordDecl *PrimaryBase,
+ bool PrimaryBaseIsVirtual,
const BaseOffsetsMapTy& BaseOffsets,
const BaseOffsetsMapTy& VBaseOffsets)
: Size(size), DataSize(datasize), FieldOffsets(0), Alignment(alignment),
@@ -55,9 +57,10 @@ ASTRecordLayout::ASTRecordLayout(ASTContext &Ctx,
memcpy(FieldOffsets, fieldoffsets, FieldCount * sizeof(*FieldOffsets));
}
- CXXInfo->PrimaryBase = PrimaryBase;
+ CXXInfo->PrimaryBase = PrimaryBaseInfo(PrimaryBase, PrimaryBaseIsVirtual);
CXXInfo->NonVirtualSize = nonvirtualsize;
CXXInfo->NonVirtualAlign = nonvirtualalign;
+ CXXInfo->SizeOfLargestEmptySubobject = SizeOfLargestEmptySubobject;
CXXInfo->BaseOffsets = BaseOffsets;
CXXInfo->VBaseOffsets = VBaseOffsets;
diff --git a/lib/AST/RecordLayoutBuilder.cpp b/lib/AST/RecordLayoutBuilder.cpp
index 3782985e5302..983a2874a735 100644
--- a/lib/AST/RecordLayoutBuilder.cpp
+++ b/lib/AST/RecordLayoutBuilder.cpp
@@ -1,4 +1,4 @@
-//=== ASTRecordLayoutBuilder.cpp - Helper class for building record layouts ==//
+//=== RecordLayoutBuilder.cpp - Helper class for building record layouts ---==//
//
// The LLVM Compiler Infrastructure
//
@@ -7,28 +7,443 @@
//
//===----------------------------------------------------------------------===//
-#include "RecordLayoutBuilder.h"
-
#include "clang/AST/Attr.h"
#include "clang/AST/Decl.h"
#include "clang/AST/DeclCXX.h"
#include "clang/AST/DeclObjC.h"
#include "clang/AST/Expr.h"
+#include "clang/AST/RecordLayout.h"
#include "clang/Basic/TargetInfo.h"
#include "llvm/Support/Format.h"
#include "llvm/ADT/SmallSet.h"
#include "llvm/Support/MathExtras.h"
+#include <map>
using namespace clang;
-ASTRecordLayoutBuilder::ASTRecordLayoutBuilder(ASTContext &Context)
- : Context(Context), Size(0), Alignment(8), Packed(false),
- UnfilledBitsInLastByte(0), MaxFieldAlignment(0), DataSize(0), IsUnion(false),
- NonVirtualSize(0), NonVirtualAlignment(8), FirstNearlyEmptyVBase(0) { }
+namespace {
+
+/// EmptySubobjectMap - Keeps track of which empty subobjects exist at different
+/// offsets while laying out a C++ class.
+class EmptySubobjectMap {
+ ASTContext &Context;
+
+ /// Class - The class whose empty entries we're keeping track of.
+ const CXXRecordDecl *Class;
+
+ /// EmptyClassOffsets - A map from offsets to empty record decls.
+ typedef llvm::SmallVector<const CXXRecordDecl *, 1> ClassVectorTy;
+ typedef llvm::DenseMap<uint64_t, ClassVectorTy> EmptyClassOffsetsMapTy;
+ EmptyClassOffsetsMapTy EmptyClassOffsets;
+
+ /// ComputeEmptySubobjectSizes - Compute the size of the largest base or
+ /// member subobject that is empty.
+ void ComputeEmptySubobjectSizes();
+
+ struct BaseInfo {
+ const CXXRecordDecl *Class;
+ bool IsVirtual;
+
+ const CXXRecordDecl *PrimaryVirtualBase;
+
+ llvm::SmallVector<BaseInfo*, 4> Bases;
+ const BaseInfo *Derived;
+ };
+
+ llvm::DenseMap<const CXXRecordDecl *, BaseInfo *> VirtualBaseInfo;
+ llvm::DenseMap<const CXXRecordDecl *, BaseInfo *> NonVirtualBaseInfo;
+
+ BaseInfo *ComputeBaseInfo(const CXXRecordDecl *RD, bool IsVirtual,
+ const BaseInfo *Derived);
+ void ComputeBaseInfo();
+
+ bool CanPlaceBaseSubobjectAtOffset(const BaseInfo *Info, uint64_t Offset);
+ void UpdateEmptyBaseSubobjects(const BaseInfo *Info, uint64_t Offset);
+
+public:
+ /// This holds the size of the largest empty subobject (either a base
+ /// or a member). Will be zero if the record being built doesn't contain
+ /// any empty classes.
+ uint64_t SizeOfLargestEmptySubobject;
+
+ EmptySubobjectMap(ASTContext &Context, const CXXRecordDecl *Class)
+ : Context(Context), Class(Class), SizeOfLargestEmptySubobject(0) {
+ ComputeEmptySubobjectSizes();
+
+ ComputeBaseInfo();
+ }
+
+ /// CanPlaceBaseAtOffset - Return whether the given base class can be placed
+ /// at the given offset.
+ /// Returns false if placing the record will result in two components
+ /// (direct or indirect) of the same type having the same offset.
+ bool CanPlaceBaseAtOffset(const CXXRecordDecl *RD, bool BaseIsVirtual,
+ uint64_t Offset);
+};
+
+void EmptySubobjectMap::ComputeEmptySubobjectSizes() {
+ // Check the bases.
+ for (CXXRecordDecl::base_class_const_iterator I = Class->bases_begin(),
+ E = Class->bases_end(); I != E; ++I) {
+ const CXXRecordDecl *BaseDecl =
+ cast<CXXRecordDecl>(I->getType()->getAs<RecordType>()->getDecl());
+
+ uint64_t EmptySize = 0;
+ const ASTRecordLayout &Layout = Context.getASTRecordLayout(BaseDecl);
+ if (BaseDecl->isEmpty()) {
+ // If the class decl is empty, get its size.
+ EmptySize = Layout.getSize();
+ } else {
+ // Otherwise, we get the largest empty subobject for the decl.
+ EmptySize = Layout.getSizeOfLargestEmptySubobject();
+ }
+
+ SizeOfLargestEmptySubobject = std::max(SizeOfLargestEmptySubobject,
+ EmptySize);
+ }
+
+ // Check the fields.
+ for (CXXRecordDecl::field_iterator I = Class->field_begin(),
+ E = Class->field_end(); I != E; ++I) {
+ const FieldDecl *FD = *I;
+
+ const RecordType *RT =
+ Context.getBaseElementType(FD->getType())->getAs<RecordType>();
+
+ // We only care about record types.
+ if (!RT)
+ continue;
+
+ uint64_t EmptySize = 0;
+ const CXXRecordDecl *MemberDecl = cast<CXXRecordDecl>(RT->getDecl());
+ const ASTRecordLayout &Layout = Context.getASTRecordLayout(MemberDecl);
+ if (MemberDecl->isEmpty()) {
+ // If the class decl is empty, get its size.
+ EmptySize = Layout.getSize();
+ } else {
+ // Otherwise, we get the largest empty subobject for the decl.
+ EmptySize = Layout.getSizeOfLargestEmptySubobject();
+ }
+
+ SizeOfLargestEmptySubobject = std::max(SizeOfLargestEmptySubobject,
+ EmptySize);
+ }
+}
+
+EmptySubobjectMap::BaseInfo *
+EmptySubobjectMap::ComputeBaseInfo(const CXXRecordDecl *RD, bool IsVirtual,
+ const BaseInfo *Derived) {
+ BaseInfo *Info;
+
+ if (IsVirtual) {
+ BaseInfo *&InfoSlot = VirtualBaseInfo[RD];
+ if (InfoSlot) {
+ assert(InfoSlot->Class == RD && "Wrong class for virtual base info!");
+ return InfoSlot;
+ }
+
+ InfoSlot = new (Context) BaseInfo;
+ Info = InfoSlot;
+ } else {
+ Info = new (Context) BaseInfo;
+ }
+
+ Info->Class = RD;
+ Info->IsVirtual = IsVirtual;
+ Info->Derived = Derived;
+ Info->PrimaryVirtualBase = 0;
+
+ if (RD->getNumVBases()) {
+ // Check if this class has a primary virtual base.
+ const ASTRecordLayout &Layout = Context.getASTRecordLayout(RD);
+ if (Layout.getPrimaryBaseWasVirtual()) {
+ Info->PrimaryVirtualBase = Layout.getPrimaryBase();
+ assert(Info->PrimaryVirtualBase &&
+ "Didn't have a primary virtual base!");
+ }
+ }
+
+ for (CXXRecordDecl::base_class_const_iterator I = RD->bases_begin(),
+ E = RD->bases_end(); I != E; ++I) {
+ bool IsVirtual = I->isVirtual();
+
+ const CXXRecordDecl *BaseDecl =
+ cast<CXXRecordDecl>(I->getType()->getAs<RecordType>()->getDecl());
+
+ Info->Bases.push_back(ComputeBaseInfo(BaseDecl, IsVirtual, Info));
+ }
+
+ return Info;
+}
+
+void EmptySubobjectMap::ComputeBaseInfo() {
+ for (CXXRecordDecl::base_class_const_iterator I = Class->bases_begin(),
+ E = Class->bases_end(); I != E; ++I) {
+ bool IsVirtual = I->isVirtual();
+
+ const CXXRecordDecl *BaseDecl =
+ cast<CXXRecordDecl>(I->getType()->getAs<RecordType>()->getDecl());
+
+ BaseInfo *Info = ComputeBaseInfo(BaseDecl, IsVirtual, /*Derived=*/0);
+ if (IsVirtual) {
+ // ComputeBaseInfo has already added this base for us.
+ continue;
+ }
+
+ // Add the base info to the map of non-virtual bases.
+ assert(!NonVirtualBaseInfo.count(BaseDecl) &&
+ "Non-virtual base already exists!");
+ NonVirtualBaseInfo.insert(std::make_pair(BaseDecl, Info));
+ }
+}
+
+bool
+EmptySubobjectMap::CanPlaceBaseSubobjectAtOffset(const BaseInfo *Info,
+ uint64_t Offset) {
+ // Traverse all non-virtual bases.
+ for (unsigned I = 0, E = Info->Bases.size(); I != E; ++I) {
+ BaseInfo* Base = Info->Bases[I];
+ if (Base->IsVirtual)
+ continue;
+
+ const ASTRecordLayout &Layout = Context.getASTRecordLayout(Info->Class);
+ uint64_t BaseOffset = Offset + Layout.getBaseClassOffset(Base->Class);
+
+ if (!CanPlaceBaseSubobjectAtOffset(Base, BaseOffset))
+ return false;
+ }
+
+ if (Info->PrimaryVirtualBase) {
+ BaseInfo *PrimaryVirtualBaseInfo =
+ VirtualBaseInfo.lookup(Info->PrimaryVirtualBase);
+ assert(PrimaryVirtualBaseInfo && "Didn't find base info!");
+
+ if (Info == PrimaryVirtualBaseInfo->Derived) {
+ if (!CanPlaceBaseSubobjectAtOffset(PrimaryVirtualBaseInfo, Offset))
+ return false;
+ }
+ }
+
+ // FIXME: Member variables.
+ return true;
+}
+
+void EmptySubobjectMap::UpdateEmptyBaseSubobjects(const BaseInfo *Info,
+ uint64_t Offset) {
+ if (Info->Class->isEmpty()) {
+ // FIXME: Record that there is an empty class at this offset.
+ }
+
+ // Traverse all non-virtual bases.
+ for (unsigned I = 0, E = Info->Bases.size(); I != E; ++I) {
+ BaseInfo* Base = Info->Bases[I];
+ if (Base->IsVirtual)
+ continue;
+
+ const ASTRecordLayout &Layout = Context.getASTRecordLayout(Info->Class);
+ uint64_t BaseOffset = Offset + Layout.getBaseClassOffset(Base->Class);
+
+ UpdateEmptyBaseSubobjects(Base, BaseOffset);
+ }
+
+ if (Info->PrimaryVirtualBase) {
+ BaseInfo *PrimaryVirtualBaseInfo =
+ VirtualBaseInfo.lookup(Info->PrimaryVirtualBase);
+ assert(PrimaryVirtualBaseInfo && "Didn't find base info!");
+
+ if (Info == PrimaryVirtualBaseInfo->Derived)
+ UpdateEmptyBaseSubobjects(PrimaryVirtualBaseInfo, Offset);
+ }
+
+ // FIXME: Member variables.
+}
+
+bool EmptySubobjectMap::CanPlaceBaseAtOffset(const CXXRecordDecl *RD,
+ bool BaseIsVirtual,
+ uint64_t Offset) {
+ // If we know this class doesn't have any empty subobjects we don't need to
+ // bother checking.
+ if (!SizeOfLargestEmptySubobject)
+ return true;
+
+ BaseInfo *Info;
+
+ if (BaseIsVirtual)
+ Info = VirtualBaseInfo.lookup(RD);
+ else
+ Info = NonVirtualBaseInfo.lookup(RD);
+
+ if (!CanPlaceBaseSubobjectAtOffset(Info, Offset))
+ return false;
+
+ UpdateEmptyBaseSubobjects(Info, Offset);
+ return true;
+}
+
+class RecordLayoutBuilder {
+ // FIXME: Remove this and make the appropriate fields public.
+ friend class clang::ASTContext;
+
+ ASTContext &Context;
+
+ EmptySubobjectMap *EmptySubobjects;
+
+ /// Size - The current size of the record layout.
+ uint64_t Size;
+
+ /// Alignment - The current alignment of the record layout.
+ unsigned Alignment;
+
+ llvm::SmallVector<uint64_t, 16> FieldOffsets;
+
+ /// Packed - Whether the record is packed or not.
+ unsigned Packed : 1;
+
+ unsigned IsUnion : 1;
+
+ unsigned IsMac68kAlign : 1;
+
+ /// UnfilledBitsInLastByte - If the last field laid out was a bitfield,
+ /// this contains the number of bits in the last byte that can be used for
+ /// an adjacent bitfield if necessary.
+ unsigned char UnfilledBitsInLastByte;
+
+ /// MaxFieldAlignment - The maximum allowed field alignment. This is set by
+ /// #pragma pack.
+ unsigned MaxFieldAlignment;
+
+ /// DataSize - The data size of the record being laid out.
+ uint64_t DataSize;
+
+ uint64_t NonVirtualSize;
+ unsigned NonVirtualAlignment;
+
+ /// PrimaryBase - the primary base class (if one exists) of the class
+ /// we're laying out.
+ const CXXRecordDecl *PrimaryBase;
+
+ /// PrimaryBaseIsVirtual - Whether the primary base of the class we're laying
+ /// out is virtual.
+ bool PrimaryBaseIsVirtual;
+
+ typedef llvm::DenseMap<const CXXRecordDecl *, uint64_t> BaseOffsetsMapTy;
+
+ /// Bases - base classes and their offsets in the record.
+ BaseOffsetsMapTy Bases;
+
+ // VBases - virtual base classes and their offsets in the record.
+ BaseOffsetsMapTy VBases;
+
+ /// IndirectPrimaryBases - Virtual base classes, direct or indirect, that are
+ /// primary base classes for some other direct or indirect base class.
+ llvm::SmallSet<const CXXRecordDecl*, 32> IndirectPrimaryBases;
+
+ /// FirstNearlyEmptyVBase - The first nearly empty virtual base class in
+ /// inheritance graph order. Used for determining the primary base class.
+ const CXXRecordDecl *FirstNearlyEmptyVBase;
+
+ /// VisitedVirtualBases - A set of all the visited virtual bases, used to
+ /// avoid visiting virtual bases more than once.
+ llvm::SmallPtrSet<const CXXRecordDecl *, 4> VisitedVirtualBases;
+
+ /// EmptyClassOffsets - A map from offsets to empty record decls.
+ typedef std::multimap<uint64_t, const CXXRecordDecl *> EmptyClassOffsetsTy;
+ EmptyClassOffsetsTy EmptyClassOffsets;
+
+ RecordLayoutBuilder(ASTContext &Context, EmptySubobjectMap *EmptySubobjects)
+ : Context(Context), EmptySubobjects(EmptySubobjects), Size(0), Alignment(8),
+ Packed(false), IsUnion(false), IsMac68kAlign(false),
+ UnfilledBitsInLastByte(0), MaxFieldAlignment(0), DataSize(0),
+ NonVirtualSize(0), NonVirtualAlignment(8), PrimaryBase(0),
+ PrimaryBaseIsVirtual(false), FirstNearlyEmptyVBase(0) { }
+
+ void Layout(const RecordDecl *D);
+ void Layout(const CXXRecordDecl *D);
+ void Layout(const ObjCInterfaceDecl *D);
+
+ void LayoutFields(const RecordDecl *D);
+ void LayoutField(const FieldDecl *D);
+ void LayoutWideBitField(uint64_t FieldSize, uint64_t TypeSize);
+ void LayoutBitField(const FieldDecl *D);
+
+ /// ComputeEmptySubobjectSizes - Compute the size of the largest base or
+ /// member subobject that is empty.
+ void ComputeEmptySubobjectSizes(const CXXRecordDecl *RD);
+
+ /// DeterminePrimaryBase - Determine the primary base of the given class.
+ void DeterminePrimaryBase(const CXXRecordDecl *RD);
+
+ void SelectPrimaryVBase(const CXXRecordDecl *RD);
+
+ /// IdentifyPrimaryBases - Identify all virtual base classes, direct or
+ /// indirect, that are primary base classes for some other direct or indirect
+ /// base class.
+ void IdentifyPrimaryBases(const CXXRecordDecl *RD);
+
+ bool IsNearlyEmpty(const CXXRecordDecl *RD) const;
+
+ /// LayoutNonVirtualBases - Determines the primary base class (if any) and
+ /// lays it out. Will then proceed to lay out all non-virtual base clasess.
+ void LayoutNonVirtualBases(const CXXRecordDecl *RD);
+
+ /// LayoutNonVirtualBase - Lays out a single non-virtual base.
+ void LayoutNonVirtualBase(const CXXRecordDecl *Base);
+
+ void AddPrimaryVirtualBaseOffsets(const CXXRecordDecl *RD, uint64_t Offset,
+ const CXXRecordDecl *MostDerivedClass);
+
+ /// LayoutVirtualBases - Lays out all the virtual bases.
+ void LayoutVirtualBases(const CXXRecordDecl *RD,
+ const CXXRecordDecl *MostDerivedClass);
+
+ /// LayoutVirtualBase - Lays out a single virtual base.
+ void LayoutVirtualBase(const CXXRecordDecl *Base);
+
+ /// LayoutBase - Will lay out a base and return the offset where it was
+ /// placed, in bits.
+ uint64_t LayoutBase(const CXXRecordDecl *Base, bool BaseIsVirtual);
+
+ /// canPlaceRecordAtOffset - Return whether a record (either a base class
+ /// or a field) can be placed at the given offset.
+ /// Returns false if placing the record will result in two components
+ /// (direct or indirect) of the same type having the same offset.
+ bool canPlaceRecordAtOffset(const CXXRecordDecl *RD, uint64_t Offset,
+ bool CheckVBases) const;
+
+ /// canPlaceFieldAtOffset - Return whether a field can be placed at the given
+ /// offset.
+ bool canPlaceFieldAtOffset(const FieldDecl *FD, uint64_t Offset) const;
+
+ /// UpdateEmptyClassOffsets - Called after a record (either a base class
+ /// or a field) has been placed at the given offset. Will update the
+ /// EmptyClassOffsets map if the class is empty or has any empty bases or
+ /// fields.
+ void UpdateEmptyClassOffsets(const CXXRecordDecl *RD, uint64_t Offset,
+ bool UpdateVBases);
+
+ /// UpdateEmptyClassOffsets - Called after a field has been placed at the
+ /// given offset.
+ void UpdateEmptyClassOffsets(const FieldDecl *FD, uint64_t Offset);
+
+ /// InitializeLayout - Initialize record layout for the given record decl.
+ void InitializeLayout(const Decl *D);
+
+ /// FinishLayout - Finalize record layout. Adjust record size based on the
+ /// alignment.
+ void FinishLayout();
+
+ void UpdateAlignment(unsigned NewAlignment);
+
+ RecordLayoutBuilder(const RecordLayoutBuilder&); // DO NOT IMPLEMENT
+ void operator=(const RecordLayoutBuilder&); // DO NOT IMPLEMENT
+public:
+ static const CXXMethodDecl *ComputeKeyFunction(const CXXRecordDecl *RD);
+};
+} // end anonymous namespace
/// IsNearlyEmpty - Indicates when a class has a vtable pointer, but
/// no other data.
-bool ASTRecordLayoutBuilder::IsNearlyEmpty(const CXXRecordDecl *RD) const {
+bool RecordLayoutBuilder::IsNearlyEmpty(const CXXRecordDecl *RD) const {
// FIXME: Audit the corners
if (!RD->isDynamicClass())
return false;
@@ -38,7 +453,7 @@ bool ASTRecordLayoutBuilder::IsNearlyEmpty(const CXXRecordDecl *RD) const {
return false;
}
-void ASTRecordLayoutBuilder::IdentifyPrimaryBases(const CXXRecordDecl *RD) {
+void RecordLayoutBuilder::IdentifyPrimaryBases(const CXXRecordDecl *RD) {
const ASTRecordLayout::PrimaryBaseInfo &BaseInfo =
Context.getASTRecordLayout(RD).getPrimaryBaseInfo();
@@ -63,7 +478,7 @@ void ASTRecordLayoutBuilder::IdentifyPrimaryBases(const CXXRecordDecl *RD) {
}
void
-ASTRecordLayoutBuilder::SelectPrimaryVBase(const CXXRecordDecl *RD) {
+RecordLayoutBuilder::SelectPrimaryVBase(const CXXRecordDecl *RD) {
for (CXXRecordDecl::base_class_const_iterator I = RD->bases_begin(),
E = RD->bases_end(); I != E; ++I) {
assert(!I->getType()->isDependentType() &&
@@ -77,8 +492,8 @@ ASTRecordLayoutBuilder::SelectPrimaryVBase(const CXXRecordDecl *RD) {
// If it's not an indirect primary base, then we've found our primary
// base.
if (!IndirectPrimaryBases.count(Base)) {
- PrimaryBase = ASTRecordLayout::PrimaryBaseInfo(Base,
- /*IsVirtual=*/true);
+ PrimaryBase = Base;
+ PrimaryBaseIsVirtual = true;
return;
}
@@ -88,13 +503,13 @@ ASTRecordLayoutBuilder::SelectPrimaryVBase(const CXXRecordDecl *RD) {
}
SelectPrimaryVBase(Base);
- if (PrimaryBase.getBase())
+ if (PrimaryBase)
return;
}
}
/// DeterminePrimaryBase - Determine the primary base of the given class.
-void ASTRecordLayoutBuilder::DeterminePrimaryBase(const CXXRecordDecl *RD) {
+void RecordLayoutBuilder::DeterminePrimaryBase(const CXXRecordDecl *RD) {
// If the class isn't dynamic, it won't have a primary base.
if (!RD->isDynamicClass())
return;
@@ -124,7 +539,8 @@ void ASTRecordLayoutBuilder::DeterminePrimaryBase(const CXXRecordDecl *RD) {
if (Base->isDynamicClass()) {
// We found it.
- PrimaryBase = ASTRecordLayout::PrimaryBaseInfo(Base, /*IsVirtual=*/false);
+ PrimaryBase = Base;
+ PrimaryBaseIsVirtual = false;
return;
}
}
@@ -133,20 +549,20 @@ void ASTRecordLayoutBuilder::DeterminePrimaryBase(const CXXRecordDecl *RD) {
// indirect primary virtual base class, if one exists.
if (RD->getNumVBases() != 0) {
SelectPrimaryVBase(RD);
- if (PrimaryBase.getBase())
+ if (PrimaryBase)
return;
}
// Otherwise, it is the first nearly empty virtual base that is not an
// indirect primary virtual base class, if one exists.
if (FirstNearlyEmptyVBase) {
- PrimaryBase = ASTRecordLayout::PrimaryBaseInfo(FirstNearlyEmptyVBase,
- /*IsVirtual=*/true);
+ PrimaryBase = FirstNearlyEmptyVBase;
+ PrimaryBaseIsVirtual = true;
return;
}
// Otherwise there is no primary base class.
- assert(!PrimaryBase.getBase() && "Should not get here with a primary base!");
+ assert(!PrimaryBase && "Should not get here with a primary base!");
// Allocate the virtual table pointer at offset zero.
assert(DataSize == 0 && "Vtable pointer must be at offset zero!");
@@ -160,22 +576,23 @@ void ASTRecordLayoutBuilder::DeterminePrimaryBase(const CXXRecordDecl *RD) {
}
void
-ASTRecordLayoutBuilder::LayoutNonVirtualBases(const CXXRecordDecl *RD) {
+RecordLayoutBuilder::LayoutNonVirtualBases(const CXXRecordDecl *RD) {
// First, determine the primary base class.
DeterminePrimaryBase(RD);
// If we have a primary base class, lay it out.
- if (const CXXRecordDecl *Base = PrimaryBase.getBase()) {
- if (PrimaryBase.isVirtual()) {
+ if (PrimaryBase) {
+ if (PrimaryBaseIsVirtual) {
// We have a virtual primary base, insert it as an indirect primary base.
- IndirectPrimaryBases.insert(Base);
+ IndirectPrimaryBases.insert(PrimaryBase);
- assert(!VisitedVirtualBases.count(Base) && "vbase already visited!");
- VisitedVirtualBases.insert(Base);
-
- LayoutVirtualBase(Base);
+ assert(!VisitedVirtualBases.count(PrimaryBase) &&
+ "vbase already visited!");
+ VisitedVirtualBases.insert(PrimaryBase);
+
+ LayoutVirtualBase(PrimaryBase);
} else
- LayoutNonVirtualBase(Base);
+ LayoutNonVirtualBase(PrimaryBase);
}
// Now lay out the non-virtual bases.
@@ -190,7 +607,7 @@ ASTRecordLayoutBuilder::LayoutNonVirtualBases(const CXXRecordDecl *RD) {
cast<CXXRecordDecl>(I->getType()->getAs<RecordType>()->getDecl());
// Skip the primary base.
- if (Base == PrimaryBase.getBase() && !PrimaryBase.isVirtual())
+ if (Base == PrimaryBase && !PrimaryBaseIsVirtual)
continue;
// Lay out the base.
@@ -198,17 +615,17 @@ ASTRecordLayoutBuilder::LayoutNonVirtualBases(const CXXRecordDecl *RD) {
}
}
-void ASTRecordLayoutBuilder::LayoutNonVirtualBase(const CXXRecordDecl *RD) {
+void RecordLayoutBuilder::LayoutNonVirtualBase(const CXXRecordDecl *Base) {
// Layout the base.
- uint64_t Offset = LayoutBase(RD);
+ uint64_t Offset = LayoutBase(Base, /*BaseIsVirtual=*/false);
// Add its base class offset.
- if (!Bases.insert(std::make_pair(RD, Offset)).second)
+ if (!Bases.insert(std::make_pair(Base, Offset)).second)
assert(false && "Added same base offset more than once!");
}
void
-ASTRecordLayoutBuilder::AddPrimaryVirtualBaseOffsets(const CXXRecordDecl *RD,
+RecordLayoutBuilder::AddPrimaryVirtualBaseOffsets(const CXXRecordDecl *RD,
uint64_t Offset,
const CXXRecordDecl *MostDerivedClass) {
// We already have the offset for the primary base of the most derived class.
@@ -226,7 +643,7 @@ ASTRecordLayoutBuilder::AddPrimaryVirtualBaseOffsets(const CXXRecordDecl *RD,
E = RD->bases_end(); I != E; ++I) {
assert(!I->getType()->isDependentType() &&
"Cannot layout class with dependent bases.");
-
+
const CXXRecordDecl *BaseDecl =
cast<CXXRecordDecl>(I->getType()->getAs<RecordType>()->getDecl());
@@ -234,17 +651,17 @@ ASTRecordLayoutBuilder::AddPrimaryVirtualBaseOffsets(const CXXRecordDecl *RD,
// This base isn't interesting since it doesn't have any virtual bases.
continue;
}
-
+
// Compute the offset of this base.
uint64_t BaseOffset;
-
+
if (I->isVirtual()) {
// If we don't know this vbase yet, don't visit it. It will be visited
// later.
if (!VBases.count(BaseDecl)) {
continue;
}
-
+
// Check if we've already visited this base.
if (!VisitedVirtualBases.insert(BaseDecl))
continue;
@@ -265,14 +682,14 @@ ASTRecordLayoutBuilder::AddPrimaryVirtualBaseOffsets(const CXXRecordDecl *RD,
}
void
-ASTRecordLayoutBuilder::LayoutVirtualBases(const CXXRecordDecl *RD,
+RecordLayoutBuilder::LayoutVirtualBases(const CXXRecordDecl *RD,
const CXXRecordDecl *MostDerivedClass) {
const CXXRecordDecl *PrimaryBase;
bool PrimaryBaseIsVirtual;
if (MostDerivedClass == RD) {
- PrimaryBase = this->PrimaryBase.getBase();
- PrimaryBaseIsVirtual = this->PrimaryBase.isVirtual();
+ PrimaryBase = this->PrimaryBase;
+ PrimaryBaseIsVirtual = this->PrimaryBaseIsVirtual;
} else {
const ASTRecordLayout &Layout = Context.getASTRecordLayout(RD);
PrimaryBase = Layout.getPrimaryBase();
@@ -296,7 +713,7 @@ ASTRecordLayoutBuilder::LayoutVirtualBases(const CXXRecordDecl *RD,
// Only visit virtual bases once.
if (!VisitedVirtualBases.insert(Base))
continue;
-
+
LayoutVirtualBase(Base);
}
}
@@ -311,58 +728,64 @@ ASTRecordLayoutBuilder::LayoutVirtualBases(const CXXRecordDecl *RD,
}
}
-void ASTRecordLayoutBuilder::LayoutVirtualBase(const CXXRecordDecl *RD) {
+void RecordLayoutBuilder::LayoutVirtualBase(const CXXRecordDecl *Base) {
// Layout the base.
- uint64_t Offset = LayoutBase(RD);
+ uint64_t Offset = LayoutBase(Base, /*BaseIsVirtual=*/true);
// Add its base class offset.
- if (!VBases.insert(std::make_pair(RD, Offset)).second)
+ if (!VBases.insert(std::make_pair(Base, Offset)).second)
assert(false && "Added same vbase offset more than once!");
}
-uint64_t ASTRecordLayoutBuilder::LayoutBase(const CXXRecordDecl *RD) {
- const ASTRecordLayout &BaseInfo = Context.getASTRecordLayout(RD);
+uint64_t RecordLayoutBuilder::LayoutBase(const CXXRecordDecl *Base,
+ bool BaseIsVirtual) {
+ const ASTRecordLayout &Layout = Context.getASTRecordLayout(Base);
// If we have an empty base class, try to place it at offset 0.
- if (RD->isEmpty() && canPlaceRecordAtOffset(RD, 0)) {
+ if (Base->isEmpty() &&
+ EmptySubobjects->CanPlaceBaseAtOffset(Base, BaseIsVirtual, 0) &&
+ canPlaceRecordAtOffset(Base, 0, /*CheckVBases=*/false)) {
// We were able to place the class at offset 0.
- UpdateEmptyClassOffsets(RD, 0);
+ UpdateEmptyClassOffsets(Base, 0, /*UpdateVBases=*/false);
- Size = std::max(Size, BaseInfo.getSize());
+ Size = std::max(Size, Layout.getSize());
return 0;
}
- unsigned BaseAlign = BaseInfo.getNonVirtualAlign();
+ unsigned BaseAlign = Layout.getNonVirtualAlign();
// Round up the current record size to the base's alignment boundary.
uint64_t Offset = llvm::RoundUpToAlignment(DataSize, BaseAlign);
// Try to place the base.
while (true) {
- if (canPlaceRecordAtOffset(RD, Offset))
+ if (EmptySubobjects->CanPlaceBaseAtOffset(Base, BaseIsVirtual, Offset) &&
+ canPlaceRecordAtOffset(Base, Offset, /*CheckVBases=*/false))
break;
Offset += BaseAlign;
}
- if (!RD->isEmpty()) {
+ if (!Base->isEmpty()) {
// Update the data size.
- DataSize = Offset + BaseInfo.getNonVirtualSize();
+ DataSize = Offset + Layout.getNonVirtualSize();
Size = std::max(Size, DataSize);
} else
- Size = std::max(Size, Offset + BaseInfo.getSize());
+ Size = std::max(Size, Offset + Layout.getSize());
// Remember max struct/class alignment.
UpdateAlignment(BaseAlign);
- UpdateEmptyClassOffsets(RD, Offset);
+ UpdateEmptyClassOffsets(Base, Offset, /*UpdateVBases=*/false);
return Offset;
}
-bool ASTRecordLayoutBuilder::canPlaceRecordAtOffset(const CXXRecordDecl *RD,
- uint64_t Offset) const {
+bool
+RecordLayoutBuilder::canPlaceRecordAtOffset(const CXXRecordDecl *RD,
+ uint64_t Offset,
+ bool CheckVBases) const {
// Look for an empty class with the same type at the same offset.
for (EmptyClassOffsetsTy::const_iterator I =
EmptyClassOffsets.lower_bound(Offset),
@@ -372,7 +795,7 @@ bool ASTRecordLayoutBuilder::canPlaceRecordAtOffset(const CXXRecordDecl *RD,
return false;
}
- const ASTRecordLayout &Info = Context.getASTRecordLayout(RD);
+ const ASTRecordLayout &Layout = Context.getASTRecordLayout(RD);
// Check bases.
for (CXXRecordDecl::base_class_const_iterator I = RD->bases_begin(),
@@ -382,12 +805,13 @@ bool ASTRecordLayoutBuilder::canPlaceRecordAtOffset(const CXXRecordDecl *RD,
if (I->isVirtual())
continue;
- const CXXRecordDecl *Base =
+ const CXXRecordDecl *BaseDecl =
cast<CXXRecordDecl>(I->getType()->getAs<RecordType>()->getDecl());
- uint64_t BaseClassOffset = Info.getBaseClassOffset(Base);
+ uint64_t BaseOffset = Layout.getBaseClassOffset(BaseDecl);
- if (!canPlaceRecordAtOffset(Base, Offset + BaseClassOffset))
+ if (!canPlaceRecordAtOffset(BaseDecl, Offset + BaseOffset,
+ /*CheckVBases=*/false))
return false;
}
@@ -397,22 +821,25 @@ bool ASTRecordLayoutBuilder::canPlaceRecordAtOffset(const CXXRecordDecl *RD,
I != E; ++I, ++FieldNo) {
const FieldDecl *FD = *I;
- uint64_t FieldOffset = Info.getFieldOffset(FieldNo);
+ uint64_t FieldOffset = Layout.getFieldOffset(FieldNo);
if (!canPlaceFieldAtOffset(FD, Offset + FieldOffset))
return false;
}
- // FIXME: virtual bases.
+ if (CheckVBases) {
+ // FIXME: virtual bases.
+ }
+
return true;
}
-bool ASTRecordLayoutBuilder::canPlaceFieldAtOffset(const FieldDecl *FD,
+bool RecordLayoutBuilder::canPlaceFieldAtOffset(const FieldDecl *FD,
uint64_t Offset) const {
QualType T = FD->getType();
if (const RecordType *RT = T->getAs<RecordType>()) {
if (const CXXRecordDecl *RD = dyn_cast<CXXRecordDecl>(RT->getDecl()))
- return canPlaceRecordAtOffset(RD, Offset);
+ return canPlaceRecordAtOffset(RD, Offset, /*CheckVBases=*/true);
}
if (const ConstantArrayType *AT = Context.getAsConstantArrayType(T)) {
@@ -424,27 +851,28 @@ bool ASTRecordLayoutBuilder::canPlaceFieldAtOffset(const FieldDecl *FD,
if (!RD)
return true;
- const ASTRecordLayout &Info = Context.getASTRecordLayout(RD);
+ const ASTRecordLayout &Layout = Context.getASTRecordLayout(RD);
uint64_t NumElements = Context.getConstantArrayElementCount(AT);
uint64_t ElementOffset = Offset;
for (uint64_t I = 0; I != NumElements; ++I) {
- if (!canPlaceRecordAtOffset(RD, ElementOffset))
+ if (!canPlaceRecordAtOffset(RD, ElementOffset, /*CheckVBases=*/true))
return false;
- ElementOffset += Info.getSize();
+ ElementOffset += Layout.getSize();
}
}
return true;
}
-void ASTRecordLayoutBuilder::UpdateEmptyClassOffsets(const CXXRecordDecl *RD,
- uint64_t Offset) {
+void RecordLayoutBuilder::UpdateEmptyClassOffsets(const CXXRecordDecl *RD,
+ uint64_t Offset,
+ bool UpdateVBases) {
if (RD->isEmpty())
EmptyClassOffsets.insert(std::make_pair(Offset, RD));
- const ASTRecordLayout &Info = Context.getASTRecordLayout(RD);
+ const ASTRecordLayout &Layout = Context.getASTRecordLayout(RD);
// Update bases.
for (CXXRecordDecl::base_class_const_iterator I = RD->bases_begin(),
@@ -457,8 +885,9 @@ void ASTRecordLayoutBuilder::UpdateEmptyClassOffsets(const CXXRecordDecl *RD,
const CXXRecordDecl *Base =
cast<CXXRecordDecl>(I->getType()->getAs<RecordType>()->getDecl());
- uint64_t BaseClassOffset = Info.getBaseClassOffset(Base);
- UpdateEmptyClassOffsets(Base, Offset + BaseClassOffset);
+ uint64_t BaseClassOffset = Layout.getBaseClassOffset(Base);
+ UpdateEmptyClassOffsets(Base, Offset + BaseClassOffset,
+ /*UpdateVBases=*/false);
}
// Update fields.
@@ -467,21 +896,30 @@ void ASTRecordLayoutBuilder::UpdateEmptyClassOffsets(const CXXRecordDecl *RD,
I != E; ++I, ++FieldNo) {
const FieldDecl *FD = *I;
- uint64_t FieldOffset = Info.getFieldOffset(FieldNo);
+ uint64_t FieldOffset = Layout.getFieldOffset(FieldNo);
UpdateEmptyClassOffsets(FD, Offset + FieldOffset);
}
- // FIXME: Update virtual bases.
+ const CXXRecordDecl *PrimaryBase = Layout.getPrimaryBase();
+
+ if (UpdateVBases) {
+ // FIXME: Update virtual bases.
+ } else if (PrimaryBase && Layout.getPrimaryBaseWasVirtual()) {
+ // We always want to update the offsets of a primary virtual base.
+ assert(Layout.getVBaseClassOffset(PrimaryBase) == 0 &&
+ "primary base class offset must always be 0!");
+ UpdateEmptyClassOffsets(PrimaryBase, Offset, /*UpdateVBases=*/false);
+ }
}
void
-ASTRecordLayoutBuilder::UpdateEmptyClassOffsets(const FieldDecl *FD,
+RecordLayoutBuilder::UpdateEmptyClassOffsets(const FieldDecl *FD,
uint64_t Offset) {
QualType T = FD->getType();
if (const RecordType *RT = T->getAs<RecordType>()) {
if (const CXXRecordDecl *RD = dyn_cast<CXXRecordDecl>(RT->getDecl())) {
- UpdateEmptyClassOffsets(RD, Offset);
+ UpdateEmptyClassOffsets(RD, Offset, /*UpdateVBases=*/true);
return;
}
}
@@ -501,76 +939,90 @@ ASTRecordLayoutBuilder::UpdateEmptyClassOffsets(const FieldDecl *FD,
uint64_t ElementOffset = Offset;
for (uint64_t I = 0; I != NumElements; ++I) {
- UpdateEmptyClassOffsets(RD, ElementOffset);
+ UpdateEmptyClassOffsets(RD, ElementOffset, /*UpdateVBases=*/true);
ElementOffset += Info.getSize();
}
}
}
-void ASTRecordLayoutBuilder::Layout(const RecordDecl *D) {
- IsUnion = D->isUnion();
+void RecordLayoutBuilder::InitializeLayout(const Decl *D) {
+ if (const RecordDecl *RD = dyn_cast<RecordDecl>(D))
+ IsUnion = RD->isUnion();
Packed = D->hasAttr<PackedAttr>();
- // The #pragma pack attribute specifies the maximum field alignment.
- if (const PragmaPackAttr *PPA = D->getAttr<PragmaPackAttr>())
- MaxFieldAlignment = PPA->getAlignment();
-
- if (const AlignedAttr *AA = D->getAttr<AlignedAttr>())
- UpdateAlignment(AA->getMaxAlignment());
+ // mac68k alignment supersedes maximum field alignment and attribute aligned,
+ // and forces all structures to have 2-byte alignment. The IBM docs on it
+ // allude to additional (more complicated) semantics, especially with regard
+ // to bit-fields, but gcc appears not to follow that.
+ if (D->hasAttr<AlignMac68kAttr>()) {
+ IsMac68kAlign = true;
+ MaxFieldAlignment = 2 * 8;
+ Alignment = 2 * 8;
+ } else {
+ if (const MaxFieldAlignmentAttr *MFAA = D->getAttr<MaxFieldAlignmentAttr>())
+ MaxFieldAlignment = MFAA->getAlignment();
- // If this is a C++ class, lay out the vtable and the non-virtual bases.
- const CXXRecordDecl *RD = dyn_cast<CXXRecordDecl>(D);
- if (RD)
- LayoutNonVirtualBases(RD);
+ if (const AlignedAttr *AA = D->getAttr<AlignedAttr>())
+ UpdateAlignment(AA->getMaxAlignment());
+ }
+}
+void RecordLayoutBuilder::Layout(const RecordDecl *D) {
+ InitializeLayout(D);
LayoutFields(D);
+ // Finally, round the size of the total struct up to the alignment of the
+ // struct itself.
+ FinishLayout();
+}
+
+void RecordLayoutBuilder::Layout(const CXXRecordDecl *RD) {
+ InitializeLayout(RD);
+
+ // Lay out the vtable and the non-virtual bases.
+ LayoutNonVirtualBases(RD);
+
+ LayoutFields(RD);
+
NonVirtualSize = Size;
NonVirtualAlignment = Alignment;
- // If this is a C++ class, lay out its virtual bases and add its primary
- // virtual base offsets.
- if (RD) {
- LayoutVirtualBases(RD, RD);
+ // Lay out the virtual bases and add the primary virtual base offsets.
+ LayoutVirtualBases(RD, RD);
- VisitedVirtualBases.clear();
- AddPrimaryVirtualBaseOffsets(RD, 0, RD);
- }
+ VisitedVirtualBases.clear();
+ AddPrimaryVirtualBaseOffsets(RD, 0, RD);
// Finally, round the size of the total struct up to the alignment of the
// struct itself.
FinishLayout();
-
+
#ifndef NDEBUG
- if (RD) {
- // Check that we have base offsets for all bases.
- for (CXXRecordDecl::base_class_const_iterator I = RD->bases_begin(),
- E = RD->bases_end(); I != E; ++I) {
- if (I->isVirtual())
- continue;
-
- const CXXRecordDecl *BaseDecl =
- cast<CXXRecordDecl>(I->getType()->getAs<RecordType>()->getDecl());
-
- assert(Bases.count(BaseDecl) && "Did not find base offset!");
- }
-
- // And all virtual bases.
- for (CXXRecordDecl::base_class_const_iterator I = RD->vbases_begin(),
- E = RD->vbases_end(); I != E; ++I) {
- const CXXRecordDecl *BaseDecl =
- cast<CXXRecordDecl>(I->getType()->getAs<RecordType>()->getDecl());
-
- assert(VBases.count(BaseDecl) && "Did not find base offset!");
- }
+ // Check that we have base offsets for all bases.
+ for (CXXRecordDecl::base_class_const_iterator I = RD->bases_begin(),
+ E = RD->bases_end(); I != E; ++I) {
+ if (I->isVirtual())
+ continue;
+
+ const CXXRecordDecl *BaseDecl =
+ cast<CXXRecordDecl>(I->getType()->getAs<RecordType>()->getDecl());
+
+ assert(Bases.count(BaseDecl) && "Did not find base offset!");
+ }
+
+ // And all virtual bases.
+ for (CXXRecordDecl::base_class_const_iterator I = RD->vbases_begin(),
+ E = RD->vbases_end(); I != E; ++I) {
+ const CXXRecordDecl *BaseDecl =
+ cast<CXXRecordDecl>(I->getType()->getAs<RecordType>()->getDecl());
+
+ assert(VBases.count(BaseDecl) && "Did not find base offset!");
}
#endif
}
-// FIXME. Impl is no longer needed.
-void ASTRecordLayoutBuilder::Layout(const ObjCInterfaceDecl *D,
- const ObjCImplementationDecl *Impl) {
+void RecordLayoutBuilder::Layout(const ObjCInterfaceDecl *D) {
if (ObjCInterfaceDecl *SD = D->getSuperClass()) {
const ASTRecordLayout &SL = Context.getASTObjCInterfaceLayout(SD);
@@ -582,14 +1034,8 @@ void ASTRecordLayoutBuilder::Layout(const ObjCInterfaceDecl *D,
DataSize = Size;
}
- Packed = D->hasAttr<PackedAttr>();
-
- // The #pragma pack attribute specifies the maximum field alignment.
- if (const PragmaPackAttr *PPA = D->getAttr<PragmaPackAttr>())
- MaxFieldAlignment = PPA->getAlignment();
+ InitializeLayout(D);
- if (const AlignedAttr *AA = D->getAttr<AlignedAttr>())
- UpdateAlignment(AA->getMaxAlignment());
// Layout each ivar sequentially.
llvm::SmallVector<ObjCIvarDecl*, 16> Ivars;
Context.ShallowCollectObjCIvars(D, Ivars);
@@ -601,7 +1047,7 @@ void ASTRecordLayoutBuilder::Layout(const ObjCInterfaceDecl *D,
FinishLayout();
}
-void ASTRecordLayoutBuilder::LayoutFields(const RecordDecl *D) {
+void RecordLayoutBuilder::LayoutFields(const RecordDecl *D) {
// Layout each field, for now, just sequentially, respecting alignment. In
// the future, this will need to be tweakable by targets.
for (RecordDecl::field_iterator Field = D->field_begin(),
@@ -609,17 +1055,17 @@ void ASTRecordLayoutBuilder::LayoutFields(const RecordDecl *D) {
LayoutField(*Field);
}
-void ASTRecordLayoutBuilder::LayoutWideBitField(uint64_t FieldSize,
+void RecordLayoutBuilder::LayoutWideBitField(uint64_t FieldSize,
uint64_t TypeSize) {
assert(Context.getLangOptions().CPlusPlus &&
"Can only have wide bit-fields in C++!");
-
+
// Itanium C++ ABI 2.4:
- // If sizeof(T)*8 < n, let T' be the largest integral POD type with
+ // If sizeof(T)*8 < n, let T' be the largest integral POD type with
// sizeof(T')*8 <= n.
-
+
QualType IntegralPODTypes[] = {
- Context.UnsignedCharTy, Context.UnsignedShortTy, Context.UnsignedIntTy,
+ Context.UnsignedCharTy, Context.UnsignedShortTy, Context.UnsignedIntTy,
Context.UnsignedLongTy, Context.UnsignedLongLongTy
};
@@ -634,24 +1080,24 @@ void ASTRecordLayoutBuilder::LayoutWideBitField(uint64_t FieldSize,
Type = IntegralPODTypes[I];
}
assert(!Type.isNull() && "Did not find a type!");
-
+
unsigned TypeAlign = Context.getTypeAlign(Type);
// We're not going to use any of the unfilled bits in the last byte.
UnfilledBitsInLastByte = 0;
uint64_t FieldOffset;
-
+
if (IsUnion) {
DataSize = std::max(DataSize, FieldSize);
FieldOffset = 0;
} else {
// The bitfield is allocated starting at the next offset aligned appropriately
- // for T', with length n bits.
+ // for T', with length n bits.
FieldOffset = llvm::RoundUpToAlignment(DataSize, TypeAlign);
-
+
uint64_t NewSizeInBits = FieldOffset + FieldSize;
-
+
DataSize = llvm::RoundUpToAlignment(NewSizeInBits, 8);
UnfilledBitsInLastByte = DataSize - NewSizeInBits;
}
@@ -661,12 +1107,12 @@ void ASTRecordLayoutBuilder::LayoutWideBitField(uint64_t FieldSize,
// Update the size.
Size = std::max(Size, DataSize);
-
+
// Remember max struct/class alignment.
UpdateAlignment(TypeAlign);
}
-void ASTRecordLayoutBuilder::LayoutBitField(const FieldDecl *D) {
+void RecordLayoutBuilder::LayoutBitField(const FieldDecl *D) {
bool FieldPacked = Packed || D->hasAttr<PackedAttr>();
uint64_t FieldOffset = IsUnion ? 0 : (DataSize - UnfilledBitsInLastByte);
uint64_t FieldSize = D->getBitWidth()->EvaluateAsInt(Context).getZExtValue();
@@ -718,7 +1164,7 @@ void ASTRecordLayoutBuilder::LayoutBitField(const FieldDecl *D) {
UpdateAlignment(FieldAlign);
}
-void ASTRecordLayoutBuilder::LayoutField(const FieldDecl *D) {
+void RecordLayoutBuilder::LayoutField(const FieldDecl *D) {
if (D->isBitField()) {
LayoutBitField(D);
return;
@@ -791,7 +1237,7 @@ void ASTRecordLayoutBuilder::LayoutField(const FieldDecl *D) {
UpdateAlignment(FieldAlign);
}
-void ASTRecordLayoutBuilder::FinishLayout() {
+void RecordLayoutBuilder::FinishLayout() {
// In C++, records cannot be of size 0.
if (Context.getLangOptions().CPlusPlus && Size == 0)
Size = 8;
@@ -800,7 +1246,11 @@ void ASTRecordLayoutBuilder::FinishLayout() {
Size = llvm::RoundUpToAlignment(Size, Alignment);
}
-void ASTRecordLayoutBuilder::UpdateAlignment(unsigned NewAlignment) {
+void RecordLayoutBuilder::UpdateAlignment(unsigned NewAlignment) {
+ // The alignment is not modified when using 'mac68k' alignment.
+ if (IsMac68kAlign)
+ return;
+
if (NewAlignment <= Alignment)
return;
@@ -809,55 +1259,8 @@ void ASTRecordLayoutBuilder::UpdateAlignment(unsigned NewAlignment) {
Alignment = NewAlignment;
}
-const ASTRecordLayout *
-ASTRecordLayoutBuilder::ComputeLayout(ASTContext &Ctx,
- const RecordDecl *D) {
- ASTRecordLayoutBuilder Builder(Ctx);
-
- Builder.Layout(D);
-
- if (!isa<CXXRecordDecl>(D))
- return new (Ctx) ASTRecordLayout(Ctx, Builder.Size, Builder.Alignment,
- Builder.Size,
- Builder.FieldOffsets.data(),
- Builder.FieldOffsets.size());
-
- // FIXME: This is not always correct. See the part about bitfields at
- // http://www.codesourcery.com/public/cxx-abi/abi.html#POD for more info.
- // FIXME: IsPODForThePurposeOfLayout should be stored in the record layout.
- bool IsPODForThePurposeOfLayout = cast<CXXRecordDecl>(D)->isPOD();
-
- // FIXME: This should be done in FinalizeLayout.
- uint64_t DataSize =
- IsPODForThePurposeOfLayout ? Builder.Size : Builder.DataSize;
- uint64_t NonVirtualSize =
- IsPODForThePurposeOfLayout ? DataSize : Builder.NonVirtualSize;
-
- return new (Ctx) ASTRecordLayout(Ctx, Builder.Size, Builder.Alignment,
- DataSize, Builder.FieldOffsets.data(),
- Builder.FieldOffsets.size(),
- NonVirtualSize,
- Builder.NonVirtualAlignment,
- Builder.PrimaryBase,
- Builder.Bases, Builder.VBases);
-}
-
-const ASTRecordLayout *
-ASTRecordLayoutBuilder::ComputeLayout(ASTContext &Ctx,
- const ObjCInterfaceDecl *D,
- const ObjCImplementationDecl *Impl) {
- ASTRecordLayoutBuilder Builder(Ctx);
-
- Builder.Layout(D, Impl);
-
- return new (Ctx) ASTRecordLayout(Ctx, Builder.Size, Builder.Alignment,
- Builder.DataSize,
- Builder.FieldOffsets.data(),
- Builder.FieldOffsets.size());
-}
-
const CXXMethodDecl *
-ASTRecordLayoutBuilder::ComputeKeyFunction(const CXXRecordDecl *RD) {
+RecordLayoutBuilder::ComputeKeyFunction(const CXXRecordDecl *RD) {
assert(RD->isDynamicClass() && "Class does not have any virtual methods!");
// If a class isn't polymorphic it doesn't have a key function.
@@ -898,6 +1301,124 @@ ASTRecordLayoutBuilder::ComputeKeyFunction(const CXXRecordDecl *RD) {
return 0;
}
+/// getASTRecordLayout - Get or compute information about the layout of the
+/// specified record (struct/union/class), which indicates its size and field
+/// position information.
+const ASTRecordLayout &ASTContext::getASTRecordLayout(const RecordDecl *D) {
+ D = D->getDefinition();
+ assert(D && "Cannot get layout of forward declarations!");
+
+ // Look up this layout, if already laid out, return what we have.
+ // Note that we can't save a reference to the entry because this function
+ // is recursive.
+ const ASTRecordLayout *Entry = ASTRecordLayouts[D];
+ if (Entry) return *Entry;
+
+ const ASTRecordLayout *NewEntry;
+
+ if (const CXXRecordDecl *RD = dyn_cast<CXXRecordDecl>(D)) {
+ EmptySubobjectMap EmptySubobjects(*this, RD);
+
+ RecordLayoutBuilder Builder(*this, &EmptySubobjects);
+ Builder.Layout(RD);
+
+ // FIXME: This is not always correct. See the part about bitfields at
+ // http://www.codesourcery.com/public/cxx-abi/abi.html#POD for more info.
+ // FIXME: IsPODForThePurposeOfLayout should be stored in the record layout.
+ bool IsPODForThePurposeOfLayout = cast<CXXRecordDecl>(D)->isPOD();
+
+ // FIXME: This should be done in FinalizeLayout.
+ uint64_t DataSize =
+ IsPODForThePurposeOfLayout ? Builder.Size : Builder.DataSize;
+ uint64_t NonVirtualSize =
+ IsPODForThePurposeOfLayout ? DataSize : Builder.NonVirtualSize;
+
+ NewEntry =
+ new (*this) ASTRecordLayout(*this, Builder.Size, Builder.Alignment,
+ DataSize, Builder.FieldOffsets.data(),
+ Builder.FieldOffsets.size(),
+ NonVirtualSize,
+ Builder.NonVirtualAlignment,
+ EmptySubobjects.SizeOfLargestEmptySubobject,
+ Builder.PrimaryBase,
+ Builder.PrimaryBaseIsVirtual,
+ Builder.Bases, Builder.VBases);
+ } else {
+ RecordLayoutBuilder Builder(*this, /*EmptySubobjects=*/0);
+ Builder.Layout(D);
+
+ NewEntry =
+ new (*this) ASTRecordLayout(*this, Builder.Size, Builder.Alignment,
+ Builder.Size,
+ Builder.FieldOffsets.data(),
+ Builder.FieldOffsets.size());
+ }
+
+ ASTRecordLayouts[D] = NewEntry;
+
+ if (getLangOptions().DumpRecordLayouts) {
+ llvm::errs() << "\n*** Dumping AST Record Layout\n";
+ DumpRecordLayout(D, llvm::errs());
+ }
+
+ return *NewEntry;
+}
+
+const CXXMethodDecl *ASTContext::getKeyFunction(const CXXRecordDecl *RD) {
+ RD = cast<CXXRecordDecl>(RD->getDefinition());
+ assert(RD && "Cannot get key function for forward declarations!");
+
+ const CXXMethodDecl *&Entry = KeyFunctions[RD];
+ if (!Entry)
+ Entry = RecordLayoutBuilder::ComputeKeyFunction(RD);
+ else
+ assert(Entry == RecordLayoutBuilder::ComputeKeyFunction(RD) &&
+ "Key function changed!");
+
+ return Entry;
+}
+
+/// getInterfaceLayoutImpl - Get or compute information about the
+/// layout of the given interface.
+///
+/// \param Impl - If given, also include the layout of the interface's
+/// implementation. This may differ by including synthesized ivars.
+const ASTRecordLayout &
+ASTContext::getObjCLayout(const ObjCInterfaceDecl *D,
+ const ObjCImplementationDecl *Impl) {
+ assert(!D->isForwardDecl() && "Invalid interface decl!");
+
+ // Look up this layout, if already laid out, return what we have.
+ ObjCContainerDecl *Key =
+ Impl ? (ObjCContainerDecl*) Impl : (ObjCContainerDecl*) D;
+ if (const ASTRecordLayout *Entry = ObjCLayouts[Key])
+ return *Entry;
+
+ // Add in synthesized ivar count if laying out an implementation.
+ if (Impl) {
+ 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
+ // frequently.
+ if (SynthCount == 0)
+ return getObjCLayout(D, 0);
+ }
+
+ RecordLayoutBuilder Builder(*this, /*EmptySubobjects=*/0);
+ Builder.Layout(D);
+
+ const ASTRecordLayout *NewEntry =
+ new (*this) ASTRecordLayout(*this, Builder.Size, Builder.Alignment,
+ Builder.DataSize,
+ Builder.FieldOffsets.data(),
+ Builder.FieldOffsets.size());
+
+ ObjCLayouts[Key] = NewEntry;
+
+ return *NewEntry;
+}
+
static void PrintOffset(llvm::raw_ostream &OS,
uint64_t Offset, unsigned IndentLevel) {
OS << llvm::format("%4d | ", Offset);
diff --git a/lib/AST/RecordLayoutBuilder.h b/lib/AST/RecordLayoutBuilder.h
deleted file mode 100644
index f277c29398b3..000000000000
--- a/lib/AST/RecordLayoutBuilder.h
+++ /dev/null
@@ -1,170 +0,0 @@
-//===- ASTRecordLayoutBuilder.h - Helper class for building record layouts ===//
-//
-// The LLVM Compiler Infrastructure
-//
-// This file is distributed under the University of Illinois Open Source
-// License. See LICENSE.TXT for details.
-//
-//===----------------------------------------------------------------------===//
-
-#ifndef LLVM_CLANG_AST_RECORDLAYOUTBUILDER_H
-#define LLVM_CLANG_AST_RECORDLAYOUTBUILDER_H
-
-#include "clang/AST/RecordLayout.h"
-#include "llvm/ADT/SmallVector.h"
-#include "llvm/ADT/SmallSet.h"
-#include "llvm/System/DataTypes.h"
-#include <map>
-
-namespace clang {
- class ASTContext;
- class ASTRecordLayout;
- class CXXRecordDecl;
- class FieldDecl;
- class ObjCImplementationDecl;
- class ObjCInterfaceDecl;
- class RecordDecl;
-
-class ASTRecordLayoutBuilder {
- ASTContext &Context;
-
- /// Size - The current size of the record layout.
- uint64_t Size;
-
- /// Alignment - The current alignment of the record layout.
- unsigned Alignment;
-
- llvm::SmallVector<uint64_t, 16> FieldOffsets;
-
- /// Packed - Whether the record is packed or not.
- bool Packed;
-
- /// UnfilledBitsInLastByte - If the last field laid out was a bitfield,
- /// this contains the number of bits in the last byte that can be used for
- /// an adjacent bitfield if necessary.
- unsigned char UnfilledBitsInLastByte;
-
- /// MaxFieldAlignment - The maximum allowed field alignment. This is set by
- /// #pragma pack.
- unsigned MaxFieldAlignment;
-
- /// DataSize - The data size of the record being laid out.
- uint64_t DataSize;
-
- bool IsUnion;
-
- uint64_t NonVirtualSize;
- unsigned NonVirtualAlignment;
-
- /// PrimaryBase - the primary base class (if one exists) of the class
- /// we're laying out.
- ASTRecordLayout::PrimaryBaseInfo PrimaryBase;
-
- /// Bases - base classes and their offsets in the record.
- ASTRecordLayout::BaseOffsetsMapTy Bases;
-
- // VBases - virtual base classes and their offsets in the record.
- ASTRecordLayout::BaseOffsetsMapTy VBases;
-
- /// IndirectPrimaryBases - Virtual base classes, direct or indirect, that are
- /// primary base classes for some other direct or indirect base class.
- llvm::SmallSet<const CXXRecordDecl*, 32> IndirectPrimaryBases;
-
- /// FirstNearlyEmptyVBase - The first nearly empty virtual base class in
- /// inheritance graph order. Used for determining the primary base class.
- const CXXRecordDecl *FirstNearlyEmptyVBase;
-
- /// VisitedVirtualBases - A set of all the visited virtual bases, used to
- /// avoid visiting virtual bases more than once.
- llvm::SmallPtrSet<const CXXRecordDecl *, 4> VisitedVirtualBases;
-
- /// EmptyClassOffsets - A map from offsets to empty record decls.
- typedef std::multimap<uint64_t, const CXXRecordDecl *> EmptyClassOffsetsTy;
- EmptyClassOffsetsTy EmptyClassOffsets;
-
- ASTRecordLayoutBuilder(ASTContext &Ctx);
-
- void Layout(const RecordDecl *D);
- void Layout(const CXXRecordDecl *D);
- void Layout(const ObjCInterfaceDecl *D,
- const ObjCImplementationDecl *Impl);
-
- void LayoutFields(const RecordDecl *D);
- void LayoutField(const FieldDecl *D);
- void LayoutWideBitField(uint64_t FieldSize, uint64_t TypeSize);
- void LayoutBitField(const FieldDecl *D);
-
- /// DeterminePrimaryBase - Determine the primary base of the given class.
- void DeterminePrimaryBase(const CXXRecordDecl *RD);
-
- void SelectPrimaryVBase(const CXXRecordDecl *RD);
-
- /// IdentifyPrimaryBases - Identify all virtual base classes, direct or
- /// indirect, that are primary base classes for some other direct or indirect
- /// base class.
- void IdentifyPrimaryBases(const CXXRecordDecl *RD);
-
- bool IsNearlyEmpty(const CXXRecordDecl *RD) const;
-
- /// LayoutNonVirtualBases - Determines the primary base class (if any) and
- /// lays it out. Will then proceed to lay out all non-virtual base clasess.
- void LayoutNonVirtualBases(const CXXRecordDecl *RD);
-
- /// LayoutNonVirtualBase - Lays out a single non-virtual base.
- void LayoutNonVirtualBase(const CXXRecordDecl *RD);
-
- void AddPrimaryVirtualBaseOffsets(const CXXRecordDecl *RD, uint64_t Offset,
- const CXXRecordDecl *MostDerivedClass);
-
- /// LayoutVirtualBases - Lays out all the virtual bases.
- void LayoutVirtualBases(const CXXRecordDecl *RD,
- const CXXRecordDecl *MostDerivedClass);
-
- /// LayoutVirtualBase - Lays out a single virtual base.
- void LayoutVirtualBase(const CXXRecordDecl *RD);
-
- /// LayoutBase - Will lay out a base and return the offset where it was
- /// placed, in bits.
- uint64_t LayoutBase(const CXXRecordDecl *RD);
-
- /// canPlaceRecordAtOffset - Return whether a record (either a base class
- /// or a field) can be placed at the given offset.
- /// Returns false if placing the record will result in two components
- /// (direct or indirect) of the same type having the same offset.
- bool canPlaceRecordAtOffset(const CXXRecordDecl *RD, uint64_t Offset) const;
-
- /// canPlaceFieldAtOffset - Return whether a field can be placed at the given
- /// offset.
- bool canPlaceFieldAtOffset(const FieldDecl *FD, uint64_t Offset) const;
-
- /// UpdateEmptyClassOffsets - Called after a record (either a base class
- /// or a field) has been placed at the given offset. Will update the
- /// EmptyClassOffsets map if the class is empty or has any empty bases or
- /// fields.
- void UpdateEmptyClassOffsets(const CXXRecordDecl *RD, uint64_t Offset);
-
- /// UpdateEmptyClassOffsets - Called after a field has been placed at the
- /// given offset.
- void UpdateEmptyClassOffsets(const FieldDecl *FD, uint64_t Offset);
-
- /// FinishLayout - Finalize record layout. Adjust record size based on the
- /// alignment.
- void FinishLayout();
-
- void UpdateAlignment(unsigned NewAlignment);
-
- ASTRecordLayoutBuilder(const ASTRecordLayoutBuilder&); // DO NOT IMPLEMENT
- void operator=(const ASTRecordLayoutBuilder&); // DO NOT IMPLEMENT
-public:
- static const ASTRecordLayout *ComputeLayout(ASTContext &Ctx,
- const RecordDecl *RD);
- static const ASTRecordLayout *ComputeLayout(ASTContext &Ctx,
- const ObjCInterfaceDecl *D,
- const ObjCImplementationDecl *Impl);
- static const CXXMethodDecl *ComputeKeyFunction(const CXXRecordDecl *RD);
-};
-
-} // end namespace clang
-
-#endif
-
diff --git a/lib/AST/Stmt.cpp b/lib/AST/Stmt.cpp
index 67fd74c288c7..80f5695e42ad 100644
--- a/lib/AST/Stmt.cpp
+++ b/lib/AST/Stmt.cpp
@@ -27,7 +27,7 @@ static struct StmtClassNameTable {
const char *Name;
unsigned Counter;
unsigned Size;
-} StmtClassInfo[Stmt::lastExprConstant+1];
+} StmtClassInfo[Stmt::lastStmtConstant+1];
static StmtClassNameTable &getStmtInfoTableEntry(Stmt::StmtClass E) {
static bool Initialized = false;
@@ -36,11 +36,11 @@ static StmtClassNameTable &getStmtInfoTableEntry(Stmt::StmtClass E) {
// Intialize the table on the first use.
Initialized = true;
-#define ABSTRACT_EXPR(CLASS, PARENT)
+#define ABSTRACT_STMT(STMT)
#define STMT(CLASS, PARENT) \
StmtClassInfo[(unsigned)Stmt::CLASS##Class].Name = #CLASS; \
StmtClassInfo[(unsigned)Stmt::CLASS##Class].Size = sizeof(CLASS);
-#include "clang/AST/StmtNodes.def"
+#include "clang/AST/StmtNodes.inc"
return StmtClassInfo[E];
}
@@ -55,13 +55,13 @@ void Stmt::PrintStats() {
unsigned sum = 0;
fprintf(stderr, "*** Stmt/Expr Stats:\n");
- for (int i = 0; i != Stmt::lastExprConstant+1; i++) {
+ for (int i = 0; i != Stmt::lastStmtConstant+1; i++) {
if (StmtClassInfo[i].Name == 0) continue;
sum += StmtClassInfo[i].Counter;
}
fprintf(stderr, " %d stmts/exprs total.\n", sum);
sum = 0;
- for (int i = 0; i != Stmt::lastExprConstant+1; i++) {
+ for (int i = 0; i != Stmt::lastStmtConstant+1; i++) {
if (StmtClassInfo[i].Name == 0) continue;
if (StmtClassInfo[i].Counter == 0) continue;
fprintf(stderr, " %d %s, %d each (%d bytes)\n",
diff --git a/lib/AST/StmtDumper.cpp b/lib/AST/StmtDumper.cpp
index a11e313fa8ae..b388a3b18ffa 100644
--- a/lib/AST/StmtDumper.cpp
+++ b/lib/AST/StmtDumper.cpp
@@ -66,8 +66,8 @@ namespace {
DumpSubTree(*CI++);
}
}
- OS << ')';
}
+ OS << ')';
} else {
Indent();
OS << "<<<NULL>>>";
diff --git a/lib/AST/StmtPrinter.cpp b/lib/AST/StmtPrinter.cpp
index 52f627d449e2..9bef49c3984d 100644
--- a/lib/AST/StmtPrinter.cpp
+++ b/lib/AST/StmtPrinter.cpp
@@ -89,7 +89,7 @@ namespace {
void VisitStmt(Stmt *Node);
#define STMT(CLASS, PARENT) \
void Visit##CLASS(CLASS *Node);
-#include "clang/AST/StmtNodes.def"
+#include "clang/AST/StmtNodes.inc"
};
}
diff --git a/lib/AST/StmtProfile.cpp b/lib/AST/StmtProfile.cpp
index d45bb2f010c0..ac3a9eeda66f 100644
--- a/lib/AST/StmtProfile.cpp
+++ b/lib/AST/StmtProfile.cpp
@@ -36,7 +36,7 @@ namespace {
void VisitStmt(Stmt *S);
#define STMT(Node, Base) void Visit##Node(Node *S);
-#include "clang/AST/StmtNodes.def"
+#include "clang/AST/StmtNodes.inc"
/// \brief Visit a declaration that is referenced within an expression
/// or statement.
@@ -430,7 +430,215 @@ void StmtProfiler::VisitBlockDeclRefExpr(BlockDeclRefExpr *S) {
ID.AddBoolean(S->isConstQualAdded());
}
+static Stmt::StmtClass DecodeOperatorCall(CXXOperatorCallExpr *S,
+ UnaryOperator::Opcode &UnaryOp,
+ BinaryOperator::Opcode &BinaryOp) {
+ switch (S->getOperator()) {
+ case OO_None:
+ case OO_New:
+ case OO_Delete:
+ case OO_Array_New:
+ case OO_Array_Delete:
+ case OO_Arrow:
+ case OO_Call:
+ case OO_Conditional:
+ case NUM_OVERLOADED_OPERATORS:
+ llvm_unreachable("Invalid operator call kind");
+ return Stmt::ArraySubscriptExprClass;
+
+ case OO_Plus:
+ if (S->getNumArgs() == 1) {
+ UnaryOp = UnaryOperator::Plus;
+ return Stmt::UnaryOperatorClass;
+ }
+
+ BinaryOp = BinaryOperator::Add;
+ return Stmt::BinaryOperatorClass;
+
+ case OO_Minus:
+ if (S->getNumArgs() == 1) {
+ UnaryOp = UnaryOperator::Minus;
+ return Stmt::UnaryOperatorClass;
+ }
+
+ BinaryOp = BinaryOperator::Sub;
+ return Stmt::BinaryOperatorClass;
+
+ case OO_Star:
+ if (S->getNumArgs() == 1) {
+ UnaryOp = UnaryOperator::Minus;
+ return Stmt::UnaryOperatorClass;
+ }
+
+ BinaryOp = BinaryOperator::Sub;
+ return Stmt::BinaryOperatorClass;
+
+ case OO_Slash:
+ BinaryOp = BinaryOperator::Div;
+ return Stmt::BinaryOperatorClass;
+
+ case OO_Percent:
+ BinaryOp = BinaryOperator::Rem;
+ return Stmt::BinaryOperatorClass;
+
+ case OO_Caret:
+ BinaryOp = BinaryOperator::Xor;
+ return Stmt::BinaryOperatorClass;
+
+ case OO_Amp:
+ if (S->getNumArgs() == 1) {
+ UnaryOp = UnaryOperator::AddrOf;
+ return Stmt::UnaryOperatorClass;
+ }
+
+ BinaryOp = BinaryOperator::And;
+ return Stmt::BinaryOperatorClass;
+
+ case OO_Pipe:
+ BinaryOp = BinaryOperator::Or;
+ return Stmt::BinaryOperatorClass;
+
+ case OO_Tilde:
+ UnaryOp = UnaryOperator::Not;
+ return Stmt::UnaryOperatorClass;
+
+ case OO_Exclaim:
+ UnaryOp = UnaryOperator::LNot;
+ return Stmt::UnaryOperatorClass;
+
+ case OO_Equal:
+ BinaryOp = BinaryOperator::Assign;
+ return Stmt::BinaryOperatorClass;
+
+ case OO_Less:
+ BinaryOp = BinaryOperator::LT;
+ return Stmt::BinaryOperatorClass;
+
+ case OO_Greater:
+ BinaryOp = BinaryOperator::GT;
+ return Stmt::BinaryOperatorClass;
+
+ case OO_PlusEqual:
+ BinaryOp = BinaryOperator::AddAssign;
+ return Stmt::CompoundAssignOperatorClass;
+
+ case OO_MinusEqual:
+ BinaryOp = BinaryOperator::SubAssign;
+ return Stmt::CompoundAssignOperatorClass;
+
+ case OO_StarEqual:
+ BinaryOp = BinaryOperator::MulAssign;
+ return Stmt::CompoundAssignOperatorClass;
+
+ case OO_SlashEqual:
+ BinaryOp = BinaryOperator::DivAssign;
+ return Stmt::CompoundAssignOperatorClass;
+
+ case OO_PercentEqual:
+ BinaryOp = BinaryOperator::RemAssign;
+ return Stmt::CompoundAssignOperatorClass;
+
+ case OO_CaretEqual:
+ BinaryOp = BinaryOperator::XorAssign;
+ return Stmt::CompoundAssignOperatorClass;
+
+ case OO_AmpEqual:
+ BinaryOp = BinaryOperator::AndAssign;
+ return Stmt::CompoundAssignOperatorClass;
+
+ case OO_PipeEqual:
+ BinaryOp = BinaryOperator::OrAssign;
+ return Stmt::CompoundAssignOperatorClass;
+
+ case OO_LessLess:
+ BinaryOp = BinaryOperator::Shl;
+ return Stmt::BinaryOperatorClass;
+
+ case OO_GreaterGreater:
+ BinaryOp = BinaryOperator::Shr;
+ return Stmt::BinaryOperatorClass;
+
+ case OO_LessLessEqual:
+ BinaryOp = BinaryOperator::ShlAssign;
+ return Stmt::CompoundAssignOperatorClass;
+
+ case OO_GreaterGreaterEqual:
+ BinaryOp = BinaryOperator::ShrAssign;
+ return Stmt::CompoundAssignOperatorClass;
+
+ case OO_EqualEqual:
+ BinaryOp = BinaryOperator::EQ;
+ return Stmt::BinaryOperatorClass;
+
+ case OO_ExclaimEqual:
+ BinaryOp = BinaryOperator::NE;
+ return Stmt::BinaryOperatorClass;
+
+ case OO_LessEqual:
+ BinaryOp = BinaryOperator::LE;
+ return Stmt::BinaryOperatorClass;
+
+ case OO_GreaterEqual:
+ BinaryOp = BinaryOperator::GE;
+ return Stmt::BinaryOperatorClass;
+
+ case OO_AmpAmp:
+ BinaryOp = BinaryOperator::LAnd;
+ return Stmt::BinaryOperatorClass;
+
+ case OO_PipePipe:
+ BinaryOp = BinaryOperator::LOr;
+ return Stmt::BinaryOperatorClass;
+
+ case OO_PlusPlus:
+ UnaryOp = S->getNumArgs() == 1? UnaryOperator::PreInc
+ : UnaryOperator::PostInc;
+ return Stmt::UnaryOperatorClass;
+
+ case OO_MinusMinus:
+ UnaryOp = S->getNumArgs() == 1? UnaryOperator::PreDec
+ : UnaryOperator::PostDec;
+ return Stmt::UnaryOperatorClass;
+
+ case OO_Comma:
+ BinaryOp = BinaryOperator::Comma;
+ return Stmt::BinaryOperatorClass;
+
+
+ case OO_ArrowStar:
+ BinaryOp = BinaryOperator::PtrMemI;
+ return Stmt::BinaryOperatorClass;
+
+ case OO_Subscript:
+ return Stmt::ArraySubscriptExprClass;
+ }
+
+ llvm_unreachable("Invalid overloaded operator expression");
+}
+
+
void StmtProfiler::VisitCXXOperatorCallExpr(CXXOperatorCallExpr *S) {
+ if (S->isTypeDependent()) {
+ // Type-dependent operator calls are profiled like their underlying
+ // syntactic operator.
+ UnaryOperator::Opcode UnaryOp = UnaryOperator::Extension;
+ BinaryOperator::Opcode BinaryOp = BinaryOperator::Comma;
+ Stmt::StmtClass SC = DecodeOperatorCall(S, UnaryOp, BinaryOp);
+
+ ID.AddInteger(SC);
+ for (unsigned I = 0, N = S->getNumArgs(); I != N; ++I)
+ Visit(S->getArg(I));
+ if (SC == Stmt::UnaryOperatorClass)
+ ID.AddInteger(UnaryOp);
+ else if (SC == Stmt::BinaryOperatorClass ||
+ SC == Stmt::CompoundAssignOperatorClass)
+ ID.AddInteger(BinaryOp);
+ else
+ assert(SC == Stmt::ArraySubscriptExprClass);
+
+ return;
+ }
+
VisitCallExpr(S);
ID.AddInteger(S->getOperator());
}
diff --git a/lib/AST/TemplateBase.cpp b/lib/AST/TemplateBase.cpp
index e9b17256415f..1c775efe5777 100644
--- a/lib/AST/TemplateBase.cpp
+++ b/lib/AST/TemplateBase.cpp
@@ -18,6 +18,7 @@
#include "clang/AST/DeclTemplate.h"
#include "clang/AST/Expr.h"
#include "clang/AST/TypeLoc.h"
+#include "clang/Basic/Diagnostic.h"
using namespace clang;
@@ -102,7 +103,7 @@ SourceRange TemplateArgumentLoc::getSourceRange() const {
return getSourceDeclExpression()->getSourceRange();
case TemplateArgument::Type:
- return getTypeSourceInfo()->getTypeLoc().getFullSourceRange();
+ return getTypeSourceInfo()->getTypeLoc().getSourceRange();
case TemplateArgument::Template:
if (getTemplateQualifierRange().isValid())
@@ -119,3 +120,42 @@ SourceRange TemplateArgumentLoc::getSourceRange() const {
// Silence bonus gcc warning.
return SourceRange();
}
+
+const DiagnosticBuilder &clang::operator<<(const DiagnosticBuilder &DB,
+ const TemplateArgument &Arg) {
+ switch (Arg.getKind()) {
+ case TemplateArgument::Null:
+ return DB;
+
+ case TemplateArgument::Type:
+ return DB << Arg.getAsType();
+
+ case TemplateArgument::Declaration:
+ return DB << Arg.getAsDecl();
+
+ case TemplateArgument::Integral:
+ return DB << Arg.getAsIntegral()->toString(10);
+
+ case TemplateArgument::Template:
+ return DB << Arg.getAsTemplate();
+
+ case TemplateArgument::Expression: {
+ // This shouldn't actually ever happen, so it's okay that we're
+ // regurgitating an expression here.
+ // FIXME: We're guessing at LangOptions!
+ llvm::SmallString<32> Str;
+ llvm::raw_svector_ostream OS(Str);
+ LangOptions LangOpts;
+ LangOpts.CPlusPlus = true;
+ PrintingPolicy Policy(LangOpts);
+ Arg.getAsExpr()->printPretty(OS, 0, Policy);
+ return DB << OS.str();
+ }
+
+ case TemplateArgument::Pack:
+ // FIXME: Format arguments in a list!
+ return DB << "<parameter pack>";
+ }
+
+ return DB;
+}
diff --git a/lib/AST/Type.cpp b/lib/AST/Type.cpp
index 05e7fdc49e35..1aab65ebec55 100644
--- a/lib/AST/Type.cpp
+++ b/lib/AST/Type.cpp
@@ -18,6 +18,7 @@
#include "clang/AST/DeclTemplate.h"
#include "clang/AST/Expr.h"
#include "clang/AST/PrettyPrinter.h"
+#include "clang/Basic/Specifiers.h"
#include "llvm/ADT/StringExtras.h"
#include "llvm/Support/raw_ostream.h"
using namespace clang;
@@ -276,6 +277,9 @@ QualType Type::getPointeeType() const {
/// array types and types that contain variable array types in their
/// declarator
bool Type::isVariablyModifiedType() const {
+ // FIXME: We should really keep a "variably modified" bit in Type, rather
+ // than walking the type hierarchy to recompute it.
+
// A VLA is a variably modified type.
if (isVariableArrayType())
return true;
@@ -344,29 +348,36 @@ const RecordType *Type::getAsUnionType() const {
return 0;
}
-ObjCInterfaceType::ObjCInterfaceType(QualType Canonical,
- ObjCInterfaceDecl *D,
- ObjCProtocolDecl **Protos, unsigned NumP) :
- Type(ObjCInterface, Canonical, /*Dependent=*/false),
- Decl(D), NumProtocols(NumP)
-{
+void ObjCInterfaceType::Destroy(ASTContext& C) {
+ this->~ObjCInterfaceType();
+ C.Deallocate(this);
+}
+
+ObjCObjectType::ObjCObjectType(QualType Canonical, QualType Base,
+ ObjCProtocolDecl * const *Protocols,
+ unsigned NumProtocols)
+ : Type(ObjCObject, Canonical, false),
+ NumProtocols(NumProtocols),
+ BaseType(Base) {
+ assert(this->NumProtocols == NumProtocols &&
+ "bitfield overflow in protocol count");
if (NumProtocols)
- memcpy(reinterpret_cast<ObjCProtocolDecl**>(this + 1), Protos,
- NumProtocols * sizeof(*Protos));
+ memcpy(getProtocolStorage(), Protocols,
+ NumProtocols * sizeof(ObjCProtocolDecl*));
}
-void ObjCInterfaceType::Destroy(ASTContext& C) {
- this->~ObjCInterfaceType();
+void ObjCObjectTypeImpl::Destroy(ASTContext& C) {
+ this->~ObjCObjectTypeImpl();
C.Deallocate(this);
}
-const ObjCInterfaceType *Type::getAsObjCQualifiedInterfaceType() const {
- // There is no sugar for ObjCInterfaceType's, just return the canonical
+const ObjCObjectType *Type::getAsObjCQualifiedInterfaceType() const {
+ // There is no sugar for ObjCObjectType's, just return the canonical
// type pointer if it is the right class. There is no typedef information to
// return and these cannot be Address-space qualified.
- if (const ObjCInterfaceType *OIT = getAs<ObjCInterfaceType>())
- if (OIT->getNumProtocols())
- return OIT;
+ if (const ObjCObjectType *T = getAs<ObjCObjectType>())
+ if (T->getNumProtocols() && T->getInterface())
+ return T;
return 0;
}
@@ -374,17 +385,6 @@ bool Type::isObjCQualifiedInterfaceType() const {
return getAsObjCQualifiedInterfaceType() != 0;
}
-ObjCObjectPointerType::ObjCObjectPointerType(QualType Canonical, QualType T,
- ObjCProtocolDecl **Protos,
- unsigned NumP) :
- Type(ObjCObjectPointer, Canonical, /*Dependent=*/false),
- PointeeType(T), NumProtocols(NumP)
-{
- if (NumProtocols)
- memcpy(reinterpret_cast<ObjCProtocolDecl **>(this + 1), Protos,
- NumProtocols * sizeof(*Protos));
-}
-
void ObjCObjectPointerType::Destroy(ASTContext& C) {
this->~ObjCObjectPointerType();
C.Deallocate(this);
@@ -637,6 +637,8 @@ bool Type::isIncompleteType() const {
case IncompleteArray:
// An array of unknown size is an incomplete type (C99 6.2.5p22).
return true;
+ case ObjCObject:
+ return cast<ObjCObjectType>(this)->getBaseType()->isIncompleteType();
case ObjCInterface:
// ObjC interfaces are incomplete if they are @class, not @interface.
return cast<ObjCInterfaceType>(this)->getDecl()->isForwardDecl();
@@ -764,36 +766,106 @@ bool Type::isSpecifierType() const {
case TemplateTypeParm:
case SubstTemplateTypeParm:
case TemplateSpecialization:
- case QualifiedName:
+ case Elaborated:
case DependentName:
case ObjCInterface:
- case ObjCObjectPointer:
- case Elaborated:
+ case ObjCObject:
+ case ObjCObjectPointer: // FIXME: object pointers aren't really specifiers
return true;
default:
return false;
}
}
-bool Type::isElaboratedTypeSpecifier() const {
- if (getTypeClass() == Elaborated)
+TypeWithKeyword::~TypeWithKeyword() {
+}
+
+ElaboratedTypeKeyword
+TypeWithKeyword::getKeywordForTypeSpec(unsigned TypeSpec) {
+ switch (TypeSpec) {
+ default: return ETK_None;
+ case TST_typename: return ETK_Typename;
+ case TST_class: return ETK_Class;
+ case TST_struct: return ETK_Struct;
+ case TST_union: return ETK_Union;
+ case TST_enum: return ETK_Enum;
+ }
+}
+
+TagTypeKind
+TypeWithKeyword::getTagTypeKindForTypeSpec(unsigned TypeSpec) {
+ switch(TypeSpec) {
+ case TST_class: return TTK_Class;
+ case TST_struct: return TTK_Struct;
+ case TST_union: return TTK_Union;
+ case TST_enum: return TTK_Enum;
+ default: llvm_unreachable("Type specifier is not a tag type kind.");
+ }
+}
+
+ElaboratedTypeKeyword
+TypeWithKeyword::getKeywordForTagTypeKind(TagTypeKind Kind) {
+ switch (Kind) {
+ case TTK_Class: return ETK_Class;
+ case TTK_Struct: return ETK_Struct;
+ case TTK_Union: return ETK_Union;
+ case TTK_Enum: return ETK_Enum;
+ }
+ llvm_unreachable("Unknown tag type kind.");
+}
+
+TagTypeKind
+TypeWithKeyword::getTagTypeKindForKeyword(ElaboratedTypeKeyword Keyword) {
+ switch (Keyword) {
+ case ETK_Class: return TTK_Class;
+ case ETK_Struct: return TTK_Struct;
+ case ETK_Union: return TTK_Union;
+ case ETK_Enum: return TTK_Enum;
+ case ETK_None: // Fall through.
+ case ETK_Typename:
+ llvm_unreachable("Elaborated type keyword is not a tag type kind.");
+ }
+ llvm_unreachable("Unknown elaborated type keyword.");
+}
+
+bool
+TypeWithKeyword::KeywordIsTagTypeKind(ElaboratedTypeKeyword Keyword) {
+ switch (Keyword) {
+ case ETK_None:
+ case ETK_Typename:
+ return false;
+ case ETK_Class:
+ case ETK_Struct:
+ case ETK_Union:
+ case ETK_Enum:
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;
+ llvm_unreachable("Unknown elaborated type keyword.");
+}
+
+const char*
+TypeWithKeyword::getKeywordName(ElaboratedTypeKeyword Keyword) {
+ switch (Keyword) {
+ default: llvm_unreachable("Unknown elaborated type keyword.");
+ case ETK_None: return "";
+ case ETK_Typename: return "typename";
+ case ETK_Class: return "class";
+ case ETK_Struct: return "struct";
+ case ETK_Union: return "union";
+ case ETK_Enum: return "enum";
+ }
+}
+
+bool Type::isElaboratedTypeSpecifier() const {
+ ElaboratedTypeKeyword Keyword;
+ if (const ElaboratedType *Elab = dyn_cast<ElaboratedType>(this))
+ Keyword = Elab->getKeyword();
+ else if (const DependentNameType *DepName = dyn_cast<DependentNameType>(this))
+ Keyword = DepName->getKeyword();
+ else
+ return false;
+
+ return TypeWithKeyword::KeywordIsTagTypeKind(Keyword);
}
const char *Type::getTypeClassName() const {
@@ -836,10 +908,12 @@ const char *BuiltinType::getName(const LangOptions &LO) const {
case UndeducedAuto: return "auto";
case ObjCId: return "id";
case ObjCClass: return "Class";
- case ObjCSel: return "SEL";
+ case ObjCSel: return "SEL";
}
}
+void FunctionType::ANCHOR() {} // Key function for FunctionType.
+
llvm::StringRef FunctionType::getNameForCallConv(CallingConv CC) {
switch (CC) {
case CC_Default: llvm_unreachable("no name for default cc");
@@ -848,6 +922,7 @@ llvm::StringRef FunctionType::getNameForCallConv(CallingConv CC) {
case CC_C: return "cdecl";
case CC_X86StdCall: return "stdcall";
case CC_X86FastCall: return "fastcall";
+ case CC_X86ThisCall: return "thiscall";
}
}
@@ -881,19 +956,6 @@ void FunctionProtoType::Profile(llvm::FoldingSetNodeID &ID) {
getExtInfo());
}
-void ObjCObjectPointerType::Profile(llvm::FoldingSetNodeID &ID,
- QualType OIT,
- ObjCProtocolDecl * const *protocols,
- unsigned NumProtocols) {
- ID.AddPointer(OIT.getAsOpaquePtr());
- for (unsigned i = 0; i != NumProtocols; i++)
- ID.AddPointer(protocols[i]);
-}
-
-void ObjCObjectPointerType::Profile(llvm::FoldingSetNodeID &ID) {
- Profile(ID, getPointeeType(), qual_begin(), getNumProtocols());
-}
-
/// LookThroughTypedefs - Return the ultimate type this typedef corresponds to
/// potentially looking through *all* consequtive typedefs. This returns the
/// sum of the type qualifiers, so if you have:
@@ -975,6 +1037,10 @@ static bool isDependent(const TemplateArgument &Arg) {
return Arg.getAsTemplate().isDependent();
case TemplateArgument::Declaration:
+ if (DeclContext *DC = dyn_cast<DeclContext>(Arg.getAsDecl()))
+ return DC->isDependentContext();
+ return Arg.getAsDecl()->getDeclContext()->isDependentContext();
+
case TemplateArgument::Integral:
// Never dependent
return false;
@@ -984,7 +1050,13 @@ static bool isDependent(const TemplateArgument &Arg) {
Arg.getAsExpr()->isValueDependent());
case TemplateArgument::Pack:
- assert(0 && "FIXME: Implement!");
+ for (TemplateArgument::pack_iterator P = Arg.pack_begin(),
+ PEnd = Arg.pack_end();
+ P != PEnd; ++P) {
+ if (isDependent(*P))
+ return true;
+ }
+
return false;
}
@@ -1081,36 +1153,53 @@ QualType QualifierCollector::apply(const Type *T) const {
return Context->getQualifiedType(T, *this);
}
-void ObjCInterfaceType::Profile(llvm::FoldingSetNodeID &ID,
- const ObjCInterfaceDecl *Decl,
- ObjCProtocolDecl * const *protocols,
- unsigned NumProtocols) {
- ID.AddPointer(Decl);
+void ObjCObjectTypeImpl::Profile(llvm::FoldingSetNodeID &ID,
+ QualType BaseType,
+ ObjCProtocolDecl * const *Protocols,
+ unsigned NumProtocols) {
+ ID.AddPointer(BaseType.getAsOpaquePtr());
for (unsigned i = 0; i != NumProtocols; i++)
- ID.AddPointer(protocols[i]);
+ ID.AddPointer(Protocols[i]);
}
-void ObjCInterfaceType::Profile(llvm::FoldingSetNodeID &ID) {
- Profile(ID, getDecl(), qual_begin(), getNumProtocols());
+void ObjCObjectTypeImpl::Profile(llvm::FoldingSetNodeID &ID) {
+ Profile(ID, getBaseType(), qual_begin(), getNumProtocols());
}
-Linkage Type::getLinkage() const {
- // C++ [basic.link]p8:
- // Names not covered by these rules have no linkage.
+/// \brief Determine the linkage of this type.
+Linkage Type::getLinkage() const {
if (this != CanonicalType.getTypePtr())
return CanonicalType->getLinkage();
+
+ if (!LinkageKnown) {
+ CachedLinkage = getLinkageImpl();
+ LinkageKnown = true;
+ }
+
+ return static_cast<clang::Linkage>(CachedLinkage);
+}
+Linkage Type::getLinkageImpl() const {
+ // C++ [basic.link]p8:
+ // Names not covered by these rules have no linkage.
return NoLinkage;
}
-Linkage BuiltinType::getLinkage() const {
+void Type::ClearLinkageCache() {
+ if (this != CanonicalType.getTypePtr())
+ CanonicalType->ClearLinkageCache();
+ else
+ LinkageKnown = false;
+}
+
+Linkage BuiltinType::getLinkageImpl() const {
// C++ [basic.link]p8:
// A type is said to have linkage if and only if:
// - it is a fundamental type (3.9.1); or
return ExternalLinkage;
}
-Linkage TagType::getLinkage() const {
+Linkage TagType::getLinkageImpl() const {
// C++ [basic.link]p8:
// - it is a class or enumeration type that is named (or has a name for
// linkage purposes (7.1.3)) and the name has linkage; or
@@ -1121,39 +1210,39 @@ Linkage TagType::getLinkage() const {
// C++ [basic.link]p8:
// - it is a compound type (3.9.2) other than a class or enumeration,
// compounded exclusively from types that have linkage; or
-Linkage ComplexType::getLinkage() const {
+Linkage ComplexType::getLinkageImpl() const {
return ElementType->getLinkage();
}
-Linkage PointerType::getLinkage() const {
+Linkage PointerType::getLinkageImpl() const {
return PointeeType->getLinkage();
}
-Linkage BlockPointerType::getLinkage() const {
+Linkage BlockPointerType::getLinkageImpl() const {
return PointeeType->getLinkage();
}
-Linkage ReferenceType::getLinkage() const {
+Linkage ReferenceType::getLinkageImpl() const {
return PointeeType->getLinkage();
}
-Linkage MemberPointerType::getLinkage() const {
+Linkage MemberPointerType::getLinkageImpl() const {
return minLinkage(Class->getLinkage(), PointeeType->getLinkage());
}
-Linkage ArrayType::getLinkage() const {
+Linkage ArrayType::getLinkageImpl() const {
return ElementType->getLinkage();
}
-Linkage VectorType::getLinkage() const {
+Linkage VectorType::getLinkageImpl() const {
return ElementType->getLinkage();
}
-Linkage FunctionNoProtoType::getLinkage() const {
+Linkage FunctionNoProtoType::getLinkageImpl() const {
return getResultType()->getLinkage();
}
-Linkage FunctionProtoType::getLinkage() const {
+Linkage FunctionProtoType::getLinkageImpl() const {
Linkage L = getResultType()->getLinkage();
for (arg_type_iterator A = arg_type_begin(), AEnd = arg_type_end();
A != AEnd; ++A)
@@ -1162,10 +1251,10 @@ Linkage FunctionProtoType::getLinkage() const {
return L;
}
-Linkage ObjCInterfaceType::getLinkage() const {
+Linkage ObjCObjectType::getLinkageImpl() const {
return ExternalLinkage;
}
-Linkage ObjCObjectPointerType::getLinkage() const {
+Linkage ObjCObjectPointerType::getLinkageImpl() const {
return ExternalLinkage;
}
diff --git a/lib/AST/TypeLoc.cpp b/lib/AST/TypeLoc.cpp
index fd9fbc191868..4893b384dd10 100644
--- a/lib/AST/TypeLoc.cpp
+++ b/lib/AST/TypeLoc.cpp
@@ -27,13 +27,13 @@ namespace {
#define ABSTRACT_TYPELOC(CLASS, PARENT)
#define TYPELOC(CLASS, PARENT) \
SourceRange Visit##CLASS##TypeLoc(CLASS##TypeLoc TyLoc) { \
- return TyLoc.getSourceRange(); \
+ return TyLoc.getLocalSourceRange(); \
}
#include "clang/AST/TypeLocNodes.def"
};
}
-SourceRange TypeLoc::getSourceRangeImpl(TypeLoc TL) {
+SourceRange TypeLoc::getLocalSourceRangeImpl(TypeLoc TL) {
if (TL.isNull()) return SourceRange();
return TypeLocRanger().Visit(TL);
}
@@ -92,11 +92,58 @@ namespace {
/// recursively, as if the entire tree had been written in the
/// given location.
void TypeLoc::initializeImpl(TypeLoc TL, SourceLocation Loc) {
- do {
- TypeLocInitializer(Loc).Visit(TL);
- } while ((TL = TL.getNextTypeLoc()));
+ while (true) {
+ switch (TL.getTypeLocClass()) {
+#define ABSTRACT_TYPELOC(CLASS, PARENT)
+#define TYPELOC(CLASS, PARENT) \
+ case CLASS: { \
+ CLASS##TypeLoc TLCasted = cast<CLASS##TypeLoc>(TL); \
+ TLCasted.initializeLocal(Loc); \
+ TL = TLCasted.getNextTypeLoc(); \
+ if (!TL) return; \
+ continue; \
+ }
+#include "clang/AST/TypeLocNodes.def"
+ }
+ }
+}
+
+SourceLocation TypeLoc::getBeginLoc() const {
+ TypeLoc Cur = *this;
+ while (true) {
+ switch (Cur.getTypeLocClass()) {
+ // FIXME: Currently QualifiedTypeLoc does not have a source range
+ // case Qualified:
+ case Elaborated:
+ break;
+ default:
+ TypeLoc Next = Cur.getNextTypeLoc();
+ if (Next.isNull()) break;
+ Cur = Next;
+ continue;
+ }
+ break;
+ }
+ return Cur.getLocalSourceRange().getBegin();
}
+SourceLocation TypeLoc::getEndLoc() const {
+ TypeLoc Cur = *this;
+ while (true) {
+ switch (Cur.getTypeLocClass()) {
+ default:
+ break;
+ case Qualified:
+ case Elaborated:
+ Cur = Cur.getNextTypeLoc();
+ continue;
+ }
+ break;
+ }
+ return Cur.getLocalSourceRange().getEnd();
+}
+
+
namespace {
struct TSTChecker : public TypeLocVisitor<TSTChecker, bool> {
// Overload resolution does the real work for us.
@@ -129,7 +176,7 @@ bool TypeSpecTypeLoc::classof(const TypeLoc *TL) {
// Reimplemented to account for GNU/C++ extension
// typeof unary-expression
// where there are no parentheses.
-SourceRange TypeOfExprTypeLoc::getSourceRange() const {
+SourceRange TypeOfExprTypeLoc::getLocalSourceRange() const {
if (getRParenLoc().isValid())
return SourceRange(getTypeofLoc(), getRParenLoc());
else
diff --git a/lib/AST/TypePrinter.cpp b/lib/AST/TypePrinter.cpp
index 915d7af9a8c3..35a7e096994d 100644
--- a/lib/AST/TypePrinter.cpp
+++ b/lib/AST/TypePrinter.cpp
@@ -295,6 +295,9 @@ void TypePrinter::PrintFunctionProto(const FunctionProtoType *T,
case CC_X86FastCall:
S += " __attribute__((fastcall))";
break;
+ case CC_X86ThisCall:
+ S += " __attribute__((thiscall))";
+ break;
}
if (Info.getNoReturn())
S += " __attribute__((noreturn))";
@@ -497,16 +500,6 @@ void TypePrinter::PrintEnum(const EnumType *T, std::string &S) {
PrintTag(T->getDecl(), S);
}
-void TypePrinter::PrintElaborated(const ElaboratedType *T, std::string &S) {
- Print(T->getUnderlyingType(), S);
-
- // We don't actually make these in C, but the language options
- // sometimes lie to us -- for example, if someone calls
- // QualType::getAsString(). Just suppress the redundant tag if so.
- if (Policy.LangOpts.CPlusPlus)
- S = std::string(T->getNameForTagKind(T->getTagKind())) + ' ' + S;
-}
-
void TypePrinter::PrintTemplateTypeParm(const TemplateTypeParmType *T,
std::string &S) {
if (!S.empty()) // Prefix the basic type, e.g. 'parmname X'.
@@ -549,13 +542,17 @@ void TypePrinter::PrintInjectedClassName(const InjectedClassNameType *T,
PrintTemplateSpecialization(T->getInjectedTST(), S);
}
-void TypePrinter::PrintQualifiedName(const QualifiedNameType *T,
- std::string &S) {
+void TypePrinter::PrintElaborated(const ElaboratedType *T, std::string &S) {
std::string MyString;
{
llvm::raw_string_ostream OS(MyString);
- T->getQualifier()->print(OS, Policy);
+ OS << TypeWithKeyword::getKeywordName(T->getKeyword());
+ if (T->getKeyword() != ETK_None)
+ OS << " ";
+ NestedNameSpecifier* Qualifier = T->getQualifier();
+ if (Qualifier)
+ Qualifier->print(OS, Policy);
}
std::string TypeStr;
@@ -575,14 +572,9 @@ void TypePrinter::PrintDependentName(const DependentNameType *T, std::string &S)
{
llvm::raw_string_ostream OS(MyString);
- 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;
- }
+ OS << TypeWithKeyword::getKeywordName(T->getKeyword());
+ if (T->getKeyword() != ETK_None)
+ OS << " ";
T->getQualifier()->print(OS, Policy);
@@ -607,25 +599,37 @@ void TypePrinter::PrintObjCInterface(const ObjCInterfaceType *T,
std::string &S) {
if (!S.empty()) // Prefix the basic type, e.g. 'typedefname X'.
S = ' ' + S;
-
+
std::string ObjCQIString = T->getDecl()->getNameAsString();
- if (T->getNumProtocols()) {
- ObjCQIString += '<';
- bool isFirst = true;
- for (ObjCInterfaceType::qual_iterator I = T->qual_begin(),
- E = T->qual_end();
- I != E; ++I) {
- if (isFirst)
- isFirst = false;
- else
- ObjCQIString += ',';
- ObjCQIString += (*I)->getNameAsString();
- }
- ObjCQIString += '>';
- }
S = ObjCQIString + S;
}
+void TypePrinter::PrintObjCObject(const ObjCObjectType *T,
+ std::string &S) {
+ if (T->qual_empty())
+ return Print(T->getBaseType(), S);
+
+ std::string tmp;
+ Print(T->getBaseType(), tmp);
+ tmp += '<';
+ bool isFirst = true;
+ for (ObjCObjectType::qual_iterator
+ I = T->qual_begin(), E = T->qual_end(); I != E; ++I) {
+ if (isFirst)
+ isFirst = false;
+ else
+ tmp += ',';
+ tmp += (*I)->getNameAsString();
+ }
+ tmp += '>';
+
+ if (!S.empty()) {
+ tmp += ' ';
+ tmp += S;
+ }
+ std::swap(tmp, S);
+}
+
void TypePrinter::PrintObjCObjectPointer(const ObjCObjectPointerType *T,
std::string &S) {
std::string ObjCQIString;
diff --git a/lib/Analysis/CFG.cpp b/lib/Analysis/CFG.cpp
index 7f71e0acf7a3..6f2cb41a6e40 100644
--- a/lib/Analysis/CFG.cpp
+++ b/lib/Analysis/CFG.cpp
@@ -985,6 +985,11 @@ CFGBlock* CFGBuilder::VisitForStmt(ForStmt* F) {
} else
LoopSuccessor = Succ;
+ // Save the current value for the break targets.
+ // All breaks should go to the code following the loop.
+ SaveAndRestore<CFGBlock*> save_break(BreakTargetBlock);
+ BreakTargetBlock = LoopSuccessor;
+
// Because of short-circuit evaluation, the condition of the loop can span
// multiple basic blocks. Thus we need the "Entry" and "Exit" blocks that
// evaluate the condition.
@@ -1032,10 +1037,9 @@ CFGBlock* CFGBuilder::VisitForStmt(ForStmt* F) {
{
assert(F->getBody());
- // Save the current values for Block, Succ, and continue and break targets
- SaveAndRestore<CFGBlock*> save_Block(Block), save_Succ(Succ),
- save_continue(ContinueTargetBlock),
- save_break(BreakTargetBlock);
+ // Save the current values for Block, Succ, and continue targets.
+ SaveAndRestore<CFGBlock*> save_Block(Block), save_Succ(Succ),
+ save_continue(ContinueTargetBlock);
// Create a new block to contain the (bottom) of the loop body.
Block = NULL;
@@ -1065,9 +1069,6 @@ CFGBlock* CFGBuilder::VisitForStmt(ForStmt* F) {
// represent the 'loop target' for looping back to the start of the loop.
ContinueTargetBlock->setLoopTarget(F);
- // All breaks should go to the code following the loop.
- BreakTargetBlock = LoopSuccessor;
-
// Now populate the body block, and in the process create new blocks as we
// walk the body of the loop.
CFGBlock* BodyBlock = addStmt(F->getBody());
@@ -1223,10 +1224,9 @@ CFGBlock* CFGBuilder::VisitObjCAtSynchronizedStmt(ObjCAtSynchronizedStmt* S) {
return 0;
Block = 0;
+ Succ = SyncBlock;
}
- Succ = SyncBlock;
-
// Inline the sync expression.
return addStmt(S->getSynchExpr());
}
diff --git a/lib/Analysis/CMakeLists.txt b/lib/Analysis/CMakeLists.txt
index b4e0e242485b..a8e37087c09c 100644
--- a/lib/Analysis/CMakeLists.txt
+++ b/lib/Analysis/CMakeLists.txt
@@ -9,4 +9,4 @@ add_clang_library(clangAnalysis
UninitializedValues.cpp
)
-add_dependencies(clangAnalysis ClangDiagnosticAnalysis)
+add_dependencies(clangAnalysis ClangDiagnosticAnalysis ClangStmtNodes)
diff --git a/lib/Basic/Diagnostic.cpp b/lib/Basic/Diagnostic.cpp
index 9e6f168f1711..2fd985f53803 100644
--- a/lib/Basic/Diagnostic.cpp
+++ b/lib/Basic/Diagnostic.cpp
@@ -127,6 +127,35 @@ const char *Diagnostic::getWarningOptionForDiag(unsigned DiagID) {
return 0;
}
+/// getWarningOptionForDiag - Return the category number that a specified
+/// DiagID belongs to, or 0 if no category.
+unsigned Diagnostic::getCategoryNumberForDiag(unsigned DiagID) {
+ if (const StaticDiagInfoRec *Info = GetDiagInfo(DiagID))
+ return Info->Category;
+ return 0;
+}
+
+/// getCategoryNameFromID - Given a category ID, return the name of the
+/// category, an empty string if CategoryID is zero, or null if CategoryID is
+/// invalid.
+const char *Diagnostic::getCategoryNameFromID(unsigned CategoryID) {
+ // Second the table of options, sorted by name for fast binary lookup.
+ static const char *CategoryNameTable[] = {
+#define GET_CATEGORY_TABLE
+#define CATEGORY(X) X,
+#include "clang/Basic/DiagnosticGroups.inc"
+#undef GET_CATEGORY_TABLE
+ "<<END>>"
+ };
+ static const size_t CategoryNameTableSize =
+ sizeof(CategoryNameTable) / sizeof(CategoryNameTable[0])-1;
+
+ if (CategoryID >= CategoryNameTableSize) return 0;
+ return CategoryNameTable[CategoryID];
+}
+
+
+
Diagnostic::SFINAEResponse
Diagnostic::getDiagnosticSFINAEResponse(unsigned DiagID) {
if (const StaticDiagInfoRec *Info = GetDiagInfo(DiagID)) {
@@ -432,7 +461,7 @@ Diagnostic::getDiagnosticLevel(unsigned DiagID, unsigned DiagClass) const {
struct WarningOption {
const char *Name;
const short *Members;
- const char *SubGroups;
+ const short *SubGroups;
};
#define GET_DIAG_ARRAYS
@@ -462,9 +491,9 @@ static void MapGroupMembers(const WarningOption *Group, diag::Mapping Mapping,
}
// Enable/disable all subgroups along with this one.
- if (const char *SubGroups = Group->SubGroups) {
- for (; *SubGroups != (char)-1; ++SubGroups)
- MapGroupMembers(&OptionTable[(unsigned char)*SubGroups], Mapping, Diags);
+ if (const short *SubGroups = Group->SubGroups) {
+ for (; *SubGroups != (short)-1; ++SubGroups)
+ MapGroupMembers(&OptionTable[(short)*SubGroups], Mapping, Diags);
}
}
diff --git a/lib/Basic/IdentifierTable.cpp b/lib/Basic/IdentifierTable.cpp
index ed0de8c4af09..8993e6713fbe 100644
--- a/lib/Basic/IdentifierTable.cpp
+++ b/lib/Basic/IdentifierTable.cpp
@@ -70,7 +70,8 @@ namespace {
KEYGNU = 16,
KEYMS = 32,
BOOLSUPPORT = 64,
- KEYALTIVEC = 128
+ KEYALTIVEC = 128,
+ KEYNOMS = 256
};
}
@@ -94,6 +95,7 @@ static void AddKeyword(llvm::StringRef Keyword,
else if (LangOpts.Microsoft && (Flags & KEYMS)) AddResult = 1;
else if (LangOpts.Bool && (Flags & BOOLSUPPORT)) AddResult = 2;
else if (LangOpts.AltiVec && (Flags & KEYALTIVEC)) AddResult = 2;
+ else if (!LangOpts.Microsoft && (Flags & KEYNOMS)) AddResult = 2;
// Don't add this keyword if disabled in this language.
if (AddResult == 0) return;
diff --git a/lib/Basic/SourceManager.cpp b/lib/Basic/SourceManager.cpp
index 3ecab1d8c16f..e6d9785e1505 100644
--- a/lib/Basic/SourceManager.cpp
+++ b/lib/Basic/SourceManager.cpp
@@ -1154,6 +1154,27 @@ SourceLocation SourceManager::getLocation(const FileEntry *SourceFile,
return getLocForStartOfFile(FirstFID).getFileLocWithOffset(FilePos + Col - 1);
}
+/// Given a decomposed source location, move it up the include/instantiation
+/// stack to the parent source location. If this is possible, return the
+/// decomposed version of the parent in Loc and return false. If Loc is the
+/// top-level entry, return true and don't modify it.
+static bool MoveUpIncludeHierarchy(std::pair<FileID, unsigned> &Loc,
+ const SourceManager &SM) {
+ SourceLocation UpperLoc;
+ const SrcMgr::SLocEntry &Entry = SM.getSLocEntry(Loc.first);
+ if (Entry.isInstantiation())
+ UpperLoc = Entry.getInstantiation().getInstantiationLocStart();
+ else
+ UpperLoc = Entry.getFile().getIncludeLoc();
+
+ if (UpperLoc.isInvalid())
+ return true; // We reached the top.
+
+ Loc = SM.getDecomposedLoc(UpperLoc);
+ return false;
+}
+
+
/// \brief Determines the order of 2 source locations in the translation unit.
///
/// \returns true if LHS source location comes before RHS, false otherwise.
@@ -1172,78 +1193,74 @@ bool SourceManager::isBeforeInTranslationUnit(SourceLocation LHS,
// If we are comparing a source location with multiple locations in the same
// file, we get a big win by caching the result.
+ if (IsBeforeInTUCache.isCacheValid(LOffs.first, ROffs.first))
+ return IsBeforeInTUCache.getCachedResult(LOffs.second, ROffs.second);
- if (LastLFIDForBeforeTUCheck == LOffs.first &&
- LastRFIDForBeforeTUCheck == ROffs.first)
- return LastResForBeforeTUCheck;
-
- LastLFIDForBeforeTUCheck = LOffs.first;
- LastRFIDForBeforeTUCheck = ROffs.first;
+ // Okay, we missed in the cache, start updating the cache for this query.
+ IsBeforeInTUCache.setQueryFIDs(LOffs.first, ROffs.first);
// "Traverse" the include/instantiation stacks of both locations and try to
- // find a common "ancestor".
+ // find a common "ancestor". FileIDs build a tree-like structure that
+ // reflects the #include hierarchy, and this algorithm needs to find the
+ // nearest common ancestor between the two locations. For example, if you
+ // have a.c that includes b.h and c.h, and are comparing a location in b.h to
+ // a location in c.h, we need to find that their nearest common ancestor is
+ // a.c, and compare the locations of the two #includes to find their relative
+ // ordering.
//
- // First we traverse the stack of the right location and check each level
- // against the level of the left location, while collecting all levels in a
- // "stack map".
-
- std::map<FileID, unsigned> ROffsMap;
- ROffsMap[ROffs.first] = ROffs.second;
-
- while (1) {
- SourceLocation UpperLoc;
- const SrcMgr::SLocEntry &Entry = getSLocEntry(ROffs.first);
- if (Entry.isInstantiation())
- UpperLoc = Entry.getInstantiation().getInstantiationLocStart();
- else
- UpperLoc = Entry.getFile().getIncludeLoc();
-
- if (UpperLoc.isInvalid())
- break; // We reached the top.
-
- ROffs = getDecomposedLoc(UpperLoc);
-
- if (LOffs.first == ROffs.first)
- return LastResForBeforeTUCheck = LOffs.second < ROffs.second;
-
- ROffsMap[ROffs.first] = ROffs.second;
- }
-
- // We didn't find a common ancestor. Now traverse the stack of the left
- // location, checking against the stack map of the right location.
-
- while (1) {
- SourceLocation UpperLoc;
- const SrcMgr::SLocEntry &Entry = getSLocEntry(LOffs.first);
- if (Entry.isInstantiation())
- UpperLoc = Entry.getInstantiation().getInstantiationLocStart();
- else
- UpperLoc = Entry.getFile().getIncludeLoc();
-
- if (UpperLoc.isInvalid())
- break; // We reached the top.
-
- LOffs = getDecomposedLoc(UpperLoc);
+ // SourceManager assigns FileIDs in order of parsing. This means that an
+ // includee always has a larger FileID than an includer. While you might
+ // think that we could just compare the FileID's here, that doesn't work to
+ // compare a point at the end of a.c with a point within c.h. Though c.h has
+ // a larger FileID, we have to compare the include point of c.h to the
+ // location in a.c.
+ //
+ // Despite not being able to directly compare FileID's, we can tell that a
+ // larger FileID is necessarily more deeply nested than a lower one and use
+ // this information to walk up the tree to the nearest common ancestor.
+ do {
+ // If LOffs is larger than ROffs, then LOffs must be more deeply nested than
+ // ROffs, walk up the #include chain.
+ if (LOffs.first.ID > ROffs.first.ID) {
+ if (MoveUpIncludeHierarchy(LOffs, *this))
+ break; // We reached the top.
+
+ } else {
+ // Otherwise, ROffs is larger than LOffs, so ROffs must be more deeply
+ // nested than LOffs, walk up the #include chain.
+ if (MoveUpIncludeHierarchy(ROffs, *this))
+ break; // We reached the top.
+ }
+ } while (LOffs.first != ROffs.first);
- std::map<FileID, unsigned>::iterator I = ROffsMap.find(LOffs.first);
- if (I != ROffsMap.end())
- return LastResForBeforeTUCheck = LOffs.second < I->second;
+ // If we exited because we found a nearest common ancestor, compare the
+ // locations within the common file and cache them.
+ if (LOffs.first == ROffs.first) {
+ IsBeforeInTUCache.setCommonLoc(LOffs.first, LOffs.second, ROffs.second);
+ return IsBeforeInTUCache.getCachedResult(LOffs.second, ROffs.second);
}
// There is no common ancestor, most probably because one location is in the
- // predefines buffer.
- //
+ // predefines buffer or a PCH file.
// FIXME: We should rearrange the external interface so this simply never
// happens; it can't conceptually happen. Also see PR5662.
+ IsBeforeInTUCache.setQueryFIDs(FileID(), FileID()); // Don't try caching.
+ // Zip both entries up to the top level record.
+ while (!MoveUpIncludeHierarchy(LOffs, *this)) /*empty*/;
+ while (!MoveUpIncludeHierarchy(ROffs, *this)) /*empty*/;
+
// If exactly one location is a memory buffer, assume it preceeds the other.
- bool LIsMB = !getSLocEntry(LOffs.first).getFile().getContentCache()->Entry;
- bool RIsMB = !getSLocEntry(ROffs.first).getFile().getContentCache()->Entry;
+
+ // Strip off macro instantation locations, going up to the top-level File
+ // SLocEntry.
+ bool LIsMB = getFileEntryForID(LOffs.first) == 0;
+ bool RIsMB = getFileEntryForID(ROffs.first) == 0;
if (LIsMB != RIsMB)
- return LastResForBeforeTUCheck = LIsMB;
+ return LIsMB;
// Otherwise, just assume FileIDs were created in order.
- return LastResForBeforeTUCheck = (LOffs.first < ROffs.first);
+ return LOffs.first < ROffs.first;
}
/// PrintStats - Print statistics to stderr.
diff --git a/lib/Basic/TargetInfo.cpp b/lib/Basic/TargetInfo.cpp
index 4c0c59a109e7..6692e641f2a4 100644
--- a/lib/Basic/TargetInfo.cpp
+++ b/lib/Basic/TargetInfo.cpp
@@ -52,6 +52,7 @@ TargetInfo::TargetInfo(const std::string &T) : Triple(T) {
DescriptionString = "E-p:32:32:32-i1:8:8-i8:8:8-i16:16:16-i32:32:32-"
"i64:64:64-f32:32:32-f64:64:64-n32";
UserLabelPrefix = "_";
+ HasAlignMac68kSupport = false;
}
// Out of line virtual dtor for TargetInfo.
diff --git a/lib/Basic/Targets.cpp b/lib/Basic/Targets.cpp
index 3d5048ccb9bf..92fd417173bd 100644
--- a/lib/Basic/Targets.cpp
+++ b/lib/Basic/Targets.cpp
@@ -1138,6 +1138,7 @@ public:
DescriptionString = "e-p:32:32:32-i1:8:8-i8:8:8-i16:16:16-i32:32:32-"
"i64:32:64-f32:32:32-f64:32:64-v64:64:64-v128:128:128-"
"a0:0:64-f80:128:128-n8:16:32";
+ HasAlignMac68kSupport = true;
}
};
@@ -1669,7 +1670,9 @@ protected:
public:
DarwinARMTargetInfo(const std::string& triple)
- : DarwinTargetInfo<ARMTargetInfo>(triple) {}
+ : DarwinTargetInfo<ARMTargetInfo>(triple) {
+ HasAlignMac68kSupport = true;
+ }
};
} // end anonymous namespace.
diff --git a/lib/Basic/Version.cpp b/lib/Basic/Version.cpp
index dc87d148ed34..e0c23362b930 100644
--- a/lib/Basic/Version.cpp
+++ b/lib/Basic/Version.cpp
@@ -28,7 +28,8 @@ llvm::StringRef getClangRepositoryPath() {
if (End)
URLEnd = End;
- End = strstr(URL, "/clang/tools/clang");
+ // Strip off version from a build from an integration branch.
+ End = strstr(URL, "/src/tools/clang");
if (End)
URLEnd = End;
diff --git a/lib/Checker/BasicObjCFoundationChecks.cpp b/lib/Checker/BasicObjCFoundationChecks.cpp
index e7275ca551c2..b852e2ad9a48 100644
--- a/lib/Checker/BasicObjCFoundationChecks.cpp
+++ b/lib/Checker/BasicObjCFoundationChecks.cpp
@@ -521,11 +521,11 @@ void ClassReleaseChecker::PreVisitObjCMessageExpr(CheckerContext &C,
ObjCInterfaceDecl *Class = 0;
switch (ME->getReceiverKind()) {
case ObjCMessageExpr::Class:
- Class = ME->getClassReceiver()->getAs<ObjCInterfaceType>()->getDecl();
+ Class = ME->getClassReceiver()->getAs<ObjCObjectType>()->getInterface();
break;
case ObjCMessageExpr::SuperClass:
- Class = ME->getSuperType()->getAs<ObjCInterfaceType>()->getDecl();
+ Class = ME->getSuperType()->getAs<ObjCObjectType>()->getInterface();
break;
case ObjCMessageExpr::Instance:
diff --git a/lib/Checker/BasicStore.cpp b/lib/Checker/BasicStore.cpp
index 34470af29f4a..5be5ca615ed6 100644
--- a/lib/Checker/BasicStore.cpp
+++ b/lib/Checker/BasicStore.cpp
@@ -72,7 +72,7 @@ public:
/// RemoveDeadBindings - Scans a BasicStore of 'state' for dead values.
/// It updatees the GRState object in place with the values removed.
- Store RemoveDeadBindings(Store store, Stmt* Loc,
+ const GRState *RemoveDeadBindings(GRState &state, Stmt* Loc,
const StackFrameContext *LCtx,
SymbolReaper& SymReaper,
llvm::SmallVectorImpl<const MemRegion*>& RegionRoots);
@@ -251,11 +251,12 @@ Store BasicStoreManager::Remove(Store store, Loc loc) {
}
}
-Store BasicStoreManager::RemoveDeadBindings(Store store, Stmt* Loc,
+const GRState *BasicStoreManager::RemoveDeadBindings(GRState &state, Stmt* Loc,
const StackFrameContext *LCtx,
SymbolReaper& SymReaper,
llvm::SmallVectorImpl<const MemRegion*>& RegionRoots)
{
+ Store store = state.getStore();
BindingsTy B = GetBindings(store);
typedef SVal::symbol_iterator symbol_iterator;
@@ -329,7 +330,8 @@ Store BasicStoreManager::RemoveDeadBindings(Store store, Stmt* Loc,
}
}
- return store;
+ state.setStore(store);
+ return StateMgr.getPersistentState(state);
}
Store BasicStoreManager::scanForIvars(Stmt *B, const Decl* SelfDecl,
diff --git a/lib/Checker/CFRefCount.cpp b/lib/Checker/CFRefCount.cpp
index d26ee1db5653..42e6f67f0172 100644
--- a/lib/Checker/CFRefCount.cpp
+++ b/lib/Checker/CFRefCount.cpp
@@ -37,6 +37,49 @@ using namespace clang;
using llvm::StringRef;
using llvm::StrInStrNoCase;
+namespace {
+class InstanceReceiver {
+ const ObjCMessageExpr *ME;
+ const LocationContext *LC;
+public:
+ InstanceReceiver(const ObjCMessageExpr *me = 0,
+ const LocationContext *lc = 0) : ME(me), LC(lc) {}
+
+ bool isValid() const {
+ return ME && ME->isInstanceMessage();
+ }
+ operator bool() const {
+ return isValid();
+ }
+
+ SVal getSValAsScalarOrLoc(const GRState *state) {
+ assert(isValid());
+ // We have an expression for the receiver? Fetch the value
+ // of that expression.
+ if (const Expr *Ex = ME->getInstanceReceiver())
+ return state->getSValAsScalarOrLoc(Ex);
+
+ // Otherwise we are sending a message to super. In this case the
+ // object reference is the same as 'self'.
+ if (const ImplicitParamDecl *SelfDecl = LC->getSelfDecl())
+ return state->getSVal(state->getRegion(SelfDecl, LC));
+
+ return UnknownVal();
+ }
+
+ SourceRange getSourceRange() const {
+ assert(isValid());
+ if (const Expr *Ex = ME->getInstanceReceiver())
+ return Ex->getSourceRange();
+
+ // Otherwise we are sending a message to super.
+ SourceLocation L = ME->getSuperLoc();
+ assert(L.isValid());
+ return SourceRange(L, L);
+ }
+};
+}
+
static const ObjCMethodDecl*
ResolveToInterfaceMethodDecl(const ObjCMethodDecl *MD) {
ObjCInterfaceDecl *ID =
@@ -618,11 +661,11 @@ public:
break;
case ObjCMessageExpr::Class:
- OD = ME->getClassReceiver()->getAs<ObjCInterfaceType>()->getDecl();
+ OD = ME->getClassReceiver()->getAs<ObjCObjectType>()->getInterface();
break;
case ObjCMessageExpr::SuperClass:
- OD = ME->getSuperType()->getAs<ObjCInterfaceType>()->getDecl();
+ OD = ME->getSuperType()->getAs<ObjCObjectType>()->getInterface();
break;
}
@@ -1374,7 +1417,7 @@ RetainSummaryManager::getInstanceMethodSummary(const ObjCMessageExpr *ME,
// we just use the 'ID' from the message expression.
SVal receiverV;
- if (const Expr *Receiver = ME->getInstanceReceiver()) {
+ if (Receiver) {
receiverV = state->getSValAsScalarOrLoc(Receiver);
// FIXME: Eventually replace the use of state->get<RefBindings> with
@@ -1724,7 +1767,7 @@ private:
void ProcessNonLeakError(ExplodedNodeSet& Dst,
GRStmtNodeBuilder& Builder,
- Expr* NodeExpr, Expr* ErrorExpr,
+ Expr* NodeExpr, SourceRange ErrorRange,
ExplodedNode* Pred,
const GRState* St,
RefVal::Kind hasErr, SymbolRef Sym);
@@ -1768,7 +1811,7 @@ public:
GRExprEngine& Eng,
GRStmtNodeBuilder& Builder,
Expr* Ex,
- Expr* Receiver,
+ InstanceReceiver Receiver,
const RetainSummary& Summ,
const MemRegion *Callee,
ExprIterator arg_beg, ExprIterator arg_end,
@@ -2552,7 +2595,8 @@ static QualType GetReturnType(const Expr* RetE, ASTContext& Ctx) {
// is a call to a class method whose type we can resolve. In such
// cases, promote the return type to XXX* (where XXX is the class).
const ObjCInterfaceDecl *D = ME->getReceiverInterface();
- return !D ? RetTy : Ctx.getPointerType(Ctx.getObjCInterfaceType(D));
+ return !D ? RetTy :
+ Ctx.getObjCObjectPointerType(Ctx.getObjCInterfaceType(D));
}
return RetTy;
@@ -2562,7 +2606,7 @@ void CFRefCount::EvalSummary(ExplodedNodeSet& Dst,
GRExprEngine& Eng,
GRStmtNodeBuilder& Builder,
Expr* Ex,
- Expr* Receiver,
+ InstanceReceiver Receiver,
const RetainSummary& Summ,
const MemRegion *Callee,
ExprIterator arg_beg, ExprIterator arg_end,
@@ -2571,7 +2615,7 @@ void CFRefCount::EvalSummary(ExplodedNodeSet& Dst,
// Evaluate the effect of the arguments.
RefVal::Kind hasErr = (RefVal::Kind) 0;
unsigned idx = 0;
- Expr* ErrorExpr = NULL;
+ SourceRange ErrorRange;
SymbolRef ErrorSym = 0;
llvm::SmallVector<const MemRegion*, 10> RegionsToInvalidate;
@@ -2584,7 +2628,7 @@ void CFRefCount::EvalSummary(ExplodedNodeSet& Dst,
if (RefBindings::data_type* T = state->get<RefBindings>(Sym)) {
state = Update(state, Sym, *T, Summ.getArg(idx), hasErr);
if (hasErr) {
- ErrorExpr = *I;
+ ErrorRange = (*I)->getSourceRange();
ErrorSym = Sym;
break;
}
@@ -2677,13 +2721,13 @@ void CFRefCount::EvalSummary(ExplodedNodeSet& Dst,
}
// Evaluate the effect on the message receiver.
- if (!ErrorExpr && Receiver) {
- SymbolRef Sym = state->getSValAsScalarOrLoc(Receiver).getAsLocSymbol();
+ if (!ErrorRange.isValid() && Receiver) {
+ SymbolRef Sym = Receiver.getSValAsScalarOrLoc(state).getAsLocSymbol();
if (Sym) {
if (const RefVal* T = state->get<RefBindings>(Sym)) {
state = Update(state, Sym, *T, Summ.getReceiverEffect(), hasErr);
if (hasErr) {
- ErrorExpr = Receiver;
+ ErrorRange = Receiver.getSourceRange();
ErrorSym = Sym;
}
}
@@ -2692,7 +2736,7 @@ void CFRefCount::EvalSummary(ExplodedNodeSet& Dst,
// Process any errors.
if (hasErr) {
- ProcessNonLeakError(Dst, Builder, Ex, ErrorExpr, Pred, state,
+ ProcessNonLeakError(Dst, Builder, Ex, ErrorRange, Pred, state,
hasErr, ErrorSym);
return;
}
@@ -2703,7 +2747,7 @@ void CFRefCount::EvalSummary(ExplodedNodeSet& Dst,
if (RE.getKind() == RetEffect::OwnedWhenTrackedReceiver) {
bool found = false;
if (Receiver) {
- SVal V = state->getSValAsScalarOrLoc(Receiver);
+ SVal V = Receiver.getSValAsScalarOrLoc(state);
if (SymbolRef Sym = V.getAsLocSymbol())
if (state->get<RefBindings>(Sym)) {
found = true;
@@ -2759,8 +2803,8 @@ void CFRefCount::EvalSummary(ExplodedNodeSet& Dst,
}
case RetEffect::ReceiverAlias: {
- assert (Receiver);
- SVal V = state->getSValAsScalarOrLoc(Receiver);
+ assert(Receiver);
+ SVal V = Receiver.getSValAsScalarOrLoc(state);
state = state->BindExpr(Ex, V, false);
break;
}
@@ -2848,7 +2892,8 @@ void CFRefCount::EvalObjCMessageExpr(ExplodedNodeSet& Dst,
: Summaries.getClassMethodSummary(ME);
assert(Summ && "RetainSummary is null");
- EvalSummary(Dst, Eng, Builder, ME, ME->getInstanceReceiver(), *Summ, NULL,
+ EvalSummary(Dst, Eng, Builder, ME,
+ InstanceReceiver(ME, Pred->getLocationContext()), *Summ, NULL,
ME->arg_begin(), ME->arg_end(), Pred, state);
}
@@ -3408,7 +3453,7 @@ void CFRefCount::EvalDeadSymbols(ExplodedNodeSet& Dst,
void CFRefCount::ProcessNonLeakError(ExplodedNodeSet& Dst,
GRStmtNodeBuilder& Builder,
- Expr* NodeExpr, Expr* ErrorExpr,
+ Expr* NodeExpr, SourceRange ErrorRange,
ExplodedNode* Pred,
const GRState* St,
RefVal::Kind hasErr, SymbolRef Sym) {
@@ -3439,7 +3484,7 @@ void CFRefCount::ProcessNonLeakError(ExplodedNodeSet& Dst,
}
CFRefReport *report = new CFRefReport(*BT, *this, N, Sym);
- report->addRange(ErrorExpr->getSourceRange());
+ report->addRange(ErrorRange);
BR->EmitReport(report);
}
diff --git a/lib/Checker/CMakeLists.txt b/lib/Checker/CMakeLists.txt
index 82e93a425e6e..9c6adc6bf2ee 100644
--- a/lib/Checker/CMakeLists.txt
+++ b/lib/Checker/CMakeLists.txt
@@ -14,6 +14,7 @@ add_clang_library(clangChecker
BuiltinFunctionChecker.cpp
CallAndMessageChecker.cpp
CallInliner.cpp
+ CastSizeChecker.cpp
CastToStructChecker.cpp
CFRefCount.cpp
CheckDeadStores.cpp
@@ -69,3 +70,5 @@ add_clang_library(clangChecker
ValueManager.cpp
VLASizeChecker.cpp
)
+
+add_dependencies(clangChecker ClangStmtNodes)
diff --git a/lib/Checker/CastSizeChecker.cpp b/lib/Checker/CastSizeChecker.cpp
new file mode 100644
index 000000000000..754d775a65d1
--- /dev/null
+++ b/lib/Checker/CastSizeChecker.cpp
@@ -0,0 +1,82 @@
+//=== CastSizeChecker.cpp ---------------------------------------*- C++ -*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+//
+// CastSizeChecker checks when casting a malloc'ed symbolic region to type T,
+// whether the size of the symbolic region is a multiple of the size of T.
+//
+//===----------------------------------------------------------------------===//
+#include "clang/AST/CharUnits.h"
+#include "clang/Checker/BugReporter/BugType.h"
+#include "clang/Checker/PathSensitive/CheckerVisitor.h"
+#include "GRExprEngineInternalChecks.h"
+
+using namespace clang;
+
+namespace {
+class CastSizeChecker : public CheckerVisitor<CastSizeChecker> {
+ BuiltinBug *BT;
+public:
+ CastSizeChecker() : BT(0) {}
+ static void *getTag();
+ void PreVisitCastExpr(CheckerContext &C, const CastExpr *B);
+};
+}
+
+void *CastSizeChecker::getTag() {
+ static int x;
+ return &x;
+}
+
+void CastSizeChecker::PreVisitCastExpr(CheckerContext &C, const CastExpr *CE) {
+ const Expr *E = CE->getSubExpr();
+ ASTContext &Ctx = C.getASTContext();
+ QualType ToTy = Ctx.getCanonicalType(CE->getType());
+ PointerType *ToPTy = dyn_cast<PointerType>(ToTy.getTypePtr());
+
+ if (!ToPTy)
+ return;
+
+ QualType ToPointeeTy = ToPTy->getPointeeType();
+
+ const MemRegion *R = C.getState()->getSVal(E).getAsRegion();
+ if (R == 0)
+ return;
+
+ const SymbolicRegion *SR = dyn_cast<SymbolicRegion>(R);
+ if (SR == 0)
+ return;
+
+ llvm::Optional<SVal> V =
+ C.getEngine().getStoreManager().getExtent(C.getState(), SR);
+ if (!V)
+ return;
+
+ const nonloc::ConcreteInt *CI = dyn_cast<nonloc::ConcreteInt>(V);
+ if (!CI)
+ return;
+
+ CharUnits RegionSize = CharUnits::fromQuantity(CI->getValue().getSExtValue());
+ CharUnits TypeSize = C.getASTContext().getTypeSizeInChars(ToPointeeTy);
+ if (RegionSize % TypeSize != 0) {
+ if (ExplodedNode *N = C.GenerateSink()) {
+ if (!BT)
+ BT = new BuiltinBug("Cast region with wrong size.",
+ "Cast a region whose size is not a multiple of the"
+ " destination type size.");
+ RangedBugReport *R = new RangedBugReport(*BT, BT->getDescription(), N);
+ R->addRange(CE->getSourceRange());
+ C.EmitReport(R);
+ }
+ }
+}
+
+
+void clang::RegisterCastSizeChecker(GRExprEngine &Eng) {
+ Eng.registerCheck(new CastSizeChecker());
+}
diff --git a/lib/Checker/CheckObjCDealloc.cpp b/lib/Checker/CheckObjCDealloc.cpp
index c23be873f481..11ddaca9d6fc 100644
--- a/lib/Checker/CheckObjCDealloc.cpp
+++ b/lib/Checker/CheckObjCDealloc.cpp
@@ -115,7 +115,8 @@ void clang::CheckObjCDealloc(const ObjCImplementationDecl* D,
QualType T = ID->getType();
if (!T->isObjCObjectPointerType() ||
- ID->getAttr<IBOutletAttr>()) // Skip IBOutlets.
+ ID->getAttr<IBOutletAttr>() || // Skip IBOutlets.
+ ID->getAttr<IBOutletCollectionAttr>()) // Skip IBOutletCollections.
continue;
containsPointerIvar = true;
diff --git a/lib/Checker/FlatStore.cpp b/lib/Checker/FlatStore.cpp
index 2af9ffa4a4d9..7f1c579c6edb 100644
--- a/lib/Checker/FlatStore.cpp
+++ b/lib/Checker/FlatStore.cpp
@@ -44,11 +44,11 @@ public:
}
SVal ArrayToPointer(Loc Array);
- Store RemoveDeadBindings(Store store, Stmt* Loc,
+ const GRState *RemoveDeadBindings(GRState &state, Stmt* Loc,
const StackFrameContext *LCtx,
SymbolReaper& SymReaper,
llvm::SmallVectorImpl<const MemRegion*>& RegionRoots){
- return store;
+ return StateMgr.getPersistentState(state);
}
Store BindDecl(Store store, const VarRegion *VR, SVal initVal);
diff --git a/lib/Checker/GRCXXExprEngine.cpp b/lib/Checker/GRCXXExprEngine.cpp
index 00ac99559282..18e112cc8d36 100644
--- a/lib/Checker/GRCXXExprEngine.cpp
+++ b/lib/Checker/GRCXXExprEngine.cpp
@@ -86,7 +86,7 @@ void GRExprEngine::VisitCXXConstructExpr(const CXXConstructExpr *E, SVal Dest,
const CXXConstructorDecl *CD = E->getConstructor();
assert(CD);
- if (!CD->isThisDeclarationADefinition())
+ if (!(CD->isThisDeclarationADefinition() && AMgr.shouldInlineCall()))
// FIXME: invalidate the object.
return;
@@ -147,7 +147,7 @@ void GRExprEngine::VisitCXXMemberCallExpr(const CXXMemberCallExpr *MCE,
const CXXMethodDecl *MD = cast<CXXMethodDecl>(ME->getMemberDecl());
assert(MD && "not a CXXMethodDecl?");
- if (!MD->isThisDeclarationADefinition())
+ if (!(MD->isThisDeclarationADefinition() && AMgr.shouldInlineCall()))
// FIXME: conservative method call evaluation.
return;
diff --git a/lib/Checker/GRExprEngine.cpp b/lib/Checker/GRExprEngine.cpp
index 67090b86694f..24176586728c 100644
--- a/lib/Checker/GRExprEngine.cpp
+++ b/lib/Checker/GRExprEngine.cpp
@@ -1017,9 +1017,8 @@ void GRExprEngine::VisitLValue(Expr* Ex, ExplodedNode* Pred,
bool GRExprEngine::ProcessBlockEntrance(CFGBlock* B, const ExplodedNode *Pred,
GRBlockCounter BC) {
-
return BC.getNumVisited(Pred->getLocationContext()->getCurrentStackFrame(),
- B->getBlockID()) < 3;
+ B->getBlockID()) < AMgr.getMaxLoop();
}
//===----------------------------------------------------------------------===//
@@ -1810,6 +1809,28 @@ void GRExprEngine::EvalLocation(ExplodedNodeSet &Dst, Stmt *S,
}
}
+bool GRExprEngine::InlineCall(ExplodedNodeSet &Dst, const CallExpr *CE,
+ ExplodedNode *Pred) {
+ const GRState *state = GetState(Pred);
+ const Expr *Callee = CE->getCallee();
+ SVal L = state->getSVal(Callee);
+
+ const FunctionDecl *FD = L.getAsFunctionDecl();
+ if (!FD)
+ return false;
+
+ if (!FD->getBody(FD))
+ return false;
+
+ // Now we have the definition of the callee, create a CallEnter node.
+ CallEnter Loc(CE, FD, Pred->getLocationContext());
+
+ ExplodedNode *N = Builder->generateNode(Loc, state, Pred);
+ if (N)
+ Dst.Add(N);
+ return true;
+}
+
void GRExprEngine::VisitCall(CallExpr* CE, ExplodedNode* Pred,
CallExpr::arg_iterator AI,
CallExpr::arg_iterator AE,
@@ -1889,6 +1910,10 @@ void GRExprEngine::VisitCall(CallExpr* CE, ExplodedNode* Pred,
// If the callee is processed by a checker, skip the rest logic.
if (CheckerEvalCall(CE, DstChecker, *DI))
DstTmp3.insert(DstChecker);
+ else if (AMgr.shouldInlineCall() && InlineCall(Dst, CE, *DI)) {
+ // Callee is inlined. We shouldn't do post call checking.
+ return;
+ }
else {
for (ExplodedNodeSet::iterator DI_Checker = DstChecker.begin(),
DE_Checker = DstChecker.end();
@@ -1944,7 +1969,7 @@ void GRExprEngine::VisitCall(CallExpr* CE, ExplodedNode* Pred,
//===----------------------------------------------------------------------===//
static std::pair<const void*,const void*> EagerlyAssumeTag
- = std::pair<const void*,const void*>(&EagerlyAssumeTag,0);
+ = std::pair<const void*,const void*>(&EagerlyAssumeTag,static_cast<void*>(0));
void GRExprEngine::EvalEagerlyAssume(ExplodedNodeSet &Dst, ExplodedNodeSet &Src,
Expr *Ex) {
@@ -2595,8 +2620,8 @@ void GRExprEngine::VisitSizeOfAlignOfExpr(SizeOfAlignOfExpr* Ex,
Dst.Add(Pred);
return;
}
- else if (T->isObjCInterfaceType()) {
- // Some code tries to take the sizeof an ObjCInterfaceType, relying that
+ else if (T->getAs<ObjCObjectType>()) {
+ // Some code tries to take the sizeof an ObjCObjectType, relying that
// the compiler has laid out its representation. Just report Unknown
// for these.
Dst.Add(Pred);
diff --git a/lib/Checker/GRExprEngineExperimentalChecks.cpp b/lib/Checker/GRExprEngineExperimentalChecks.cpp
index 89b4e4b6392f..6066a1c74d33 100644
--- a/lib/Checker/GRExprEngineExperimentalChecks.cpp
+++ b/lib/Checker/GRExprEngineExperimentalChecks.cpp
@@ -36,5 +36,6 @@ void clang::RegisterExperimentalInternalChecks(GRExprEngine &Eng) {
RegisterPointerSubChecker(Eng);
RegisterPointerArithChecker(Eng);
RegisterCastToStructChecker(Eng);
+ RegisterCastSizeChecker(Eng);
RegisterArrayBoundChecker(Eng);
}
diff --git a/lib/Checker/GRExprEngineInternalChecks.h b/lib/Checker/GRExprEngineInternalChecks.h
index d1176001cac7..335b85e308e0 100644
--- a/lib/Checker/GRExprEngineInternalChecks.h
+++ b/lib/Checker/GRExprEngineInternalChecks.h
@@ -26,6 +26,7 @@ void RegisterAttrNonNullChecker(GRExprEngine &Eng);
void RegisterBuiltinFunctionChecker(GRExprEngine &Eng);
void RegisterCallAndMessageChecker(GRExprEngine &Eng);
void RegisterCastToStructChecker(GRExprEngine &Eng);
+void RegisterCastSizeChecker(GRExprEngine &Eng);
void RegisterDereferenceChecker(GRExprEngine &Eng);
void RegisterDivZeroChecker(GRExprEngine &Eng);
void RegisterFixedAddressChecker(GRExprEngine &Eng);
diff --git a/lib/Checker/GRState.cpp b/lib/Checker/GRState.cpp
index f68e10b0cbc9..b16e922776e5 100644
--- a/lib/Checker/GRState.cpp
+++ b/lib/Checker/GRState.cpp
@@ -51,11 +51,10 @@ GRStateManager::RemoveDeadBindings(const GRState* state, Stmt* Loc,
state, RegionRoots);
// Clean up the store.
- NewState.St = StoreMgr->RemoveDeadBindings(NewState.St, Loc, LCtx, SymReaper,
- RegionRoots);
+ const GRState *s = StoreMgr->RemoveDeadBindings(NewState, Loc, LCtx,
+ SymReaper, RegionRoots);
- return ConstraintMgr->RemoveDeadBindings(getPersistentState(NewState),
- SymReaper);
+ return ConstraintMgr->RemoveDeadBindings(s, SymReaper);
}
const GRState *GRState::unbindLoc(Loc LV) const {
diff --git a/lib/Checker/LLVMConventionsChecker.cpp b/lib/Checker/LLVMConventionsChecker.cpp
index 14f0fc1280df..39ded431279c 100644
--- a/lib/Checker/LLVMConventionsChecker.cpp
+++ b/lib/Checker/LLVMConventionsChecker.cpp
@@ -47,7 +47,7 @@ static bool InStdNamespace(const Decl *D) {
}
static bool IsStdString(QualType T) {
- if (const QualifiedNameType *QT = T->getAs<QualifiedNameType>())
+ if (const ElaboratedType *QT = T->getAs<ElaboratedType>())
T = QT->getNamedType();
const TypedefType *TT = T->getAs<TypedefType>();
diff --git a/lib/Checker/MallocChecker.cpp b/lib/Checker/MallocChecker.cpp
index a22df3046920..086dbd8fdd36 100644
--- a/lib/Checker/MallocChecker.cpp
+++ b/lib/Checker/MallocChecker.cpp
@@ -182,7 +182,10 @@ const GRState *MallocChecker::FreeMemAux(CheckerContext &C, const CallExpr *CE,
return state;
SymbolRef Sym = ArgVal.getAsLocSymbol();
- assert(Sym);
+
+ // Various cases could lead to non-symbol values here.
+ if (!Sym)
+ return state;
const RefState *RS = state->get<RegionState>(Sym);
diff --git a/lib/Checker/MemRegion.cpp b/lib/Checker/MemRegion.cpp
index 9a664c78a77c..575458c9dc79 100644
--- a/lib/Checker/MemRegion.cpp
+++ b/lib/Checker/MemRegion.cpp
@@ -539,7 +539,7 @@ MemRegionManager::getElementRegion(QualType elementType, SVal Idx,
const MemRegion* superRegion,
ASTContext& Ctx){
- QualType T = Ctx.getCanonicalType(elementType);
+ QualType T = Ctx.getCanonicalType(elementType).getUnqualifiedType();
llvm::FoldingSetNodeID ID;
ElementRegion::ProfileRegion(ID, T, Idx, superRegion);
diff --git a/lib/Checker/ObjCUnusedIVarsChecker.cpp b/lib/Checker/ObjCUnusedIVarsChecker.cpp
index 0e47621d4205..2523cff9d8d0 100644
--- a/lib/Checker/ObjCUnusedIVarsChecker.cpp
+++ b/lib/Checker/ObjCUnusedIVarsChecker.cpp
@@ -114,7 +114,8 @@ void clang::CheckObjCUnusedIvar(const ObjCImplementationDecl *D,
// (b) explicitly marked unused
// (c) are iboutlets
if (ID->getAccessControl() != ObjCIvarDecl::Private ||
- ID->getAttr<UnusedAttr>() || ID->getAttr<IBOutletAttr>())
+ ID->getAttr<UnusedAttr>() || ID->getAttr<IBOutletAttr>() ||
+ ID->getAttr<IBOutletCollectionAttr>())
continue;
M[ID] = Unused;
diff --git a/lib/Checker/RegionStore.cpp b/lib/Checker/RegionStore.cpp
index 1e15d43a5ac2..c4072fd80307 100644
--- a/lib/Checker/RegionStore.cpp
+++ b/lib/Checker/RegionStore.cpp
@@ -352,9 +352,9 @@ public: // Part of public interface to class.
/// RemoveDeadBindings - Scans the RegionStore of 'state' for dead values.
/// It returns a new Store with these values removed.
- Store RemoveDeadBindings(Store store, Stmt* Loc,
- const StackFrameContext *LCtx,
- SymbolReaper& SymReaper,
+ const GRState *RemoveDeadBindings(GRState &state, Stmt* Loc,
+ const StackFrameContext *LCtx,
+ SymbolReaper& SymReaper,
llvm::SmallVectorImpl<const MemRegion*>& RegionRoots);
const GRState *EnterStackFrame(const GRState *state,
@@ -364,7 +364,18 @@ public: // Part of public interface to class.
// Region "extents".
//===------------------------------------------------------------------===//
- const GRState *setExtent(const GRState *state,const MemRegion* R,SVal Extent);
+ const GRState *setExtent(const GRState *state,const MemRegion* R,SVal Extent){
+ return state->set<RegionExtents>(R, Extent);
+ }
+
+ Optional<SVal> getExtent(const GRState *state, const MemRegion *R) {
+ const SVal *V = state->get<RegionExtents>(R);
+ if (V)
+ return *V;
+ else
+ return Optional<SVal>();
+ }
+
DefinedOrUnknownSVal getSizeInElements(const GRState *state,
const MemRegion* R, QualType EleTy);
@@ -798,12 +809,6 @@ DefinedOrUnknownSVal RegionStoreManager::getSizeInElements(const GRState *state,
return UnknownVal();
}
-const GRState *RegionStoreManager::setExtent(const GRState *state,
- const MemRegion *region,
- SVal extent) {
- return state->set<RegionExtents>(region, extent);
-}
-
//===----------------------------------------------------------------------===//
// Location and region casting.
//===----------------------------------------------------------------------===//
@@ -1817,12 +1822,12 @@ bool RemoveDeadBindingsWorker::UpdatePostponed() {
return changed;
}
-Store RegionStoreManager::RemoveDeadBindings(Store store, Stmt* Loc,
+const GRState *RegionStoreManager::RemoveDeadBindings(GRState &state, Stmt* Loc,
const StackFrameContext *LCtx,
SymbolReaper& SymReaper,
llvm::SmallVectorImpl<const MemRegion*>& RegionRoots)
{
- RegionBindings B = GetRegionBindings(store);
+ RegionBindings B = GetRegionBindings(state.getStore());
RemoveDeadBindingsWorker W(*this, StateMgr, B, SymReaper, Loc, LCtx);
W.GenerateClusters();
@@ -1855,8 +1860,16 @@ Store RegionStoreManager::RemoveDeadBindings(Store store, Stmt* Loc,
for (; SI != SE; ++SI)
SymReaper.maybeDead(*SI);
}
-
- return B.getRoot();
+ state.setStore(B.getRoot());
+ const GRState *s = StateMgr.getPersistentState(state);
+ // Remove the extents of dead symbolic regions.
+ llvm::ImmutableMap<const MemRegion*,SVal> Extents = s->get<RegionExtents>();
+ for (llvm::ImmutableMap<const MemRegion *, SVal>::iterator I=Extents.begin(),
+ E = Extents.end(); I != E; ++I) {
+ if (!W.isVisited(I->first))
+ s = s->remove<RegionExtents>(I->first);
+ }
+ return s;
}
diff --git a/lib/CodeGen/CGBlocks.cpp b/lib/CodeGen/CGBlocks.cpp
index 8082b33fd66d..de58597e298d 100644
--- a/lib/CodeGen/CGBlocks.cpp
+++ b/lib/CodeGen/CGBlocks.cpp
@@ -24,6 +24,45 @@
using namespace clang;
using namespace CodeGen;
+/// CGBlockInfo - Information to generate a block literal.
+class clang::CodeGen::CGBlockInfo {
+public:
+ /// Name - The name of the block, kindof.
+ const char *Name;
+
+ /// DeclRefs - Variables from parent scopes that have been
+ /// imported into this block.
+ llvm::SmallVector<const BlockDeclRefExpr *, 8> DeclRefs;
+
+ /// InnerBlocks - This block and the blocks it encloses.
+ llvm::SmallPtrSet<const DeclContext *, 4> InnerBlocks;
+
+ /// CXXThisRef - Non-null if 'this' was required somewhere, in
+ /// which case this is that expression.
+ const CXXThisExpr *CXXThisRef;
+
+ /// NeedsObjCSelf - True if something in this block has an implicit
+ /// reference to 'self'.
+ bool NeedsObjCSelf;
+
+ /// These are initialized by GenerateBlockFunction.
+ bool BlockHasCopyDispose;
+ CharUnits BlockSize;
+ CharUnits BlockAlign;
+ llvm::SmallVector<const Expr*, 8> BlockLayout;
+
+ CGBlockInfo(const char *Name);
+};
+
+CGBlockInfo::CGBlockInfo(const char *N)
+ : Name(N), CXXThisRef(0), NeedsObjCSelf(false) {
+
+ // Skip asm prefix, if any.
+ if (Name && Name[0] == '\01')
+ ++Name;
+}
+
+
llvm::Constant *CodeGenFunction::
BuildDescriptorBlockDecl(const BlockExpr *BE, bool BlockHasCopyDispose, CharUnits Size,
const llvm::StructType* Ty,
@@ -86,58 +125,86 @@ llvm::Constant *BlockModule::getNSConcreteStackBlock() {
return NSConcreteStackBlock;
}
-static void CollectBlockDeclRefInfo(
- const Stmt *S, CodeGenFunction::BlockInfo &Info,
- llvm::SmallSet<const DeclContext *, 16> &InnerContexts) {
+static void CollectBlockDeclRefInfo(const Stmt *S, CGBlockInfo &Info) {
for (Stmt::const_child_iterator I = S->child_begin(), E = S->child_end();
I != E; ++I)
if (*I)
- CollectBlockDeclRefInfo(*I, Info, InnerContexts);
+ CollectBlockDeclRefInfo(*I, Info);
// We want to ensure we walk down into block literals so we can find
// all nested BlockDeclRefExprs.
if (const BlockExpr *BE = dyn_cast<BlockExpr>(S)) {
- InnerContexts.insert(cast<DeclContext>(BE->getBlockDecl()));
- CollectBlockDeclRefInfo(BE->getBody(), Info, InnerContexts);
+ Info.InnerBlocks.insert(BE->getBlockDecl());
+ CollectBlockDeclRefInfo(BE->getBody(), Info);
}
- if (const BlockDeclRefExpr *BDRE = dyn_cast<BlockDeclRefExpr>(S)) {
+ else if (const BlockDeclRefExpr *BDRE = dyn_cast<BlockDeclRefExpr>(S)) {
+ const ValueDecl *D = BDRE->getDecl();
// FIXME: Handle enums.
- if (isa<FunctionDecl>(BDRE->getDecl()))
+ if (isa<FunctionDecl>(D))
return;
+ if (isa<ImplicitParamDecl>(D) &&
+ isa<ObjCMethodDecl>(D->getDeclContext()) &&
+ cast<ObjCMethodDecl>(D->getDeclContext())->getSelfDecl() == D) {
+ Info.NeedsObjCSelf = true;
+ return;
+ }
+
// Only Decls that escape are added.
- if (!InnerContexts.count(BDRE->getDecl()->getDeclContext()))
+ if (!Info.InnerBlocks.count(D->getDeclContext()))
Info.DeclRefs.push_back(BDRE);
}
+
+ // Make sure to capture implicit 'self' references due to super calls.
+ else if (const ObjCMessageExpr *E = dyn_cast<ObjCMessageExpr>(S)) {
+ if (E->getReceiverKind() == ObjCMessageExpr::SuperClass ||
+ E->getReceiverKind() == ObjCMessageExpr::SuperInstance)
+ Info.NeedsObjCSelf = true;
+ }
+
+ // Getter/setter uses may also cause implicit super references,
+ // which we can check for with:
+ else if (isa<ObjCSuperExpr>(S))
+ Info.NeedsObjCSelf = true;
+
+ else if (isa<CXXThisExpr>(S))
+ Info.CXXThisRef = cast<CXXThisExpr>(S);
}
-/// CanBlockBeGlobal - Given a BlockInfo struct, determines if a block can be
+/// CanBlockBeGlobal - Given a CGBlockInfo struct, determines if a block can be
/// declared as a global variable instead of on the stack.
-static bool CanBlockBeGlobal(const CodeGenFunction::BlockInfo &Info) {
+static bool CanBlockBeGlobal(const CGBlockInfo &Info) {
return Info.DeclRefs.empty();
}
/// AllocateAllBlockDeclRefs - Preallocate all nested BlockDeclRefExprs to
/// ensure we can generate the debug information for the parameter for the block
/// invoke function.
-static void AllocateAllBlockDeclRefs(const CodeGenFunction::BlockInfo &Info,
- CodeGenFunction *CGF) {
- // FIXME: Also always forward the this pointer in C++ as well.
+static void AllocateAllBlockDeclRefs(CodeGenFunction &CGF, CGBlockInfo &Info) {
+ if (Info.CXXThisRef)
+ CGF.AllocateBlockCXXThisPointer(Info.CXXThisRef);
for (size_t i = 0; i < Info.DeclRefs.size(); ++i)
- CGF->AllocateBlockDecl(Info.DeclRefs[i]);
+ CGF.AllocateBlockDecl(Info.DeclRefs[i]);
+
+ if (Info.NeedsObjCSelf) {
+ ValueDecl *Self = cast<ObjCMethodDecl>(CGF.CurFuncDecl)->getSelfDecl();
+ BlockDeclRefExpr *BDRE =
+ new (CGF.getContext()) BlockDeclRefExpr(Self, Self->getType(),
+ SourceLocation(), false);
+ Info.DeclRefs.push_back(BDRE);
+ CGF.AllocateBlockDecl(BDRE);
+ }
}
// FIXME: Push most into CGM, passing down a few bits, like current function
// name.
llvm::Value *CodeGenFunction::BuildBlockLiteralTmp(const BlockExpr *BE) {
-
std::string Name = CurFn->getName();
- CodeGenFunction::BlockInfo Info(0, Name.c_str());
- llvm::SmallSet<const DeclContext *, 16> InnerContexts;
- InnerContexts.insert(BE->getBlockDecl());
- CollectBlockDeclRefInfo(BE->getBody(), Info, InnerContexts);
+ CGBlockInfo Info(Name.c_str());
+ Info.InnerBlocks.insert(BE->getBlockDecl());
+ CollectBlockDeclRefInfo(BE->getBody(), Info);
// Check if the block can be global.
// FIXME: This test doesn't work for nested blocks yet. Longer term, I'd like
@@ -160,23 +227,15 @@ llvm::Value *CodeGenFunction::BuildBlockLiteralTmp(const BlockExpr *BE) {
// We run this first so that we set BlockHasCopyDispose from the entire
// block literal.
// __invoke
- CharUnits subBlockSize;
- CharUnits subBlockAlign;
- llvm::SmallVector<const Expr *, 8> subBlockDeclRefDecls;
- bool subBlockHasCopyDispose = false;
llvm::Function *Fn
= CodeGenFunction(CGM).GenerateBlockFunction(BE, Info, CurFuncDecl,
- LocalDeclMap,
- subBlockSize,
- subBlockAlign,
- subBlockDeclRefDecls,
- subBlockHasCopyDispose);
- BlockHasCopyDispose |= subBlockHasCopyDispose;
+ LocalDeclMap);
+ BlockHasCopyDispose |= Info.BlockHasCopyDispose;
Elts[3] = Fn;
// FIXME: Don't use BlockHasCopyDispose, it is set more often then
// necessary, for example: { ^{ __block int i; ^{ i = 1; }(); }(); }
- if (subBlockHasCopyDispose)
+ if (Info.BlockHasCopyDispose)
flags |= BLOCK_HAS_COPY_DISPOSE;
// __isa
@@ -206,10 +265,10 @@ llvm::Value *CodeGenFunction::BuildBlockLiteralTmp(const BlockExpr *BE) {
C = llvm::ConstantInt::get(IntTy, 0);
Elts[2] = C;
- if (subBlockDeclRefDecls.size() == 0) {
+ if (Info.BlockLayout.empty()) {
// __descriptor
- Elts[4] = BuildDescriptorBlockDecl(BE, subBlockHasCopyDispose, subBlockSize,
- 0, 0);
+ Elts[4] = BuildDescriptorBlockDecl(BE, Info.BlockHasCopyDispose,
+ Info.BlockSize, 0, 0);
// Optimize to being a global block.
Elts[0] = CGM.getNSConcreteGlobalBlock();
@@ -227,13 +286,13 @@ llvm::Value *CodeGenFunction::BuildBlockLiteralTmp(const BlockExpr *BE) {
return C;
}
- std::vector<const llvm::Type *> Types(BlockFields+subBlockDeclRefDecls.size());
+ std::vector<const llvm::Type *> Types(BlockFields+Info.BlockLayout.size());
for (int i=0; i<4; ++i)
Types[i] = Elts[i]->getType();
Types[4] = PtrToInt8Ty;
- for (unsigned i=0; i < subBlockDeclRefDecls.size(); ++i) {
- const Expr *E = subBlockDeclRefDecls[i];
+ for (unsigned i = 0, n = Info.BlockLayout.size(); i != n; ++i) {
+ const Expr *E = Info.BlockLayout[i];
const BlockDeclRefExpr *BDRE = dyn_cast<BlockDeclRefExpr>(E);
QualType Ty = E->getType();
if (BDRE && BDRE->isByRef()) {
@@ -245,105 +304,113 @@ llvm::Value *CodeGenFunction::BuildBlockLiteralTmp(const BlockExpr *BE) {
llvm::StructType *Ty = llvm::StructType::get(VMContext, Types, true);
llvm::AllocaInst *A = CreateTempAlloca(Ty);
- A->setAlignment(subBlockAlign.getQuantity());
+ A->setAlignment(Info.BlockAlign.getQuantity());
V = A;
- std::vector<HelperInfo> NoteForHelper(subBlockDeclRefDecls.size());
- int helpersize = 0;
+ // Build layout / cleanup information for all the data entries in the
+ // layout, and write the enclosing fields into the type.
+ std::vector<HelperInfo> NoteForHelper(Info.BlockLayout.size());
+ unsigned NumHelpers = 0;
for (unsigned i=0; i<4; ++i)
Builder.CreateStore(Elts[i], Builder.CreateStructGEP(V, i, "block.tmp"));
- for (unsigned i=0; i < subBlockDeclRefDecls.size(); ++i)
- {
- // FIXME: Push const down.
- Expr *E = const_cast<Expr*>(subBlockDeclRefDecls[i]);
- DeclRefExpr *DR;
- ValueDecl *VD;
-
- DR = dyn_cast<DeclRefExpr>(E);
- // Skip padding.
- if (DR) continue;
-
- BlockDeclRefExpr *BDRE = dyn_cast<BlockDeclRefExpr>(E);
- VD = BDRE->getDecl();
-
- llvm::Value* Addr = Builder.CreateStructGEP(V, i+BlockFields, "tmp");
- NoteForHelper[helpersize].index = i+5;
- NoteForHelper[helpersize].RequiresCopying
- = BlockRequiresCopying(VD->getType());
- NoteForHelper[helpersize].flag
- = (VD->getType()->isBlockPointerType()
- ? BLOCK_FIELD_IS_BLOCK
- : BLOCK_FIELD_IS_OBJECT);
-
- if (LocalDeclMap[VD]) {
- if (BDRE->isByRef()) {
- NoteForHelper[helpersize].flag = BLOCK_FIELD_IS_BYREF |
- // FIXME: Someone double check this.
- (VD->getType().isObjCGCWeak() ? BLOCK_FIELD_IS_WEAK : 0);
- llvm::Value *Loc = LocalDeclMap[VD];
- Loc = Builder.CreateStructGEP(Loc, 1, "forwarding");
- Loc = Builder.CreateLoad(Loc);
- Builder.CreateStore(Loc, Addr);
- ++helpersize;
- continue;
- } else
- E = new (getContext()) DeclRefExpr (VD,
- VD->getType(),
- SourceLocation());
- }
+ for (unsigned i=0; i < Info.BlockLayout.size(); ++i) {
+ const Expr *E = Info.BlockLayout[i];
+
+ // Skip padding.
+ if (isa<DeclRefExpr>(E)) continue;
+
+ llvm::Value* Addr = Builder.CreateStructGEP(V, i+BlockFields, "tmp");
+ HelperInfo &Note = NoteForHelper[NumHelpers++];
+
+ Note.index = i+5;
+
+ if (isa<CXXThisExpr>(E)) {
+ Note.RequiresCopying = false;
+ Note.flag = BLOCK_FIELD_IS_OBJECT;
+
+ Builder.CreateStore(LoadCXXThis(), Addr);
+ continue;
+ }
+
+ const BlockDeclRefExpr *BDRE = cast<BlockDeclRefExpr>(E);
+ const ValueDecl *VD = BDRE->getDecl();
+ QualType T = VD->getType();
+
+ Note.RequiresCopying = BlockRequiresCopying(T);
+
+ if (BDRE->isByRef()) {
+ Note.flag = BLOCK_FIELD_IS_BYREF;
+ if (T.isObjCGCWeak())
+ Note.flag |= BLOCK_FIELD_IS_WEAK;
+ } else if (T->isBlockPointerType()) {
+ Note.flag = BLOCK_FIELD_IS_BLOCK;
+ } else {
+ Note.flag = BLOCK_FIELD_IS_OBJECT;
+ }
+
+ if (LocalDeclMap[VD]) {
if (BDRE->isByRef()) {
- NoteForHelper[helpersize].flag = BLOCK_FIELD_IS_BYREF |
- // FIXME: Someone double check this.
- (VD->getType().isObjCGCWeak() ? BLOCK_FIELD_IS_WEAK : 0);
- E = new (getContext())
- UnaryOperator(E, UnaryOperator::AddrOf,
- getContext().getPointerType(E->getType()),
- SourceLocation());
- }
- ++helpersize;
-
- RValue r = EmitAnyExpr(E, Addr, false);
- if (r.isScalar()) {
- llvm::Value *Loc = r.getScalarVal();
- const llvm::Type *Ty = Types[i+BlockFields];
- if (BDRE->isByRef()) {
- // E is now the address of the value field, instead, we want the
- // address of the actual ByRef struct. We optimize this slightly
- // compared to gcc by not grabbing the forwarding slot as this must
- // be done during Block_copy for us, and we can postpone the work
- // until then.
- CharUnits offset = BlockDecls[BDRE->getDecl()];
-
- llvm::Value *BlockLiteral = LoadBlockStruct();
-
- Loc = Builder.CreateGEP(BlockLiteral,
- llvm::ConstantInt::get(llvm::Type::getInt64Ty(VMContext),
- offset.getQuantity()),
- "block.literal");
- Ty = llvm::PointerType::get(Ty, 0);
- Loc = Builder.CreateBitCast(Loc, Ty);
- Loc = Builder.CreateLoad(Loc);
- // Loc = Builder.CreateBitCast(Loc, Ty);
- }
+ llvm::Value *Loc = LocalDeclMap[VD];
+ Loc = Builder.CreateStructGEP(Loc, 1, "forwarding");
+ Loc = Builder.CreateLoad(Loc);
Builder.CreateStore(Loc, Addr);
- } else if (r.isComplex())
- // FIXME: implement
- ErrorUnsupported(BE, "complex in block literal");
- else if (r.isAggregate())
- ; // Already created into the destination
- else
- assert (0 && "bad block variable");
- // FIXME: Ensure that the offset created by the backend for
- // the struct matches the previously computed offset in BlockDecls.
+ continue;
+ } else {
+ E = new (getContext()) DeclRefExpr(const_cast<ValueDecl*>(VD),
+ VD->getType(),
+ SourceLocation());
+ }
}
- NoteForHelper.resize(helpersize);
+
+ if (BDRE->isByRef()) {
+ E = new (getContext())
+ UnaryOperator(const_cast<Expr*>(E), UnaryOperator::AddrOf,
+ getContext().getPointerType(E->getType()),
+ SourceLocation());
+ }
+
+ RValue r = EmitAnyExpr(E, Addr, false);
+ if (r.isScalar()) {
+ llvm::Value *Loc = r.getScalarVal();
+ const llvm::Type *Ty = Types[i+BlockFields];
+ if (BDRE->isByRef()) {
+ // E is now the address of the value field, instead, we want the
+ // address of the actual ByRef struct. We optimize this slightly
+ // compared to gcc by not grabbing the forwarding slot as this must
+ // be done during Block_copy for us, and we can postpone the work
+ // until then.
+ CharUnits offset = BlockDecls[BDRE->getDecl()];
+
+ llvm::Value *BlockLiteral = LoadBlockStruct();
+
+ Loc = Builder.CreateGEP(BlockLiteral,
+ llvm::ConstantInt::get(llvm::Type::getInt64Ty(VMContext),
+ offset.getQuantity()),
+ "block.literal");
+ Ty = llvm::PointerType::get(Ty, 0);
+ Loc = Builder.CreateBitCast(Loc, Ty);
+ Loc = Builder.CreateLoad(Loc);
+ // Loc = Builder.CreateBitCast(Loc, Ty);
+ }
+ Builder.CreateStore(Loc, Addr);
+ } else if (r.isComplex())
+ // FIXME: implement
+ ErrorUnsupported(BE, "complex in block literal");
+ else if (r.isAggregate())
+ ; // Already created into the destination
+ else
+ assert (0 && "bad block variable");
+ // FIXME: Ensure that the offset created by the backend for
+ // the struct matches the previously computed offset in BlockDecls.
+ }
+ NoteForHelper.resize(NumHelpers);
// __descriptor
llvm::Value *Descriptor = BuildDescriptorBlockDecl(BE,
- subBlockHasCopyDispose,
- subBlockSize, Ty,
+ Info.BlockHasCopyDispose,
+ Info.BlockSize, Ty,
&NoteForHelper);
Descriptor = Builder.CreateBitCast(Descriptor, PtrToInt8Ty);
Builder.CreateStore(Descriptor, Builder.CreateStructGEP(V, 4, "block.tmp"));
@@ -487,13 +554,25 @@ RValue CodeGenFunction::EmitBlockCallExpr(const CallExpr* E,
return EmitCall(FnInfo, Func, ReturnValue, Args);
}
-CharUnits CodeGenFunction::AllocateBlockDecl(const BlockDeclRefExpr *E) {
+void CodeGenFunction::AllocateBlockCXXThisPointer(const CXXThisExpr *E) {
+ assert(BlockCXXThisOffset.isZero() && "already computed 'this' pointer");
+
+ // Figure out what the offset is.
+ QualType T = E->getType();
+ std::pair<CharUnits,CharUnits> TypeInfo = getContext().getTypeInfoInChars(T);
+ CharUnits Offset = getBlockOffset(TypeInfo.first, TypeInfo.second);
+
+ BlockCXXThisOffset = Offset;
+ BlockLayout.push_back(E);
+}
+
+void CodeGenFunction::AllocateBlockDecl(const BlockDeclRefExpr *E) {
const ValueDecl *VD = E->getDecl();
- CharUnits &offset = BlockDecls[VD];
+ CharUnits &Offset = BlockDecls[VD];
// See if we have already allocated an offset for this variable.
- if (offset.isPositive())
- return offset;
+ if (!Offset.isZero())
+ return;
// Don't run the expensive check, unless we have to.
if (!BlockHasCopyDispose)
@@ -501,23 +580,34 @@ CharUnits CodeGenFunction::AllocateBlockDecl(const BlockDeclRefExpr *E) {
|| BlockRequiresCopying(E->getType()))
BlockHasCopyDispose = true;
- // if not, allocate one now.
- offset = getBlockOffset(E);
+ const ValueDecl *D = cast<ValueDecl>(E->getDecl());
- return offset;
+ CharUnits Size;
+ CharUnits Align;
+
+ if (E->isByRef()) {
+ llvm::tie(Size,Align) =
+ getContext().getTypeInfoInChars(getContext().VoidPtrTy);
+ } else {
+ Size = getContext().getTypeSizeInChars(D->getType());
+ Align = getContext().getDeclAlign(D);
+ }
+
+ Offset = getBlockOffset(Size, Align);
+ BlockLayout.push_back(E);
}
-llvm::Value *CodeGenFunction::GetAddrOfBlockDecl(const BlockDeclRefExpr *E) {
- const ValueDecl *VD = E->getDecl();
- CharUnits offset = AllocateBlockDecl(E);
-
+llvm::Value *CodeGenFunction::GetAddrOfBlockDecl(const ValueDecl *VD,
+ bool IsByRef) {
+ CharUnits offset = BlockDecls[VD];
+ assert(!offset.isZero() && "getting address of unallocated decl");
llvm::Value *BlockLiteral = LoadBlockStruct();
llvm::Value *V = Builder.CreateGEP(BlockLiteral,
llvm::ConstantInt::get(llvm::Type::getInt64Ty(VMContext),
offset.getQuantity()),
"block.literal");
- if (E->isByRef()) {
+ if (IsByRef) {
const llvm::Type *PtrStructTy
= llvm::PointerType::get(BuildByRefType(VD), 0);
// The block literal will need a copy/destroy helper.
@@ -543,19 +633,6 @@ llvm::Value *CodeGenFunction::GetAddrOfBlockDecl(const BlockDeclRefExpr *E) {
return V;
}
-void CodeGenFunction::BlockForwardSelf() {
- const ObjCMethodDecl *OMD = cast<ObjCMethodDecl>(CurFuncDecl);
- ImplicitParamDecl *SelfDecl = OMD->getSelfDecl();
- llvm::Value *&DMEntry = LocalDeclMap[SelfDecl];
- if (DMEntry)
- return;
- // FIXME - Eliminate BlockDeclRefExprs, clients don't need/want to care
- BlockDeclRefExpr *BDRE = new (getContext())
- BlockDeclRefExpr(SelfDecl,
- SelfDecl->getType(), SourceLocation(), false);
- DMEntry = GetAddrOfBlockDecl(BDRE);
-}
-
llvm::Constant *
BlockModule::GetAddrOfGlobalBlock(const BlockExpr *BE, const char * n) {
// Generate the block descriptor.
@@ -600,19 +677,11 @@ BlockModule::GetAddrOfGlobalBlock(const BlockExpr *BE, const char * n) {
std::vector<llvm::Constant*> LiteralFields(FieldCount);
- CodeGenFunction::BlockInfo Info(0, n);
- CharUnits subBlockSize;
- CharUnits subBlockAlign;
- llvm::SmallVector<const Expr *, 8> subBlockDeclRefDecls;
- bool subBlockHasCopyDispose = false;
+ CGBlockInfo Info(n);
llvm::DenseMap<const Decl*, llvm::Value*> LocalDeclMap;
llvm::Function *Fn
- = CodeGenFunction(CGM).GenerateBlockFunction(BE, Info, 0, LocalDeclMap,
- subBlockSize,
- subBlockAlign,
- subBlockDeclRefDecls,
- subBlockHasCopyDispose);
- assert(subBlockSize == BlockLiteralSize
+ = CodeGenFunction(CGM).GenerateBlockFunction(BE, Info, 0, LocalDeclMap);
+ assert(Info.BlockSize == BlockLiteralSize
&& "no imports allowed for global block");
// isa
@@ -651,13 +720,9 @@ llvm::Value *CodeGenFunction::LoadBlockStruct() {
llvm::Function *
CodeGenFunction::GenerateBlockFunction(const BlockExpr *BExpr,
- const BlockInfo& Info,
+ CGBlockInfo &Info,
const Decl *OuterFuncDecl,
- llvm::DenseMap<const Decl*, llvm::Value*> ldm,
- CharUnits &Size,
- CharUnits &Align,
- llvm::SmallVector<const Expr *, 8> &subBlockDeclRefDecls,
- bool &subBlockHasCopyDispose) {
+ llvm::DenseMap<const Decl*, llvm::Value*> ldm) {
// Check if we should generate debug info for this block.
if (CGM.getDebugInfo())
@@ -701,11 +766,12 @@ CodeGenFunction::GenerateBlockFunction(const BlockExpr *BExpr,
IdentifierInfo *II = &CGM.getContext().Idents.get(".block_descriptor");
- // Allocate all BlockDeclRefDecls, so we can calculate the right ParmTy below.
- AllocateAllBlockDeclRefs(Info, this);
+ // Build the block struct now.
+ AllocateAllBlockDeclRefs(*this, Info);
QualType ParmTy = getContext().getBlockParmType(BlockHasCopyDispose,
- BlockDeclRefDecls);
+ BlockLayout);
+
// FIXME: This leaks
ImplicitParamDecl *SelfDecl =
ImplicitParamDecl::Create(getContext(), const_cast<BlockDecl*>(BD),
@@ -725,10 +791,11 @@ CodeGenFunction::GenerateBlockFunction(const BlockExpr *BExpr,
CodeGenTypes &Types = CGM.getTypes();
const llvm::FunctionType *LTy = Types.GetFunctionType(FI, IsVariadic);
+ MangleBuffer Name;
+ CGM.getMangledName(Name, BD);
llvm::Function *Fn =
- llvm::Function::Create(LTy, llvm::GlobalValue::InternalLinkage,
- llvm::Twine("__") + Info.Name + "_block_invoke_",
- &CGM.getModule());
+ llvm::Function::Create(LTy, llvm::GlobalValue::InternalLinkage,
+ Name.getString(), &CGM.getModule());
CGM.SetInternalFunctionAttributes(BD, Fn, FI);
@@ -738,6 +805,34 @@ CodeGenFunction::GenerateBlockFunction(const BlockExpr *BExpr,
CurFuncDecl = OuterFuncDecl;
CurCodeDecl = BD;
+ // If we have a C++ 'this' reference, go ahead and force it into
+ // existence now.
+ if (Info.CXXThisRef) {
+ assert(!BlockCXXThisOffset.isZero() &&
+ "haven't yet allocated 'this' reference");
+
+ // TODO: I have a dream that one day this will be typed.
+ llvm::Value *BlockLiteral = LoadBlockStruct();
+ llvm::Value *ThisPtrRaw =
+ Builder.CreateConstInBoundsGEP1_64(BlockLiteral,
+ BlockCXXThisOffset.getQuantity(),
+ "this.ptr.raw");
+
+ const llvm::Type *Ty =
+ CGM.getTypes().ConvertType(Info.CXXThisRef->getType());
+ Ty = llvm::PointerType::get(Ty, 0);
+ llvm::Value *ThisPtr = Builder.CreateBitCast(ThisPtrRaw, Ty, "this.ptr");
+
+ CXXThisValue = Builder.CreateLoad(ThisPtr, "this");
+ }
+
+ // If we have an Objective C 'self' reference, go ahead and force it
+ // into existence now.
+ if (Info.NeedsObjCSelf) {
+ ValueDecl *Self = cast<ObjCMethodDecl>(CurFuncDecl)->getSelfDecl();
+ LocalDeclMap[Self] = GetAddrOfBlockDecl(Self, false);
+ }
+
// Save a spot to insert the debug information for all the BlockDeclRefDecls.
llvm::BasicBlock *entry = Builder.GetInsertBlock();
llvm::BasicBlock::iterator entry_ptr = Builder.GetInsertPoint();
@@ -754,9 +849,10 @@ CodeGenFunction::GenerateBlockFunction(const BlockExpr *BExpr,
if (CGDebugInfo *DI = getDebugInfo()) {
// Emit debug information for all the BlockDeclRefDecls.
- for (unsigned i = 0, e = BlockDeclRefDecls.size(); i != e; ++i) {
- if (const BlockDeclRefExpr *BDRE =
- dyn_cast<BlockDeclRefExpr>(BlockDeclRefDecls[i])) {
+ // FIXME: also for 'this'
+ for (unsigned i = 0, e = BlockLayout.size(); i != e; ++i) {
+ if (const BlockDeclRefExpr *BDRE =
+ dyn_cast<BlockDeclRefExpr>(BlockLayout[i])) {
const ValueDecl *D = BDRE->getDecl();
DI->setLocation(D->getLocation());
DI->EmitDeclareOfBlockDeclRefVariable(BDRE,
@@ -779,25 +875,15 @@ CodeGenFunction::GenerateBlockFunction(const BlockExpr *BExpr,
llvm::RoundUpToAlignment(BlockOffset.getQuantity(),
MinAlign.getQuantity()));
- Size = BlockOffset;
- Align = BlockAlign;
- subBlockDeclRefDecls = BlockDeclRefDecls;
- subBlockHasCopyDispose |= BlockHasCopyDispose;
+ Info.BlockSize = BlockOffset;
+ Info.BlockAlign = BlockAlign;
+ Info.BlockLayout = BlockLayout;
+ Info.BlockHasCopyDispose = BlockHasCopyDispose;
return Fn;
}
-CharUnits BlockFunction::getBlockOffset(const BlockDeclRefExpr *BDRE) {
- const ValueDecl *D = dyn_cast<ValueDecl>(BDRE->getDecl());
-
- CharUnits Size = getContext().getTypeSizeInChars(D->getType());
- CharUnits Align = getContext().getDeclAlign(D);
-
- if (BDRE->isByRef()) {
- Size = getContext().getTypeSizeInChars(getContext().VoidPtrTy);
- Align = getContext().getTypeAlignInChars(getContext().VoidPtrTy);
- }
-
- assert ((Align.isPositive()) && "alignment must be 1 byte or more");
+CharUnits BlockFunction::getBlockOffset(CharUnits Size, CharUnits Align) {
+ assert((Align.isPositive()) && "alignment must be 1 byte or more");
CharUnits OldOffset = BlockOffset;
@@ -808,23 +894,22 @@ CharUnits BlockFunction::getBlockOffset(const BlockDeclRefExpr *BDRE) {
CharUnits Pad = BlockOffset - OldOffset;
if (Pad.isPositive()) {
- llvm::ArrayType::get(llvm::Type::getInt8Ty(VMContext), Pad.getQuantity());
QualType PadTy = getContext().getConstantArrayType(getContext().CharTy,
llvm::APInt(32,
Pad.getQuantity()),
ArrayType::Normal, 0);
- ValueDecl *PadDecl = VarDecl::Create(getContext(), 0, SourceLocation(),
+ ValueDecl *PadDecl = VarDecl::Create(getContext(),
+ getContext().getTranslationUnitDecl(),
+ SourceLocation(),
0, QualType(PadTy), 0,
VarDecl::None, VarDecl::None);
- Expr *E;
- E = new (getContext()) DeclRefExpr(PadDecl, PadDecl->getType(),
- SourceLocation());
- BlockDeclRefDecls.push_back(E);
+ Expr *E = new (getContext()) DeclRefExpr(PadDecl, PadDecl->getType(),
+ SourceLocation());
+ BlockLayout.push_back(E);
}
- BlockDeclRefDecls.push_back(BDRE);
BlockOffset += Size;
- return BlockOffset-Size;
+ return BlockOffset - Size;
}
llvm::Constant *BlockFunction::
diff --git a/lib/CodeGen/CGBlocks.h b/lib/CodeGen/CGBlocks.h
index 5646d0036e90..e9b2bd549af5 100644
--- a/lib/CodeGen/CGBlocks.h
+++ b/lib/CodeGen/CGBlocks.h
@@ -148,26 +148,6 @@ public:
BLOCK_BYREF_CURRENT_MAX = 256
};
- /// BlockInfo - Information to generate a block literal.
- struct BlockInfo {
- /// BlockLiteralTy - The type of the block literal.
- const llvm::Type *BlockLiteralTy;
-
- /// Name - the name of the function this block was created for, if any.
- const char *Name;
-
- /// ByCopyDeclRefs - Variables from parent scopes that have been imported
- /// into this block.
- llvm::SmallVector<const BlockDeclRefExpr *, 8> DeclRefs;
-
- BlockInfo(const llvm::Type *blt, const char *n)
- : BlockLiteralTy(blt), Name(n) {
- // Skip asm prefix, if any.
- if (Name && Name[0] == '\01')
- ++Name;
- }
- };
-
CGBuilderTy &Builder;
BlockFunction(CodeGenModule &cgm, CodeGenFunction &cgf, CGBuilderTy &B);
@@ -179,19 +159,31 @@ public:
/// characters.
CharUnits BlockAlign;
- /// getBlockOffset - Allocate an offset for the ValueDecl from a
- /// BlockDeclRefExpr in a block literal (BlockExpr).
- CharUnits getBlockOffset(const BlockDeclRefExpr *E);
+ /// getBlockOffset - Allocate a location within the block's storage
+ /// for a value with the given size and alignment requirements.
+ CharUnits getBlockOffset(CharUnits Size, CharUnits Align);
/// BlockHasCopyDispose - True iff the block uses copy/dispose.
bool BlockHasCopyDispose;
- /// BlockDeclRefDecls - Decls from BlockDeclRefExprs in apperance order
- /// in a block literal. Decls without names are used for padding.
- llvm::SmallVector<const Expr *, 8> BlockDeclRefDecls;
+ /// BlockLayout - The layout of the block's storage, represented as
+ /// a sequence of expressions which require such storage. The
+ /// expressions can be:
+ /// - a BlockDeclRefExpr, indicating that the given declaration
+ /// from an enclosing scope is needed by the block;
+ /// - a DeclRefExpr, which always wraps an anonymous VarDecl with
+ /// array type, used to insert padding into the block; or
+ /// - a CXXThisExpr, indicating that the C++ 'this' value should
+ /// propagate from the parent to the block.
+ /// This is a really silly representation.
+ llvm::SmallVector<const Expr *, 8> BlockLayout;
/// BlockDecls - Offsets for all Decls in BlockDeclRefExprs.
- std::map<const Decl*, CharUnits> BlockDecls;
+ llvm::DenseMap<const Decl*, CharUnits> BlockDecls;
+
+ /// BlockCXXThisOffset - The offset of the C++ 'this' value within
+ /// the block structure.
+ CharUnits BlockCXXThisOffset;
ImplicitParamDecl *BlockStructDecl;
ImplicitParamDecl *getBlockStructDecl() { return BlockStructDecl; }
diff --git a/lib/CodeGen/CGBuiltin.cpp b/lib/CodeGen/CGBuiltin.cpp
index 95c41db86e09..dd505c2ae88f 100644
--- a/lib/CodeGen/CGBuiltin.cpp
+++ b/lib/CodeGen/CGBuiltin.cpp
@@ -71,7 +71,7 @@ static RValue EmitBinaryAtomic(CodeGenFunction &CGF,
/// Utility to insert an atomic instruction based Instrinsic::ID and
// the expression node, where the return value is the result of the
// operation.
-static RValue EmitBinaryAtomicPost(CodeGenFunction& CGF,
+static RValue EmitBinaryAtomicPost(CodeGenFunction &CGF,
Intrinsic::ID Id, const CallExpr *E,
Instruction::BinaryOps Op) {
const llvm::Type *ResType[2];
@@ -88,6 +88,30 @@ static llvm::ConstantInt *getInt32(llvm::LLVMContext &Context, int32_t Value) {
return llvm::ConstantInt::get(llvm::Type::getInt32Ty(Context), Value);
}
+
+/// EmitFAbs - Emit a call to fabs/fabsf/fabsl, depending on the type of ValTy,
+/// which must be a scalar floating point type.
+static Value *EmitFAbs(CodeGenFunction &CGF, Value *V, QualType ValTy) {
+ const BuiltinType *ValTyP = ValTy->getAs<BuiltinType>();
+ assert(ValTyP && "isn't scalar fp type!");
+
+ StringRef FnName;
+ switch (ValTyP->getKind()) {
+ default: assert(0 && "Isn't a scalar fp type!");
+ case BuiltinType::Float: FnName = "fabsf"; break;
+ case BuiltinType::Double: FnName = "fabs"; break;
+ case BuiltinType::LongDouble: FnName = "fabsl"; break;
+ }
+
+ // The prototype is something that takes and returns whatever V's type is.
+ std::vector<const llvm::Type*> Args;
+ Args.push_back(V->getType());
+ llvm::FunctionType *FT = llvm::FunctionType::get(V->getType(), Args, false);
+ llvm::Value *Fn = CGF.CGM.CreateRuntimeFunction(FT, FnName);
+
+ return CGF.Builder.CreateCall(Fn, V, "abs");
+}
+
RValue CodeGenFunction::EmitBuiltinExpr(const FunctionDecl *FD,
unsigned BuiltinID, const CallExpr *E) {
// See if we can constant fold this builtin. If so, don't emit it at all.
@@ -328,6 +352,50 @@ RValue CodeGenFunction::EmitBuiltinExpr(const FunctionDecl *FD,
V = Builder.CreateFCmpUNO(V, V, "cmp");
return RValue::get(Builder.CreateZExt(V, ConvertType(E->getType()), "tmp"));
}
+
+ case Builtin::BI__builtin_isinf: {
+ // isinf(x) --> fabs(x) == infinity
+ Value *V = EmitScalarExpr(E->getArg(0));
+ V = EmitFAbs(*this, V, E->getArg(0)->getType());
+
+ V = Builder.CreateFCmpOEQ(V, ConstantFP::getInfinity(V->getType()),"isinf");
+ return RValue::get(Builder.CreateZExt(V, ConvertType(E->getType()), "tmp"));
+ }
+
+ // TODO: BI__builtin_isinf_sign
+ // isinf_sign(x) -> isinf(x) ? (signbit(x) ? -1 : 1) : 0
+
+ case Builtin::BI__builtin_isnormal: {
+ // isnormal(x) --> x == x && fabsf(x) < infinity && fabsf(x) >= float_min
+ Value *V = EmitScalarExpr(E->getArg(0));
+ Value *Eq = Builder.CreateFCmpOEQ(V, V, "iseq");
+
+ Value *Abs = EmitFAbs(*this, V, E->getArg(0)->getType());
+ Value *IsLessThanInf =
+ Builder.CreateFCmpULT(Abs, ConstantFP::getInfinity(V->getType()),"isinf");
+ APFloat Smallest = APFloat::getSmallestNormalized(
+ getContext().getFloatTypeSemantics(E->getArg(0)->getType()));
+ Value *IsNormal =
+ Builder.CreateFCmpUGE(Abs, ConstantFP::get(V->getContext(), Smallest),
+ "isnormal");
+ V = Builder.CreateAnd(Eq, IsLessThanInf, "and");
+ V = Builder.CreateAnd(V, IsNormal, "and");
+ return RValue::get(Builder.CreateZExt(V, ConvertType(E->getType())));
+ }
+
+ case Builtin::BI__builtin_isfinite: {
+ // isfinite(x) --> x == x && fabs(x) != infinity; }
+ Value *V = EmitScalarExpr(E->getArg(0));
+ Value *Eq = Builder.CreateFCmpOEQ(V, V, "iseq");
+
+ Value *Abs = EmitFAbs(*this, V, E->getArg(0)->getType());
+ Value *IsNotInf =
+ Builder.CreateFCmpUNE(Abs, ConstantFP::getInfinity(V->getType()),"isinf");
+
+ V = Builder.CreateAnd(Eq, IsNotInf, "and");
+ return RValue::get(Builder.CreateZExt(V, ConvertType(E->getType())));
+ }
+
case Builtin::BIalloca:
case Builtin::BI__builtin_alloca: {
// FIXME: LLVM IR Should allow alloca with an i64 size!
diff --git a/lib/CodeGen/CGCXX.cpp b/lib/CodeGen/CGCXX.cpp
index 74cf1134d5b7..525877903e7a 100644
--- a/lib/CodeGen/CGCXX.cpp
+++ b/lib/CodeGen/CGCXX.cpp
@@ -13,6 +13,7 @@
// We might split this into multiple files if it gets too unwieldy
+#include "CGCXXABI.h"
#include "CodeGenFunction.h"
#include "CodeGenModule.h"
#include "Mangle.h"
@@ -206,6 +207,7 @@ void CodeGenModule::EmitCXXConstructor(const CXXConstructorDecl *D,
return;
llvm::Function *Fn = cast<llvm::Function>(GetAddrOfCXXConstructor(D, Type));
+ setFunctionLinkage(D, Fn);
CodeGenFunction(*this).GenerateCode(GlobalDecl(D, Type), Fn);
@@ -229,6 +231,10 @@ CodeGenModule::GetAddrOfCXXConstructor(const CXXConstructorDecl *D,
GetOrCreateLLVMFunction(Name, FTy, GlobalDecl(D, Type)));
}
+void CodeGenModule::getMangledName(MangleBuffer &Buffer, const BlockDecl *BD) {
+ getMangleContext().mangleBlock(BD, Buffer.getBuffer());
+}
+
void CodeGenModule::getMangledCXXCtorName(MangleBuffer &Name,
const CXXConstructorDecl *D,
CXXCtorType Type) {
@@ -269,6 +275,7 @@ void CodeGenModule::EmitCXXDestructor(const CXXDestructorDecl *D,
return;
llvm::Function *Fn = cast<llvm::Function>(GetAddrOfCXXDestructor(D, Type));
+ setFunctionLinkage(D, Fn);
CodeGenFunction(*this).GenerateCode(GlobalDecl(D, Type), Fn);
@@ -327,3 +334,5 @@ CodeGenFunction::BuildVirtualCall(const CXXDestructorDecl *DD, CXXDtorType Type,
return ::BuildVirtualCall(*this, VTableIndex, This, Ty);
}
+
+CXXABI::~CXXABI() {}
diff --git a/lib/CodeGen/CGCXXABI.h b/lib/CodeGen/CGCXXABI.h
new file mode 100644
index 000000000000..a7e18714e8b3
--- /dev/null
+++ b/lib/CodeGen/CGCXXABI.h
@@ -0,0 +1,37 @@
+//===----- CGCXXABI.h - Interface to C++ ABIs -------------------*- C++ -*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+//
+// This provides an abstract class for C++ code generation. Concrete subclasses
+// of this implement code generation for specific C++ ABIs.
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef CLANG_CODEGEN_CXXABI_H
+#define CLANG_CODEGEN_CXXABI_H
+
+namespace clang {
+namespace CodeGen {
+ class CodeGenModule;
+ class MangleContext;
+
+/// Implements C++ ABI-specific code generation functions.
+class CXXABI {
+public:
+ virtual ~CXXABI();
+
+ /// Gets the mangle context.
+ virtual MangleContext &getMangleContext() = 0;
+};
+
+/// Creates an instance of a C++ ABI class.
+CXXABI *CreateItaniumCXXABI(CodeGenModule &CGM);
+}
+}
+
+#endif
diff --git a/lib/CodeGen/CGCall.cpp b/lib/CodeGen/CGCall.cpp
index 92d15d9d8c97..73cee3c10d2e 100644
--- a/lib/CodeGen/CGCall.cpp
+++ b/lib/CodeGen/CGCall.cpp
@@ -38,6 +38,7 @@ static unsigned ClangCallConvToLLVMCallConv(CallingConv CC) {
default: return llvm::CallingConv::C;
case CC_X86StdCall: return llvm::CallingConv::X86_StdCall;
case CC_X86FastCall: return llvm::CallingConv::X86_FastCall;
+ case CC_X86ThisCall: return llvm::CallingConv::X86_ThisCall;
}
}
@@ -97,6 +98,9 @@ static CallingConv getCallingConventionForDecl(const Decl *D) {
if (D->hasAttr<FastCallAttr>())
return CC_X86FastCall;
+ if (D->hasAttr<ThisCallAttr>())
+ return CC_X86ThisCall;
+
return CC_C;
}
@@ -858,6 +862,36 @@ void CodeGenFunction::EmitFunctionEpilog(const CGFunctionInfo &FI,
}
}
+RValue CodeGenFunction::EmitDelegateCallArg(const VarDecl *Param) {
+ // StartFunction converted the ABI-lowered parameter(s) into a
+ // local alloca. We need to turn that into an r-value suitable
+ // for EmitCall.
+ llvm::Value *Local = GetAddrOfLocalVar(Param);
+
+ QualType ArgType = Param->getType();
+
+ // For the most part, we just need to load the alloca, except:
+ // 1) aggregate r-values are actually pointers to temporaries, and
+ // 2) references to aggregates are pointers directly to the aggregate.
+ // I don't know why references to non-aggregates are different here.
+ if (const ReferenceType *RefType = ArgType->getAs<ReferenceType>()) {
+ if (hasAggregateLLVMType(RefType->getPointeeType()))
+ return RValue::getAggregate(Local);
+
+ // Locals which are references to scalars are represented
+ // with allocas holding the pointer.
+ return RValue::get(Builder.CreateLoad(Local));
+ }
+
+ if (ArgType->isAnyComplexType())
+ return RValue::getComplex(LoadComplexFromAddr(Local, /*volatile*/ false));
+
+ if (hasAggregateLLVMType(ArgType))
+ return RValue::getAggregate(Local);
+
+ return RValue::get(EmitLoadOfScalar(Local, false, ArgType));
+}
+
RValue CodeGenFunction::EmitCallArg(const Expr *E, QualType ArgType) {
if (ArgType->isReferenceType())
return EmitReferenceBindingToExpr(E);
diff --git a/lib/CodeGen/CGClass.cpp b/lib/CodeGen/CGClass.cpp
index a604eef49a13..bebea549f965 100644
--- a/lib/CodeGen/CGClass.cpp
+++ b/lib/CodeGen/CGClass.cpp
@@ -262,102 +262,7 @@ CodeGenFunction::GetAddressOfDerivedClass(llvm::Value *Value,
return Value;
}
-
-/// EmitCopyCtorCall - Emit a call to a copy constructor.
-static void
-EmitCopyCtorCall(CodeGenFunction &CGF, const CXXConstructorDecl *CopyCtor,
- llvm::Value *ThisPtr, llvm::Value *Src) {
- llvm::Value *Callee = CGF.CGM.GetAddrOfCXXConstructor(CopyCtor, Ctor_Complete);
-
- CallArgList CallArgs;
-
- // Push the this ptr.
- CallArgs.push_back(std::make_pair(RValue::get(ThisPtr),
- CopyCtor->getThisType(CGF.getContext())));
-
- // Push the 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.
-// FIXME. Consolidate this with EmitCXXAggrConstructorCall.
-void CodeGenFunction::EmitClassAggrMemberwiseCopy(llvm::Value *Dest,
- llvm::Value *Src,
- const ConstantArrayType *Array,
- const CXXRecordDecl *ClassDecl) {
- // Create a temporary for the loop index and initialize it with 0.
- llvm::Value *IndexPtr = CreateTempAlloca(llvm::Type::getInt64Ty(VMContext),
- "loop.index");
- llvm::Value* zeroConstant =
- llvm::Constant::getNullValue(llvm::Type::getInt64Ty(VMContext));
- Builder.CreateStore(zeroConstant, IndexPtr);
- // Start the loop with a block that tests the condition.
- llvm::BasicBlock *CondBlock = createBasicBlock("for.cond");
- llvm::BasicBlock *AfterFor = createBasicBlock("for.end");
-
- EmitBlock(CondBlock);
-
- llvm::BasicBlock *ForBody = createBasicBlock("for.body");
- // Generate: if (loop-index < number-of-elements fall to the loop body,
- // otherwise, go to the block after the for-loop.
- uint64_t NumElements = getContext().getConstantArrayElementCount(Array);
- llvm::Value * NumElementsPtr =
- llvm::ConstantInt::get(llvm::Type::getInt64Ty(VMContext), NumElements);
- llvm::Value *Counter = Builder.CreateLoad(IndexPtr);
- llvm::Value *IsLess = Builder.CreateICmpULT(Counter, NumElementsPtr,
- "isless");
- // If the condition is true, execute the body.
- Builder.CreateCondBr(IsLess, ForBody, AfterFor);
-
- EmitBlock(ForBody);
- llvm::BasicBlock *ContinueBlock = createBasicBlock("for.inc");
- // Inside the loop body, emit the constructor call on the array element.
- Counter = Builder.CreateLoad(IndexPtr);
- Src = Builder.CreateInBoundsGEP(Src, Counter, "srcaddress");
- Dest = Builder.CreateInBoundsGEP(Dest, Counter, "destaddress");
- EmitClassMemberwiseCopy(Dest, Src, ClassDecl);
-
- EmitBlock(ContinueBlock);
-
- // Emit the increment of the loop counter.
- llvm::Value *NextVal = llvm::ConstantInt::get(Counter->getType(), 1);
- Counter = Builder.CreateLoad(IndexPtr);
- NextVal = Builder.CreateAdd(Counter, NextVal, "inc");
- Builder.CreateStore(NextVal, IndexPtr);
-
- // Finally, branch back up to the condition for the next iteration.
- EmitBranch(CondBlock);
-
- // Emit the fall-through block.
- EmitBlock(AfterFor, true);
-}
-
/// 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,
@@ -405,111 +310,6 @@ static llvm::Value *GetVTTParameter(CodeGenFunction &CGF, GlobalDecl GD,
return VTT;
}
-
-/// EmitClassMemberwiseCopy - This routine generates code to copy a class
-/// object from SrcValue to DestValue. Copying can be either a bitwise copy
-/// or via a copy constructor call.
-void CodeGenFunction::EmitClassMemberwiseCopy(
- llvm::Value *Dest, llvm::Value *Src,
- const CXXRecordDecl *ClassDecl) {
- if (ClassDecl->hasTrivialCopyConstructor()) {
- EmitAggregateCopy(Dest, Src, getContext().getTagDeclType(ClassDecl));
- return;
- }
-
- CXXConstructorDecl *CopyCtor = ClassDecl->getCopyConstructor(getContext(), 0);
- assert(CopyCtor && "Did not have copy ctor!");
-
- EmitCopyCtorCall(*this, CopyCtor, Dest, Src);
-}
-
-/// SynthesizeCXXCopyConstructor - This routine implicitly defines body of a
-/// copy constructor, in accordance with section 12.8 (p7 and p8) of C++03
-/// The implicitly-defined copy constructor for class X performs a memberwise
-/// copy of its subobjects. The order of copying is the same as the order of
-/// initialization of bases and members in a user-defined constructor
-/// Each subobject is copied in the manner appropriate to its type:
-/// if the subobject is of class type, the copy constructor for the class is
-/// used;
-/// if the subobject is an array, each element is copied, in the manner
-/// appropriate to the element type;
-/// if the subobject is of scalar type, the built-in assignment operator is
-/// used.
-/// Virtual base class subobjects shall be copied only once by the
-/// implicitly-defined copy constructor
-
-void
-CodeGenFunction::SynthesizeCXXCopyConstructor(const FunctionArgList &Args) {
- const CXXConstructorDecl *Ctor = cast<CXXConstructorDecl>(CurGD.getDecl());
- CXXCtorType CtorType = CurGD.getCtorType();
- (void) CtorType;
-
- const CXXRecordDecl *ClassDecl = Ctor->getParent();
- assert(!ClassDecl->hasUserDeclaredCopyConstructor() &&
- "SynthesizeCXXCopyConstructor - copy constructor has definition already");
- assert(!Ctor->isTrivial() && "shouldn't need to generate trivial ctor");
-
- llvm::Value *ThisPtr = LoadCXXThis();
-
- // Find the source pointer.
- unsigned SrcArgIndex = Args.size() - 1;
- assert(CtorType == Ctor_Base || SrcArgIndex == 1);
- assert(CtorType != Ctor_Base ||
- (ClassDecl->getNumVBases() != 0 && SrcArgIndex == 2) ||
- SrcArgIndex == 1);
-
- llvm::Value *SrcPtr =
- Builder.CreateLoad(GetAddrOfLocalVar(Args[SrcArgIndex].first));
-
- for (CXXRecordDecl::field_iterator I = ClassDecl->field_begin(),
- E = ClassDecl->field_end(); I != E; ++I) {
- const FieldDecl *Field = *I;
-
- QualType FieldType = getContext().getCanonicalType(Field->getType());
- const ConstantArrayType *Array =
- getContext().getAsConstantArrayType(FieldType);
- if (Array)
- FieldType = getContext().getBaseElementType(FieldType);
-
- if (const RecordType *FieldClassType = FieldType->getAs<RecordType>()) {
- CXXRecordDecl *FieldClassDecl
- = cast<CXXRecordDecl>(FieldClassType->getDecl());
- LValue LHS = EmitLValueForField(ThisPtr, Field, 0);
- LValue RHS = EmitLValueForField(SrcPtr, Field, 0);
- if (Array) {
- const llvm::Type *BasePtr = ConvertType(FieldType)->getPointerTo();
- llvm::Value *DestBaseAddrPtr =
- Builder.CreateBitCast(LHS.getAddress(), BasePtr);
- llvm::Value *SrcBaseAddrPtr =
- Builder.CreateBitCast(RHS.getAddress(), BasePtr);
- EmitClassAggrMemberwiseCopy(DestBaseAddrPtr, SrcBaseAddrPtr, Array,
- FieldClassDecl);
- }
- else
- EmitClassMemberwiseCopy(LHS.getAddress(), RHS.getAddress(),
- FieldClassDecl);
- continue;
- }
-
- // Do a built-in assignment of scalar data members.
- LValue LHS = EmitLValueForFieldInitialization(ThisPtr, Field, 0);
- LValue RHS = EmitLValueForFieldInitialization(SrcPtr, Field, 0);
-
- if (!hasAggregateLLVMType(Field->getType())) {
- RValue RVRHS = EmitLoadOfLValue(RHS, Field->getType());
- EmitStoreThroughLValue(RVRHS, LHS, Field->getType());
- } else if (Field->getType()->isAnyComplexType()) {
- ComplexPairTy Pair = LoadComplexFromAddr(RHS.getAddress(),
- RHS.isVolatileQualified());
- StoreComplexToAddr(Pair, LHS.getAddress(), LHS.isVolatileQualified());
- } else {
- EmitAggregateCopy(LHS.getAddress(), RHS.getAddress(), Field->getType());
- }
- }
-
- InitializeVTablePointers(ClassDecl);
-}
-
static void EmitBaseInitializer(CodeGenFunction &CGF,
const CXXRecordDecl *ClassDecl,
CXXBaseOrMemberInitializer *BaseInit,
@@ -547,9 +347,97 @@ static void EmitBaseInitializer(CodeGenFunction &CGF,
}
}
+static void EmitAggMemberInitializer(CodeGenFunction &CGF,
+ LValue LHS,
+ llvm::Value *ArrayIndexVar,
+ CXXBaseOrMemberInitializer *MemberInit,
+ QualType T,
+ unsigned Index) {
+ if (Index == MemberInit->getNumArrayIndices()) {
+ CodeGenFunction::CleanupScope Cleanups(CGF);
+
+ llvm::Value *Dest = LHS.getAddress();
+ if (ArrayIndexVar) {
+ // If we have an array index variable, load it and use it as an offset.
+ // Then, increment the value.
+ llvm::Value *ArrayIndex = CGF.Builder.CreateLoad(ArrayIndexVar);
+ Dest = CGF.Builder.CreateInBoundsGEP(Dest, ArrayIndex, "destaddress");
+ llvm::Value *Next = llvm::ConstantInt::get(ArrayIndex->getType(), 1);
+ Next = CGF.Builder.CreateAdd(ArrayIndex, Next, "inc");
+ CGF.Builder.CreateStore(Next, ArrayIndexVar);
+ }
+
+ CGF.EmitAggExpr(MemberInit->getInit(), Dest,
+ LHS.isVolatileQualified(),
+ /*IgnoreResult*/ false,
+ /*IsInitializer*/ true);
+
+ return;
+ }
+
+ const ConstantArrayType *Array = CGF.getContext().getAsConstantArrayType(T);
+ assert(Array && "Array initialization without the array type?");
+ llvm::Value *IndexVar
+ = CGF.GetAddrOfLocalVar(MemberInit->getArrayIndex(Index));
+ assert(IndexVar && "Array index variable not loaded");
+
+ // Initialize this index variable to zero.
+ llvm::Value* Zero
+ = llvm::Constant::getNullValue(
+ CGF.ConvertType(CGF.getContext().getSizeType()));
+ CGF.Builder.CreateStore(Zero, IndexVar);
+
+ // Start the loop with a block that tests the condition.
+ llvm::BasicBlock *CondBlock = CGF.createBasicBlock("for.cond");
+ llvm::BasicBlock *AfterFor = CGF.createBasicBlock("for.end");
+
+ CGF.EmitBlock(CondBlock);
+
+ llvm::BasicBlock *ForBody = CGF.createBasicBlock("for.body");
+ // Generate: if (loop-index < number-of-elements) fall to the loop body,
+ // otherwise, go to the block after the for-loop.
+ uint64_t NumElements = Array->getSize().getZExtValue();
+ llvm::Value *Counter = CGF.Builder.CreateLoad(IndexVar);
+ llvm::Value *NumElementsPtr =
+ llvm::ConstantInt::get(Counter->getType(), NumElements);
+ llvm::Value *IsLess = CGF.Builder.CreateICmpULT(Counter, NumElementsPtr,
+ "isless");
+
+ // If the condition is true, execute the body.
+ CGF.Builder.CreateCondBr(IsLess, ForBody, AfterFor);
+
+ CGF.EmitBlock(ForBody);
+ llvm::BasicBlock *ContinueBlock = CGF.createBasicBlock("for.inc");
+
+ {
+ CodeGenFunction::CleanupScope Cleanups(CGF);
+
+ // Inside the loop body recurse to emit the inner loop or, eventually, the
+ // constructor call.
+ EmitAggMemberInitializer(CGF, LHS, ArrayIndexVar, MemberInit,
+ Array->getElementType(), Index + 1);
+ }
+
+ CGF.EmitBlock(ContinueBlock);
+
+ // Emit the increment of the loop counter.
+ llvm::Value *NextVal = llvm::ConstantInt::get(Counter->getType(), 1);
+ Counter = CGF.Builder.CreateLoad(IndexVar);
+ NextVal = CGF.Builder.CreateAdd(Counter, NextVal, "inc");
+ CGF.Builder.CreateStore(NextVal, IndexVar);
+
+ // Finally, branch back up to the condition for the next iteration.
+ CGF.EmitBranch(CondBlock);
+
+ // Emit the fall-through block.
+ CGF.EmitBlock(AfterFor, true);
+}
+
static void EmitMemberInitializer(CodeGenFunction &CGF,
const CXXRecordDecl *ClassDecl,
- CXXBaseOrMemberInitializer *MemberInit) {
+ CXXBaseOrMemberInitializer *MemberInit,
+ const CXXConstructorDecl *Constructor,
+ FunctionArgList &Args) {
assert(MemberInit->isMemberInitializer() &&
"Must have member initializer!");
@@ -558,13 +446,15 @@ static void EmitMemberInitializer(CodeGenFunction &CGF,
QualType FieldType = CGF.getContext().getCanonicalType(Field->getType());
llvm::Value *ThisPtr = CGF.LoadCXXThis();
- LValue LHS = CGF.EmitLValueForFieldInitialization(ThisPtr, Field, 0);
+ LValue LHS;
// If we are initializing an anonymous union field, drill down to the field.
if (MemberInit->getAnonUnionMember()) {
Field = MemberInit->getAnonUnionMember();
- LHS = CGF.EmitLValueForField(LHS.getAddress(), Field, 0);
+ LHS = CGF.EmitLValueForAnonRecordField(ThisPtr, Field, 0);
FieldType = Field->getType();
+ } else {
+ LHS = CGF.EmitLValueForFieldInitialization(ThisPtr, Field, 0);
}
// FIXME: If there's no initializer and the CXXBaseOrMemberInitializer
@@ -575,7 +465,7 @@ static void EmitMemberInitializer(CodeGenFunction &CGF,
/*IsInitializer=*/true);
CGF.EmitStoreThroughLValue(RHS, LHS, FieldType);
} else if (FieldType->isArrayType() && !MemberInit->getInit()) {
- CGF.EmitMemSetToZero(LHS.getAddress(), Field->getType());
+ CGF.EmitNullInitialization(LHS.getAddress(), Field->getType());
} else if (!CGF.hasAggregateLLVMType(Field->getType())) {
RHS = RValue::get(CGF.EmitScalarExpr(MemberInit->getInit(), true));
CGF.EmitStoreThroughLValue(RHS, LHS, FieldType);
@@ -583,14 +473,61 @@ static void EmitMemberInitializer(CodeGenFunction &CGF,
CGF.EmitComplexExprIntoAddr(MemberInit->getInit(), LHS.getAddress(),
LHS.isVolatileQualified());
} else {
- CGF.EmitAggExpr(MemberInit->getInit(), LHS.getAddress(),
- LHS.isVolatileQualified(),
- /*IgnoreResult*/ false,
- /*IsInitializer*/ true);
+ llvm::Value *ArrayIndexVar = 0;
+ const ConstantArrayType *Array
+ = CGF.getContext().getAsConstantArrayType(FieldType);
+ if (Array && Constructor->isImplicit() &&
+ Constructor->isCopyConstructor()) {
+ const llvm::Type *SizeTy
+ = CGF.ConvertType(CGF.getContext().getSizeType());
+
+ // The LHS is a pointer to the first object we'll be constructing, as
+ // a flat array.
+ QualType BaseElementTy = CGF.getContext().getBaseElementType(Array);
+ const llvm::Type *BasePtr = CGF.ConvertType(BaseElementTy);
+ BasePtr = llvm::PointerType::getUnqual(BasePtr);
+ llvm::Value *BaseAddrPtr = CGF.Builder.CreateBitCast(LHS.getAddress(),
+ BasePtr);
+ LHS = LValue::MakeAddr(BaseAddrPtr, CGF.MakeQualifiers(BaseElementTy));
+
+ // Create an array index that will be used to walk over all of the
+ // objects we're constructing.
+ ArrayIndexVar = CGF.CreateTempAlloca(SizeTy, "object.index");
+ llvm::Value *Zero = llvm::Constant::getNullValue(SizeTy);
+ CGF.Builder.CreateStore(Zero, ArrayIndexVar);
+
+ // If we are copying an array of scalars or classes with trivial copy
+ // constructors, perform a single aggregate copy.
+ const RecordType *Record = BaseElementTy->getAs<RecordType>();
+ if (!Record ||
+ cast<CXXRecordDecl>(Record->getDecl())->hasTrivialCopyConstructor()) {
+ // Find the source pointer. We knows it's the last argument because
+ // we know we're in a copy constructor.
+ unsigned SrcArgIndex = Args.size() - 1;
+ llvm::Value *SrcPtr
+ = CGF.Builder.CreateLoad(
+ CGF.GetAddrOfLocalVar(Args[SrcArgIndex].first));
+ LValue Src = CGF.EmitLValueForFieldInitialization(SrcPtr, Field, 0);
+
+ // Copy the aggregate.
+ CGF.EmitAggregateCopy(LHS.getAddress(), Src.getAddress(), FieldType,
+ LHS.isVolatileQualified());
+ return;
+ }
+
+ // Emit the block variables for the array indices, if any.
+ for (unsigned I = 0, N = MemberInit->getNumArrayIndices(); I != N; ++I)
+ CGF.EmitLocalBlockVarDecl(*MemberInit->getArrayIndex(I));
+ }
+
+ EmitAggMemberInitializer(CGF, LHS, ArrayIndexVar, MemberInit, FieldType, 0);
if (!CGF.Exceptions)
return;
+ // FIXME: If we have an array of classes w/ non-trivial destructors,
+ // we need to destroy in reverse order of construction along the exception
+ // path.
const RecordType *RT = FieldType->getAs<RecordType>();
if (!RT)
return;
@@ -680,20 +617,13 @@ void CodeGenFunction::EmitConstructorBody(FunctionArgList &Args) {
// Emit the constructor prologue, i.e. the base and member
// initializers.
- EmitCtorPrologue(Ctor, CtorType);
+ EmitCtorPrologue(Ctor, CtorType, Args);
// Emit the body of the statement.
if (IsTryBody)
EmitStmt(cast<CXXTryStmt>(Body)->getTryBlock());
else if (Body)
EmitStmt(Body);
- else {
- assert(Ctor->isImplicit() && "bodyless ctor not implicit");
- if (!Ctor->isDefaultConstructor()) {
- assert(Ctor->isCopyConstructor());
- SynthesizeCXXCopyConstructor(Args);
- }
- }
// Emit any cleanup blocks associated with the member or base
// initializers, which includes (along the exceptional path) the
@@ -708,7 +638,8 @@ void CodeGenFunction::EmitConstructorBody(FunctionArgList &Args) {
/// EmitCtorPrologue - This routine generates necessary code to initialize
/// base classes and non-static data members belonging to this constructor.
void CodeGenFunction::EmitCtorPrologue(const CXXConstructorDecl *CD,
- CXXCtorType CtorType) {
+ CXXCtorType CtorType,
+ FunctionArgList &Args) {
const CXXRecordDecl *ClassDecl = CD->getParent();
llvm::SmallVector<CXXBaseOrMemberInitializer *, 8> MemberInitializers;
@@ -733,7 +664,7 @@ void CodeGenFunction::EmitCtorPrologue(const CXXConstructorDecl *CD,
assert(LiveTemporaries.empty() &&
"Should not have any live temporaries at initializer start!");
- EmitMemberInitializer(*this, ClassDecl, MemberInitializers[I]);
+ EmitMemberInitializer(*this, ClassDecl, MemberInitializers[I], CD, Args);
}
}
@@ -1206,34 +1137,9 @@ CodeGenFunction::EmitDelegateCXXConstructorCall(const CXXConstructorDecl *Ctor,
// Explicit arguments.
for (; I != E; ++I) {
-
const VarDecl *Param = I->first;
QualType ArgType = Param->getType(); // because we're passing it to itself
-
- // StartFunction converted the ABI-lowered parameter(s) into a
- // local alloca. We need to turn that into an r-value suitable
- // for EmitCall.
- llvm::Value *Local = GetAddrOfLocalVar(Param);
- RValue Arg;
-
- // For the most part, we just need to load the alloca, except:
- // 1) aggregate r-values are actually pointers to temporaries, and
- // 2) references to aggregates are pointers directly to the aggregate.
- // I don't know why references to non-aggregates are different here.
- if (ArgType->isReferenceType()) {
- const ReferenceType *RefType = ArgType->getAs<ReferenceType>();
- if (hasAggregateLLVMType(RefType->getPointeeType()))
- Arg = RValue::getAggregate(Local);
- else
- // Locals which are references to scalars are represented
- // with allocas holding the pointer.
- Arg = RValue::get(Builder.CreateLoad(Local));
- } else {
- if (hasAggregateLLVMType(ArgType))
- Arg = RValue::getAggregate(Local);
- else
- Arg = RValue::get(EmitLoadOfScalar(Local, false, ArgType));
- }
+ RValue Arg = EmitDelegateCallArg(Param);
DelegateArgs.push_back(std::make_pair(Arg, ArgType));
}
diff --git a/lib/CodeGen/CGDebugInfo.cpp b/lib/CodeGen/CGDebugInfo.cpp
index 48ae5113b3af..c9bcb1b7e043 100644
--- a/lib/CodeGen/CGDebugInfo.cpp
+++ b/lib/CodeGen/CGDebugInfo.cpp
@@ -64,7 +64,14 @@ llvm::DIDescriptor CGDebugInfo::getContextDescriptor(const Decl *Context,
// Check namespace.
if (const NamespaceDecl *NSDecl = dyn_cast<NamespaceDecl>(Context))
return llvm::DIDescriptor(getOrCreateNameSpace(NSDecl, CompileUnit));
-
+
+ if (const RecordDecl *RDecl = dyn_cast<RecordDecl>(Context)) {
+ if (!RDecl->isDependentType()) {
+ llvm::DIType Ty = getOrCreateType(CGM.getContext().getTypeDeclType(RDecl),
+ llvm::DIFile(CompileUnit));
+ return llvm::DIDescriptor(Ty);
+ }
+ }
return CompileUnit;
}
@@ -114,10 +121,29 @@ llvm::DIFile CGDebugInfo::getOrCreateFile(SourceLocation Loc) {
llvm::DIFile F = DebugFactory.CreateFile(AbsFileName.getLast(),
AbsFileName.getDirname(), TheCU);
- DIFileCache[fname] = F.getNode();
+ DIFileCache[fname] = F;
return F;
}
+
+/// getLineNumber - Get line number for the location. If location is invalid
+/// then use current location.
+unsigned CGDebugInfo::getLineNumber(SourceLocation Loc) {
+ assert (CurLoc.isValid() && "Invalid current location!");
+ SourceManager &SM = CGM.getContext().getSourceManager();
+ PresumedLoc PLoc = SM.getPresumedLoc(Loc.isValid() ? Loc : CurLoc);
+ return PLoc.getLine();
+}
+
+/// getColumnNumber - Get column number for the location. If location is
+/// invalid then use current location.
+unsigned CGDebugInfo::getColumnNumber(SourceLocation Loc) {
+ assert (CurLoc.isValid() && "Invalid current location!");
+ SourceManager &SM = CGM.getContext().getSourceManager();
+ PresumedLoc PLoc = SM.getPresumedLoc(Loc.isValid() ? Loc : CurLoc);
+ return PLoc.getColumn();
+}
+
/// CreateCompileUnit - Create new compile unit.
void CGDebugInfo::CreateCompileUnit() {
@@ -327,10 +353,11 @@ llvm::DIType CGDebugInfo::CreateType(const BlockPointerType *Ty,
EltTys.clear();
unsigned Flags = llvm::DIType::FlagAppleBlock;
+ unsigned LineNo = getLineNumber(CurLoc);
EltTy = DebugFactory.CreateCompositeType(Tag, Unit, "__block_descriptor",
- Unit, 0, FieldOffset, 0, 0, Flags,
- llvm::DIType(), Elements);
+ Unit, LineNo, FieldOffset, 0, 0,
+ Flags, llvm::DIType(), Elements);
// Bit size, align and offset of the type.
uint64_t Size = CGM.getContext().getTypeSize(Ty);
@@ -338,7 +365,7 @@ llvm::DIType CGDebugInfo::CreateType(const BlockPointerType *Ty,
DescTy = DebugFactory.CreateDerivedType(llvm::dwarf::DW_TAG_pointer_type,
Unit, "", Unit,
- 0, Size, Align, 0, 0, EltTy);
+ LineNo, Size, Align, 0, 0, EltTy);
FieldOffset = 0;
FType = CGM.getContext().getPointerType(CGM.getContext().VoidTy);
@@ -355,7 +382,7 @@ llvm::DIType CGDebugInfo::CreateType(const BlockPointerType *Ty,
FieldAlign = CGM.getContext().getTypeAlign(Ty);
FieldTy = DebugFactory.CreateDerivedType(llvm::dwarf::DW_TAG_member, Unit,
"__descriptor", Unit,
- 0, FieldSize, FieldAlign,
+ LineNo, FieldSize, FieldAlign,
FieldOffset, 0, FieldTy);
EltTys.push_back(FieldTy);
@@ -363,14 +390,14 @@ llvm::DIType CGDebugInfo::CreateType(const BlockPointerType *Ty,
Elements = DebugFactory.GetOrCreateArray(EltTys.data(), EltTys.size());
EltTy = DebugFactory.CreateCompositeType(Tag, Unit, "__block_literal_generic",
- Unit, 0, FieldOffset, 0, 0, Flags,
- llvm::DIType(), Elements);
+ Unit, LineNo, FieldOffset, 0, 0,
+ Flags, llvm::DIType(), Elements);
BlockLiteralGenericSet = true;
BlockLiteralGeneric
= DebugFactory.CreateDerivedType(llvm::dwarf::DW_TAG_pointer_type, Unit,
"", Unit,
- 0, Size, Align, 0, 0, EltTy);
+ LineNo, Size, Align, 0, 0, EltTy);
return BlockLiteralGeneric;
}
@@ -382,9 +409,7 @@ llvm::DIType CGDebugInfo::CreateType(const TypedefType *Ty,
// We don't set size information, but do specify where the typedef was
// declared.
- SourceManager &SM = CGM.getContext().getSourceManager();
- PresumedLoc PLoc = SM.getPresumedLoc(Ty->getDecl()->getLocation());
- unsigned Line = PLoc.isInvalid() ? 0 : PLoc.getLine();
+ unsigned Line = getLineNumber(Ty->getDecl()->getLocation());
llvm::DIDescriptor TyContext
= getContextDescriptor(dyn_cast<Decl>(Ty->getDecl()->getDeclContext()),
@@ -430,7 +455,6 @@ void CGDebugInfo::
CollectRecordFields(const RecordDecl *RD, llvm::DIFile Unit,
llvm::SmallVectorImpl<llvm::DIDescriptor> &EltTys) {
unsigned FieldNo = 0;
- SourceManager &SM = CGM.getContext().getSourceManager();
const ASTRecordLayout &RL = CGM.getContext().getASTRecordLayout(RD);
for (RecordDecl::field_iterator I = RD->field_begin(),
E = RD->field_end();
@@ -445,16 +469,8 @@ CollectRecordFields(const RecordDecl *RD, llvm::DIFile Unit,
continue;
// Get the location for the field.
- SourceLocation FieldDefLoc = Field->getLocation();
- PresumedLoc PLoc = SM.getPresumedLoc(FieldDefLoc);
- llvm::DIFile FieldDefUnit;
- unsigned FieldLine = 0;
-
- if (!PLoc.isInvalid()) {
- FieldDefUnit = getOrCreateFile(FieldDefLoc);
- FieldLine = PLoc.getLine();
- }
-
+ llvm::DIFile FieldDefUnit = getOrCreateFile(Field->getLocation());
+ unsigned FieldLine = getLineNumber(Field->getLocation());
QualType FType = Field->getType();
uint64_t FieldSize = 0;
unsigned FieldAlign = 0;
@@ -506,7 +522,7 @@ CGDebugInfo::getOrCreateMethodType(const CXXMethodDecl *Method,
// Add "this" pointer.
- llvm::DIArray Args = llvm::DICompositeType(FnTy.getNode()).getTypeArray();
+ llvm::DIArray Args = llvm::DICompositeType(FnTy).getTypeArray();
assert (Args.getNumElements() && "Invalid number of arguments!");
llvm::SmallVector<llvm::DIDescriptor, 16> Elts;
@@ -520,7 +536,7 @@ CGDebugInfo::getOrCreateMethodType(const CXXMethodDecl *Method,
Context.getPointerType(Context.getTagDeclType(Method->getParent()));
llvm::DIType ThisPtrType =
DebugFactory.CreateArtificialType(getOrCreateType(ThisPtr, Unit));
- TypeCache[ThisPtr.getAsOpaquePtr()] = ThisPtrType.getNode();
+ TypeCache[ThisPtr.getAsOpaquePtr()] = ThisPtrType;
Elts.push_back(ThisPtrType);
// Copy rest of the arguments.
@@ -555,18 +571,9 @@ CGDebugInfo::CreateCXXMemberFunction(const CXXMethodDecl *Method,
if (!IsCtorOrDtor)
CGM.getMangledName(MethodLinkageName, Method);
- SourceManager &SM = CGM.getContext().getSourceManager();
-
// Get the location for the method.
- SourceLocation MethodDefLoc = Method->getLocation();
- PresumedLoc PLoc = SM.getPresumedLoc(MethodDefLoc);
- llvm::DIFile MethodDefUnit;
- unsigned MethodLine = 0;
-
- if (!PLoc.isInvalid()) {
- MethodDefUnit = getOrCreateFile(MethodDefLoc);
- MethodLine = PLoc.getLine();
- }
+ llvm::DIFile MethodDefUnit = getOrCreateFile(Method->getLocation());
+ unsigned MethodLine = getLineNumber(Method->getLocation());
// Collect virtual method info.
llvm::DIType ContainingType;
@@ -597,7 +604,7 @@ CGDebugInfo::CreateCXXMemberFunction(const CXXMethodDecl *Method,
// Don't cache ctors or dtors since we have to emit multiple functions for
// a single ctor or dtor.
if (!IsCtorOrDtor && Method->isThisDeclarationADefinition())
- SPCache[Method] = llvm::WeakVH(SP.getNode());
+ SPCache[Method] = llvm::WeakVH(SP);
return SP;
}
@@ -741,16 +748,9 @@ llvm::DIType CGDebugInfo::CreateType(const RecordType *Ty,
Tag = llvm::dwarf::DW_TAG_class_type;
}
- SourceManager &SM = CGM.getContext().getSourceManager();
-
// Get overall information about the record type for the debug info.
- PresumedLoc PLoc = SM.getPresumedLoc(RD->getLocation());
- llvm::DIFile DefUnit;
- unsigned Line = 0;
- if (!PLoc.isInvalid()) {
- DefUnit = getOrCreateFile(RD->getLocation());
- Line = PLoc.getLine();
- }
+ llvm::DIFile DefUnit = getOrCreateFile(RD->getLocation());
+ unsigned Line = getLineNumber(RD->getLocation());
// Records and classes and unions can all be recursive. To handle them, we
// first generate a debug descriptor for the struct as a forward declaration.
@@ -774,13 +774,14 @@ llvm::DIType CGDebugInfo::CreateType(const RecordType *Ty,
if (!RD->getDefinition())
return FwdDecl;
- llvm::TrackingVH<llvm::MDNode> FwdDeclNode = FwdDecl.getNode();
+ llvm::MDNode *MN = FwdDecl;
+ llvm::TrackingVH<llvm::MDNode> FwdDeclNode = MN;
// Otherwise, insert it into the TypeCache so that recursive uses will find
// it.
- TypeCache[QualType(Ty, 0).getAsOpaquePtr()] = FwdDecl.getNode();
+ TypeCache[QualType(Ty, 0).getAsOpaquePtr()] = FwdDecl;
// Push the struct on region stack.
- RegionStack.push_back(FwdDecl.getNode());
- RegionMap[Ty->getDecl()] = llvm::WeakVH(FwdDecl.getNode());
+ RegionStack.push_back(FwdDeclNode);
+ RegionMap[Ty->getDecl()] = llvm::WeakVH(FwdDecl);
// Convert all the elements.
llvm::SmallVector<llvm::DIDescriptor, 16> EltTys;
@@ -799,9 +800,9 @@ llvm::DIType CGDebugInfo::CreateType(const RecordType *Ty,
const ASTRecordLayout &RL = CGM.getContext().getASTRecordLayout(RD);
if (const CXXRecordDecl *PBase = RL.getPrimaryBase())
ContainingType =
- getOrCreateType(QualType(PBase->getTypeForDecl(), 0), Unit).getNode();
+ getOrCreateType(QualType(PBase->getTypeForDecl(), 0), Unit);
else if (CXXDecl->isDynamicClass())
- ContainingType = FwdDecl.getNode();
+ ContainingType = FwdDecl;
}
llvm::DIArray Elements =
@@ -829,24 +830,26 @@ llvm::DIType CGDebugInfo::CreateType(const RecordType *Ty,
// Now that we have a real decl for the struct, replace anything using the
// old decl with the new one. This will recursively update the debug info.
llvm::DIDerivedType(FwdDeclNode).replaceAllUsesWith(RealDecl);
- RegionMap[RD] = llvm::WeakVH(RealDecl.getNode());
+ RegionMap[RD] = llvm::WeakVH(RealDecl);
return RealDecl;
}
+/// CreateType - get objective-c object type.
+llvm::DIType CGDebugInfo::CreateType(const ObjCObjectType *Ty,
+ llvm::DIFile Unit) {
+ // Ignore protocols.
+ return getOrCreateType(Ty->getBaseType(), Unit);
+}
+
/// CreateType - get objective-c interface type.
llvm::DIType CGDebugInfo::CreateType(const ObjCInterfaceType *Ty,
llvm::DIFile Unit) {
ObjCInterfaceDecl *ID = Ty->getDecl();
-
unsigned Tag = llvm::dwarf::DW_TAG_structure_type;
- SourceManager &SM = CGM.getContext().getSourceManager();
// Get overall information about the record type for the debug info.
llvm::DIFile DefUnit = getOrCreateFile(ID->getLocation());
- PresumedLoc PLoc = SM.getPresumedLoc(ID->getLocation());
- unsigned Line = PLoc.isInvalid() ? 0 : PLoc.getLine();
-
-
+ unsigned Line = getLineNumber(ID->getLocation());
unsigned RuntimeLang = TheCU.getLanguage();
// To handle recursive interface, we
@@ -865,13 +868,14 @@ llvm::DIType CGDebugInfo::CreateType(const ObjCInterfaceType *Ty,
if (ID->isForwardDecl())
return FwdDecl;
- llvm::TrackingVH<llvm::MDNode> FwdDeclNode = FwdDecl.getNode();
+ llvm::MDNode *MN = FwdDecl;
+ llvm::TrackingVH<llvm::MDNode> FwdDeclNode = MN;
// Otherwise, insert it into the TypeCache so that recursive uses will find
// it.
- TypeCache[QualType(Ty, 0).getAsOpaquePtr()] = FwdDecl.getNode();
+ TypeCache[QualType(Ty, 0).getAsOpaquePtr()] = FwdDecl;
// Push the struct on region stack.
- RegionStack.push_back(FwdDecl.getNode());
- RegionMap[Ty->getDecl()] = llvm::WeakVH(FwdDecl.getNode());
+ RegionStack.push_back(FwdDeclNode);
+ RegionMap[Ty->getDecl()] = llvm::WeakVH(FwdDecl);
// Convert all the elements.
llvm::SmallVector<llvm::DIDescriptor, 16> EltTys;
@@ -902,12 +906,8 @@ llvm::DIType CGDebugInfo::CreateType(const ObjCInterfaceType *Ty,
continue;
// Get the location for the field.
- SourceLocation FieldDefLoc = Field->getLocation();
- llvm::DIFile FieldDefUnit = getOrCreateFile(FieldDefLoc);
- PresumedLoc PLoc = SM.getPresumedLoc(FieldDefLoc);
- unsigned FieldLine = PLoc.isInvalid() ? 0 : PLoc.getLine();
-
-
+ llvm::DIFile FieldDefUnit = getOrCreateFile(Field->getLocation());
+ unsigned FieldLine = getLineNumber(Field->getLocation());
QualType FType = Field->getType();
uint64_t FieldSize = 0;
unsigned FieldAlign = 0;
@@ -962,7 +962,7 @@ llvm::DIType CGDebugInfo::CreateType(const ObjCInterfaceType *Ty,
// Now that we have a real decl for the struct, replace anything using the
// old decl with the new one. This will recursively update the debug info.
llvm::DIDerivedType(FwdDeclNode).replaceAllUsesWith(RealDecl);
- RegionMap[ID] = llvm::WeakVH(RealDecl.getNode());
+ RegionMap[ID] = llvm::WeakVH(RealDecl);
return RealDecl;
}
@@ -985,12 +985,8 @@ llvm::DIType CGDebugInfo::CreateType(const EnumType *Ty,
llvm::DIArray EltArray =
DebugFactory.GetOrCreateArray(Enumerators.data(), Enumerators.size());
- SourceLocation DefLoc = ED->getLocation();
- llvm::DIFile DefUnit = getOrCreateFile(DefLoc);
- SourceManager &SM = CGM.getContext().getSourceManager();
- PresumedLoc PLoc = SM.getPresumedLoc(DefLoc);
- unsigned Line = PLoc.isInvalid() ? 0 : PLoc.getLine();
-
+ llvm::DIFile DefUnit = getOrCreateFile(ED->getLocation());
+ unsigned Line = getLineNumber(ED->getLocation());
// Size and align of the type.
uint64_t Size = 0;
@@ -1152,15 +1148,12 @@ static QualType UnwrapTypeForDebugInfo(QualType T) {
case Type::Decltype:
T = cast<DecltypeType>(T)->getUnderlyingType();
break;
- case Type::QualifiedName:
- T = cast<QualifiedNameType>(T)->getNamedType();
+ case Type::Elaborated:
+ T = cast<ElaboratedType>(T)->getNamedType();
break;
case Type::SubstTemplateTypeParm:
T = cast<SubstTemplateTypeParmType>(T)->getReplacementType();
break;
- case Type::Elaborated:
- T = cast<ElaboratedType>(T)->getUnderlyingType();
- break;
}
assert(T != LastT && "Type unwrapping failed to unwrap!");
@@ -1194,7 +1187,7 @@ llvm::DIType CGDebugInfo::getOrCreateType(QualType Ty,
llvm::DIType Res = CreateTypeNode(Ty, Unit);
// And update the type cache.
- TypeCache[Ty.getAsOpaquePtr()] = Res.getNode();
+ TypeCache[Ty.getAsOpaquePtr()] = Res;
return Res;
}
@@ -1224,6 +1217,8 @@ llvm::DIType CGDebugInfo::CreateTypeNode(QualType Ty,
return CreateType(cast<VectorType>(Ty), Unit);
case Type::ObjCObjectPointer:
return CreateType(cast<ObjCObjectPointerType>(Ty), Unit);
+ case Type::ObjCObject:
+ return CreateType(cast<ObjCObjectType>(Ty), Unit);
case Type::ObjCInterface:
return CreateType(cast<ObjCInterfaceType>(Ty), Unit);
case Type::Builtin: return CreateType(cast<BuiltinType>(Ty), Unit);
@@ -1251,7 +1246,6 @@ llvm::DIType CGDebugInfo::CreateTypeNode(QualType Ty,
case Type::TemplateSpecialization:
case Type::Elaborated:
- case Type::QualifiedName:
case Type::SubstTemplateTypeParm:
case Type::TypeOfExpr:
case Type::TypeOf:
@@ -1304,9 +1298,10 @@ void CGDebugInfo::EmitFunctionStart(GlobalDecl GD, QualType FnType,
FI = SPCache.find(FD);
if (FI != SPCache.end()) {
llvm::DIDescriptor SP(dyn_cast_or_null<llvm::MDNode>(FI->second));
- if (SP.isSubprogram() && llvm::DISubprogram(SP.getNode()).isDefinition()) {
- RegionStack.push_back(SP.getNode());
- RegionMap[D] = llvm::WeakVH(SP.getNode());
+ if (SP.isSubprogram() && llvm::DISubprogram(SP).isDefinition()) {
+ llvm::MDNode *SPN = SP;
+ RegionStack.push_back(SPN);
+ RegionMap[D] = llvm::WeakVH(SP);
return;
}
}
@@ -1325,8 +1320,7 @@ void CGDebugInfo::EmitFunctionStart(GlobalDecl GD, QualType FnType,
// Usually, CurLoc points to the left bracket location of compound
// statement representing function body.
llvm::DIFile Unit = getOrCreateFile(CurLoc);
- SourceManager &SM = CGM.getContext().getSourceManager();
- unsigned LineNo = SM.getPresumedLoc(CurLoc).getLine();
+ unsigned LineNo = getLineNumber(CurLoc);
llvm::DISubprogram SP =
DebugFactory.CreateSubprogram(Unit, Name, Name, LinkageName, Unit, LineNo,
@@ -1334,8 +1328,9 @@ void CGDebugInfo::EmitFunctionStart(GlobalDecl GD, QualType FnType,
Fn->hasInternalLinkage(), true/*definition*/);
// Push function on region stack.
- RegionStack.push_back(SP.getNode());
- RegionMap[D] = llvm::WeakVH(SP.getNode());
+ llvm::MDNode *SPN = SP;
+ RegionStack.push_back(SPN);
+ RegionMap[D] = llvm::WeakVH(SP);
}
@@ -1355,27 +1350,23 @@ void CGDebugInfo::EmitStopPoint(llvm::Function *Fn, CGBuilderTy &Builder) {
// Update last state.
PrevLoc = CurLoc;
- // Get the appropriate compile unit.
- llvm::DIFile Unit = getOrCreateFile(CurLoc);
- PresumedLoc PLoc = SM.getPresumedLoc(CurLoc);
-
llvm::MDNode *Scope = RegionStack.back();
- Builder.SetCurrentDebugLocation(llvm::DebugLoc::get(PLoc.getLine(),
- PLoc.getColumn(),
+ Builder.SetCurrentDebugLocation(llvm::DebugLoc::get(getLineNumber(CurLoc),
+ getColumnNumber(CurLoc),
Scope));
}
/// EmitRegionStart- Constructs the debug code for entering a declarative
/// region - "llvm.dbg.region.start.".
void CGDebugInfo::EmitRegionStart(llvm::Function *Fn, CGBuilderTy &Builder) {
- SourceManager &SM = CGM.getContext().getSourceManager();
- PresumedLoc PLoc = SM.getPresumedLoc(CurLoc);
llvm::DIDescriptor D =
DebugFactory.CreateLexicalBlock(RegionStack.empty() ?
llvm::DIDescriptor() :
llvm::DIDescriptor(RegionStack.back()),
- PLoc.getLine(), PLoc.getColumn());
- RegionStack.push_back(D.getNode());
+ getLineNumber(CurLoc),
+ getColumnNumber(CurLoc));
+ llvm::MDNode *DN = D;
+ RegionStack.push_back(DN);
}
/// EmitRegionEnd - Constructs the debug code for exiting a declarative
@@ -1473,20 +1464,14 @@ void CGDebugInfo::EmitDeclare(const VarDecl *VD, unsigned Tag,
else
Ty = getOrCreateType(VD->getType(), Unit);
+ // If there is not any debug info for type then do not emit debug info
+ // for this variable.
+ if (!Ty)
+ return;
+
// Get location information.
- SourceManager &SM = CGM.getContext().getSourceManager();
- PresumedLoc PLoc = SM.getPresumedLoc(VD->getLocation());
- unsigned Line = 0;
- unsigned Column = 0;
- if (PLoc.isInvalid())
- PLoc = SM.getPresumedLoc(CurLoc);
- if (PLoc.isValid()) {
- Line = PLoc.getLine();
- Column = PLoc.getColumn();
- Unit = getOrCreateFile(CurLoc);
- } else {
- Unit = llvm::DIFile();
- }
+ unsigned Line = getLineNumber(VD->getLocation());
+ unsigned Column = getColumnNumber(VD->getLocation());
// Create the descriptor for the variable.
llvm::DIVariable D =
@@ -1520,13 +1505,8 @@ void CGDebugInfo::EmitDeclare(const BlockDeclRefExpr *BDRE, unsigned Tag,
Ty = getOrCreateType(VD->getType(), Unit);
// Get location information.
- SourceManager &SM = CGM.getContext().getSourceManager();
- PresumedLoc PLoc = SM.getPresumedLoc(VD->getLocation());
- unsigned Line = 0;
- if (!PLoc.isInvalid())
- Line = PLoc.getLine();
- else
- Unit = llvm::DIFile();
+ unsigned Line = getLineNumber(VD->getLocation());
+ unsigned Column = getColumnNumber(VD->getLocation());
CharUnits offset = CGF->BlockDecls[VD];
llvm::SmallVector<llvm::Value *, 9> addr;
@@ -1558,7 +1538,7 @@ void CGDebugInfo::EmitDeclare(const BlockDeclRefExpr *BDRE, unsigned Tag,
DebugFactory.InsertDeclare(Storage, D, Builder.GetInsertBlock());
llvm::MDNode *Scope = RegionStack.back();
- Call->setDebugLoc(llvm::DebugLoc::get(Line, PLoc.getColumn(), Scope));
+ Call->setDebugLoc(llvm::DebugLoc::get(Line, Column, Scope));
}
void CGDebugInfo::EmitDeclareOfAutoVariable(const VarDecl *VD,
@@ -1588,9 +1568,7 @@ void CGDebugInfo::EmitGlobalVariable(llvm::GlobalVariable *Var,
// Create global variable debug descriptor.
llvm::DIFile Unit = getOrCreateFile(D->getLocation());
- SourceManager &SM = CGM.getContext().getSourceManager();
- PresumedLoc PLoc = SM.getPresumedLoc(D->getLocation());
- unsigned LineNo = PLoc.isInvalid() ? 0 : PLoc.getLine();
+ unsigned LineNo = getLineNumber(D->getLocation());
QualType T = D->getType();
if (T->isIncompleteArrayType()) {
@@ -1605,11 +1583,13 @@ void CGDebugInfo::EmitGlobalVariable(llvm::GlobalVariable *Var,
ArrayType::Normal, 0);
}
llvm::StringRef DeclName = D->getName();
+ llvm::StringRef LinkageName;
+ if (D->getDeclContext() && !isa<FunctionDecl>(D->getDeclContext()))
+ LinkageName = Var->getName();
llvm::DIDescriptor DContext =
getContextDescriptor(dyn_cast<Decl>(D->getDeclContext()), Unit);
- DebugFactory.CreateGlobalVariable(DContext, DeclName,
- DeclName, llvm::StringRef(), Unit, LineNo,
- getOrCreateType(T, Unit),
+ DebugFactory.CreateGlobalVariable(DContext, DeclName, DeclName, LinkageName,
+ Unit, LineNo, getOrCreateType(T, Unit),
Var->hasInternalLinkage(),
true/*definition*/, Var);
}
@@ -1619,9 +1599,7 @@ void CGDebugInfo::EmitGlobalVariable(llvm::GlobalVariable *Var,
ObjCInterfaceDecl *ID) {
// Create global variable debug descriptor.
llvm::DIFile Unit = getOrCreateFile(ID->getLocation());
- SourceManager &SM = CGM.getContext().getSourceManager();
- PresumedLoc PLoc = SM.getPresumedLoc(ID->getLocation());
- unsigned LineNo = PLoc.isInvalid() ? 0 : PLoc.getLine();
+ unsigned LineNo = getLineNumber(ID->getLocation());
llvm::StringRef Name = ID->getName();
@@ -1654,15 +1632,13 @@ CGDebugInfo::getOrCreateNameSpace(const NamespaceDecl *NSDecl,
if (I != NameSpaceCache.end())
return llvm::DINameSpace(cast<llvm::MDNode>(I->second));
- SourceManager &SM = CGM.getContext().getSourceManager();
- PresumedLoc PLoc = SM.getPresumedLoc(NSDecl->getLocation());
- unsigned LineNo = PLoc.isInvalid() ? 0 : PLoc.getLine();
+ unsigned LineNo = getLineNumber(NSDecl->getLocation());
llvm::DIDescriptor Context =
getContextDescriptor(dyn_cast<Decl>(NSDecl->getDeclContext()), Unit);
llvm::DINameSpace NS =
DebugFactory.CreateNameSpace(Context, NSDecl->getName(),
- llvm::DIFile(Unit.getNode()), LineNo);
- NameSpaceCache[NSDecl] = llvm::WeakVH(NS.getNode());
+ llvm::DIFile(Unit), LineNo);
+ NameSpaceCache[NSDecl] = llvm::WeakVH(NS);
return NS;
}
diff --git a/lib/CodeGen/CGDebugInfo.h b/lib/CodeGen/CGDebugInfo.h
index c16379aca34c..620a5f2f8480 100644
--- a/lib/CodeGen/CGDebugInfo.h
+++ b/lib/CodeGen/CGDebugInfo.h
@@ -80,6 +80,7 @@ class CGDebugInfo {
llvm::DIType CreateType(const TagType *Ty, llvm::DIFile F);
llvm::DIType CreateType(const RecordType *Ty, llvm::DIFile F);
llvm::DIType CreateType(const ObjCInterfaceType *Ty, llvm::DIFile F);
+ llvm::DIType CreateType(const ObjCObjectType *Ty, llvm::DIFile F);
llvm::DIType CreateType(const EnumType *Ty, llvm::DIFile F);
llvm::DIType CreateType(const VectorType *Ty, llvm::DIFile F);
llvm::DIType CreateType(const ArrayType *Ty, llvm::DIFile F);
@@ -208,6 +209,13 @@ private:
/// getVTableName - Get vtable name for the given Class.
llvm::StringRef getVTableName(const CXXRecordDecl *Decl);
+ /// getLineNumber - Get line number for the location. If location is invalid
+ /// then use current location.
+ unsigned getLineNumber(SourceLocation Loc);
+
+ /// getColumnNumber - Get column number for the location. If location is
+ /// invalid then use current location.
+ unsigned getColumnNumber(SourceLocation Loc);
};
} // namespace CodeGen
} // namespace clang
diff --git a/lib/CodeGen/CGDecl.cpp b/lib/CodeGen/CGDecl.cpp
index 48198ff5761b..07edca0f5fef 100644
--- a/lib/CodeGen/CGDecl.cpp
+++ b/lib/CodeGen/CGDecl.cpp
@@ -114,14 +114,14 @@ void CodeGenFunction::EmitBlockVarDecl(const VarDecl &D) {
llvm::GlobalValue::LinkageTypes Linkage =
llvm::GlobalValue::InternalLinkage;
- // If this is a static declaration inside an inline function, it must have
- // weak linkage so that the linker will merge multiple definitions of it.
- if (getContext().getLangOptions().CPlusPlus) {
- if (const FunctionDecl *FD = dyn_cast<FunctionDecl>(CurFuncDecl)) {
- if (FD->isInlined())
- Linkage = llvm::GlobalValue::WeakAnyLinkage;
- }
- }
+ // If the function definition has some sort of weak linkage, its
+ // static variables should also be weak so that they get properly
+ // uniqued. We can't do this in C, though, because there's no
+ // standard way to agree on which variables are the same (i.e.
+ // there's no mangling).
+ if (getContext().getLangOptions().CPlusPlus)
+ if (llvm::GlobalValue::isWeakForLinker(CurFn->getLinkage()))
+ Linkage = CurFn->getLinkage();
return EmitStaticBlockVarDecl(D, Linkage);
}
@@ -239,8 +239,6 @@ void CodeGenFunction::EmitStaticBlockVarDecl(const VarDecl &D,
// Store into LocalDeclMap before generating initializer to handle
// circular references.
DMEntry = GV;
- if (getContext().getLangOptions().CPlusPlus)
- CGM.setStaticLocalDeclAddress(&D, GV);
// We can't have a VLA here, but we can have a pointer to a VLA,
// even though that doesn't really make any sense.
@@ -269,6 +267,9 @@ void CodeGenFunction::EmitStaticBlockVarDecl(const VarDecl &D,
if (D.hasAttr<UsedAttr>())
CGM.AddUsedGlobal(GV);
+ if (getContext().getLangOptions().CPlusPlus)
+ CGM.setStaticLocalDeclAddress(&D, GV);
+
// We may have to cast the constant because of the initializer
// mismatch above.
//
@@ -398,16 +399,20 @@ void CodeGenFunction::EmitLocalBlockVarDecl(const VarDecl &D) {
CharUnits Align = CharUnits::Zero();
bool IsSimpleConstantInitializer = false;
+ bool NRVO = false;
+ llvm::Value *NRVOFlag = 0;
llvm::Value *DeclPtr;
if (Ty->isConstantSizeType()) {
if (!Target.useGlobalsForAutomaticVariables()) {
-
+ NRVO = getContext().getLangOptions().ElideConstructors &&
+ D.isNRVOVariable();
// If this value is an array or struct, is POD, and if the initializer is
- // a staticly determinable constant, try to optimize it.
+ // a staticly determinable constant, try to optimize it (unless the NRVO
+ // is already optimizing this).
if (D.getInit() && !isByRef &&
(Ty->isArrayType() || Ty->isRecordType()) &&
Ty->isPODType() &&
- D.getInit()->isConstantInitializer(getContext())) {
+ D.getInit()->isConstantInitializer(getContext()) && !NRVO) {
// If this variable is marked 'const', emit the value as a global.
if (CGM.getCodeGenOpts().MergeAllConstants &&
Ty.isConstant(getContext())) {
@@ -418,19 +423,44 @@ void CodeGenFunction::EmitLocalBlockVarDecl(const VarDecl &D) {
IsSimpleConstantInitializer = true;
}
- // A normal fixed sized variable becomes an alloca in the entry block.
+ // A normal fixed sized variable becomes an alloca in the entry block,
+ // unless it's an NRVO variable.
const llvm::Type *LTy = ConvertTypeForMem(Ty);
- if (isByRef)
- LTy = BuildByRefType(&D);
- llvm::AllocaInst *Alloc = CreateTempAlloca(LTy);
- Alloc->setName(D.getNameAsString());
-
- Align = getContext().getDeclAlign(&D);
- if (isByRef)
- Align = std::max(Align,
- CharUnits::fromQuantity(Target.getPointerAlign(0) / 8));
- Alloc->setAlignment(Align.getQuantity());
- DeclPtr = Alloc;
+
+ if (NRVO) {
+ // The named return value optimization: allocate this variable in the
+ // return slot, so that we can elide the copy when returning this
+ // variable (C++0x [class.copy]p34).
+ DeclPtr = ReturnValue;
+
+ if (const RecordType *RecordTy = Ty->getAs<RecordType>()) {
+ if (!cast<CXXRecordDecl>(RecordTy->getDecl())->hasTrivialDestructor()) {
+ // Create a flag that is used to indicate when the NRVO was applied
+ // to this variable. Set it to zero to indicate that NRVO was not
+ // applied.
+ const llvm::Type *BoolTy = llvm::Type::getInt1Ty(VMContext);
+ llvm::Value *Zero = llvm::ConstantInt::get(BoolTy, 0);
+ NRVOFlag = CreateTempAlloca(BoolTy, "nrvo");
+ Builder.CreateStore(Zero, NRVOFlag);
+
+ // Record the NRVO flag for this variable.
+ NRVOFlags[&D] = NRVOFlag;
+ }
+ }
+ } else {
+ if (isByRef)
+ LTy = BuildByRefType(&D);
+
+ llvm::AllocaInst *Alloc = CreateTempAlloca(LTy);
+ Alloc->setName(D.getNameAsString());
+
+ Align = getContext().getDeclAlign(&D);
+ if (isByRef)
+ Align = std::max(Align,
+ CharUnits::fromQuantity(Target.getPointerAlign(0) / 8));
+ Alloc->setAlignment(Align.getQuantity());
+ DeclPtr = Alloc;
+ }
} else {
// Targets that don't support recursion emit locals as globals.
const char *Class =
@@ -645,13 +675,15 @@ void CodeGenFunction::EmitLocalBlockVarDecl(const VarDecl &D) {
while (const ArrayType *Array = getContext().getAsArrayType(DtorTy))
DtorTy = getContext().getBaseElementType(Array);
if (const RecordType *RT = DtorTy->getAs<RecordType>())
- if (CXXRecordDecl *ClassDecl = dyn_cast<CXXRecordDecl>(RT->getDecl())) {
- llvm::Value *Loc = DeclPtr;
- if (isByRef)
- Loc = Builder.CreateStructGEP(DeclPtr, getByRefValueLLVMField(&D),
- D.getNameAsString());
-
+ if (CXXRecordDecl *ClassDecl = dyn_cast<CXXRecordDecl>(RT->getDecl())) {
if (!ClassDecl->hasTrivialDestructor()) {
+ // Note: We suppress the destructor call when the corresponding NRVO
+ // flag has been set.
+ llvm::Value *Loc = DeclPtr;
+ if (isByRef)
+ Loc = Builder.CreateStructGEP(DeclPtr, getByRefValueLLVMField(&D),
+ D.getNameAsString());
+
const CXXDestructorDecl *D = ClassDecl->getDestructor(getContext());
assert(D && "EmitLocalBlockVarDecl - destructor is nul");
@@ -680,13 +712,27 @@ void CodeGenFunction::EmitLocalBlockVarDecl(const VarDecl &D) {
}
} else {
{
+ // Normal destruction.
DelayedCleanupBlock Scope(*this);
+
+ if (NRVO) {
+ // If we exited via NRVO, we skip the destructor call.
+ llvm::BasicBlock *NoNRVO = createBasicBlock("nrvo.unused");
+ Builder.CreateCondBr(Builder.CreateLoad(NRVOFlag, "nrvo.val"),
+ Scope.getCleanupExitBlock(),
+ NoNRVO);
+ EmitBlock(NoNRVO);
+ }
+
+ // We don't call the destructor along the normal edge if we're
+ // applying the NRVO.
EmitCXXDestructorCall(D, Dtor_Complete, /*ForVirtualBase=*/false,
Loc);
// Make sure to jump to the exit block.
EmitBranch(Scope.getCleanupExitBlock());
}
+
if (Exceptions) {
EHCleanupBlock Cleanup(*this);
EmitCXXDestructorCall(D, Dtor_Complete, /*ForVirtualBase=*/false,
diff --git a/lib/CodeGen/CGDeclCXX.cpp b/lib/CodeGen/CGDeclCXX.cpp
index 6afa53868ecc..f94ddd988662 100644
--- a/lib/CodeGen/CGDeclCXX.cpp
+++ b/lib/CodeGen/CGDeclCXX.cpp
@@ -13,6 +13,8 @@
#include "CodeGenFunction.h"
#include "clang/CodeGen/CodeGenOptions.h"
+#include "llvm/Intrinsics.h"
+
using namespace clang;
using namespace CodeGen;
@@ -22,7 +24,6 @@ static void EmitDeclInit(CodeGenFunction &CGF, const VarDecl &D,
assert(!D.getType()->isReferenceType() &&
"Should not call EmitDeclInit on a reference!");
- CodeGenModule &CGM = CGF.CGM;
ASTContext &Context = CGF.getContext();
const Expr *Init = D.getInit();
@@ -36,41 +37,52 @@ static void EmitDeclInit(CodeGenFunction &CGF, const VarDecl &D,
CGF.EmitComplexExprIntoAddr(Init, DeclPtr, isVolatile);
} else {
CGF.EmitAggExpr(Init, DeclPtr, isVolatile);
-
- // Avoid generating destructor(s) for initialized objects.
- if (!isa<CXXConstructExpr>(Init))
- return;
-
- const ConstantArrayType *Array = Context.getAsConstantArrayType(T);
- if (Array)
- T = Context.getBaseElementType(Array);
-
- const RecordType *RT = T->getAs<RecordType>();
- if (!RT)
- return;
-
- CXXRecordDecl *RD = cast<CXXRecordDecl>(RT->getDecl());
- if (RD->hasTrivialDestructor())
- return;
-
- CXXDestructorDecl *Dtor = RD->getDestructor(Context);
-
- llvm::Constant *DtorFn;
- if (Array) {
- DtorFn =
- CodeGenFunction(CGM).GenerateCXXAggrDestructorHelper(Dtor,
- Array,
- DeclPtr);
- const llvm::Type *Int8PtrTy =
- llvm::Type::getInt8PtrTy(CGM.getLLVMContext());
- DeclPtr = llvm::Constant::getNullValue(Int8PtrTy);
- } else
- DtorFn = CGM.GetAddrOfCXXDestructor(Dtor, Dtor_Complete);
-
- CGF.EmitCXXGlobalDtorRegistration(DtorFn, DeclPtr);
}
}
+static void EmitDeclDestroy(CodeGenFunction &CGF, const VarDecl &D,
+ llvm::Constant *DeclPtr) {
+ CodeGenModule &CGM = CGF.CGM;
+ ASTContext &Context = CGF.getContext();
+
+ const Expr *Init = D.getInit();
+ QualType T = D.getType();
+ if (!CGF.hasAggregateLLVMType(T) || T->isAnyComplexType())
+ return;
+
+ // Avoid generating destructor(s) for initialized objects.
+ if (!isa<CXXConstructExpr>(Init))
+ return;
+
+ const ConstantArrayType *Array = Context.getAsConstantArrayType(T);
+ if (Array)
+ T = Context.getBaseElementType(Array);
+
+ const RecordType *RT = T->getAs<RecordType>();
+ if (!RT)
+ return;
+
+ CXXRecordDecl *RD = cast<CXXRecordDecl>(RT->getDecl());
+ if (RD->hasTrivialDestructor())
+ return;
+
+ CXXDestructorDecl *Dtor = RD->getDestructor(Context);
+
+ llvm::Constant *DtorFn;
+ if (Array) {
+ DtorFn =
+ CodeGenFunction(CGM).GenerateCXXAggrDestructorHelper(Dtor,
+ Array,
+ DeclPtr);
+ const llvm::Type *Int8PtrTy =
+ llvm::Type::getInt8PtrTy(CGM.getLLVMContext());
+ DeclPtr = llvm::Constant::getNullValue(Int8PtrTy);
+ } else
+ DtorFn = CGM.GetAddrOfCXXDestructor(Dtor, Dtor_Complete);
+
+ CGF.EmitCXXGlobalDtorRegistration(DtorFn, DeclPtr);
+}
+
void CodeGenFunction::EmitCXXGlobalVarDeclInit(const VarDecl &D,
llvm::Constant *DeclPtr) {
@@ -79,6 +91,7 @@ void CodeGenFunction::EmitCXXGlobalVarDeclInit(const VarDecl &D,
if (!T->isReferenceType()) {
EmitDeclInit(*this, D, DeclPtr);
+ EmitDeclDestroy(*this, D, DeclPtr);
return;
}
if (Init->isLvalue(getContext()) == Expr::LV_Valid) {
@@ -310,7 +323,10 @@ CodeGenFunction::EmitStaticCXXBlockVarDeclInit(const VarDecl &D,
EmitBlock(InitCheckBlock);
- if (ThreadsafeStatics) {
+ // Variables used when coping with thread-safe statics and exceptions.
+ llvm::BasicBlock *SavedLandingPad = 0;
+ llvm::BasicBlock *LandingPad = 0;
+ if (ThreadsafeStatics) {
// Call __cxa_guard_acquire.
V = Builder.CreateCall(getGuardAcquireFn(*this), GuardVariable);
@@ -319,14 +335,13 @@ CodeGenFunction::EmitStaticCXXBlockVarDeclInit(const VarDecl &D,
Builder.CreateCondBr(Builder.CreateIsNotNull(V, "tobool"),
InitBlock, EndBlock);
- EmitBlock(InitBlock);
-
if (Exceptions) {
- EHCleanupBlock Cleanup(*this);
-
- // Call __cxa_guard_abort.
- Builder.CreateCall(getGuardAbortFn(*this), GuardVariable);
+ SavedLandingPad = getInvokeDest();
+ LandingPad = createBasicBlock("guard.lpad");
+ setInvokeDest(LandingPad);
}
+
+ EmitBlock(InitBlock);
}
if (D.getType()->isReferenceType()) {
@@ -342,12 +357,68 @@ CodeGenFunction::EmitStaticCXXBlockVarDeclInit(const VarDecl &D,
if (ThreadsafeStatics) {
// Call __cxa_guard_release.
- Builder.CreateCall(getGuardReleaseFn(*this), GuardVariable);
+ Builder.CreateCall(getGuardReleaseFn(*this), GuardVariable);
} else {
llvm::Value *One =
llvm::ConstantInt::get(llvm::Type::getInt8Ty(VMContext), 1);
Builder.CreateStore(One, Builder.CreateBitCast(GuardVariable, PtrTy));
}
+ // Register the call to the destructor.
+ if (!D.getType()->isReferenceType())
+ EmitDeclDestroy(*this, D, GV);
+
+ if (ThreadsafeStatics && Exceptions) {
+ // If an exception is thrown during initialization, call __cxa_guard_abort
+ // along the exceptional edge.
+ EmitBranch(EndBlock);
+
+ // Construct the landing pad.
+ EmitBlock(LandingPad);
+
+ // Personality function and LLVM intrinsics.
+ llvm::Constant *Personality =
+ CGM.CreateRuntimeFunction(llvm::FunctionType::get(llvm::Type::getInt32Ty
+ (VMContext),
+ true),
+ "__gxx_personality_v0");
+ Personality = llvm::ConstantExpr::getBitCast(Personality, PtrToInt8Ty);
+ llvm::Value *llvm_eh_exception =
+ CGM.getIntrinsic(llvm::Intrinsic::eh_exception);
+ llvm::Value *llvm_eh_selector =
+ CGM.getIntrinsic(llvm::Intrinsic::eh_selector);
+
+ // Exception object
+ llvm::Value *Exc = Builder.CreateCall(llvm_eh_exception, "exc");
+ llvm::Value *RethrowPtr = CreateTempAlloca(Exc->getType(), "_rethrow");
+
+ // Call the selector function.
+ const llvm::PointerType *PtrToInt8Ty
+ = llvm::PointerType::getUnqual(llvm::Type::getInt8Ty(VMContext));
+ llvm::Constant *Null = llvm::ConstantPointerNull::get(PtrToInt8Ty);
+ llvm::Value* SelectorArgs[3] = { Exc, Personality, Null };
+ Builder.CreateCall(llvm_eh_selector, SelectorArgs, SelectorArgs + 3,
+ "selector");
+ Builder.CreateStore(Exc, RethrowPtr);
+
+ // Call __cxa_guard_abort along the exceptional edge.
+ Builder.CreateCall(getGuardAbortFn(*this), GuardVariable);
+
+ setInvokeDest(SavedLandingPad);
+
+ // Rethrow the current exception.
+ if (getInvokeDest()) {
+ llvm::BasicBlock *Cont = createBasicBlock("invoke.cont");
+ Builder.CreateInvoke(getUnwindResumeOrRethrowFn(), Cont,
+ getInvokeDest(),
+ Builder.CreateLoad(RethrowPtr));
+ EmitBlock(Cont);
+ } else
+ Builder.CreateCall(getUnwindResumeOrRethrowFn(),
+ Builder.CreateLoad(RethrowPtr));
+
+ Builder.CreateUnreachable();
+ }
+
EmitBlock(EndBlock);
}
diff --git a/lib/CodeGen/CGException.cpp b/lib/CodeGen/CGException.cpp
index c1d05bf233b2..ddc1c7743344 100644
--- a/lib/CodeGen/CGException.cpp
+++ b/lib/CodeGen/CGException.cpp
@@ -100,17 +100,17 @@ static llvm::Constant *getUnexpectedFn(CodeGenFunction &CGF) {
return CGF.CGM.CreateRuntimeFunction(FTy, "__cxa_call_unexpected");
}
-static llvm::Constant *getUnwindResumeOrRethrowFn(CodeGenFunction &CGF) {
- const llvm::Type *Int8PtrTy = llvm::Type::getInt8PtrTy(CGF.getLLVMContext());
+llvm::Constant *CodeGenFunction::getUnwindResumeOrRethrowFn() {
+ const llvm::Type *Int8PtrTy = llvm::Type::getInt8PtrTy(getLLVMContext());
std::vector<const llvm::Type*> Args(1, Int8PtrTy);
const llvm::FunctionType *FTy =
- llvm::FunctionType::get(llvm::Type::getVoidTy(CGF.getLLVMContext()), Args,
+ llvm::FunctionType::get(llvm::Type::getVoidTy(getLLVMContext()), Args,
false);
- if (CGF.CGM.getLangOptions().SjLjExceptions)
- return CGF.CGM.CreateRuntimeFunction(FTy, "_Unwind_SjLj_Resume");
- return CGF.CGM.CreateRuntimeFunction(FTy, "_Unwind_Resume_or_Rethrow");
+ if (CGM.getLangOptions().SjLjExceptions)
+ return CGM.CreateRuntimeFunction(FTy, "_Unwind_SjLj_Resume");
+ return CGM.CreateRuntimeFunction(FTy, "_Unwind_Resume_or_Rethrow");
}
static llvm::Constant *getTerminateFn(CodeGenFunction &CGF) {
@@ -119,7 +119,29 @@ static llvm::Constant *getTerminateFn(CodeGenFunction &CGF) {
const llvm::FunctionType *FTy =
llvm::FunctionType::get(llvm::Type::getVoidTy(CGF.getLLVMContext()), false);
- return CGF.CGM.CreateRuntimeFunction(FTy, "_ZSt9terminatev");
+ return CGF.CGM.CreateRuntimeFunction(FTy,
+ CGF.CGM.getLangOptions().CPlusPlus ? "_ZSt9terminatev" : "abort");
+}
+
+static llvm::Constant *getPersonalityFn(CodeGenModule &CGM) {
+ const char *PersonalityFnName = "__gcc_personality_v0";
+ LangOptions Opts = CGM.getLangOptions();
+ if (Opts.CPlusPlus)
+ PersonalityFnName = "__gxx_personality_v0";
+ else if (Opts.ObjC1) {
+ if (Opts.NeXTRuntime) {
+ if (Opts.ObjCNonFragileABI)
+ PersonalityFnName = "__gcc_personality_v0";
+ } else
+ PersonalityFnName = "__gnu_objc_personality_v0";
+ }
+
+ llvm::Constant *Personality =
+ CGM.CreateRuntimeFunction(llvm::FunctionType::get(llvm::Type::getInt32Ty(
+ CGM.getLLVMContext()),
+ true),
+ PersonalityFnName);
+ return llvm::ConstantExpr::getBitCast(Personality, CGM.PtrToInt8Ty);
}
// Emits an exception expression into the given location. This
@@ -324,12 +346,7 @@ void CodeGenFunction::EmitStartEHSpec(const Decl *D) {
if (!Proto->hasExceptionSpec())
return;
- llvm::Constant *Personality =
- CGM.CreateRuntimeFunction(llvm::FunctionType::get(llvm::Type::getInt32Ty
- (VMContext),
- true),
- "__gxx_personality_v0");
- Personality = llvm::ConstantExpr::getBitCast(Personality, PtrToInt8Ty);
+ llvm::Constant *Personality = getPersonalityFn(CGM);
llvm::Value *llvm_eh_exception =
CGM.getIntrinsic(llvm::Intrinsic::eh_exception);
llvm::Value *llvm_eh_selector =
@@ -397,7 +414,7 @@ void CodeGenFunction::EmitStartEHSpec(const Decl *D) {
if (Proto->getNumExceptions()) {
EmitBlock(Unwind);
- Builder.CreateCall(getUnwindResumeOrRethrowFn(*this),
+ Builder.CreateCall(getUnwindResumeOrRethrowFn(),
Builder.CreateLoad(RethrowPtr));
Builder.CreateUnreachable();
}
@@ -444,12 +461,7 @@ CodeGenFunction::EnterCXXTryStmt(const CXXTryStmt &S) {
void CodeGenFunction::ExitCXXTryStmt(const CXXTryStmt &S,
CXXTryStmtInfo TryInfo) {
// Pointer to the personality function
- llvm::Constant *Personality =
- CGM.CreateRuntimeFunction(llvm::FunctionType::get(llvm::Type::getInt32Ty
- (VMContext),
- true),
- "__gxx_personality_v0");
- Personality = llvm::ConstantExpr::getBitCast(Personality, PtrToInt8Ty);
+ llvm::Constant *Personality = getPersonalityFn(CGM);
llvm::Value *llvm_eh_exception =
CGM.getIntrinsic(llvm::Intrinsic::eh_exception);
llvm::Value *llvm_eh_selector =
@@ -631,12 +643,12 @@ void CodeGenFunction::ExitCXXTryStmt(const CXXTryStmt &S,
// here.
if (getInvokeDest()) {
llvm::BasicBlock *Cont = createBasicBlock("invoke.cont");
- Builder.CreateInvoke(getUnwindResumeOrRethrowFn(*this), Cont,
+ Builder.CreateInvoke(getUnwindResumeOrRethrowFn(), Cont,
getInvokeDest(),
Builder.CreateLoad(RethrowPtr));
EmitBlock(Cont);
} else
- Builder.CreateCall(getUnwindResumeOrRethrowFn(*this),
+ Builder.CreateCall(getUnwindResumeOrRethrowFn(),
Builder.CreateLoad(RethrowPtr));
Builder.CreateUnreachable();
@@ -654,12 +666,7 @@ CodeGenFunction::EHCleanupBlock::~EHCleanupBlock() {
// The libstdc++ personality function.
// TODO: generalize to work with other libraries.
- llvm::Constant *Personality =
- CGF.CGM.CreateRuntimeFunction(llvm::FunctionType::get(llvm::Type::getInt32Ty
- (CGF.VMContext),
- true),
- "__gxx_personality_v0");
- Personality = llvm::ConstantExpr::getBitCast(Personality, CGF.PtrToInt8Ty);
+ llvm::Constant *Personality = getPersonalityFn(CGF.CGM);
// %exception = call i8* @llvm.eh.exception()
// Magic intrinsic which tells gives us a handle to the caught
@@ -687,11 +694,11 @@ CodeGenFunction::EHCleanupBlock::~EHCleanupBlock() {
// Rethrow the exception.
if (CGF.getInvokeDest()) {
llvm::BasicBlock *Cont = CGF.createBasicBlock("invoke.cont");
- CGF.Builder.CreateInvoke(getUnwindResumeOrRethrowFn(CGF), Cont,
+ CGF.Builder.CreateInvoke(CGF.getUnwindResumeOrRethrowFn(), Cont,
CGF.getInvokeDest(), Exc);
CGF.EmitBlock(Cont);
} else
- CGF.Builder.CreateCall(getUnwindResumeOrRethrowFn(CGF), Exc);
+ CGF.Builder.CreateCall(CGF.getUnwindResumeOrRethrowFn(), Exc);
CGF.Builder.CreateUnreachable();
// Resume inserting where we started, but put the new cleanup
@@ -715,12 +722,7 @@ llvm::BasicBlock *CodeGenFunction::getTerminateHandler() {
llvm::BasicBlock::iterator SavedInsertPoint = Builder.GetInsertPoint();
Builder.ClearInsertionPoint();
- llvm::Constant *Personality =
- CGM.CreateRuntimeFunction(llvm::FunctionType::get(llvm::Type::getInt32Ty
- (VMContext),
- true),
- "__gxx_personality_v0");
- Personality = llvm::ConstantExpr::getBitCast(Personality, PtrToInt8Ty);
+ llvm::Constant *Personality = getPersonalityFn(CGM);
llvm::Value *llvm_eh_exception =
CGM.getIntrinsic(llvm::Intrinsic::eh_exception);
llvm::Value *llvm_eh_selector =
diff --git a/lib/CodeGen/CGExpr.cpp b/lib/CodeGen/CGExpr.cpp
index 9ade916f42b7..d67618bfca35 100644
--- a/lib/CodeGen/CGExpr.cpp
+++ b/lib/CodeGen/CGExpr.cpp
@@ -135,6 +135,39 @@ void CodeGenFunction::EmitAnyExprToMem(const Expr *E,
}
}
+/// \brief An adjustment to be made to the temporary created when emitting a
+/// reference binding, which accesses a particular subobject of that temporary.
+struct SubobjectAdjustment {
+ enum { DerivedToBaseAdjustment, FieldAdjustment } Kind;
+
+ union {
+ struct {
+ const CXXBaseSpecifierArray *BasePath;
+ const CXXRecordDecl *DerivedClass;
+ } DerivedToBase;
+
+ struct {
+ FieldDecl *Field;
+ unsigned CVRQualifiers;
+ } Field;
+ };
+
+ SubobjectAdjustment(const CXXBaseSpecifierArray *BasePath,
+ const CXXRecordDecl *DerivedClass)
+ : Kind(DerivedToBaseAdjustment)
+ {
+ DerivedToBase.BasePath = BasePath;
+ DerivedToBase.DerivedClass = DerivedClass;
+ }
+
+ SubobjectAdjustment(FieldDecl *Field, unsigned CVRQualifiers)
+ : Kind(FieldAdjustment)
+ {
+ this->Field.Field = Field;
+ this->Field.CVRQualifiers = CVRQualifiers;
+ }
+};
+
RValue CodeGenFunction::EmitReferenceBindingToExpr(const Expr* E,
bool IsInitializer) {
bool ShouldDestroyTemporaries = false;
@@ -174,19 +207,46 @@ RValue CodeGenFunction::EmitReferenceBindingToExpr(const Expr* E,
PopCXXTemporary();
}
} else {
- const CXXBaseSpecifierArray *BasePath = 0;
- const CXXRecordDecl *DerivedClassDecl = 0;
+ QualType ResultTy = E->getType();
- if (const CastExpr *CE =
- dyn_cast<CastExpr>(E->IgnoreParenNoopCasts(getContext()))) {
- if (CE->getCastKind() == CastExpr::CK_DerivedToBase) {
- E = CE->getSubExpr();
-
- BasePath = &CE->getBasePath();
- DerivedClassDecl =
- cast<CXXRecordDecl>(E->getType()->getAs<RecordType>()->getDecl());
+ llvm::SmallVector<SubobjectAdjustment, 2> Adjustments;
+ do {
+ if (const ParenExpr *PE = dyn_cast<ParenExpr>(E)) {
+ E = PE->getSubExpr();
+ continue;
+ }
+
+ if (const CastExpr *CE = dyn_cast<CastExpr>(E)) {
+ if ((CE->getCastKind() == CastExpr::CK_DerivedToBase ||
+ CE->getCastKind() == CastExpr::CK_UncheckedDerivedToBase) &&
+ E->getType()->isRecordType()) {
+ E = CE->getSubExpr();
+ CXXRecordDecl *Derived
+ = cast<CXXRecordDecl>(E->getType()->getAs<RecordType>()->getDecl());
+ Adjustments.push_back(SubobjectAdjustment(&CE->getBasePath(),
+ Derived));
+ continue;
+ }
+
+ if (CE->getCastKind() == CastExpr::CK_NoOp) {
+ E = CE->getSubExpr();
+ continue;
+ }
+ } else if (const MemberExpr *ME = dyn_cast<MemberExpr>(E)) {
+ if (ME->getBase()->isLvalue(getContext()) != Expr::LV_Valid &&
+ ME->getBase()->getType()->isRecordType()) {
+ if (FieldDecl *Field = dyn_cast<FieldDecl>(ME->getMemberDecl())) {
+ E = ME->getBase();
+ Adjustments.push_back(SubobjectAdjustment(Field,
+ E->getType().getCVRQualifiers()));
+ continue;
+ }
+ }
}
- }
+
+ // Nothing changed.
+ break;
+ } while (true);
Val = EmitAnyExprToTemp(E, /*IsAggLocVolatile=*/false,
IsInitializer);
@@ -225,13 +285,47 @@ RValue CodeGenFunction::EmitReferenceBindingToExpr(const Expr* E,
}
}
- // Check if need to perform the derived-to-base cast.
- if (BasePath) {
- llvm::Value *Derived = Val.getAggregateAddr();
- llvm::Value *Base =
- GetAddressOfBaseClass(Derived, DerivedClassDecl, *BasePath,
- /*NullCheckValue=*/false);
- return RValue::get(Base);
+ // Check if need to perform derived-to-base casts and/or field accesses, to
+ // get from the temporary object we created (and, potentially, for which we
+ // extended the lifetime) to the subobject we're binding the reference to.
+ if (!Adjustments.empty()) {
+ llvm::Value *Object = Val.getAggregateAddr();
+ for (unsigned I = Adjustments.size(); I != 0; --I) {
+ SubobjectAdjustment &Adjustment = Adjustments[I-1];
+ switch (Adjustment.Kind) {
+ case SubobjectAdjustment::DerivedToBaseAdjustment:
+ Object = GetAddressOfBaseClass(Object,
+ Adjustment.DerivedToBase.DerivedClass,
+ *Adjustment.DerivedToBase.BasePath,
+ /*NullCheckValue=*/false);
+ break;
+
+ case SubobjectAdjustment::FieldAdjustment: {
+ unsigned CVR = Adjustment.Field.CVRQualifiers;
+ LValue LV = EmitLValueForField(Object, Adjustment.Field.Field, CVR);
+ if (LV.isSimple()) {
+ Object = LV.getAddress();
+ break;
+ }
+
+ // For non-simple lvalues, we actually have to create a copy of
+ // the object we're binding to.
+ QualType T = Adjustment.Field.Field->getType().getNonReferenceType()
+ .getUnqualifiedType();
+ Object = CreateTempAlloca(ConvertType(T), "lv");
+ EmitStoreThroughLValue(EmitLoadOfLValue(LV, T),
+ LValue::MakeAddr(Object,
+ Qualifiers::fromCVRMask(CVR)),
+ T);
+ break;
+ }
+ }
+ }
+
+ const llvm::Type *ResultPtrTy
+ = llvm::PointerType::get(ConvertType(ResultTy), 0);
+ Object = Builder.CreateBitCast(Object, ResultPtrTy, "temp");
+ return RValue::get(Object);
}
}
@@ -309,8 +403,7 @@ EmitScalarPrePostIncDec(const UnaryOperator *E, LValue LV,
llvm::ConstantInt::get(llvm::Type::getInt32Ty(VMContext), AmountVal);
if (!isa<llvm::FunctionType>(PT->getElementType())) {
QualType PTEE = ValTy->getPointeeType();
- if (const ObjCInterfaceType *OIT =
- dyn_cast<ObjCInterfaceType>(PTEE)) {
+ if (const ObjCObjectType *OIT = PTEE->getAs<ObjCObjectType>()) {
// Handle interface types, which are not represented with a concrete
// type.
int size = getContext().getTypeSize(OIT) / 8;
@@ -1371,8 +1464,8 @@ LValue CodeGenFunction::EmitArraySubscriptExpr(const ArraySubscriptExpr *E) {
llvm::ConstantInt::get(Idx->getType(),
BaseTypeSize.getQuantity()));
Address = Builder.CreateInBoundsGEP(Base, Idx, "arrayidx");
- } else if (const ObjCInterfaceType *OIT =
- dyn_cast<ObjCInterfaceType>(E->getType())) {
+ } else if (const ObjCObjectType *OIT =
+ E->getType()->getAs<ObjCObjectType>()) {
llvm::Value *InterfaceSize =
llvm::ConstantInt::get(Idx->getType(),
getContext().getTypeSizeInChars(OIT).getQuantity());
@@ -1530,6 +1623,35 @@ LValue CodeGenFunction::EmitLValueForBitfield(llvm::Value* BaseValue,
Field->getType().getCVRQualifiers()|CVRQualifiers);
}
+/// EmitLValueForAnonRecordField - Given that the field is a member of
+/// an anonymous struct or union buried inside a record, and given
+/// that the base value is a pointer to the enclosing record, derive
+/// an lvalue for the ultimate field.
+LValue CodeGenFunction::EmitLValueForAnonRecordField(llvm::Value *BaseValue,
+ const FieldDecl *Field,
+ unsigned CVRQualifiers) {
+ llvm::SmallVector<const FieldDecl *, 8> Path;
+ Path.push_back(Field);
+
+ while (Field->getParent()->isAnonymousStructOrUnion()) {
+ const ValueDecl *VD = Field->getParent()->getAnonymousStructOrUnionObject();
+ if (!isa<FieldDecl>(VD)) break;
+ Field = cast<FieldDecl>(VD);
+ Path.push_back(Field);
+ }
+
+ llvm::SmallVectorImpl<const FieldDecl*>::reverse_iterator
+ I = Path.rbegin(), E = Path.rend();
+ while (true) {
+ LValue LV = EmitLValueForField(BaseValue, *I, CVRQualifiers);
+ if (++I == E) return LV;
+
+ assert(LV.isSimple());
+ BaseValue = LV.getAddress();
+ CVRQualifiers |= LV.getVRQualifiers();
+ }
+}
+
LValue CodeGenFunction::EmitLValueForField(llvm::Value* BaseValue,
const FieldDecl* Field,
unsigned CVRQualifiers) {
@@ -1670,7 +1792,17 @@ LValue CodeGenFunction::EmitCastLValue(const CastExpr *E) {
MakeQualifiers(E->getType()));
}
- case CastExpr::CK_NoOp:
+ case CastExpr::CK_NoOp: {
+ LValue LV = EmitLValue(E->getSubExpr());
+ if (LV.isPropertyRef()) {
+ QualType QT = E->getSubExpr()->getType();
+ RValue RV = EmitLoadOfPropertyRefLValue(LV, QT);
+ assert(!RV.isScalar() && "EmitCastLValue - scalar cast of property ref");
+ llvm::Value *V = RV.getAggregateAddr();
+ return LValue::MakeAddr(V, MakeQualifiers(QT));
+ }
+ return LV;
+ }
case CastExpr::CK_ConstructorConversion:
case CastExpr::CK_UserDefinedConversion:
case CastExpr::CK_AnyPointerToObjCPointerCast:
@@ -1724,7 +1856,7 @@ LValue CodeGenFunction::EmitNullInitializationLValue(
const CXXZeroInitValueExpr *E) {
QualType Ty = E->getType();
LValue LV = LValue::MakeAddr(CreateMemTemp(Ty), MakeQualifiers(Ty));
- EmitMemSetToZero(LV.getAddress(), Ty);
+ EmitNullInitialization(LV.getAddress(), Ty);
return LV;
}
diff --git a/lib/CodeGen/CGExprAgg.cpp b/lib/CodeGen/CGExprAgg.cpp
index d1b0dff11e5a..a4e64fb3d638 100644
--- a/lib/CodeGen/CGExprAgg.cpp
+++ b/lib/CodeGen/CGExprAgg.cpp
@@ -37,6 +37,16 @@ class AggExprEmitter : public StmtVisitor<AggExprEmitter> {
bool IgnoreResult;
bool IsInitializer;
bool RequiresGCollection;
+
+ ReturnValueSlot getReturnValueSlot() const {
+ // If the destination slot requires garbage collection, we can't
+ // use the real return value slot, because we have to use the GC
+ // API.
+ if (RequiresGCollection) return ReturnValueSlot();
+
+ return ReturnValueSlot(DestPtr, VolatileDest);
+ }
+
public:
AggExprEmitter(CodeGenFunction &cgf, llvm::Value *destPtr, bool v,
bool ignore, bool isinit, bool requiresGCollection)
@@ -58,6 +68,10 @@ public:
void EmitFinalDestCopy(const Expr *E, LValue Src, bool Ignore = false);
void EmitFinalDestCopy(const Expr *E, RValue Src, bool Ignore = false);
+ void EmitGCMove(const Expr *E, RValue Src);
+
+ bool TypeRequiresGCollection(QualType T);
+
//===--------------------------------------------------------------------===//
// Visitor Methods
//===--------------------------------------------------------------------===//
@@ -137,6 +151,39 @@ void AggExprEmitter::EmitAggLoadOfLValue(const Expr *E) {
EmitFinalDestCopy(E, LV);
}
+/// \brief True if the given aggregate type requires special GC API calls.
+bool AggExprEmitter::TypeRequiresGCollection(QualType T) {
+ // Only record types have members that might require garbage collection.
+ const RecordType *RecordTy = T->getAs<RecordType>();
+ if (!RecordTy) return false;
+
+ // Don't mess with non-trivial C++ types.
+ RecordDecl *Record = RecordTy->getDecl();
+ if (isa<CXXRecordDecl>(Record) &&
+ (!cast<CXXRecordDecl>(Record)->hasTrivialCopyConstructor() ||
+ !cast<CXXRecordDecl>(Record)->hasTrivialDestructor()))
+ return false;
+
+ // Check whether the type has an object member.
+ return Record->hasObjectMember();
+}
+
+/// \brief Perform the final move to DestPtr if RequiresGCollection is set.
+///
+/// The idea is that you do something like this:
+/// RValue Result = EmitSomething(..., getReturnValueSlot());
+/// EmitGCMove(E, Result);
+/// If GC doesn't interfere, this will cause the result to be emitted
+/// directly into the return value slot. If GC does interfere, a final
+/// move will be performed.
+void AggExprEmitter::EmitGCMove(const Expr *E, RValue Src) {
+ if (!RequiresGCollection) return;
+
+ CGF.CGM.getObjCRuntime().EmitGCMemmoveCollectable(CGF, DestPtr,
+ Src.getAggregateAddr(),
+ E->getType());
+}
+
/// EmitFinalDestCopy - Perform the final copy to DestPtr, if desired.
void AggExprEmitter::EmitFinalDestCopy(const Expr *E, RValue Src, bool Ignore) {
assert(Src.isAggregate() && "value must be aggregate value!");
@@ -178,7 +225,7 @@ void AggExprEmitter::EmitFinalDestCopy(const Expr *E, LValue Src, bool Ignore) {
//===----------------------------------------------------------------------===//
void AggExprEmitter::VisitCastExpr(CastExpr *E) {
- if (!DestPtr) {
+ if (!DestPtr && E->getCastKind() != CastExpr::CK_Dynamic) {
Visit(E->getSubExpr());
return;
}
@@ -186,6 +233,20 @@ void AggExprEmitter::VisitCastExpr(CastExpr *E) {
switch (E->getCastKind()) {
default: assert(0 && "Unhandled cast kind!");
+ case CastExpr::CK_Dynamic: {
+ assert(isa<CXXDynamicCastExpr>(E) && "CK_Dynamic without a dynamic_cast?");
+ LValue LV = CGF.EmitCheckedLValue(E->getSubExpr());
+ // FIXME: Do we also need to handle property references here?
+ if (LV.isSimple())
+ CGF.EmitDynamicCast(LV.getAddress(), cast<CXXDynamicCastExpr>(E));
+ else
+ CGF.CGM.ErrorUnsupported(E, "non-simple lvalue dynamic_cast");
+
+ if (DestPtr)
+ CGF.CGM.ErrorUnsupported(E, "lvalue dynamic_cast with a destination");
+ break;
+ }
+
case CastExpr::CK_ToUnion: {
// GCC union extension
QualType PtrTy =
@@ -198,6 +259,14 @@ void AggExprEmitter::VisitCastExpr(CastExpr *E) {
break;
}
+ case CastExpr::CK_DerivedToBase:
+ case CastExpr::CK_BaseToDerived:
+ case CastExpr::CK_UncheckedDerivedToBase: {
+ assert(0 && "cannot perform hierarchy conversion in EmitAggExpr: "
+ "should have been unpacked before we got here");
+ break;
+ }
+
// FIXME: Remove the CK_Unknown check here.
case CastExpr::CK_Unknown:
case CastExpr::CK_NoOp:
@@ -282,31 +351,24 @@ void AggExprEmitter::VisitCallExpr(const CallExpr *E) {
return;
}
- // If the struct doesn't require GC, we can just pass the destination
- // directly to EmitCall.
- if (!RequiresGCollection) {
- CGF.EmitCallExpr(E, ReturnValueSlot(DestPtr, VolatileDest));
- return;
- }
-
- RValue RV = CGF.EmitCallExpr(E);
- EmitFinalDestCopy(E, RV);
+ RValue RV = CGF.EmitCallExpr(E, getReturnValueSlot());
+ EmitGCMove(E, RV);
}
void AggExprEmitter::VisitObjCMessageExpr(ObjCMessageExpr *E) {
- RValue RV = CGF.EmitObjCMessageExpr(E);
- EmitFinalDestCopy(E, RV);
+ RValue RV = CGF.EmitObjCMessageExpr(E, getReturnValueSlot());
+ EmitGCMove(E, RV);
}
void AggExprEmitter::VisitObjCPropertyRefExpr(ObjCPropertyRefExpr *E) {
- RValue RV = CGF.EmitObjCPropertyGet(E);
- EmitFinalDestCopy(E, RV);
+ RValue RV = CGF.EmitObjCPropertyGet(E, getReturnValueSlot());
+ EmitGCMove(E, RV);
}
void AggExprEmitter::VisitObjCImplicitSetterGetterRefExpr(
ObjCImplicitSetterGetterRefExpr *E) {
- RValue RV = CGF.EmitObjCPropertyGet(E);
- EmitFinalDestCopy(E, RV);
+ RValue RV = CGF.EmitObjCPropertyGet(E, getReturnValueSlot());
+ EmitGCMove(E, RV);
}
void AggExprEmitter::VisitBinComma(const BinaryOperator *E) {
@@ -412,11 +474,9 @@ void AggExprEmitter::VisitBinAssign(const BinaryOperator *E) {
RValue::getAggregate(AggLoc, VolatileDest));
} else {
bool RequiresGCollection = false;
- if (CGF.getContext().getLangOptions().NeXTRuntime) {
- QualType LHSTy = E->getLHS()->getType();
- if (const RecordType *FDTTy = LHSTy.getTypePtr()->getAs<RecordType>())
- RequiresGCollection = FDTTy->getDecl()->hasObjectMember();
- }
+ if (CGF.getContext().getLangOptions().getGCMode())
+ RequiresGCollection = TypeRequiresGCollection(E->getLHS()->getType());
+
// Codegen the RHS so that it stores directly into the LHS.
CGF.EmitAggExpr(E->getRHS(), LHS.getAddress(), LHS.isVolatileQualified(),
false, false, RequiresGCollection);
@@ -559,14 +619,10 @@ void AggExprEmitter::EmitNullInitializationToLValue(LValue LV, QualType T) {
llvm::Value *Null = llvm::Constant::getNullValue(CGF.ConvertType(T));
CGF.EmitStoreThroughLValue(RValue::get(Null), LV, T);
} else {
- // Otherwise, just memset the whole thing to zero. This is legal
- // because in LLVM, all default initializers are guaranteed to have a
- // bit pattern of all zeros.
- // FIXME: That isn't true for member pointers!
// There's a potential optimization opportunity in combining
// memsets; that would be easy for arrays, but relatively
// difficult for structures with the current code.
- CGF.EmitMemSetToZero(LV.getAddress(), T);
+ CGF.EmitNullInitialization(LV.getAddress(), T);
}
}
@@ -738,21 +794,20 @@ LValue CodeGenFunction::EmitAggExprToLValue(const Expr *E) {
return LValue::MakeAddr(Temp, Q);
}
-void CodeGenFunction::EmitAggregateClear(llvm::Value *DestPtr, QualType Ty) {
- assert(!Ty->isAnyComplexType() && "Shouldn't happen for complex");
-
- EmitMemSetToZero(DestPtr, Ty);
-}
-
void CodeGenFunction::EmitAggregateCopy(llvm::Value *DestPtr,
llvm::Value *SrcPtr, QualType Ty,
bool isVolatile) {
assert(!Ty->isAnyComplexType() && "Shouldn't happen for complex");
- // Ignore empty classes in C++.
if (getContext().getLangOptions().CPlusPlus) {
if (const RecordType *RT = Ty->getAs<RecordType>()) {
- if (cast<CXXRecordDecl>(RT->getDecl())->isEmpty())
+ CXXRecordDecl *Record = cast<CXXRecordDecl>(RT->getDecl());
+ assert((Record->hasTrivialCopyConstructor() ||
+ Record->hasTrivialCopyAssignment()) &&
+ "Trying to aggregate-copy a type without a trivial copy "
+ "constructor or assignment operator");
+ // Ignore empty classes in C++.
+ if (Record->isEmpty())
return;
}
}
diff --git a/lib/CodeGen/CGExprCXX.cpp b/lib/CodeGen/CGExprCXX.cpp
index b57cdc93340e..f93c79c74267 100644
--- a/lib/CodeGen/CGExprCXX.cpp
+++ b/lib/CodeGen/CGExprCXX.cpp
@@ -12,6 +12,7 @@
//===----------------------------------------------------------------------===//
#include "CodeGenFunction.h"
+#include "CGObjCRuntime.h"
using namespace clang;
using namespace CodeGen;
@@ -255,16 +256,29 @@ CodeGenFunction::EmitCXXOperatorMemberCallExpr(const CXXOperatorCallExpr *E,
ReturnValueSlot ReturnValue) {
assert(MD->isInstance() &&
"Trying to emit a member call expr on a static method!");
-
if (MD->isCopyAssignment()) {
const CXXRecordDecl *ClassDecl = cast<CXXRecordDecl>(MD->getDeclContext());
if (ClassDecl->hasTrivialCopyAssignment()) {
assert(!ClassDecl->hasUserDeclaredCopyAssignment() &&
"EmitCXXOperatorMemberCallExpr - user declared copy assignment");
- llvm::Value *This = EmitLValue(E->getArg(0)).getAddress();
+ LValue LV = EmitLValue(E->getArg(0));
+ llvm::Value *This;
+ if (LV.isPropertyRef()) {
+ llvm::Value *AggLoc = CreateMemTemp(E->getArg(1)->getType());
+ EmitAggExpr(E->getArg(1), AggLoc, false /*VolatileDest*/);
+ EmitObjCPropertySet(LV.getPropertyRefExpr(),
+ RValue::getAggregate(AggLoc, false /*VolatileDest*/));
+ return RValue::getAggregate(0, false);
+ }
+ else
+ This = LV.getAddress();
+
llvm::Value *Src = EmitLValue(E->getArg(1)).getAddress();
QualType Ty = E->getType();
- EmitAggregateCopy(This, Src, Ty);
+ if (ClassDecl->hasObjectMember())
+ CGM.getObjCRuntime().EmitGCMemmoveCollectable(*this, This, Src, Ty);
+ else
+ EmitAggregateCopy(This, Src, Ty);
return RValue::get(This);
}
}
@@ -273,8 +287,15 @@ CodeGenFunction::EmitCXXOperatorMemberCallExpr(const CXXOperatorCallExpr *E,
const llvm::Type *Ty =
CGM.getTypes().GetFunctionType(CGM.getTypes().getFunctionInfo(MD),
FPT->isVariadic());
-
- llvm::Value *This = EmitLValue(E->getArg(0)).getAddress();
+ LValue LV = EmitLValue(E->getArg(0));
+ llvm::Value *This;
+ if (LV.isPropertyRef()) {
+ RValue RV = EmitLoadOfPropertyRefLValue(LV, E->getArg(0)->getType());
+ assert (!RV.isScalar() && "EmitCXXOperatorMemberCallExpr");
+ This = RV.getAggregateAddr();
+ }
+ else
+ This = LV.getAddress();
llvm::Value *Callee;
if (MD->isVirtual() && !canDevirtualizeMemberFunctionCalls(E->getArg(0)))
@@ -305,11 +326,13 @@ CodeGenFunction::EmitCXXConstructExpr(llvm::Value *Dest,
return;
}
// Code gen optimization to eliminate copy constructor and return
- // its first argument instead.
+ // its first argument instead, if in fact that argument is a temporary
+ // object.
if (getContext().getLangOptions().ElideConstructors && E->isElidable()) {
- const Expr *Arg = E->getArg(0)->getTemporaryObject();
- EmitAggExpr(Arg, Dest, false);
- return;
+ if (const Expr *Arg = E->getArg(0)->getTemporaryObject()) {
+ EmitAggExpr(Arg, Dest, false);
+ return;
+ }
}
if (Array) {
QualType BaseElementTy = getContext().getBaseElementType(Array);
@@ -851,6 +874,8 @@ llvm::Value *CodeGenFunction::EmitDynamicCast(llvm::Value *V,
ToVoid = true;
} else {
LTy = LTy->getPointerTo();
+
+ // FIXME: What if exceptions are disabled?
ThrowOnBad = true;
}
@@ -917,15 +942,21 @@ llvm::Value *CodeGenFunction::EmitDynamicCast(llvm::Value *V,
if (ThrowOnBad) {
BadCastBlock = createBasicBlock();
-
Builder.CreateCondBr(Builder.CreateIsNotNull(V), ContBlock, BadCastBlock);
EmitBlock(BadCastBlock);
- /// Call __cxa_bad_cast
+ /// Invoke __cxa_bad_cast
ResultType = llvm::Type::getVoidTy(VMContext);
const llvm::FunctionType *FBadTy;
FBadTy = llvm::FunctionType::get(ResultType, false);
llvm::Value *F = CGM.CreateRuntimeFunction(FBadTy, "__cxa_bad_cast");
- Builder.CreateCall(F)->setDoesNotReturn();
+ if (llvm::BasicBlock *InvokeDest = getInvokeDest()) {
+ llvm::BasicBlock *Cont = createBasicBlock("invoke.cont");
+ Builder.CreateInvoke(F, Cont, InvokeDest)->setDoesNotReturn();
+ EmitBlock(Cont);
+ } else {
+ // FIXME: Does this ever make sense?
+ Builder.CreateCall(F)->setDoesNotReturn();
+ }
Builder.CreateUnreachable();
}
}
diff --git a/lib/CodeGen/CGExprConstant.cpp b/lib/CodeGen/CGExprConstant.cpp
index 2595ff0060ca..551a47aa9f80 100644
--- a/lib/CodeGen/CGExprConstant.cpp
+++ b/lib/CodeGen/CGExprConstant.cpp
@@ -984,32 +984,81 @@ llvm::Constant *CodeGenModule::EmitConstantExpr(const Expr *E,
return C;
}
-static bool containsPointerToDataMember(CodeGenTypes &Types, QualType T) {
- // No need to check for member pointers when not compiling C++.
- if (!Types.getContext().getLangOptions().CPlusPlus)
- return false;
-
- T = Types.getContext().getBaseElementType(T);
-
- 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);
+static void
+FillInNullDataMemberPointers(CodeGenModule &CGM, QualType T,
+ std::vector<llvm::Constant *> &Elements,
+ uint64_t StartOffset) {
+ assert(StartOffset % 8 == 0 && "StartOffset not byte aligned!");
+
+ if (!CGM.getTypes().ContainsPointerToDataMember(T))
+ return;
+
+ if (const ConstantArrayType *CAT =
+ CGM.getContext().getAsConstantArrayType(T)) {
+ QualType ElementTy = CAT->getElementType();
+ uint64_t ElementSize = CGM.getContext().getTypeSize(ElementTy);
- const CGRecordLayout &Layout = Types.getCGRecordLayout(RD);
- return Layout.containsPointerToDataMember();
- }
+ for (uint64_t I = 0, E = CAT->getSize().getZExtValue(); I != E; ++I) {
+ FillInNullDataMemberPointers(CGM, ElementTy, Elements,
+ StartOffset + I * ElementSize);
+ }
+ } else if (const RecordType *RT = T->getAs<RecordType>()) {
+ const CXXRecordDecl *RD = cast<CXXRecordDecl>(RT->getDecl());
+ const ASTRecordLayout &Layout = CGM.getContext().getASTRecordLayout(RD);
+
+ // Go through all bases and fill in any null pointer to data members.
+ for (CXXRecordDecl::base_class_const_iterator I = RD->bases_begin(),
+ E = RD->bases_end(); I != E; ++I) {
+ assert(!I->isVirtual() && "Should not see virtual bases here!");
+
+ const CXXRecordDecl *BaseDecl =
+ cast<CXXRecordDecl>(I->getType()->getAs<RecordType>()->getDecl());
+
+ // Ignore empty bases.
+ if (BaseDecl->isEmpty())
+ continue;
+
+ // Ignore bases that don't have any pointer to data members.
+ if (!CGM.getTypes().ContainsPointerToDataMember(BaseDecl))
+ continue;
+
+ uint64_t BaseOffset = Layout.getBaseClassOffset(BaseDecl);
+ FillInNullDataMemberPointers(CGM, I->getType(),
+ Elements, StartOffset + BaseOffset);
+ }
- if (const MemberPointerType *MPT = T->getAs<MemberPointerType>())
- return !MPT->getPointeeType()->isFunctionType();
+ // Visit all fields.
+ unsigned FieldNo = 0;
+ for (RecordDecl::field_iterator I = RD->field_begin(),
+ E = RD->field_end(); I != E; ++I, ++FieldNo) {
+ QualType FieldType = I->getType();
+
+ if (!CGM.getTypes().ContainsPointerToDataMember(FieldType))
+ continue;
+
+ uint64_t FieldOffset = StartOffset + Layout.getFieldOffset(FieldNo);
+ FillInNullDataMemberPointers(CGM, FieldType, Elements, FieldOffset);
+ }
+ } else {
+ assert(T->isMemberPointerType() && "Should only see member pointers here!");
+ assert(!T->getAs<MemberPointerType>()->getPointeeType()->isFunctionType() &&
+ "Should only see pointers to data members here!");
- return false;
+ uint64_t StartIndex = StartOffset / 8;
+ uint64_t EndIndex = StartIndex + CGM.getContext().getTypeSize(T) / 8;
+
+ llvm::Constant *NegativeOne =
+ llvm::ConstantInt::get(llvm::Type::getInt8Ty(CGM.getLLVMContext()),
+ -1ULL, /*isSigned=*/true);
+
+ // Fill in the null data member pointer.
+ for (uint64_t I = StartIndex; I != EndIndex; ++I)
+ Elements[I] = NegativeOne;
+ }
}
llvm::Constant *CodeGenModule::EmitNullConstant(QualType T) {
- if (!containsPointerToDataMember(getTypes(), T))
+ if (!getTypes().ContainsPointerToDataMember(T))
return llvm::Constant::getNullValue(getTypes().ConvertTypeForMem(T));
if (const ConstantArrayType *CAT = Context.getAsConstantArrayType(T)) {
@@ -1029,21 +1078,60 @@ llvm::Constant *CodeGenModule::EmitNullConstant(QualType T) {
if (const RecordType *RT = T->getAs<RecordType>()) {
const CXXRecordDecl *RD = cast<CXXRecordDecl>(RT->getDecl());
- assert(!RD->getNumBases() &&
- "FIXME: Handle zero-initializing structs with bases and "
- "pointers to data members.");
const llvm::StructType *STy =
cast<llvm::StructType>(getTypes().ConvertTypeForMem(T));
unsigned NumElements = STy->getNumElements();
std::vector<llvm::Constant *> Elements(NumElements);
+ const CGRecordLayout &Layout = getTypes().getCGRecordLayout(RD);
+
+ // Go through all bases and fill in any null pointer to data members.
+ for (CXXRecordDecl::base_class_const_iterator I = RD->bases_begin(),
+ E = RD->bases_end(); I != E; ++I) {
+ assert(!I->isVirtual() && "Should not see virtual bases here!");
+
+ const CXXRecordDecl *BaseDecl =
+ cast<CXXRecordDecl>(I->getType()->getAs<RecordType>()->getDecl());
+
+ // Ignore empty bases.
+ if (BaseDecl->isEmpty())
+ continue;
+
+ // Ignore bases that don't have any pointer to data members.
+ if (!getTypes().ContainsPointerToDataMember(BaseDecl))
+ continue;
+
+ // Currently, all bases are arrays of i8. Figure out how many elements
+ // this base array has.
+ unsigned BaseFieldNo = Layout.getNonVirtualBaseLLVMFieldNo(BaseDecl);
+ const llvm::ArrayType *BaseArrayTy =
+ cast<llvm::ArrayType>(STy->getElementType(BaseFieldNo));
+
+ unsigned NumBaseElements = BaseArrayTy->getNumElements();
+ std::vector<llvm::Constant *> BaseElements(NumBaseElements);
+
+ // Now fill in null data member pointers.
+ FillInNullDataMemberPointers(*this, I->getType(), BaseElements, 0);
+
+ // Now go through all other elements and zero them out.
+ if (NumBaseElements) {
+ llvm::Constant *Zero =
+ llvm::ConstantInt::get(llvm::Type::getInt8Ty(getLLVMContext()), 0);
+
+ for (unsigned I = 0; I != NumBaseElements; ++I) {
+ if (!BaseElements[I])
+ BaseElements[I] = Zero;
+ }
+ }
+
+ Elements[BaseFieldNo] = llvm::ConstantArray::get(BaseArrayTy,
+ BaseElements);
+ }
+
for (RecordDecl::field_iterator I = RD->field_begin(),
E = RD->field_end(); I != E; ++I) {
const FieldDecl *FD = *I;
-
- const CGRecordLayout &RL =
- getTypes().getCGRecordLayout(FD->getParent());
- unsigned FieldNo = RL.getLLVMFieldNo(FD);
+ unsigned FieldNo = Layout.getLLVMFieldNo(FD);
Elements[FieldNo] = EmitNullConstant(FD->getType());
}
@@ -1056,6 +1144,7 @@ llvm::Constant *CodeGenModule::EmitNullConstant(QualType T) {
return llvm::ConstantStruct::get(STy, Elements);
}
+ assert(T->isMemberPointerType() && "Should only see member pointers here!");
assert(!T->getAs<MemberPointerType>()->getPointeeType()->isFunctionType() &&
"Should only see pointers to data members here!");
diff --git a/lib/CodeGen/CGExprScalar.cpp b/lib/CodeGen/CGExprScalar.cpp
index 984968802382..2108414c5ae6 100644
--- a/lib/CodeGen/CGExprScalar.cpp
+++ b/lib/CodeGen/CGExprScalar.cpp
@@ -96,6 +96,9 @@ public:
Value *EmitComplexToScalarConversion(CodeGenFunction::ComplexPairTy Src,
QualType SrcTy, QualType DstTy);
+ /// EmitNullValue - Emit a value that corresponds to null for the given type.
+ Value *EmitNullValue(QualType Ty);
+
//===--------------------------------------------------------------------===//
// Visitor Methods
//===--------------------------------------------------------------------===//
@@ -123,10 +126,10 @@ public:
return llvm::ConstantInt::get(ConvertType(E->getType()), E->getValue());
}
Value *VisitCXXZeroInitValueExpr(const CXXZeroInitValueExpr *E) {
- return llvm::Constant::getNullValue(ConvertType(E->getType()));
+ return EmitNullValue(E->getType());
}
Value *VisitGNUNullExpr(const GNUNullExpr *E) {
- return llvm::Constant::getNullValue(ConvertType(E->getType()));
+ return EmitNullValue(E->getType());
}
Value *VisitTypesCompatibleExpr(const TypesCompatibleExpr *E) {
return llvm::ConstantInt::get(ConvertType(E->getType()),
@@ -186,7 +189,7 @@ public:
Value *VisitInitListExpr(InitListExpr *E);
Value *VisitImplicitValueInitExpr(const ImplicitValueInitExpr *E) {
- return llvm::Constant::getNullValue(ConvertType(E->getType()));
+ return CGF.CGM.EmitNullConstant(E->getType());
}
Value *VisitCastExpr(CastExpr *E) {
// Make sure to evaluate VLA bounds now so that we have them for later.
@@ -278,7 +281,7 @@ public:
}
Value *VisitCXXNullPtrLiteralExpr(const CXXNullPtrLiteralExpr *E) {
- return llvm::Constant::getNullValue(ConvertType(E->getType()));
+ return EmitNullValue(E->getType());
}
Value *VisitCXXThrowExpr(const CXXThrowExpr *E) {
@@ -549,6 +552,19 @@ EmitComplexToScalarConversion(CodeGenFunction::ComplexPairTy Src,
return EmitScalarConversion(Src.first, SrcTy, DstTy);
}
+Value *ScalarExprEmitter::EmitNullValue(QualType Ty) {
+ const llvm::Type *LTy = ConvertType(Ty);
+
+ if (!Ty->isMemberPointerType())
+ return llvm::Constant::getNullValue(LTy);
+
+ assert(!Ty->isMemberFunctionPointerType() &&
+ "member function pointers are not scalar!");
+
+ // Itanium C++ ABI 2.3:
+ // A NULL pointer is represented as -1.
+ return llvm::ConstantInt::get(LTy, -1ULL, /*isSigned=*/true);
+}
//===----------------------------------------------------------------------===//
// Visitor Methods
@@ -1334,7 +1350,7 @@ Value *ScalarExprEmitter::EmitAdd(const BinOpInfo &Ops) {
}
const QualType ElementType = PT ? PT->getPointeeType() : OPT->getPointeeType();
// Handle interface types, which are not represented with a concrete type.
- if (const ObjCInterfaceType *OIT = dyn_cast<ObjCInterfaceType>(ElementType)) {
+ if (const ObjCObjectType *OIT = ElementType->getAs<ObjCObjectType>()) {
llvm::Value *InterfaceSize =
llvm::ConstantInt::get(Idx->getType(),
CGF.getContext().getTypeSizeInChars(OIT).getQuantity());
@@ -1402,8 +1418,7 @@ Value *ScalarExprEmitter::EmitSub(const BinOpInfo &Ops) {
Idx = Builder.CreateNeg(Idx, "sub.ptr.neg");
// Handle interface types, which are not represented with a concrete type.
- if (const ObjCInterfaceType *OIT =
- dyn_cast<ObjCInterfaceType>(LHSElementType)) {
+ if (const ObjCObjectType *OIT = LHSElementType->getAs<ObjCObjectType>()) {
llvm::Value *InterfaceSize =
llvm::ConstantInt::get(Idx->getType(),
CGF.getContext().
diff --git a/lib/CodeGen/CGObjC.cpp b/lib/CodeGen/CGObjC.cpp
index 8426f7105be4..7c842a94986c 100644
--- a/lib/CodeGen/CGObjC.cpp
+++ b/lib/CodeGen/CGObjC.cpp
@@ -47,7 +47,8 @@ llvm::Value *CodeGenFunction::EmitObjCProtocolExpr(const ObjCProtocolExpr *E) {
}
-RValue CodeGenFunction::EmitObjCMessageExpr(const ObjCMessageExpr *E) {
+RValue CodeGenFunction::EmitObjCMessageExpr(const ObjCMessageExpr *E,
+ ReturnValueSlot Return) {
// Only the lookup mechanism and first two arguments of the method
// implementation vary between runtimes. We can get the receiver and
// arguments in generic code.
@@ -64,10 +65,11 @@ RValue CodeGenFunction::EmitObjCMessageExpr(const ObjCMessageExpr *E) {
break;
case ObjCMessageExpr::Class: {
- const ObjCInterfaceType *IFace
- = E->getClassReceiver()->getAs<ObjCInterfaceType>();
- OID = IFace->getDecl();
- assert(IFace && "Invalid Objective-C class message send");
+ const ObjCObjectType *ObjTy
+ = E->getClassReceiver()->getAs<ObjCObjectType>();
+ assert(ObjTy && "Invalid Objective-C class message send");
+ OID = ObjTy->getInterface();
+ assert(OID && "Invalid Objective-C class message send");
Receiver = Runtime.GetClass(Builder, OID);
isClassMessage = true;
break;
@@ -92,7 +94,7 @@ RValue CodeGenFunction::EmitObjCMessageExpr(const ObjCMessageExpr *E) {
// super is only valid in an Objective-C method
const ObjCMethodDecl *OMD = cast<ObjCMethodDecl>(CurFuncDecl);
bool isCategoryImpl = isa<ObjCCategoryImplDecl>(OMD->getDeclContext());
- return Runtime.GenerateMessageSendSuper(*this, E->getType(),
+ return Runtime.GenerateMessageSendSuper(*this, Return, E->getType(),
E->getSelector(),
OMD->getClassInterface(),
isCategoryImpl,
@@ -102,7 +104,8 @@ RValue CodeGenFunction::EmitObjCMessageExpr(const ObjCMessageExpr *E) {
E->getMethodDecl());
}
- return Runtime.GenerateMessageSend(*this, E->getType(), E->getSelector(),
+ return Runtime.GenerateMessageSend(*this, Return, E->getType(),
+ E->getSelector(),
Receiver, Args, OID,
E->getMethodDecl());
}
@@ -157,9 +160,6 @@ void CodeGenFunction::GenerateObjCGetter(ObjCImplementationDecl *IMP,
!(PD->getPropertyAttributes() & ObjCPropertyDecl::OBJC_PR_nonatomic);
ObjCMethodDecl *OMD = PD->getGetterMethodDecl();
assert(OMD && "Invalid call to generate getter (empty method)");
- // FIXME: This is rather murky, we create this here since they will not have
- // been created by Sema for us.
- OMD->createImplicitParams(getContext(), IMP->getClassInterface());
StartObjCMethod(OMD, IMP->getClassInterface());
// Determine if we should use an objc_getProperty call for
@@ -208,8 +208,9 @@ void CodeGenFunction::GenerateObjCGetter(ObjCImplementationDecl *IMP,
Types.ConvertType(PD->getType())));
EmitReturnOfRValue(RV, PD->getType());
} else {
- LValue LV = EmitLValueForIvar(TypeOfSelfObject(), LoadObjCSelf(), Ivar, 0);
if (Ivar->getType()->isAnyComplexType()) {
+ LValue LV = EmitLValueForIvar(TypeOfSelfObject(), LoadObjCSelf(),
+ Ivar, 0);
ComplexPairTy Pair = LoadComplexFromAddr(LV.getAddress(),
LV.isVolatileQualified());
StoreComplexToAddr(Pair, ReturnValue, LV.isVolatileQualified());
@@ -219,6 +220,8 @@ void CodeGenFunction::GenerateObjCGetter(ObjCImplementationDecl *IMP,
if ((IsAtomic || (IsStrong = IvarTypeWithAggrGCObjects(Ivar->getType())))
&& CurFnInfo->getReturnInfo().getKind() == ABIArgInfo::Indirect
&& CGM.getObjCRuntime().GetCopyStructFunction()) {
+ LValue LV = EmitLValueForIvar(TypeOfSelfObject(), LoadObjCSelf(),
+ Ivar, 0);
llvm::Value *GetCopyStructFn =
CGM.getObjCRuntime().GetCopyStructFunction();
CodeGenTypes &Types = CGM.getTypes();
@@ -251,9 +254,23 @@ void CodeGenFunction::GenerateObjCGetter(ObjCImplementationDecl *IMP,
FunctionType::ExtInfo()),
GetCopyStructFn, ReturnValueSlot(), Args);
}
- else
- EmitAggregateCopy(ReturnValue, LV.getAddress(), Ivar->getType());
+ else {
+ if (PID->getGetterCXXConstructor()) {
+ ReturnStmt *Stmt =
+ new (getContext()) ReturnStmt(SourceLocation(),
+ PID->getGetterCXXConstructor(),
+ 0);
+ EmitReturnStmt(*Stmt);
+ }
+ else {
+ LValue LV = EmitLValueForIvar(TypeOfSelfObject(), LoadObjCSelf(),
+ Ivar, 0);
+ EmitAggregateCopy(ReturnValue, LV.getAddress(), Ivar->getType());
+ }
+ }
} else {
+ LValue LV = EmitLValueForIvar(TypeOfSelfObject(), LoadObjCSelf(),
+ Ivar, 0);
CodeGenTypes &Types = CGM.getTypes();
RValue RV = EmitLoadOfLValue(LV, Ivar->getType());
RV = RValue::get(Builder.CreateBitCast(RV.getScalarVal(),
@@ -274,9 +291,6 @@ void CodeGenFunction::GenerateObjCSetter(ObjCImplementationDecl *IMP,
const ObjCPropertyDecl *PD = PID->getPropertyDecl();
ObjCMethodDecl *OMD = PD->getSetterMethodDecl();
assert(OMD && "Invalid call to generate setter (empty method)");
- // FIXME: This is rather murky, we create this here since they will not have
- // been created by Sema for us.
- OMD->createImplicitParams(getContext(), IMP->getClassInterface());
StartObjCMethod(OMD, IMP->getClassInterface());
bool IsCopy = PD->getSetterKind() == ObjCPropertyDecl::Copy;
@@ -368,6 +382,10 @@ void CodeGenFunction::GenerateObjCSetter(ObjCImplementationDecl *IMP,
EmitCall(Types.getFunctionInfo(getContext().VoidTy, Args,
FunctionType::ExtInfo()),
GetCopyStructFn, ReturnValueSlot(), Args);
+ } else if (PID->getSetterCXXAssignment()) {
+ EmitAnyExpr(PID->getSetterCXXAssignment(), (llvm::Value *)0, false, true,
+ false);
+
} else {
// FIXME: Find a clean way to avoid AST node creation.
SourceLocation Loc = PD->getLocation();
@@ -425,8 +443,7 @@ void CodeGenFunction::GenerateObjCCtorDtorMethod(ObjCImplementationDecl *IMP,
llvm::Value *SelfAsId =
Builder.CreateBitCast(LoadObjCSelf(), Types.ConvertType(IdTy));
EmitReturnOfRValue(RValue::get(SelfAsId), IdTy);
- }
- else {
+ } else {
// dtor
for (size_t i = IvarInitializers.size(); i > 0; --i) {
FieldDecl *Field = IvarInitializers[i - 1]->getMember();
@@ -442,7 +459,7 @@ void CodeGenFunction::GenerateObjCCtorDtorMethod(ObjCImplementationDecl *IMP,
const RecordType *RT = FieldType->getAs<RecordType>();
CXXRecordDecl *FieldClassDecl = cast<CXXRecordDecl>(RT->getDecl());
CXXDestructorDecl *Dtor = FieldClassDecl->getDestructor(getContext());
- if (!Dtor->isTrivial())
+ if (!Dtor->isTrivial()) {
if (Array) {
const llvm::Type *BasePtr = ConvertType(FieldType);
BasePtr = llvm::PointerType::getUnqual(BasePtr);
@@ -450,12 +467,13 @@ void CodeGenFunction::GenerateObjCCtorDtorMethod(ObjCImplementationDecl *IMP,
Builder.CreateBitCast(LV.getAddress(), BasePtr);
EmitCXXAggrDestructorCall(Dtor,
Array, BaseAddrPtr);
- }
- else
+ } else {
EmitCXXDestructorCall(Dtor,
Dtor_Complete, /*ForVirtualBase=*/false,
LV.getAddress());
- }
+ }
+ }
+ }
}
FinishFunction();
}
@@ -478,8 +496,6 @@ bool CodeGenFunction::IvarTypeWithAggrGCObjects(QualType Ty) {
llvm::Value *CodeGenFunction::LoadObjCSelf() {
const ObjCMethodDecl *OMD = cast<ObjCMethodDecl>(CurFuncDecl);
- // See if we need to lazily forward self inside a block literal.
- BlockForwardSelf();
return Builder.CreateLoad(LocalDeclMap[OMD->getSelfDecl()], "self");
}
@@ -492,12 +508,14 @@ QualType CodeGenFunction::TypeOfSelfObject() {
}
RValue CodeGenFunction::EmitObjCSuperPropertyGet(const Expr *Exp,
- const Selector &S) {
+ const Selector &S,
+ ReturnValueSlot Return) {
llvm::Value *Receiver = LoadObjCSelf();
const ObjCMethodDecl *OMD = cast<ObjCMethodDecl>(CurFuncDecl);
bool isClassMessage = OMD->isClassMethod();
bool isCategoryImpl = isa<ObjCCategoryImplDecl>(OMD->getDeclContext());
return CGM.getObjCRuntime().GenerateMessageSendSuper(*this,
+ Return,
Exp->getType(),
S,
OMD->getClassInterface(),
@@ -508,15 +526,16 @@ RValue CodeGenFunction::EmitObjCSuperPropertyGet(const Expr *Exp,
}
-RValue CodeGenFunction::EmitObjCPropertyGet(const Expr *Exp) {
+RValue CodeGenFunction::EmitObjCPropertyGet(const Expr *Exp,
+ ReturnValueSlot Return) {
Exp = Exp->IgnoreParens();
// FIXME: Split it into two separate routines.
if (const ObjCPropertyRefExpr *E = dyn_cast<ObjCPropertyRefExpr>(Exp)) {
Selector S = E->getProperty()->getGetterName();
if (isa<ObjCSuperExpr>(E->getBase()))
- return EmitObjCSuperPropertyGet(E, S);
+ return EmitObjCSuperPropertyGet(E, S, Return);
return CGM.getObjCRuntime().
- GenerateMessageSend(*this, Exp->getType(), S,
+ GenerateMessageSend(*this, Return, Exp->getType(), S,
EmitScalarExpr(E->getBase()),
CallArgList());
} else {
@@ -528,11 +547,11 @@ RValue CodeGenFunction::EmitObjCPropertyGet(const Expr *Exp) {
const ObjCInterfaceDecl *OID = KE->getInterfaceDecl();
Receiver = CGM.getObjCRuntime().GetClass(Builder, OID);
} else if (isa<ObjCSuperExpr>(KE->getBase()))
- return EmitObjCSuperPropertyGet(KE, S);
+ return EmitObjCSuperPropertyGet(KE, S, Return);
else
Receiver = EmitScalarExpr(KE->getBase());
return CGM.getObjCRuntime().
- GenerateMessageSend(*this, Exp->getType(), S,
+ GenerateMessageSend(*this, Return, Exp->getType(), S,
Receiver,
CallArgList(), KE->getInterfaceDecl());
}
@@ -548,6 +567,7 @@ void CodeGenFunction::EmitObjCSuperPropertySet(const Expr *Exp,
bool isCategoryImpl = isa<ObjCCategoryImplDecl>(OMD->getDeclContext());
Args.push_back(std::make_pair(Src, Exp->getType()));
CGM.getObjCRuntime().GenerateMessageSendSuper(*this,
+ ReturnValueSlot(),
Exp->getType(),
S,
OMD->getClassInterface(),
@@ -569,7 +589,8 @@ void CodeGenFunction::EmitObjCPropertySet(const Expr *Exp,
}
CallArgList Args;
Args.push_back(std::make_pair(Src, E->getType()));
- CGM.getObjCRuntime().GenerateMessageSend(*this, getContext().VoidTy, S,
+ CGM.getObjCRuntime().GenerateMessageSend(*this, ReturnValueSlot(),
+ getContext().VoidTy, S,
EmitScalarExpr(E->getBase()),
Args);
} else if (const ObjCImplicitSetterGetterRefExpr *E =
@@ -586,7 +607,8 @@ void CodeGenFunction::EmitObjCPropertySet(const Expr *Exp,
} else
Receiver = EmitScalarExpr(E->getBase());
Args.push_back(std::make_pair(Src, E->getType()));
- CGM.getObjCRuntime().GenerateMessageSend(*this, getContext().VoidTy, S,
+ CGM.getObjCRuntime().GenerateMessageSend(*this, ReturnValueSlot(),
+ getContext().VoidTy, S,
Receiver,
Args, E->getInterfaceDecl());
} else
@@ -618,7 +640,7 @@ void CodeGenFunction::EmitObjCForCollectionStmt(const ObjCForCollectionStmt &S){
// Fast enumeration state.
QualType StateTy = getContext().getObjCFastEnumerationStateType();
llvm::Value *StatePtr = CreateMemTemp(StateTy, "state.ptr");
- EmitMemSetToZero(StatePtr, StateTy);
+ EmitNullInitialization(StatePtr, StateTy);
// Number of elements in the items array.
static const unsigned NumItems = 16;
@@ -653,7 +675,7 @@ void CodeGenFunction::EmitObjCForCollectionStmt(const ObjCForCollectionStmt &S){
getContext().UnsignedLongTy));
RValue CountRV =
- CGM.getObjCRuntime().GenerateMessageSend(*this,
+ CGM.getObjCRuntime().GenerateMessageSend(*this, ReturnValueSlot(),
getContext().UnsignedLongTy,
FastEnumSel,
Collection, Args);
@@ -778,7 +800,7 @@ void CodeGenFunction::EmitObjCForCollectionStmt(const ObjCForCollectionStmt &S){
EmitBlock(FetchMore);
CountRV =
- CGM.getObjCRuntime().GenerateMessageSend(*this,
+ CGM.getObjCRuntime().GenerateMessageSend(*this, ReturnValueSlot(),
getContext().UnsignedLongTy,
FastEnumSel,
Collection, Args);
diff --git a/lib/CodeGen/CGObjCGNU.cpp b/lib/CodeGen/CGObjCGNU.cpp
index 3c51b7ee9de7..6c25afeb9ad3 100644
--- a/lib/CodeGen/CGObjCGNU.cpp
+++ b/lib/CodeGen/CGObjCGNU.cpp
@@ -142,6 +142,7 @@ public:
virtual llvm::Constant *GenerateConstantString(const StringLiteral *);
virtual CodeGen::RValue
GenerateMessageSend(CodeGen::CodeGenFunction &CGF,
+ ReturnValueSlot Return,
QualType ResultType,
Selector Sel,
llvm::Value *Receiver,
@@ -150,6 +151,7 @@ public:
const ObjCMethodDecl *Method);
virtual CodeGen::RValue
GenerateMessageSendSuper(CodeGen::CodeGenFunction &CGF,
+ ReturnValueSlot Return,
QualType ResultType,
Selector Sel,
const ObjCInterfaceDecl *Class,
@@ -235,6 +237,21 @@ static std::string SymbolNameForMethod(const std::string &ClassName, const
return std::string(isClassMethod ? "_c_" : "_i_") + ClassName + "_" +
CategoryName + "_" + MethodNameColonStripped;
}
+static std::string MangleSelectorTypes(const std::string &TypeString) {
+ std::string Mangled = TypeString;
+ // Simple mangling to avoid breaking when we mix JIT / static code.
+ // Not part of the ABI, subject to change without notice.
+ std::replace(Mangled.begin(), Mangled.end(), '@', '_');
+ std::replace(Mangled.begin(), Mangled.end(), ':', 'J');
+ std::replace(Mangled.begin(), Mangled.end(), '*', 'e');
+ std::replace(Mangled.begin(), Mangled.end(), '#', 'E');
+ std::replace(Mangled.begin(), Mangled.end(), ':', 'j');
+ std::replace(Mangled.begin(), Mangled.end(), '(', 'g');
+ std::replace(Mangled.begin(), Mangled.end(), ')', 'G');
+ std::replace(Mangled.begin(), Mangled.end(), '[', 'h');
+ std::replace(Mangled.begin(), Mangled.end(), ']', 'H');
+ return Mangled;
+}
CGObjCGNU::CGObjCGNU(CodeGen::CodeGenModule &cgm)
: CGM(cgm), TheModule(CGM.getModule()), ClassPtrAlias(0),
@@ -440,6 +457,7 @@ llvm::Constant *CGObjCGNU::GenerateConstantString(const StringLiteral *SL) {
///should be called.
CodeGen::RValue
CGObjCGNU::GenerateMessageSendSuper(CodeGen::CodeGenFunction &CGF,
+ ReturnValueSlot Return,
QualType ResultType,
Selector Sel,
const ObjCInterfaceDecl *Class,
@@ -567,7 +585,7 @@ CGObjCGNU::GenerateMessageSendSuper(CodeGen::CodeGenFunction &CGF,
llvm::MDNode *node = llvm::MDNode::get(VMContext, impMD, 3);
llvm::Instruction *call;
- RValue msgRet = CGF.EmitCall(FnInfo, imp, ReturnValueSlot(), ActualArgs,
+ RValue msgRet = CGF.EmitCall(FnInfo, imp, Return, ActualArgs,
0, &call);
call->setMetadata(msgSendMDKind, node);
return msgRet;
@@ -576,6 +594,7 @@ CGObjCGNU::GenerateMessageSendSuper(CodeGen::CodeGenFunction &CGF,
/// Generate code for a message send expression.
CodeGen::RValue
CGObjCGNU::GenerateMessageSend(CodeGen::CodeGenFunction &CGF,
+ ReturnValueSlot Return,
QualType ResultType,
Selector Sel,
llvm::Value *Receiver,
@@ -611,16 +630,16 @@ CGObjCGNU::GenerateMessageSend(CodeGen::CodeGenFunction &CGF,
llvm::BasicBlock *startBB = 0;
llvm::BasicBlock *messageBB = 0;
- llvm::BasicBlock *contiueBB = 0;
+ llvm::BasicBlock *continueBB = 0;
if (!isPointerSizedReturn) {
startBB = Builder.GetInsertBlock();
messageBB = CGF.createBasicBlock("msgSend");
- contiueBB = CGF.createBasicBlock("continue");
+ continueBB = CGF.createBasicBlock("continue");
llvm::Value *isNil = Builder.CreateICmpEQ(Receiver,
llvm::Constant::getNullValue(Receiver->getType()));
- Builder.CreateCondBr(isNil, contiueBB, messageBB);
+ Builder.CreateCondBr(isNil, continueBB, messageBB);
CGF.EmitBlock(messageBB);
}
@@ -711,12 +730,15 @@ CGObjCGNU::GenerateMessageSend(CodeGen::CodeGenFunction &CGF,
cast<llvm::CallInst>(imp)->setMetadata(msgSendMDKind, node);
}
llvm::Instruction *call;
- RValue msgRet = CGF.EmitCall(FnInfo, imp, ReturnValueSlot(), ActualArgs,
+ RValue msgRet = CGF.EmitCall(FnInfo, imp, Return, ActualArgs,
0, &call);
call->setMetadata(msgSendMDKind, node);
+
if (!isPointerSizedReturn) {
- CGF.EmitBlock(contiueBB);
+ messageBB = CGF.Builder.GetInsertBlock();
+ CGF.Builder.CreateBr(continueBB);
+ CGF.EmitBlock(continueBB);
if (msgRet.isScalar()) {
llvm::Value *v = msgRet.getScalarVal();
llvm::PHINode *phi = Builder.CreatePHI(v->getType());
@@ -1665,34 +1687,36 @@ llvm::Function *CGObjCGNU::ModuleInitFunction() {
llvm::Constant *Idxs[] = {Zeros[0],
llvm::ConstantInt::get(llvm::Type::getInt32Ty(VMContext), index++), Zeros[0]};
llvm::Constant *SelPtr = new llvm::GlobalVariable(TheModule, SelStructPtrTy,
- true, llvm::GlobalValue::InternalLinkage,
- llvm::ConstantExpr::getGetElementPtr(SelectorList, Idxs, 2),
- ".objc_sel_ptr");
+ true, llvm::GlobalValue::LinkOnceODRLinkage,
+ llvm::ConstantExpr::getGetElementPtr(SelectorList, Idxs, 2),
+ MangleSelectorTypes(".objc_sel_ptr"+iter->first.first+"."+
+ iter->first.second));
// If selectors are defined as an opaque type, cast the pointer to this
// type.
if (isSelOpaque) {
SelPtr = llvm::ConstantExpr::getBitCast(SelPtr,
llvm::PointerType::getUnqual(SelectorTy));
}
- (*iter).second->setAliasee(SelPtr);
+ (*iter).second->replaceAllUsesWith(SelPtr);
+ (*iter).second->eraseFromParent();
}
for (llvm::StringMap<llvm::GlobalAlias*>::iterator
iter=UntypedSelectors.begin(), iterEnd = UntypedSelectors.end();
iter != iterEnd; iter++) {
llvm::Constant *Idxs[] = {Zeros[0],
llvm::ConstantInt::get(llvm::Type::getInt32Ty(VMContext), index++), Zeros[0]};
- llvm::Constant *SelPtr = new llvm::GlobalVariable
- (TheModule, SelStructPtrTy,
- true, llvm::GlobalValue::InternalLinkage,
- llvm::ConstantExpr::getGetElementPtr(SelectorList, Idxs, 2),
- ".objc_sel_ptr");
+ llvm::Constant *SelPtr = new llvm::GlobalVariable(TheModule, SelStructPtrTy,
+ true, llvm::GlobalValue::LinkOnceODRLinkage,
+ llvm::ConstantExpr::getGetElementPtr(SelectorList, Idxs, 2),
+ MangleSelectorTypes(std::string(".objc_sel_ptr")+iter->getKey().str()));
// If selectors are defined as an opaque type, cast the pointer to this
// type.
if (isSelOpaque) {
SelPtr = llvm::ConstantExpr::getBitCast(SelPtr,
llvm::PointerType::getUnqual(SelectorTy));
}
- (*iter).second->setAliasee(SelPtr);
+ (*iter).second->replaceAllUsesWith(SelPtr);
+ (*iter).second->eraseFromParent();
}
// Number of classes defined.
Elements.push_back(llvm::ConstantInt::get(llvm::Type::getInt16Ty(VMContext),
@@ -1922,11 +1946,11 @@ void CGObjCGNU::EmitTryOrSynchronizedStmt(CodeGen::CodeGenFunction &CGF,
const ObjCObjectPointerType *OPT =
CatchDecl->getType()->getAs<ObjCObjectPointerType>();
assert(OPT && "Invalid @catch type.");
- const ObjCInterfaceType *IT =
- OPT->getPointeeType()->getAs<ObjCInterfaceType>();
- assert(IT && "Invalid @catch type.");
+ const ObjCInterfaceDecl *IDecl =
+ OPT->getObjectType()->getInterface();
+ assert(IDecl && "Invalid @catch type.");
llvm::Value *EHType =
- MakeConstantString(IT->getDecl()->getNameAsString());
+ MakeConstantString(IDecl->getNameAsString());
ESelArgs.push_back(EHType);
}
}
@@ -2208,7 +2232,8 @@ LValue CGObjCGNU::EmitObjCValueForIvar(CodeGen::CodeGenFunction &CGF,
llvm::Value *BaseValue,
const ObjCIvarDecl *Ivar,
unsigned CVRQualifiers) {
- const ObjCInterfaceDecl *ID = ObjectTy->getAs<ObjCInterfaceType>()->getDecl();
+ const ObjCInterfaceDecl *ID =
+ ObjectTy->getAs<ObjCObjectType>()->getInterface();
return EmitValueForIvarAtOffset(CGF, ID, BaseValue, Ivar, CVRQualifiers,
EmitIvarOffset(CGF, ID, Ivar));
}
diff --git a/lib/CodeGen/CGObjCMac.cpp b/lib/CodeGen/CGObjCMac.cpp
index 77eabbfd4141..d3bafd7eda78 100644
--- a/lib/CodeGen/CGObjCMac.cpp
+++ b/lib/CodeGen/CGObjCMac.cpp
@@ -973,6 +973,7 @@ protected:
bool AddToUsed);
CodeGen::RValue EmitLegacyMessageSend(CodeGen::CodeGenFunction &CGF,
+ ReturnValueSlot Return,
QualType ResultType,
llvm::Value *Sel,
llvm::Value *Arg0,
@@ -1039,6 +1040,7 @@ private:
llvm::Value *EmitSuperClassRef(const ObjCInterfaceDecl *ID);
CodeGen::RValue EmitMessageSend(CodeGen::CodeGenFunction &CGF,
+ ReturnValueSlot Return,
QualType ResultType,
Selector Sel,
llvm::Value *Arg0,
@@ -1126,6 +1128,7 @@ public:
virtual llvm::Function *ModuleInitFunction();
virtual CodeGen::RValue GenerateMessageSend(CodeGen::CodeGenFunction &CGF,
+ ReturnValueSlot Return,
QualType ResultType,
Selector Sel,
llvm::Value *Receiver,
@@ -1135,6 +1138,7 @@ public:
virtual CodeGen::RValue
GenerateMessageSendSuper(CodeGen::CodeGenFunction &CGF,
+ ReturnValueSlot Return,
QualType ResultType,
Selector Sel,
const ObjCInterfaceDecl *Class,
@@ -1279,6 +1283,7 @@ private:
ObjCProtocolDecl::protocol_iterator end);
CodeGen::RValue EmitMessageSend(CodeGen::CodeGenFunction &CGF,
+ ReturnValueSlot Return,
QualType ResultType,
Selector Sel,
llvm::Value *Receiver,
@@ -1354,6 +1359,7 @@ public:
virtual llvm::Function *ModuleInitFunction();
virtual CodeGen::RValue GenerateMessageSend(CodeGen::CodeGenFunction &CGF,
+ ReturnValueSlot Return,
QualType ResultType,
Selector Sel,
llvm::Value *Receiver,
@@ -1363,6 +1369,7 @@ public:
virtual CodeGen::RValue
GenerateMessageSendSuper(CodeGen::CodeGenFunction &CGF,
+ ReturnValueSlot Return,
QualType ResultType,
Selector Sel,
const ObjCInterfaceDecl *Class,
@@ -1515,6 +1522,7 @@ llvm::Constant *CGObjCCommonMac::GenerateConstantString(
/// which class's method should be called.
CodeGen::RValue
CGObjCMac::GenerateMessageSendSuper(CodeGen::CodeGenFunction &CGF,
+ ReturnValueSlot Return,
QualType ResultType,
Selector Sel,
const ObjCInterfaceDecl *Class,
@@ -1566,7 +1574,7 @@ CGObjCMac::GenerateMessageSendSuper(CodeGen::CodeGenFunction &CGF,
Target = CGF.Builder.CreateBitCast(Target, ClassTy);
CGF.Builder.CreateStore(Target,
CGF.Builder.CreateStructGEP(ObjCSuper, 1));
- return EmitLegacyMessageSend(CGF, ResultType,
+ return EmitLegacyMessageSend(CGF, Return, ResultType,
EmitSelector(CGF.Builder, Sel),
ObjCSuper, ObjCTypes.SuperPtrCTy,
true, CallArgs, Method, ObjCTypes);
@@ -1574,13 +1582,14 @@ CGObjCMac::GenerateMessageSendSuper(CodeGen::CodeGenFunction &CGF,
/// Generate code for a message send expression.
CodeGen::RValue CGObjCMac::GenerateMessageSend(CodeGen::CodeGenFunction &CGF,
+ ReturnValueSlot Return,
QualType ResultType,
Selector Sel,
llvm::Value *Receiver,
const CallArgList &CallArgs,
const ObjCInterfaceDecl *Class,
const ObjCMethodDecl *Method) {
- return EmitLegacyMessageSend(CGF, ResultType,
+ return EmitLegacyMessageSend(CGF, Return, ResultType,
EmitSelector(CGF.Builder, Sel),
Receiver, CGF.getContext().getObjCIdType(),
false, CallArgs, Method, ObjCTypes);
@@ -1588,6 +1597,7 @@ CodeGen::RValue CGObjCMac::GenerateMessageSend(CodeGen::CodeGenFunction &CGF,
CodeGen::RValue
CGObjCCommonMac::EmitLegacyMessageSend(CodeGen::CodeGenFunction &CGF,
+ ReturnValueSlot Return,
QualType ResultType,
llvm::Value *Sel,
llvm::Value *Arg0,
@@ -1634,7 +1644,7 @@ CGObjCCommonMac::EmitLegacyMessageSend(CodeGen::CodeGenFunction &CGF,
assert(Fn && "EmitLegacyMessageSend - unknown API");
Fn = llvm::ConstantExpr::getBitCast(Fn,
llvm::PointerType::getUnqual(FTy));
- return CGF.EmitCall(FnInfo, Fn, ReturnValueSlot(), ActualArgs);
+ return CGF.EmitCall(FnInfo, Fn, Return, ActualArgs);
}
llvm::Value *CGObjCMac::GenerateProtocolRef(CGBuilderTy &Builder,
@@ -2701,12 +2711,12 @@ void CGObjCMac::EmitTryOrSynchronizedStmt(CodeGen::CodeGenFunction &CGF,
}
assert(OPT && "Unexpected non-object pointer type in @catch");
- QualType T = OPT->getPointeeType();
- const ObjCInterfaceType *ObjCType = T->getAs<ObjCInterfaceType>();
- assert(ObjCType && "Catch parameter must have Objective-C type!");
+ const ObjCObjectType *ObjTy = OPT->getObjectType();
+ ObjCInterfaceDecl *IDecl = ObjTy->getInterface();
+ assert(IDecl && "Catch parameter must have Objective-C type!");
// Check if the @catch block matches the exception object.
- llvm::Value *Class = EmitClassRef(CGF.Builder, ObjCType->getDecl());
+ llvm::Value *Class = EmitClassRef(CGF.Builder, IDecl);
llvm::Value *Match =
CGF.Builder.CreateCall2(ObjCTypes.getExceptionMatchFn(),
@@ -2938,7 +2948,8 @@ LValue CGObjCMac::EmitObjCValueForIvar(CodeGen::CodeGenFunction &CGF,
llvm::Value *BaseValue,
const ObjCIvarDecl *Ivar,
unsigned CVRQualifiers) {
- const ObjCInterfaceDecl *ID = ObjectTy->getAs<ObjCInterfaceType>()->getDecl();
+ const ObjCInterfaceDecl *ID =
+ ObjectTy->getAs<ObjCObjectType>()->getInterface();
return EmitValueForIvarAtOffset(CGF, ID, BaseValue, Ivar, CVRQualifiers,
EmitIvarOffset(CGF, ID, Ivar));
}
@@ -3669,7 +3680,7 @@ ObjCCommonTypesHelper::ObjCCommonTypesHelper(CodeGen::CodeGenModule &cgm)
// id self;
// Class cls;
// }
- RecordDecl *RD = RecordDecl::Create(Ctx, TagDecl::TK_struct,
+ RecordDecl *RD = RecordDecl::Create(Ctx, TTK_Struct,
Ctx.getTranslationUnitDecl(),
SourceLocation(),
&Ctx.Idents.get("_objc_super"));
@@ -4131,7 +4142,7 @@ ObjCNonFragileABITypesHelper::ObjCNonFragileABITypesHelper(CodeGen::CodeGenModul
// };
// First the clang type for struct _message_ref_t
- RecordDecl *RD = RecordDecl::Create(Ctx, TagDecl::TK_struct,
+ RecordDecl *RD = RecordDecl::Create(Ctx, TTK_Struct,
Ctx.getTranslationUnitDecl(),
SourceLocation(),
&Ctx.Idents.get("_message_ref_t"));
@@ -5095,12 +5106,12 @@ CGObjCNonFragileABIMac::GetMethodDescriptionConstant(const ObjCMethodDecl *MD) {
/// @encode
///
LValue CGObjCNonFragileABIMac::EmitObjCValueForIvar(
- CodeGen::CodeGenFunction &CGF,
- QualType ObjectTy,
- llvm::Value *BaseValue,
- const ObjCIvarDecl *Ivar,
- unsigned CVRQualifiers) {
- const ObjCInterfaceDecl *ID = ObjectTy->getAs<ObjCInterfaceType>()->getDecl();
+ CodeGen::CodeGenFunction &CGF,
+ QualType ObjectTy,
+ llvm::Value *BaseValue,
+ const ObjCIvarDecl *Ivar,
+ unsigned CVRQualifiers) {
+ ObjCInterfaceDecl *ID = ObjectTy->getAs<ObjCObjectType>()->getInterface();
return EmitValueForIvarAtOffset(CGF, ID, BaseValue, Ivar, CVRQualifiers,
EmitIvarOffset(CGF, ID, Ivar));
}
@@ -5114,6 +5125,7 @@ llvm::Value *CGObjCNonFragileABIMac::EmitIvarOffset(
CodeGen::RValue CGObjCNonFragileABIMac::EmitMessageSend(
CodeGen::CodeGenFunction &CGF,
+ ReturnValueSlot Return,
QualType ResultType,
Selector Sel,
llvm::Value *Receiver,
@@ -5213,12 +5225,13 @@ CodeGen::RValue CGObjCNonFragileABIMac::EmitMessageSend(
const llvm::FunctionType *FTy = Types.GetFunctionType(FnInfo1, true);
Callee = CGF.Builder.CreateBitCast(Callee,
llvm::PointerType::getUnqual(FTy));
- return CGF.EmitCall(FnInfo1, Callee, ReturnValueSlot(), ActualArgs);
+ return CGF.EmitCall(FnInfo1, Callee, Return, ActualArgs);
}
/// Generate code for a message send expression in the nonfragile abi.
CodeGen::RValue
CGObjCNonFragileABIMac::GenerateMessageSend(CodeGen::CodeGenFunction &CGF,
+ ReturnValueSlot Return,
QualType ResultType,
Selector Sel,
llvm::Value *Receiver,
@@ -5226,10 +5239,11 @@ CGObjCNonFragileABIMac::GenerateMessageSend(CodeGen::CodeGenFunction &CGF,
const ObjCInterfaceDecl *Class,
const ObjCMethodDecl *Method) {
return LegacyDispatchedSelector(Sel)
- ? EmitLegacyMessageSend(CGF, ResultType, EmitSelector(CGF.Builder, Sel),
+ ? EmitLegacyMessageSend(CGF, Return, ResultType,
+ EmitSelector(CGF.Builder, Sel),
Receiver, CGF.getContext().getObjCIdType(),
false, CallArgs, Method, ObjCTypes)
- : EmitMessageSend(CGF, ResultType, Sel,
+ : EmitMessageSend(CGF, Return, ResultType, Sel,
Receiver, CGF.getContext().getObjCIdType(),
false, CallArgs);
}
@@ -5336,6 +5350,7 @@ llvm::Value *CGObjCNonFragileABIMac::GetClass(CGBuilderTy &Builder,
/// which class's method should be called.
CodeGen::RValue
CGObjCNonFragileABIMac::GenerateMessageSendSuper(CodeGen::CodeGenFunction &CGF,
+ ReturnValueSlot Return,
QualType ResultType,
Selector Sel,
const ObjCInterfaceDecl *Class,
@@ -5378,10 +5393,11 @@ CGObjCNonFragileABIMac::GenerateMessageSendSuper(CodeGen::CodeGenFunction &CGF,
CGF.Builder.CreateStructGEP(ObjCSuper, 1));
return (LegacyDispatchedSelector(Sel))
- ? EmitLegacyMessageSend(CGF, ResultType,EmitSelector(CGF.Builder, Sel),
+ ? EmitLegacyMessageSend(CGF, Return, ResultType,
+ EmitSelector(CGF.Builder, Sel),
ObjCSuper, ObjCTypes.SuperPtrCTy,
true, CallArgs, Method, ObjCTypes)
- : EmitMessageSend(CGF, ResultType, Sel,
+ : EmitMessageSend(CGF, Return, ResultType, Sel,
ObjCSuper, ObjCTypes.SuperPtrCTy,
true, CallArgs);
}
diff --git a/lib/CodeGen/CGObjCRuntime.h b/lib/CodeGen/CGObjCRuntime.h
index 654ad0a4bfae..8de7f10b8612 100644
--- a/lib/CodeGen/CGObjCRuntime.h
+++ b/lib/CodeGen/CGObjCRuntime.h
@@ -119,6 +119,7 @@ public:
/// a property setter or getter.
virtual CodeGen::RValue
GenerateMessageSend(CodeGen::CodeGenFunction &CGF,
+ ReturnValueSlot ReturnSlot,
QualType ResultType,
Selector Sel,
llvm::Value *Receiver,
@@ -134,6 +135,7 @@ public:
/// a property setter or getter.
virtual CodeGen::RValue
GenerateMessageSendSuper(CodeGen::CodeGenFunction &CGF,
+ ReturnValueSlot ReturnSlot,
QualType ResultType,
Selector Sel,
const ObjCInterfaceDecl *Class,
diff --git a/lib/CodeGen/CGRecordLayout.h b/lib/CodeGen/CGRecordLayout.h
index 9f966fb7ae46..e95591e5cc01 100644
--- a/lib/CodeGen/CGRecordLayout.h
+++ b/lib/CodeGen/CGRecordLayout.h
@@ -168,6 +168,10 @@ private:
/// field no. This info is populated by record builder.
llvm::DenseMap<const FieldDecl *, CGBitFieldInfo> BitFields;
+ // FIXME: Maybe we could use a CXXBaseSpecifier as the key and use a single
+ // map for both virtual and non virtual bases.
+ llvm::DenseMap<const CXXRecordDecl *, unsigned> NonVirtualBaseFields;
+
/// 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;
@@ -194,6 +198,11 @@ public:
return FieldInfo.lookup(FD);
}
+ unsigned getNonVirtualBaseLLVMFieldNo(const CXXRecordDecl *RD) const {
+ assert(NonVirtualBaseFields.count(RD) && "Invalid non-virtual base!");
+ return NonVirtualBaseFields.lookup(RD);
+ }
+
/// \brief Return the BitFieldInfo that corresponds to the field FD.
const CGBitFieldInfo &getBitFieldInfo(const FieldDecl *FD) const {
assert(FD->isBitField() && "Invalid call for non bit-field decl!");
diff --git a/lib/CodeGen/CGRecordLayoutBuilder.cpp b/lib/CodeGen/CGRecordLayoutBuilder.cpp
index 6302cf8d1fc0..9f1687577c3e 100644
--- a/lib/CodeGen/CGRecordLayoutBuilder.cpp
+++ b/lib/CodeGen/CGRecordLayoutBuilder.cpp
@@ -42,6 +42,9 @@ public:
typedef std::pair<const FieldDecl *, CGBitFieldInfo> LLVMBitFieldInfo;
llvm::SmallVector<LLVMBitFieldInfo, 16> LLVMBitFields;
+ typedef std::pair<const CXXRecordDecl *, unsigned> LLVMBaseInfo;
+ llvm::SmallVector<LLVMBaseInfo, 16> LLVMNonVirtualBases;
+
/// 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.
@@ -81,8 +84,13 @@ private:
/// 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);
+ /// LayoutNonVirtualBase - layout a single non-virtual base.
+ void LayoutNonVirtualBase(const CXXRecordDecl *BaseDecl,
+ uint64_t BaseOffset);
+
+ /// LayoutNonVirtualBases - layout the non-virtual bases of a record decl.
+ void LayoutNonVirtualBases(const CXXRecordDecl *RD,
+ const ASTRecordLayout &Layout);
/// LayoutField - layout a single field. Returns false if the operation failed
/// because the current struct is not packed.
@@ -110,6 +118,7 @@ private:
/// CheckForPointerToDataMember - Check if the given type contains a pointer
/// to data member.
void CheckForPointerToDataMember(QualType T);
+ void CheckForPointerToDataMember(const CXXRecordDecl *RD);
public:
CGRecordLayoutBuilder(CodeGenTypes &Types)
@@ -143,6 +152,7 @@ void CGRecordLayoutBuilder::Layout(const RecordDecl *D) {
FieldTypes.clear();
LLVMFields.clear();
LLVMBitFields.clear();
+ LLVMNonVirtualBases.clear();
LayoutFields(D);
}
@@ -319,8 +329,9 @@ bool CGRecordLayoutBuilder::LayoutField(const FieldDecl *D,
if (const RecordType *RT = D->getType()->getAs<RecordType>()) {
const RecordDecl *RD = cast<RecordDecl>(RT->getDecl());
- if (const PragmaPackAttr *PPA = RD->getAttr<PragmaPackAttr>()) {
- if (PPA->getAlignment() != TypeAlignment * 8 && !Packed)
+ if (const MaxFieldAlignmentAttr *MFAA =
+ RD->getAttr<MaxFieldAlignmentAttr>()) {
+ if (MFAA->getAlignment() != TypeAlignment * 8 && !Packed)
return false;
}
}
@@ -435,16 +446,66 @@ void CGRecordLayoutBuilder::LayoutUnion(const RecordDecl *D) {
AppendPadding(Layout.getSize() / 8, Align);
}
-void CGRecordLayoutBuilder::LayoutBases(const CXXRecordDecl *RD,
- const ASTRecordLayout &Layout) {
+void CGRecordLayoutBuilder::LayoutNonVirtualBase(const CXXRecordDecl *BaseDecl,
+ uint64_t BaseOffset) {
+ const ASTRecordLayout &Layout =
+ Types.getContext().getASTRecordLayout(BaseDecl);
+
+ uint64_t NonVirtualSize = Layout.getNonVirtualSize();
+
+ if (BaseDecl->isEmpty()) {
+ // FIXME: Lay out empty bases.
+ return;
+ }
+
+ CheckForPointerToDataMember(BaseDecl);
+
+ // FIXME: Actually use a better type than [sizeof(BaseDecl) x i8] when we can.
+ AppendPadding(BaseOffset / 8, 1);
+
+ // Append the base field.
+ LLVMNonVirtualBases.push_back(LLVMBaseInfo(BaseDecl, FieldTypes.size()));
+
+ AppendBytes(NonVirtualSize / 8);
+}
+
+void
+CGRecordLayoutBuilder::LayoutNonVirtualBases(const CXXRecordDecl *RD,
+ const ASTRecordLayout &Layout) {
+ const CXXRecordDecl *PrimaryBase = Layout.getPrimaryBase();
+
// Check if we need to add a vtable pointer.
- if (RD->isDynamicClass() && !Layout.getPrimaryBase()) {
- const llvm::Type *Int8PtrTy =
- llvm::Type::getInt8PtrTy(Types.getLLVMContext());
+ if (RD->isDynamicClass()) {
+ if (!PrimaryBase) {
+ const llvm::Type *FunctionType =
+ llvm::FunctionType::get(llvm::Type::getInt32Ty(Types.getLLVMContext()),
+ /*isVarArg=*/true);
+ const llvm::Type *VTableTy = FunctionType->getPointerTo();
+
+ assert(NextFieldOffsetInBytes == 0 &&
+ "VTable pointer must come first!");
+ AppendField(NextFieldOffsetInBytes, VTableTy->getPointerTo());
+ } else {
+ // FIXME: Handle a virtual primary base.
+ if (!Layout.getPrimaryBaseWasVirtual())
+ LayoutNonVirtualBase(PrimaryBase, 0);
+ }
+ }
- assert(NextFieldOffsetInBytes == 0 &&
- "VTable pointer must come first!");
- AppendField(NextFieldOffsetInBytes, Int8PtrTy->getPointerTo());
+ // Layout the non-virtual bases.
+ for (CXXRecordDecl::base_class_const_iterator I = RD->bases_begin(),
+ E = RD->bases_end(); I != E; ++I) {
+ if (I->isVirtual())
+ continue;
+
+ const CXXRecordDecl *BaseDecl =
+ cast<CXXRecordDecl>(I->getType()->getAs<RecordType>()->getDecl());
+
+ // We've already laid out the primary base.
+ if (BaseDecl == PrimaryBase && !Layout.getPrimaryBaseWasVirtual())
+ continue;
+
+ LayoutNonVirtualBase(BaseDecl, Layout.getBaseClassOffset(BaseDecl));
}
}
@@ -455,7 +516,7 @@ bool CGRecordLayoutBuilder::LayoutFields(const RecordDecl *D) {
const ASTRecordLayout &Layout = Types.getContext().getASTRecordLayout(D);
if (const CXXRecordDecl *RD = dyn_cast<CXXRecordDecl>(D))
- LayoutBases(RD, Layout);
+ LayoutNonVirtualBases(RD, Layout);
unsigned FieldNo = 0;
@@ -561,15 +622,24 @@ 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);
+ return CheckForPointerToDataMember(RD);
+ }
+}
- const CGRecordLayout &Layout = Types.getCGRecordLayout(RD);
+void
+CGRecordLayoutBuilder::CheckForPointerToDataMember(const CXXRecordDecl *RD) {
+ // This record already contains a member pointer.
+ if (ContainsPointerToDataMember)
+ return;
- if (Layout.containsPointerToDataMember())
- ContainsPointerToDataMember = true;
- }
+ // 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 *CodeGenTypes::ComputeRecordLayout(const RecordDecl *D) {
@@ -584,13 +654,17 @@ CGRecordLayout *CodeGenTypes::ComputeRecordLayout(const RecordDecl *D) {
CGRecordLayout *RL =
new CGRecordLayout(Ty, Builder.ContainsPointerToDataMember);
+ // Add all the non-virtual base field numbers.
+ RL->NonVirtualBaseFields.insert(Builder.LLVMNonVirtualBases.begin(),
+ Builder.LLVMNonVirtualBases.end());
+
// Add all the field numbers.
- for (unsigned i = 0, e = Builder.LLVMFields.size(); i != e; ++i)
- RL->FieldInfo.insert(Builder.LLVMFields[i]);
+ RL->FieldInfo.insert(Builder.LLVMFields.begin(),
+ Builder.LLVMFields.end());
// Add bitfield info.
- for (unsigned i = 0, e = Builder.LLVMBitFields.size(); i != e; ++i)
- RL->BitFields.insert(Builder.LLVMBitFields[i]);
+ RL->BitFields.insert(Builder.LLVMBitFields.begin(),
+ Builder.LLVMBitFields.end());
// Dump the layout, if requested.
if (getContext().getLangOptions().DumpRecordLayouts) {
diff --git a/lib/CodeGen/CGStmt.cpp b/lib/CodeGen/CGStmt.cpp
index a914c80da2ac..efde3807111f 100644
--- a/lib/CodeGen/CGStmt.cpp
+++ b/lib/CodeGen/CGStmt.cpp
@@ -30,7 +30,10 @@ using namespace CodeGen;
void CodeGenFunction::EmitStopPoint(const Stmt *S) {
if (CGDebugInfo *DI = getDebugInfo()) {
- DI->setLocation(S->getLocStart());
+ if (isa<DeclStmt>(S))
+ DI->setLocation(S->getLocEnd());
+ else
+ DI->setLocation(S->getLocStart());
DI->EmitStopPoint(CurFn, Builder);
}
}
@@ -76,8 +79,11 @@ void CodeGenFunction::EmitStmt(const Stmt *S) {
// Expression emitters don't handle unreachable blocks yet, so look for one
// explicitly here. This handles the common case of a call to a noreturn
// function.
+ // We can't erase blocks with an associated cleanup size here since the
+ // memory might be reused, leaving the old cleanup info pointing at a new
+ // block.
if (llvm::BasicBlock *CurBB = Builder.GetInsertBlock()) {
- if (CurBB->empty() && CurBB->use_empty()) {
+ if (CurBB->empty() && CurBB->use_empty() && !BlockScopes.count(CurBB)) {
CurBB->eraseFromParent();
Builder.ClearInsertionPoint();
}
@@ -484,8 +490,6 @@ void CodeGenFunction::EmitDoStmt(const DoStmt &S) {
}
void CodeGenFunction::EmitForStmt(const ForStmt &S) {
- // FIXME: What do we do if the increment (f.e.) contains a stmt expression,
- // which contains a continue/break?
CleanupScope ForScope(*this);
// Evaluate the first part before the loop.
@@ -555,14 +559,14 @@ void CodeGenFunction::EmitForStmt(const ForStmt &S) {
EmitStmt(S.getBody());
}
- BreakContinueStack.pop_back();
-
// If there is an increment, emit it next.
if (S.getInc()) {
EmitBlock(IncBlock);
EmitStmt(S.getInc());
}
+ BreakContinueStack.pop_back();
+
// Finally, branch back up to the condition for the next iteration.
if (CondCleanup) {
// Branch to the cleanup block.
@@ -604,7 +608,20 @@ void CodeGenFunction::EmitReturnStmt(const ReturnStmt &S) {
// FIXME: Clean this up by using an LValue for ReturnTemp,
// EmitStoreThroughLValue, and EmitAnyExpr.
- if (!ReturnValue) {
+ if (S.getNRVOCandidate() && S.getNRVOCandidate()->isNRVOVariable() &&
+ !Target.useGlobalsForAutomaticVariables()) {
+ // Apply the named return value optimization for this return statement,
+ // which means doing nothing: the appropriate result has already been
+ // constructed into the NRVO variable.
+
+ // If there is an NRVO flag for this variable, set it to 1 into indicate
+ // that the cleanup code should not destroy the variable.
+ if (llvm::Value *NRVOFlag = NRVOFlags[S.getNRVOCandidate()]) {
+ const llvm::Type *BoolTy = llvm::Type::getInt1Ty(VMContext);
+ llvm::Value *One = llvm::ConstantInt::get(BoolTy, 1);
+ Builder.CreateStore(One, NRVOFlag);
+ }
+ } else if (!ReturnValue) {
// Make sure not to return anything, but evaluate the expression
// for side effects.
if (RV)
diff --git a/lib/CodeGen/CGVTT.cpp b/lib/CodeGen/CGVTT.cpp
index 15e564810f83..61c74230e118 100644
--- a/lib/CodeGen/CGVTT.cpp
+++ b/lib/CodeGen/CGVTT.cpp
@@ -378,7 +378,7 @@ CodeGenVTables::GenerateVTT(llvm::GlobalVariable::LinkageTypes Linkage,
D1(printf("vtt %s\n", RD->getNameAsCString()));
- llvm::GlobalVariable *GV = CGM.getModule().getGlobalVariable(Name);
+ llvm::GlobalVariable *GV = CGM.getModule().getGlobalVariable(Name, true);
if (GV == 0 || GV->isDeclaration()) {
const llvm::Type *Int8PtrTy =
llvm::Type::getInt8PtrTy(CGM.getLLVMContext());
diff --git a/lib/CodeGen/CGVTables.cpp b/lib/CodeGen/CGVTables.cpp
index 159753aa359c..0f023e63ae54 100644
--- a/lib/CodeGen/CGVTables.cpp
+++ b/lib/CodeGen/CGVTables.cpp
@@ -2548,7 +2548,7 @@ llvm::Constant *CodeGenModule::GetAddrOfThunk(GlobalDecl GD,
getMangleContext().mangleThunk(MD, Thunk, Name);
const llvm::Type *Ty = getTypes().GetFunctionTypeForVTable(MD);
- return GetOrCreateLLVMFunction(Name, Ty, GlobalDecl());
+ return GetOrCreateLLVMFunction(Name, Ty, GD);
}
static llvm::Value *PerformTypeAdjustment(CodeGenFunction &CGF,
@@ -2641,10 +2641,9 @@ void CodeGenFunction::GenerateThunk(llvm::Function *Fn, GlobalDecl GD,
E = MD->param_end(); I != E; ++I) {
ParmVarDecl *Param = *I;
QualType ArgType = Param->getType();
+ RValue Arg = EmitDelegateCallArg(Param);
- // 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));
+ CallArgs.push_back(std::make_pair(Arg, ArgType));
}
// Get our callee.
@@ -2657,8 +2656,15 @@ void CodeGenFunction::GenerateThunk(llvm::Function *Fn, GlobalDecl GD,
CGM.getTypes().getFunctionInfo(ResultType, CallArgs,
FPT->getExtInfo());
+ // Determine whether we have a return value slot to use.
+ ReturnValueSlot Slot;
+ if (!ResultType->isVoidType() &&
+ FnInfo.getReturnInfo().getKind() == ABIArgInfo::Indirect &&
+ hasAggregateLLVMType(CurFnInfo->getReturnType()))
+ Slot = ReturnValueSlot(ReturnValue, ResultType.isVolatileQualified());
+
// Now emit our call.
- RValue RV = EmitCall(FnInfo, Callee, ReturnValueSlot(), CallArgs, MD);
+ RValue RV = EmitCall(FnInfo, Callee, Slot, CallArgs, MD);
if (!Thunk.Return.isEmpty()) {
// Emit the return adjustment.
@@ -2701,7 +2707,7 @@ void CodeGenFunction::GenerateThunk(llvm::Function *Fn, GlobalDecl GD,
RV = RValue::get(ReturnValue);
}
- if (!ResultType->isVoidType())
+ if (!ResultType->isVoidType() && Slot.isNull())
EmitReturnOfRValue(RV, ResultType);
FinishFunction();
@@ -2710,7 +2716,7 @@ void CodeGenFunction::GenerateThunk(llvm::Function *Fn, GlobalDecl GD,
CXXThisDecl->Destroy(getContext());
// Set the right linkage.
- Fn->setLinkage(CGM.getFunctionLinkage(MD));
+ CGM.setFunctionLinkage(MD, Fn);
// Set the right visibility.
CGM.setGlobalVisibility(Fn, MD);
@@ -2788,7 +2794,13 @@ void CodeGenVTables::ComputeVTableRelatedInformation(const CXXRecordDecl *RD) {
// Check if we've computed this information before.
if (LayoutData)
return;
-
+
+ // We may need to generate a definition for this vtable.
+ if (!isKeyFunctionInAnotherTU(CGM.getContext(), RD) &&
+ RD->getTemplateSpecializationKind()
+ != TSK_ExplicitInstantiationDeclaration)
+ CGM.DeferredVTables.push_back(RD);
+
VTableBuilder Builder(*this, RD, 0, /*MostDerivedClassIsVirtual=*/0, RD);
// Add the VTable layout.
@@ -3119,49 +3131,3 @@ CodeGenVTables::GenerateClassData(llvm::GlobalVariable::LinkageTypes Linkage,
DC->getParent()->isTranslationUnit())
CGM.EmitFundamentalRTTIDescriptors();
}
-
-void CodeGenVTables::EmitVTableRelatedData(GlobalDecl GD) {
- const CXXMethodDecl *MD = cast<CXXMethodDecl>(GD.getDecl());
- const CXXRecordDecl *RD = MD->getParent();
-
- // If the class doesn't have a vtable we don't need to emit one.
- if (!RD->isDynamicClass())
- return;
-
- // Check if we need to emit thunks for this function.
- if (MD->isVirtual())
- EmitThunks(GD);
-
- // Get the key function.
- const CXXMethodDecl *KeyFunction = CGM.getContext().getKeyFunction(RD);
-
- TemplateSpecializationKind RDKind = RD->getTemplateSpecializationKind();
- TemplateSpecializationKind MDKind = MD->getTemplateSpecializationKind();
-
- if (KeyFunction) {
- // We don't have the right key function.
- if (KeyFunction->getCanonicalDecl() != MD->getCanonicalDecl())
- return;
- } else {
- // If we have no key funcion and this is a explicit instantiation declaration,
- // we will produce a vtable at the explicit instantiation. We don't need one
- // here.
- if (RDKind == clang::TSK_ExplicitInstantiationDeclaration)
- return;
-
- // If this is an explicit instantiation of a method, we don't need a vtable.
- // Since we have no key function, we will emit the vtable when we see
- // a use, and just defining a function is not an use.
- if (RDKind == TSK_ImplicitInstantiation &&
- MDKind == TSK_ExplicitInstantiationDefinition)
- return;
- }
-
- if (VTables.count(RD))
- return;
-
- if (RDKind == TSK_ImplicitInstantiation)
- CGM.DeferredVTables.push_back(RD);
- else
- GenerateClassData(CGM.getVTableLinkage(RD), RD);
-}
diff --git a/lib/CodeGen/CGVTables.h b/lib/CodeGen/CGVTables.h
index 6c18ca83f091..e55377f2fa2f 100644
--- a/lib/CodeGen/CGVTables.h
+++ b/lib/CodeGen/CGVTables.h
@@ -272,9 +272,6 @@ class CodeGenVTables {
/// 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.
@@ -349,11 +346,10 @@ public:
VTableAddressPointsMapTy& AddressPoints);
llvm::GlobalVariable *getVTT(const CXXRecordDecl *RD);
-
- // EmitVTableRelatedData - Will emit any thunks that the global decl might
- // have, as well as the vtable itself if the global decl is the key function.
- void EmitVTableRelatedData(GlobalDecl GD);
+ /// EmitThunks - Emit the associated thunks for the given global decl.
+ void EmitThunks(GlobalDecl GD);
+
/// GenerateClassData - Generate all the class data required to be generated
/// upon definition of a KeyFunction. This includes the vtable, the
/// rtti data structure and the VTT.
diff --git a/lib/CodeGen/CMakeLists.txt b/lib/CodeGen/CMakeLists.txt
index dfd2a391a4cf..a226400a3787 100644
--- a/lib/CodeGen/CMakeLists.txt
+++ b/lib/CodeGen/CMakeLists.txt
@@ -28,7 +28,10 @@ add_clang_library(clangCodeGen
CodeGenFunction.cpp
CodeGenModule.cpp
CodeGenTypes.cpp
+ ItaniumCXXABI.cpp
Mangle.cpp
ModuleBuilder.cpp
TargetInfo.cpp
)
+
+add_dependencies(clangCodeGen ClangStmtNodes)
diff --git a/lib/CodeGen/CodeGenFunction.cpp b/lib/CodeGen/CodeGenFunction.cpp
index d3bf1645a026..73de0fd77384 100644
--- a/lib/CodeGen/CodeGenFunction.cpp
+++ b/lib/CodeGen/CodeGenFunction.cpp
@@ -37,6 +37,7 @@ CodeGenFunction::CodeGenFunction(CodeGenModule &cgm)
LLVMPointerWidth = Target.getPointerWidth(0);
Exceptions = getContext().getLangOptions().Exceptions;
CatchUndefined = getContext().getLangOptions().CatchUndefined;
+ CGM.getMangleContext().startNewFunction();
}
ASTContext &CodeGenFunction::getContext() const {
@@ -472,7 +473,23 @@ void CodeGenFunction::ErrorUnsupported(const Stmt *S, const char *Type,
CGM.ErrorUnsupported(S, Type, OmitOnError);
}
-void CodeGenFunction::EmitMemSetToZero(llvm::Value *DestPtr, QualType Ty) {
+void
+CodeGenFunction::EmitNullInitialization(llvm::Value *DestPtr, QualType Ty) {
+ // If the type contains a pointer to data member we can't memset it to zero.
+ // Instead, create a null constant and copy it to the destination.
+ if (CGM.getTypes().ContainsPointerToDataMember(Ty)) {
+ llvm::Constant *NullConstant = CGM.EmitNullConstant(Ty);
+
+ llvm::GlobalVariable *NullVariable =
+ new llvm::GlobalVariable(CGM.getModule(), NullConstant->getType(),
+ /*isConstant=*/true,
+ llvm::GlobalVariable::PrivateLinkage,
+ NullConstant, llvm::Twine());
+ EmitAggregateCopy(DestPtr, NullVariable, Ty, /*isVolatile=*/false);
+ return;
+ }
+
+
// Ignore empty classes in C++.
if (getContext().getLangOptions().CPlusPlus) {
if (const RecordType *RT = Ty->getAs<RecordType>()) {
@@ -481,6 +498,9 @@ void CodeGenFunction::EmitMemSetToZero(llvm::Value *DestPtr, QualType Ty) {
}
}
+ // Otherwise, just memset the whole thing to zero. This is legal
+ // because in LLVM, all default initializers (other than the ones we just
+ // handled above) are guaranteed to have a bit pattern of all zeros.
const llvm::Type *BP = llvm::Type::getInt8PtrTy(VMContext);
if (DestPtr->getType() != BP)
DestPtr = Builder.CreateBitCast(DestPtr, BP, "tmp");
diff --git a/lib/CodeGen/CodeGenFunction.h b/lib/CodeGen/CodeGenFunction.h
index 90a3ec4a4b10..ece275e7629e 100644
--- a/lib/CodeGen/CodeGenFunction.h
+++ b/lib/CodeGen/CodeGenFunction.h
@@ -67,6 +67,7 @@ namespace CodeGen {
class CGDebugInfo;
class CGFunctionInfo;
class CGRecordLayout;
+ class CGBlockInfo;
/// CodeGenFunction - This class organizes the per-function state that is used
/// while generating LLVM code.
@@ -107,6 +108,11 @@ public:
bool Exceptions;
bool CatchUndefined;
+
+ /// \brief A mapping from NRVO variables to the flags used to indicate
+ /// when the NRVO has been applied to this variable.
+ llvm::DenseMap<const VarDecl *, llvm::Value *> NRVOFlags;
+
public:
/// ObjCEHValueStack - Stack of Objective-C exception values, used for
/// rethrows.
@@ -496,18 +502,18 @@ public:
std::vector<HelperInfo> *);
llvm::Function *GenerateBlockFunction(const BlockExpr *BExpr,
- const BlockInfo& Info,
+ CGBlockInfo &Info,
const Decl *OuterFuncDecl,
- llvm::DenseMap<const Decl*, llvm::Value*> ldm,
- CharUnits &Size, CharUnits &Align,
- llvm::SmallVector<const Expr *, 8> &subBlockDeclRefDecls,
- bool &subBlockHasCopyDispose);
+ llvm::DenseMap<const Decl*, llvm::Value*> ldm);
- void BlockForwardSelf();
llvm::Value *LoadBlockStruct();
- CharUnits AllocateBlockDecl(const BlockDeclRefExpr *E);
- llvm::Value *GetAddrOfBlockDecl(const BlockDeclRefExpr *E);
+ void AllocateBlockCXXThisPointer(const CXXThisExpr *E);
+ void AllocateBlockDecl(const BlockDeclRefExpr *E);
+ llvm::Value *GetAddrOfBlockDecl(const BlockDeclRefExpr *E) {
+ return GetAddrOfBlockDecl(E->getDecl(), E->isByRef());
+ }
+ llvm::Value *GetAddrOfBlockDecl(const ValueDecl *D, bool ByRef);
const llvm::Type *BuildByRefType(const ValueDecl *D);
void GenerateCode(GlobalDecl GD, llvm::Function *Fn);
@@ -531,7 +537,8 @@ public:
/// 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 EmitCtorPrologue(const CXXConstructorDecl *CD, CXXCtorType Type,
+ FunctionArgList &Args);
/// InitializeVTablePointer - Initialize the vtable pointer of the given
/// subobject.
@@ -554,8 +561,6 @@ public:
void InitializeVTablePointers(const CXXRecordDecl *ClassDecl);
- void SynthesizeCXXCopyConstructor(const FunctionArgList &Args);
-
/// EmitDtorEpilogue - Emit all code that comes at the end of class's
/// destructor. This is to call destructors on members and base classes in
/// reverse order of their construction.
@@ -725,8 +730,6 @@ public:
void EmitAggregateCopy(llvm::Value *DestPtr, llvm::Value *SrcPtr,
QualType EltTy, bool isVolatile=false);
- void EmitAggregateClear(llvm::Value *DestPtr, QualType Ty);
-
/// StartBlock - Start new block named N. If insert block is a dummy block
/// then reuse it.
void StartBlock(const char *N);
@@ -744,8 +747,10 @@ public:
llvm::BlockAddress *GetAddrOfLabel(const LabelStmt *L);
llvm::BasicBlock *GetIndirectGotoBlock();
- /// EmitMemSetToZero - Generate code to memset a value of the given type to 0.
- void EmitMemSetToZero(llvm::Value *DestPtr, QualType Ty);
+ /// EmitNullInitialization - Generate code to set a value of the given type to
+ /// null, If the type contains data member pointers, they will be initialized
+ /// to -1 in accordance with the Itanium C++ ABI.
+ void EmitNullInitialization(llvm::Value *DestPtr, QualType Ty);
// EmitVAArg - Generate code to get an argument from the passed in pointer
// and update it accordingly. The return value is a pointer to the argument.
@@ -802,14 +807,6 @@ public:
const CXXRecordDecl *ClassDecl,
const CXXRecordDecl *BaseClassDecl);
- void EmitClassAggrMemberwiseCopy(llvm::Value *DestValue,
- llvm::Value *SrcValue,
- const ConstantArrayType *Array,
- const CXXRecordDecl *ClassDecl);
-
- void EmitClassMemberwiseCopy(llvm::Value *DestValue, llvm::Value *SrcValue,
- const CXXRecordDecl *ClassDecl);
-
void EmitDelegateCXXConstructorCall(const CXXConstructorDecl *Ctor,
CXXCtorType CtorType,
const FunctionArgList &Args);
@@ -940,6 +937,7 @@ public:
void EmitObjCAtThrowStmt(const ObjCAtThrowStmt &S);
void EmitObjCAtSynchronizedStmt(const ObjCAtSynchronizedStmt &S);
+ llvm::Constant *getUnwindResumeOrRethrowFn();
struct CXXTryStmtInfo {
llvm::BasicBlock *SavedLandingPad;
llvm::BasicBlock *HandlerBlock;
@@ -1056,6 +1054,9 @@ public:
llvm::Value *EmitIvarOffset(const ObjCInterfaceDecl *Interface,
const ObjCIvarDecl *Ivar);
+ LValue EmitLValueForAnonRecordField(llvm::Value* Base,
+ const FieldDecl* Field,
+ unsigned CVRQualifiers);
LValue EmitLValueForField(llvm::Value* Base, const FieldDecl* Field,
unsigned CVRQualifiers);
@@ -1151,9 +1152,12 @@ public:
llvm::Value *EmitObjCProtocolExpr(const ObjCProtocolExpr *E);
llvm::Value *EmitObjCStringLiteral(const ObjCStringLiteral *E);
llvm::Value *EmitObjCSelectorExpr(const ObjCSelectorExpr *E);
- RValue EmitObjCMessageExpr(const ObjCMessageExpr *E);
- RValue EmitObjCPropertyGet(const Expr *E);
- RValue EmitObjCSuperPropertyGet(const Expr *Exp, const Selector &S);
+ RValue EmitObjCMessageExpr(const ObjCMessageExpr *E,
+ ReturnValueSlot Return = ReturnValueSlot());
+ RValue EmitObjCPropertyGet(const Expr *E,
+ ReturnValueSlot Return = ReturnValueSlot());
+ RValue EmitObjCSuperPropertyGet(const Expr *Exp, const Selector &S,
+ ReturnValueSlot Return = ReturnValueSlot());
void EmitObjCPropertySet(const Expr *E, RValue Src);
void EmitObjCSuperPropertySet(const Expr *E, const Selector &S, RValue Src);
@@ -1298,6 +1302,11 @@ public:
/// EmitCallArg - Emit a single call argument.
RValue EmitCallArg(const Expr *E, QualType ArgType);
+ /// EmitDelegateCallArg - We are performing a delegate call; that
+ /// is, the current function is delegating to another one. Produce
+ /// a r-value suitable for passing the given parameter.
+ RValue EmitDelegateCallArg(const VarDecl *Param);
+
private:
void EmitReturnOfRValue(RValue RV, QualType Ty);
diff --git a/lib/CodeGen/CodeGenModule.cpp b/lib/CodeGen/CodeGenModule.cpp
index cc90a2855dee..103024c32392 100644
--- a/lib/CodeGen/CodeGenModule.cpp
+++ b/lib/CodeGen/CodeGenModule.cpp
@@ -48,7 +48,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, diags), VTables(*this), Runtime(0),
+ VTables(*this), Runtime(0), ABI(0),
CFConstantStringClassRef(0),
NSConstantStringClassRef(0),
VMContext(M.getContext()) {
@@ -62,12 +62,17 @@ CodeGenModule::CodeGenModule(ASTContext &C, const CodeGenOptions &CGO,
else
Runtime = CreateMacObjCRuntime(*this);
+ if (!Features.CPlusPlus)
+ ABI = 0;
+ else createCXXABI();
+
// If debug info generation is enabled, create the CGDebugInfo object.
DebugInfo = CodeGenOpts.DebugInfo ? new CGDebugInfo(*this) : 0;
}
CodeGenModule::~CodeGenModule() {
delete Runtime;
+ delete ABI;
delete DebugInfo;
}
@@ -80,6 +85,11 @@ void CodeGenModule::createObjCRuntime() {
Runtime = CreateMacObjCRuntime(*this);
}
+void CodeGenModule::createCXXABI() {
+ // For now, just create an Itanium ABI.
+ ABI = CreateItaniumCXXABI(*this);
+}
+
void CodeGenModule::Release() {
EmitDeferred();
EmitCXXGlobalInitFunc();
@@ -316,17 +326,6 @@ GetLinkageForFunction(ASTContext &Context, const FunctionDecl *FD,
== TSK_ExplicitInstantiationDeclaration)
return CodeGenModule::GVA_C99Inline;
- // If this is a virtual method and its class has a key method in another
- // translation unit, we know that this method will be present in that
- // translation unit. In this translation unit we will use this method
- // only for inlining and analysis. This is the semantics of c99 inline.
- if (const CXXMethodDecl *MD = dyn_cast<CXXMethodDecl>(FD)) {
- const CXXRecordDecl *RD = MD->getParent();
- if (MD->isVirtual() &&
- CodeGenVTables::isKeyFunctionInAnotherTU(Context, RD))
- return CodeGenModule::GVA_C99Inline;
- }
-
return CodeGenModule::GVA_CXXInline;
}
@@ -372,7 +371,6 @@ CodeGenModule::getFunctionLinkage(const FunctionDecl *D) {
/// variables (these details are set in EmitGlobalVarDefinition for variables).
void CodeGenModule::SetFunctionDefinitionAttributes(const FunctionDecl *D,
llvm::GlobalValue *GV) {
- GV->setLinkage(getFunctionLinkage(D));
SetCommonAttributes(D, GV);
}
@@ -515,9 +513,14 @@ void CodeGenModule::EmitDeferred() {
GlobalDecl D = DeferredDeclsToEmit.back();
DeferredDeclsToEmit.pop_back();
- // Look it up to see if it was defined with a stronger definition (e.g. an
- // extern inline function with a strong function redefinition). If so,
- // just ignore the deferred decl.
+ // Check to see if we've already emitted this. This is necessary
+ // for a couple of reasons: first, decls can end up in the
+ // deferred-decls queue multiple times, and second, decls can end
+ // up with definitions in unusual ways (e.g. by an extern inline
+ // function acquiring a strong function redefinition). Just
+ // ignore these cases.
+ //
+ // TODO: That said, looking this up multiple times is very wasteful.
MangleBuffer Name;
getMangledName(Name, D);
llvm::GlobalValue *CGRef = GetGlobalValue(Name);
@@ -526,6 +529,11 @@ void CodeGenModule::EmitDeferred() {
if (!CGRef->isDeclaration())
continue;
+ // GlobalAlias::isDeclaration() defers to the aliasee, but for our
+ // purposes an alias counts as a definition.
+ if (isa<llvm::GlobalAlias>(CGRef))
+ continue;
+
// Otherwise, emit the definition and move on to the next one.
EmitGlobalDefinition(D);
}
@@ -727,8 +735,9 @@ void CodeGenModule::EmitGlobalDefinition(GlobalDecl GD) {
Context.getSourceManager(),
"Generating code for declaration");
- if (isa<CXXMethodDecl>(D))
- getVTables().EmitVTableRelatedData(GD);
+ if (const CXXMethodDecl *Method = dyn_cast<CXXMethodDecl>(D))
+ if (Method->isVirtual())
+ getVTables().EmitThunks(GD);
if (const CXXConstructorDecl *CD = dyn_cast<CXXConstructorDecl>(D))
return EmitCXXConstructor(CD, GD.getCtorType());
@@ -984,6 +993,11 @@ void CodeGenModule::EmitTentativeDefinition(const VarDecl *D) {
EmitGlobalVarDefinition(D);
}
+void CodeGenModule::EmitVTable(CXXRecordDecl *Class, bool DefinitionRequired) {
+ if (DefinitionRequired)
+ getVTables().GenerateClassData(getVTableLinkage(Class), Class);
+}
+
llvm::GlobalVariable::LinkageTypes
CodeGenModule::getVTableLinkage(const CXXRecordDecl *RD) {
if (RD->isInAnonymousNamespace() || !RD->hasLinkage())
@@ -1101,10 +1115,12 @@ void CodeGenModule::EmitGlobalVarDefinition(const VarDecl *D) {
assert(!ASTTy->isIncompleteType() && "Unexpected incomplete type");
Init = EmitNullConstant(D->getType());
} else {
- Init = EmitConstantExpr(InitExpr, D->getType());
-
+ Init = EmitConstantExpr(InitExpr, D->getType());
if (!Init) {
QualType T = InitExpr->getType();
+ if (D->getType()->isReferenceType())
+ T = D->getType();
+
if (getLangOptions().CPlusPlus) {
EmitCXXGlobalVarDeclInitFunc(D);
Init = EmitNullConstant(T);
@@ -1333,6 +1349,7 @@ void CodeGenModule::EmitGlobalFunctionDefinition(GlobalDecl GD) {
}
llvm::Function *Fn = cast<llvm::Function>(Entry);
+ setFunctionLinkage(D, Fn);
CodeGenFunction(*this).GenerateCode(D, Fn);
diff --git a/lib/CodeGen/CodeGenModule.h b/lib/CodeGen/CodeGenModule.h
index 93d8ddf3e485..319744c4be3d 100644
--- a/lib/CodeGen/CodeGenModule.h
+++ b/lib/CodeGen/CodeGenModule.h
@@ -22,6 +22,7 @@
#include "CGCall.h"
#include "CGCXX.h"
#include "CGVTables.h"
+#include "CGCXXABI.h"
#include "CodeGenTypes.h"
#include "GlobalDecl.h"
#include "Mangle.h"
@@ -90,13 +91,13 @@ class CodeGenModule : public BlockModule {
mutable const TargetCodeGenInfo *TheTargetCodeGenInfo;
Diagnostic &Diags;
CodeGenTypes Types;
- MangleContext MangleCtx;
/// VTables - Holds information about C++ vtables.
CodeGenVTables VTables;
friend class CodeGenVTables;
CGObjCRuntime* Runtime;
+ CXXABI* ABI;
CGDebugInfo* DebugInfo;
// WeakRefReferences - A set of references that have only been seen via
@@ -153,6 +154,8 @@ class CodeGenModule : public BlockModule {
/// Lazily create the Objective-C runtime
void createObjCRuntime();
+ /// Lazily create the C++ ABI
+ void createCXXABI();
llvm::LLVMContext &VMContext;
public:
@@ -175,6 +178,16 @@ public:
/// been configured.
bool hasObjCRuntime() { return !!Runtime; }
+ /// getCXXABI() - Return a reference to the configured
+ /// C++ ABI.
+ CXXABI &getCXXABI() {
+ if (!ABI) createCXXABI();
+ return *ABI;
+ }
+
+ /// hasCXXABI() - Return true iff a C++ ABI has been configured.
+ bool hasCXXABI() { return !!ABI; }
+
llvm::Value *getStaticLocalDeclAddress(const VarDecl *VD) {
return StaticLocalDeclMap[VD];
}
@@ -189,7 +202,10 @@ public:
const LangOptions &getLangOptions() const { return Features; }
llvm::Module &getModule() const { return TheModule; }
CodeGenTypes &getTypes() { return Types; }
- MangleContext &getMangleContext() { return MangleCtx; }
+ MangleContext &getMangleContext() {
+ if (!ABI) createCXXABI();
+ return ABI->getMangleContext();
+ }
CodeGenVTables &getVTables() { return VTables; }
Diagnostic &getDiags() const { return Diags; }
const llvm::TargetData &getTargetData() const { return TheTargetData; }
@@ -413,6 +429,7 @@ public:
void getMangledName(MangleBuffer &Buffer, GlobalDecl D);
void getMangledName(MangleBuffer &Buffer, const NamedDecl *ND);
+ void getMangledName(MangleBuffer &Buffer, const BlockDecl *BD);
void getMangledCXXCtorName(MangleBuffer &Buffer,
const CXXConstructorDecl *D,
CXXCtorType Type);
@@ -422,6 +439,8 @@ public:
void EmitTentativeDefinition(const VarDecl *D);
+ void EmitVTable(CXXRecordDecl *Class, bool DefinitionRequired);
+
enum GVALinkage {
GVA_Internal,
GVA_C99Inline,
@@ -434,6 +453,10 @@ public:
llvm::GlobalVariable::LinkageTypes
getFunctionLinkage(const FunctionDecl *FD);
+ void setFunctionLinkage(const FunctionDecl *FD, llvm::GlobalValue *V) {
+ V->setLinkage(getFunctionLinkage(FD));
+ }
+
/// getVTableLinkage - Return the appropriate linkage for the vtable, VTT,
/// and type information of the given class.
static llvm::GlobalVariable::LinkageTypes
diff --git a/lib/CodeGen/CodeGenTypes.cpp b/lib/CodeGen/CodeGenTypes.cpp
index f53dd83d7035..a46dc726a45b 100644
--- a/lib/CodeGen/CodeGenTypes.cpp
+++ b/lib/CodeGen/CodeGenTypes.cpp
@@ -322,6 +322,9 @@ const llvm::Type *CodeGenTypes::ConvertNewType(QualType T) {
true);
}
+ case Type::ObjCObject:
+ return ConvertTypeRecursive(cast<ObjCObjectType>(Ty).getBaseType());
+
case Type::ObjCInterface: {
// Objective-C interfaces are always opaque (outside of the
// runtime, which can do whatever it likes); we never refine
@@ -467,3 +470,32 @@ CodeGenTypes::getCGRecordLayout(const RecordDecl *TD) const {
assert(Layout && "Unable to find record layout information for type");
return *Layout;
}
+
+bool CodeGenTypes::ContainsPointerToDataMember(QualType T) {
+ // No need to check for member pointers when not compiling C++.
+ if (!Context.getLangOptions().CPlusPlus)
+ return false;
+
+ T = Context.getBaseElementType(T);
+
+ if (const RecordType *RT = T->getAs<RecordType>()) {
+ const CXXRecordDecl *RD = cast<CXXRecordDecl>(RT->getDecl());
+
+ return ContainsPointerToDataMember(RD);
+ }
+
+ if (const MemberPointerType *MPT = T->getAs<MemberPointerType>())
+ return !MPT->getPointeeType()->isFunctionType();
+
+ return false;
+}
+
+bool CodeGenTypes::ContainsPointerToDataMember(const CXXRecordDecl *RD) {
+
+ // FIXME: It would be better if there was a way to explicitly compute the
+ // record layout instead of converting to a type.
+ ConvertTagDeclType(RD);
+
+ const CGRecordLayout &Layout = getCGRecordLayout(RD);
+ return Layout.containsPointerToDataMember();
+}
diff --git a/lib/CodeGen/CodeGenTypes.h b/lib/CodeGen/CodeGenTypes.h
index 10e71e2a03fa..fc28c3ae33f4 100644
--- a/lib/CodeGen/CodeGenTypes.h
+++ b/lib/CodeGen/CodeGenTypes.h
@@ -186,6 +186,14 @@ public: // These are internal details of CGT that shouldn't be used externally.
/// argument types it would be passed as on the provided vector \arg
/// ArgTys. See ABIArgInfo::Expand.
void GetExpandedTypes(QualType Ty, std::vector<const llvm::Type*> &ArgTys);
+
+ /// ContainsPointerToDataMember - Return whether the given type contains a
+ /// pointer to a data member.
+ bool ContainsPointerToDataMember(QualType T);
+
+ /// ContainsPointerToDataMember - Return whether the record decl contains a
+ /// pointer to a data member.
+ bool ContainsPointerToDataMember(const CXXRecordDecl *RD);
};
} // end namespace CodeGen
diff --git a/lib/CodeGen/ItaniumCXXABI.cpp b/lib/CodeGen/ItaniumCXXABI.cpp
new file mode 100644
index 000000000000..98db75ea2b46
--- /dev/null
+++ b/lib/CodeGen/ItaniumCXXABI.cpp
@@ -0,0 +1,39 @@
+//===------- ItaniumCXXABI.cpp - Emit LLVM Code from ASTs for a Module ----===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+//
+// This provides C++ code generation targetting the Itanium C++ ABI. The class
+// in this file generates structures that follow the Itanium C++ ABI, which is
+// documented at:
+// http://www.codesourcery.com/public/cxx-abi/abi.html
+// http://www.codesourcery.com/public/cxx-abi/abi-eh.html
+//===----------------------------------------------------------------------===//
+
+#include "CGCXXABI.h"
+#include "CodeGenModule.h"
+#include "Mangle.h"
+
+using namespace clang;
+
+namespace {
+class ItaniumCXXABI : public CodeGen::CXXABI {
+ CodeGen::MangleContext MangleCtx;
+public:
+ ItaniumCXXABI(CodeGen::CodeGenModule &CGM) :
+ MangleCtx(CGM.getContext(), CGM.getDiags()) { }
+
+ CodeGen::MangleContext &getMangleContext() {
+ return MangleCtx;
+ }
+};
+}
+
+CodeGen::CXXABI *CodeGen::CreateItaniumCXXABI(CodeGenModule &CGM) {
+ return new ItaniumCXXABI(CGM);
+}
+
diff --git a/lib/CodeGen/Mangle.cpp b/lib/CodeGen/Mangle.cpp
index 8658cfb0282c..6c2a64898fee 100644
--- a/lib/CodeGen/Mangle.cpp
+++ b/lib/CodeGen/Mangle.cpp
@@ -36,6 +36,57 @@
using namespace clang;
using namespace CodeGen;
+MiscNameMangler::MiscNameMangler(MangleContext &C,
+ llvm::SmallVectorImpl<char> &Res)
+ : Context(C), Out(Res) { }
+
+void MiscNameMangler::mangleBlock(const BlockDecl *BD) {
+ // Mangle the context of the block.
+ // FIXME: We currently mimic GCC's mangling scheme, which leaves much to be
+ // desired. Come up with a better mangling scheme.
+ const DeclContext *DC = BD->getDeclContext();
+ while (isa<BlockDecl>(DC) || isa<EnumDecl>(DC))
+ DC = DC->getParent();
+ if (DC->isFunctionOrMethod()) {
+ Out << "__";
+ if (const ObjCMethodDecl *Method = dyn_cast<ObjCMethodDecl>(DC))
+ mangleObjCMethodName(Method);
+ else {
+ const NamedDecl *ND = cast<NamedDecl>(DC);
+ if (IdentifierInfo *II = ND->getIdentifier())
+ Out << II->getName();
+ else {
+ // FIXME: We were doing a mangleUnqualifiedName() before, but that's
+ // a private member of a class that will soon itself be private to the
+ // Itanium C++ ABI object. What should we do now? Right now, I'm just
+ // calling the mangleName() method on the MangleContext; is there a
+ // better way?
+ llvm::SmallString<64> Buffer;
+ Context.mangleName(ND, Buffer);
+ Out << Buffer;
+ }
+ }
+ Out << "_block_invoke_" << Context.getBlockId(BD, true);
+ } else {
+ Out << "__block_global_" << Context.getBlockId(BD, false);
+ }
+}
+
+void MiscNameMangler::mangleObjCMethodName(const ObjCMethodDecl *MD) {
+ llvm::SmallString<64> Name;
+ llvm::raw_svector_ostream OS(Name);
+
+ const ObjCContainerDecl *CD =
+ dyn_cast<ObjCContainerDecl>(MD->getDeclContext());
+ assert (CD && "Missing container decl in GetNameForMethod");
+ OS << (MD->isInstanceMethod() ? '-' : '+') << '[' << CD->getName();
+ if (const ObjCCategoryImplDecl *CID = dyn_cast<ObjCCategoryImplDecl>(CD))
+ OS << '(' << CID << ')';
+ OS << ' ' << MD->getSelector().getAsString() << ']';
+
+ Out << OS.str().size() << OS.str();
+}
+
namespace {
static const DeclContext *GetLocalClassFunctionDeclContext(
@@ -107,7 +158,8 @@ public:
void mangleFunctionEncoding(const FunctionDecl *FD);
void mangleName(const NamedDecl *ND);
void mangleType(QualType T);
-
+ void mangleNameOrStandardSubstitution(const NamedDecl *ND);
+
private:
bool mangleSubstitution(const NamedDecl *ND);
bool mangleSubstitution(QualType T);
@@ -714,8 +766,9 @@ void CXXNameMangler::mangleLocalName(const NamedDecl *ND) {
const DeclContext *DC = ND->getDeclContext();
Out << 'Z';
- if (const ObjCMethodDecl *MD = dyn_cast<ObjCMethodDecl>(DC))
- mangleObjCMethodName(MD);
+ if (const ObjCMethodDecl *MD = dyn_cast<ObjCMethodDecl>(DC)) {
+ mangleObjCMethodName(MD);
+ }
else if (const DeclContext *CDC = GetLocalClassFunctionDeclContext(DC)) {
mangleFunctionEncoding(cast<FunctionDecl>(CDC));
Out << 'E';
@@ -752,6 +805,14 @@ void CXXNameMangler::manglePrefix(const DeclContext *DC, bool NoFunction) {
if (DC->isTranslationUnit())
return;
+ if (const BlockDecl *Block = dyn_cast<BlockDecl>(DC)) {
+ manglePrefix(DC->getParent(), NoFunction);
+ llvm::SmallString<64> Name;
+ Context.mangleBlock(Block, Name);
+ Out << Name.size() << Name;
+ return;
+ }
+
if (mangleSubstitution(cast<NamedDecl>(DC)))
return;
@@ -762,8 +823,10 @@ void CXXNameMangler::manglePrefix(const DeclContext *DC, bool NoFunction) {
TemplateParameterList *TemplateParameters = TD->getTemplateParameters();
mangleTemplateArgs(*TemplateParameters, *TemplateArgs);
}
- else if(NoFunction && isa<FunctionDecl>(DC))
+ else if(NoFunction && (isa<FunctionDecl>(DC) || isa<ObjCMethodDecl>(DC)))
return;
+ else if (const ObjCMethodDecl *Method = dyn_cast<ObjCMethodDecl>(DC))
+ mangleObjCMethodName(Method);
else {
manglePrefix(DC->getParent(), NoFunction);
mangleUnqualifiedName(cast<NamedDecl>(DC));
@@ -942,18 +1005,9 @@ void CXXNameMangler::mangleQualifiers(Qualifiers Quals) {
}
void CXXNameMangler::mangleObjCMethodName(const ObjCMethodDecl *MD) {
- llvm::SmallString<64> Name;
- llvm::raw_svector_ostream OS(Name);
-
- const ObjCContainerDecl *CD =
- dyn_cast<ObjCContainerDecl>(MD->getDeclContext());
- assert (CD && "Missing container decl in GetNameForMethod");
- OS << (MD->isInstanceMethod() ? '-' : '+') << '[' << CD->getName();
- if (const ObjCCategoryImplDecl *CID = dyn_cast<ObjCCategoryImplDecl>(CD))
- OS << '(' << CID << ')';
- OS << ' ' << MD->getSelector().getAsString() << ']';
-
- Out << OS.str().size() << OS.str();
+ llvm::SmallString<64> Buffer;
+ MiscNameMangler(Context, Buffer).mangleObjCMethodName(MD);
+ Out << Buffer;
}
void CXXNameMangler::mangleType(QualType T) {
@@ -989,6 +1043,11 @@ void CXXNameMangler::mangleType(QualType T) {
addSubstitution(T);
}
+void CXXNameMangler::mangleNameOrStandardSubstitution(const NamedDecl *ND) {
+ if (!mangleStandardSubstitution(ND))
+ mangleName(ND);
+}
+
void CXXNameMangler::mangleType(const BuiltinType *T) {
// <type> ::= <builtin-type>
// <builtin-type> ::= v # void
@@ -1206,6 +1265,12 @@ void CXXNameMangler::mangleType(const ObjCInterfaceType *T) {
mangleSourceName(T->getDecl()->getIdentifier());
}
+void CXXNameMangler::mangleType(const ObjCObjectType *T) {
+ // We don't allow overloading by different protocol qualification,
+ // so mangling them isn't necessary.
+ mangleType(T->getBaseType());
+}
+
void CXXNameMangler::mangleType(const BlockPointerType *T) {
Out << "U13block_pointer";
mangleType(T->getPointeeType());
@@ -1369,7 +1434,7 @@ void CXXNameMangler::mangleExpression(const Expr *E) {
#define EXPR(Type, Base)
#define STMT(Type, Base) \
case Expr::Type##Class:
-#include "clang/AST/StmtNodes.def"
+#include "clang/AST/StmtNodes.inc"
llvm_unreachable("unexpected statement kind");
break;
@@ -2027,6 +2092,12 @@ void MangleContext::mangleCXXDtor(const CXXDestructorDecl *D, CXXDtorType Type,
Mangler.mangle(D);
}
+void MangleContext::mangleBlock(const BlockDecl *BD,
+ llvm::SmallVectorImpl<char> &Res) {
+ MiscNameMangler Mangler(*this, Res);
+ Mangler.mangleBlock(BD);
+}
+
void MangleContext::mangleThunk(const CXXMethodDecl *MD,
const ThunkInfo &Thunk,
llvm::SmallVectorImpl<char> &Res) {
@@ -2089,7 +2160,7 @@ void MangleContext::mangleCXXVTable(const CXXRecordDecl *RD,
// <special-name> ::= TV <type> # virtual table
CXXNameMangler Mangler(*this, Res);
Mangler.getStream() << "_ZTV";
- Mangler.mangleName(RD);
+ Mangler.mangleNameOrStandardSubstitution(RD);
}
void MangleContext::mangleCXXVTT(const CXXRecordDecl *RD,
@@ -2097,7 +2168,7 @@ void MangleContext::mangleCXXVTT(const CXXRecordDecl *RD,
// <special-name> ::= TT <type> # VTT structure
CXXNameMangler Mangler(*this, Res);
Mangler.getStream() << "_ZTT";
- Mangler.mangleName(RD);
+ Mangler.mangleNameOrStandardSubstitution(RD);
}
void MangleContext::mangleCXXCtorVTable(const CXXRecordDecl *RD, int64_t Offset,
@@ -2106,10 +2177,10 @@ void MangleContext::mangleCXXCtorVTable(const CXXRecordDecl *RD, int64_t Offset,
// <special-name> ::= TC <type> <offset number> _ <base type>
CXXNameMangler Mangler(*this, Res);
Mangler.getStream() << "_ZTC";
- Mangler.mangleName(RD);
+ Mangler.mangleNameOrStandardSubstitution(RD);
Mangler.getStream() << Offset;
Mangler.getStream() << '_';
- Mangler.mangleName(Type);
+ Mangler.mangleNameOrStandardSubstitution(Type);
}
void MangleContext::mangleCXXRTTI(QualType Ty,
diff --git a/lib/CodeGen/Mangle.h b/lib/CodeGen/Mangle.h
index da3626fc5d37..f1c5358bdd85 100644
--- a/lib/CodeGen/Mangle.h
+++ b/lib/CodeGen/Mangle.h
@@ -23,14 +23,17 @@
#include "llvm/ADT/DenseMap.h"
#include "llvm/ADT/StringRef.h"
#include "llvm/ADT/SmallString.h"
+#include "llvm/Support/raw_ostream.h"
namespace clang {
class ASTContext;
+ class BlockDecl;
class CXXConstructorDecl;
class CXXDestructorDecl;
class CXXMethodDecl;
class FunctionDecl;
class NamedDecl;
+ class ObjCMethodDecl;
class VarDecl;
namespace CodeGen {
@@ -63,7 +66,7 @@ private:
llvm::StringRef String;
llvm::SmallString<256> Buffer;
};
-
+
/// MangleContext - Context for tracking state which persists across multiple
/// calls to the C++ name mangler.
class MangleContext {
@@ -73,6 +76,8 @@ class MangleContext {
llvm::DenseMap<const TagDecl *, uint64_t> AnonStructIds;
unsigned Discriminator;
llvm::DenseMap<const NamedDecl*, unsigned> Uniquifier;
+ llvm::DenseMap<const BlockDecl*, unsigned> GlobalBlockIds;
+ llvm::DenseMap<const BlockDecl*, unsigned> LocalBlockIds;
public:
explicit MangleContext(ASTContext &Context,
@@ -83,6 +88,8 @@ public:
Diagnostic &getDiags() const { return Diags; }
+ void startNewFunction() { LocalBlockIds.clear(); }
+
uint64_t getAnonymousStructId(const TagDecl *TD) {
std::pair<llvm::DenseMap<const TagDecl *,
uint64_t>::iterator, bool> Result =
@@ -90,31 +97,42 @@ public:
return Result.first->second;
}
+ unsigned getBlockId(const BlockDecl *BD, bool Local) {
+ llvm::DenseMap<const BlockDecl *, unsigned> &BlockIds
+ = Local? LocalBlockIds : GlobalBlockIds;
+ std::pair<llvm::DenseMap<const BlockDecl *, unsigned>::iterator, bool>
+ Result = BlockIds.insert(std::make_pair(BD, BlockIds.size()));
+ return Result.first->second;
+ }
+
/// @name Mangler Entry Points
/// @{
bool shouldMangleDeclName(const NamedDecl *D);
-
- void mangleName(const NamedDecl *D, llvm::SmallVectorImpl<char> &);
- void mangleThunk(const CXXMethodDecl *MD,
- const ThunkInfo &Thunk,
- llvm::SmallVectorImpl<char> &);
- void mangleCXXDtorThunk(const CXXDestructorDecl *DD, CXXDtorType Type,
- const ThisAdjustment &ThisAdjustment,
+ virtual void mangleName(const NamedDecl *D, llvm::SmallVectorImpl<char> &);
+ virtual void mangleThunk(const CXXMethodDecl *MD,
+ const ThunkInfo &Thunk,
llvm::SmallVectorImpl<char> &);
- void mangleGuardVariable(const VarDecl *D, llvm::SmallVectorImpl<char> &);
- void mangleCXXVTable(const CXXRecordDecl *RD, llvm::SmallVectorImpl<char> &);
- void mangleCXXVTT(const CXXRecordDecl *RD, llvm::SmallVectorImpl<char> &);
- void mangleCXXCtorVTable(const CXXRecordDecl *RD, int64_t Offset,
- const CXXRecordDecl *Type,
- llvm::SmallVectorImpl<char> &);
- void mangleCXXRTTI(QualType T, llvm::SmallVectorImpl<char> &);
- void mangleCXXRTTIName(QualType T, llvm::SmallVectorImpl<char> &);
- void mangleCXXCtor(const CXXConstructorDecl *D, CXXCtorType Type,
- llvm::SmallVectorImpl<char> &);
- void mangleCXXDtor(const CXXDestructorDecl *D, CXXDtorType Type,
- llvm::SmallVectorImpl<char> &);
-
+ virtual void mangleCXXDtorThunk(const CXXDestructorDecl *DD, CXXDtorType Type,
+ const ThisAdjustment &ThisAdjustment,
+ llvm::SmallVectorImpl<char> &);
+ virtual void mangleGuardVariable(const VarDecl *D,
+ llvm::SmallVectorImpl<char> &);
+ virtual void mangleCXXVTable(const CXXRecordDecl *RD,
+ llvm::SmallVectorImpl<char> &);
+ virtual void mangleCXXVTT(const CXXRecordDecl *RD,
+ llvm::SmallVectorImpl<char> &);
+ virtual void mangleCXXCtorVTable(const CXXRecordDecl *RD, int64_t Offset,
+ const CXXRecordDecl *Type,
+ llvm::SmallVectorImpl<char> &);
+ virtual void mangleCXXRTTI(QualType T, llvm::SmallVectorImpl<char> &);
+ virtual void mangleCXXRTTIName(QualType T, llvm::SmallVectorImpl<char> &);
+ virtual void mangleCXXCtor(const CXXConstructorDecl *D, CXXCtorType Type,
+ llvm::SmallVectorImpl<char> &);
+ virtual void mangleCXXDtor(const CXXDestructorDecl *D, CXXDtorType Type,
+ llvm::SmallVectorImpl<char> &);
+ void mangleBlock(const BlockDecl *BD, llvm::SmallVectorImpl<char> &);
+
void mangleInitDiscriminator() {
Discriminator = 0;
}
@@ -130,7 +148,23 @@ public:
}
/// @}
};
+
+/// MiscNameMangler - Mangles Objective-C method names and blocks.
+class MiscNameMangler {
+ MangleContext &Context;
+ llvm::raw_svector_ostream Out;
+ ASTContext &getASTContext() const { return Context.getASTContext(); }
+
+public:
+ MiscNameMangler(MangleContext &C, llvm::SmallVectorImpl<char> &Res);
+
+ llvm::raw_svector_ostream &getStream() { return Out; }
+
+ void mangleBlock(const BlockDecl *BD);
+ void mangleObjCMethodName(const ObjCMethodDecl *MD);
+};
+
}
}
diff --git a/lib/CodeGen/ModuleBuilder.cpp b/lib/CodeGen/ModuleBuilder.cpp
index 1e1edc1c482f..9905ca6f1dc8 100644
--- a/lib/CodeGen/ModuleBuilder.cpp
+++ b/lib/CodeGen/ModuleBuilder.cpp
@@ -89,6 +89,13 @@ namespace {
Builder->EmitTentativeDefinition(D);
}
+
+ virtual void HandleVTable(CXXRecordDecl *RD, bool DefinitionRequired) {
+ if (Diags.hasErrorOccurred())
+ return;
+
+ Builder->EmitVTable(RD, DefinitionRequired);
+ }
};
}
diff --git a/lib/CodeGen/TargetInfo.cpp b/lib/CodeGen/TargetInfo.cpp
index e1fdf86eb026..b29d3cb00c4a 100644
--- a/lib/CodeGen/TargetInfo.cpp
+++ b/lib/CodeGen/TargetInfo.cpp
@@ -23,6 +23,18 @@
using namespace clang;
using namespace CodeGen;
+static void AssignToArrayRange(CodeGen::CGBuilderTy &Builder,
+ llvm::Value *Array,
+ llvm::Value *Value,
+ unsigned FirstIndex,
+ unsigned LastIndex) {
+ // Alternatively, we could emit this as a loop in the source.
+ for (unsigned I = FirstIndex; I <= LastIndex; ++I) {
+ llvm::Value *Cell = Builder.CreateConstInBoundsGEP1_32(Array, I);
+ Builder.CreateStore(Value, Cell);
+ }
+}
+
ABIInfo::~ABIInfo() {}
void ABIArgInfo::dump() const {
@@ -71,6 +83,17 @@ static bool isEmptyField(ASTContext &Context, const FieldDecl *FD,
while (const ConstantArrayType *AT = Context.getAsConstantArrayType(FT))
FT = AT->getElementType();
+ const RecordType *RT = FT->getAs<RecordType>();
+ if (!RT)
+ return false;
+
+ // C++ record fields are never empty, at least in the Itanium ABI.
+ //
+ // FIXME: We should use a predicate for whether this behavior is true in the
+ // current ABI.
+ if (isa<CXXRecordDecl>(RT->getDecl()))
+ return false;
+
return isEmptyRecord(Context, FT, AllowArrays);
}
@@ -84,6 +107,14 @@ static bool isEmptyRecord(ASTContext &Context, QualType T, bool AllowArrays) {
const RecordDecl *RD = RT->getDecl();
if (RD->hasFlexibleArrayMember())
return false;
+
+ // If this is a C++ record, check the bases first.
+ if (const CXXRecordDecl *CXXRD = dyn_cast<CXXRecordDecl>(RD))
+ for (CXXRecordDecl::base_class_const_iterator i = CXXRD->bases_begin(),
+ e = CXXRD->bases_end(); i != e; ++i)
+ if (!isEmptyRecord(Context, i->getType(), true))
+ return false;
+
for (RecordDecl::field_iterator i = RD->field_begin(), e = RD->field_end();
i != e; ++i)
if (!isEmptyField(Context, *i, AllowArrays))
@@ -130,6 +161,28 @@ static const Type *isSingleElementStruct(QualType T, ASTContext &Context) {
return 0;
const Type *Found = 0;
+
+ // If this is a C++ record, check the bases first.
+ if (const CXXRecordDecl *CXXRD = dyn_cast<CXXRecordDecl>(RD)) {
+ for (CXXRecordDecl::base_class_const_iterator i = CXXRD->bases_begin(),
+ e = CXXRD->bases_end(); i != e; ++i) {
+ // Ignore empty records.
+ if (isEmptyRecord(Context, i->getType(), true))
+ continue;
+
+ // If we already found an element then this isn't a single-element struct.
+ if (Found)
+ return 0;
+
+ // If this is non-empty and not a single element struct, the composite
+ // cannot be a single element struct.
+ Found = isSingleElementStruct(i->getType(), Context);
+ if (!Found)
+ return 0;
+ }
+ }
+
+ // Check for single element.
for (RecordDecl::field_iterator i = RD->field_begin(), e = RD->field_end();
i != e; ++i) {
const FieldDecl *FD = *i;
@@ -164,7 +217,7 @@ static const Type *isSingleElementStruct(QualType T, ASTContext &Context) {
}
static bool is32Or64BitBasicType(QualType Ty, ASTContext &Context) {
- if (!Ty->getAs<BuiltinType>() && !Ty->isAnyPointerType() &&
+ if (!Ty->getAs<BuiltinType>() && !Ty->hasPointerRepresentation() &&
!Ty->isAnyComplexType() && !Ty->isEnumeralType() &&
!Ty->isBlockPointerType())
return false;
@@ -212,23 +265,6 @@ static bool canExpandIndirectArgument(QualType Ty, ASTContext &Context) {
return true;
}
-static bool typeContainsSSEVector(const RecordDecl *RD, ASTContext &Context) {
- for (RecordDecl::field_iterator i = RD->field_begin(), e = RD->field_end();
- i != e; ++i) {
- const FieldDecl *FD = *i;
-
- if (FD->getType()->isVectorType() &&
- Context.getTypeSize(FD->getType()) >= 128)
- return true;
-
- if (const RecordType* RT = FD->getType()->getAs<RecordType>())
- if (typeContainsSSEVector(RT->getDecl(), Context))
- return true;
- }
-
- return false;
-}
-
namespace {
/// DefaultABIInfo - The default implementation for ABI specific
/// details. This implementation provides information which results in
@@ -363,10 +399,11 @@ bool X86_32ABIInfo::shouldReturnTypeInRegister(QualType Ty,
return true;
}
- // If this is a builtin, pointer, enum, or complex type, it is ok.
- if (Ty->getAs<BuiltinType>() || Ty->isAnyPointerType() ||
+ // If this is a builtin, pointer, enum, complex type, member pointer, or
+ // member function pointer it is ok.
+ if (Ty->getAs<BuiltinType>() || Ty->hasPointerRepresentation() ||
Ty->isAnyComplexType() || Ty->isEnumeralType() ||
- Ty->isBlockPointerType())
+ Ty->isBlockPointerType() || Ty->isMemberPointerType())
return true;
// Arrays are treated like records.
@@ -596,20 +633,14 @@ bool X86_32TargetCodeGenInfo::initDwarfEHRegSizeTable(
// 0-7 are the eight integer registers; the order is different
// on Darwin (for EH), but the range is the same.
// 8 is %eip.
- for (unsigned I = 0, E = 9; I != E; ++I) {
- llvm::Value *Slot = Builder.CreateConstInBoundsGEP1_32(Address, I);
- Builder.CreateStore(Four8, Slot);
- }
+ AssignToArrayRange(Builder, Address, Four8, 0, 8);
if (CGF.CGM.isTargetDarwin()) {
// 12-16 are st(0..4). Not sure why we stop at 4.
// These have size 16, which is sizeof(long double) on
// platforms with 8-byte alignment for that type.
llvm::Value *Sixteen8 = llvm::ConstantInt::get(i8, 16);
- for (unsigned I = 12, E = 17; I != E; ++I) {
- llvm::Value *Slot = Builder.CreateConstInBoundsGEP1_32(Address, I);
- Builder.CreateStore(Sixteen8, Slot);
- }
+ AssignToArrayRange(Builder, Address, Sixteen8, 12, 16);
} else {
// 9 is %eflags, which doesn't get a size on Darwin for some
@@ -620,11 +651,8 @@ bool X86_32TargetCodeGenInfo::initDwarfEHRegSizeTable(
// These have size 12, which is sizeof(long double) on
// platforms with 4-byte alignment for that type.
llvm::Value *Twelve8 = llvm::ConstantInt::get(i8, 12);
- for (unsigned I = 11, E = 17; I != E; ++I) {
- llvm::Value *Slot = Builder.CreateConstInBoundsGEP1_32(Address, I);
- Builder.CreateStore(Twelve8, Slot);
- }
- }
+ AssignToArrayRange(Builder, Address, Twelve8, 11, 16);
+ }
return false;
}
@@ -733,12 +761,9 @@ public:
const llvm::IntegerType *i8 = llvm::Type::getInt8Ty(Context);
llvm::Value *Eight8 = llvm::ConstantInt::get(i8, 8);
- // 0-16 are the 16 integer registers.
- // 17 is %rip.
- for (unsigned I = 0, E = 17; I != E; ++I) {
- llvm::Value *Slot = Builder.CreateConstInBoundsGEP1_32(Address, I);
- Builder.CreateStore(Eight8, Slot);
- }
+ // 0-15 are the 16 integer registers.
+ // 16 is %rip.
+ AssignToArrayRange(Builder, Address, Eight8, 0, 16);
return false;
}
@@ -828,6 +853,11 @@ void X86_64ABIInfo::classify(QualType Ty,
classify(ET->getDecl()->getIntegerType(), Context, OffsetBase, Lo, Hi);
} else if (Ty->hasPointerRepresentation()) {
Current = Integer;
+ } else if (Ty->isMemberPointerType()) {
+ if (Ty->isMemberFunctionPointerType())
+ Lo = Hi = Integer;
+ else
+ Current = Integer;
} else if (const VectorType *VT = Ty->getAs<VectorType>()) {
uint64_t Size = Context.getTypeSize(VT);
if (Size == 32) {
@@ -1661,16 +1691,10 @@ PPC32TargetCodeGenInfo::initDwarfEHRegSizeTable(CodeGen::CodeGenFunction &CGF,
llvm::Value *Sixteen8 = llvm::ConstantInt::get(i8, 16);
// 0-31: r0-31, the 4-byte general-purpose registers
- for (unsigned I = 0, E = 32; I != E; ++I) {
- llvm::Value *Slot = Builder.CreateConstInBoundsGEP1_32(Address, I);
- Builder.CreateStore(Four8, Slot);
- }
+ AssignToArrayRange(Builder, Address, Four8, 0, 31);
// 32-63: fp0-31, the 8-byte floating-point registers
- for (unsigned I = 32, E = 64; I != E; ++I) {
- llvm::Value *Slot = Builder.CreateConstInBoundsGEP1_32(Address, I);
- Builder.CreateStore(Eight8, Slot);
- }
+ AssignToArrayRange(Builder, Address, Eight8, 32, 63);
// 64-76 are various 4-byte special-purpose registers:
// 64: mq
@@ -1679,26 +1703,17 @@ PPC32TargetCodeGenInfo::initDwarfEHRegSizeTable(CodeGen::CodeGenFunction &CGF,
// 67: ap
// 68-75 cr0-7
// 76: xer
- for (unsigned I = 64, E = 77; I != E; ++I) {
- llvm::Value *Slot = Builder.CreateConstInBoundsGEP1_32(Address, I);
- Builder.CreateStore(Four8, Slot);
- }
+ AssignToArrayRange(Builder, Address, Four8, 64, 76);
// 77-108: v0-31, the 16-byte vector registers
- for (unsigned I = 77, E = 109; I != E; ++I) {
- llvm::Value *Slot = Builder.CreateConstInBoundsGEP1_32(Address, I);
- Builder.CreateStore(Sixteen8, Slot);
- }
+ AssignToArrayRange(Builder, Address, Sixteen8, 77, 108);
// 109: vrsave
// 110: vscr
// 111: spe_acc
// 112: spefscr
// 113: sfp
- for (unsigned I = 109, E = 114; I != E; ++I) {
- llvm::Value *Slot = Builder.CreateConstInBoundsGEP1_32(Address, I);
- Builder.CreateStore(Four8, Slot);
- }
+ AssignToArrayRange(Builder, Address, Four8, 109, 113);
return false;
}
@@ -2123,6 +2138,56 @@ void MSP430TargetCodeGenInfo::SetTargetAttributes(const Decl *D,
}
}
+// MIPS ABI Implementation. This works for both little-endian and
+// big-endian variants.
+namespace {
+class MIPSTargetCodeGenInfo : public TargetCodeGenInfo {
+public:
+ MIPSTargetCodeGenInfo(): TargetCodeGenInfo(new DefaultABIInfo()) {}
+
+ int getDwarfEHStackPointer(CodeGen::CodeGenModule &CGM) const {
+ return 29;
+ }
+
+ bool initDwarfEHRegSizeTable(CodeGen::CodeGenFunction &CGF,
+ llvm::Value *Address) const;
+};
+}
+
+bool
+MIPSTargetCodeGenInfo::initDwarfEHRegSizeTable(CodeGen::CodeGenFunction &CGF,
+ llvm::Value *Address) const {
+ // This information comes from gcc's implementation, which seems to
+ // as canonical as it gets.
+
+ CodeGen::CGBuilderTy &Builder = CGF.Builder;
+ llvm::LLVMContext &Context = CGF.getLLVMContext();
+
+ // Everything on MIPS is 4 bytes. Double-precision FP registers
+ // are aliased to pairs of single-precision FP registers.
+ const llvm::IntegerType *i8 = llvm::Type::getInt8Ty(Context);
+ llvm::Value *Four8 = llvm::ConstantInt::get(i8, 4);
+
+ // 0-31 are the general purpose registers, $0 - $31.
+ // 32-63 are the floating-point registers, $f0 - $f31.
+ // 64 and 65 are the multiply/divide registers, $hi and $lo.
+ // 66 is the (notional, I think) register for signal-handler return.
+ AssignToArrayRange(Builder, Address, Four8, 0, 65);
+
+ // 67-74 are the floating-point status registers, $fcc0 - $fcc7.
+ // They are one bit wide and ignored here.
+
+ // 80-111 are the coprocessor 0 registers, $c0r0 - $c0r31.
+ // (coprocessor 1 is the FP unit)
+ // 112-143 are the coprocessor 2 registers, $c2r0 - $c2r31.
+ // 144-175 are the coprocessor 3 registers, $c3r0 - $c3r31.
+ // 176-181 are the DSP accumulator registers.
+ AssignToArrayRange(Builder, Address, Four8, 80, 181);
+
+ return false;
+}
+
+
const TargetCodeGenInfo &CodeGenModule::getTargetCodeGenInfo() const {
if (TheTargetCodeGenInfo)
return *TheTargetCodeGenInfo;
@@ -2135,6 +2200,10 @@ const TargetCodeGenInfo &CodeGenModule::getTargetCodeGenInfo() const {
default:
return *(TheTargetCodeGenInfo = new DefaultTargetCodeGenInfo);
+ case llvm::Triple::mips:
+ case llvm::Triple::mipsel:
+ return *(TheTargetCodeGenInfo = new MIPSTargetCodeGenInfo());
+
case llvm::Triple::arm:
case llvm::Triple::thumb:
// FIXME: We want to know the float calling convention as well.
diff --git a/lib/Driver/ArgList.cpp b/lib/Driver/ArgList.cpp
index 95805b016b1f..3d07431209e2 100644
--- a/lib/Driver/ArgList.cpp
+++ b/lib/Driver/ArgList.cpp
@@ -9,12 +9,14 @@
#include "clang/Driver/ArgList.h"
#include "clang/Driver/Arg.h"
+#include "clang/Driver/DriverDiagnostic.h"
#include "clang/Driver/Option.h"
#include "llvm/ADT/SmallString.h"
#include "llvm/ADT/Twine.h"
#include "llvm/Support/raw_ostream.h"
+using namespace clang;
using namespace clang::driver;
void arg_iterator::SkipToNextArg() {
@@ -108,6 +110,32 @@ bool ArgList::hasFlag(OptSpecifier Pos, OptSpecifier Neg, bool Default) const {
return Default;
}
+llvm::StringRef ArgList::getLastArgValue(OptSpecifier Id,
+ llvm::StringRef Default) const {
+ if (Arg *A = getLastArg(Id))
+ return A->getValue(*this);
+ return Default;
+}
+
+int ArgList::getLastArgIntValue(OptSpecifier Id, int Default,
+ clang::Diagnostic &Diags) const {
+ int Res = Default;
+
+ if (Arg *A = getLastArg(Id)) {
+ if (llvm::StringRef(A->getValue(*this)).getAsInteger(10, Res))
+ Diags.Report(diag::err_drv_invalid_int_value)
+ << A->getAsString(*this) << A->getValue(*this);
+ }
+
+ return Res;
+}
+
+std::vector<std::string> ArgList::getAllArgValues(OptSpecifier Id) const {
+ llvm::SmallVector<const char *, 16> Values;
+ AddAllArgValues(Values, Id);
+ return std::vector<std::string>(Values.begin(), Values.end());
+}
+
void ArgList::AddLastArg(ArgStringList &Output, OptSpecifier Id) const {
if (Arg *A = getLastArg(Id)) {
A->claim();
diff --git a/lib/Driver/CC1AsOptions.cpp b/lib/Driver/CC1AsOptions.cpp
new file mode 100644
index 000000000000..90c69ff0d62a
--- /dev/null
+++ b/lib/Driver/CC1AsOptions.cpp
@@ -0,0 +1,39 @@
+//===--- CC1AsOptions.cpp - Clang Assembler Options Table -----------------===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#include "clang/Driver/CC1AsOptions.h"
+#include "clang/Driver/Option.h"
+#include "clang/Driver/OptTable.h"
+using namespace clang;
+using namespace clang::driver;
+using namespace clang::driver::options;
+using namespace clang::driver::cc1asoptions;
+
+static const OptTable::Info CC1AsInfoTable[] = {
+#define OPTION(NAME, ID, KIND, GROUP, ALIAS, FLAGS, PARAM, \
+ HELPTEXT, METAVAR) \
+ { NAME, HELPTEXT, METAVAR, Option::KIND##Class, FLAGS, PARAM, \
+ OPT_##GROUP, OPT_##ALIAS },
+#include "clang/Driver/CC1AsOptions.inc"
+};
+
+namespace {
+
+class CC1AsOptTable : public OptTable {
+public:
+ CC1AsOptTable()
+ : OptTable(CC1AsInfoTable,
+ sizeof(CC1AsInfoTable) / sizeof(CC1AsInfoTable[0])) {}
+};
+
+}
+
+OptTable *clang::driver::createCC1AsOptTable() {
+ return new CC1AsOptTable();
+}
diff --git a/lib/Driver/CC1Options.cpp b/lib/Driver/CC1Options.cpp
index 0e98bb9c113b..14cf0904c45b 100644
--- a/lib/Driver/CC1Options.cpp
+++ b/lib/Driver/CC1Options.cpp
@@ -1,4 +1,4 @@
-//===--- CC1Options.cpp - Clang CC1 Options Table -----------------------*-===//
+//===--- CC1Options.cpp - Clang CC1 Options Table -------------------------===//
//
// The LLVM Compiler Infrastructure
//
diff --git a/lib/Driver/CMakeLists.txt b/lib/Driver/CMakeLists.txt
index 7efcd8a8dde4..5af754d7d142 100644
--- a/lib/Driver/CMakeLists.txt
+++ b/lib/Driver/CMakeLists.txt
@@ -5,6 +5,7 @@ add_clang_library(clangDriver
Arg.cpp
ArgList.cpp
CC1Options.cpp
+ CC1AsOptions.cpp
Compilation.cpp
Driver.cpp
DriverOptions.cpp
@@ -20,4 +21,5 @@ add_clang_library(clangDriver
Types.cpp
)
-add_dependencies(clangDriver ClangDiagnosticDriver ClangDriverOptions ClangCC1Options)
+add_dependencies(clangDriver ClangDiagnosticDriver ClangDriverOptions
+ ClangCC1Options ClangCC1AsOptions)
diff --git a/lib/Driver/Driver.cpp b/lib/Driver/Driver.cpp
index 7371a930c337..da83803dd701 100644
--- a/lib/Driver/Driver.cpp
+++ b/lib/Driver/Driver.cpp
@@ -227,28 +227,31 @@ int Driver::ExecuteCompilation(const Compilation &C) const {
// Remove temp files.
C.CleanupFileList(C.getTempFiles());
- // If the compilation failed, remove result files as well.
- if (Res != 0 && !C.getArgs().hasArg(options::OPT_save_temps))
+ // If the command succeeded, we are done.
+ if (Res == 0)
+ return Res;
+
+ // Otherwise, remove result files as well.
+ if (!C.getArgs().hasArg(options::OPT_save_temps))
C.CleanupFileList(C.getResultFiles(), true);
// Print extra information about abnormal failures, if possible.
- if (Res) {
- // This is ad-hoc, but we don't want to be excessively noisy. If the result
- // status was 1, assume the command failed normally. In particular, if it
- // was the compiler then assume it gave a reasonable error code. Failures in
- // other tools are less common, and they generally have worse diagnostics,
- // so always print the diagnostic there.
- const Action &Source = FailingCommand->getSource();
-
- if (!FailingCommand->getCreator().hasGoodDiagnostics() || Res != 1) {
- // FIXME: See FIXME above regarding result code interpretation.
- if (Res < 0)
- Diag(clang::diag::err_drv_command_signalled)
- << Source.getClassName() << -Res;
- else
- Diag(clang::diag::err_drv_command_failed)
- << Source.getClassName() << Res;
- }
+ //
+ // This is ad-hoc, but we don't want to be excessively noisy. If the result
+ // status was 1, assume the command failed normally. In particular, if it was
+ // the compiler then assume it gave a reasonable error code. Failures in other
+ // tools are less common, and they generally have worse diagnostics, so always
+ // print the diagnostic there.
+ const Tool &FailingTool = FailingCommand->getCreator();
+
+ if (!FailingCommand->getCreator().hasGoodDiagnostics() || Res != 1) {
+ // FIXME: See FIXME above regarding result code interpretation.
+ if (Res < 0)
+ Diag(clang::diag::err_drv_command_signalled)
+ << FailingTool.getShortName() << -Res;
+ else
+ Diag(clang::diag::err_drv_command_failed)
+ << FailingTool.getShortName() << Res;
}
return Res;
@@ -291,6 +294,14 @@ void Driver::PrintVersion(const Compilation &C, llvm::raw_ostream &OS) const {
OS << "Thread model: " << "posix" << '\n';
}
+/// PrintDiagnosticCategories - Implement the --print-diagnostic-categories
+/// option.
+static void PrintDiagnosticCategories(llvm::raw_ostream &OS) {
+ for (unsigned i = 1; // Skip the empty category.
+ const char *CategoryName = Diagnostic::getCategoryNameFromID(i); ++i)
+ OS << i << ',' << CategoryName << '\n';
+}
+
bool Driver::HandleImmediateArgs(const Compilation &C) {
// The order these options are handled in in gcc is all over the place, but we
// don't expect inconsistencies w.r.t. that to matter in practice.
@@ -299,6 +310,11 @@ bool Driver::HandleImmediateArgs(const Compilation &C) {
llvm::outs() << CLANG_VERSION_STRING "\n";
return false;
}
+
+ if (C.getArgs().hasArg(options::OPT__print_diagnostic_categories)) {
+ PrintDiagnosticCategories(llvm::outs());
+ return false;
+ }
if (C.getArgs().hasArg(options::OPT__help) ||
C.getArgs().hasArg(options::OPT__help_hidden)) {
@@ -889,9 +905,16 @@ static const Tool &SelectToolForJob(Compilation &C, const ToolChain *TC,
// See if we should look for a compiler with an integrated assembler. We match
// bottom up, so what we are actually looking for is an assembler job with a
// compiler input.
- if (C.getArgs().hasArg(options::OPT_integrated_as,
+
+ // FIXME: This doesn't belong here, but ideally we will support static soon
+ // anyway.
+ bool HasStatic = (C.getArgs().hasArg(options::OPT_mkernel) ||
+ C.getArgs().hasArg(options::OPT_static) ||
+ C.getArgs().hasArg(options::OPT_fapple_kext));
+ bool IsIADefault = (TC->IsIntegratedAssemblerDefault() && !HasStatic);
+ if (C.getArgs().hasFlag(options::OPT_integrated_as,
options::OPT_no_integrated_as,
- TC->IsIntegratedAssemblerDefault()) &&
+ IsIADefault) &&
!C.getArgs().hasArg(options::OPT_save_temps) &&
isa<AssembleJobAction>(JA) &&
Inputs->size() == 1 && isa<CompileJobAction>(*Inputs->begin())) {
diff --git a/lib/Driver/Tool.cpp b/lib/Driver/Tool.cpp
index 781e0a702060..fe01531d9a2a 100644
--- a/lib/Driver/Tool.cpp
+++ b/lib/Driver/Tool.cpp
@@ -11,8 +11,10 @@
using namespace clang::driver;
-Tool::Tool(const char *_Name, const ToolChain &TC) : Name(_Name),
- TheToolChain(TC) {
+Tool::Tool(const char *_Name, const char *_ShortName,
+ const ToolChain &TC) : Name(_Name), ShortName(_ShortName),
+ TheToolChain(TC)
+{
}
Tool::~Tool() {
diff --git a/lib/Driver/ToolChains.cpp b/lib/Driver/ToolChains.cpp
index 1cd8ee186cae..abb55b07d106 100644
--- a/lib/Driver/ToolChains.cpp
+++ b/lib/Driver/ToolChains.cpp
@@ -11,6 +11,7 @@
#include "clang/Driver/Arg.h"
#include "clang/Driver/ArgList.h"
+#include "clang/Driver/Compilation.h"
#include "clang/Driver/Driver.h"
#include "clang/Driver/DriverDiagnostic.h"
#include "clang/Driver/HostInfo.h"
@@ -190,6 +191,16 @@ Tool &Darwin::SelectTool(const Compilation &C, const JobAction &JA) const {
else
Key = JA.getKind();
+ // FIXME: This doesn't belong here, but ideally we will support static soon
+ // anyway.
+ bool HasStatic = (C.getArgs().hasArg(options::OPT_mkernel) ||
+ C.getArgs().hasArg(options::OPT_static) ||
+ C.getArgs().hasArg(options::OPT_fapple_kext));
+ bool IsIADefault = IsIntegratedAssemblerDefault() && !HasStatic;
+ bool UseIntegratedAs = C.getArgs().hasFlag(options::OPT_integrated_as,
+ options::OPT_no_integrated_as,
+ IsIADefault);
+
Tool *&T = Tools[Key];
if (!T) {
switch (Key) {
@@ -203,8 +214,13 @@ Tool &Darwin::SelectTool(const Compilation &C, const JobAction &JA) const {
case Action::PrecompileJobClass:
case Action::CompileJobClass:
T = new tools::darwin::Compile(*this); break;
- case Action::AssembleJobClass:
- T = new tools::darwin::Assemble(*this); break;
+ case Action::AssembleJobClass: {
+ if (UseIntegratedAs)
+ T = new tools::ClangAs(*this);
+ else
+ T = new tools::darwin::Assemble(*this);
+ break;
+ }
case Action::LinkJobClass:
T = new tools::darwin::Link(*this); break;
case Action::LipoJobClass:
diff --git a/lib/Driver/ToolChains.h b/lib/Driver/ToolChains.h
index 9acc950879d5..ad975bfe6dee 100644
--- a/lib/Driver/ToolChains.h
+++ b/lib/Driver/ToolChains.h
@@ -25,7 +25,7 @@ namespace toolchains {
/// Generic_GCC - A tool chain using the 'gcc' command to perform
/// all subcommands; this relies on gcc translating the majority of
/// command line options.
-class VISIBILITY_HIDDEN Generic_GCC : public ToolChain {
+class LLVM_LIBRARY_VISIBILITY Generic_GCC : public ToolChain {
protected:
mutable llvm::DenseMap<unsigned, Tool*> Tools;
@@ -44,7 +44,7 @@ public:
};
/// Darwin - The base Darwin tool chain.
-class VISIBILITY_HIDDEN Darwin : public ToolChain {
+class LLVM_LIBRARY_VISIBILITY Darwin : public ToolChain {
mutable llvm::DenseMap<unsigned, Tool*> Tools;
/// Whether the information on the target has been initialized.
@@ -56,7 +56,7 @@ class VISIBILITY_HIDDEN Darwin : public ToolChain {
/// Whether we are targetting iPhoneOS target.
mutable bool TargetIsIPhoneOS;
-
+
/// The OS version we are targetting.
mutable unsigned TargetVersion[3];
@@ -159,6 +159,11 @@ public:
else
return !isMacosxVersionLT(10, 6);
}
+ virtual bool IsIntegratedAssemblerDefault() const {
+ // Default integrated assembler to on for x86.
+ return (getTriple().getArch() == llvm::Triple::x86 ||
+ getTriple().getArch() == llvm::Triple::x86_64);
+ }
virtual bool IsObjCNonFragileABIDefault() const {
// Non-fragile ABI is default for everything but i386.
return getTriple().getArch() != llvm::Triple::x86;
@@ -193,7 +198,7 @@ public:
};
/// DarwinClang - The Darwin toolchain used by Clang.
-class VISIBILITY_HIDDEN DarwinClang : public Darwin {
+class LLVM_LIBRARY_VISIBILITY DarwinClang : public Darwin {
public:
DarwinClang(const HostInfo &Host, const llvm::Triple& Triple,
const unsigned (&DarwinVersion)[3]);
@@ -211,7 +216,7 @@ public:
};
/// DarwinGCC - The Darwin toolchain used by GCC.
-class VISIBILITY_HIDDEN DarwinGCC : public Darwin {
+class LLVM_LIBRARY_VISIBILITY DarwinGCC : public Darwin {
/// GCC version to use.
unsigned GCCVersion[3];
@@ -236,7 +241,7 @@ public:
};
/// Darwin_Generic_GCC - Generic Darwin tool chain using gcc.
-class VISIBILITY_HIDDEN Darwin_Generic_GCC : public Generic_GCC {
+class LLVM_LIBRARY_VISIBILITY Darwin_Generic_GCC : public Generic_GCC {
public:
Darwin_Generic_GCC(const HostInfo &Host, const llvm::Triple& Triple)
: Generic_GCC(Host, Triple) {}
@@ -244,35 +249,35 @@ public:
virtual const char *GetDefaultRelocationModel() const { return "pic"; }
};
-class VISIBILITY_HIDDEN AuroraUX : public Generic_GCC {
+class LLVM_LIBRARY_VISIBILITY AuroraUX : public Generic_GCC {
public:
AuroraUX(const HostInfo &Host, const llvm::Triple& Triple);
virtual Tool &SelectTool(const Compilation &C, const JobAction &JA) const;
};
-class VISIBILITY_HIDDEN OpenBSD : public Generic_GCC {
+class LLVM_LIBRARY_VISIBILITY OpenBSD : public Generic_GCC {
public:
OpenBSD(const HostInfo &Host, const llvm::Triple& Triple);
virtual Tool &SelectTool(const Compilation &C, const JobAction &JA) const;
};
-class VISIBILITY_HIDDEN FreeBSD : public Generic_GCC {
+class LLVM_LIBRARY_VISIBILITY FreeBSD : public Generic_GCC {
public:
FreeBSD(const HostInfo &Host, const llvm::Triple& Triple, bool Lib32);
virtual Tool &SelectTool(const Compilation &C, const JobAction &JA) const;
};
-class VISIBILITY_HIDDEN DragonFly : public Generic_GCC {
+class LLVM_LIBRARY_VISIBILITY DragonFly : public Generic_GCC {
public:
DragonFly(const HostInfo &Host, const llvm::Triple& Triple);
virtual Tool &SelectTool(const Compilation &C, const JobAction &JA) const;
};
-class VISIBILITY_HIDDEN Linux : public Generic_GCC {
+class LLVM_LIBRARY_VISIBILITY Linux : public Generic_GCC {
public:
Linux(const HostInfo &Host, const llvm::Triple& Triple);
};
@@ -280,7 +285,7 @@ public:
/// TCEToolChain - A tool chain using the llvm bitcode tools to perform
/// all subcommands. See http://tce.cs.tut.fi for our peculiar target.
-class VISIBILITY_HIDDEN TCEToolChain : public ToolChain {
+class LLVM_LIBRARY_VISIBILITY TCEToolChain : public ToolChain {
public:
TCEToolChain(const HostInfo &Host, const llvm::Triple& Triple);
~TCEToolChain();
diff --git a/lib/Driver/Tools.cpp b/lib/Driver/Tools.cpp
index 5a3916d19ea7..918f0d9715e7 100644
--- a/lib/Driver/Tools.cpp
+++ b/lib/Driver/Tools.cpp
@@ -21,7 +21,6 @@
#include "clang/Driver/Options.h"
#include "clang/Driver/ToolChain.h"
#include "clang/Driver/Util.h"
-#include "clang/Frontend/DiagnosticOptions.h"
#include "llvm/ADT/SmallString.h"
#include "llvm/ADT/StringSwitch.h"
@@ -769,6 +768,15 @@ void Clang::ConstructJob(Compilation &C, const JobAction &JA,
CmdArgs.push_back("-E");
} else if (isa<AssembleJobAction>(JA)) {
CmdArgs.push_back("-emit-obj");
+
+ // At -O0, we use -mrelax-all by default.
+ bool IsOpt = false;
+ if (Arg *A = Args.getLastArg(options::OPT_O_Group))
+ IsOpt = !A->getOption().matches(options::OPT_O0);
+ if (Args.hasFlag(options::OPT_mrelax_all,
+ options::OPT_mno_relax_all,
+ !IsOpt))
+ CmdArgs.push_back("-mrelax-all");
} else if (isa<PrecompileJobAction>(JA)) {
// Use PCH if the user requested it, except for C++ (for now).
bool UsePCH = D.CCCUsePCH;
@@ -911,8 +919,15 @@ void Clang::ConstructJob(Compilation &C, const JobAction &JA,
if (!Args.hasFlag(options::OPT_fzero_initialized_in_bss,
options::OPT_fno_zero_initialized_in_bss))
CmdArgs.push_back("-mno-zero-initialized-in-bss");
- if (Args.hasArg(options::OPT_dA) || Args.hasArg(options::OPT_fverbose_asm))
+
+ // Decide whether to use verbose asm. Verbose assembly is the default on
+ // toolchains which have the integrated assembler on by default.
+ bool IsVerboseAsmDefault = getToolChain().IsIntegratedAssemblerDefault();
+ if (Args.hasFlag(options::OPT_fverbose_asm, options::OPT_fno_verbose_asm,
+ IsVerboseAsmDefault) ||
+ Args.hasArg(options::OPT_dA))
CmdArgs.push_back("-masm-verbose");
+
if (Args.hasArg(options::OPT_fdebug_pass_structure)) {
CmdArgs.push_back("-mdebug-pass");
CmdArgs.push_back("Structure");
@@ -979,6 +994,9 @@ void Clang::ConstructJob(Compilation &C, const JobAction &JA,
false))
CmdArgs.push_back("-fmath-errno");
+ // Explicitly error on some things we know we don't support and can't just
+ // ignore.
+ types::ID InputType = Inputs[0].getType();
Arg *Unsupported;
if ((Unsupported = Args.getLastArg(options::OPT_MG)) ||
(Unsupported = Args.getLastArg(options::OPT_iframework)) ||
@@ -986,6 +1004,14 @@ void Clang::ConstructJob(Compilation &C, const JobAction &JA,
D.Diag(clang::diag::err_drv_clang_unsupported)
<< Unsupported->getOption().getName();
+ if (types::isCXX(InputType) &&
+ getToolChain().getTriple().getOS() == llvm::Triple::Darwin &&
+ getToolChain().getTriple().getArch() == llvm::Triple::x86) {
+ if ((Unsupported = Args.getLastArg(options::OPT_fapple_kext)))
+ D.Diag(clang::diag::err_drv_clang_unsupported_opt_cxx_darwin_i386)
+ << Unsupported->getOption().getName();
+ }
+
Args.AddAllArgs(CmdArgs, options::OPT_v);
Args.AddLastArg(CmdArgs, options::OPT_P);
Args.AddLastArg(CmdArgs, options::OPT_print_ivar_layout);
@@ -993,9 +1019,12 @@ void Clang::ConstructJob(Compilation &C, const JobAction &JA,
// Special case debug options to only pass -g to clang. This is
// wrong.
Args.ClaimAllArgs(options::OPT_g_Group);
- Arg *Garg = Args.getLastArg(options::OPT_g_Group);
- if (Garg && Garg != Args.getLastArg(options::OPT_g0))
- CmdArgs.push_back("-g");
+ if (Arg *A = Args.getLastArg(options::OPT_g_Group))
+ if (!A->getOption().matches(options::OPT_g0))
+ CmdArgs.push_back("-g");
+
+ Args.AddAllArgs(CmdArgs, options::OPT_ffunction_sections);
+ Args.AddAllArgs(CmdArgs, options::OPT_fdata_sections);
Args.AddLastArg(CmdArgs, options::OPT_nostdinc);
Args.AddLastArg(CmdArgs, options::OPT_nostdincxx);
@@ -1009,7 +1038,6 @@ void Clang::ConstructJob(Compilation &C, const JobAction &JA,
// preprocessor.
//
// FIXME: Support -fpreprocessed
- types::ID InputType = Inputs[0].getType();
if (types::getPreprocessedType(InputType) != types::TY_INVALID)
AddPreprocessingOptions(D, Args, CmdArgs, Output, Inputs);
@@ -1018,7 +1046,8 @@ void Clang::ConstructJob(Compilation &C, const JobAction &JA,
if (Arg *A = Args.getLastArg(options::OPT_O_Group)) {
if (A->getOption().matches(options::OPT_O4))
CmdArgs.push_back("-O3");
- else if (A->getValue(Args)[0] == '\0')
+ else if (A->getOption().matches(options::OPT_O) &&
+ A->getValue(Args)[0] == '\0')
CmdArgs.push_back("-O2");
else
A->render(Args, CmdArgs);
@@ -1059,6 +1088,14 @@ void Clang::ConstructJob(Compilation &C, const JobAction &JA,
Args.AddLastArg(CmdArgs, options::OPT_trigraphs);
}
+ // Translate GCC's misnamer '-fasm' arguments to '-fgnu-keywords'.
+ if (Arg *Asm = Args.getLastArg(options::OPT_fasm, options::OPT_fno_asm)) {
+ if (Asm->getOption().matches(options::OPT_fasm))
+ CmdArgs.push_back("-fgnu-keywords");
+ else
+ CmdArgs.push_back("-fno-gnu-keywords");
+ }
+
if (Arg *A = Args.getLastArg(options::OPT_ftemplate_depth_)) {
CmdArgs.push_back("-ftemplate-depth");
CmdArgs.push_back(A->getValue(Args));
@@ -1083,20 +1120,16 @@ void Clang::ConstructJob(Compilation &C, const JobAction &JA,
else
CmdArgs.push_back("19");
- CmdArgs.push_back("-fmacro-backtrace-limit");
- if (Arg *A = Args.getLastArg(options::OPT_fmacro_backtrace_limit_EQ))
+ if (Arg *A = Args.getLastArg(options::OPT_fmacro_backtrace_limit_EQ)) {
+ CmdArgs.push_back("-fmacro-backtrace-limit");
CmdArgs.push_back(A->getValue(Args));
- else
- CmdArgs.push_back(Args.MakeArgString(
- llvm::Twine(DiagnosticOptions::DefaultMacroBacktraceLimit)));
-
- CmdArgs.push_back("-ftemplate-backtrace-limit");
- if (Arg *A = Args.getLastArg(options::OPT_ftemplate_backtrace_limit_EQ))
+ }
+
+ if (Arg *A = Args.getLastArg(options::OPT_ftemplate_backtrace_limit_EQ)) {
+ CmdArgs.push_back("-ftemplate-backtrace-limit");
CmdArgs.push_back(A->getValue(Args));
- else
- CmdArgs.push_back(Args.MakeArgString(
- llvm::Twine(DiagnosticOptions::DefaultTemplateBacktraceLimit)));
-
+ }
+
// Pass -fmessage-length=.
CmdArgs.push_back("-fmessage-length");
if (Arg *A = Args.getLastArg(options::OPT_fmessage_length_EQ)) {
@@ -1265,6 +1298,11 @@ void Clang::ConstructJob(Compilation &C, const JobAction &JA,
CmdArgs.push_back("-fobjc-dispatch-method=non-legacy");
}
}
+
+ // FIXME: -fobjc-nonfragile-abi2 is a transient option meant to expose
+ // features in testing. It will eventually be removed.
+ if (Args.hasArg(options::OPT_fobjc_nonfragile_abi2))
+ CmdArgs.push_back("-fobjc-nonfragile-abi2");
}
if (!Args.hasFlag(options::OPT_fassume_sane_operator_new,
@@ -1320,6 +1358,12 @@ void Clang::ConstructJob(Compilation &C, const JobAction &JA,
options::OPT_fno_diagnostics_show_option))
CmdArgs.push_back("-fdiagnostics-show-option");
+ if (const Arg *A =
+ Args.getLastArg(options::OPT_fdiagnostics_show_category_EQ)) {
+ CmdArgs.push_back("-fdiagnostics-show-category");
+ CmdArgs.push_back(A->getValue(Args));
+ }
+
// Color diagnostics are the default, unless the terminal doesn't support
// them.
if (Args.hasFlag(options::OPT_fcolor_diagnostics,
@@ -1451,6 +1495,67 @@ void Clang::ConstructJob(Compilation &C, const JobAction &JA,
Args.ClaimAllArgs(options::OPT_clang_ignored_m_Group);
}
+void ClangAs::ConstructJob(Compilation &C, const JobAction &JA,
+ Job &Dest,
+ const InputInfo &Output,
+ const InputInfoList &Inputs,
+ const ArgList &Args,
+ const char *LinkingOutput) const {
+ const Driver &D = getToolChain().getDriver();
+ ArgStringList CmdArgs;
+
+ assert(Inputs.size() == 1 && "Unexpected number of inputs.");
+ const InputInfo &Input = Inputs[0];
+
+ // Invoke ourselves in -cc1as mode.
+ //
+ // FIXME: Implement custom jobs for internal actions.
+ CmdArgs.push_back("-cc1as");
+
+ // Add the "effective" target triple.
+ CmdArgs.push_back("-triple");
+ std::string TripleStr = getEffectiveClangTriple(D, getToolChain(), Args);
+ CmdArgs.push_back(Args.MakeArgString(TripleStr));
+
+ // Set the output mode, we currently only expect to be used as a real
+ // assembler.
+ CmdArgs.push_back("-filetype");
+ CmdArgs.push_back("obj");
+
+ // At -O0, we use -mrelax-all by default.
+ bool IsOpt = false;
+ if (Arg *A = Args.getLastArg(options::OPT_O_Group))
+ IsOpt = !A->getOption().matches(options::OPT_O0);
+ if (Args.hasFlag(options::OPT_mrelax_all,
+ options::OPT_mno_relax_all,
+ !IsOpt))
+ CmdArgs.push_back("-mrelax-all");
+
+ // FIXME: Add -force_cpusubtype_ALL support, once we have it.
+
+ // FIXME: Add -g support, once we have it.
+
+ // FIXME: Add -static support, once we have it.
+
+ Args.AddAllArgValues(CmdArgs, options::OPT_Wa_COMMA,
+ options::OPT_Xassembler);
+
+ assert(Output.isFilename() && "Unexpected lipo output.");
+ CmdArgs.push_back("-o");
+ CmdArgs.push_back(Output.getFilename());
+
+ if (Input.isPipe()) {
+ CmdArgs.push_back("-");
+ } else {
+ assert(Input.isFilename() && "Invalid input.");
+ CmdArgs.push_back(Input.getFilename());
+ }
+
+ const char *Exec =
+ Args.MakeArgString(getToolChain().GetProgramPath(C, "clang"));
+ Dest.addCommand(new Command(JA, *this, Exec, CmdArgs));
+}
+
void gcc::Common::ConstructJob(Compilation &C, const JobAction &JA,
Job &Dest,
const InputInfo &Output,
diff --git a/lib/Driver/Tools.h b/lib/Driver/Tools.h
index 091fec380622..d5e98dd24c48 100644
--- a/lib/Driver/Tools.h
+++ b/lib/Driver/Tools.h
@@ -26,7 +26,8 @@ namespace toolchains {
namespace tools {
- class VISIBILITY_HIDDEN Clang : public Tool {
+ /// \brief Clang compiler tool.
+ class LLVM_LIBRARY_VISIBILITY Clang : public Tool {
void AddPreprocessingOptions(const Driver &D,
const ArgList &Args,
ArgStringList &CmdArgs,
@@ -38,7 +39,7 @@ namespace tools {
void AddX86TargetArgs(const ArgList &Args, ArgStringList &CmdArgs) const;
public:
- Clang(const ToolChain &TC) : Tool("clang", TC) {}
+ Clang(const ToolChain &TC) : Tool("clang", "clang frontend", TC) {}
virtual bool acceptsPipedInput() const { return true; }
virtual bool canPipeOutput() const { return true; }
@@ -54,11 +55,32 @@ namespace tools {
const char *LinkingOutput) const;
};
+ /// \brief Clang integrated assembler tool.
+ class LLVM_LIBRARY_VISIBILITY ClangAs : public Tool {
+ public:
+ ClangAs(const ToolChain &TC) : Tool("clang::as",
+ "clang integrated assembler", TC) {}
+
+ virtual bool acceptsPipedInput() const { return true; }
+ virtual bool canPipeOutput() const { return true; }
+ virtual bool hasGoodDiagnostics() const { return true; }
+ virtual bool hasIntegratedAssembler() const { return false; }
+ virtual bool hasIntegratedCPP() const { return false; }
+
+ virtual void ConstructJob(Compilation &C, const JobAction &JA,
+ Job &Dest,
+ const InputInfo &Output,
+ const InputInfoList &Inputs,
+ const ArgList &TCArgs,
+ const char *LinkingOutput) const;
+ };
+
/// gcc - Generic GCC tool implementations.
namespace gcc {
- class VISIBILITY_HIDDEN Common : public Tool {
+ class LLVM_LIBRARY_VISIBILITY Common : public Tool {
public:
- Common(const char *Name, const ToolChain &TC) : Tool(Name, TC) {}
+ Common(const char *Name, const char *ShortName,
+ const ToolChain &TC) : Tool(Name, ShortName, TC) {}
virtual void ConstructJob(Compilation &C, const JobAction &JA,
Job &Dest,
@@ -74,9 +96,10 @@ namespace gcc {
};
- class VISIBILITY_HIDDEN Preprocess : public Common {
+ class LLVM_LIBRARY_VISIBILITY Preprocess : public Common {
public:
- Preprocess(const ToolChain &TC) : Common("gcc::Preprocess", TC) {}
+ Preprocess(const ToolChain &TC) : Common("gcc::Preprocess",
+ "gcc preprocessor", TC) {}
virtual bool acceptsPipedInput() const { return true; }
virtual bool canPipeOutput() const { return true; }
@@ -87,9 +110,10 @@ namespace gcc {
ArgStringList &CmdArgs) const;
};
- class VISIBILITY_HIDDEN Precompile : public Common {
+ class LLVM_LIBRARY_VISIBILITY Precompile : public Common {
public:
- Precompile(const ToolChain &TC) : Common("gcc::Precompile", TC) {}
+ Precompile(const ToolChain &TC) : Common("gcc::Precompile",
+ "gcc precompile", TC) {}
virtual bool acceptsPipedInput() const { return true; }
virtual bool canPipeOutput() const { return false; }
@@ -100,9 +124,10 @@ namespace gcc {
ArgStringList &CmdArgs) const;
};
- class VISIBILITY_HIDDEN Compile : public Common {
+ class LLVM_LIBRARY_VISIBILITY Compile : public Common {
public:
- Compile(const ToolChain &TC) : Common("gcc::Compile", TC) {}
+ Compile(const ToolChain &TC) : Common("gcc::Compile",
+ "gcc frontend", TC) {}
virtual bool acceptsPipedInput() const { return true; }
virtual bool canPipeOutput() const { return true; }
@@ -113,9 +138,10 @@ namespace gcc {
ArgStringList &CmdArgs) const;
};
- class VISIBILITY_HIDDEN Assemble : public Common {
+ class LLVM_LIBRARY_VISIBILITY Assemble : public Common {
public:
- Assemble(const ToolChain &TC) : Common("gcc::Assemble", TC) {}
+ Assemble(const ToolChain &TC) : Common("gcc::Assemble",
+ "assembler (via gcc)", TC) {}
virtual bool acceptsPipedInput() const { return true; }
virtual bool canPipeOutput() const { return false; }
@@ -125,9 +151,10 @@ namespace gcc {
ArgStringList &CmdArgs) const;
};
- class VISIBILITY_HIDDEN Link : public Common {
+ class LLVM_LIBRARY_VISIBILITY Link : public Common {
public:
- Link(const ToolChain &TC) : Common("gcc::Link", TC) {}
+ Link(const ToolChain &TC) : Common("gcc::Link",
+ "linker (via gcc)", TC) {}
virtual bool acceptsPipedInput() const { return false; }
virtual bool canPipeOutput() const { return false; }
@@ -139,7 +166,7 @@ namespace gcc {
} // end namespace gcc
namespace darwin {
- class VISIBILITY_HIDDEN DarwinTool : public Tool {
+ class LLVM_LIBRARY_VISIBILITY DarwinTool : public Tool {
protected:
void AddDarwinArch(const ArgList &Args, ArgStringList &CmdArgs) const;
@@ -148,10 +175,11 @@ namespace darwin {
}
public:
- DarwinTool(const char *Name, const ToolChain &TC) : Tool(Name, TC) {}
+ DarwinTool(const char *Name, const char *ShortName,
+ const ToolChain &TC) : Tool(Name, ShortName, TC) {}
};
- class VISIBILITY_HIDDEN CC1 : public DarwinTool {
+ class LLVM_LIBRARY_VISIBILITY CC1 : public DarwinTool {
public:
static const char *getBaseInputName(const ArgList &Args,
const InputInfoList &Input);
@@ -176,7 +204,8 @@ namespace darwin {
void AddCPPArgs(const ArgList &Args, ArgStringList &CmdArgs) const;
public:
- CC1(const char *Name, const ToolChain &TC) : DarwinTool(Name, TC) {}
+ CC1(const char *Name, const char *ShortName,
+ const ToolChain &TC) : DarwinTool(Name, ShortName, TC) {}
virtual bool acceptsPipedInput() const { return true; }
virtual bool canPipeOutput() const { return true; }
@@ -184,9 +213,10 @@ namespace darwin {
virtual bool hasIntegratedCPP() const { return true; }
};
- class VISIBILITY_HIDDEN Preprocess : public CC1 {
+ class LLVM_LIBRARY_VISIBILITY Preprocess : public CC1 {
public:
- Preprocess(const ToolChain &TC) : CC1("darwin::Preprocess", TC) {}
+ Preprocess(const ToolChain &TC) : CC1("darwin::Preprocess",
+ "gcc preprocessor", TC) {}
virtual void ConstructJob(Compilation &C, const JobAction &JA,
Job &Dest,
@@ -196,9 +226,9 @@ namespace darwin {
const char *LinkingOutput) const;
};
- class VISIBILITY_HIDDEN Compile : public CC1 {
+ class LLVM_LIBRARY_VISIBILITY Compile : public CC1 {
public:
- Compile(const ToolChain &TC) : CC1("darwin::Compile", TC) {}
+ Compile(const ToolChain &TC) : CC1("darwin::Compile", "gcc frontend", TC) {}
virtual void ConstructJob(Compilation &C, const JobAction &JA,
Job &Dest,
@@ -208,9 +238,10 @@ namespace darwin {
const char *LinkingOutput) const;
};
- class VISIBILITY_HIDDEN Assemble : public DarwinTool {
+ class LLVM_LIBRARY_VISIBILITY Assemble : public DarwinTool {
public:
- Assemble(const ToolChain &TC) : DarwinTool("darwin::Assemble", TC) {}
+ Assemble(const ToolChain &TC) : DarwinTool("darwin::Assemble",
+ "assembler", TC) {}
virtual bool acceptsPipedInput() const { return true; }
virtual bool canPipeOutput() const { return false; }
@@ -224,11 +255,11 @@ namespace darwin {
const char *LinkingOutput) const;
};
- class VISIBILITY_HIDDEN Link : public DarwinTool {
+ class LLVM_LIBRARY_VISIBILITY Link : public DarwinTool {
void AddLinkArgs(const ArgList &Args, ArgStringList &CmdArgs) const;
public:
- Link(const ToolChain &TC) : DarwinTool("darwin::Link", TC) {}
+ Link(const ToolChain &TC) : DarwinTool("darwin::Link", "linker", TC) {}
virtual bool acceptsPipedInput() const { return false; }
virtual bool canPipeOutput() const { return false; }
@@ -242,9 +273,9 @@ namespace darwin {
const char *LinkingOutput) const;
};
- class VISIBILITY_HIDDEN Lipo : public DarwinTool {
+ class LLVM_LIBRARY_VISIBILITY Lipo : public DarwinTool {
public:
- Lipo(const ToolChain &TC) : DarwinTool("darwin::Lipo", TC) {}
+ Lipo(const ToolChain &TC) : DarwinTool("darwin::Lipo", "lipo", TC) {}
virtual bool acceptsPipedInput() const { return false; }
virtual bool canPipeOutput() const { return false; }
@@ -261,9 +292,10 @@ namespace darwin {
/// openbsd -- Directly call GNU Binutils assembler and linker
namespace openbsd {
- class VISIBILITY_HIDDEN Assemble : public Tool {
+ class LLVM_LIBRARY_VISIBILITY Assemble : public Tool {
public:
- Assemble(const ToolChain &TC) : Tool("openbsd::Assemble", TC) {}
+ Assemble(const ToolChain &TC) : Tool("openbsd::Assemble", "assembler",
+ TC) {}
virtual bool acceptsPipedInput() const { return true; }
virtual bool canPipeOutput() const { return true; }
@@ -276,9 +308,9 @@ namespace openbsd {
const ArgList &TCArgs,
const char *LinkingOutput) const;
};
- class VISIBILITY_HIDDEN Link : public Tool {
+ class LLVM_LIBRARY_VISIBILITY Link : public Tool {
public:
- Link(const ToolChain &TC) : Tool("openbsd::Link", TC) {}
+ Link(const ToolChain &TC) : Tool("openbsd::Link", "linker", TC) {}
virtual bool acceptsPipedInput() const { return true; }
virtual bool canPipeOutput() const { return true; }
@@ -295,9 +327,10 @@ namespace openbsd {
/// freebsd -- Directly call GNU Binutils assembler and linker
namespace freebsd {
- class VISIBILITY_HIDDEN Assemble : public Tool {
+ class LLVM_LIBRARY_VISIBILITY Assemble : public Tool {
public:
- Assemble(const ToolChain &TC) : Tool("freebsd::Assemble", TC) {}
+ Assemble(const ToolChain &TC) : Tool("freebsd::Assemble", "assembler",
+ TC) {}
virtual bool acceptsPipedInput() const { return true; }
virtual bool canPipeOutput() const { return true; }
@@ -310,9 +343,9 @@ namespace freebsd {
const ArgList &TCArgs,
const char *LinkingOutput) const;
};
- class VISIBILITY_HIDDEN Link : public Tool {
+ class LLVM_LIBRARY_VISIBILITY Link : public Tool {
public:
- Link(const ToolChain &TC) : Tool("freebsd::Link", TC) {}
+ Link(const ToolChain &TC) : Tool("freebsd::Link", "linker", TC) {}
virtual bool acceptsPipedInput() const { return true; }
virtual bool canPipeOutput() const { return true; }
@@ -329,9 +362,10 @@ namespace freebsd {
/// auroraux -- Directly call GNU Binutils assembler and linker
namespace auroraux {
- class VISIBILITY_HIDDEN Assemble : public Tool {
+ class LLVM_LIBRARY_VISIBILITY Assemble : public Tool {
public:
- Assemble(const ToolChain &TC) : Tool("auroraux::Assemble", TC) {}
+ Assemble(const ToolChain &TC) : Tool("auroraux::Assemble", "assembler",
+ TC) {}
virtual bool acceptsPipedInput() const { return true; }
virtual bool canPipeOutput() const { return true; }
@@ -344,9 +378,9 @@ namespace auroraux {
const ArgList &TCArgs,
const char *LinkingOutput) const;
};
- class VISIBILITY_HIDDEN Link : public Tool {
+ class LLVM_LIBRARY_VISIBILITY Link : public Tool {
public:
- Link(const ToolChain &TC) : Tool("auroraux::Link", TC) {}
+ Link(const ToolChain &TC) : Tool("auroraux::Link", "linker", TC) {}
virtual bool acceptsPipedInput() const { return true; }
virtual bool canPipeOutput() const { return true; }
@@ -363,9 +397,10 @@ namespace auroraux {
/// dragonfly -- Directly call GNU Binutils assembler and linker
namespace dragonfly {
- class VISIBILITY_HIDDEN Assemble : public Tool {
+ class LLVM_LIBRARY_VISIBILITY Assemble : public Tool {
public:
- Assemble(const ToolChain &TC) : Tool("dragonfly::Assemble", TC) {}
+ Assemble(const ToolChain &TC) : Tool("dragonfly::Assemble", "assembler",
+ TC) {}
virtual bool acceptsPipedInput() const { return true; }
virtual bool canPipeOutput() const { return true; }
@@ -378,9 +413,9 @@ namespace dragonfly {
const ArgList &TCArgs,
const char *LinkingOutput) const;
};
- class VISIBILITY_HIDDEN Link : public Tool {
+ class LLVM_LIBRARY_VISIBILITY Link : public Tool {
public:
- Link(const ToolChain &TC) : Tool("dragonfly::Link", TC) {}
+ Link(const ToolChain &TC) : Tool("dragonfly::Link", "linker", TC) {}
virtual bool acceptsPipedInput() const { return true; }
virtual bool canPipeOutput() const { return true; }
diff --git a/lib/Frontend/AnalysisConsumer.cpp b/lib/Frontend/AnalysisConsumer.cpp
index 87c3fca24962..6a4727929e7a 100644
--- a/lib/Frontend/AnalysisConsumer.cpp
+++ b/lib/Frontend/AnalysisConsumer.cpp
@@ -174,10 +174,10 @@ public:
Mgr.reset(new AnalysisManager(*Ctx, PP.getDiagnostics(),
PP.getLangOptions(), PD,
CreateStoreMgr, CreateConstraintMgr,
- Opts.MaxNodes,
+ Opts.MaxNodes, Opts.MaxLoop,
Opts.VisualizeEGDot, Opts.VisualizeEGUbi,
Opts.PurgeDead, Opts.EagerlyAssume,
- Opts.TrimGraph));
+ Opts.TrimGraph, Opts.InlineCall));
}
virtual void HandleTranslationUnit(ASTContext &C);
diff --git a/lib/Frontend/BoostConAction.cpp b/lib/Frontend/BoostConAction.cpp
new file mode 100644
index 000000000000..ae150c6ec21e
--- /dev/null
+++ b/lib/Frontend/BoostConAction.cpp
@@ -0,0 +1,39 @@
+//===-- BoostConAction.cpp - BoostCon Workshop Action -----------*- C++ -*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+#include "clang/Frontend/FrontendActions.h"
+#include "clang/AST/ASTConsumer.h"
+#include "clang/AST/RecursiveASTVisitor.h"
+#include <cstdio>
+#include <iostream>
+using namespace clang;
+
+namespace {
+ class BoostConASTConsumer : public ASTConsumer,
+ public RecursiveASTVisitor<BoostConASTConsumer> {
+ public:
+ /// HandleTranslationUnit - This method is called when the ASTs for entire
+ /// translation unit have been parsed.
+ virtual void HandleTranslationUnit(ASTContext &Ctx);
+
+ bool VisitCXXRecordDecl(CXXRecordDecl *D) {
+ std::cout << D->getNameAsString() << std::endl;
+ return false;
+ }
+ };
+}
+
+ASTConsumer *BoostConAction::CreateASTConsumer(CompilerInstance &CI,
+ llvm::StringRef InFile) {
+ return new BoostConASTConsumer();
+}
+
+void BoostConASTConsumer::HandleTranslationUnit(ASTContext &Ctx) {
+ fprintf(stderr, "Welcome to BoostCon!\n");
+ Visit(Ctx.getTranslationUnitDecl());
+}
diff --git a/lib/Frontend/CMakeLists.txt b/lib/Frontend/CMakeLists.txt
index b69ad9740d2a..01592d1f81e4 100644
--- a/lib/Frontend/CMakeLists.txt
+++ b/lib/Frontend/CMakeLists.txt
@@ -5,6 +5,7 @@ add_clang_library(clangFrontend
ASTMerge.cpp
ASTUnit.cpp
AnalysisConsumer.cpp
+ BoostConAction.cpp
CacheTokens.cpp
CodeGenAction.cpp
CompilerInstance.cpp
@@ -54,4 +55,5 @@ ENDIF(MSVC)
add_dependencies(clangFrontend
ClangDiagnosticFrontend
ClangDiagnosticLex
- ClangDiagnosticSema)
+ ClangDiagnosticSema
+ ClangStmtNodes)
diff --git a/lib/Frontend/CodeGenAction.cpp b/lib/Frontend/CodeGenAction.cpp
index 79d7d5f4c241..3416aa825fcb 100644
--- a/lib/Frontend/CodeGenAction.cpp
+++ b/lib/Frontend/CodeGenAction.cpp
@@ -48,6 +48,7 @@ namespace {
Backend_EmitBC, ///< Emit LLVM bitcode files
Backend_EmitLL, ///< Emit human-readable LLVM assembly
Backend_EmitNothing, ///< Don't emit anything (benchmarking mode)
+ Backend_EmitMCNull, ///< Run CodeGen, but don't emit anything
Backend_EmitObj ///< Emit native object files
};
@@ -180,6 +181,10 @@ namespace {
Gen->CompleteTentativeDefinition(D);
}
+ virtual void HandleVTable(CXXRecordDecl *RD, bool DefinitionRequired) {
+ Gen->HandleVTable(RD, DefinitionRequired);
+ }
+
static void InlineAsmDiagHandler(const llvm::SMDiagnostic &SM,void *Context,
unsigned LocCookie) {
SourceLocation Loc = SourceLocation::getFromRawEncoding(LocCookie);
@@ -316,6 +321,9 @@ bool BackendConsumer::AddEmitPasses() {
}
TargetMachine *TM = TheTarget->createTargetMachine(Triple, FeaturesStr);
+ if (CodeGenOpts.RelaxAll)
+ TM->setMCRelaxAll(true);
+
// Set register scheduler & allocation policy.
RegisterScheduler::setDefault(createDefaultScheduler);
RegisterRegAlloc::setDefault(Fast ? createLocalRegisterAllocator :
@@ -336,6 +344,10 @@ bool BackendConsumer::AddEmitPasses() {
TargetMachine::CodeGenFileType CGFT = TargetMachine::CGFT_AssemblyFile;
if (Action == Backend_EmitObj)
CGFT = TargetMachine::CGFT_ObjectFile;
+ else if (Action == Backend_EmitMCNull)
+ CGFT = TargetMachine::CGFT_Null;
+ else
+ assert(Action == Backend_EmitAssembly && "Invalid action!");
if (TM->addPassesToEmitFile(*PM, FormattedOutStream, CGFT, OptLevel,
/*DisableVerify=*/!CodeGenOpts.VerifyModule)) {
Diags.Report(diag::err_fe_unable_to_interface_with_target);
@@ -553,6 +565,7 @@ ASTConsumer *CodeGenAction::CreateASTConsumer(CompilerInstance &CI,
break;
case Backend_EmitNothing:
break;
+ case Backend_EmitMCNull:
case Backend_EmitObj:
OS.reset(CI.createDefaultOutputFile(true, InFile, "o"));
break;
@@ -575,4 +588,6 @@ EmitLLVMAction::EmitLLVMAction() : CodeGenAction(Backend_EmitLL) {}
EmitLLVMOnlyAction::EmitLLVMOnlyAction() : CodeGenAction(Backend_EmitNothing) {}
+EmitCodeGenOnlyAction::EmitCodeGenOnlyAction() : CodeGenAction(Backend_EmitMCNull) {}
+
EmitObjAction::EmitObjAction() : CodeGenAction(Backend_EmitObj) {}
diff --git a/lib/Frontend/CompilerInstance.cpp b/lib/Frontend/CompilerInstance.cpp
index 5ed9c409a3dc..2b251682b713 100644
--- a/lib/Frontend/CompilerInstance.cpp
+++ b/lib/Frontend/CompilerInstance.cpp
@@ -295,6 +295,7 @@ void CompilerInstance::createCodeCompletionConsumer() {
Loc.FileName, Loc.Line, Loc.Column,
getFrontendOpts().DebugCodeCompletionPrinter,
getFrontendOpts().ShowMacrosInCodeCompletion,
+ getFrontendOpts().ShowCodePatternsInCodeCompletion,
llvm::outs()));
if (!CompletionConsumer)
return;
@@ -317,6 +318,7 @@ CompilerInstance::createCodeCompletionConsumer(Preprocessor &PP,
unsigned Column,
bool UseDebugPrinter,
bool ShowMacros,
+ bool ShowCodePatterns,
llvm::raw_ostream &OS) {
// Tell the source manager to chop off the given file at a specific
// line and column.
@@ -332,9 +334,9 @@ CompilerInstance::createCodeCompletionConsumer(Preprocessor &PP,
// Set up the creation routine for code-completion.
if (UseDebugPrinter)
- return new PrintingCodeCompleteConsumer(ShowMacros, OS);
+ return new PrintingCodeCompleteConsumer(ShowMacros, ShowCodePatterns, OS);
else
- return new CIndexCodeCompleteConsumer(ShowMacros, OS);
+ return new CIndexCodeCompleteConsumer(ShowMacros, ShowCodePatterns, OS);
}
// Output Files
diff --git a/lib/Frontend/CompilerInvocation.cpp b/lib/Frontend/CompilerInvocation.cpp
index 729c1dcc15e1..1d81e82ca37b 100644
--- a/lib/Frontend/CompilerInvocation.cpp
+++ b/lib/Frontend/CompilerInvocation.cpp
@@ -187,6 +187,8 @@ static void CodeGenOptsToArgs(const CodeGenOptions &Opts,
Res.push_back("-fobjc-dispatch-method=non-legacy");
break;
}
+ if (Opts.RelaxAll)
+ Res.push_back("-mrelax-all");
if (Opts.SoftFloat)
Res.push_back("-msoft-float");
if (Opts.UnwindTables)
@@ -243,6 +245,10 @@ static void DiagnosticOptsToArgs(const DiagnosticOptions &Opts,
Res.push_back("-fdiagnostics-binary");
if (Opts.ShowOptionNames)
Res.push_back("-fdiagnostics-show-option");
+ if (Opts.ShowCategories == 1)
+ Res.push_back("-fdiagnostics-show-category=id");
+ else if (Opts.ShowCategories == 2)
+ Res.push_back("-fdiagnostics-show-category=name");
if (Opts.ErrorLimit) {
Res.push_back("-ferror-limit");
Res.push_back(llvm::utostr(Opts.ErrorLimit));
@@ -304,6 +310,7 @@ static const char *getActionName(frontend::ActionKind Kind) {
case frontend::ASTPrint: return "-ast-print";
case frontend::ASTPrintXML: return "-ast-print-xml";
case frontend::ASTView: return "-ast-view";
+ case frontend::BoostCon: return "-boostcon";
case frontend::DumpRawTokens: return "-dump-raw-tokens";
case frontend::DumpTokens: return "-dump-tokens";
case frontend::EmitAssembly: return "-S";
@@ -311,6 +318,7 @@ static const char *getActionName(frontend::ActionKind Kind) {
case frontend::EmitHTML: return "-emit-html";
case frontend::EmitLLVM: return "-emit-llvm";
case frontend::EmitLLVMOnly: return "-emit-llvm-only";
+ case frontend::EmitCodeGenOnly: return "-emit-codegen-only";
case frontend::EmitObj: return "-emit-obj";
case frontend::FixIt: return "-fixit";
case frontend::GeneratePCH: return "-emit-pch";
@@ -344,6 +352,8 @@ static void FrontendOptsToArgs(const FrontendOptions &Opts,
Res.push_back("-help");
if (Opts.ShowMacrosInCodeCompletion)
Res.push_back("-code-completion-macros");
+ if (Opts.ShowCodePatternsInCodeCompletion)
+ Res.push_back("-code-completion-patterns");
if (Opts.ShowStats)
Res.push_back("-print-stats");
if (Opts.ShowTimers)
@@ -695,34 +705,6 @@ void CompilerInvocation::toArgs(std::vector<std::string> &Res) {
using namespace clang::driver;
using namespace clang::driver::cc1options;
-static llvm::StringRef getLastArgValue(ArgList &Args, cc1options::ID ID,
- llvm::StringRef Default = "") {
- if (Arg *A = Args.getLastArg(ID))
- return A->getValue(Args);
- return Default;
-}
-
-static int getLastArgIntValue(ArgList &Args, cc1options::ID ID,
- int Default, Diagnostic &Diags) {
- Arg *A = Args.getLastArg(ID);
- if (!A)
- return Default;
-
- int Res = Default;
- if (llvm::StringRef(A->getValue(Args)).getAsInteger(10, Res))
- Diags.Report(diag::err_drv_invalid_int_value)
- << A->getAsString(Args) << A->getValue(Args);
-
- return Res;
-}
-
-static std::vector<std::string>
-getAllArgValues(ArgList &Args, cc1options::ID ID) {
- llvm::SmallVector<const char *, 16> Values;
- Args.AddAllArgValues(Values, ID);
- return std::vector<std::string>(Values.begin(), Values.end());
-}
-
//
static void ParseAnalyzerArgs(AnalyzerOptions &Opts, ArgList &Args,
@@ -787,12 +769,14 @@ static void ParseAnalyzerArgs(AnalyzerOptions &Opts, ArgList &Args,
Args.hasArg(OPT_analyzer_opt_analyze_nested_blocks);
Opts.PurgeDead = !Args.hasArg(OPT_analyzer_no_purge_dead);
Opts.EagerlyAssume = Args.hasArg(OPT_analyzer_eagerly_assume);
- Opts.AnalyzeSpecificFunction = getLastArgValue(Args, OPT_analyze_function);
+ Opts.AnalyzeSpecificFunction = Args.getLastArgValue(OPT_analyze_function);
Opts.EnableExperimentalChecks = Args.hasArg(OPT_analyzer_experimental_checks);
Opts.EnableExperimentalInternalChecks =
Args.hasArg(OPT_analyzer_experimental_internal_checks);
Opts.TrimGraph = Args.hasArg(OPT_trim_egraph);
- Opts.MaxNodes = getLastArgIntValue(Args, OPT_analyzer_max_nodes,150000,Diags);
+ Opts.MaxNodes = Args.getLastArgIntValue(OPT_analyzer_max_nodes, 150000,Diags);
+ Opts.MaxLoop = Args.getLastArgIntValue(OPT_analyzer_max_loop, 3, Diags);
+ Opts.InlineCall = Args.hasArg(OPT_analyzer_inline_call);
}
static void ParseCodeGenArgs(CodeGenOptions &Opts, ArgList &Args,
@@ -802,7 +786,7 @@ static void ParseCodeGenArgs(CodeGenOptions &Opts, ArgList &Args,
if (Args.hasArg(OPT_Os))
Opts.OptimizationLevel = 2;
else {
- Opts.OptimizationLevel = getLastArgIntValue(Args, OPT_O, 0, Diags);
+ Opts.OptimizationLevel = Args.getLastArgIntValue(OPT_O, 0, Diags);
if (Opts.OptimizationLevel > 3) {
Diags.Report(diag::err_drv_invalid_value)
<< Args.getLastArg(OPT_O)->getAsString(Args) << Opts.OptimizationLevel;
@@ -817,7 +801,7 @@ static void ParseCodeGenArgs(CodeGenOptions &Opts, ArgList &Args,
Opts.DebugInfo = Args.hasArg(OPT_g);
Opts.DisableLLVMOpts = Args.hasArg(OPT_disable_llvm_optzns);
Opts.DisableRedZone = Args.hasArg(OPT_disable_red_zone);
- Opts.DwarfDebugFlags = getLastArgValue(Args, OPT_dwarf_debug_flags);
+ Opts.DwarfDebugFlags = Args.getLastArgValue(OPT_dwarf_debug_flags);
Opts.MergeAllConstants = !Args.hasArg(OPT_fno_merge_all_constants);
Opts.NoCommon = Args.hasArg(OPT_fno_common);
Opts.NoImplicitFloat = Args.hasArg(OPT_no_implicit_float);
@@ -827,20 +811,21 @@ static void ParseCodeGenArgs(CodeGenOptions &Opts, ArgList &Args,
Opts.AsmVerbose = Args.hasArg(OPT_masm_verbose);
Opts.CXAAtExit = !Args.hasArg(OPT_fno_use_cxa_atexit);
Opts.CXXCtorDtorAliases = Args.hasArg(OPT_mconstructor_aliases);
- Opts.CodeModel = getLastArgValue(Args, OPT_mcode_model);
- Opts.DebugPass = getLastArgValue(Args, OPT_mdebug_pass);
+ Opts.CodeModel = Args.getLastArgValue(OPT_mcode_model);
+ Opts.DebugPass = Args.getLastArgValue(OPT_mdebug_pass);
Opts.DisableFPElim = Args.hasArg(OPT_mdisable_fp_elim);
- Opts.FloatABI = getLastArgValue(Args, OPT_mfloat_abi);
- Opts.LimitFloatPrecision = getLastArgValue(Args, OPT_mlimit_float_precision);
+ Opts.FloatABI = Args.getLastArgValue(OPT_mfloat_abi);
+ Opts.LimitFloatPrecision = Args.getLastArgValue(OPT_mlimit_float_precision);
Opts.NoZeroInitializedInBSS = Args.hasArg(OPT_mno_zero_initialized_in_bss);
+ Opts.RelaxAll = Args.hasArg(OPT_mrelax_all);
Opts.SoftFloat = Args.hasArg(OPT_msoft_float);
Opts.UnwindTables = Args.hasArg(OPT_munwind_tables);
- Opts.RelocationModel = getLastArgValue(Args, OPT_mrelocation_model, "pic");
+ Opts.RelocationModel = Args.getLastArgValue(OPT_mrelocation_model, "pic");
Opts.FunctionSections = Args.hasArg(OPT_ffunction_sections);
Opts.DataSections = Args.hasArg(OPT_fdata_sections);
- Opts.MainFileName = getLastArgValue(Args, OPT_main_file_name);
+ Opts.MainFileName = Args.getLastArgValue(OPT_main_file_name);
Opts.VerifyModule = !Args.hasArg(OPT_disable_llvm_verifier);
if (Arg *A = Args.getLastArg(OPT_fobjc_dispatch_method_EQ)) {
@@ -860,8 +845,8 @@ static void ParseCodeGenArgs(CodeGenOptions &Opts, ArgList &Args,
static void ParseDependencyOutputArgs(DependencyOutputOptions &Opts,
ArgList &Args) {
using namespace cc1options;
- Opts.OutputFile = getLastArgValue(Args, OPT_dependency_file);
- Opts.Targets = getAllArgValues(Args, OPT_MT);
+ Opts.OutputFile = Args.getLastArgValue(OPT_dependency_file);
+ Opts.Targets = Args.getAllArgValues(OPT_MT);
Opts.IncludeSystemHeaders = Args.hasArg(OPT_sys_header_deps);
Opts.UsePhonyTargets = Args.hasArg(OPT_MP);
}
@@ -879,27 +864,41 @@ static void ParseDiagnosticArgs(DiagnosticOptions &Opts, ArgList &Args,
Opts.ShowFixits = !Args.hasArg(OPT_fno_diagnostics_fixit_info);
Opts.ShowLocation = !Args.hasArg(OPT_fno_show_source_location);
Opts.ShowOptionNames = Args.hasArg(OPT_fdiagnostics_show_option);
+
+ llvm::StringRef ShowCategory =
+ Args.getLastArgValue(OPT_fdiagnostics_show_category, "none");
+ if (ShowCategory == "none")
+ Opts.ShowCategories = 0;
+ else if (ShowCategory == "id")
+ Opts.ShowCategories = 1;
+ else if (ShowCategory == "name")
+ Opts.ShowCategories = 2;
+ else
+ Diags.Report(diag::err_drv_invalid_value)
+ << Args.getLastArg(OPT_fdiagnostics_show_category)->getAsString(Args)
+ << ShowCategory;
+
Opts.ShowSourceRanges = Args.hasArg(OPT_fdiagnostics_print_source_range_info);
Opts.VerifyDiagnostics = Args.hasArg(OPT_verify);
Opts.BinaryOutput = Args.hasArg(OPT_fdiagnostics_binary);
- Opts.ErrorLimit = getLastArgIntValue(Args, OPT_ferror_limit, 0, Diags);
+ Opts.ErrorLimit = Args.getLastArgIntValue(OPT_ferror_limit, 0, Diags);
Opts.MacroBacktraceLimit
- = getLastArgIntValue(Args, OPT_fmacro_backtrace_limit,
+ = Args.getLastArgIntValue(OPT_fmacro_backtrace_limit,
DiagnosticOptions::DefaultMacroBacktraceLimit, Diags);
Opts.TemplateBacktraceLimit
- = getLastArgIntValue(Args, OPT_ftemplate_backtrace_limit,
+ = Args.getLastArgIntValue(OPT_ftemplate_backtrace_limit,
DiagnosticOptions::DefaultTemplateBacktraceLimit,
Diags);
- Opts.TabStop = getLastArgIntValue(Args, OPT_ftabstop,
+ Opts.TabStop = Args.getLastArgIntValue(OPT_ftabstop,
DiagnosticOptions::DefaultTabStop, Diags);
if (Opts.TabStop == 0 || Opts.TabStop > DiagnosticOptions::MaxTabStop) {
Diags.Report(diag::warn_ignoring_ftabstop_value)
<< Opts.TabStop << DiagnosticOptions::DefaultTabStop;
Opts.TabStop = DiagnosticOptions::DefaultTabStop;
}
- Opts.MessageLength = getLastArgIntValue(Args, OPT_fmessage_length, 0, Diags);
- Opts.DumpBuildInformation = getLastArgValue(Args, OPT_dump_build_information);
- Opts.Warnings = getAllArgValues(Args, OPT_W);
+ Opts.MessageLength = Args.getLastArgIntValue(OPT_fmessage_length, 0, Diags);
+ Opts.DumpBuildInformation = Args.getLastArgValue(OPT_dump_build_information);
+ Opts.Warnings = Args.getAllArgValues(OPT_W);
}
static FrontendOptions::InputKind
@@ -918,6 +917,8 @@ ParseFrontendArgs(FrontendOptions &Opts, ArgList &Args, Diagnostic &Diags) {
Opts.ProgramAction = frontend::ASTPrintXML; break;
case OPT_ast_view:
Opts.ProgramAction = frontend::ASTView; break;
+ case OPT_boostcon:
+ Opts.ProgramAction = frontend::BoostCon; break;
case OPT_dump_raw_tokens:
Opts.ProgramAction = frontend::DumpRawTokens; break;
case OPT_dump_tokens:
@@ -932,6 +933,8 @@ ParseFrontendArgs(FrontendOptions &Opts, ArgList &Args, Diagnostic &Diags) {
Opts.ProgramAction = frontend::EmitLLVM; break;
case OPT_emit_llvm_only:
Opts.ProgramAction = frontend::EmitLLVMOnly; break;
+ case OPT_emit_codegen_only:
+ Opts.ProgramAction = frontend::EmitCodeGenOnly; break;
case OPT_emit_obj:
Opts.ProgramAction = frontend::EmitObj; break;
case OPT_fixit_EQ:
@@ -983,17 +986,19 @@ ParseFrontendArgs(FrontendOptions &Opts, ArgList &Args, Diagnostic &Diags) {
!Args.hasArg(OPT_no_code_completion_debug_printer);
Opts.DisableFree = Args.hasArg(OPT_disable_free);
- Opts.OutputFile = getLastArgValue(Args, OPT_o);
- Opts.Plugins = getAllArgValues(Args, OPT_load);
+ Opts.OutputFile = Args.getLastArgValue(OPT_o);
+ Opts.Plugins = Args.getAllArgValues(OPT_load);
Opts.RelocatablePCH = Args.hasArg(OPT_relocatable_pch);
Opts.ShowHelp = Args.hasArg(OPT_help);
Opts.ShowMacrosInCodeCompletion = Args.hasArg(OPT_code_completion_macros);
+ Opts.ShowCodePatternsInCodeCompletion
+ = Args.hasArg(OPT_code_completion_patterns);
Opts.ShowStats = Args.hasArg(OPT_print_stats);
Opts.ShowTimers = Args.hasArg(OPT_ftime_report);
Opts.ShowVersion = Args.hasArg(OPT_version);
- Opts.ViewClassInheritance = getLastArgValue(Args, OPT_cxx_inheritance_view);
- Opts.ASTMergeFiles = getAllArgValues(Args, OPT_ast_merge);
- Opts.LLVMArgs = getAllArgValues(Args, OPT_mllvm);
+ Opts.ViewClassInheritance = Args.getLastArgValue(OPT_cxx_inheritance_view);
+ Opts.ASTMergeFiles = Args.getAllArgValues(OPT_ast_merge);
+ Opts.LLVMArgs = Args.getAllArgValues(OPT_mllvm);
FrontendOptions::InputKind DashX = FrontendOptions::IK_None;
if (const Arg *A = Args.getLastArg(OPT_x)) {
@@ -1022,7 +1027,7 @@ ParseFrontendArgs(FrontendOptions &Opts, ArgList &Args, Diagnostic &Diags) {
}
// '-' is the default input if none is given.
- std::vector<std::string> Inputs = getAllArgValues(Args, OPT_INPUT);
+ std::vector<std::string> Inputs = Args.getAllArgValues(OPT_INPUT);
Opts.Inputs.clear();
if (Inputs.empty())
Inputs.push_back("-");
@@ -1060,12 +1065,12 @@ std::string CompilerInvocation::GetResourcesPath(const char *Argv0,
static void ParseHeaderSearchArgs(HeaderSearchOptions &Opts, ArgList &Args) {
using namespace cc1options;
- Opts.Sysroot = getLastArgValue(Args, OPT_isysroot, "/");
+ Opts.Sysroot = Args.getLastArgValue(OPT_isysroot, "/");
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);
+ Opts.ResourceDir = Args.getLastArgValue(OPT_resource_dir);
// Add -I... and -F... options in order.
for (arg_iterator it = Args.filtered_begin(OPT_I, OPT_F),
@@ -1204,8 +1209,7 @@ static void ParseLangArgs(LangOptions &Opts, ArgList &Args,
if (Args.hasArg(OPT_pthread))
Opts.POSIXThreads = 1;
- llvm::StringRef Vis = getLastArgValue(Args, OPT_fvisibility,
- "default");
+ llvm::StringRef Vis = Args.getLastArgValue(OPT_fvisibility, "default");
if (Vis == "default")
Opts.setVisibilityMode(LangOptions::Default);
else if (Vis == "hidden")
@@ -1247,18 +1251,18 @@ static void ParseLangArgs(LangOptions &Opts, ArgList &Args,
Opts.AccessControl = !Args.hasArg(OPT_fno_access_control);
Opts.ElideConstructors = !Args.hasArg(OPT_fno_elide_constructors);
Opts.MathErrno = Args.hasArg(OPT_fmath_errno);
- Opts.InstantiationDepth = getLastArgIntValue(Args, OPT_ftemplate_depth, 1024,
+ Opts.InstantiationDepth = Args.getLastArgIntValue(OPT_ftemplate_depth, 1024,
Diags);
Opts.NeXTRuntime = !Args.hasArg(OPT_fgnu_runtime);
- Opts.ObjCConstantStringClass = getLastArgValue(Args,
- OPT_fconstant_string_class);
+ Opts.ObjCConstantStringClass =
+ Args.getLastArgValue(OPT_fconstant_string_class);
Opts.ObjCNonFragileABI = Args.hasArg(OPT_fobjc_nonfragile_abi);
Opts.ObjCNonFragileABI2 = Args.hasArg(OPT_fobjc_nonfragile_abi2);
if (Opts.ObjCNonFragileABI2)
Opts.ObjCNonFragileABI = true;
Opts.CatchUndefined = Args.hasArg(OPT_fcatch_undefined_behavior);
Opts.EmitAllDecls = Args.hasArg(OPT_femit_all_decls);
- Opts.PICLevel = getLastArgIntValue(Args, OPT_pic_level, 0, Diags);
+ Opts.PICLevel = Args.getLastArgIntValue(OPT_pic_level, 0, Diags);
Opts.SjLjExceptions = Args.hasArg(OPT_fsjlj_exceptions);
Opts.Static = Args.hasArg(OPT_static_define);
Opts.DumpRecordLayouts = Args.hasArg(OPT_fdump_record_layouts);
@@ -1268,7 +1272,7 @@ static void ParseLangArgs(LangOptions &Opts, ArgList &Args,
// FIXME: Eliminate this dependency.
unsigned Opt =
- Args.hasArg(OPT_Os) ? 2 : getLastArgIntValue(Args, OPT_O, 0, Diags);
+ Args.hasArg(OPT_Os) ? 2 : Args.getLastArgIntValue(OPT_O, 0, Diags);
Opts.Optimize = Opt != 0;
// This is the __NO_INLINE__ define, which just depends on things like the
@@ -1278,7 +1282,7 @@ static void ParseLangArgs(LangOptions &Opts, ArgList &Args,
// FIXME: This is affected by other options (-fno-inline).
Opts.NoInline = !Opt;
- unsigned SSP = getLastArgIntValue(Args, OPT_stack_protector, 0, Diags);
+ unsigned SSP = Args.getLastArgIntValue(OPT_stack_protector, 0, Diags);
switch (SSP) {
default:
Diags.Report(diag::err_drv_invalid_value)
@@ -1293,8 +1297,8 @@ static void ParseLangArgs(LangOptions &Opts, ArgList &Args,
static void ParsePreprocessorArgs(PreprocessorOptions &Opts, ArgList &Args,
Diagnostic &Diags) {
using namespace cc1options;
- Opts.ImplicitPCHInclude = getLastArgValue(Args, OPT_include_pch);
- Opts.ImplicitPTHInclude = getLastArgValue(Args, OPT_include_pth);
+ Opts.ImplicitPCHInclude = Args.getLastArgValue(OPT_include_pch);
+ Opts.ImplicitPTHInclude = Args.getLastArgValue(OPT_include_pth);
if (const Arg *A = Args.getLastArg(OPT_token_cache))
Opts.TokenCache = A->getValue(Args);
else
@@ -1310,7 +1314,7 @@ static void ParsePreprocessorArgs(PreprocessorOptions &Opts, ArgList &Args,
Opts.addMacroUndef(it->getValue(Args));
}
- Opts.MacroIncludes = getAllArgValues(Args, OPT_imacros);
+ Opts.MacroIncludes = Args.getAllArgValues(OPT_imacros);
// Add the ordered list of -includes.
for (arg_iterator it = Args.filtered_begin(OPT_include, OPT_include_pch,
@@ -1358,10 +1362,10 @@ static void ParsePreprocessorOutputArgs(PreprocessorOutputOptions &Opts,
static void ParseTargetArgs(TargetOptions &Opts, ArgList &Args) {
using namespace cc1options;
- Opts.ABI = getLastArgValue(Args, OPT_target_abi);
- Opts.CPU = getLastArgValue(Args, OPT_target_cpu);
- Opts.Triple = getLastArgValue(Args, OPT_triple);
- Opts.Features = getAllArgValues(Args, OPT_target_feature);
+ Opts.ABI = Args.getLastArgValue(OPT_target_abi);
+ Opts.CPU = Args.getLastArgValue(OPT_target_cpu);
+ Opts.Triple = Args.getLastArgValue(OPT_triple);
+ Opts.Features = Args.getAllArgValues(OPT_target_feature);
// Use the host triple if unspecified.
if (Opts.Triple.empty())
diff --git a/lib/Frontend/DeclXML.cpp b/lib/Frontend/DeclXML.cpp
index 8750b1efcab5..97a7f5558392 100644
--- a/lib/Frontend/DeclXML.cpp
+++ b/lib/Frontend/DeclXML.cpp
@@ -47,11 +47,39 @@ class DocumentXML::DeclPrinter : public DeclVisitor<DocumentXML::DeclPrinter> {
void addSubNodes(CXXRecordDecl* RD) {
addSubNodes(cast<RecordDecl>(RD));
- for (CXXRecordDecl::method_iterator i = RD->method_begin(),
- e = RD->method_end(); i != e; ++i) {
- Visit(*i);
- Doc.toParent();
+
+ if (RD->isDefinition()) {
+ // FIXME: This breaks XML generation
+ //Doc.addAttribute("num_bases", RD->getNumBases());
+
+ for (CXXRecordDecl::base_class_iterator
+ base = RD->bases_begin(),
+ bend = RD->bases_end();
+ base != bend;
+ ++base) {
+ Doc.addSubNode("Base");
+ Doc.addAttribute("id", base->getType());
+ AccessSpecifier as = base->getAccessSpecifierAsWritten();
+ const char* as_name = "";
+ switch(as) {
+ case AS_none: as_name = ""; break;
+ case AS_public: as_name = "public"; break;
+ case AS_protected: as_name = "protected"; break;
+ case AS_private: as_name = "private"; break;
+ }
+ Doc.addAttributeOptional("access", as_name);
+ Doc.addAttribute("is_virtual", base->isVirtual());
+ Doc.toParent();
+ }
+
+ for (CXXRecordDecl::method_iterator i = RD->method_begin(),
+ e = RD->method_end(); i != e; ++i) {
+ Visit(*i);
+ Doc.toParent();
+ }
+
}
+
}
void addSubNodes(EnumDecl* ED) {
@@ -82,6 +110,18 @@ class DocumentXML::DeclPrinter : public DeclVisitor<DocumentXML::DeclPrinter> {
Doc.PrintStmt(argDecl->getDefaultArg());
}
+ void addSubNodes(NamespaceDecl* ns) {
+
+ for (DeclContext::decl_iterator
+ d = ns->decls_begin(),
+ dend = ns->decls_end();
+ d != dend;
+ ++d) {
+ Visit(*d);
+ Doc.toParent();
+ }
+ }
+
void addSpecialAttribute(const char* pName, EnumDecl* ED) {
const QualType& enumType = ED->getIntegerType();
if (!enumType.isNull())
diff --git a/lib/Frontend/DocumentXML.cpp b/lib/Frontend/DocumentXML.cpp
index 0263c30bfd57..894f230216f6 100644
--- a/lib/Frontend/DocumentXML.cpp
+++ b/lib/Frontend/DocumentXML.cpp
@@ -199,6 +199,35 @@ void DocumentXML::addPtrAttribute(const char* pAttributeName,
}
//---------------------------------------------------------
+void DocumentXML::addPtrAttribute(const char* pAttributeName,
+ const NestedNameSpecifier* pNNS) {
+ switch (pNNS->getKind()) {
+ case NestedNameSpecifier::Identifier: {
+ IdentifierInfo *ii = pNNS->getAsIdentifier();
+ // FIXME how should we handle those ?
+ addPtrAttribute(pAttributeName, ii->getName().data());
+ break;
+ }
+ case NestedNameSpecifier::Namespace: {
+ addPtrAttribute(pAttributeName, pNNS->getAsNamespace());
+ break;
+ }
+ case NestedNameSpecifier::TypeSpec: {
+ addPtrAttribute(pAttributeName, pNNS->getAsType());
+ break;
+ }
+ case NestedNameSpecifier::TypeSpecWithTemplate: {
+ addPtrAttribute(pAttributeName, pNNS->getAsType());
+ break;
+ }
+ case NestedNameSpecifier::Global: {
+ addPtrAttribute(pAttributeName, "::");
+ break;
+ }
+ }
+}
+
+//---------------------------------------------------------
void DocumentXML::addTypeRecursively(const QualType& pType)
{
if (addToMap(Types, pType))
diff --git a/lib/Frontend/InitHeaderSearch.cpp b/lib/Frontend/InitHeaderSearch.cpp
index 12a4d4dbd094..e0391c254b38 100644
--- a/lib/Frontend/InitHeaderSearch.cpp
+++ b/lib/Frontend/InitHeaderSearch.cpp
@@ -54,7 +54,7 @@ public:
bool isCXXAware, bool isUserSupplied,
bool isFramework, bool IgnoreSysRoot = false);
- /// AddGnuCPlusPlusIncludePaths - Add the necessary paths to suport a gnu
+ /// AddGnuCPlusPlusIncludePaths - Add the necessary paths to support a gnu
/// libstdc++.
void AddGnuCPlusPlusIncludePaths(llvm::StringRef Base,
llvm::StringRef ArchDir,
@@ -73,7 +73,8 @@ public:
void AddDelimitedPaths(llvm::StringRef String);
// AddDefaultCIncludePaths - Add paths that should always be searched.
- void AddDefaultCIncludePaths(const llvm::Triple &triple);
+ void AddDefaultCIncludePaths(const llvm::Triple &triple,
+ const HeaderSearchOptions &HSOpts);
// AddDefaultCPlusPlusIncludePaths - Add paths that should be searched when
// compiling c++.
@@ -83,7 +84,7 @@ public:
/// that e.g. stdio.h is found.
void AddDefaultSystemIncludePaths(const LangOptions &Lang,
const llvm::Triple &triple,
- bool UseStandardCXXIncludes);
+ const HeaderSearchOptions &HSOpts);
/// Realize - Merges all search path lists into one list and send it to
/// HeaderSearch.
@@ -323,10 +324,14 @@ static bool getSystemRegistryString(const char*, const char*, char*, size_t) {
// Get Visual Studio installation directory.
static bool getVisualStudioDir(std::string &path) {
char vsIDEInstallDir[256];
+ char vsExpressIDEInstallDir[256];
// Try the Windows registry first.
bool hasVCDir = getSystemRegistryString(
"HKEY_LOCAL_MACHINE\\SOFTWARE\\Microsoft\\VisualStudio\\$VERSION",
"InstallDir", vsIDEInstallDir, sizeof(vsIDEInstallDir) - 1);
+ bool hasVCExpressDir = getSystemRegistryString(
+ "HKEY_LOCAL_MACHINE\\SOFTWARE\\Microsoft\\VCExpress\\$VERSION",
+ "InstallDir", vsExpressIDEInstallDir, sizeof(vsExpressIDEInstallDir) - 1);
// If we have both vc80 and vc90, pick version we were compiled with.
if (hasVCDir && vsIDEInstallDir[0]) {
char *p = (char*)strstr(vsIDEInstallDir, "\\Common7\\IDE");
@@ -335,25 +340,43 @@ static bool getVisualStudioDir(std::string &path) {
path = vsIDEInstallDir;
return(true);
}
+ else if (hasVCExpressDir && vsExpressIDEInstallDir[0]) {
+ char *p = (char*)strstr(vsExpressIDEInstallDir, "\\Common7\\IDE");
+ if (p)
+ *p = '\0';
+ path = vsExpressIDEInstallDir;
+ return(true);
+ }
else {
// Try the environment.
+ const char* vs100comntools = getenv("VS100COMNTOOLS");
const char* vs90comntools = getenv("VS90COMNTOOLS");
const char* vs80comntools = getenv("VS80COMNTOOLS");
const char* vscomntools = NULL;
- // If we have both vc80 and vc90, pick version we were compiled with.
- if (vs90comntools && vs80comntools) {
- #if (_MSC_VER >= 1500) // VC90
- vscomntools = vs90comntools;
- #elif (_MSC_VER == 1400) // VC80
- vscomntools = vs80comntools;
- #else
- vscomntools = vs90comntools;
- #endif
+
+ // Try to find the version that we were compiled with
+ if(false) {}
+ #if (_MSC_VER >= 1600) // VC100
+ else if(vs100comntools) {
+ vscomntools = vs100comntools;
}
+ #elif (_MSC_VER == 1500) // VC80
+ else if(vs90comntools) {
+ vscomntools = vs90comntools;
+ }
+ #elif (_MSC_VER == 1400) // VC80
+ else if(vs80comntools) {
+ vscomntools = vs80comntools;
+ }
+ #endif
+ // Otherwise find any version we can
+ else if (vs100comntools)
+ vscomntools = vs100comntools;
else if (vs90comntools)
vscomntools = vs90comntools;
else if (vs80comntools)
vscomntools = vs80comntools;
+
if (vscomntools && *vscomntools) {
char *p = const_cast<char *>(strstr(vscomntools, "\\Common7\\Tools"));
if (p)
@@ -382,8 +405,22 @@ static bool getWindowsSDKDir(std::string &path) {
return(false);
}
-void InitHeaderSearch::AddDefaultCIncludePaths(const llvm::Triple &triple) {
+void InitHeaderSearch::AddDefaultCIncludePaths(const llvm::Triple &triple,
+ const HeaderSearchOptions &HSOpts) {
// FIXME: temporary hack: hard-coded paths.
+ AddPath("/usr/local/include", System, true, false, false);
+
+ // Builtin includes use #include_next directives and should be positioned
+ // just prior C include dirs.
+ if (HSOpts.UseBuiltinIncludes) {
+ // Ignore the sys root, we *always* look for clang headers relative to
+ // supplied path.
+ llvm::sys::Path P(HSOpts.ResourceDir);
+ P.appendComponent("include");
+ AddPath(P.str(), System, false, false, false, /*IgnoreSysRoot=*/ true);
+ }
+
+ // Add dirs specified via 'configure --with-c-include-dirs'.
llvm::StringRef CIncludeDirs(C_INCLUDE_DIRS);
if (CIncludeDirs != "") {
llvm::SmallVector<llvm::StringRef, 5> dirs;
@@ -410,6 +447,8 @@ void InitHeaderSearch::AddDefaultCIncludePaths(const llvm::Triple &triple) {
}
else {
// Default install paths.
+ AddPath("C:/Program Files/Microsoft Visual Studio 10.0/VC/include",
+ System, false, false, false);
AddPath("C:/Program Files/Microsoft Visual Studio 9.0/VC/include",
System, false, false, false);
AddPath(
@@ -480,21 +519,23 @@ void InitHeaderSearch::AddDefaultCIncludePaths(const llvm::Triple &triple) {
break;
}
- AddPath("/usr/local/include", System, true, false, false);
AddPath("/usr/include", System, false, false, false);
}
-void InitHeaderSearch::AddDefaultCPlusPlusIncludePaths(const llvm::Triple &triple) {
+void InitHeaderSearch::
+AddDefaultCPlusPlusIncludePaths(const llvm::Triple &triple) {
llvm::Triple::OSType os = triple.getOS();
llvm::StringRef CxxIncludeRoot(CXX_INCLUDE_ROOT);
if (CxxIncludeRoot != "") {
llvm::StringRef CxxIncludeArch(CXX_INCLUDE_ARCH);
if (CxxIncludeArch == "")
AddGnuCPlusPlusIncludePaths(CxxIncludeRoot, triple.str().c_str(),
- CXX_INCLUDE_32BIT_DIR, CXX_INCLUDE_64BIT_DIR, triple);
+ CXX_INCLUDE_32BIT_DIR, CXX_INCLUDE_64BIT_DIR,
+ triple);
else
AddGnuCPlusPlusIncludePaths(CxxIncludeRoot, CXX_INCLUDE_ARCH,
- CXX_INCLUDE_32BIT_DIR, CXX_INCLUDE_64BIT_DIR, triple);
+ CXX_INCLUDE_32BIT_DIR, CXX_INCLUDE_64BIT_DIR,
+ triple);
return;
}
// FIXME: temporary hack: hard-coded paths.
@@ -527,62 +568,78 @@ void InitHeaderSearch::AddDefaultCPlusPlusIncludePaths(const llvm::Triple &tripl
AddPath("/usr/include/c++/4.1", System, true, false, false);
break;
case llvm::Triple::Linux:
- // Exherbo (2010-01-25)
- AddGnuCPlusPlusIncludePaths("/usr/include/c++/4.4.3",
- "x86_64-pc-linux-gnu", "32", "", triple);
- AddGnuCPlusPlusIncludePaths("/usr/include/c++/4.4.3",
- "i686-pc-linux-gnu", "", "", triple);
- // Debian sid
+ //===------------------------------------------------------------------===//
+ // Debian based distros.
+ // Note: these distros symlink /usr/include/c++/X.Y.Z -> X.Y
+ //===------------------------------------------------------------------===//
+ // Ubuntu 10.04 LTS "Lucid Lynx" -- gcc-4.4.3
+ // Ubuntu 9.10 "Karmic Koala" -- gcc-4.4.1
+ // Debian 6.0 "squeeze" -- gcc-4.4.2
AddGnuCPlusPlusIncludePaths("/usr/include/c++/4.4",
"x86_64-linux-gnu", "32", "", triple);
AddGnuCPlusPlusIncludePaths("/usr/include/c++/4.4",
- "i486-linux-gnu", "64", "", triple);
- // Ubuntu 7.10 - Gutsy Gibbon
- AddGnuCPlusPlusIncludePaths("/usr/include/c++/4.1.3",
- "i486-linux-gnu", "", "", triple);
- // Ubuntu 9.04
- AddGnuCPlusPlusIncludePaths("/usr/include/c++/4.3.3",
- "x86_64-linux-gnu","32", "", triple);
- // Ubuntu 9.10
- AddGnuCPlusPlusIncludePaths("/usr/include/c++/4.4.1",
+ "i486-linux-gnu", "", "64", triple);
+ // Ubuntu 9.04 "Jaunty Jackalope" -- gcc-4.3.3
+ // Ubuntu 8.10 "Intrepid Ibex" -- gcc-4.3.2
+ // Debian 5.0 "lenny" -- gcc-4.3.2
+ AddGnuCPlusPlusIncludePaths("/usr/include/c++/4.3",
"x86_64-linux-gnu", "32", "", triple);
- // Fedora 8
- AddGnuCPlusPlusIncludePaths("/usr/include/c++/4.1.2",
- "i386-redhat-linux", "", "", triple);
- // Fedora 9
- AddGnuCPlusPlusIncludePaths("/usr/include/c++/4.3.0",
- "i386-redhat-linux", "", "", triple);
- // Fedora 10
- AddGnuCPlusPlusIncludePaths("/usr/include/c++/4.3.2",
- "i386-redhat-linux","", "", triple);
+ AddGnuCPlusPlusIncludePaths("/usr/include/c++/4.3",
+ "i486-linux-gnu", "", "64", triple);
+ // Ubuntu 8.04.4 LTS "Hardy Heron" -- gcc-4.2.4
+ // Ubuntu 8.04.[0-3] LTS "Hardy Heron" -- gcc-4.2.3
+ AddGnuCPlusPlusIncludePaths("/usr/include/c++/4.2",
+ "x86_64-linux-gnu", "32", "", triple);
+ AddGnuCPlusPlusIncludePaths("/usr/include/c++/4.2",
+ "i486-linux-gnu", "", "64", triple);
+ // Ubuntu 7.10 "Gutsy Gibbon" -- gcc-4.1.3
+ AddGnuCPlusPlusIncludePaths("/usr/include/c++/4.1",
+ "x86_64-linux-gnu", "32", "", triple);
+ AddGnuCPlusPlusIncludePaths("/usr/include/c++/4.1",
+ "i486-linux-gnu", "", "64", triple);
- // Fedora 10 x86_64
- AddGnuCPlusPlusIncludePaths("/usr/include/c++/4.3.2",
+ //===------------------------------------------------------------------===//
+ // Redhat based distros.
+ //===------------------------------------------------------------------===//
+ // Fedora 13
+ // Fedora 12
+ AddGnuCPlusPlusIncludePaths("/usr/include/c++/4.4.3",
"x86_64-redhat-linux", "32", "", triple);
-
+ AddGnuCPlusPlusIncludePaths("/usr/include/c++/4.4.3",
+ "i686-redhat-linux","", "", triple);
+ // Fedora 12 (pre-FEB-2010)
+ AddGnuCPlusPlusIncludePaths("/usr/include/c++/4.4.2",
+ "x86_64-redhat-linux", "32", "", triple);
+ AddGnuCPlusPlusIncludePaths("/usr/include/c++/4.4.2",
+ "i686-redhat-linux","", "", triple);
// Fedora 11
AddGnuCPlusPlusIncludePaths("/usr/include/c++/4.4.1",
- "i586-redhat-linux","", "", triple);
-
- // Fedora 11 x86_64
+ "x86_64-redhat-linux", "32", "", triple);
AddGnuCPlusPlusIncludePaths("/usr/include/c++/4.4.1",
+ "i586-redhat-linux","", "", triple);
+ // Fedora 10
+ AddGnuCPlusPlusIncludePaths("/usr/include/c++/4.3.2",
"x86_64-redhat-linux", "32", "", triple);
-
- // Fedora 12
- AddGnuCPlusPlusIncludePaths("/usr/include/c++/4.4.2",
- "i686-redhat-linux","", "", triple);
-
- // Fedora 12 x86_64
- AddGnuCPlusPlusIncludePaths("/usr/include/c++/4.4.2",
+ AddGnuCPlusPlusIncludePaths("/usr/include/c++/4.3.2",
+ "i386-redhat-linux","", "", triple);
+ // Fedora 9
+ AddGnuCPlusPlusIncludePaths("/usr/include/c++/4.3.0",
"x86_64-redhat-linux", "32", "", triple);
+ AddGnuCPlusPlusIncludePaths("/usr/include/c++/4.3.0",
+ "i386-redhat-linux", "", "", triple);
+ // Fedora 8
+ AddGnuCPlusPlusIncludePaths("/usr/include/c++/4.1.2",
+ "x86_64-redhat-linux", "", "", triple);
+ AddGnuCPlusPlusIncludePaths("/usr/include/c++/4.1.2",
+ "i386-redhat-linux", "", "", triple);
- // Fedora 12 (February-2010+)
- AddGnuCPlusPlusIncludePaths("/usr/include/c++/4.4.3",
- "i686-redhat-linux","", "", triple);
+ //===------------------------------------------------------------------===//
- // Fedora 12 (February-2010+) x86_64
+ // Exherbo (2010-01-25)
AddGnuCPlusPlusIncludePaths("/usr/include/c++/4.4.3",
- "x86_64-redhat-linux", "32", "", triple);
+ "x86_64-pc-linux-gnu", "32", "", triple);
+ AddGnuCPlusPlusIncludePaths("/usr/include/c++/4.4.3",
+ "i686-pc-linux-gnu", "", "", triple);
// openSUSE 11.1 32 bit
AddGnuCPlusPlusIncludePaths("/usr/include/c++/4.3",
@@ -612,12 +669,6 @@ void InitHeaderSearch::AddDefaultCPlusPlusIncludePaths(const llvm::Triple &tripl
AddGnuCPlusPlusIncludePaths(
"/usr/lib/gcc/i686-pc-linux-gnu/4.1.2/include/g++-v4",
"i686-pc-linux-gnu", "", "", triple);
- // Ubuntu 8.10
- AddGnuCPlusPlusIncludePaths("/usr/include/c++/4.3",
- "i486-pc-linux-gnu", "", "", triple);
- // Ubuntu 9.04
- AddGnuCPlusPlusIncludePaths("/usr/include/c++/4.3",
- "i486-linux-gnu","", "", triple);
// Gentoo amd64 stable
AddGnuCPlusPlusIncludePaths(
"/usr/lib/gcc/x86_64-pc-linux-gnu/4.1.2/include/g++-v4",
@@ -635,6 +686,8 @@ void InitHeaderSearch::AddDefaultCPlusPlusIncludePaths(const llvm::Triple &tripl
break;
case llvm::Triple::FreeBSD:
+ // FreeBSD 8.0
+ // FreeBSD 7.3
AddGnuCPlusPlusIncludePaths("/usr/include/c++/4.2", "", "", "", triple);
break;
case llvm::Triple::Solaris:
@@ -651,11 +704,11 @@ void InitHeaderSearch::AddDefaultCPlusPlusIncludePaths(const llvm::Triple &tripl
void InitHeaderSearch::AddDefaultSystemIncludePaths(const LangOptions &Lang,
const llvm::Triple &triple,
- bool UseStandardCXXIncludes) {
- if (Lang.CPlusPlus && UseStandardCXXIncludes)
+ const HeaderSearchOptions &HSOpts) {
+ if (Lang.CPlusPlus && HSOpts.UseStandardCXXIncludes)
AddDefaultCPlusPlusIncludePaths(triple);
- AddDefaultCIncludePaths(triple);
+ AddDefaultCIncludePaths(triple, HSOpts);
// Add the default framework include paths on Darwin.
if (triple.getOS() == llvm::Triple::Darwin) {
@@ -813,17 +866,8 @@ void clang::ApplyHeaderSearchOptions(HeaderSearch &HS,
else
Init.AddDelimitedPaths(HSOpts.CEnvIncPath);
- if (HSOpts.UseBuiltinIncludes) {
- // Ignore the sys root, we *always* look for clang headers relative to
- // supplied path.
- llvm::sys::Path P(HSOpts.ResourceDir);
- P.appendComponent("include");
- Init.AddPath(P.str(), System, false, false, false, /*IgnoreSysRoot=*/ true);
- }
-
if (HSOpts.UseStandardIncludes)
- Init.AddDefaultSystemIncludePaths(Lang, Triple,
- HSOpts.UseStandardCXXIncludes);
+ Init.AddDefaultSystemIncludePaths(Lang, Triple, HSOpts);
Init.Realize();
}
diff --git a/lib/Frontend/InitPreprocessor.cpp b/lib/Frontend/InitPreprocessor.cpp
index f1e9819d83ca..2b35c8e2296b 100644
--- a/lib/Frontend/InitPreprocessor.cpp
+++ b/lib/Frontend/InitPreprocessor.cpp
@@ -428,6 +428,11 @@ static void InitializePredefinedMacros(const TargetInfo &TI,
if (FEOpts.ProgramAction == frontend::RewriteObjC)
Builder.defineMacro("__weak", "__attribute__((objc_gc(weak)))");
+
+ // Define a macro that exists only when using the static analyzer.
+ if (FEOpts.ProgramAction == frontend::RunAnalysis)
+ Builder.defineMacro("__clang_analyzer__");
+
// Get other target #defines.
TI.getTargetDefines(LangOpts, Builder);
}
diff --git a/lib/Frontend/PCHReader.cpp b/lib/Frontend/PCHReader.cpp
index ae57ce581def..88e9b9db1805 100644
--- a/lib/Frontend/PCHReader.cpp
+++ b/lib/Frontend/PCHReader.cpp
@@ -2165,28 +2165,32 @@ QualType PCHReader::ReadTypeRecord(uint64_t Offset) {
return QualType();
}
unsigned Tag = Record[1];
- return Context->getElaboratedType(GetType(Record[0]),
- (ElaboratedType::TagKind) Tag);
+ // FIXME: Deserialize the qualifier (C++ only)
+ return Context->getElaboratedType((ElaboratedTypeKeyword) Tag,
+ /* NNS */ 0,
+ GetType(Record[0]));
}
case pch::TYPE_OBJC_INTERFACE: {
unsigned Idx = 0;
ObjCInterfaceDecl *ItfD = cast<ObjCInterfaceDecl>(GetDecl(Record[Idx++]));
+ return Context->getObjCInterfaceType(ItfD);
+ }
+
+ case pch::TYPE_OBJC_OBJECT: {
+ unsigned Idx = 0;
+ QualType Base = GetType(Record[Idx++]);
unsigned NumProtos = Record[Idx++];
llvm::SmallVector<ObjCProtocolDecl*, 4> Protos;
for (unsigned I = 0; I != NumProtos; ++I)
Protos.push_back(cast<ObjCProtocolDecl>(GetDecl(Record[Idx++])));
- return Context->getObjCInterfaceType(ItfD, Protos.data(), NumProtos);
+ return Context->getObjCObjectType(Base, Protos.data(), NumProtos);
}
case pch::TYPE_OBJC_OBJECT_POINTER: {
unsigned Idx = 0;
- QualType OIT = GetType(Record[Idx++]);
- unsigned NumProtos = Record[Idx++];
- llvm::SmallVector<ObjCProtocolDecl*, 4> Protos;
- for (unsigned I = 0; I != NumProtos; ++I)
- Protos.push_back(cast<ObjCProtocolDecl>(GetDecl(Record[Idx++])));
- return Context->getObjCObjectPointerType(OIT, Protos.data(), NumProtos);
+ QualType Pointee = GetType(Record[Idx++]);
+ return Context->getObjCObjectPointerType(Pointee);
}
case pch::TYPE_SUBST_TEMPLATE_TYPE_PARM: {
@@ -2334,9 +2338,6 @@ void TypeLocReader::VisitRecordTypeLoc(RecordTypeLoc TL) {
void TypeLocReader::VisitEnumTypeLoc(EnumTypeLoc TL) {
TL.setNameLoc(SourceLocation::getFromRawEncoding(Record[Idx++]));
}
-void TypeLocReader::VisitElaboratedTypeLoc(ElaboratedTypeLoc TL) {
- TL.setNameLoc(SourceLocation::getFromRawEncoding(Record[Idx++]));
-}
void TypeLocReader::VisitTemplateTypeParmTypeLoc(TemplateTypeParmTypeLoc TL) {
TL.setNameLoc(SourceLocation::getFromRawEncoding(Record[Idx++]));
}
@@ -2354,17 +2355,23 @@ void TypeLocReader::VisitTemplateSpecializationTypeLoc(
Reader.GetTemplateArgumentLocInfo(TL.getTypePtr()->getArg(i).getKind(),
Record, Idx));
}
-void TypeLocReader::VisitQualifiedNameTypeLoc(QualifiedNameTypeLoc TL) {
- TL.setNameLoc(SourceLocation::getFromRawEncoding(Record[Idx++]));
+void TypeLocReader::VisitElaboratedTypeLoc(ElaboratedTypeLoc TL) {
+ TL.setKeywordLoc(SourceLocation::getFromRawEncoding(Record[Idx++]));
+ TL.setQualifierRange(Reader.ReadSourceRange(Record, Idx));
}
void TypeLocReader::VisitInjectedClassNameTypeLoc(InjectedClassNameTypeLoc TL) {
TL.setNameLoc(SourceLocation::getFromRawEncoding(Record[Idx++]));
}
void TypeLocReader::VisitDependentNameTypeLoc(DependentNameTypeLoc TL) {
+ TL.setKeywordLoc(SourceLocation::getFromRawEncoding(Record[Idx++]));
+ TL.setQualifierRange(Reader.ReadSourceRange(Record, Idx));
TL.setNameLoc(SourceLocation::getFromRawEncoding(Record[Idx++]));
}
void TypeLocReader::VisitObjCInterfaceTypeLoc(ObjCInterfaceTypeLoc TL) {
TL.setNameLoc(SourceLocation::getFromRawEncoding(Record[Idx++]));
+}
+void TypeLocReader::VisitObjCObjectTypeLoc(ObjCObjectTypeLoc TL) {
+ TL.setHasBaseTypeAsWritten(Record[Idx++]);
TL.setLAngleLoc(SourceLocation::getFromRawEncoding(Record[Idx++]));
TL.setRAngleLoc(SourceLocation::getFromRawEncoding(Record[Idx++]));
for (unsigned i = 0, e = TL.getNumProtocols(); i != e; ++i)
@@ -2372,13 +2379,6 @@ void TypeLocReader::VisitObjCInterfaceTypeLoc(ObjCInterfaceTypeLoc TL) {
}
void TypeLocReader::VisitObjCObjectPointerTypeLoc(ObjCObjectPointerTypeLoc TL) {
TL.setStarLoc(SourceLocation::getFromRawEncoding(Record[Idx++]));
- TL.setLAngleLoc(SourceLocation::getFromRawEncoding(Record[Idx++]));
- TL.setRAngleLoc(SourceLocation::getFromRawEncoding(Record[Idx++]));
- TL.setHasBaseTypeAsWritten(Record[Idx++]);
- TL.setHasProtocolsAsWritten(Record[Idx++]);
- if (TL.hasProtocolsAsWritten())
- for (unsigned i = 0, e = TL.getNumProtocols(); i != e; ++i)
- TL.setProtocolLoc(i, SourceLocation::getFromRawEncoding(Record[Idx++]));
}
TypeSourceInfo *PCHReader::GetTypeSourceInfo(const RecordData &Record,
@@ -2901,6 +2901,51 @@ PCHReader::ReadDeclarationName(const RecordData &Record, unsigned &Idx) {
return DeclarationName();
}
+NestedNameSpecifier *
+PCHReader::ReadNestedNameSpecifier(const RecordData &Record, unsigned &Idx) {
+ unsigned N = Record[Idx++];
+ NestedNameSpecifier *NNS = 0, *Prev = 0;
+ for (unsigned I = 0; I != N; ++I) {
+ NestedNameSpecifier::SpecifierKind Kind
+ = (NestedNameSpecifier::SpecifierKind)Record[Idx++];
+ switch (Kind) {
+ case NestedNameSpecifier::Identifier: {
+ IdentifierInfo *II = GetIdentifierInfo(Record, Idx);
+ NNS = NestedNameSpecifier::Create(*Context, Prev, II);
+ break;
+ }
+
+ case NestedNameSpecifier::Namespace: {
+ NamespaceDecl *NS = cast<NamespaceDecl>(GetDecl(Record[Idx++]));
+ NNS = NestedNameSpecifier::Create(*Context, Prev, NS);
+ break;
+ }
+
+ case NestedNameSpecifier::TypeSpec:
+ case NestedNameSpecifier::TypeSpecWithTemplate: {
+ Type *T = GetType(Record[Idx++]).getTypePtr();
+ bool Template = Record[Idx++];
+ NNS = NestedNameSpecifier::Create(*Context, Prev, Template, T);
+ break;
+ }
+
+ case NestedNameSpecifier::Global: {
+ NNS = NestedNameSpecifier::GlobalSpecifier(*Context);
+ // No associated value, and there can't be a prefix.
+ break;
+ }
+ Prev = NNS;
+ }
+ }
+ return NNS;
+}
+
+SourceRange
+PCHReader::ReadSourceRange(const RecordData &Record, unsigned &Idx) {
+ return SourceRange(SourceLocation::getFromRawEncoding(Record[Idx++]),
+ SourceLocation::getFromRawEncoding(Record[Idx++]));
+}
+
/// \brief Read an integral value
llvm::APInt PCHReader::ReadAPInt(const RecordData &Record, unsigned &Idx) {
unsigned BitWidth = Record[Idx++];
@@ -2929,6 +2974,12 @@ std::string PCHReader::ReadString(const RecordData &Record, unsigned &Idx) {
return Result;
}
+CXXTemporary *PCHReader::ReadCXXTemporary(const RecordData &Record,
+ unsigned &Idx) {
+ CXXDestructorDecl *Decl = cast<CXXDestructorDecl>(GetDecl(Record[Idx++]));
+ return CXXTemporary::Create(*Context, Decl);
+}
+
DiagnosticBuilder PCHReader::Diag(unsigned DiagID) {
return Diag(SourceLocation(), DiagID);
}
diff --git a/lib/Frontend/PCHReaderDecl.cpp b/lib/Frontend/PCHReaderDecl.cpp
index 14dd2e927c41..1ef0441ebf60 100644
--- a/lib/Frontend/PCHReaderDecl.cpp
+++ b/lib/Frontend/PCHReaderDecl.cpp
@@ -17,6 +17,8 @@
#include "clang/AST/ASTContext.h"
#include "clang/AST/DeclVisitor.h"
#include "clang/AST/DeclGroup.h"
+#include "clang/AST/DeclCXX.h"
+#include "clang/AST/DeclTemplate.h"
#include "clang/AST/Expr.h"
using namespace clang;
@@ -40,22 +42,49 @@ namespace {
void VisitTranslationUnitDecl(TranslationUnitDecl *TU);
void VisitNamedDecl(NamedDecl *ND);
void VisitNamespaceDecl(NamespaceDecl *D);
+ void VisitUsingDirectiveDecl(UsingDirectiveDecl *D);
+ void VisitNamespaceAliasDecl(NamespaceAliasDecl *D);
void VisitTypeDecl(TypeDecl *TD);
void VisitTypedefDecl(TypedefDecl *TD);
+ void VisitUnresolvedUsingTypename(UnresolvedUsingTypenameDecl *D);
void VisitTagDecl(TagDecl *TD);
void VisitEnumDecl(EnumDecl *ED);
void VisitRecordDecl(RecordDecl *RD);
+ void VisitCXXRecordDecl(CXXRecordDecl *D);
+ void VisitClassTemplateSpecializationDecl(
+ ClassTemplateSpecializationDecl *D);
+ void VisitClassTemplatePartialSpecializationDecl(
+ ClassTemplatePartialSpecializationDecl *D);
+ void VisitTemplateTypeParmDecl(TemplateTypeParmDecl *D);
void VisitValueDecl(ValueDecl *VD);
void VisitEnumConstantDecl(EnumConstantDecl *ECD);
+ void VisitUnresolvedUsingValue(UnresolvedUsingValueDecl *D);
void VisitDeclaratorDecl(DeclaratorDecl *DD);
void VisitFunctionDecl(FunctionDecl *FD);
+ void VisitCXXMethodDecl(CXXMethodDecl *D);
+ void VisitCXXConstructorDecl(CXXConstructorDecl *D);
+ void VisitCXXDestructorDecl(CXXDestructorDecl *D);
+ void VisitCXXConversionDecl(CXXConversionDecl *D);
void VisitFieldDecl(FieldDecl *FD);
void VisitVarDecl(VarDecl *VD);
void VisitImplicitParamDecl(ImplicitParamDecl *PD);
void VisitParmVarDecl(ParmVarDecl *PD);
+ void VisitNonTypeTemplateParmDecl(NonTypeTemplateParmDecl *D);
+ void VisitTemplateDecl(TemplateDecl *D);
+ void VisitClassTemplateDecl(ClassTemplateDecl *D);
+ void visitFunctionTemplateDecl(FunctionTemplateDecl *D);
+ void VisitTemplateTemplateParmDecl(TemplateTemplateParmDecl *D);
+ void VisitUsing(UsingDecl *D);
+ void VisitUsingShadow(UsingShadowDecl *D);
+ void VisitLinkageSpecDecl(LinkageSpecDecl *D);
void VisitFileScopeAsmDecl(FileScopeAsmDecl *AD);
+ void VisitFriendTemplateDecl(FriendTemplateDecl *D);
+ void VisitStaticAssertDecl(StaticAssertDecl *D);
void VisitBlockDecl(BlockDecl *BD);
+
std::pair<uint64_t, uint64_t> VisitDeclContext(DeclContext *DC);
+
+ // FIXME: Reorder according to DeclNodes.def?
void VisitObjCMethodDecl(ObjCMethodDecl *D);
void VisitObjCContainerDecl(ObjCContainerDecl *D);
void VisitObjCInterfaceDecl(ObjCInterfaceDecl *D);
@@ -90,6 +119,8 @@ void PCHDeclReader::VisitDecl(Decl *D) {
void PCHDeclReader::VisitTranslationUnitDecl(TranslationUnitDecl *TU) {
VisitDecl(TU);
+ TU->setAnonymousNamespace(
+ cast_or_null<NamespaceDecl>(Reader.GetDecl(Record[Idx++])));
}
void PCHDeclReader::VisitNamedDecl(NamedDecl *ND) {
@@ -97,18 +128,6 @@ void PCHDeclReader::VisitNamedDecl(NamedDecl *ND) {
ND->setDeclName(Reader.ReadDeclarationName(Record, Idx));
}
-void PCHDeclReader::VisitNamespaceDecl(NamespaceDecl *D) {
- VisitNamedDecl(D);
- D->setLBracLoc(SourceLocation::getFromRawEncoding(Record[Idx++]));
- D->setRBracLoc(SourceLocation::getFromRawEncoding(Record[Idx++]));
- D->setNextNamespace(
- cast_or_null<NamespaceDecl>(Reader.GetDecl(Record[Idx++])));
- D->setOriginalNamespace(
- cast_or_null<NamespaceDecl>(Reader.GetDecl(Record[Idx++])));
- D->setAnonymousNamespace(
- cast_or_null<NamespaceDecl>(Reader.GetDecl(Record[Idx++])));
-}
-
void PCHDeclReader::VisitTypeDecl(TypeDecl *TD) {
VisitNamedDecl(TD);
TD->setTypeForDecl(Reader.GetType(Record[Idx++]).getTypePtr());
@@ -142,6 +161,8 @@ void PCHDeclReader::VisitEnumDecl(EnumDecl *ED) {
VisitTagDecl(ED);
ED->setIntegerType(Reader.GetType(Record[Idx++]));
ED->setPromotionType(Reader.GetType(Record[Idx++]));
+ ED->setNumPositiveBits(Record[Idx++]);
+ ED->setNumNegativeBits(Record[Idx++]);
// FIXME: C++ InstantiatedFrom
}
@@ -191,6 +212,8 @@ void PCHDeclReader::VisitFunctionDecl(FunctionDecl *FD) {
FD->setHasImplicitReturnZero(Record[Idx++]);
FD->setLocEnd(SourceLocation::getFromRawEncoding(Record[Idx++]));
// FIXME: C++ TemplateOrInstantiation
+
+ // Read in the parameters.
unsigned NumParams = Record[Idx++];
llvm::SmallVector<ParmVarDecl *, 16> Params;
Params.reserve(NumParams);
@@ -394,6 +417,7 @@ void PCHDeclReader::VisitObjCPropertyImplDecl(ObjCPropertyImplDecl *D) {
cast_or_null<ObjCPropertyDecl>(Reader.GetDecl(Record[Idx++])));
D->setPropertyIvarDecl(
cast_or_null<ObjCIvarDecl>(Reader.GetDecl(Record[Idx++])));
+ // FIXME. read GetterCXXConstructor and SetterCXXAssignment
}
void PCHDeclReader::VisitFieldDecl(FieldDecl *FD) {
@@ -411,6 +435,7 @@ void PCHDeclReader::VisitVarDecl(VarDecl *VD) {
VD->setCXXDirectInitializer(Record[Idx++]);
VD->setDeclaredInCondition(Record[Idx++]);
VD->setExceptionVariable(Record[Idx++]);
+ VD->setNRVOVariable(Record[Idx++]);
VD->setPreviousDeclaration(
cast_or_null<VarDecl>(Reader.GetDecl(Record[Idx++])));
if (Record[Idx++])
@@ -443,6 +468,155 @@ void PCHDeclReader::VisitBlockDecl(BlockDecl *BD) {
BD->setParams(Params.data(), NumParams);
}
+void PCHDeclReader::VisitLinkageSpecDecl(LinkageSpecDecl *D) {
+ VisitDecl(D);
+ D->setLanguage((LinkageSpecDecl::LanguageIDs)Record[Idx++]);
+ D->setHasBraces(Record[Idx++]);
+}
+
+void PCHDeclReader::VisitNamespaceDecl(NamespaceDecl *D) {
+ VisitNamedDecl(D);
+ D->setLBracLoc(Reader.ReadSourceLocation(Record, Idx));
+ D->setRBracLoc(Reader.ReadSourceLocation(Record, Idx));
+ D->setNextNamespace(
+ cast_or_null<NamespaceDecl>(Reader.GetDecl(Record[Idx++])));
+
+ // Only read one reference--the original or anonymous namespace.
+ bool IsOriginal = Record[Idx++];
+ if (IsOriginal)
+ D->setAnonymousNamespace(
+ cast_or_null<NamespaceDecl>(Reader.GetDecl(Record[Idx++])));
+ else
+ D->setOriginalNamespace(
+ cast_or_null<NamespaceDecl>(Reader.GetDecl(Record[Idx++])));
+}
+
+void PCHDeclReader::VisitNamespaceAliasDecl(NamespaceAliasDecl *D) {
+ VisitNamedDecl(D);
+
+ D->setAliasLoc(Reader.ReadSourceLocation(Record, Idx));
+ D->setQualifierRange(Reader.ReadSourceRange(Record, Idx));
+ D->setQualifier(Reader.ReadNestedNameSpecifier(Record, Idx));
+ D->setTargetNameLoc(Reader.ReadSourceLocation(Record, Idx));
+ D->setAliasedNamespace(cast<NamedDecl>(Reader.GetDecl(Record[Idx++])));
+}
+
+void PCHDeclReader::VisitUsing(UsingDecl *D) {
+ VisitNamedDecl(D);
+ D->setUsingLocation(Reader.ReadSourceLocation(Record, Idx));
+ D->setNestedNameRange(Reader.ReadSourceRange(Record, Idx));
+ D->setTargetNestedNameDecl(Reader.ReadNestedNameSpecifier(Record, Idx));
+
+ // FIXME: It would probably be more efficient to read these into a vector
+ // and then re-cosntruct the shadow decl set over that vector since it
+ // would avoid existence checks.
+ unsigned NumShadows = Record[Idx++];
+ for(unsigned I = 0; I != NumShadows; ++I) {
+ D->addShadowDecl(cast<UsingShadowDecl>(Reader.GetDecl(Record[Idx++])));
+ }
+ D->setTypeName(Record[Idx++]);
+}
+
+void PCHDeclReader::VisitUsingShadow(UsingShadowDecl *D) {
+ VisitNamedDecl(D);
+ D->setTargetDecl(cast<NamedDecl>(Reader.GetDecl(Record[Idx++])));
+ D->setUsingDecl(cast<UsingDecl>(Reader.GetDecl(Record[Idx++])));
+}
+
+void PCHDeclReader::VisitUsingDirectiveDecl(UsingDirectiveDecl *D) {
+ VisitNamedDecl(D);
+ D->setNamespaceKeyLocation(Reader.ReadSourceLocation(Record, Idx));
+ D->setQualifierRange(Reader.ReadSourceRange(Record, Idx));
+ D->setQualifier(Reader.ReadNestedNameSpecifier(Record, Idx));
+ D->setIdentLocation(Reader.ReadSourceLocation(Record, Idx));
+ D->setNominatedNamespace(cast<NamedDecl>(Reader.GetDecl(Record[Idx++])));
+ D->setCommonAncestor(cast_or_null<DeclContext>(
+ Reader.GetDecl(Record[Idx++])));
+}
+
+void PCHDeclReader::VisitUnresolvedUsingValue(UnresolvedUsingValueDecl *D) {
+ VisitValueDecl(D);
+ D->setTargetNestedNameRange(Reader.ReadSourceRange(Record, Idx));
+ D->setUsingLoc(Reader.ReadSourceLocation(Record, Idx));
+ D->setTargetNestedNameSpecifier(Reader.ReadNestedNameSpecifier(Record, Idx));
+}
+
+void PCHDeclReader::VisitUnresolvedUsingTypename(
+ UnresolvedUsingTypenameDecl *D) {
+ VisitTypeDecl(D);
+ D->setTargetNestedNameRange(Reader.ReadSourceRange(Record, Idx));
+ D->setUsingLoc(Reader.ReadSourceLocation(Record, Idx));
+ D->setTypenameLoc(Reader.ReadSourceLocation(Record, Idx));
+ D->setTargetNestedNameSpecifier(Reader.ReadNestedNameSpecifier(Record, Idx));
+}
+
+void PCHDeclReader::VisitCXXRecordDecl(CXXRecordDecl *D) {
+ // assert(false && "cannot read CXXRecordDecl");
+ VisitRecordDecl(D);
+}
+
+void PCHDeclReader::VisitCXXMethodDecl(CXXMethodDecl *D) {
+ // assert(false && "cannot read CXXMethodDecl");
+ VisitFunctionDecl(D);
+}
+
+void PCHDeclReader::VisitCXXConstructorDecl(CXXConstructorDecl *D) {
+ // assert(false && "cannot read CXXConstructorDecl");
+ VisitCXXMethodDecl(D);
+}
+
+void PCHDeclReader::VisitCXXDestructorDecl(CXXDestructorDecl *D) {
+ // assert(false && "cannot read CXXDestructorDecl");
+ VisitCXXMethodDecl(D);
+}
+
+void PCHDeclReader::VisitCXXConversionDecl(CXXConversionDecl *D) {
+ // assert(false && "cannot read CXXConversionDecl");
+ VisitCXXMethodDecl(D);
+}
+
+void PCHDeclReader::VisitFriendTemplateDecl(FriendTemplateDecl *D) {
+ assert(false && "cannot read FriendTemplateDecl");
+}
+
+void PCHDeclReader::VisitTemplateDecl(TemplateDecl *D) {
+ assert(false && "cannot read TemplateDecl");
+}
+
+void PCHDeclReader::VisitClassTemplateDecl(ClassTemplateDecl *D) {
+ assert(false && "cannot read ClassTemplateDecl");
+}
+
+void PCHDeclReader::VisitClassTemplateSpecializationDecl(
+ ClassTemplateSpecializationDecl *D) {
+ assert(false && "cannot read ClassTemplateSpecializationDecl");
+}
+
+void PCHDeclReader::VisitClassTemplatePartialSpecializationDecl(
+ ClassTemplatePartialSpecializationDecl *D) {
+ assert(false && "cannot read ClassTemplatePartialSpecializationDecl");
+}
+
+void PCHDeclReader::visitFunctionTemplateDecl(FunctionTemplateDecl *D) {
+ assert(false && "cannot read FunctionTemplateDecl");
+}
+
+void PCHDeclReader::VisitTemplateTypeParmDecl(TemplateTypeParmDecl *D) {
+ assert(false && "cannot read TemplateTypeParmDecl");
+}
+
+void PCHDeclReader::VisitNonTypeTemplateParmDecl(NonTypeTemplateParmDecl *D) {
+ assert(false && "cannot read NonTypeTemplateParmDecl");
+}
+
+void PCHDeclReader::VisitTemplateTemplateParmDecl(TemplateTemplateParmDecl *D) {
+ assert(false && "cannot read TemplateTemplateParmDecl");
+}
+
+void PCHDeclReader::VisitStaticAssertDecl(StaticAssertDecl *D) {
+ assert(false && "cannot read StaticAssertDecl");
+}
+
std::pair<uint64_t, uint64_t>
PCHDeclReader::VisitDeclContext(DeclContext *DC) {
uint64_t LexicalOffset = Record[Idx++];
@@ -492,6 +666,7 @@ Attr *PCHReader::ReadAttributes() {
assert(0 && "Unknown attribute!");
break;
STRING_ATTR(Alias);
+ SIMPLE_ATTR(AlignMac68k);
UNSIGNED_ATTR(Aligned);
SIMPLE_ATTR(AlwaysInline);
SIMPLE_ATTR(AnalyzerNoReturn);
@@ -552,6 +727,13 @@ Attr *PCHReader::ReadAttributes() {
New = ::new (*Context) IBOutletAttr();
break;
+ case Attr::IBOutletCollectionKind: {
+ ObjCInterfaceDecl *D =
+ cast_or_null<ObjCInterfaceDecl>(GetDecl(Record[Idx++]));
+ New = ::new (*Context) IBOutletCollectionAttr(D);
+ break;
+ }
+
SIMPLE_ATTR(Malloc);
SIMPLE_ATTR(NoDebug);
SIMPLE_ATTR(NoInline);
@@ -584,11 +766,12 @@ Attr *PCHReader::ReadAttributes() {
SIMPLE_ATTR(Overloadable);
SIMPLE_ATTR(Override);
SIMPLE_ATTR(Packed);
- UNSIGNED_ATTR(PragmaPack);
+ UNSIGNED_ATTR(MaxFieldAlignment);
SIMPLE_ATTR(Pure);
UNSIGNED_ATTR(Regparm);
STRING_ATTR(Section);
SIMPLE_ATTR(StdCall);
+ SIMPLE_ATTR(ThisCall);
SIMPLE_ATTR(TransparentUnion);
SIMPLE_ATTR(Unavailable);
SIMPLE_ATTR(Unused);
@@ -692,7 +875,7 @@ Decl *PCHReader::ReadDeclRecord(uint64_t Offset, unsigned Index) {
D = EnumDecl::Create(*Context, 0, SourceLocation(), 0, SourceLocation(), 0);
break;
case pch::DECL_RECORD:
- D = RecordDecl::Create(*Context, TagDecl::TK_struct, 0, SourceLocation(),
+ D = RecordDecl::Create(*Context, TTK_Struct, 0, SourceLocation(),
0, SourceLocation(), 0);
break;
case pch::DECL_ENUM_CONSTANT:
@@ -703,6 +886,94 @@ Decl *PCHReader::ReadDeclRecord(uint64_t Offset, unsigned Index) {
D = FunctionDecl::Create(*Context, 0, SourceLocation(), DeclarationName(),
QualType(), 0);
break;
+ case pch::DECL_LINKAGE_SPEC:
+ D = LinkageSpecDecl::Create(*Context, 0, SourceLocation(),
+ (LinkageSpecDecl::LanguageIDs)0,
+ false);
+ break;
+ case pch::DECL_NAMESPACE:
+ D = NamespaceDecl::Create(*Context, 0, SourceLocation(), 0);
+ break;
+ case pch::DECL_NAMESPACE_ALIAS:
+ D = NamespaceAliasDecl::Create(*Context, 0, SourceLocation(),
+ SourceLocation(), 0, SourceRange(), 0,
+ SourceLocation(), 0);
+ break;
+ case pch::DECL_USING:
+ D = UsingDecl::Create(*Context, 0, SourceLocation(), SourceRange(),
+ SourceLocation(), 0, DeclarationName(), false);
+ break;
+ case pch::DECL_USING_SHADOW:
+ D = UsingShadowDecl::Create(*Context, 0, SourceLocation(), 0, 0);
+ break;
+ case pch::DECL_USING_DIRECTIVE:
+ D = UsingDirectiveDecl::Create(*Context, 0, SourceLocation(),
+ SourceLocation(), SourceRange(), 0,
+ SourceLocation(), 0, 0);
+ break;
+ case pch::DECL_UNRESOLVED_USING_VALUE:
+ D = UnresolvedUsingValueDecl::Create(*Context, 0, SourceLocation(),
+ SourceRange(), 0, SourceLocation(),
+ DeclarationName());
+ break;
+ case pch::DECL_UNRESOLVED_USING_TYPENAME:
+ D = UnresolvedUsingTypenameDecl::Create(*Context, 0, SourceLocation(),
+ SourceLocation(), SourceRange(),
+ 0, SourceLocation(),
+ DeclarationName());
+ break;
+ case pch::DECL_CXX_RECORD:
+ D = CXXRecordDecl::Create(*Context, TTK_Struct, 0,
+ SourceLocation(), 0, SourceLocation(), 0);
+ break;
+ case pch::DECL_CXX_METHOD:
+ D = CXXMethodDecl::Create(*Context, 0, SourceLocation(), DeclarationName(),
+ QualType(), 0);
+ break;
+ case pch::DECL_CXX_CONSTRUCTOR:
+ D = CXXConstructorDecl::Create(*Context, Decl::EmptyShell());
+ break;
+ case pch::DECL_CXX_DESTRUCTOR:
+ D = CXXDestructorDecl::Create(*Context, Decl::EmptyShell());
+ break;
+ case pch::DECL_CXX_CONVERSION:
+ D = CXXConversionDecl::Create(*Context, Decl::EmptyShell());
+ break;
+ case pch::DECL_FRIEND:
+ assert(false && "cannot read FriendDecl");
+ break;
+ case pch::DECL_FRIEND_TEMPLATE:
+ assert(false && "cannot read FriendTemplateDecl");
+ break;
+ case pch::DECL_TEMPLATE:
+ // FIXME: Should TemplateDecl be ABSTRACT_DECL???
+ assert(false && "TemplateDecl should be abstract!");
+ break;
+ case pch::DECL_CLASS_TEMPLATE:
+ assert(false && "cannot read ClassTemplateDecl");
+ break;
+ case pch::DECL_CLASS_TEMPLATE_SPECIALIZATION:
+ assert(false && "cannot read ClasstemplateSpecializationDecl");
+ break;
+ case pch::DECL_CLASS_TEMPLATE_PARTIAL_SPECIALIZATION:
+ assert(false && "cannot read ClassTemplatePartialSpecializationDecl");
+ break;
+ case pch::DECL_FUNCTION_TEMPLATE:
+ assert(false && "cannot read FunctionTemplateDecl");
+ break;
+ case pch::DECL_TEMPLATE_TYPE_PARM:
+ assert(false && "cannot read TemplateTypeParmDecl");
+ break;
+ case pch::DECL_NON_TYPE_TEMPLATE_PARM:
+ assert(false && "cannot read NonTypeTemplateParmDecl");
+ break;
+ case pch::DECL_TEMPLATE_TEMPLATE_PARM:
+ assert(false && "cannot read TemplateTemplateParmDecl");
+ break;
+ case pch::DECL_STATIC_ASSERT:
+ assert(false && "cannot read StaticAssertDecl");
+ break;
+
case pch::DECL_OBJC_METHOD:
D = ObjCMethodDecl::Create(*Context, SourceLocation(), SourceLocation(),
Selector(), QualType(), 0, 0);
@@ -772,10 +1043,6 @@ Decl *PCHReader::ReadDeclRecord(uint64_t Offset, unsigned Index) {
case pch::DECL_BLOCK:
D = BlockDecl::Create(*Context, 0, SourceLocation());
break;
-
- case pch::DECL_NAMESPACE:
- D = NamespaceDecl::Create(*Context, 0, SourceLocation(), 0);
- break;
}
assert(D && "Unknown declaration reading PCH file");
diff --git a/lib/Frontend/PCHReaderStmt.cpp b/lib/Frontend/PCHReaderStmt.cpp
index ef6b77026d7f..3931adbe8f21 100644
--- a/lib/Frontend/PCHReaderStmt.cpp
+++ b/lib/Frontend/PCHReaderStmt.cpp
@@ -126,6 +126,16 @@ namespace {
unsigned VisitCXXFunctionalCastExpr(CXXFunctionalCastExpr *E);
unsigned VisitCXXBoolLiteralExpr(CXXBoolLiteralExpr *E);
unsigned VisitCXXNullPtrLiteralExpr(CXXNullPtrLiteralExpr *E);
+ unsigned VisitCXXTypeidExpr(CXXTypeidExpr *E);
+ unsigned VisitCXXThisExpr(CXXThisExpr *E);
+ unsigned VisitCXXThrowExpr(CXXThrowExpr *E);
+ unsigned VisitCXXDefaultArgExpr(CXXDefaultArgExpr *E);
+ unsigned VisitCXXBindTemporaryExpr(CXXBindTemporaryExpr *E);
+
+ unsigned VisitCXXZeroInitValueExpr(CXXZeroInitValueExpr *E);
+ unsigned VisitCXXNewExpr(CXXNewExpr *E);
+
+ unsigned VisitCXXExprWithTemporaries(CXXExprWithTemporaries *E);
};
}
@@ -281,6 +291,7 @@ unsigned PCHStmtReader::VisitReturnStmt(ReturnStmt *S) {
VisitStmt(S);
S->setRetValue(cast_or_null<Expr>(StmtStack.back()));
S->setReturnLoc(SourceLocation::getFromRawEncoding(Record[Idx++]));
+ S->setNRVOCandidate(cast_or_null<VarDecl>(Reader.GetDecl(Record[Idx++])));
return 1;
}
@@ -529,7 +540,6 @@ unsigned PCHStmtReader::VisitCastExpr(CastExpr *E) {
VisitExpr(E);
E->setSubExpr(cast<Expr>(StmtStack.back()));
E->setCastKind((CastExpr::CastKind)Record[Idx++]);
-
return 1;
}
@@ -947,6 +957,7 @@ unsigned PCHStmtReader::VisitCXXConstructExpr(CXXConstructExpr *E) {
E->setRequiresZeroInitialization(Record[Idx++]);
for (unsigned I = 0, N = E->getNumArgs(); I != N; ++I)
E->setArg(I, cast<Expr>(StmtStack[StmtStack.size() - N + I]));
+ E->setConstructionKind((CXXConstructExpr::ConstructionKind)Record[Idx++]);
return E->getNumArgs();
}
@@ -992,6 +1003,99 @@ unsigned PCHStmtReader::VisitCXXNullPtrLiteralExpr(CXXNullPtrLiteralExpr *E) {
return 0;
}
+unsigned PCHStmtReader::VisitCXXTypeidExpr(CXXTypeidExpr *E) {
+ VisitExpr(E);
+ E->setSourceRange(Reader.ReadSourceRange(Record, Idx));
+ if (E->isTypeOperand()) { // typeid(int)
+ E->setTypeOperandSourceInfo(Reader.GetTypeSourceInfo(Record, Idx));
+ return 0;
+ }
+
+ // typeid(42+2)
+ E->setExprOperand(cast<Expr>(StmtStack.back()));
+ return 1;
+}
+
+unsigned PCHStmtReader::VisitCXXThisExpr(CXXThisExpr *E) {
+ VisitExpr(E);
+ E->setLocation(SourceLocation::getFromRawEncoding(Record[Idx++]));
+ E->setImplicit(Record[Idx++]);
+ return 0;
+}
+
+unsigned PCHStmtReader::VisitCXXThrowExpr(CXXThrowExpr *E) {
+ VisitExpr(E);
+ E->setThrowLoc(SourceLocation::getFromRawEncoding(Record[Idx++]));
+ E->setSubExpr(cast<Expr>(StmtStack.back()));
+ return 1;
+}
+
+unsigned PCHStmtReader::VisitCXXDefaultArgExpr(CXXDefaultArgExpr *E) {
+ VisitExpr(E);
+ E->setUsedLocation(SourceLocation::getFromRawEncoding(Record[Idx++]));
+ bool HasStoredExpr = Record[Idx++];
+ if (!HasStoredExpr) return 0;
+ E->setExpr(cast<Expr>(StmtStack.back()));
+ return 1;
+}
+
+unsigned PCHStmtReader::VisitCXXBindTemporaryExpr(CXXBindTemporaryExpr *E) {
+ VisitExpr(E);
+ E->setTemporary(Reader.ReadCXXTemporary(Record, Idx));
+ E->setSubExpr(cast<Expr>(StmtStack.back()));
+ return 1;
+}
+
+unsigned PCHStmtReader::VisitCXXZeroInitValueExpr(CXXZeroInitValueExpr *E) {
+ VisitExpr(E);
+ E->setTypeBeginLoc(SourceLocation::getFromRawEncoding(Record[Idx++]));
+ E->setRParenLoc(SourceLocation::getFromRawEncoding(Record[Idx++]));
+ return 0;
+}
+
+unsigned PCHStmtReader::VisitCXXNewExpr(CXXNewExpr *E) {
+ VisitExpr(E);
+ E->setGlobalNew(Record[Idx++]);
+ E->setParenTypeId(Record[Idx++]);
+ E->setHasInitializer(Record[Idx++]);
+ bool isArray = Record[Idx++];
+ unsigned NumPlacementArgs = Record[Idx++];
+ unsigned NumCtorArgs = Record[Idx++];
+ E->setOperatorNew(cast_or_null<FunctionDecl>(Reader.GetDecl(Record[Idx++])));
+ E->setOperatorDelete(
+ cast_or_null<FunctionDecl>(Reader.GetDecl(Record[Idx++])));
+ E->setConstructor(
+ cast_or_null<CXXConstructorDecl>(Reader.GetDecl(Record[Idx++])));
+ E->setStartLoc(SourceLocation::getFromRawEncoding(Record[Idx++]));
+ E->setEndLoc(SourceLocation::getFromRawEncoding(Record[Idx++]));
+
+ E->AllocateArgsArray(*Reader.getContext(), isArray, NumPlacementArgs,
+ NumCtorArgs);
+
+ // Install all the subexpressions.
+ unsigned TotalSubExprs = E->raw_arg_end()-E->raw_arg_begin();
+ unsigned SSIdx = StmtStack.size()-TotalSubExprs;
+ for (CXXNewExpr::raw_arg_iterator I = E->raw_arg_begin(),e = E->raw_arg_end();
+ I != e; ++I)
+ *I = StmtStack[SSIdx++];
+
+ return TotalSubExprs;
+}
+
+
+unsigned PCHStmtReader::VisitCXXExprWithTemporaries(CXXExprWithTemporaries *E) {
+ VisitExpr(E);
+ unsigned NumTemps = Record[Idx++];
+ if (NumTemps) {
+ E->setNumTemporaries(*Reader.getContext(), NumTemps);
+ for (unsigned i = 0; i != NumTemps; ++i)
+ E->setTemporary(i, Reader.ReadCXXTemporary(Record, Idx));
+ }
+ E->setSubExpr(cast<Expr>(StmtStack.back()));
+ return 1;
+}
+
+
// Within the bitstream, expressions are stored in Reverse Polish
// Notation, with each of the subexpressions preceding the
// expression they are stored in. To evaluate expressions, we
@@ -1304,6 +1408,10 @@ Stmt *PCHReader::ReadStmt(llvm::BitstreamCursor &Cursor) {
case pch::EXPR_CXX_OPERATOR_CALL:
S = new (Context) CXXOperatorCallExpr(*Context, Empty);
break;
+
+ case pch::EXPR_CXX_MEMBER_CALL:
+ S = new (Context) CXXMemberCallExpr(*Context, Empty);
+ break;
case pch::EXPR_CXX_CONSTRUCT:
S = new (Context) CXXConstructExpr(Empty, *Context,
@@ -1337,6 +1445,36 @@ Stmt *PCHReader::ReadStmt(llvm::BitstreamCursor &Cursor) {
case pch::EXPR_CXX_NULL_PTR_LITERAL:
S = new (Context) CXXNullPtrLiteralExpr(Empty);
break;
+ case pch::EXPR_CXX_TYPEID_EXPR:
+ S = new (Context) CXXTypeidExpr(Empty, true);
+ break;
+ case pch::EXPR_CXX_TYPEID_TYPE:
+ S = new (Context) CXXTypeidExpr(Empty, false);
+ break;
+ case pch::EXPR_CXX_THIS:
+ S = new (Context) CXXThisExpr(Empty);
+ break;
+ case pch::EXPR_CXX_THROW:
+ S = new (Context) CXXThrowExpr(Empty);
+ break;
+ case pch::EXPR_CXX_DEFAULT_ARG:
+ S = new (Context) CXXDefaultArgExpr(Empty);
+ break;
+ case pch::EXPR_CXX_BIND_TEMPORARY:
+ S = new (Context) CXXBindTemporaryExpr(Empty);
+ break;
+
+ case pch::EXPR_CXX_ZERO_INIT_VALUE:
+ S = new (Context) CXXZeroInitValueExpr(Empty);
+ break;
+ case pch::EXPR_CXX_NEW:
+ S = new (Context) CXXNewExpr(Empty);
+ break;
+
+
+ case pch::EXPR_CXX_EXPR_WITH_TEMPORARIES:
+ S = new (Context) CXXExprWithTemporaries(Empty);
+ break;
}
// We hit a STMT_STOP, so we're done with this expression.
diff --git a/lib/Frontend/PCHWriter.cpp b/lib/Frontend/PCHWriter.cpp
index e56dd3132224..3d5b7d8156a8 100644
--- a/lib/Frontend/PCHWriter.cpp
+++ b/lib/Frontend/PCHWriter.cpp
@@ -213,12 +213,6 @@ void PCHTypeWriter::VisitEnumType(const EnumType *T) {
Code = pch::TYPE_ENUM;
}
-void PCHTypeWriter::VisitElaboratedType(const ElaboratedType *T) {
- Writer.AddTypeRef(T->getUnderlyingType(), Record);
- Record.push_back(T->getTagKind());
- Code = pch::TYPE_ELABORATED;
-}
-
void
PCHTypeWriter::VisitSubstTemplateTypeParmType(
const SubstTemplateTypeParmType *T) {
@@ -234,9 +228,12 @@ PCHTypeWriter::VisitTemplateSpecializationType(
assert(false && "Cannot serialize template specialization types");
}
-void PCHTypeWriter::VisitQualifiedNameType(const QualifiedNameType *T) {
- // FIXME: Serialize this type (C++ only)
- assert(false && "Cannot serialize qualified name types");
+void PCHTypeWriter::VisitElaboratedType(const ElaboratedType *T) {
+ Writer.AddTypeRef(T->getNamedType(), Record);
+ Record.push_back(T->getKeyword());
+ // FIXME: Serialize the qualifier (C++ only)
+ assert(T->getQualifier() == 0 && "Cannot serialize qualified name types");
+ Code = pch::TYPE_ELABORATED;
}
void PCHTypeWriter::VisitInjectedClassNameType(const InjectedClassNameType *T) {
@@ -247,20 +244,21 @@ void PCHTypeWriter::VisitInjectedClassNameType(const InjectedClassNameType *T) {
void PCHTypeWriter::VisitObjCInterfaceType(const ObjCInterfaceType *T) {
Writer.AddDeclRef(T->getDecl(), Record);
+ Code = pch::TYPE_OBJC_INTERFACE;
+}
+
+void PCHTypeWriter::VisitObjCObjectType(const ObjCObjectType *T) {
+ Writer.AddTypeRef(T->getBaseType(), Record);
Record.push_back(T->getNumProtocols());
- for (ObjCInterfaceType::qual_iterator I = T->qual_begin(),
+ for (ObjCObjectType::qual_iterator I = T->qual_begin(),
E = T->qual_end(); I != E; ++I)
Writer.AddDeclRef(*I, Record);
- Code = pch::TYPE_OBJC_INTERFACE;
+ Code = pch::TYPE_OBJC_OBJECT;
}
void
PCHTypeWriter::VisitObjCObjectPointerType(const ObjCObjectPointerType *T) {
Writer.AddTypeRef(T->getPointeeType(), Record);
- Record.push_back(T->getNumProtocols());
- for (ObjCInterfaceType::qual_iterator I = T->qual_begin(),
- E = T->qual_end(); I != E; ++I)
- Writer.AddDeclRef(*I, Record);
Code = pch::TYPE_OBJC_OBJECT_POINTER;
}
@@ -383,9 +381,6 @@ void TypeLocWriter::VisitRecordTypeLoc(RecordTypeLoc TL) {
void TypeLocWriter::VisitEnumTypeLoc(EnumTypeLoc TL) {
Writer.AddSourceLocation(TL.getNameLoc(), Record);
}
-void TypeLocWriter::VisitElaboratedTypeLoc(ElaboratedTypeLoc TL) {
- Writer.AddSourceLocation(TL.getNameLoc(), Record);
-}
void TypeLocWriter::VisitTemplateTypeParmTypeLoc(TemplateTypeParmTypeLoc TL) {
Writer.AddSourceLocation(TL.getNameLoc(), Record);
}
@@ -401,17 +396,23 @@ void TypeLocWriter::VisitTemplateSpecializationTypeLoc(
for (unsigned i = 0, e = TL.getNumArgs(); i != e; ++i)
Writer.AddTemplateArgumentLoc(TL.getArgLoc(i), Record);
}
-void TypeLocWriter::VisitQualifiedNameTypeLoc(QualifiedNameTypeLoc TL) {
- Writer.AddSourceLocation(TL.getNameLoc(), Record);
+void TypeLocWriter::VisitElaboratedTypeLoc(ElaboratedTypeLoc TL) {
+ Writer.AddSourceLocation(TL.getKeywordLoc(), Record);
+ Writer.AddSourceRange(TL.getQualifierRange(), Record);
}
void TypeLocWriter::VisitInjectedClassNameTypeLoc(InjectedClassNameTypeLoc TL) {
Writer.AddSourceLocation(TL.getNameLoc(), Record);
}
void TypeLocWriter::VisitDependentNameTypeLoc(DependentNameTypeLoc TL) {
+ Writer.AddSourceLocation(TL.getKeywordLoc(), Record);
+ Writer.AddSourceRange(TL.getQualifierRange(), Record);
Writer.AddSourceLocation(TL.getNameLoc(), Record);
}
void TypeLocWriter::VisitObjCInterfaceTypeLoc(ObjCInterfaceTypeLoc TL) {
Writer.AddSourceLocation(TL.getNameLoc(), Record);
+}
+void TypeLocWriter::VisitObjCObjectTypeLoc(ObjCObjectTypeLoc TL) {
+ Record.push_back(TL.hasBaseTypeAsWritten());
Writer.AddSourceLocation(TL.getLAngleLoc(), Record);
Writer.AddSourceLocation(TL.getRAngleLoc(), Record);
for (unsigned i = 0, e = TL.getNumProtocols(); i != e; ++i)
@@ -419,13 +420,6 @@ void TypeLocWriter::VisitObjCInterfaceTypeLoc(ObjCInterfaceTypeLoc TL) {
}
void TypeLocWriter::VisitObjCObjectPointerTypeLoc(ObjCObjectPointerTypeLoc TL) {
Writer.AddSourceLocation(TL.getStarLoc(), Record);
- Writer.AddSourceLocation(TL.getLAngleLoc(), Record);
- Writer.AddSourceLocation(TL.getRAngleLoc(), Record);
- Record.push_back(TL.hasBaseTypeAsWritten());
- Record.push_back(TL.hasProtocolsAsWritten());
- if (TL.hasProtocolsAsWritten())
- for (unsigned i = 0, e = TL.getNumProtocols(); i != e; ++i)
- Writer.AddSourceLocation(TL.getProtocolLoc(i), Record);
}
//===----------------------------------------------------------------------===//
@@ -609,6 +603,7 @@ void PCHWriter::WriteBlockInfoBlock() {
RECORD(TYPE_RECORD);
RECORD(TYPE_ENUM);
RECORD(TYPE_OBJC_INTERFACE);
+ RECORD(TYPE_OBJC_OBJECT);
RECORD(TYPE_OBJC_OBJECT_POINTER);
RECORD(DECL_ATTR);
RECORD(DECL_TRANSLATION_UNIT);
@@ -1841,6 +1836,9 @@ void PCHWriter::WriteAttributeRecord(const Attr *Attr) {
AddString(cast<AliasAttr>(Attr)->getAliasee(), Record);
break;
+ case Attr::AlignMac68k:
+ break;
+
case Attr::Aligned:
Record.push_back(cast<AlignedAttr>(Attr)->getAlignment());
break;
@@ -1925,6 +1923,12 @@ void PCHWriter::WriteAttributeRecord(const Attr *Attr) {
case Attr::NoThrow:
break;
+ case Attr::IBOutletCollectionKind: {
+ const IBOutletCollectionAttr *ICA = cast<IBOutletCollectionAttr>(Attr);
+ AddDeclRef(ICA->getClass(), Record);
+ break;
+ }
+
case Attr::NonNull: {
const NonNullAttr *NonNull = cast<NonNullAttr>(Attr);
Record.push_back(NonNull->size());
@@ -1942,8 +1946,8 @@ void PCHWriter::WriteAttributeRecord(const Attr *Attr) {
case Attr::Override:
break;
- case Attr::PragmaPack:
- Record.push_back(cast<PragmaPackAttr>(Attr)->getAlignment());
+ case Attr::MaxFieldAlignment:
+ Record.push_back(cast<MaxFieldAlignmentAttr>(Attr)->getAlignment());
break;
case Attr::Packed:
@@ -2181,6 +2185,11 @@ void PCHWriter::AddSourceLocation(SourceLocation Loc, RecordData &Record) {
Record.push_back(Loc.getRawEncoding());
}
+void PCHWriter::AddSourceRange(SourceRange Range, RecordData &Record) {
+ AddSourceLocation(Range.getBegin(), Record);
+ AddSourceLocation(Range.getEnd(), Record);
+}
+
void PCHWriter::AddAPInt(const llvm::APInt &Value, RecordData &Record) {
Record.push_back(Value.getBitWidth());
unsigned N = Value.getNumWords();
@@ -2236,6 +2245,10 @@ void PCHWriter::AddSelectorRef(const Selector SelRef, RecordData &Record) {
Record.push_back(SID);
}
+void PCHWriter::AddCXXTemporary(const CXXTemporary *Temp, RecordData &Record) {
+ AddDeclRef(Temp->getDestructor(), Record);
+}
+
void PCHWriter::AddTemplateArgumentLoc(const TemplateArgumentLoc &Arg,
RecordData &Record) {
switch (Arg.getArgument().getKind()) {
@@ -2407,3 +2420,42 @@ void PCHWriter::AddDeclarationName(DeclarationName Name, RecordData &Record) {
break;
}
}
+
+void PCHWriter::AddNestedNameSpecifier(NestedNameSpecifier *NNS,
+ RecordData &Record) {
+ // Nested name specifiers usually aren't too long. I think that 8 would
+ // typically accomodate the vast majority.
+ llvm::SmallVector<NestedNameSpecifier *, 8> NestedNames;
+
+ // Push each of the NNS's onto a stack for serialization in reverse order.
+ while (NNS) {
+ NestedNames.push_back(NNS);
+ NNS = NNS->getPrefix();
+ }
+
+ Record.push_back(NestedNames.size());
+ while(!NestedNames.empty()) {
+ NNS = NestedNames.pop_back_val();
+ NestedNameSpecifier::SpecifierKind Kind = NNS->getKind();
+ Record.push_back(Kind);
+ switch (Kind) {
+ case NestedNameSpecifier::Identifier:
+ AddIdentifierRef(NNS->getAsIdentifier(), Record);
+ break;
+
+ case NestedNameSpecifier::Namespace:
+ AddDeclRef(NNS->getAsNamespace(), Record);
+ break;
+
+ case NestedNameSpecifier::TypeSpec:
+ case NestedNameSpecifier::TypeSpecWithTemplate:
+ AddTypeRef(QualType(NNS->getAsType(), 0), Record);
+ Record.push_back(Kind == NestedNameSpecifier::TypeSpecWithTemplate);
+ break;
+
+ case NestedNameSpecifier::Global:
+ // Don't need to write an associated value.
+ break;
+ }
+ }
+}
diff --git a/lib/Frontend/PCHWriterDecl.cpp b/lib/Frontend/PCHWriterDecl.cpp
index 7b7806239604..cc58e8ee4654 100644
--- a/lib/Frontend/PCHWriterDecl.cpp
+++ b/lib/Frontend/PCHWriterDecl.cpp
@@ -13,6 +13,8 @@
#include "clang/Frontend/PCHWriter.h"
#include "clang/AST/DeclVisitor.h"
+#include "clang/AST/DeclCXX.h"
+#include "clang/AST/DeclTemplate.h"
#include "clang/AST/Expr.h"
#include "llvm/ADT/Twine.h"
#include "llvm/Bitcode/BitstreamWriter.h"
@@ -43,23 +45,51 @@ namespace {
void VisitTranslationUnitDecl(TranslationUnitDecl *D);
void VisitNamedDecl(NamedDecl *D);
void VisitNamespaceDecl(NamespaceDecl *D);
+ void VisitUsingDirectiveDecl(UsingDirectiveDecl *D);
+ void VisitNamespaceAliasDecl(NamespaceAliasDecl *D);
void VisitTypeDecl(TypeDecl *D);
void VisitTypedefDecl(TypedefDecl *D);
+ void VisitUnresolvedUsingTypename(UnresolvedUsingTypenameDecl *D);
void VisitTagDecl(TagDecl *D);
void VisitEnumDecl(EnumDecl *D);
void VisitRecordDecl(RecordDecl *D);
+ void VisitCXXRecordDecl(CXXRecordDecl *D);
+ void VisitClassTemplateSpecializationDecl(
+ ClassTemplateSpecializationDecl *D);
+ void VisitClassTemplatePartialSpecializationDecl(
+ ClassTemplatePartialSpecializationDecl *D);
+ void VisitTemplateTypeParmDecl(TemplateTypeParmDecl *D);
void VisitValueDecl(ValueDecl *D);
void VisitEnumConstantDecl(EnumConstantDecl *D);
+ void VisitUnresolvedUsingValue(UnresolvedUsingValueDecl *D);
void VisitDeclaratorDecl(DeclaratorDecl *D);
void VisitFunctionDecl(FunctionDecl *D);
+ void VisitCXXMethodDecl(CXXMethodDecl *D);
+ void VisitCXXConstructorDecl(CXXConstructorDecl *D);
+ void VisitCXXDestructorDecl(CXXDestructorDecl *D);
+ void VisitCXXConversionDecl(CXXConversionDecl *D);
void VisitFieldDecl(FieldDecl *D);
void VisitVarDecl(VarDecl *D);
void VisitImplicitParamDecl(ImplicitParamDecl *D);
void VisitParmVarDecl(ParmVarDecl *D);
+ void VisitNonTypeTemplateParmDecl(NonTypeTemplateParmDecl *D);
+ void VisitTemplateDecl(TemplateDecl *D);
+ void VisitClassTemplateDecl(ClassTemplateDecl *D);
+ void visitFunctionTemplateDecl(FunctionTemplateDecl *D);
+ void VisitTemplateTemplateParmDecl(TemplateTemplateParmDecl *D);
+ void VisitUsing(UsingDecl *D);
+ void VisitUsingShadow(UsingShadowDecl *D);
+ void VisitLinkageSpecDecl(LinkageSpecDecl *D);
void VisitFileScopeAsmDecl(FileScopeAsmDecl *D);
+ void VisitFriendTemplateDecl(FriendTemplateDecl *D);
+ void VisitStaticAssertDecl(StaticAssertDecl *D);
void VisitBlockDecl(BlockDecl *D);
+
void VisitDeclContext(DeclContext *DC, uint64_t LexicalOffset,
uint64_t VisibleOffset);
+
+
+ // FIXME: Put in the same order is DeclNodes.def?
void VisitObjCMethodDecl(ObjCMethodDecl *D);
void VisitObjCContainerDecl(ObjCContainerDecl *D);
void VisitObjCInterfaceDecl(ObjCInterfaceDecl *D);
@@ -92,6 +122,7 @@ void PCHDeclWriter::VisitDecl(Decl *D) {
void PCHDeclWriter::VisitTranslationUnitDecl(TranslationUnitDecl *D) {
VisitDecl(D);
+ Writer.AddDeclRef(D->getAnonymousNamespace(), Record);
Code = pch::DECL_TRANSLATION_UNIT;
}
@@ -100,16 +131,6 @@ void PCHDeclWriter::VisitNamedDecl(NamedDecl *D) {
Writer.AddDeclarationName(D->getDeclName(), Record);
}
-void PCHDeclWriter::VisitNamespaceDecl(NamespaceDecl *D) {
- VisitNamedDecl(D);
- Writer.AddSourceLocation(D->getLBracLoc(), Record);
- Writer.AddSourceLocation(D->getRBracLoc(), Record);
- Writer.AddDeclRef(D->getNextNamespace(), Record);
- Writer.AddDeclRef(D->getOriginalNamespace(), Record);
- Writer.AddDeclRef(D->getAnonymousNamespace(), Record);
- Code = pch::DECL_NAMESPACE;
-}
-
void PCHDeclWriter::VisitTypeDecl(TypeDecl *D) {
VisitNamedDecl(D);
Writer.AddTypeRef(QualType(D->getTypeForDecl(), 0), Record);
@@ -137,6 +158,8 @@ void PCHDeclWriter::VisitEnumDecl(EnumDecl *D) {
VisitTagDecl(D);
Writer.AddTypeRef(D->getIntegerType(), Record);
Writer.AddTypeRef(D->getPromotionType(), Record);
+ Record.push_back(D->getNumPositiveBits());
+ Record.push_back(D->getNumNegativeBits());
// FIXME: C++ InstantiatedFrom
Code = pch::DECL_ENUM;
}
@@ -171,9 +194,11 @@ void PCHDeclWriter::VisitDeclaratorDecl(DeclaratorDecl *D) {
void PCHDeclWriter::VisitFunctionDecl(FunctionDecl *D) {
VisitDeclaratorDecl(D);
+
Record.push_back(D->isThisDeclarationADefinition());
if (D->isThisDeclarationADefinition())
Writer.AddStmt(D->getBody());
+
Writer.AddDeclRef(D->getPreviousDeclaration(), Record);
Record.push_back(D->getStorageClass()); // FIXME: stable encoding
Record.push_back(D->getStorageClassAsWritten());
@@ -186,8 +211,9 @@ void PCHDeclWriter::VisitFunctionDecl(FunctionDecl *D) {
Record.push_back(D->isTrivial());
Record.push_back(D->isCopyAssignment());
Record.push_back(D->hasImplicitReturnZero());
+ // FIXME: C++ TemplateOrInstantiation???
Writer.AddSourceLocation(D->getLocEnd(), Record);
- // FIXME: C++ TemplateOrInstantiation
+
Record.push_back(D->param_size());
for (FunctionDecl::param_iterator P = D->param_begin(), PEnd = D->param_end();
P != PEnd; ++P)
@@ -225,9 +251,7 @@ void PCHDeclWriter::VisitObjCMethodDecl(ObjCMethodDecl *D) {
void PCHDeclWriter::VisitObjCContainerDecl(ObjCContainerDecl *D) {
VisitNamedDecl(D);
- SourceRange R = D->getAtEndRange();
- Writer.AddSourceLocation(R.getBegin(), Record);
- Writer.AddSourceLocation(R.getEnd(), Record);
+ Writer.AddSourceRange(D->getAtEndRange(), Record);
// Abstract class (no need to define a stable pch::DECL code).
}
@@ -370,6 +394,7 @@ void PCHDeclWriter::VisitObjCPropertyImplDecl(ObjCPropertyImplDecl *D) {
Writer.AddSourceLocation(D->getLocStart(), Record);
Writer.AddDeclRef(D->getPropertyDecl(), Record);
Writer.AddDeclRef(D->getPropertyIvarDecl(), Record);
+ // FIXME. write GetterCXXConstructor and SetterCXXAssignment.
Code = pch::DECL_OBJC_PROPERTY_IMPL;
}
@@ -390,8 +415,9 @@ void PCHDeclWriter::VisitVarDecl(VarDecl *D) {
Record.push_back(D->hasCXXDirectInitializer());
Record.push_back(D->isDeclaredInCondition());
Record.push_back(D->isExceptionVariable());
+ Record.push_back(D->isNRVOVariable());
Writer.AddDeclRef(D->getPreviousDeclaration(), Record);
- Record.push_back(D->getInit()? 1 : 0);
+ Record.push_back(D->getInit() ? 1 : 0);
if (D->getInit())
Writer.AddStmt(D->getInit());
Code = pch::DECL_VAR;
@@ -408,7 +434,6 @@ void PCHDeclWriter::VisitParmVarDecl(ParmVarDecl *D) {
Record.push_back(D->hasInheritedDefaultArg());
Code = pch::DECL_PARM_VAR;
-
// If the assumptions about the DECL_PARM_VAR abbrev are true, use it. Here
// we dynamically check for the properties that we optimize for, but don't
// know are true of all PARM_VAR_DECLs.
@@ -421,7 +446,8 @@ void PCHDeclWriter::VisitParmVarDecl(ParmVarDecl *D) {
D->getStorageClass() == 0 &&
!D->hasCXXDirectInitializer() && // Can params have this ever?
D->getObjCDeclQualifier() == 0 &&
- !D->hasInheritedDefaultArg())
+ !D->hasInheritedDefaultArg() &&
+ D->getInit() == 0) // No default expr.
AbbrevToUse = Writer.getParmVarDeclAbbrev();
// Check things we know are true of *every* PARM_VAR_DECL, which is more than
@@ -432,7 +458,6 @@ void PCHDeclWriter::VisitParmVarDecl(ParmVarDecl *D) {
assert(!D->isDeclaredInCondition() && "PARM_VAR_DECL can't be in condition");
assert(!D->isExceptionVariable() && "PARM_VAR_DECL can't be exception var");
assert(D->getPreviousDeclaration() == 0 && "PARM_VAR_DECL can't be redecl");
- assert(D->getInit() == 0 && "PARM_VAR_DECL never has init");
}
void PCHDeclWriter::VisitFileScopeAsmDecl(FileScopeAsmDecl *D) {
@@ -451,6 +476,161 @@ void PCHDeclWriter::VisitBlockDecl(BlockDecl *D) {
Code = pch::DECL_BLOCK;
}
+void PCHDeclWriter::VisitLinkageSpecDecl(LinkageSpecDecl *D) {
+ VisitDecl(D);
+ // FIXME: It might be nice to serialize the brace locations for this
+ // declaration, which don't seem to be readily available in the AST.
+ Record.push_back(D->getLanguage());
+ Record.push_back(D->hasBraces());
+ Code = pch::DECL_LINKAGE_SPEC;
+}
+
+void PCHDeclWriter::VisitNamespaceDecl(NamespaceDecl *D) {
+ VisitNamedDecl(D);
+ Writer.AddSourceLocation(D->getLBracLoc(), Record);
+ Writer.AddSourceLocation(D->getRBracLoc(), Record);
+ Writer.AddDeclRef(D->getNextNamespace(), Record);
+
+ // Only write one reference--original or anonymous
+ Record.push_back(D->isOriginalNamespace());
+ if (D->isOriginalNamespace())
+ Writer.AddDeclRef(D->getAnonymousNamespace(), Record);
+ else
+ Writer.AddDeclRef(D->getOriginalNamespace(), Record);
+ Code = pch::DECL_NAMESPACE;
+}
+
+void PCHDeclWriter::VisitNamespaceAliasDecl(NamespaceAliasDecl *D) {
+ VisitNamedDecl(D);
+ Writer.AddSourceLocation(D->getAliasLoc(), Record);
+ Writer.AddSourceRange(D->getQualifierRange(), Record);
+ Writer.AddNestedNameSpecifier(D->getQualifier(), Record);
+ Writer.AddSourceLocation(D->getTargetNameLoc(), Record);
+ Writer.AddDeclRef(D->getNamespace(), Record);
+ Code = pch::DECL_NAMESPACE_ALIAS;
+}
+
+void PCHDeclWriter::VisitUsing(UsingDecl *D) {
+ VisitNamedDecl(D);
+ Writer.AddSourceRange(D->getNestedNameRange(), Record);
+ Writer.AddSourceLocation(D->getUsingLocation(), Record);
+ Writer.AddNestedNameSpecifier(D->getTargetNestedNameDecl(), Record);
+ Record.push_back(D->getNumShadowDecls());
+ for (UsingDecl::shadow_iterator P = D->shadow_begin(),
+ PEnd = D->shadow_end(); P != PEnd; ++P)
+ Writer.AddDeclRef(*P, Record);
+ Record.push_back(D->isTypeName());
+ Code = pch::DECL_USING;
+}
+
+void PCHDeclWriter::VisitUsingShadow(UsingShadowDecl *D) {
+ VisitNamedDecl(D);
+ Writer.AddDeclRef(D->getTargetDecl(), Record);
+ Writer.AddDeclRef(D->getUsingDecl(), Record);
+ Code = pch::DECL_USING_SHADOW;
+}
+
+void PCHDeclWriter::VisitUsingDirectiveDecl(UsingDirectiveDecl *D) {
+ VisitNamedDecl(D);
+ Writer.AddSourceLocation(D->getNamespaceKeyLocation(), Record);
+ Writer.AddSourceRange(D->getQualifierRange(), Record);
+ Writer.AddNestedNameSpecifier(D->getQualifier(), Record);
+ Writer.AddSourceLocation(D->getIdentLocation(), Record);
+ Writer.AddDeclRef(D->getNominatedNamespace(), Record);
+ Writer.AddDeclRef(dyn_cast<Decl>(D->getCommonAncestor()), Record);
+ Code = pch::DECL_USING_DIRECTIVE;
+}
+
+void PCHDeclWriter::VisitUnresolvedUsingValue(UnresolvedUsingValueDecl *D) {
+ VisitValueDecl(D);
+ Writer.AddSourceRange(D->getTargetNestedNameRange(), Record);
+ Writer.AddSourceLocation(D->getUsingLoc(), Record);
+ Writer.AddNestedNameSpecifier(D->getTargetNestedNameSpecifier(), Record);
+ Code = pch::DECL_UNRESOLVED_USING_VALUE;
+}
+
+void PCHDeclWriter::VisitUnresolvedUsingTypename(
+ UnresolvedUsingTypenameDecl *D) {
+ VisitTypeDecl(D);
+ Writer.AddSourceRange(D->getTargetNestedNameRange(), Record);
+ Writer.AddSourceLocation(D->getUsingLoc(), Record);
+ Writer.AddSourceLocation(D->getTypenameLoc(), Record);
+ Writer.AddNestedNameSpecifier(D->getTargetNestedNameSpecifier(), Record);
+ Code = pch::DECL_UNRESOLVED_USING_TYPENAME;
+}
+
+void PCHDeclWriter::VisitCXXRecordDecl(CXXRecordDecl *D) {
+ // assert(false && "cannot write CXXRecordDecl");
+ VisitRecordDecl(D);
+ Code = pch::DECL_CXX_RECORD;
+}
+
+void PCHDeclWriter::VisitCXXMethodDecl(CXXMethodDecl *D) {
+ // assert(false && "cannot write CXXMethodDecl");
+ VisitFunctionDecl(D);
+ Code = pch::DECL_CXX_METHOD;
+}
+
+void PCHDeclWriter::VisitCXXConstructorDecl(CXXConstructorDecl *D) {
+ // assert(false && "cannot write CXXConstructorDecl");
+ VisitCXXMethodDecl(D);
+ Code = pch::DECL_CXX_CONSTRUCTOR;
+}
+
+void PCHDeclWriter::VisitCXXDestructorDecl(CXXDestructorDecl *D) {
+ // assert(false && "cannot write CXXDestructorDecl");
+ VisitCXXMethodDecl(D);
+ Code = pch::DECL_CXX_DESTRUCTOR;
+}
+
+void PCHDeclWriter::VisitCXXConversionDecl(CXXConversionDecl *D) {
+ // assert(false && "cannot write CXXConversionDecl");
+ VisitCXXMethodDecl(D);
+ Code = pch::DECL_CXX_CONVERSION;
+}
+
+void PCHDeclWriter::VisitFriendTemplateDecl(FriendTemplateDecl *D) {
+ assert(false && "cannot write FriendTemplateDecl");
+}
+
+void PCHDeclWriter::VisitTemplateDecl(TemplateDecl *D) {
+ assert(false && "cannot write TemplateDecl");
+}
+
+void PCHDeclWriter::VisitClassTemplateDecl(ClassTemplateDecl *D) {
+ assert(false && "cannot write ClassTemplateDecl");
+}
+
+void PCHDeclWriter::VisitClassTemplateSpecializationDecl(
+ ClassTemplateSpecializationDecl *D) {
+ assert(false && "cannot write ClassTemplateSpecializationDecl");
+}
+
+void PCHDeclWriter::VisitClassTemplatePartialSpecializationDecl(
+ ClassTemplatePartialSpecializationDecl *D) {
+ assert(false && "cannot write ClassTemplatePartialSpecializationDecl");
+}
+
+void PCHDeclWriter::visitFunctionTemplateDecl(FunctionTemplateDecl *D) {
+ assert(false && "cannot write FunctionTemplateDecl");
+}
+
+void PCHDeclWriter::VisitTemplateTypeParmDecl(TemplateTypeParmDecl *D) {
+ assert(false && "cannot write TemplateTypeParmDecl");
+}
+
+void PCHDeclWriter::VisitNonTypeTemplateParmDecl(NonTypeTemplateParmDecl *D) {
+ assert(false && "cannot write NonTypeTemplateParmDecl");
+}
+
+void PCHDeclWriter::VisitTemplateTemplateParmDecl(TemplateTemplateParmDecl *D) {
+ assert(false && "cannot write TemplateTemplateParmDecl");
+}
+
+void PCHDeclWriter::VisitStaticAssertDecl(StaticAssertDecl *D) {
+ assert(false && "cannot write StaticAssertDecl");
+}
+
/// \brief Emit the DeclContext part of a declaration context decl.
///
/// \param LexicalOffset the offset at which the DECL_CONTEXT_LEXICAL
@@ -504,6 +684,7 @@ void PCHWriter::WriteDeclsBlockAbbrevs() {
Abv->Add(BitCodeAbbrevOp(0)); // hasCXXDirectInitializer
Abv->Add(BitCodeAbbrevOp(0)); // isDeclaredInCondition
Abv->Add(BitCodeAbbrevOp(0)); // isExceptionVariable
+ Abv->Add(BitCodeAbbrevOp(0)); // isNRVOVariable
Abv->Add(BitCodeAbbrevOp(0)); // PrevDecl
Abv->Add(BitCodeAbbrevOp(0)); // HasInit
// ParmVarDecl
diff --git a/lib/Frontend/PCHWriterStmt.cpp b/lib/Frontend/PCHWriterStmt.cpp
index a1993d37f2dc..a9ee43527cec 100644
--- a/lib/Frontend/PCHWriterStmt.cpp
+++ b/lib/Frontend/PCHWriterStmt.cpp
@@ -112,6 +112,7 @@ namespace {
// C++ Statements
void VisitCXXOperatorCallExpr(CXXOperatorCallExpr *E);
+ void VisitCXXMemberCallExpr(CXXMemberCallExpr *E);
void VisitCXXConstructExpr(CXXConstructExpr *E);
void VisitCXXNamedCastExpr(CXXNamedCastExpr *E);
void VisitCXXStaticCastExpr(CXXStaticCastExpr *E);
@@ -121,6 +122,16 @@ namespace {
void VisitCXXFunctionalCastExpr(CXXFunctionalCastExpr *E);
void VisitCXXBoolLiteralExpr(CXXBoolLiteralExpr *E);
void VisitCXXNullPtrLiteralExpr(CXXNullPtrLiteralExpr *E);
+ void VisitCXXTypeidExpr(CXXTypeidExpr *E);
+ void VisitCXXThisExpr(CXXThisExpr *E);
+ void VisitCXXThrowExpr(CXXThrowExpr *E);
+ void VisitCXXDefaultArgExpr(CXXDefaultArgExpr *E);
+ void VisitCXXBindTemporaryExpr(CXXBindTemporaryExpr *E);
+
+ void VisitCXXZeroInitValueExpr(CXXZeroInitValueExpr *E);
+ void VisitCXXNewExpr(CXXNewExpr *E);
+
+ void VisitCXXExprWithTemporaries(CXXExprWithTemporaries *E);
};
}
@@ -264,6 +275,7 @@ void PCHStmtWriter::VisitReturnStmt(ReturnStmt *S) {
VisitStmt(S);
Writer.WriteSubStmt(S->getRetValue());
Writer.AddSourceLocation(S->getReturnLoc(), Record);
+ Writer.AddDeclRef(S->getNRVOCandidate(), Record);
Code = pch::STMT_RETURN;
}
@@ -848,6 +860,11 @@ void PCHStmtWriter::VisitCXXOperatorCallExpr(CXXOperatorCallExpr *E) {
Code = pch::EXPR_CXX_OPERATOR_CALL;
}
+void PCHStmtWriter::VisitCXXMemberCallExpr(CXXMemberCallExpr *E) {
+ VisitCallExpr(E);
+ Code = pch::EXPR_CXX_MEMBER_CALL;
+}
+
void PCHStmtWriter::VisitCXXConstructExpr(CXXConstructExpr *E) {
VisitExpr(E);
Writer.AddDeclRef(E->getConstructor(), Record);
@@ -857,6 +874,7 @@ void PCHStmtWriter::VisitCXXConstructExpr(CXXConstructExpr *E) {
Record.push_back(E->getNumArgs());
for (unsigned I = 0, N = E->getNumArgs(); I != N; ++I)
Writer.WriteSubStmt(E->getArg(I));
+ Record.push_back(E->getConstructionKind()); // FIXME: stable encoding
Code = pch::EXPR_CXX_CONSTRUCT;
}
@@ -905,6 +923,91 @@ void PCHStmtWriter::VisitCXXNullPtrLiteralExpr(CXXNullPtrLiteralExpr *E) {
Code = pch::EXPR_CXX_NULL_PTR_LITERAL;
}
+void PCHStmtWriter::VisitCXXTypeidExpr(CXXTypeidExpr *E) {
+ VisitExpr(E);
+ Writer.AddSourceRange(E->getSourceRange(), Record);
+ if (E->isTypeOperand()) {
+ Writer.AddTypeSourceInfo(E->getTypeOperandSourceInfo(), Record);
+ Code = pch::EXPR_CXX_TYPEID_TYPE;
+ } else {
+ Writer.WriteSubStmt(E->getExprOperand());
+ Code = pch::EXPR_CXX_TYPEID_EXPR;
+ }
+}
+
+void PCHStmtWriter::VisitCXXThisExpr(CXXThisExpr *E) {
+ VisitExpr(E);
+ Writer.AddSourceLocation(E->getLocation(), Record);
+ Record.push_back(E->isImplicit());
+ Code = pch::EXPR_CXX_THIS;
+}
+
+void PCHStmtWriter::VisitCXXThrowExpr(CXXThrowExpr *E) {
+ VisitExpr(E);
+ Writer.AddSourceLocation(E->getThrowLoc(), Record);
+ Writer.WriteSubStmt(E->getSubExpr());
+ Code = pch::EXPR_CXX_THROW;
+}
+
+void PCHStmtWriter::VisitCXXDefaultArgExpr(CXXDefaultArgExpr *E) {
+ VisitExpr(E);
+ Writer.AddSourceLocation(E->getUsedLocation(), Record);
+ if (E->isExprStored()) {
+ Record.push_back(1);
+ Writer.WriteSubStmt(E->getExpr());
+ } else {
+ Record.push_back(0);
+ }
+
+ Code = pch::EXPR_CXX_DEFAULT_ARG;
+}
+
+void PCHStmtWriter::VisitCXXBindTemporaryExpr(CXXBindTemporaryExpr *E) {
+ VisitExpr(E);
+ Writer.AddCXXTemporary(E->getTemporary(), Record);
+ Writer.WriteSubStmt(E->getSubExpr());
+ Code = pch::EXPR_CXX_BIND_TEMPORARY;
+}
+
+void PCHStmtWriter::VisitCXXZeroInitValueExpr(CXXZeroInitValueExpr *E) {
+ VisitExpr(E);
+ Writer.AddSourceLocation(E->getTypeBeginLoc(), Record);
+ Writer.AddSourceLocation(E->getRParenLoc(), Record);
+ Code = pch::EXPR_CXX_ZERO_INIT_VALUE;
+}
+
+void PCHStmtWriter::VisitCXXNewExpr(CXXNewExpr *E) {
+ VisitExpr(E);
+ Record.push_back(E->isGlobalNew());
+ Record.push_back(E->isParenTypeId());
+ Record.push_back(E->hasInitializer());
+ Record.push_back(E->isArray());
+ Record.push_back(E->getNumPlacementArgs());
+ Record.push_back(E->getNumConstructorArgs());
+ Writer.AddDeclRef(E->getOperatorNew(), Record);
+ Writer.AddDeclRef(E->getOperatorDelete(), Record);
+ Writer.AddDeclRef(E->getConstructor(), Record);
+ Writer.AddSourceLocation(E->getStartLoc(), Record);
+ Writer.AddSourceLocation(E->getEndLoc(), Record);
+ for (CXXNewExpr::arg_iterator I = E->raw_arg_begin(), e = E->raw_arg_end();
+ I != e; ++I)
+ Writer.WriteSubStmt(*I);
+
+ Code = pch::EXPR_CXX_NEW;
+}
+
+
+void PCHStmtWriter::VisitCXXExprWithTemporaries(CXXExprWithTemporaries *E) {
+ VisitExpr(E);
+ Record.push_back(E->getNumTemporaries());
+ for (unsigned i = 0, e = E->getNumTemporaries(); i != e; ++i)
+ Writer.AddCXXTemporary(E->getTemporary(i), Record);
+
+ Writer.WriteSubStmt(E->getSubExpr());
+ Code = pch::EXPR_CXX_EXPR_WITH_TEMPORARIES;
+}
+
+
//===----------------------------------------------------------------------===//
// PCHWriter Implementation
//===----------------------------------------------------------------------===//
@@ -949,8 +1052,13 @@ void PCHWriter::WriteSubStmt(Stmt *S) {
Writer.Code = pch::STMT_NULL_PTR;
Writer.Visit(S);
- assert(Writer.Code != pch::STMT_NULL_PTR &&
- "Unhandled expression writing PCH file");
+
+#ifndef NDEBUG
+ if (Writer.Code == pch::STMT_NULL_PTR) {
+ S->dump();
+ assert(0 && "Unhandled sub statement writing PCH file");
+ }
+#endif
Stream.EmitRecord(Writer.Code, Record);
}
@@ -971,8 +1079,12 @@ void PCHWriter::FlushStmts() {
Writer.Code = pch::STMT_NULL_PTR;
Writer.Visit(S);
- assert(Writer.Code != pch::STMT_NULL_PTR &&
- "Unhandled expression writing PCH file");
+#ifndef NDEBUG
+ if (Writer.Code == pch::STMT_NULL_PTR) {
+ S->dump();
+ assert(0 && "Unhandled expression writing PCH file");
+ }
+#endif
Stream.EmitRecord(Writer.Code, Record);
assert(N == StmtsToEmit.size() &&
diff --git a/lib/Frontend/PrintParserCallbacks.cpp b/lib/Frontend/PrintParserCallbacks.cpp
index 4df5c5263c7e..b032233b3d3b 100644
--- a/lib/Frontend/PrintParserCallbacks.cpp
+++ b/lib/Frontend/PrintParserCallbacks.cpp
@@ -161,7 +161,8 @@ namespace {
/// ParsedFreeStandingDeclSpec - This method is invoked when a declspec with
/// no declarator (e.g. "struct foo;") is parsed.
- virtual DeclPtrTy ParsedFreeStandingDeclSpec(Scope *S, DeclSpec &DS) {
+ virtual DeclPtrTy ParsedFreeStandingDeclSpec(Scope *S, AccessSpecifier AS,
+ DeclSpec &DS) {
Out << __FUNCTION__ << "\n";
return DeclPtrTy();
}
@@ -315,7 +316,8 @@ namespace {
return StmtEmpty();
}
- virtual OwningStmtResult ActOnStartOfSwitchStmt(FullExprArg Cond,
+ virtual OwningStmtResult ActOnStartOfSwitchStmt(SourceLocation SwitchLoc,
+ ExprArg Cond,
DeclPtrTy CondVar) {
Out << __FUNCTION__ << "\n";
return StmtEmpty();
diff --git a/lib/Frontend/RewriteObjC.cpp b/lib/Frontend/RewriteObjC.cpp
index 11698325e9b1..5dd7bdfcbfa1 100644
--- a/lib/Frontend/RewriteObjC.cpp
+++ b/lib/Frontend/RewriteObjC.cpp
@@ -276,6 +276,7 @@ namespace {
bool isSuperReceiver(Expr *recExpr);
QualType getSuperStructType();
QualType getConstantStringStructType();
+ QualType convertFunctionTypeOfBlocks(const FunctionType *FT);
bool BufferContainsPPDirectives(const char *startBuf, const char *endBuf);
// Expression Rewriting.
@@ -403,6 +404,18 @@ namespace {
return isa<BlockPointerType>(T);
}
+ /// convertBlockPointerToFunctionPointer - Converts a block-pointer type
+ /// to a function pointer type and upon success, returns true; false
+ /// otherwise.
+ bool convertBlockPointerToFunctionPointer(QualType &T) {
+ if (isTopLevelBlockPointerType(T)) {
+ const BlockPointerType *BPT = T->getAs<BlockPointerType>();
+ T = Context->getPointerType(BPT->getPointeeType());
+ return true;
+ }
+ return false;
+ }
+
// FIXME: This predicate seems like it would be useful to add to ASTContext.
bool isObjCType(QualType T) {
if (!LangOpts.ObjC1 && !LangOpts.ObjC2)
@@ -971,7 +984,8 @@ void RewriteObjC::RewriteCategoryDecl(ObjCCategoryDecl *CatDecl) {
RewriteMethodDeclaration(*I);
// Lastly, comment out the @end.
- ReplaceText(CatDecl->getAtEndRange().getBegin(), 0, "// ");
+ ReplaceText(CatDecl->getAtEndRange().getBegin(),
+ strlen("@end"), "/* @end */");
}
void RewriteObjC::RewriteProtocolDecl(ObjCProtocolDecl *PDecl) {
@@ -991,7 +1005,7 @@ void RewriteObjC::RewriteProtocolDecl(ObjCProtocolDecl *PDecl) {
// Lastly, comment out the @end.
SourceLocation LocEnd = PDecl->getAtEndRange().getBegin();
- ReplaceText(LocEnd, 0, "// ");
+ ReplaceText(LocEnd, strlen("@end"), "/* @end */");
// Must comment out @optional/@required
const char *startBuf = SM->getCharacterData(LocStart);
@@ -1109,12 +1123,11 @@ void RewriteObjC::RewriteObjCMethodDecl(ObjCMethodDecl *OMD,
ResultStr += PDecl->getNameAsString();
} else {
std::string Name = PDecl->getNameAsString();
- if (isTopLevelBlockPointerType(PDecl->getType())) {
- // Make sure we convert "t (^)(...)" to "t (*)(...)".
- const BlockPointerType *BPT = PDecl->getType()->getAs<BlockPointerType>();
- Context->getPointerType(BPT->getPointeeType()).getAsStringInternal(Name,
- Context->PrintingPolicy);
- } else
+ QualType QT = PDecl->getType();
+ // Make sure we convert "t (^)(...)" to "t (*)(...)".
+ if (convertBlockPointerToFunctionPointer(QT))
+ QT.getAsStringInternal(Name, Context->PrintingPolicy);
+ else
PDecl->getType().getAsStringInternal(Name, Context->PrintingPolicy);
ResultStr += Name;
}
@@ -1220,7 +1233,8 @@ void RewriteObjC::RewriteInterfaceDecl(ObjCInterfaceDecl *ClassDecl) {
RewriteMethodDeclaration(*I);
// Lastly, comment out the @end.
- ReplaceText(ClassDecl->getAtEndRange().getBegin(), 0, "// ");
+ ReplaceText(ClassDecl->getAtEndRange().getBegin(), strlen("@end"),
+ "/* @end */");
}
Stmt *RewriteObjC::RewritePropertySetter(BinaryOperator *BinOp, Expr *newStmt,
@@ -1349,7 +1363,7 @@ Stmt *RewriteObjC::RewriteObjCIvarRefExpr(ObjCIvarRefExpr *IV,
std::string RecName = clsDeclared->getIdentifier()->getName();
RecName += "_IMPL";
IdentifierInfo *II = &Context->Idents.get(RecName);
- RecordDecl *RD = RecordDecl::Create(*Context, TagDecl::TK_struct, TUDecl,
+ RecordDecl *RD = RecordDecl::Create(*Context, TTK_Struct, TUDecl,
SourceLocation(), II);
assert(RD && "RewriteObjCIvarRefExpr(): Can't find RecordDecl");
QualType castT = Context->getPointerType(Context->getTagDeclType(RD));
@@ -1394,7 +1408,7 @@ Stmt *RewriteObjC::RewriteObjCIvarRefExpr(ObjCIvarRefExpr *IV,
std::string RecName = clsDeclared->getIdentifier()->getName();
RecName += "_IMPL";
IdentifierInfo *II = &Context->Idents.get(RecName);
- RecordDecl *RD = RecordDecl::Create(*Context, TagDecl::TK_struct, TUDecl,
+ RecordDecl *RD = RecordDecl::Create(*Context, TTK_Struct, TUDecl,
SourceLocation(), II);
assert(RD && "RewriteObjCIvarRefExpr(): Can't find RecordDecl");
QualType castT = Context->getPointerType(Context->getTagDeclType(RD));
@@ -1911,13 +1925,13 @@ Stmt *RewriteObjC::RewriteObjCTryStmt(ObjCAtTryStmt *S) {
buf += "1) { ";
ReplaceText(startLoc, lParenLoc-startBuf+1, buf);
sawIdTypedCatch = true;
- } else if (t->isObjCObjectPointerType()) {
- QualType InterfaceTy = t->getPointeeType();
- const ObjCInterfaceType *cls = // Should be a pointer to a class.
- InterfaceTy->getAs<ObjCInterfaceType>();
- if (cls) {
+ } else if (const ObjCObjectPointerType *Ptr =
+ t->getAs<ObjCObjectPointerType>()) {
+ // Should be a pointer to a class.
+ ObjCInterfaceDecl *IDecl = Ptr->getObjectType()->getInterface();
+ if (IDecl) {
buf += "objc_exception_match((struct objc_class *)objc_getClass(\"";
- buf += cls->getDecl()->getNameAsString();
+ buf += IDecl->getNameAsString();
buf += "\"), (struct objc_object *)_caught)) { ";
ReplaceText(startLoc, lParenLoc-startBuf+1, buf);
}
@@ -2426,7 +2440,7 @@ void RewriteObjC::SynthMsgSendFunctionDecl() {
void RewriteObjC::SynthMsgSendSuperFunctionDecl() {
IdentifierInfo *msgSendIdent = &Context->Idents.get("objc_msgSendSuper");
llvm::SmallVector<QualType, 16> ArgTys;
- RecordDecl *RD = RecordDecl::Create(*Context, TagDecl::TK_struct, TUDecl,
+ RecordDecl *RD = RecordDecl::Create(*Context, TTK_Struct, TUDecl,
SourceLocation(),
&Context->Idents.get("objc_super"));
QualType argT = Context->getPointerType(Context->getTagDeclType(RD));
@@ -2475,7 +2489,7 @@ void RewriteObjC::SynthMsgSendSuperStretFunctionDecl() {
IdentifierInfo *msgSendIdent =
&Context->Idents.get("objc_msgSendSuper_stret");
llvm::SmallVector<QualType, 16> ArgTys;
- RecordDecl *RD = RecordDecl::Create(*Context, TagDecl::TK_struct, TUDecl,
+ RecordDecl *RD = RecordDecl::Create(*Context, TTK_Struct, TUDecl,
SourceLocation(),
&Context->Idents.get("objc_super"));
QualType argT = Context->getPointerType(Context->getTagDeclType(RD));
@@ -2625,7 +2639,7 @@ bool RewriteObjC::isSuperReceiver(Expr *recExpr) {
// struct objc_super { struct objc_object *receiver; struct objc_class *super; };
QualType RewriteObjC::getSuperStructType() {
if (!SuperStructDecl) {
- SuperStructDecl = RecordDecl::Create(*Context, TagDecl::TK_struct, TUDecl,
+ SuperStructDecl = RecordDecl::Create(*Context, TTK_Struct, TUDecl,
SourceLocation(),
&Context->Idents.get("objc_super"));
QualType FieldTypes[2];
@@ -2651,7 +2665,7 @@ QualType RewriteObjC::getSuperStructType() {
QualType RewriteObjC::getConstantStringStructType() {
if (!ConstantStringDecl) {
- ConstantStringDecl = RecordDecl::Create(*Context, TagDecl::TK_struct, TUDecl,
+ ConstantStringDecl = RecordDecl::Create(*Context, TTK_Struct, TUDecl,
SourceLocation(),
&Context->Idents.get("__NSConstantStringImpl"));
QualType FieldTypes[4];
@@ -2811,7 +2825,7 @@ Stmt *RewriteObjC::SynthMessageExpr(ObjCMessageExpr *Exp,
llvm::SmallVector<Expr*, 8> ClsExprs;
QualType argType = Context->getPointerType(Context->CharTy);
ObjCInterfaceDecl *Class
- = Exp->getClassReceiver()->getAs<ObjCInterfaceType>()->getDecl();
+ = Exp->getClassReceiver()->getAs<ObjCObjectType>()->getInterface();
IdentifierInfo *clsName = Class->getIdentifier();
ClsExprs.push_back(StringLiteral::Create(*Context,
clsName->getNameStart(),
@@ -2943,6 +2957,8 @@ Stmt *RewriteObjC::SynthMessageExpr(ObjCMessageExpr *Exp,
QualType type = ICE->getType()->isObjCQualifiedIdType()
? Context->getObjCIdType()
: ICE->getType();
+ // Make sure we convert "type (^)(...)" to "type (*)(...)".
+ (void)convertBlockPointerToFunctionPointer(type);
userExpr = NoTypeInfoCStyleCastExpr(Context, type, CastExpr::CK_Unknown,
userExpr);
}
@@ -2980,18 +2996,12 @@ Stmt *RewriteObjC::SynthMessageExpr(ObjCMessageExpr *Exp,
? Context->getObjCIdType()
: (*PI)->getType();
// Make sure we convert "t (^)(...)" to "t (*)(...)".
- if (isTopLevelBlockPointerType(t)) {
- const BlockPointerType *BPT = t->getAs<BlockPointerType>();
- t = Context->getPointerType(BPT->getPointeeType());
- }
+ (void)convertBlockPointerToFunctionPointer(t);
ArgTypes.push_back(t);
}
returnType = OMD->getResultType()->isObjCQualifiedIdType()
? Context->getObjCIdType() : OMD->getResultType();
- if (isTopLevelBlockPointerType(returnType)) {
- const BlockPointerType *BPT = returnType->getAs<BlockPointerType>();
- returnType = Context->getPointerType(BPT->getPointeeType());
- }
+ (void)convertBlockPointerToFunctionPointer(returnType);
} else {
returnType = Context->getObjCIdType();
}
@@ -4111,7 +4121,11 @@ std::string RewriteObjC::SynthesizeBlockFunc(BlockExpr *CE, int i,
E = BD->param_end(); AI != E; ++AI) {
if (AI != BD->param_begin()) S += ", ";
ParamStr = (*AI)->getNameAsString();
- (*AI)->getType().getAsStringInternal(ParamStr, Context->PrintingPolicy);
+ QualType QT = (*AI)->getType();
+ if (convertBlockPointerToFunctionPointer(QT))
+ QT.getAsStringInternal(ParamStr, Context->PrintingPolicy);
+ else
+ QT.getAsStringInternal(ParamStr, Context->PrintingPolicy);
S += ParamStr;
}
if (FT->isVariadic()) {
@@ -4532,6 +4546,39 @@ void RewriteObjC::GetInnerBlockDeclRefExprs(Stmt *S,
return;
}
+/// convertFunctionTypeOfBlocks - This routine converts a function type
+/// whose result type may be a block pointer or whose argument type(s)
+/// might be block pointers to an equivalent funtion type replacing
+/// all block pointers to function pointers.
+QualType RewriteObjC::convertFunctionTypeOfBlocks(const FunctionType *FT) {
+ const FunctionProtoType *FTP = dyn_cast<FunctionProtoType>(FT);
+ // FTP will be null for closures that don't take arguments.
+ // Generate a funky cast.
+ llvm::SmallVector<QualType, 8> ArgTypes;
+ QualType Res = FT->getResultType();
+ bool HasBlockType = convertBlockPointerToFunctionPointer(Res);
+
+ if (FTP) {
+ for (FunctionProtoType::arg_type_iterator I = FTP->arg_type_begin(),
+ E = FTP->arg_type_end(); I && (I != E); ++I) {
+ QualType t = *I;
+ // Make sure we convert "t (^)(...)" to "t (*)(...)".
+ if (convertBlockPointerToFunctionPointer(t))
+ HasBlockType = true;
+ ArgTypes.push_back(t);
+ }
+ }
+ QualType FuncType;
+ // FIXME. Does this work if block takes no argument but has a return type
+ // which is of block type?
+ if (HasBlockType)
+ FuncType = Context->getFunctionType(Res,
+ &ArgTypes[0], ArgTypes.size(), false/*no variadic*/, 0,
+ false, false, 0, 0, FunctionType::ExtInfo());
+ else FuncType = QualType(FT, 0);
+ return FuncType;
+}
+
Stmt *RewriteObjC::SynthesizeBlockCall(CallExpr *Exp, const Expr *BlockExp) {
// Navigate to relevant type information.
const BlockPointerType *CPT = 0;
@@ -4573,7 +4620,7 @@ Stmt *RewriteObjC::SynthesizeBlockCall(CallExpr *Exp, const Expr *BlockExp) {
const FunctionProtoType *FTP = dyn_cast<FunctionProtoType>(FT);
// FTP will be null for closures that don't take arguments.
- RecordDecl *RD = RecordDecl::Create(*Context, TagDecl::TK_struct, TUDecl,
+ RecordDecl *RD = RecordDecl::Create(*Context, TTK_Struct, TUDecl,
SourceLocation(),
&Context->Idents.get("__block_impl"));
QualType PtrBlock = Context->getPointerType(Context->getTagDeclType(RD));
@@ -4588,10 +4635,7 @@ Stmt *RewriteObjC::SynthesizeBlockCall(CallExpr *Exp, const Expr *BlockExp) {
E = FTP->arg_type_end(); I && (I != E); ++I) {
QualType t = *I;
// Make sure we convert "t (^)(...)" to "t (*)(...)".
- if (isTopLevelBlockPointerType(t)) {
- const BlockPointerType *BPT = t->getAs<BlockPointerType>();
- t = Context->getPointerType(BPT->getPointeeType());
- }
+ (void)convertBlockPointerToFunctionPointer(t);
ArgTypes.push_back(t);
}
}
@@ -5174,7 +5218,8 @@ Stmt *RewriteObjC::SynthBlockInitExpr(BlockExpr *Exp,
std::string Func = "__" + FuncName + "_block_func_" + BlockNumber;
// Get a pointer to the function type so we can cast appropriately.
- QualType FType = Context->getPointerType(QualType(Exp->getFunctionType(),0));
+ QualType BFT = convertFunctionTypeOfBlocks(Exp->getFunctionType());
+ QualType FType = Context->getPointerType(BFT);
FunctionDecl *FD;
Expr *NewRep;
@@ -5218,6 +5263,12 @@ Stmt *RewriteObjC::SynthBlockInitExpr(BlockExpr *Exp,
// FIXME: Conform to ABI ([[obj retain] autorelease]).
FD = SynthBlockInitFunctionDecl((*I)->getNameAsCString());
Exp = new (Context) DeclRefExpr(FD, FD->getType(), SourceLocation());
+ if (HasLocalVariableExternalStorage(*I)) {
+ QualType QT = (*I)->getType();
+ QT = Context->getPointerType(QT);
+ Exp = new (Context) UnaryOperator(Exp, UnaryOperator::AddrOf, QT,
+ SourceLocation());
+ }
} else if (isTopLevelBlockPointerType((*I)->getType())) {
FD = SynthBlockInitFunctionDecl((*I)->getNameAsCString());
Arg = new (Context) DeclRefExpr(FD, FD->getType(), SourceLocation());
@@ -5245,7 +5296,7 @@ Stmt *RewriteObjC::SynthBlockInitExpr(BlockExpr *Exp,
RewriteByRefString(RecName, Name, ND);
IdentifierInfo *II = &Context->Idents.get(RecName.c_str()
+ sizeof("struct"));
- RecordDecl *RD = RecordDecl::Create(*Context, TagDecl::TK_struct, TUDecl,
+ RecordDecl *RD = RecordDecl::Create(*Context, TTK_Struct, TUDecl,
SourceLocation(), II);
assert(RD && "SynthBlockInitExpr(): Can't find RecordDecl");
QualType castT = Context->getPointerType(Context->getTagDeclType(RD));
diff --git a/lib/Frontend/TextDiagnosticPrinter.cpp b/lib/Frontend/TextDiagnosticPrinter.cpp
index 66ed956a22a7..6ccf4f1ad0a6 100644
--- a/lib/Frontend/TextDiagnosticPrinter.cpp
+++ b/lib/Frontend/TextDiagnosticPrinter.cpp
@@ -18,6 +18,7 @@
#include "llvm/Support/MemoryBuffer.h"
#include "llvm/Support/raw_ostream.h"
#include "llvm/ADT/SmallString.h"
+#include "llvm/ADT/StringExtras.h"
#include <algorithm>
using namespace clang;
@@ -819,21 +820,52 @@ void TextDiagnosticPrinter::HandleDiagnostic(Diagnostic::Level Level,
llvm::SmallString<100> OutStr;
Info.FormatDiagnostic(OutStr);
+ std::string OptionName;
if (DiagOpts->ShowOptionNames) {
if (const char *Opt = Diagnostic::getWarningOptionForDiag(Info.getID())) {
- OutStr += " [-W";
- OutStr += Opt;
- OutStr += ']';
+ OptionName = "-W";
+ OptionName += Opt;
+ } else if (Info.getID() == diag::fatal_too_many_errors) {
+ OptionName = "-ferror-limit=";
} else {
// If the diagnostic is an extension diagnostic and not enabled by default
// then it must have been turned on with -pedantic.
bool EnabledByDefault;
if (Diagnostic::isBuiltinExtensionDiag(Info.getID(), EnabledByDefault) &&
!EnabledByDefault)
- OutStr += " [-pedantic]";
+ OptionName = "-pedantic";
}
}
+
+ // If the user wants to see category information, include it too.
+ unsigned DiagCategory = 0;
+ if (DiagOpts->ShowCategories)
+ DiagCategory = Diagnostic::getCategoryNumberForDiag(Info.getID());
+
+ // If there is any categorization information, include it.
+ if (!OptionName.empty() || DiagCategory != 0) {
+ bool NeedsComma = false;
+ OutStr += " [";
+
+ if (!OptionName.empty()) {
+ OutStr += OptionName;
+ NeedsComma = true;
+ }
+
+ if (DiagCategory) {
+ if (NeedsComma) OutStr += ',';
+ if (DiagOpts->ShowCategories == 1)
+ OutStr += llvm::utostr(DiagCategory);
+ else {
+ assert(DiagOpts->ShowCategories == 2 && "Invalid ShowCategories value");
+ OutStr += Diagnostic::getCategoryNameFromID(DiagCategory);
+ }
+ }
+
+ OutStr += "]";
+ }
+
if (DiagOpts->ShowColors) {
// Print warnings, errors and fatal errors in bold, no color
switch (Level) {
diff --git a/lib/Headers/emmintrin.h b/lib/Headers/emmintrin.h
index 6b9dd2aba588..8afbe76fbeb5 100644
--- a/lib/Headers/emmintrin.h
+++ b/lib/Headers/emmintrin.h
@@ -1310,8 +1310,9 @@ _mm_movemask_pd(__m128d a)
return __builtin_ia32_movmskpd(a);
}
-#define _mm_shuffle_pd(a, b, i) (__builtin_shufflevector((a), (b), (i) & 1, \
- (((i) & 2) >> 1) + 2))
+#define _mm_shuffle_pd(a, b, i) \
+ (__builtin_shufflevector((__m128d)(a), (__m128d)(b), (i) & 1, \
+ (((i) & 2) >> 1) + 2))
static __inline__ __m128 __attribute__((__always_inline__, __nodebug__))
_mm_castpd_ps(__m128d in)
diff --git a/lib/Headers/xmmintrin.h b/lib/Headers/xmmintrin.h
index 4e313b23b3d0..3e82e28c42ed 100644
--- a/lib/Headers/xmmintrin.h
+++ b/lib/Headers/xmmintrin.h
@@ -723,7 +723,8 @@ _mm_setcsr(unsigned int i)
}
#define _mm_shuffle_ps(a, b, mask) \
- (__builtin_shufflevector(a, b, (mask) & 0x3, ((mask) & 0xc) >> 2, \
+ (__builtin_shufflevector((__v4sf)a, (__v4sf)b, \
+ (mask) & 0x3, ((mask) & 0xc) >> 2, \
(((mask) & 0x30) >> 4) + 4, \
(((mask) & 0xc0) >> 6) + 4))
diff --git a/lib/Index/ASTLocation.cpp b/lib/Index/ASTLocation.cpp
index 091bc78c2669..bd3b5ee8bf98 100644
--- a/lib/Index/ASTLocation.cpp
+++ b/lib/Index/ASTLocation.cpp
@@ -69,7 +69,7 @@ SourceRange ASTLocation::getSourceRange() const {
case N_NamedRef:
return SourceRange(AsNamedRef().Loc, AsNamedRef().Loc);
case N_Type:
- return AsTypeLoc().getSourceRange();
+ return AsTypeLoc().getLocalSourceRange();
}
return SourceRange();
diff --git a/lib/Index/Analyzer.cpp b/lib/Index/Analyzer.cpp
index 1354fe6be0d2..6be35ab4a378 100644
--- a/lib/Index/Analyzer.cpp
+++ b/lib/Index/Analyzer.cpp
@@ -180,7 +180,7 @@ public:
if (IsInstanceMethod)
return false;
- MsgD = Msg->getClassReceiver()->getAs<ObjCInterfaceType>()->getDecl();
+ MsgD = Msg->getClassReceiver()->getAs<ObjCObjectType>()->getInterface();
break;
}
@@ -189,7 +189,7 @@ public:
if (IsInstanceMethod)
return false;
- MsgD = Msg->getSuperType()->getAs<ObjCInterfaceType>()->getDecl();
+ MsgD = Msg->getSuperType()->getAs<ObjCObjectType>()->getInterface();
break;
case ObjCMessageExpr::SuperInstance:
@@ -292,12 +292,12 @@ public:
case ObjCMessageExpr::Class:
CanBeClassMethod = true;
- MsgD = Msg->getClassReceiver()->getAs<ObjCInterfaceType>()->getDecl();
+ MsgD = Msg->getClassReceiver()->getAs<ObjCObjectType>()->getInterface();
break;
case ObjCMessageExpr::SuperClass:
CanBeClassMethod = true;
- MsgD = Msg->getSuperType()->getAs<ObjCInterfaceType>()->getDecl();
+ MsgD = Msg->getSuperType()->getAs<ObjCObjectType>()->getInterface();
break;
case ObjCMessageExpr::SuperInstance:
diff --git a/lib/Index/ResolveLocation.cpp b/lib/Index/ResolveLocation.cpp
index 4bb15943bb4d..ccd7a126b40c 100644
--- a/lib/Index/ResolveLocation.cpp
+++ b/lib/Index/ResolveLocation.cpp
@@ -51,7 +51,7 @@ protected:
return CheckRange(D->getSourceRange());
}
RangePos CheckRange(Stmt *Node) { return CheckRange(Node->getSourceRange()); }
- RangePos CheckRange(TypeLoc TL) { return CheckRange(TL.getSourceRange()); }
+ RangePos CheckRange(TypeLoc TL) { return CheckRange(TL.getLocalSourceRange()); }
template <typename T>
bool isBeforeLocation(T Node) {
@@ -130,7 +130,7 @@ public:
ASTLocation VisitFunctionTypeLoc(FunctionTypeLoc TL);
ASTLocation VisitArrayTypeLoc(ArrayTypeLoc TL);
ASTLocation VisitObjCInterfaceTypeLoc(ObjCInterfaceTypeLoc TL);
- ASTLocation VisitObjCObjectPointerTypeLoc(ObjCObjectPointerTypeLoc TL);
+ ASTLocation VisitObjCObjectTypeLoc(ObjCObjectTypeLoc TL);
ASTLocation VisitTypeLoc(TypeLoc TL);
};
@@ -454,6 +454,13 @@ ASTLocation TypeLocResolver::VisitObjCInterfaceTypeLoc(ObjCInterfaceTypeLoc TL)
if (ContainsLocation(TL.getNameLoc()))
return ASTLocation(ParentDecl, TL.getIFaceDecl(), TL.getNameLoc());
+ return ASTLocation(ParentDecl, TL);
+}
+
+ASTLocation TypeLocResolver::VisitObjCObjectTypeLoc(ObjCObjectTypeLoc TL) {
+ assert(ContainsLocation(TL) &&
+ "Should visit only after verifying that loc is in range");
+
for (unsigned i = 0; i != TL.getNumProtocols(); ++i) {
SourceLocation L = TL.getProtocolLoc(i);
RangePos RP = CheckRange(L);
@@ -466,24 +473,6 @@ ASTLocation TypeLocResolver::VisitObjCInterfaceTypeLoc(ObjCInterfaceTypeLoc TL)
return ASTLocation(ParentDecl, TL);
}
-ASTLocation TypeLocResolver::VisitObjCObjectPointerTypeLoc(ObjCObjectPointerTypeLoc TL) {
- assert(ContainsLocation(TL) &&
- "Should visit only after verifying that loc is in range");
-
- if (TL.hasProtocolsAsWritten()) {
- for (unsigned i = 0; i != TL.getNumProtocols(); ++i) {
- SourceLocation L = TL.getProtocolLoc(i);
- RangePos RP = CheckRange(L);
- if (RP == AfterLoc)
- break;
- if (RP == ContainsLoc)
- return ASTLocation(ParentDecl, TL.getProtocol(i), L);
- }
- }
-
- return ASTLocation(ParentDecl, TL);
-}
-
ASTLocation TypeLocResolver::VisitTypeLoc(TypeLoc TL) {
assert(ContainsLocation(TL) &&
"Should visit only after verifying that loc is in range");
diff --git a/lib/Lex/Lexer.cpp b/lib/Lex/Lexer.cpp
index 74e8d7489e9a..cd153e147b5d 100644
--- a/lib/Lex/Lexer.cpp
+++ b/lib/Lex/Lexer.cpp
@@ -1141,7 +1141,8 @@ bool Lexer::SkipBlockComment(Token &Result, const char *CurPtr) {
unsigned char C = getCharAndSize(CurPtr, CharSize);
CurPtr += CharSize;
if (C == 0 && CurPtr == BufferEnd+1) {
- if (!isLexingRawMode())
+ if (!isLexingRawMode() &&
+ !PP->isCodeCompletionFile(FileLoc))
Diag(BufferPtr, diag::err_unterminated_block_comment);
--CurPtr;
@@ -1224,7 +1225,7 @@ bool Lexer::SkipBlockComment(Token &Result, const char *CurPtr) {
Diag(CurPtr-1, diag::warn_nested_block_comment);
}
} else if (C == 0 && CurPtr == BufferEnd+1) {
- if (!isLexingRawMode())
+ if (!isLexingRawMode() && !PP->isCodeCompletionFile(FileLoc))
Diag(BufferPtr, diag::err_unterminated_block_comment);
// Note: the user probably forgot a */. We could continue immediately
// after the /*, but this would involve lexing a lot of what really is the
@@ -1358,6 +1359,9 @@ bool Lexer::LexEndOfFile(Token &Result, const char *CurPtr) {
// Only do the eof -> code_completion translation once.
PP->SetCodeCompletionPoint(0, 0, 0);
+
+ // Silence any diagnostics that occur once we hit the code-completion point.
+ PP->getDiagnostics().setSuppressAllDiagnostics(true);
return true;
}
@@ -1421,6 +1425,7 @@ static const char *FindConflictEnd(const char *CurPtr, const char *BufferEnd) {
if (RestOfBuffer[Pos-1] != '\r' &&
RestOfBuffer[Pos-1] != '\n') {
RestOfBuffer = RestOfBuffer.substr(Pos+7);
+ Pos = RestOfBuffer.find(">>>>>>>");
continue;
}
return RestOfBuffer.data()+Pos;
@@ -1450,7 +1455,7 @@ bool Lexer::IsStartOfConflictMarker(const char *CurPtr) {
// Check to see if there is a >>>>>>> somewhere in the buffer at the start of
// a line to terminate this conflict marker.
- if (FindConflictEnd(CurPtr+7, BufferEnd)) {
+ if (FindConflictEnd(CurPtr, BufferEnd)) {
// We found a match. We are really in a conflict marker.
// Diagnose this, and ignore to the end of line.
Diag(CurPtr, diag::err_conflict_marker);
diff --git a/lib/Lex/LiteralSupport.cpp b/lib/Lex/LiteralSupport.cpp
index f4255822641d..b73f236641c0 100644
--- a/lib/Lex/LiteralSupport.cpp
+++ b/lib/Lex/LiteralSupport.cpp
@@ -34,7 +34,7 @@ static int HexDigitValue(char C) {
static unsigned ProcessCharEscape(const char *&ThisTokBuf,
const char *ThisTokEnd, bool &HadError,
SourceLocation Loc, bool IsWide,
- Preprocessor &PP) {
+ Preprocessor &PP, bool Complain) {
// Skip the '\' char.
++ThisTokBuf;
@@ -54,11 +54,13 @@ static unsigned ProcessCharEscape(const char *&ThisTokBuf,
ResultChar = 8;
break;
case 'e':
- PP.Diag(Loc, diag::ext_nonstandard_escape) << "e";
+ if (Complain)
+ PP.Diag(Loc, diag::ext_nonstandard_escape) << "e";
ResultChar = 27;
break;
case 'E':
- PP.Diag(Loc, diag::ext_nonstandard_escape) << "E";
+ if (Complain)
+ PP.Diag(Loc, diag::ext_nonstandard_escape) << "E";
ResultChar = 27;
break;
case 'f':
@@ -79,7 +81,8 @@ static unsigned ProcessCharEscape(const char *&ThisTokBuf,
case 'x': { // Hex escape.
ResultChar = 0;
if (ThisTokBuf == ThisTokEnd || !isxdigit(*ThisTokBuf)) {
- PP.Diag(Loc, diag::err_hex_escape_no_digits);
+ if (Complain)
+ PP.Diag(Loc, diag::err_hex_escape_no_digits);
HadError = 1;
break;
}
@@ -106,7 +109,7 @@ static unsigned ProcessCharEscape(const char *&ThisTokBuf,
}
// Check for overflow.
- if (Overflow) // Too many digits to fit in
+ if (Overflow && Complain) // Too many digits to fit in
PP.Diag(Loc, diag::warn_hex_escape_too_large);
break;
}
@@ -132,7 +135,8 @@ static unsigned ProcessCharEscape(const char *&ThisTokBuf,
: PP.getTargetInfo().getCharWidth();
if (CharWidth != 32 && (ResultChar >> CharWidth) != 0) {
- PP.Diag(Loc, diag::warn_octal_escape_too_large);
+ if (Complain)
+ PP.Diag(Loc, diag::warn_octal_escape_too_large);
ResultChar &= ~0U >> (32-CharWidth);
}
break;
@@ -141,10 +145,14 @@ static unsigned ProcessCharEscape(const char *&ThisTokBuf,
// Otherwise, these are not valid escapes.
case '(': case '{': case '[': case '%':
// GCC accepts these as extensions. We warn about them as such though.
- PP.Diag(Loc, diag::ext_nonstandard_escape)
- << std::string()+(char)ResultChar;
+ if (Complain)
+ PP.Diag(Loc, diag::ext_nonstandard_escape)
+ << std::string()+(char)ResultChar;
break;
default:
+ if (!Complain)
+ break;
+
if (isgraph(ThisTokBuf[0]))
PP.Diag(Loc, diag::ext_unknown_escape) << std::string()+(char)ResultChar;
else
@@ -161,7 +169,8 @@ static unsigned ProcessCharEscape(const char *&ThisTokBuf,
/// we will likely rework our support for UCN's.
static void ProcessUCNEscape(const char *&ThisTokBuf, const char *ThisTokEnd,
char *&ResultBuf, bool &HadError,
- SourceLocation Loc, bool IsWide, Preprocessor &PP)
+ SourceLocation Loc, bool IsWide, Preprocessor &PP,
+ bool Complain)
{
// FIXME: Add a warning - UCN's are only valid in C++ & C99.
// FIXME: Handle wide strings.
@@ -173,7 +182,8 @@ static void ProcessUCNEscape(const char *&ThisTokBuf, const char *ThisTokEnd,
ThisTokBuf += 2;
if (ThisTokBuf == ThisTokEnd || !isxdigit(*ThisTokBuf)) {
- PP.Diag(Loc, diag::err_ucn_escape_no_digits);
+ if (Complain)
+ PP.Diag(Loc, diag::err_ucn_escape_no_digits);
HadError = 1;
return;
}
@@ -189,8 +199,9 @@ static void ProcessUCNEscape(const char *&ThisTokBuf, const char *ThisTokEnd,
}
// If we didn't consume the proper number of digits, there is a problem.
if (UcnLen) {
- PP.Diag(PP.AdvanceToTokenCharacter(Loc, ThisTokBuf-ThisTokBegin),
- diag::err_ucn_escape_incomplete);
+ if (Complain)
+ PP.Diag(PP.AdvanceToTokenCharacter(Loc, ThisTokBuf-ThisTokBegin),
+ diag::err_ucn_escape_incomplete);
HadError = 1;
return;
}
@@ -199,7 +210,8 @@ static void ProcessUCNEscape(const char *&ThisTokBuf, const char *ThisTokEnd,
(UcnVal != 0x24 && UcnVal != 0x40 && UcnVal != 0x60 )) // $, @, `
|| (UcnVal >= 0xD800 && UcnVal <= 0xDFFF)
|| (UcnVal > 0x10FFFF)) /* the maximum legal UTF32 value */ {
- PP.Diag(Loc, diag::err_ucn_escape_invalid);
+ if (Complain)
+ PP.Diag(Loc, diag::err_ucn_escape_invalid);
HadError = 1;
return;
}
@@ -660,7 +672,8 @@ CharLiteralParser::CharLiteralParser(const char *begin, const char *end,
if (begin[0] != '\\') // If this is a normal character, consume it.
ResultChar = *begin++;
else // Otherwise, this is an escape character.
- ResultChar = ProcessCharEscape(begin, end, HadError, Loc, IsWide, PP);
+ ResultChar = ProcessCharEscape(begin, end, HadError, Loc, IsWide, PP,
+ /*Complain=*/true);
// If this is a multi-character constant (e.g. 'abc'), handle it. These are
// implementation defined (C99 6.4.4.4p10).
@@ -746,7 +759,7 @@ CharLiteralParser::CharLiteralParser(const char *begin, const char *end,
///
StringLiteralParser::
StringLiteralParser(const Token *StringToks, unsigned NumStringToks,
- Preprocessor &pp) : PP(pp) {
+ Preprocessor &pp, bool Complain) : PP(pp) {
// Scan all of the string portions, remember the max individual token length,
// computing a bound on the concatenated string length, and see whether any
// piece is a wide-string. If any of the string portions is a wide-string
@@ -871,13 +884,14 @@ StringLiteralParser(const Token *StringToks, unsigned NumStringToks,
// Is this a Universal Character Name escape?
if (ThisTokBuf[1] == 'u' || ThisTokBuf[1] == 'U') {
ProcessUCNEscape(ThisTokBuf, ThisTokEnd, ResultPtr,
- hadError, StringToks[i].getLocation(), ThisIsWide, PP);
+ hadError, StringToks[i].getLocation(), ThisIsWide, PP,
+ Complain);
continue;
}
// Otherwise, this is a non-UCN escape character. Process it.
unsigned ResultChar = ProcessCharEscape(ThisTokBuf, ThisTokEnd, hadError,
StringToks[i].getLocation(),
- ThisIsWide, PP);
+ ThisIsWide, PP, Complain);
// Note: our internal rep of wide char tokens is always little-endian.
*ResultPtr++ = ResultChar & 0xFF;
@@ -893,7 +907,7 @@ StringLiteralParser(const Token *StringToks, unsigned NumStringToks,
ResultBuf[0] = ResultPtr-&ResultBuf[0]-1;
// Verify that pascal strings aren't too large.
- if (GetStringLength() > 256) {
+ if (GetStringLength() > 256 && Complain) {
PP.Diag(StringToks[0].getLocation(), diag::err_pascal_string_too_long)
<< SourceRange(StringToks[0].getLocation(),
StringToks[NumStringToks-1].getLocation());
@@ -909,7 +923,8 @@ StringLiteralParser(const Token *StringToks, unsigned NumStringToks,
/// advancing over escape sequences in the string.
unsigned StringLiteralParser::getOffsetOfStringByte(const Token &Tok,
unsigned ByteNo,
- Preprocessor &PP) {
+ Preprocessor &PP,
+ bool Complain) {
// Get the spelling of the token.
llvm::SmallString<16> SpellingBuffer;
SpellingBuffer.resize(Tok.getLength());
@@ -945,7 +960,7 @@ unsigned StringLiteralParser::getOffsetOfStringByte(const Token &Tok,
// Otherwise, this is an escape character. Advance over it.
bool HadError = false;
ProcessCharEscape(SpellingPtr, SpellingEnd, HadError,
- Tok.getLocation(), false, PP);
+ Tok.getLocation(), false, PP, Complain);
assert(!HadError && "This method isn't valid on erroneous strings");
--ByteNo;
}
diff --git a/lib/Parse/AttributeList.cpp b/lib/Parse/AttributeList.cpp
index bae2a09a9882..1ebff22e4403 100644
--- a/lib/Parse/AttributeList.cpp
+++ b/lib/Parse/AttributeList.cpp
@@ -84,6 +84,7 @@ AttributeList::Kind AttributeList::getKind(const IdentifierInfo *Name) {
.Case("fastcall", AT_fastcall)
.Case("ibaction", AT_IBAction)
.Case("iboutlet", AT_IBOutlet)
+ .Case("iboutletcollection", AT_IBOutletCollection)
.Case("noreturn", AT_noreturn)
.Case("noinline", AT_noinline)
.Case("override", AT_override)
@@ -119,5 +120,10 @@ AttributeList::Kind AttributeList::getKind(const IdentifierInfo *Name) {
.Case("cf_returns_retained", AT_cf_returns_retained)
.Case("reqd_work_group_size", AT_reqd_wg_size)
.Case("no_instrument_function", AT_no_instrument_function)
+ .Case("thiscall", AT_thiscall)
+ .Case("__cdecl", AT_cdecl)
+ .Case("__stdcall", AT_stdcall)
+ .Case("__fastcall", AT_fastcall)
+ .Case("__thiscall", AT_thiscall)
.Default(UnknownAttribute);
}
diff --git a/lib/Parse/MinimalAction.cpp b/lib/Parse/MinimalAction.cpp
index 5a0376781175..b7205160c177 100644
--- a/lib/Parse/MinimalAction.cpp
+++ b/lib/Parse/MinimalAction.cpp
@@ -194,7 +194,9 @@ MinimalAction::isTemplateName(Scope *S,
UnqualifiedId &Name,
TypeTy *ObjectType,
bool EnteringScope,
- TemplateTy &TemplateDecl) {
+ TemplateTy &TemplateDecl,
+ bool &MemberOfUnknownSpecialization) {
+ MemberOfUnknownSpecialization = false;
return TNK_Non_template;
}
diff --git a/lib/Parse/ParseDecl.cpp b/lib/Parse/ParseDecl.cpp
index 91050e0a4cf9..3e7d4a13c5df 100644
--- a/lib/Parse/ParseDecl.cpp
+++ b/lib/Parse/ParseDecl.cpp
@@ -277,8 +277,8 @@ AttributeList* Parser::ParseMicrosoftTypeAttributes(AttributeList *CurrAttr) {
// Treat these like attributes
// FIXME: Allow Sema to distinguish between these and real attributes!
while (Tok.is(tok::kw___fastcall) || Tok.is(tok::kw___stdcall) ||
- Tok.is(tok::kw___cdecl) || Tok.is(tok::kw___ptr64) ||
- Tok.is(tok::kw___w64)) {
+ Tok.is(tok::kw___thiscall) || Tok.is(tok::kw___cdecl) ||
+ Tok.is(tok::kw___ptr64) || Tok.is(tok::kw___w64)) {
IdentifierInfo *AttrName = Tok.getIdentifierInfo();
SourceLocation AttrNameLoc = ConsumeToken();
if (Tok.is(tok::kw___ptr64) || Tok.is(tok::kw___w64))
@@ -364,7 +364,8 @@ Parser::DeclGroupPtrTy Parser::ParseSimpleDeclaration(unsigned Context,
// declaration-specifiers init-declarator-list[opt] ';'
if (Tok.is(tok::semi)) {
if (RequireSemi) ConsumeToken();
- DeclPtrTy TheDecl = Actions.ParsedFreeStandingDeclSpec(CurScope, DS);
+ DeclPtrTy TheDecl = Actions.ParsedFreeStandingDeclSpec(CurScope, AS_none,
+ DS);
DS.complete(TheDecl);
return Actions.ConvertDeclToDeclGroup(TheDecl);
}
@@ -838,7 +839,7 @@ void Parser::ParseDeclarationSpecifiers(DeclSpec &DS,
CCC = Action::CCC_ObjCImplementation;
Actions.CodeCompleteOrdinaryName(CurScope, CCC);
- ConsumeToken();
+ ConsumeCodeCompletionToken();
}
DS.SetRangeStart(Tok.getLocation());
@@ -1143,6 +1144,7 @@ void Parser::ParseDeclarationSpecifiers(DeclSpec &DS,
case tok::kw___cdecl:
case tok::kw___stdcall:
case tok::kw___fastcall:
+ case tok::kw___thiscall:
DS.AddAttributes(ParseMicrosoftTypeAttributes());
continue;
@@ -1622,6 +1624,7 @@ bool Parser::ParseOptionalTypeSpecifier(DeclSpec &DS, bool& isInvalid,
case tok::kw___cdecl:
case tok::kw___stdcall:
case tok::kw___fastcall:
+ case tok::kw___thiscall:
DS.AddAttributes(ParseMicrosoftTypeAttributes());
return true;
@@ -1674,7 +1677,7 @@ ParseStructDeclaration(DeclSpec &DS, FieldCallback &Fields) {
// If there are no declarators, this is a free-standing declaration
// specifier. Let the actions module cope with it.
if (Tok.is(tok::semi)) {
- Actions.ParsedFreeStandingDeclSpec(CurScope, DS);
+ Actions.ParsedFreeStandingDeclSpec(CurScope, AS_none, DS);
return;
}
@@ -1867,7 +1870,7 @@ void Parser::ParseEnumSpecifier(SourceLocation StartLoc, DeclSpec &DS,
if (Tok.is(tok::code_completion)) {
// Code completion for an enum name.
Actions.CodeCompleteTag(CurScope, DeclSpec::TST_enum);
- ConsumeToken();
+ ConsumeCodeCompletionToken();
}
llvm::OwningPtr<AttributeList> Attr;
@@ -1875,7 +1878,7 @@ void Parser::ParseEnumSpecifier(SourceLocation StartLoc, DeclSpec &DS,
if (Tok.is(tok::kw___attribute))
Attr.reset(ParseGNUAttributes());
- CXXScopeSpec SS;
+ CXXScopeSpec &SS = DS.getTypeSpecScope();
if (getLang().CPlusPlus) {
if (ParseOptionalCXXScopeSpecifier(SS, 0, false))
return;
@@ -2198,6 +2201,7 @@ bool Parser::isTypeSpecifierQualifier() {
case tok::kw___cdecl:
case tok::kw___stdcall:
case tok::kw___fastcall:
+ case tok::kw___thiscall:
case tok::kw___w64:
case tok::kw___ptr64:
return true;
@@ -2304,6 +2308,7 @@ bool Parser::isDeclarationSpecifier() {
case tok::kw___cdecl:
case tok::kw___stdcall:
case tok::kw___fastcall:
+ case tok::kw___thiscall:
case tok::kw___w64:
case tok::kw___ptr64:
case tok::kw___forceinline:
@@ -2401,6 +2406,7 @@ void Parser::ParseTypeQualifierListOpt(DeclSpec &DS, bool GNUAttributesAllowed,
case tok::kw___cdecl:
case tok::kw___stdcall:
case tok::kw___fastcall:
+ case tok::kw___thiscall:
if (GNUAttributesAllowed) {
DS.AddAttributes(ParseMicrosoftTypeAttributes());
continue;
@@ -2785,8 +2791,8 @@ void Parser::ParseParenDeclarator(Declarator &D) {
}
// Eat any Microsoft extensions.
if (Tok.is(tok::kw___cdecl) || Tok.is(tok::kw___stdcall) ||
- Tok.is(tok::kw___fastcall) || Tok.is(tok::kw___w64) ||
- Tok.is(tok::kw___ptr64)) {
+ Tok.is(tok::kw___thiscall) || Tok.is(tok::kw___fastcall) ||
+ Tok.is(tok::kw___w64) || Tok.is(tok::kw___ptr64)) {
AttrList.reset(ParseMicrosoftTypeAttributes(AttrList.take()));
}
@@ -2937,9 +2943,33 @@ void Parser::ParseFunctionDeclarator(SourceLocation LParenLoc, Declarator &D,
Diag(Tok, diag::err_argument_required_after_attribute);
delete AttrList;
}
+
// Identifier list. Note that '(' identifier-list ')' is only allowed for
- // normal declarators, not for abstract-declarators.
- return ParseFunctionDeclaratorIdentifierList(LParenLoc, D);
+ // normal declarators, not for abstract-declarators. Get the first
+ // identifier.
+ Token FirstTok = Tok;
+ ConsumeToken(); // eat the first identifier.
+
+ // Identifier lists follow a really simple grammar: the identifiers can
+ // be followed *only* by a ", moreidentifiers" or ")". However, K&R
+ // identifier lists are really rare in the brave new modern world, and it
+ // is very common for someone to typo a type in a non-k&r style list. If
+ // we are presented with something like: "void foo(intptr x, float y)",
+ // we don't want to start parsing the function declarator as though it is
+ // a K&R style declarator just because intptr is an invalid type.
+ //
+ // To handle this, we check to see if the token after the first identifier
+ // is a "," or ")". Only if so, do we parse it as an identifier list.
+ if (Tok.is(tok::comma) || Tok.is(tok::r_paren))
+ return ParseFunctionDeclaratorIdentifierList(LParenLoc,
+ FirstTok.getIdentifierInfo(),
+ FirstTok.getLocation(), D);
+
+ // If we get here, the code is invalid. Push the first identifier back
+ // into the token stream and parse the first argument as an (invalid)
+ // normal argument declarator.
+ PP.EnterToken(Tok);
+ Tok = FirstTok;
}
}
@@ -3122,13 +3152,16 @@ void Parser::ParseFunctionDeclarator(SourceLocation LParenLoc, Declarator &D,
/// ParseFunctionDeclaratorIdentifierList - While parsing a function declarator
/// we found a K&R-style identifier list instead of a type argument list. The
-/// current token is known to be the first identifier in the list.
+/// first identifier has already been consumed, and the current token is the
+/// token right after it.
///
/// identifier-list: [C99 6.7.5]
/// identifier
/// identifier-list ',' identifier
///
void Parser::ParseFunctionDeclaratorIdentifierList(SourceLocation LParenLoc,
+ IdentifierInfo *FirstIdent,
+ SourceLocation FirstIdentLoc,
Declarator &D) {
// Build up an array of information about the parsed arguments.
llvm::SmallVector<DeclaratorChunk::ParamInfo, 16> ParamInfo;
@@ -3139,17 +3172,14 @@ void Parser::ParseFunctionDeclaratorIdentifierList(SourceLocation LParenLoc,
// to be abstract. In abstract-declarators, identifier lists are not valid:
// diagnose this.
if (!D.getIdentifier())
- Diag(Tok, diag::ext_ident_list_in_param);
+ Diag(FirstIdentLoc, diag::ext_ident_list_in_param);
- // Tok is known to be the first identifier in the list. Remember this
- // identifier in ParamInfo.
- ParamsSoFar.insert(Tok.getIdentifierInfo());
- ParamInfo.push_back(DeclaratorChunk::ParamInfo(Tok.getIdentifierInfo(),
- Tok.getLocation(),
+ // The first identifier was already read, and is known to be the first
+ // identifier in the list. Remember this identifier in ParamInfo.
+ ParamsSoFar.insert(FirstIdent);
+ ParamInfo.push_back(DeclaratorChunk::ParamInfo(FirstIdent, FirstIdentLoc,
DeclPtrTy()));
- ConsumeToken(); // eat the first identifier.
-
while (Tok.is(tok::comma)) {
// Eat the comma.
ConsumeToken();
diff --git a/lib/Parse/ParseDeclCXX.cpp b/lib/Parse/ParseDeclCXX.cpp
index 015ac5b5dddd..479c04c37d7a 100644
--- a/lib/Parse/ParseDeclCXX.cpp
+++ b/lib/Parse/ParseDeclCXX.cpp
@@ -50,7 +50,7 @@ Parser::DeclPtrTy Parser::ParseNamespace(unsigned Context,
if (Tok.is(tok::code_completion)) {
Actions.CodeCompleteNamespaceDecl(CurScope);
- ConsumeToken();
+ ConsumeCodeCompletionToken();
}
SourceLocation IdentLoc;
@@ -87,6 +87,14 @@ Parser::DeclPtrTy Parser::ParseNamespace(unsigned Context,
SourceLocation LBrace = ConsumeBrace();
+ if (CurScope->isClassScope() || CurScope->isTemplateParamScope() ||
+ CurScope->isInObjcMethodScope() || CurScope->getBlockParent() ||
+ CurScope->getFnParent()) {
+ Diag(LBrace, diag::err_namespace_nonnamespace_scope);
+ SkipUntil(tok::r_brace, false);
+ return DeclPtrTy();
+ }
+
// Enter a scope for the namespace.
ParseScope NamespaceScope(this, Scope::DeclScope);
@@ -128,7 +136,7 @@ Parser::DeclPtrTy Parser::ParseNamespaceAlias(SourceLocation NamespaceLoc,
if (Tok.is(tok::code_completion)) {
Actions.CodeCompleteNamespaceAliasDecl(CurScope);
- ConsumeToken();
+ ConsumeCodeCompletionToken();
}
CXXScopeSpec SS;
@@ -223,7 +231,7 @@ Parser::DeclPtrTy Parser::ParseUsingDirectiveOrDeclaration(unsigned Context,
if (Tok.is(tok::code_completion)) {
Actions.CodeCompleteUsing(CurScope);
- ConsumeToken();
+ ConsumeCodeCompletionToken();
}
if (Tok.is(tok::kw_namespace))
@@ -260,7 +268,7 @@ Parser::DeclPtrTy Parser::ParseUsingDirective(unsigned Context,
if (Tok.is(tok::code_completion)) {
Actions.CodeCompleteUsingDirective(CurScope);
- ConsumeToken();
+ ConsumeCodeCompletionToken();
}
CXXScopeSpec SS;
@@ -602,7 +610,7 @@ void Parser::ParseClassSpecifier(tok::TokenKind TagTokKind,
if (Tok.is(tok::code_completion)) {
// Code completion for a struct, class, or union name.
Actions.CodeCompleteTag(CurScope, TagType);
- ConsumeToken();
+ ConsumeCodeCompletionToken();
}
AttributeList *AttrList = 0;
@@ -973,6 +981,7 @@ void Parser::ParseClassSpecifier(tok::TokenKind TagTokKind,
case tok::kw_typedef: // struct foo {...} typedef x;
case tok::kw_register: // struct foo {...} register x;
case tok::kw_auto: // struct foo {...} auto x;
+ case tok::kw_mutable: // struct foo {...} mutable x;
// As shown above, type qualifiers and storage class specifiers absolutely
// can occur after class specifiers according to the grammar. However,
// almost noone actually writes code like this. If we see one of these,
@@ -1298,7 +1307,7 @@ void Parser::ParseCXXClassMemberDeclaration(AccessSpecifier AS,
if (Tok.is(tok::semi)) {
ConsumeToken();
- Actions.ParsedFreeStandingDeclSpec(CurScope, DS);
+ Actions.ParsedFreeStandingDeclSpec(CurScope, AS, DS);
return;
}
diff --git a/lib/Parse/ParseExpr.cpp b/lib/Parse/ParseExpr.cpp
index b9e632a1846e..b036e568f8bb 100644
--- a/lib/Parse/ParseExpr.cpp
+++ b/lib/Parse/ParseExpr.cpp
@@ -222,7 +222,7 @@ Parser::ParseExpressionWithLeadingExtension(SourceLocation ExtLoc) {
Parser::OwningExprResult Parser::ParseAssignmentExpression() {
if (Tok.is(tok::code_completion)) {
Actions.CodeCompleteOrdinaryName(CurScope, Action::CCC_Expression);
- ConsumeToken();
+ ConsumeCodeCompletionToken();
}
if (Tok.is(tok::kw_throw))
@@ -315,8 +315,29 @@ Parser::ParseRHSOfBinaryExpression(OwningExprResult LHS, prec::Level MinPrec) {
// Eat the colon.
ColonLoc = ConsumeToken();
} else {
+ // Otherwise, we're missing a ':'. Assume that this was a typo that the
+ // user forgot. If we're not in a macro instantion, we can suggest a
+ // fixit hint. If there were two spaces before the current token,
+ // suggest inserting the colon in between them, otherwise insert ": ".
+ SourceLocation FILoc = Tok.getLocation();
+ const char *FIText = ": ";
+ if (FILoc.isFileID()) {
+ const SourceManager &SM = PP.getSourceManager();
+ bool IsInvalid = false;
+ const char *SourcePtr =
+ SM.getCharacterData(FILoc.getFileLocWithOffset(-1), &IsInvalid);
+ if (!IsInvalid && *SourcePtr == ' ') {
+ SourcePtr =
+ SM.getCharacterData(FILoc.getFileLocWithOffset(-2), &IsInvalid);
+ if (!IsInvalid && *SourcePtr == ' ') {
+ FILoc = FILoc.getFileLocWithOffset(-1);
+ FIText = ":";
+ }
+ }
+ }
+
Diag(Tok, diag::err_expected_colon)
- << FixItHint::CreateInsertion(Tok.getLocation(), ": ");
+ << FixItHint::CreateInsertion(FILoc, FIText);
Diag(OpToken, diag::note_matching) << "?";
ColonLoc = Tok.getLocation();
}
@@ -885,7 +906,7 @@ Parser::OwningExprResult Parser::ParseCastExpression(bool isUnaryExpression,
return ParsePostfixExpressionSuffix(ParseBlockLiteralExpression());
case tok::code_completion:
Actions.CodeCompleteOrdinaryName(CurScope, Action::CCC_Expression);
- ConsumeToken();
+ ConsumeCodeCompletionToken();
return ParseCastExpression(isUnaryExpression, isAddressOfOperand,
NotCastExpr, TypeOfCast);
case tok::l_square:
@@ -954,7 +975,7 @@ Parser::ParsePostfixExpressionSuffix(OwningExprResult LHS) {
if (Tok.is(tok::code_completion)) {
Actions.CodeCompleteCall(CurScope, LHS.get(), 0, 0);
- ConsumeToken();
+ ConsumeCodeCompletionToken();
}
if (Tok.isNot(tok::r_paren)) {
@@ -1008,7 +1029,7 @@ Parser::ParsePostfixExpressionSuffix(OwningExprResult LHS) {
Actions.CodeCompleteMemberReferenceExpr(CurScope, LHS.get(),
OpLoc, OpKind == tok::arrow);
- ConsumeToken();
+ ConsumeCodeCompletionToken();
}
if (MayBePseudoDestructor) {
@@ -1541,7 +1562,7 @@ bool Parser::ParseExpressionList(ExprListTy &Exprs, CommaLocsTy &CommaLocs,
if (Tok.is(tok::code_completion)) {
if (Completer)
(Actions.*Completer)(CurScope, Data, Exprs.data(), Exprs.size());
- ConsumeToken();
+ ConsumeCodeCompletionToken();
}
OwningExprResult Expr(ParseAssignmentExpression());
diff --git a/lib/Parse/ParseExprCXX.cpp b/lib/Parse/ParseExprCXX.cpp
index 146762b83ad5..46f1d94cf2c1 100644
--- a/lib/Parse/ParseExprCXX.cpp
+++ b/lib/Parse/ParseExprCXX.cpp
@@ -110,7 +110,7 @@ bool Parser::ParseOptionalCXXScopeSpecifier(CXXScopeSpec &SS,
// Code completion for a nested-name-specifier, where the code
// code completion token follows the '::'.
Actions.CodeCompleteQualifiedId(CurScope, SS, EnteringContext);
- ConsumeToken();
+ ConsumeCodeCompletionToken();
}
}
@@ -289,11 +289,13 @@ bool Parser::ParseOptionalCXXScopeSpecifier(CXXScopeSpec &SS,
TemplateTy Template;
UnqualifiedId TemplateName;
TemplateName.setIdentifier(&II, Tok.getLocation());
+ bool MemberOfUnknownSpecialization;
if (TemplateNameKind TNK = Actions.isTemplateName(CurScope, SS,
TemplateName,
ObjectType,
EnteringContext,
- Template)) {
+ Template,
+ MemberOfUnknownSpecialization)) {
// We have found a template name, so annotate this this token
// with a template-id annotation. We do not permit the
// template-id to be translated into a type annotation,
@@ -305,6 +307,31 @@ bool Parser::ParseOptionalCXXScopeSpecifier(CXXScopeSpec &SS,
SourceLocation(), false))
return true;
continue;
+ }
+
+ if (MemberOfUnknownSpecialization && (ObjectType || SS.isSet()) &&
+ IsTemplateArgumentList(1)) {
+ // We have something like t::getAs<T>, where getAs is a
+ // member of an unknown specialization. However, this will only
+ // parse correctly as a template, so suggest the keyword 'template'
+ // before 'getAs' and treat this as a dependent template name.
+ Diag(Tok.getLocation(), diag::err_missing_dependent_template_keyword)
+ << II.getName()
+ << FixItHint::CreateInsertion(Tok.getLocation(), "template ");
+
+ Template = Actions.ActOnDependentTemplateName(Tok.getLocation(), SS,
+ TemplateName, ObjectType,
+ EnteringContext);
+ if (!Template.get())
+ return true;
+
+ // Consume the identifier.
+ ConsumeToken();
+ if (AnnotateTemplateIdToken(Template, TNK_Dependent_template_name, &SS,
+ TemplateName, SourceLocation(), false))
+ return true;
+
+ continue;
}
}
@@ -576,7 +603,8 @@ Parser::ParseCXXPseudoDestructor(ExprArg Base, SourceLocation OpLoc,
// it as such.
if (Tok.is(tok::less) &&
ParseUnqualifiedIdTemplateId(SS, Name, NameLoc, false, ObjectType,
- SecondTypeName, /*AssumeTemplateName=*/true))
+ SecondTypeName, /*AssumeTemplateName=*/true,
+ /*TemplateKWLoc*/SourceLocation()))
return ExprError();
return Actions.ActOnPseudoDestructorExpr(CurScope, move(Base), OpLoc, OpKind,
@@ -688,17 +716,33 @@ Parser::ParseCXXTypeConstructExpression(const DeclSpec &DS) {
/// \param DeclResult if the condition was parsed as a declaration, the
/// parsed declaration.
///
+/// \param Loc The location of the start of the statement that requires this
+/// condition, e.g., the "for" in a for loop.
+///
+/// \param ConvertToBoolean Whether the condition expression should be
+/// converted to a boolean value.
+///
/// \returns true if there was a parsing, false otherwise.
bool Parser::ParseCXXCondition(OwningExprResult &ExprResult,
- DeclPtrTy &DeclResult) {
+ DeclPtrTy &DeclResult,
+ SourceLocation Loc,
+ bool ConvertToBoolean) {
if (Tok.is(tok::code_completion)) {
Actions.CodeCompleteOrdinaryName(CurScope, Action::CCC_Condition);
- ConsumeToken();
+ ConsumeCodeCompletionToken();
}
if (!isCXXConditionDeclaration()) {
+ // Parse the expression.
ExprResult = ParseExpression(); // expression
DeclResult = DeclPtrTy();
+ if (ExprResult.isInvalid())
+ return true;
+
+ // If required, convert to a boolean value.
+ if (ConvertToBoolean)
+ ExprResult
+ = Actions.ActOnBooleanCondition(CurScope, Loc, move(ExprResult));
return ExprResult.isInvalid();
}
@@ -746,6 +790,9 @@ bool Parser::ParseCXXCondition(OwningExprResult &ExprResult,
Diag(Tok, diag::err_expected_equal_after_declarator);
}
+ // FIXME: Build a reference to this declaration? Convert it to bool?
+ // (This is currently handled by Sema).
+
return false;
}
@@ -952,8 +999,10 @@ bool Parser::ParseUnqualifiedIdTemplateId(CXXScopeSpec &SS,
bool EnteringContext,
TypeTy *ObjectType,
UnqualifiedId &Id,
- bool AssumeTemplateId) {
- assert(Tok.is(tok::less) && "Expected '<' to finish parsing a template-id");
+ bool AssumeTemplateId,
+ SourceLocation TemplateKWLoc) {
+ assert((AssumeTemplateId || Tok.is(tok::less)) &&
+ "Expected '<' to finish parsing a template-id");
TemplateTy Template;
TemplateNameKind TNK = TNK_Non_template;
@@ -962,30 +1011,63 @@ bool Parser::ParseUnqualifiedIdTemplateId(CXXScopeSpec &SS,
case UnqualifiedId::IK_OperatorFunctionId:
case UnqualifiedId::IK_LiteralOperatorId:
if (AssumeTemplateId) {
- Template = Actions.ActOnDependentTemplateName(SourceLocation(), SS,
+ Template = Actions.ActOnDependentTemplateName(TemplateKWLoc, SS,
Id, ObjectType,
EnteringContext);
TNK = TNK_Dependent_template_name;
if (!Template.get())
return true;
- } else
+ } else {
+ bool MemberOfUnknownSpecialization;
TNK = Actions.isTemplateName(CurScope, SS, Id, ObjectType,
- EnteringContext, Template);
+ EnteringContext, Template,
+ MemberOfUnknownSpecialization);
+
+ if (TNK == TNK_Non_template && MemberOfUnknownSpecialization &&
+ ObjectType && IsTemplateArgumentList()) {
+ // We have something like t->getAs<T>(), where getAs is a
+ // member of an unknown specialization. However, this will only
+ // parse correctly as a template, so suggest the keyword 'template'
+ // before 'getAs' and treat this as a dependent template name.
+ std::string Name;
+ if (Id.getKind() == UnqualifiedId::IK_Identifier)
+ Name = Id.Identifier->getName();
+ else {
+ Name = "operator ";
+ if (Id.getKind() == UnqualifiedId::IK_OperatorFunctionId)
+ Name += getOperatorSpelling(Id.OperatorFunctionId.Operator);
+ else
+ Name += Id.Identifier->getName();
+ }
+ Diag(Id.StartLocation, diag::err_missing_dependent_template_keyword)
+ << Name
+ << FixItHint::CreateInsertion(Id.StartLocation, "template ");
+ Template = Actions.ActOnDependentTemplateName(TemplateKWLoc, SS,
+ Id, ObjectType,
+ EnteringContext);
+ TNK = TNK_Dependent_template_name;
+ if (!Template.get())
+ return true;
+ }
+ }
break;
case UnqualifiedId::IK_ConstructorName: {
UnqualifiedId TemplateName;
+ bool MemberOfUnknownSpecialization;
TemplateName.setIdentifier(Name, NameLoc);
TNK = Actions.isTemplateName(CurScope, SS, TemplateName, ObjectType,
- EnteringContext, Template);
+ EnteringContext, Template,
+ MemberOfUnknownSpecialization);
break;
}
case UnqualifiedId::IK_DestructorName: {
UnqualifiedId TemplateName;
+ bool MemberOfUnknownSpecialization;
TemplateName.setIdentifier(Name, NameLoc);
if (ObjectType) {
- Template = Actions.ActOnDependentTemplateName(SourceLocation(), SS,
+ Template = Actions.ActOnDependentTemplateName(TemplateKWLoc, SS,
TemplateName, ObjectType,
EnteringContext);
TNK = TNK_Dependent_template_name;
@@ -993,7 +1075,8 @@ bool Parser::ParseUnqualifiedIdTemplateId(CXXScopeSpec &SS,
return true;
} else {
TNK = Actions.isTemplateName(CurScope, SS, TemplateName, ObjectType,
- EnteringContext, Template);
+ EnteringContext, Template,
+ MemberOfUnknownSpecialization);
if (TNK == TNK_Non_template && Id.DestructorName == 0) {
Diag(NameLoc, diag::err_destructor_template_id)
@@ -1014,7 +1097,8 @@ bool Parser::ParseUnqualifiedIdTemplateId(CXXScopeSpec &SS,
// Parse the enclosed template argument list.
SourceLocation LAngleLoc, RAngleLoc;
TemplateArgList TemplateArgs;
- if (ParseTemplateIdAfterTemplateName(Template, Id.StartLocation,
+ if (Tok.is(tok::less) &&
+ ParseTemplateIdAfterTemplateName(Template, Id.StartLocation,
&SS, true, LAngleLoc,
TemplateArgs,
RAngleLoc))
@@ -1190,7 +1274,7 @@ bool Parser::ParseUnqualifiedIdOperator(CXXScopeSpec &SS, bool EnteringContext,
Actions.CodeCompleteOperatorName(CurScope);
// Consume the operator token.
- ConsumeToken();
+ ConsumeCodeCompletionToken();
// Don't try to parse any further.
return true;
@@ -1293,6 +1377,17 @@ bool Parser::ParseUnqualifiedId(CXXScopeSpec &SS, bool EnteringContext,
bool AllowConstructorName,
TypeTy *ObjectType,
UnqualifiedId &Result) {
+
+ // Handle 'A::template B'. This is for template-ids which have not
+ // already been annotated by ParseOptionalCXXScopeSpecifier().
+ bool TemplateSpecified = false;
+ SourceLocation TemplateKWLoc;
+ if (getLang().CPlusPlus && Tok.is(tok::kw_template) &&
+ (ObjectType || SS.isSet())) {
+ TemplateSpecified = true;
+ TemplateKWLoc = ConsumeToken();
+ }
+
// unqualified-id:
// identifier
// template-id (when it hasn't already been annotated)
@@ -1320,9 +1415,10 @@ bool Parser::ParseUnqualifiedId(CXXScopeSpec &SS, bool EnteringContext,
}
// If the next token is a '<', we may have a template.
- if (Tok.is(tok::less))
+ if (TemplateSpecified || Tok.is(tok::less))
return ParseUnqualifiedIdTemplateId(SS, Id, IdLoc, EnteringContext,
- ObjectType, Result);
+ ObjectType, Result,
+ TemplateSpecified, TemplateKWLoc);
return false;
}
@@ -1383,10 +1479,11 @@ bool Parser::ParseUnqualifiedId(CXXScopeSpec &SS, bool EnteringContext,
// operator-function-id < template-argument-list[opt] >
if ((Result.getKind() == UnqualifiedId::IK_OperatorFunctionId ||
Result.getKind() == UnqualifiedId::IK_LiteralOperatorId) &&
- Tok.is(tok::less))
+ (TemplateSpecified || Tok.is(tok::less)))
return ParseUnqualifiedIdTemplateId(SS, 0, SourceLocation(),
EnteringContext, ObjectType,
- Result);
+ Result,
+ TemplateSpecified, TemplateKWLoc);
return false;
}
@@ -1411,10 +1508,11 @@ bool Parser::ParseUnqualifiedId(CXXScopeSpec &SS, bool EnteringContext,
IdentifierInfo *ClassName = Tok.getIdentifierInfo();
SourceLocation ClassNameLoc = ConsumeToken();
- if (Tok.is(tok::less)) {
+ if (TemplateSpecified || Tok.is(tok::less)) {
Result.setDestructorName(TildeLoc, 0, ClassNameLoc);
return ParseUnqualifiedIdTemplateId(SS, ClassName, ClassNameLoc,
- EnteringContext, ObjectType, Result);
+ EnteringContext, ObjectType, Result,
+ TemplateSpecified, TemplateKWLoc);
}
// Note that this is a destructor name.
diff --git a/lib/Parse/ParseObjc.cpp b/lib/Parse/ParseObjc.cpp
index 7b1ecf6437dc..9cfe73456a5f 100644
--- a/lib/Parse/ParseObjc.cpp
+++ b/lib/Parse/ParseObjc.cpp
@@ -32,7 +32,7 @@ Parser::DeclPtrTy Parser::ParseObjCAtDirectives() {
if (Tok.is(tok::code_completion)) {
Actions.CodeCompleteObjCAtDirective(CurScope, ObjCImpDecl, false);
- ConsumeToken();
+ ConsumeCodeCompletionToken();
}
switch (Tok.getObjCKeywordID()) {
@@ -131,7 +131,7 @@ Parser::DeclPtrTy Parser::ParseObjCAtInterfaceDeclaration(
// Code completion after '@interface'.
if (Tok.is(tok::code_completion)) {
Actions.CodeCompleteObjCInterfaceDecl(CurScope);
- ConsumeToken();
+ ConsumeCodeCompletionToken();
}
if (Tok.isNot(tok::identifier)) {
@@ -149,7 +149,7 @@ Parser::DeclPtrTy Parser::ParseObjCAtInterfaceDeclaration(
IdentifierInfo *categoryId = 0;
if (Tok.is(tok::code_completion)) {
Actions.CodeCompleteObjCInterfaceCategory(CurScope, nameId, nameLoc);
- ConsumeToken();
+ ConsumeCodeCompletionToken();
}
// For ObjC2, the category name is optional (not an error).
@@ -204,7 +204,7 @@ Parser::DeclPtrTy Parser::ParseObjCAtInterfaceDeclaration(
// Code completion of superclass names.
if (Tok.is(tok::code_completion)) {
Actions.CodeCompleteObjCSuperclass(CurScope, nameId, nameLoc);
- ConsumeToken();
+ ConsumeCodeCompletionToken();
}
if (Tok.isNot(tok::identifier)) {
@@ -350,7 +350,7 @@ void Parser::ParseObjCInterfaceDeclList(DeclPtrTy interfaceDecl,
Actions.CodeCompleteOrdinaryName(CurScope,
ObjCImpDecl? Action::CCC_ObjCImplementation
: Action::CCC_ObjCInterface);
- ConsumeToken();
+ ConsumeCodeCompletionToken();
}
// If we don't have an @ directive, parse it as a function definition.
@@ -371,7 +371,7 @@ void Parser::ParseObjCInterfaceDeclList(DeclPtrTy interfaceDecl,
SourceLocation AtLoc = ConsumeToken(); // the "@"
if (Tok.is(tok::code_completion)) {
Actions.CodeCompleteObjCAtDirective(CurScope, ObjCImpDecl, true);
- ConsumeToken();
+ ConsumeCodeCompletionToken();
break;
}
@@ -438,7 +438,7 @@ void Parser::ParseObjCInterfaceDeclList(DeclPtrTy interfaceDecl,
// EOF. In the former case, eat the @end. In the later case, emit an error.
if (Tok.is(tok::code_completion)) {
Actions.CodeCompleteObjCAtDirective(CurScope, ObjCImpDecl, true);
- ConsumeToken();
+ ConsumeCodeCompletionToken();
} else if (Tok.isObjCAtKeyword(tok::objc_end))
ConsumeToken(); // the "end" identifier
else
@@ -446,7 +446,7 @@ void Parser::ParseObjCInterfaceDeclList(DeclPtrTy interfaceDecl,
// Insert collected methods declarations into the @interface object.
// This passes in an invalid SourceLocation for AtEndLoc when EOF is hit.
- Actions.ActOnAtEnd(AtEnd, interfaceDecl,
+ Actions.ActOnAtEnd(CurScope, AtEnd, interfaceDecl,
allMethods.data(), allMethods.size(),
allProperties.data(), allProperties.size(),
allTUVariables.data(), allTUVariables.size());
@@ -477,7 +477,7 @@ void Parser::ParseObjCPropertyAttribute(ObjCDeclSpec &DS, DeclPtrTy ClassDecl,
while (1) {
if (Tok.is(tok::code_completion)) {
Actions.CodeCompleteObjCPropertyFlags(CurScope, DS);
- ConsumeToken();
+ ConsumeCodeCompletionToken();
}
const IdentifierInfo *II = Tok.getIdentifierInfo();
@@ -514,7 +514,7 @@ void Parser::ParseObjCPropertyAttribute(ObjCDeclSpec &DS, DeclPtrTy ClassDecl,
else
Actions.CodeCompleteObjCPropertyGetter(CurScope, ClassDecl,
Methods, NumMethods);
- ConsumeToken();
+ ConsumeCodeCompletionToken();
}
if (Tok.isNot(tok::identifier)) {
@@ -782,7 +782,7 @@ Parser::DeclPtrTy Parser::ParseObjCMethodDecl(SourceLocation mLoc,
if (Tok.is(tok::code_completion)) {
Actions.CodeCompleteObjCMethodDecl(CurScope, mType == tok::minus,
/*ReturnType=*/0, IDecl);
- ConsumeToken();
+ ConsumeCodeCompletionToken();
}
// Parse the return type if present.
@@ -799,7 +799,7 @@ Parser::DeclPtrTy Parser::ParseObjCMethodDecl(SourceLocation mLoc,
if (Tok.is(tok::code_completion)) {
Actions.CodeCompleteObjCMethodDecl(CurScope, mType == tok::minus,
ReturnType, IDecl);
- ConsumeToken();
+ ConsumeCodeCompletionToken();
}
// Now parse the selector.
@@ -945,7 +945,7 @@ ParseObjCProtocolReferences(llvm::SmallVectorImpl<Action::DeclPtrTy> &Protocols,
if (Tok.is(tok::code_completion)) {
Actions.CodeCompleteObjCProtocolReferences(ProtocolIdents.data(),
ProtocolIdents.size());
- ConsumeToken();
+ ConsumeCodeCompletionToken();
}
if (Tok.isNot(tok::identifier)) {
@@ -1026,7 +1026,7 @@ void Parser::ParseObjCClassInstanceVariables(DeclPtrTy interfaceDecl,
if (Tok.is(tok::code_completion)) {
Actions.CodeCompleteObjCAtVisibility(CurScope);
- ConsumeToken();
+ ConsumeCodeCompletionToken();
}
switch (Tok.getObjCKeywordID()) {
@@ -1046,7 +1046,7 @@ void Parser::ParseObjCClassInstanceVariables(DeclPtrTy interfaceDecl,
if (Tok.is(tok::code_completion)) {
Actions.CodeCompleteOrdinaryName(CurScope,
Action::CCC_ObjCInstanceVariableList);
- ConsumeToken();
+ ConsumeCodeCompletionToken();
}
struct ObjCIvarCallback : FieldCallback {
@@ -1117,7 +1117,7 @@ Parser::DeclPtrTy Parser::ParseObjCAtProtocolDeclaration(SourceLocation AtLoc,
if (Tok.is(tok::code_completion)) {
Actions.CodeCompleteObjCProtocolDecl(CurScope);
- ConsumeToken();
+ ConsumeCodeCompletionToken();
}
if (Tok.isNot(tok::identifier)) {
@@ -1203,7 +1203,7 @@ Parser::DeclPtrTy Parser::ParseObjCAtImplementationDeclaration(
// Code completion after '@implementation'.
if (Tok.is(tok::code_completion)) {
Actions.CodeCompleteObjCImplementationDecl(CurScope);
- ConsumeToken();
+ ConsumeCodeCompletionToken();
}
if (Tok.isNot(tok::identifier)) {
@@ -1222,7 +1222,7 @@ Parser::DeclPtrTy Parser::ParseObjCAtImplementationDeclaration(
if (Tok.is(tok::code_completion)) {
Actions.CodeCompleteObjCImplementationCategory(CurScope, nameId, nameLoc);
- ConsumeToken();
+ ConsumeCodeCompletionToken();
}
if (Tok.is(tok::identifier)) {
@@ -1277,7 +1277,7 @@ Parser::DeclPtrTy Parser::ParseObjCAtEndDeclaration(SourceRange atEnd) {
DeclPtrTy Result = ObjCImpDecl;
ConsumeToken(); // the "end" identifier
if (ObjCImpDecl) {
- Actions.ActOnAtEnd(atEnd, ObjCImpDecl);
+ Actions.ActOnAtEnd(CurScope, atEnd, ObjCImpDecl);
ObjCImpDecl = DeclPtrTy();
PendingObjCImpDecl.pop_back();
}
@@ -1292,7 +1292,7 @@ Parser::DeclGroupPtrTy Parser::RetrievePendingObjCImpDecl() {
if (PendingObjCImpDecl.empty())
return Actions.ConvertDeclToDeclGroup(DeclPtrTy());
DeclPtrTy ImpDecl = PendingObjCImpDecl.pop_back_val();
- Actions.ActOnAtEnd(SourceRange(), ImpDecl);
+ Actions.ActOnAtEnd(CurScope, SourceRange(), ImpDecl);
return Actions.ConvertDeclToDeclGroup(ImpDecl);
}
@@ -1342,7 +1342,7 @@ Parser::DeclPtrTy Parser::ParseObjCPropertySynthesize(SourceLocation atLoc) {
while (true) {
if (Tok.is(tok::code_completion)) {
Actions.CodeCompleteObjCPropertyDefinition(CurScope, ObjCImpDecl);
- ConsumeToken();
+ ConsumeCodeCompletionToken();
}
if (Tok.isNot(tok::identifier)) {
@@ -1361,7 +1361,7 @@ Parser::DeclPtrTy Parser::ParseObjCPropertySynthesize(SourceLocation atLoc) {
if (Tok.is(tok::code_completion)) {
Actions.CodeCompleteObjCPropertySynthesizeIvar(CurScope, propertyId,
ObjCImpDecl);
- ConsumeToken();
+ ConsumeCodeCompletionToken();
}
if (Tok.isNot(tok::identifier)) {
@@ -1371,7 +1371,7 @@ Parser::DeclPtrTy Parser::ParseObjCPropertySynthesize(SourceLocation atLoc) {
propertyIvar = Tok.getIdentifierInfo();
ConsumeToken(); // consume ivar-name
}
- Actions.ActOnPropertyImplDecl(atLoc, propertyLoc, true, ObjCImpDecl,
+ Actions.ActOnPropertyImplDecl(CurScope, atLoc, propertyLoc, true, ObjCImpDecl,
propertyId, propertyIvar);
if (Tok.isNot(tok::comma))
break;
@@ -1400,7 +1400,7 @@ Parser::DeclPtrTy Parser::ParseObjCPropertyDynamic(SourceLocation atLoc) {
while (true) {
if (Tok.is(tok::code_completion)) {
Actions.CodeCompleteObjCPropertyDefinition(CurScope, ObjCImpDecl);
- ConsumeToken();
+ ConsumeCodeCompletionToken();
}
if (Tok.isNot(tok::identifier)) {
@@ -1411,7 +1411,7 @@ Parser::DeclPtrTy Parser::ParseObjCPropertyDynamic(SourceLocation atLoc) {
IdentifierInfo *propertyId = Tok.getIdentifierInfo();
SourceLocation propertyLoc = ConsumeToken(); // consume property name
- Actions.ActOnPropertyImplDecl(atLoc, propertyLoc, false, ObjCImpDecl,
+ Actions.ActOnPropertyImplDecl(CurScope, atLoc, propertyLoc, false, ObjCImpDecl,
propertyId, 0);
if (Tok.isNot(tok::comma))
@@ -1654,7 +1654,7 @@ Parser::DeclPtrTy Parser::ParseObjCMethodDefinition() {
Parser::OwningStmtResult Parser::ParseObjCAtStatement(SourceLocation AtLoc) {
if (Tok.is(tok::code_completion)) {
Actions.CodeCompleteObjCAtStatement(CurScope);
- ConsumeToken();
+ ConsumeCodeCompletionToken();
return StmtError();
}
@@ -1685,7 +1685,7 @@ Parser::OwningExprResult Parser::ParseObjCAtExpression(SourceLocation AtLoc) {
switch (Tok.getKind()) {
case tok::code_completion:
Actions.CodeCompleteObjCAtExpression(CurScope);
- ConsumeToken();
+ ConsumeCodeCompletionToken();
return ExprError();
case tok::string_literal: // primary-expression: string-literal
@@ -1925,7 +1925,7 @@ Parser::ParseObjCMessageExpressionBody(SourceLocation LBracLoc,
else
Actions.CodeCompleteObjCInstanceMessage(CurScope, ReceiverExpr.get(),
0, 0);
- ConsumeToken();
+ ConsumeCodeCompletionToken();
}
// Parse objc-selector
@@ -1979,7 +1979,7 @@ Parser::ParseObjCMessageExpressionBody(SourceLocation LBracLoc,
Actions.CodeCompleteObjCInstanceMessage(CurScope, ReceiverExpr.get(),
KeyIdents.data(),
KeyIdents.size());
- ConsumeToken();
+ ConsumeCodeCompletionToken();
}
// Check for another keyword selector.
diff --git a/lib/Parse/ParsePragma.cpp b/lib/Parse/ParsePragma.cpp
index 812d8e2af901..c4e4a525e560 100644
--- a/lib/Parse/ParsePragma.cpp
+++ b/lib/Parse/ParsePragma.cpp
@@ -23,7 +23,6 @@ using namespace clang;
// pack '(' 'show' ')'
// pack '(' ('push' | 'pop') [',' identifier] [, integer] ')'
void PragmaPackHandler::HandlePragma(Preprocessor &PP, Token &PackTok) {
- // FIXME: Should we be expanding macros here? My guess is no.
SourceLocation PackLoc = PackTok.getLocation();
Token Tok;
@@ -100,17 +99,67 @@ void PragmaPackHandler::HandlePragma(Preprocessor &PP, Token &PackTok) {
return;
}
+ SourceLocation RParenLoc = Tok.getLocation();
PP.Lex(Tok);
if (Tok.isNot(tok::eom)) {
PP.Diag(Tok.getLocation(), diag::warn_pragma_extra_tokens_at_eol) << "pack";
return;
}
- SourceLocation RParenLoc = Tok.getLocation();
Actions.ActOnPragmaPack(Kind, Name, Alignment.release(), PackLoc,
LParenLoc, RParenLoc);
}
+// #pragma 'options' 'align' '=' {'natural', 'mac68k', 'power', 'reset'}
+void PragmaOptionsHandler::HandlePragma(Preprocessor &PP, Token &OptionsTok) {
+ SourceLocation OptionsLoc = OptionsTok.getLocation();
+
+ Token Tok;
+ PP.Lex(Tok);
+ if (Tok.isNot(tok::identifier) || !Tok.getIdentifierInfo()->isStr("align")) {
+ PP.Diag(Tok.getLocation(), diag::warn_pragma_options_expected_align);
+ return;
+ }
+
+ PP.Lex(Tok);
+ if (Tok.isNot(tok::equal)) {
+ PP.Diag(Tok.getLocation(), diag::warn_pragma_options_expected_equal);
+ return;
+ }
+
+ PP.Lex(Tok);
+ if (Tok.isNot(tok::identifier)) {
+ PP.Diag(Tok.getLocation(), diag::warn_pragma_expected_identifier)
+ << "options";
+ return;
+ }
+
+ Action::PragmaOptionsAlignKind Kind = Action::POAK_Natural;
+ const IdentifierInfo *II = Tok.getIdentifierInfo();
+ if (II->isStr("natural"))
+ Kind = Action::POAK_Natural;
+ else if (II->isStr("power"))
+ Kind = Action::POAK_Power;
+ else if (II->isStr("mac68k"))
+ Kind = Action::POAK_Mac68k;
+ else if (II->isStr("reset"))
+ Kind = Action::POAK_Reset;
+ else {
+ PP.Diag(Tok.getLocation(), diag::warn_pragma_options_invalid_option);
+ return;
+ }
+
+ SourceLocation KindLoc = Tok.getLocation();
+ PP.Lex(Tok);
+ if (Tok.isNot(tok::eom)) {
+ PP.Diag(Tok.getLocation(), diag::warn_pragma_extra_tokens_at_eol)
+ << "options";
+ return;
+ }
+
+ Actions.ActOnPragmaOptionsAlign(Kind, OptionsLoc, KindLoc);
+}
+
// #pragma unused(identifier)
void PragmaUnusedHandler::HandlePragma(Preprocessor &PP, Token &UnusedTok) {
// FIXME: Should we be expanding macros here? My guess is no.
diff --git a/lib/Parse/ParsePragma.h b/lib/Parse/ParsePragma.h
index db385c6371e3..d9d06a1dc6e6 100644
--- a/lib/Parse/ParsePragma.h
+++ b/lib/Parse/ParsePragma.h
@@ -20,6 +20,15 @@ namespace clang {
class Action;
class Parser;
+class PragmaOptionsHandler : public PragmaHandler {
+ Action &Actions;
+public:
+ PragmaOptionsHandler(const IdentifierInfo *N, Action &A) : PragmaHandler(N),
+ Actions(A) {}
+
+ virtual void HandlePragma(Preprocessor &PP, Token &FirstToken);
+};
+
class PragmaPackHandler : public PragmaHandler {
Action &Actions;
public:
diff --git a/lib/Parse/ParseStmt.cpp b/lib/Parse/ParseStmt.cpp
index 9b2227002f1b..98c005837e7c 100644
--- a/lib/Parse/ParseStmt.cpp
+++ b/lib/Parse/ParseStmt.cpp
@@ -283,7 +283,7 @@ Parser::OwningStmtResult Parser::ParseCaseStatement(AttributeList *Attr) {
if (Tok.is(tok::code_completion)) {
Actions.CodeCompleteCase(CurScope);
- ConsumeToken();
+ ConsumeCodeCompletionToken();
}
/// We don't want to treat 'case x : y' as a potential typo for 'case x::y'.
@@ -536,15 +536,23 @@ Parser::OwningStmtResult Parser::ParseCompoundStatementBody(bool isStmtExpr) {
/// successfully parsed. Note that a successful parse can still have semantic
/// errors in the condition.
bool Parser::ParseParenExprOrCondition(OwningExprResult &ExprResult,
- DeclPtrTy &DeclResult) {
+ DeclPtrTy &DeclResult,
+ SourceLocation Loc,
+ bool ConvertToBoolean) {
bool ParseError = false;
SourceLocation LParenLoc = ConsumeParen();
if (getLang().CPlusPlus)
- ParseError = ParseCXXCondition(ExprResult, DeclResult);
+ ParseError = ParseCXXCondition(ExprResult, DeclResult, Loc,
+ ConvertToBoolean);
else {
ExprResult = ParseExpression();
DeclResult = DeclPtrTy();
+
+ // If required, convert to a boolean value.
+ if (!ExprResult.isInvalid() && ConvertToBoolean)
+ ExprResult
+ = Actions.ActOnBooleanCondition(CurScope, Loc, move(ExprResult));
}
// If the parser was confused by the condition and we don't have a ')', try to
@@ -603,7 +611,7 @@ Parser::OwningStmtResult Parser::ParseIfStatement(AttributeList *Attr) {
// Parse the condition.
OwningExprResult CondExp(Actions);
DeclPtrTy CondVar;
- if (ParseParenExprOrCondition(CondExp, CondVar))
+ if (ParseParenExprOrCondition(CondExp, CondVar, IfLoc, true))
return StmtError();
FullExprArg FullCondExp(Actions.MakeFullExpr(CondExp));
@@ -735,13 +743,25 @@ Parser::OwningStmtResult Parser::ParseSwitchStatement(AttributeList *Attr) {
// Parse the condition.
OwningExprResult Cond(Actions);
DeclPtrTy CondVar;
- if (ParseParenExprOrCondition(Cond, CondVar))
+ if (ParseParenExprOrCondition(Cond, CondVar, SwitchLoc, false))
return StmtError();
- FullExprArg FullCond(Actions.MakeFullExpr(Cond));
+ OwningStmtResult Switch
+ = Actions.ActOnStartOfSwitchStmt(SwitchLoc, move(Cond), CondVar);
+
+ if (Switch.isInvalid()) {
+ // Skip the switch body.
+ // FIXME: This is not optimal recovery, but parsing the body is more
+ // dangerous due to the presence of case and default statements, which
+ // will have no place to connect back with the switch.
+ if (Tok.is(tok::l_brace)) {
+ ConsumeBrace();
+ SkipUntil(tok::r_brace, false, false);
+ } else
+ SkipUntil(tok::semi);
+ return move(Switch);
+ }
- OwningStmtResult Switch = Actions.ActOnStartOfSwitchStmt(FullCond, CondVar);
-
// C99 6.8.4p3 - In C99, the body of the switch statement is a scope, even if
// there is no compound stmt. C90 does not have this clause. We only do this
// if the body isn't a compound statement to avoid push/pop in common cases.
@@ -763,11 +783,6 @@ Parser::OwningStmtResult Parser::ParseSwitchStatement(AttributeList *Attr) {
InnerScope.Exit();
SwitchScope.Exit();
- if (Cond.isInvalid() && !CondVar.get()) {
- Actions.ActOnSwitchBodyError(SwitchLoc, move(Switch), move(Body));
- return StmtError();
- }
-
if (Body.isInvalid())
// FIXME: Remove the case statement list from the Switch statement.
Body = Actions.ActOnNullStmt(Tok.getLocation());
@@ -818,7 +833,7 @@ Parser::OwningStmtResult Parser::ParseWhileStatement(AttributeList *Attr) {
// Parse the condition.
OwningExprResult Cond(Actions);
DeclPtrTy CondVar;
- if (ParseParenExprOrCondition(Cond, CondVar))
+ if (ParseParenExprOrCondition(Cond, CondVar, WhileLoc, true))
return StmtError();
FullExprArg FullCond(Actions.MakeFullExpr(Cond));
@@ -975,14 +990,17 @@ Parser::OwningStmtResult Parser::ParseForStatement(AttributeList *Attr) {
bool ForEach = false;
OwningStmtResult FirstPart(Actions);
- OwningExprResult SecondPart(Actions), ThirdPart(Actions);
+ bool SecondPartIsInvalid = false;
+ FullExprArg SecondPart(Actions);
+ OwningExprResult Collection(Actions);
+ FullExprArg ThirdPart(Actions);
DeclPtrTy SecondVar;
if (Tok.is(tok::code_completion)) {
Actions.CodeCompleteOrdinaryName(CurScope,
C99orCXXorObjC? Action::CCC_ForInit
: Action::CCC_Expression);
- ConsumeToken();
+ ConsumeCodeCompletionToken();
}
// Parse the first part of the for specifier.
@@ -1009,7 +1027,7 @@ Parser::OwningStmtResult Parser::ParseForStatement(AttributeList *Attr) {
Actions.ActOnForEachDeclStmt(DG);
// ObjC: for (id x in expr)
ConsumeToken(); // consume 'in'
- SecondPart = ParseExpression();
+ Collection = ParseExpression();
} else {
Diag(Tok, diag::err_expected_semi_for);
SkipUntil(tok::semi);
@@ -1025,35 +1043,44 @@ Parser::OwningStmtResult Parser::ParseForStatement(AttributeList *Attr) {
ConsumeToken();
} else if ((ForEach = isTokIdentifier_in())) {
ConsumeToken(); // consume 'in'
- SecondPart = ParseExpression();
+ Collection = ParseExpression();
} else {
if (!Value.isInvalid()) Diag(Tok, diag::err_expected_semi_for);
SkipUntil(tok::semi);
}
}
if (!ForEach) {
- assert(!SecondPart.get() && "Shouldn't have a second expression yet.");
+ assert(!SecondPart->get() && "Shouldn't have a second expression yet.");
// Parse the second part of the for specifier.
if (Tok.is(tok::semi)) { // for (...;;
// no second part.
} else {
+ OwningExprResult Second(Actions);
if (getLang().CPlusPlus)
- ParseCXXCondition(SecondPart, SecondVar);
- else
- SecondPart = ParseExpression();
+ ParseCXXCondition(Second, SecondVar, ForLoc, true);
+ else {
+ Second = ParseExpression();
+ if (!Second.isInvalid())
+ Second = Actions.ActOnBooleanCondition(CurScope, ForLoc,
+ move(Second));
+ }
+ SecondPartIsInvalid = Second.isInvalid();
+ SecondPart = Actions.MakeFullExpr(Second);
}
if (Tok.is(tok::semi)) {
ConsumeToken();
} else {
- if (!SecondPart.isInvalid() || SecondVar.get())
+ if (!SecondPartIsInvalid || SecondVar.get())
Diag(Tok, diag::err_expected_semi_for);
SkipUntil(tok::semi);
}
// Parse the third part of the for specifier.
- if (Tok.isNot(tok::r_paren)) // for (...;...;)
- ThirdPart = ParseExpression();
+ if (Tok.isNot(tok::r_paren)) { // for (...;...;)
+ OwningExprResult Third = ParseExpression();
+ ThirdPart = Actions.MakeFullExpr(Third);
+ }
}
// Match the ')'.
SourceLocation RParenLoc = MatchRHSPunctuation(tok::r_paren, LParenLoc);
@@ -1085,15 +1112,14 @@ Parser::OwningStmtResult Parser::ParseForStatement(AttributeList *Attr) {
return StmtError();
if (!ForEach)
- return Actions.ActOnForStmt(ForLoc, LParenLoc, move(FirstPart),
- Actions.MakeFullExpr(SecondPart), SecondVar,
- Actions.MakeFullExpr(ThirdPart), RParenLoc,
- move(Body));
-
- return Actions.ActOnObjCForCollectionStmt(ForLoc, LParenLoc,
- move(FirstPart),
- move(SecondPart),
- RParenLoc, move(Body));
+ return Actions.ActOnForStmt(ForLoc, LParenLoc, move(FirstPart), SecondPart,
+ SecondVar, ThirdPart, RParenLoc, move(Body));
+
+ // FIXME: It isn't clear how to communicate the late destruction of
+ // C++ temporaries used to create the collection.
+ return Actions.ActOnObjCForCollectionStmt(ForLoc, LParenLoc, move(FirstPart),
+ move(Collection), RParenLoc,
+ move(Body));
}
/// ParseGotoStatement
diff --git a/lib/Parse/ParseTemplate.cpp b/lib/Parse/ParseTemplate.cpp
index ff6995340151..c87ddad4e9b3 100644
--- a/lib/Parse/ParseTemplate.cpp
+++ b/lib/Parse/ParseTemplate.cpp
@@ -201,7 +201,7 @@ Parser::ParseSingleDeclarationAfterTemplate(
if (Tok.is(tok::semi)) {
DeclEnd = ConsumeToken();
- DeclPtrTy Decl = Actions.ParsedFreeStandingDeclSpec(CurScope, DS);
+ DeclPtrTy Decl = Actions.ParsedFreeStandingDeclSpec(CurScope, AS, DS);
DS.complete(Decl);
return Decl;
}
@@ -902,10 +902,12 @@ ParsedTemplateArgument Parser::ParseTemplateTemplateArgument() {
ConsumeToken(); // the identifier
if (isEndOfTemplateArgument(Tok)) {
+ bool MemberOfUnknownSpecialization;
TemplateNameKind TNK = Actions.isTemplateName(CurScope, SS, Name,
/*ObjectType=*/0,
/*EnteringContext=*/false,
- Template);
+ Template,
+ MemberOfUnknownSpecialization);
if (TNK == TNK_Dependent_template_name || TNK == TNK_Type_template) {
// We have an id-expression that refers to a class template or
// (C++0x) template alias.
@@ -966,6 +968,37 @@ ParsedTemplateArgument Parser::ParseTemplateArgument() {
ExprArg.release(), Loc);
}
+/// \brief Determine whether the current tokens can only be parsed as a
+/// template argument list (starting with the '<') and never as a '<'
+/// expression.
+bool Parser::IsTemplateArgumentList(unsigned Skip) {
+ struct AlwaysRevertAction : TentativeParsingAction {
+ AlwaysRevertAction(Parser &P) : TentativeParsingAction(P) { }
+ ~AlwaysRevertAction() { Revert(); }
+ } Tentative(*this);
+
+ while (Skip) {
+ ConsumeToken();
+ --Skip;
+ }
+
+ // '<'
+ if (!Tok.is(tok::less))
+ return false;
+ ConsumeToken();
+
+ // An empty template argument list.
+ if (Tok.is(tok::greater))
+ return true;
+
+ // See whether we have declaration specifiers, which indicate a type.
+ while (isCXXDeclarationSpecifier() == TPResult::True())
+ ConsumeToken();
+
+ // If we have a '>' or a ',' then this is a template argument list.
+ return Tok.is(tok::greater) || Tok.is(tok::comma);
+}
+
/// ParseTemplateArgumentList - Parse a C++ template-argument-list
/// (C++ [temp.names]). Returns true if there was an error.
///
diff --git a/lib/Parse/ParseTentative.cpp b/lib/Parse/ParseTentative.cpp
index a6c6d3f94535..5e64e6162b73 100644
--- a/lib/Parse/ParseTentative.cpp
+++ b/lib/Parse/ParseTentative.cpp
@@ -753,6 +753,7 @@ Parser::TPResult Parser::isCXXDeclarationSpecifier() {
case tok::kw___cdecl:
case tok::kw___stdcall:
case tok::kw___fastcall:
+ case tok::kw___thiscall:
case tok::kw___w64:
case tok::kw___ptr64:
case tok::kw___forceinline:
diff --git a/lib/Parse/Parser.cpp b/lib/Parse/Parser.cpp
index 6dbb99e395f9..296897080d0f 100644
--- a/lib/Parse/Parser.cpp
+++ b/lib/Parse/Parser.cpp
@@ -33,6 +33,11 @@ Parser::Parser(Preprocessor &pp, Action &actions)
// Add #pragma handlers. These are removed and destroyed in the
// destructor.
+ OptionsHandler.reset(new
+ PragmaOptionsHandler(&PP.getIdentifierTable().get("options"),
+ actions));
+ PP.AddPragmaHandler(0, OptionsHandler.get());
+
PackHandler.reset(new
PragmaPackHandler(&PP.getIdentifierTable().get("pack"), actions));
PP.AddPragmaHandler(0, PackHandler.get());
@@ -134,7 +139,7 @@ SourceLocation Parser::MatchRHSPunctuation(tok::TokenKind RHSTok,
/// returned.
bool Parser::ExpectAndConsume(tok::TokenKind ExpectedTok, unsigned DiagID,
const char *Msg, tok::TokenKind SkipToTok) {
- if (Tok.is(ExpectedTok)) {
+ if (Tok.is(ExpectedTok) || Tok.is(tok::code_completion)) {
ConsumeAnyToken();
return false;
}
@@ -189,7 +194,11 @@ bool Parser::SkipUntil(const tok::TokenKind *Toks, unsigned NumToks,
case tok::eof:
// Ran out of tokens.
return false;
-
+
+ case tok::code_completion:
+ ConsumeToken();
+ return false;
+
case tok::l_paren:
// Recursively skip properly-nested parens.
ConsumeParen();
@@ -294,6 +303,8 @@ Parser::~Parser() {
delete ScopeCache[i];
// Remove the pragma handlers we installed.
+ PP.RemovePragmaHandler(0, OptionsHandler.get());
+ OptionsHandler.reset();
PP.RemovePragmaHandler(0, PackHandler.get());
PackHandler.reset();
PP.RemovePragmaHandler(0, UnusedHandler.get());
@@ -447,7 +458,7 @@ Parser::DeclGroupPtrTy Parser::ParseExternalDeclaration(CXX0XAttributeList Attr)
Actions.CodeCompleteOrdinaryName(CurScope,
ObjCImpDecl? Action::CCC_ObjCImplementation
: Action::CCC_Namespace);
- ConsumeToken();
+ ConsumeCodeCompletionToken();
return ParseExternalDeclaration(Attr);
case tok::kw_using:
case tok::kw_namespace:
@@ -538,7 +549,7 @@ Parser::ParseDeclarationOrFunctionDefinition(ParsingDeclSpec &DS,
// declaration-specifiers init-declarator-list[opt] ';'
if (Tok.is(tok::semi)) {
ConsumeToken();
- DeclPtrTy TheDecl = Actions.ParsedFreeStandingDeclSpec(CurScope, DS);
+ DeclPtrTy TheDecl = Actions.ParsedFreeStandingDeclSpec(CurScope, AS, DS);
DS.complete(TheDecl);
return Actions.ConvertDeclToDeclGroup(TheDecl);
}
@@ -980,10 +991,11 @@ bool Parser::TryAnnotateTypeOrScopeToken(bool EnteringContext) {
TemplateTy Template;
UnqualifiedId TemplateName;
TemplateName.setIdentifier(Tok.getIdentifierInfo(), Tok.getLocation());
+ bool MemberOfUnknownSpecialization;
if (TemplateNameKind TNK
= Actions.isTemplateName(CurScope, SS, TemplateName,
/*ObjectType=*/0, EnteringContext,
- Template)) {
+ Template, MemberOfUnknownSpecialization)) {
// Consume the identifier.
ConsumeToken();
if (AnnotateTemplateIdToken(Template, TNK, &SS, TemplateName)) {
@@ -1071,6 +1083,22 @@ bool Parser::TryAnnotateCXXScopeToken(bool EnteringContext) {
return false;
}
+void Parser::CodeCompletionRecovery() {
+ for (Scope *S = CurScope; S; S = S->getParent()) {
+ if (S->getFlags() & Scope::FnScope) {
+ Actions.CodeCompleteOrdinaryName(CurScope, Action::CCC_RecoveryInFunction);
+ return;
+ }
+
+ if (S->getFlags() & Scope::ClassScope) {
+ Actions.CodeCompleteOrdinaryName(CurScope, Action::CCC_Class);
+ return;
+ }
+ }
+
+ Actions.CodeCompleteOrdinaryName(CurScope, Action::CCC_Namespace);
+}
+
// Anchor the Parser::FieldCallback vtable to this translation unit.
// We use a spurious method instead of the destructor because
// destroying FieldCallbacks can actually be slightly
diff --git a/lib/Sema/AnalysisBasedWarnings.cpp b/lib/Sema/AnalysisBasedWarnings.cpp
index 6ded0a34601e..448d16116a39 100644
--- a/lib/Sema/AnalysisBasedWarnings.cpp
+++ b/lib/Sema/AnalysisBasedWarnings.cpp
@@ -54,8 +54,13 @@ static void CheckUnreachable(Sema &S, AnalysisContext &AC) {
// Check for missing return value.
//===----------------------------------------------------------------------===//
-enum ControlFlowKind { NeverFallThrough = 0, MaybeFallThrough = 1,
- AlwaysFallThrough = 2, NeverFallThroughOrReturn = 3 };
+enum ControlFlowKind {
+ UnknownFallThrough,
+ NeverFallThrough,
+ MaybeFallThrough,
+ AlwaysFallThrough,
+ NeverFallThroughOrReturn
+};
/// CheckFallThrough - Check that we don't fall off the end of a
/// Statement that should return a value.
@@ -68,9 +73,7 @@ enum ControlFlowKind { NeverFallThrough = 0, MaybeFallThrough = 1,
/// will return.
static ControlFlowKind CheckFallThrough(AnalysisContext &AC) {
CFG *cfg = AC.getCFG();
- if (cfg == 0)
- // FIXME: This should be NeverFallThrough
- return NeverFallThroughOrReturn;
+ if (cfg == 0) return UnknownFallThrough;
// The CFG leaves in dead things, and we don't want the dead code paths to
// confuse us, so we mark all live things first.
@@ -164,6 +167,19 @@ static ControlFlowKind CheckFallThrough(AnalysisContext &AC) {
}
}
}
+ // FIXME: Remove this hack once temporaries and their destructors are
+ // modeled correctly by the CFG.
+ if (CXXExprWithTemporaries *E = dyn_cast<CXXExprWithTemporaries>(S)) {
+ for (unsigned I = 0, N = E->getNumTemporaries(); I != N; ++I) {
+ const FunctionDecl *FD = E->getTemporary(I)->getDestructor();
+ if (FD->hasAttr<NoReturnAttr>() ||
+ FD->getType()->getAs<FunctionType>()->getNoReturnAttr()) {
+ NoReturnEdge = true;
+ HasFakeEdge = true;
+ break;
+ }
+ }
+ }
// FIXME: Add noreturn message sends.
if (NoReturnEdge == false)
HasPlainEdge = true;
@@ -290,6 +306,9 @@ static void CheckFallThroughForBody(Sema &S, const Decl *D, const Stmt *Body,
// FIXME: Function try block
if (const CompoundStmt *Compound = dyn_cast<CompoundStmt>(Body)) {
switch (CheckFallThrough(AC)) {
+ case UnknownFallThrough:
+ break;
+
case MaybeFallThrough:
if (HasNoReturn)
S.Diag(Compound->getRBracLoc(),
diff --git a/lib/Sema/CMakeLists.txt b/lib/Sema/CMakeLists.txt
index ac0dfd6c3af5..b54e8ebfb969 100644
--- a/lib/Sema/CMakeLists.txt
+++ b/lib/Sema/CMakeLists.txt
@@ -34,4 +34,4 @@ add_clang_library(clangSema
TargetAttributesSema.cpp
)
-add_dependencies(clangSema ClangDiagnosticSema)
+add_dependencies(clangSema ClangDiagnosticSema ClangStmtNodes)
diff --git a/lib/Sema/CodeCompleteConsumer.cpp b/lib/Sema/CodeCompleteConsumer.cpp
index 0ef9a15faaf9..6cefc61f6640 100644
--- a/lib/Sema/CodeCompleteConsumer.cpp
+++ b/lib/Sema/CodeCompleteConsumer.cpp
@@ -210,9 +210,10 @@ CodeCompletionString::Chunk::Destroy() {
}
}
-CodeCompletionString::~CodeCompletionString() {
+void CodeCompletionString::clear() {
std::for_each(Chunks.begin(), Chunks.end(),
std::mem_fun_ref(&Chunk::Destroy));
+ Chunks.clear();
}
std::string CodeCompletionString::getAsString() const {
@@ -310,15 +311,13 @@ void CodeCompletionString::Serialize(llvm::raw_ostream &OS) const {
}
}
-CodeCompletionString *CodeCompletionString::Deserialize(const char *&Str,
- const char *StrEnd) {
+bool CodeCompletionString::Deserialize(const char *&Str, const char *StrEnd) {
if (Str == StrEnd || *Str == 0)
- return 0;
+ return false;
- CodeCompletionString *Result = new CodeCompletionString;
unsigned NumBlocks;
if (ReadUnsigned(Str, StrEnd, NumBlocks))
- return Result;
+ return false;
for (unsigned I = 0; I != NumBlocks; ++I) {
if (Str + 1 >= StrEnd)
@@ -327,7 +326,7 @@ CodeCompletionString *CodeCompletionString::Deserialize(const char *&Str,
// Parse the next kind.
unsigned KindValue;
if (ReadUnsigned(Str, StrEnd, KindValue))
- return Result;
+ return false;
switch (ChunkKind Kind = (ChunkKind)KindValue) {
case CK_TypedText:
@@ -338,16 +337,17 @@ CodeCompletionString *CodeCompletionString::Deserialize(const char *&Str,
case CK_CurrentParameter: {
unsigned StrLen;
if (ReadUnsigned(Str, StrEnd, StrLen) || (Str + StrLen > StrEnd))
- return Result;
+ return false;
- Result->AddChunk(Chunk(Kind, StringRef(Str, StrLen)));
+ AddChunk(Chunk(Kind, StringRef(Str, StrLen)));
Str += StrLen;
break;
}
case CK_Optional: {
- std::auto_ptr<CodeCompletionString> Optional(Deserialize(Str, StrEnd));
- Result->AddOptionalChunk(Optional);
+ std::auto_ptr<CodeCompletionString> Optional(new CodeCompletionString());
+ if (Optional->Deserialize(Str, StrEnd))
+ AddOptionalChunk(Optional);
break;
}
@@ -365,12 +365,12 @@ CodeCompletionString *CodeCompletionString::Deserialize(const char *&Str,
case CK_Equal:
case CK_HorizontalSpace:
case CK_VerticalSpace:
- Result->AddChunk(Chunk(Kind));
+ AddChunk(Chunk(Kind));
break;
}
};
- return Result;
+ return true;
}
void CodeCompleteConsumer::Result::Destroy() {
@@ -380,6 +380,25 @@ void CodeCompleteConsumer::Result::Destroy() {
}
}
+unsigned CodeCompleteConsumer::Result::getPriorityFromDecl(NamedDecl *ND) {
+ if (!ND)
+ return CCP_Unlikely;
+
+ // Context-based decisions.
+ DeclContext *DC = ND->getDeclContext()->getLookupContext();
+ if (DC->isFunctionOrMethod() || isa<BlockDecl>(DC))
+ return CCP_LocalDeclaration;
+ if (DC->isRecord() || isa<ObjCContainerDecl>(DC))
+ return CCP_MemberDeclaration;
+
+ // Content-based decisions.
+ if (isa<EnumConstantDecl>(ND))
+ return CCP_Constant;
+ if (isa<TypeDecl>(ND) || isa<ObjCInterfaceDecl>(ND))
+ return CCP_Type;
+ return CCP_Declaration;
+}
+
//===----------------------------------------------------------------------===//
// Code completion overload candidate implementation
//===----------------------------------------------------------------------===//
@@ -459,11 +478,6 @@ PrintingCodeCompleteConsumer::ProcessCodeCompleteResults(Sema &SemaRef,
}
}
}
-
- // Once we've printed the code-completion results, suppress remaining
- // diagnostics.
- // FIXME: Move this somewhere else!
- SemaRef.PP.getDiagnostics().setSuppressAllDiagnostics();
}
void
@@ -478,11 +492,6 @@ PrintingCodeCompleteConsumer::ProcessOverloadCandidates(Sema &SemaRef,
delete CCS;
}
}
-
- // Once we've printed the code-completion results, suppress remaining
- // diagnostics.
- // FIXME: Move this somewhere else!
- SemaRef.PP.getDiagnostics().setSuppressAllDiagnostics();
}
void
@@ -594,16 +603,12 @@ CIndexCodeCompleteConsumer::ProcessCodeCompleteResults(Sema &SemaRef,
}
WriteUnsigned(OS, Kind);
+ WriteUnsigned(OS, Results[I].Priority);
CodeCompletionString *CCS = Results[I].CreateCodeCompletionString(SemaRef);
assert(CCS && "No code-completion string?");
CCS->Serialize(OS);
delete CCS;
}
-
- // Once we've printed the code-completion results, suppress remaining
- // diagnostics.
- // FIXME: Move this somewhere else!
- SemaRef.PP.getDiagnostics().setSuppressAllDiagnostics();
}
void
@@ -613,15 +618,11 @@ CIndexCodeCompleteConsumer::ProcessOverloadCandidates(Sema &SemaRef,
unsigned NumCandidates) {
for (unsigned I = 0; I != NumCandidates; ++I) {
WriteUnsigned(OS, CXCursor_NotImplemented);
+ WriteUnsigned(OS, /*Priority=*/0);
CodeCompletionString *CCS
= Candidates[I].CreateSignatureString(CurrentArg, SemaRef);
assert(CCS && "No code-completion string?");
CCS->Serialize(OS);
delete CCS;
}
-
- // Once we've printed the code-completion results, suppress remaining
- // diagnostics.
- // FIXME: Move this somewhere else!
- SemaRef.PP.getDiagnostics().setSuppressAllDiagnostics();
}
diff --git a/lib/Sema/JumpDiagnostics.cpp b/lib/Sema/JumpDiagnostics.cpp
index 069429490385..543c1b61edeb 100644
--- a/lib/Sema/JumpDiagnostics.cpp
+++ b/lib/Sema/JumpDiagnostics.cpp
@@ -12,6 +12,7 @@
//
//===----------------------------------------------------------------------===//
+#include "llvm/ADT/BitVector.h"
#include "Sema.h"
#include "clang/AST/Expr.h"
#include "clang/AST/StmtObjC.h"
@@ -39,33 +40,47 @@ class JumpScopeChecker {
/// the parent scope is the function body.
unsigned ParentScope;
- /// Diag - The diagnostic to emit if there is a jump into this scope.
- unsigned Diag;
+ /// InDiag - The diagnostic to emit if there is a jump into this scope.
+ unsigned InDiag;
+
+ /// OutDiag - The diagnostic to emit if there is an indirect jump out
+ /// of this scope. Direct jumps always clean up their current scope
+ /// in an orderly way.
+ unsigned OutDiag;
/// Loc - Location to emit the diagnostic.
SourceLocation Loc;
- GotoScope(unsigned parentScope, unsigned diag, SourceLocation L)
- : ParentScope(parentScope), Diag(diag), Loc(L) {}
+ GotoScope(unsigned parentScope, unsigned InDiag, unsigned OutDiag,
+ SourceLocation L)
+ : ParentScope(parentScope), InDiag(InDiag), OutDiag(OutDiag), Loc(L) {}
};
llvm::SmallVector<GotoScope, 48> Scopes;
llvm::DenseMap<Stmt*, unsigned> LabelAndGotoScopes;
llvm::SmallVector<Stmt*, 16> Jumps;
+
+ llvm::SmallVector<IndirectGotoStmt*, 4> IndirectJumps;
+ llvm::SmallVector<LabelStmt*, 4> IndirectJumpTargets;
public:
JumpScopeChecker(Stmt *Body, Sema &S);
private:
void BuildScopeInformation(Stmt *S, unsigned ParentScope);
void VerifyJumps();
+ void VerifyIndirectJumps();
+ void DiagnoseIndirectJump(IndirectGotoStmt *IG, unsigned IGScope,
+ LabelStmt *Target, unsigned TargetScope);
void CheckJump(Stmt *From, Stmt *To,
SourceLocation DiagLoc, unsigned JumpDiag);
+
+ unsigned GetDeepestCommonScope(unsigned A, unsigned B);
};
} // end anonymous namespace
JumpScopeChecker::JumpScopeChecker(Stmt *Body, Sema &s) : S(s) {
// Add a scope entry for function scope.
- Scopes.push_back(GotoScope(~0U, ~0U, SourceLocation()));
+ Scopes.push_back(GotoScope(~0U, ~0U, ~0U, SourceLocation()));
// Build information for the top level compound statement, so that we have a
// defined scope record for every "goto" and label.
@@ -73,29 +88,64 @@ JumpScopeChecker::JumpScopeChecker(Stmt *Body, Sema &s) : S(s) {
// Check that all jumps we saw are kosher.
VerifyJumps();
+ VerifyIndirectJumps();
+}
+
+/// GetDeepestCommonScope - Finds the innermost scope enclosing the
+/// two scopes.
+unsigned JumpScopeChecker::GetDeepestCommonScope(unsigned A, unsigned B) {
+ while (A != B) {
+ // Inner scopes are created after outer scopes and therefore have
+ // higher indices.
+ if (A < B) {
+ assert(Scopes[B].ParentScope < B);
+ B = Scopes[B].ParentScope;
+ } else {
+ assert(Scopes[A].ParentScope < A);
+ A = Scopes[A].ParentScope;
+ }
+ }
+ return A;
}
/// GetDiagForGotoScopeDecl - If this decl induces a new goto scope, return a
/// diagnostic that should be emitted if control goes over it. If not, return 0.
-static unsigned GetDiagForGotoScopeDecl(const Decl *D, bool isCPlusPlus) {
+static std::pair<unsigned,unsigned>
+ GetDiagForGotoScopeDecl(const Decl *D, bool isCPlusPlus) {
if (const VarDecl *VD = dyn_cast<VarDecl>(D)) {
+ unsigned InDiag = 0, OutDiag = 0;
if (VD->getType()->isVariablyModifiedType())
- return diag::note_protected_by_vla;
- if (VD->hasAttr<CleanupAttr>())
- return diag::note_protected_by_cleanup;
- if (VD->hasAttr<BlocksAttr>())
- return diag::note_protected_by___block;
- // FIXME: In C++0x, we have to check more conditions than "did we
- // just give it an initializer?". See 6.7p3.
- if (isCPlusPlus && VD->hasLocalStorage() && VD->hasInit())
- return diag::note_protected_by_variable_init;
+ InDiag = diag::note_protected_by_vla;
+
+ if (VD->hasAttr<BlocksAttr>()) {
+ InDiag = diag::note_protected_by___block;
+ OutDiag = diag::note_exits___block;
+ } else if (VD->hasAttr<CleanupAttr>()) {
+ InDiag = diag::note_protected_by_cleanup;
+ OutDiag = diag::note_exits_cleanup;
+ } else if (isCPlusPlus) {
+ // FIXME: In C++0x, we have to check more conditions than "did we
+ // just give it an initializer?". See 6.7p3.
+ if (VD->hasLocalStorage() && VD->hasInit())
+ InDiag = diag::note_protected_by_variable_init;
+
+ CanQualType T = VD->getType()->getCanonicalTypeUnqualified();
+ while (CanQual<ArrayType> AT = T->getAs<ArrayType>())
+ T = AT->getElementType();
+ if (CanQual<RecordType> RT = T->getAs<RecordType>())
+ if (!cast<CXXRecordDecl>(RT->getDecl())->hasTrivialDestructor())
+ OutDiag = diag::note_exits_dtor;
+ }
- } else if (const TypedefDecl *TD = dyn_cast<TypedefDecl>(D)) {
+ return std::make_pair(InDiag, OutDiag);
+ }
+
+ if (const TypedefDecl *TD = dyn_cast<TypedefDecl>(D)) {
if (TD->getUnderlyingType()->isVariablyModifiedType())
- return diag::note_protected_by_vla_typedef;
+ return std::make_pair((unsigned) diag::note_protected_by_vla_typedef, 0);
}
- return 0;
+ return std::make_pair(0U, 0U);
}
@@ -106,14 +156,32 @@ static unsigned GetDiagForGotoScopeDecl(const Decl *D, bool isCPlusPlus) {
void JumpScopeChecker::BuildScopeInformation(Stmt *S, unsigned ParentScope) {
// If we found a label, remember that it is in ParentScope scope.
- if (isa<LabelStmt>(S) || isa<DefaultStmt>(S) || isa<CaseStmt>(S)) {
+ switch (S->getStmtClass()) {
+ case Stmt::LabelStmtClass:
+ case Stmt::DefaultStmtClass:
+ case Stmt::CaseStmtClass:
+ LabelAndGotoScopes[S] = ParentScope;
+ break;
+
+ case Stmt::AddrLabelExprClass:
+ IndirectJumpTargets.push_back(cast<AddrLabelExpr>(S)->getLabel());
+ break;
+
+ case Stmt::IndirectGotoStmtClass:
LabelAndGotoScopes[S] = ParentScope;
- } else if (isa<GotoStmt>(S) || isa<SwitchStmt>(S) ||
- isa<IndirectGotoStmt>(S) || isa<AddrLabelExpr>(S)) {
+ IndirectJumps.push_back(cast<IndirectGotoStmt>(S));
+ break;
+
+ case Stmt::GotoStmtClass:
+ case Stmt::SwitchStmtClass:
// Remember both what scope a goto is in as well as the fact that we have
// it. This makes the second scan not have to walk the AST again.
LabelAndGotoScopes[S] = ParentScope;
Jumps.push_back(S);
+ break;
+
+ default:
+ break;
}
for (Stmt::child_iterator CI = S->child_begin(), E = S->child_end(); CI != E;
@@ -131,8 +199,11 @@ void JumpScopeChecker::BuildScopeInformation(Stmt *S, unsigned ParentScope) {
for (DeclStmt::decl_iterator I = DS->decl_begin(), E = DS->decl_end();
I != E; ++I) {
// If this decl causes a new scope, push and switch to it.
- if (unsigned Diag = GetDiagForGotoScopeDecl(*I, isCPlusPlus)) {
- Scopes.push_back(GotoScope(ParentScope, Diag, (*I)->getLocation()));
+ std::pair<unsigned,unsigned> Diags
+ = GetDiagForGotoScopeDecl(*I, isCPlusPlus);
+ if (Diags.first || Diags.second) {
+ Scopes.push_back(GotoScope(ParentScope, Diags.first, Diags.second,
+ (*I)->getLocation()));
ParentScope = Scopes.size()-1;
}
@@ -149,7 +220,9 @@ void JumpScopeChecker::BuildScopeInformation(Stmt *S, unsigned ParentScope) {
// walking all sub-stmts in that scope.
if (ObjCAtTryStmt *AT = dyn_cast<ObjCAtTryStmt>(SubStmt)) {
// Recursively walk the AST for the @try part.
- Scopes.push_back(GotoScope(ParentScope,diag::note_protected_by_objc_try,
+ Scopes.push_back(GotoScope(ParentScope,
+ diag::note_protected_by_objc_try,
+ diag::note_exits_objc_try,
AT->getAtTryLoc()));
if (Stmt *TryPart = AT->getTryBody())
BuildScopeInformation(TryPart, Scopes.size()-1);
@@ -159,6 +232,7 @@ void JumpScopeChecker::BuildScopeInformation(Stmt *S, unsigned ParentScope) {
ObjCAtCatchStmt *AC = AT->getCatchStmt(I);
Scopes.push_back(GotoScope(ParentScope,
diag::note_protected_by_objc_catch,
+ diag::note_exits_objc_catch,
AC->getAtCatchLoc()));
// @catches are nested and it isn't
BuildScopeInformation(AC->getCatchBody(), Scopes.size()-1);
@@ -168,6 +242,7 @@ void JumpScopeChecker::BuildScopeInformation(Stmt *S, unsigned ParentScope) {
if (ObjCAtFinallyStmt *AF = AT->getFinallyStmt()) {
Scopes.push_back(GotoScope(ParentScope,
diag::note_protected_by_objc_finally,
+ diag::note_exits_objc_finally,
AF->getAtFinallyLoc()));
BuildScopeInformation(AF, Scopes.size()-1);
}
@@ -186,6 +261,7 @@ void JumpScopeChecker::BuildScopeInformation(Stmt *S, unsigned ParentScope) {
// scope.
Scopes.push_back(GotoScope(ParentScope,
diag::note_protected_by_objc_synchronized,
+ diag::note_exits_objc_synchronized,
AS->getAtSynchronizedLoc()));
BuildScopeInformation(AS->getSynchBody(), Scopes.size()-1);
continue;
@@ -194,7 +270,9 @@ void JumpScopeChecker::BuildScopeInformation(Stmt *S, unsigned ParentScope) {
// Disallow jumps into any part of a C++ try statement. This is pretty
// much the same as for Obj-C.
if (CXXTryStmt *TS = dyn_cast<CXXTryStmt>(SubStmt)) {
- Scopes.push_back(GotoScope(ParentScope, diag::note_protected_by_cxx_try,
+ Scopes.push_back(GotoScope(ParentScope,
+ diag::note_protected_by_cxx_try,
+ diag::note_exits_cxx_try,
TS->getSourceRange().getBegin()));
if (Stmt *TryBlock = TS->getTryBlock())
BuildScopeInformation(TryBlock, Scopes.size()-1);
@@ -204,6 +282,7 @@ void JumpScopeChecker::BuildScopeInformation(Stmt *S, unsigned ParentScope) {
CXXCatchStmt *CS = TS->getHandler(I);
Scopes.push_back(GotoScope(ParentScope,
diag::note_protected_by_cxx_catch,
+ diag::note_exits_cxx_catch,
CS->getSourceRange().getBegin()));
BuildScopeInformation(CS->getHandlerBlock(), Scopes.size()-1);
}
@@ -229,54 +308,178 @@ void JumpScopeChecker::VerifyJumps() {
continue;
}
- if (SwitchStmt *SS = dyn_cast<SwitchStmt>(Jump)) {
- for (SwitchCase *SC = SS->getSwitchCaseList(); SC;
- SC = SC->getNextSwitchCase()) {
- assert(LabelAndGotoScopes.count(SC) && "Case not visited?");
- CheckJump(SS, SC, SC->getLocStart(),
- diag::err_switch_into_protected_scope);
- }
- continue;
+ SwitchStmt *SS = cast<SwitchStmt>(Jump);
+ for (SwitchCase *SC = SS->getSwitchCaseList(); SC;
+ SC = SC->getNextSwitchCase()) {
+ assert(LabelAndGotoScopes.count(SC) && "Case not visited?");
+ CheckJump(SS, SC, SC->getLocStart(),
+ diag::err_switch_into_protected_scope);
}
+ }
+}
- unsigned DiagnosticScope;
-
- // We don't know where an indirect goto goes, require that it be at the
- // top level of scoping.
- if (IndirectGotoStmt *IG = dyn_cast<IndirectGotoStmt>(Jump)) {
- assert(LabelAndGotoScopes.count(Jump) &&
- "Jump didn't get added to scopes?");
- unsigned GotoScope = LabelAndGotoScopes[IG];
- if (GotoScope == 0) continue; // indirect jump is ok.
- S.Diag(IG->getGotoLoc(), diag::err_indirect_goto_in_protected_scope);
- DiagnosticScope = GotoScope;
- } else {
- // We model &&Label as a jump for purposes of scope tracking. We actually
- // don't care *where* the address of label is, but we require the *label
- // itself* to be in scope 0. If it is nested inside of a VLA scope, then
- // it is possible for an indirect goto to illegally enter the VLA scope by
- // indirectly jumping to the label.
- assert(isa<AddrLabelExpr>(Jump) && "Unknown jump type");
- LabelStmt *TheLabel = cast<AddrLabelExpr>(Jump)->getLabel();
-
- assert(LabelAndGotoScopes.count(TheLabel) &&
- "Referenced label didn't get added to scopes?");
- unsigned LabelScope = LabelAndGotoScopes[TheLabel];
- if (LabelScope == 0) continue; // Addr of label is ok.
-
- S.Diag(Jump->getLocStart(), diag::err_addr_of_label_in_protected_scope);
- DiagnosticScope = LabelScope;
+/// VerifyIndirectJumps - Verify whether any possible indirect jump
+/// might cross a protection boundary. Unlike direct jumps, indirect
+/// jumps count cleanups as protection boundaries: since there's no
+/// way to know where the jump is going, we can't implicitly run the
+/// right cleanups the way we can with direct jumps.
+///
+/// Thus, an indirect jump is "trivial" if it bypasses no
+/// initializations and no teardowns. More formally, an indirect jump
+/// from A to B is trivial if the path out from A to DCA(A,B) is
+/// trivial and the path in from DCA(A,B) to B is trivial, where
+/// DCA(A,B) is the deepest common ancestor of A and B.
+/// Jump-triviality is transitive but asymmetric.
+///
+/// A path in is trivial if none of the entered scopes have an InDiag.
+/// A path out is trivial is none of the exited scopes have an OutDiag.
+///
+/// Under these definitions, this function checks that the indirect
+/// jump between A and B is trivial for every indirect goto statement A
+/// and every label B whose address was taken in the function.
+void JumpScopeChecker::VerifyIndirectJumps() {
+ if (IndirectJumps.empty()) return;
+
+ // If there aren't any address-of-label expressions in this function,
+ // complain about the first indirect goto.
+ if (IndirectJumpTargets.empty()) {
+ S.Diag(IndirectJumps[0]->getGotoLoc(),
+ diag::err_indirect_goto_without_addrlabel);
+ return;
+ }
+
+ // Collect a single representative of every scope containing an
+ // indirect goto. For most code bases, this substantially cuts
+ // down on the number of jump sites we'll have to consider later.
+ typedef std::pair<unsigned, IndirectGotoStmt*> JumpScope;
+ llvm::SmallVector<JumpScope, 32> JumpScopes;
+ {
+ llvm::DenseMap<unsigned, IndirectGotoStmt*> JumpScopesMap;
+ for (llvm::SmallVectorImpl<IndirectGotoStmt*>::iterator
+ I = IndirectJumps.begin(), E = IndirectJumps.end(); I != E; ++I) {
+ IndirectGotoStmt *IG = *I;
+ assert(LabelAndGotoScopes.count(IG) &&
+ "indirect jump didn't get added to scopes?");
+ unsigned IGScope = LabelAndGotoScopes[IG];
+ IndirectGotoStmt *&Entry = JumpScopesMap[IGScope];
+ if (!Entry) Entry = IG;
+ }
+ JumpScopes.reserve(JumpScopesMap.size());
+ for (llvm::DenseMap<unsigned, IndirectGotoStmt*>::iterator
+ I = JumpScopesMap.begin(), E = JumpScopesMap.end(); I != E; ++I)
+ JumpScopes.push_back(*I);
+ }
+
+ // Collect a single representative of every scope containing a
+ // label whose address was taken somewhere in the function.
+ // For most code bases, there will be only one such scope.
+ llvm::DenseMap<unsigned, LabelStmt*> TargetScopes;
+ for (llvm::SmallVectorImpl<LabelStmt*>::iterator
+ I = IndirectJumpTargets.begin(), E = IndirectJumpTargets.end();
+ I != E; ++I) {
+ LabelStmt *TheLabel = *I;
+ assert(LabelAndGotoScopes.count(TheLabel) &&
+ "Referenced label didn't get added to scopes?");
+ unsigned LabelScope = LabelAndGotoScopes[TheLabel];
+ LabelStmt *&Target = TargetScopes[LabelScope];
+ if (!Target) Target = TheLabel;
+ }
+
+ // For each target scope, make sure it's trivially reachable from
+ // every scope containing a jump site.
+ //
+ // A path between scopes always consists of exitting zero or more
+ // scopes, then entering zero or more scopes. We build a set of
+ // of scopes S from which the target scope can be trivially
+ // entered, then verify that every jump scope can be trivially
+ // exitted to reach a scope in S.
+ llvm::BitVector Reachable(Scopes.size(), false);
+ for (llvm::DenseMap<unsigned,LabelStmt*>::iterator
+ TI = TargetScopes.begin(), TE = TargetScopes.end(); TI != TE; ++TI) {
+ unsigned TargetScope = TI->first;
+ LabelStmt *TargetLabel = TI->second;
+
+ Reachable.reset();
+
+ // Mark all the enclosing scopes from which you can safely jump
+ // into the target scope. 'Min' will end up being the index of
+ // the shallowest such scope.
+ unsigned Min = TargetScope;
+ while (true) {
+ Reachable.set(Min);
+
+ // Don't go beyond the outermost scope.
+ if (Min == 0) break;
+
+ // Stop if we can't trivially enter the current scope.
+ if (Scopes[Min].InDiag) break;
+
+ Min = Scopes[Min].ParentScope;
}
- // Report all the things that would be skipped over by this &&label or
- // indirect goto.
- while (DiagnosticScope != 0) {
- S.Diag(Scopes[DiagnosticScope].Loc, Scopes[DiagnosticScope].Diag);
- DiagnosticScope = Scopes[DiagnosticScope].ParentScope;
+ // Walk through all the jump sites, checking that they can trivially
+ // reach this label scope.
+ for (llvm::SmallVectorImpl<JumpScope>::iterator
+ I = JumpScopes.begin(), E = JumpScopes.end(); I != E; ++I) {
+ unsigned Scope = I->first;
+
+ // Walk out the "scope chain" for this scope, looking for a scope
+ // we've marked reachable. For well-formed code this amortizes
+ // to O(JumpScopes.size() / Scopes.size()): we only iterate
+ // when we see something unmarked, and in well-formed code we
+ // mark everything we iterate past.
+ bool IsReachable = false;
+ while (true) {
+ if (Reachable.test(Scope)) {
+ // If we find something reachable, mark all the scopes we just
+ // walked through as reachable.
+ for (unsigned S = I->first; S != Scope; S = Scopes[S].ParentScope)
+ Reachable.set(S);
+ IsReachable = true;
+ break;
+ }
+
+ // Don't walk out if we've reached the top-level scope or we've
+ // gotten shallower than the shallowest reachable scope.
+ if (Scope == 0 || Scope < Min) break;
+
+ // Don't walk out through an out-diagnostic.
+ if (Scopes[Scope].OutDiag) break;
+
+ Scope = Scopes[Scope].ParentScope;
+ }
+
+ // Only diagnose if we didn't find something.
+ if (IsReachable) continue;
+
+ DiagnoseIndirectJump(I->second, I->first, TargetLabel, TargetScope);
}
}
}
+/// Diagnose an indirect jump which is known to cross scopes.
+void JumpScopeChecker::DiagnoseIndirectJump(IndirectGotoStmt *Jump,
+ unsigned JumpScope,
+ LabelStmt *Target,
+ unsigned TargetScope) {
+ assert(JumpScope != TargetScope);
+
+ S.Diag(Jump->getGotoLoc(), diag::warn_indirect_goto_in_protected_scope);
+ S.Diag(Target->getIdentLoc(), diag::note_indirect_goto_target);
+
+ unsigned Common = GetDeepestCommonScope(JumpScope, TargetScope);
+
+ // Walk out the scope chain until we reach the common ancestor.
+ for (unsigned I = JumpScope; I != Common; I = Scopes[I].ParentScope)
+ if (Scopes[I].OutDiag)
+ S.Diag(Scopes[I].Loc, Scopes[I].OutDiag);
+
+ // Now walk into the scopes containing the label whose address was taken.
+ for (unsigned I = TargetScope; I != Common; I = Scopes[I].ParentScope)
+ if (Scopes[I].InDiag)
+ S.Diag(Scopes[I].Loc, Scopes[I].InDiag);
+}
+
/// CheckJump - Validate that the specified jump statement is valid: that it is
/// jumping within or out of its current scope, not into a deeper one.
void JumpScopeChecker::CheckJump(Stmt *From, Stmt *To,
@@ -290,42 +493,25 @@ void JumpScopeChecker::CheckJump(Stmt *From, Stmt *To,
// Common case: exactly the same scope, which is fine.
if (FromScope == ToScope) return;
- // The only valid mismatch jump case happens when the jump is more deeply
- // nested inside the jump target. Do a quick scan to see if the jump is valid
- // because valid code is more common than invalid code.
- unsigned TestScope = Scopes[FromScope].ParentScope;
- while (TestScope != ~0U) {
- // If we found the jump target, then we're jumping out of our current scope,
- // which is perfectly fine.
- if (TestScope == ToScope) return;
-
- // Otherwise, scan up the hierarchy.
- TestScope = Scopes[TestScope].ParentScope;
- }
+ unsigned CommonScope = GetDeepestCommonScope(FromScope, ToScope);
- // If we get here, then we know we have invalid code. Diagnose the bad jump,
- // and then emit a note at each VLA being jumped out of.
- S.Diag(DiagLoc, JumpDiag);
+ // It's okay to jump out from a nested scope.
+ if (CommonScope == ToScope) return;
- // Eliminate the common prefix of the jump and the target. Start by
- // linearizing both scopes, reversing them as we go.
- std::vector<unsigned> FromScopes, ToScopes;
- for (TestScope = FromScope; TestScope != ~0U;
- TestScope = Scopes[TestScope].ParentScope)
- FromScopes.push_back(TestScope);
- for (TestScope = ToScope; TestScope != ~0U;
- TestScope = Scopes[TestScope].ParentScope)
- ToScopes.push_back(TestScope);
-
- // Remove any common entries (such as the top-level function scope).
- while (!FromScopes.empty() && FromScopes.back() == ToScopes.back()) {
- FromScopes.pop_back();
- ToScopes.pop_back();
- }
+ // Pull out (and reverse) any scopes we might need to diagnose skipping.
+ llvm::SmallVector<unsigned, 10> ToScopes;
+ for (unsigned I = ToScope; I != CommonScope; I = Scopes[I].ParentScope)
+ if (Scopes[I].InDiag)
+ ToScopes.push_back(I);
+
+ // If the only scopes present are cleanup scopes, we're okay.
+ if (ToScopes.empty()) return;
+
+ S.Diag(DiagLoc, JumpDiag);
// Emit diagnostics for whatever is left in ToScopes.
for (unsigned i = 0, e = ToScopes.size(); i != e; ++i)
- S.Diag(Scopes[ToScopes[i]].Loc, Scopes[ToScopes[i]].Diag);
+ S.Diag(Scopes[ToScopes[i]].Loc, Scopes[ToScopes[i]].InDiag);
}
void Sema::DiagnoseInvalidJumps(Stmt *Body) {
diff --git a/lib/Sema/Sema.cpp b/lib/Sema/Sema.cpp
index 755af84ca960..523b19639228 100644
--- a/lib/Sema/Sema.cpp
+++ b/lib/Sema/Sema.cpp
@@ -33,22 +33,12 @@ void FunctionScopeInfo::Clear(unsigned NumErrors) {
NeedsScopeChecking = false;
LabelMap.clear();
SwitchStack.clear();
+ Returns.clear();
NumErrorsAtStartOfFunction = NumErrors;
}
BlockScopeInfo::~BlockScopeInfo() { }
-static inline RecordDecl *CreateStructDecl(ASTContext &C, const char *Name) {
- if (C.getLangOptions().CPlusPlus)
- return CXXRecordDecl::Create(C, TagDecl::TK_struct,
- C.getTranslationUnitDecl(),
- SourceLocation(), &C.Idents.get(Name));
-
- return RecordDecl::Create(C, TagDecl::TK_struct,
- C.getTranslationUnitDecl(),
- SourceLocation(), &C.Idents.get(Name));
-}
-
void Sema::ActOnTranslationUnitScope(SourceLocation Loc, Scope *S) {
TUScope = S;
PushDeclContext(S, Context.getTranslationUnitDecl());
@@ -97,8 +87,9 @@ void Sema::ActOnTranslationUnitScope(SourceLocation Loc, Scope *S) {
}
// Create the built-in typedef for 'id'.
if (Context.getObjCIdType().isNull()) {
- QualType IdT = Context.getObjCObjectPointerType(Context.ObjCBuiltinIdTy);
- TypeSourceInfo *IdInfo = Context.getTrivialTypeSourceInfo(IdT);
+ QualType T = Context.getObjCObjectType(Context.ObjCBuiltinIdTy, 0, 0);
+ T = Context.getObjCObjectPointerType(T);
+ TypeSourceInfo *IdInfo = Context.getTrivialTypeSourceInfo(T);
TypedefDecl *IdTypedef
= TypedefDecl::Create(Context, CurContext, SourceLocation(),
&Context.Idents.get("id"), IdInfo);
@@ -108,9 +99,9 @@ void Sema::ActOnTranslationUnitScope(SourceLocation Loc, Scope *S) {
}
// Create the built-in typedef for 'Class'.
if (Context.getObjCClassType().isNull()) {
- QualType ClassType
- = Context.getObjCObjectPointerType(Context.ObjCBuiltinClassTy);
- TypeSourceInfo *ClassInfo = Context.getTrivialTypeSourceInfo(ClassType);
+ QualType T = Context.getObjCObjectType(Context.ObjCBuiltinClassTy, 0, 0);
+ T = Context.getObjCObjectPointerType(T);
+ TypeSourceInfo *ClassInfo = Context.getTrivialTypeSourceInfo(T);
TypedefDecl *ClassTypedef
= TypedefDecl::Create(Context, CurContext, SourceLocation(),
&Context.Idents.get("Class"), ClassInfo);
@@ -175,7 +166,17 @@ void Sema::ImpCastExprToType(Expr *&Expr, QualType Ty,
}
}
- CheckImplicitConversion(Expr, Ty);
+ // If this is a derived-to-base cast to a through a virtual base, we
+ // need a vtable.
+ if (Kind == CastExpr::CK_DerivedToBase &&
+ BasePathInvolvesVirtualBase(BasePath)) {
+ QualType T = Expr->getType();
+ if (const PointerType *Pointer = T->getAs<PointerType>())
+ T = Pointer->getPointeeType();
+ if (const RecordType *RecordTy = T->getAs<RecordType>())
+ MarkVTableUsed(Expr->getLocStart(),
+ cast<CXXRecordDecl>(RecordTy->getDecl()));
+ }
if (ImplicitCastExpr *ImpCast = dyn_cast<ImplicitCastExpr>(Expr)) {
if (ImpCast->getCastKind() == Kind && BasePath.empty()) {
@@ -212,10 +213,10 @@ void Sema::ActOnEndOfTranslationUnit() {
// template instantiations earlier.
PerformPendingImplicitInstantiations();
- /// If ProcessPendingClassesWithUnmarkedVirtualMembers ends up marking
- /// any virtual member functions it might lead to more pending template
+ /// If DefinedUsedVTables ends up marking any virtual member
+ /// functions it might lead to more pending template
/// instantiations, which is why we need to loop here.
- if (!ProcessPendingClassesWithUnmarkedVirtualMembers())
+ if (!DefineUsedVTables())
break;
}
@@ -304,7 +305,7 @@ void Sema::ActOnEndOfTranslationUnit() {
DeclContext *Sema::getFunctionLevelDeclContext() {
DeclContext *DC = CurContext;
- while (isa<BlockDecl>(DC))
+ while (isa<BlockDecl>(DC) || isa<EnumDecl>(DC))
DC = DC->getParent();
return DC;
diff --git a/lib/Sema/Sema.h b/lib/Sema/Sema.h
index f146c8578721..dfc45ace0e03 100644
--- a/lib/Sema/Sema.h
+++ b/lib/Sema/Sema.h
@@ -134,6 +134,11 @@ struct FunctionScopeInfo {
/// block.
llvm::SmallVector<SwitchStmt*, 8> SwitchStack;
+ /// \brief The list of return statements that occur within the function or
+ /// block, if there is any chance of applying the named return value
+ /// optimization.
+ llvm::SmallVector<ReturnStmt *, 4> Returns;
+
FunctionScopeInfo(unsigned NumErrors)
: IsBlockInfo(false), NeedsScopeChecking(false),
NumErrorsAtStartOfFunction(NumErrors) { }
@@ -768,7 +773,8 @@ public:
bool RequireCompleteType(SourceLocation Loc, QualType T,
unsigned DiagID);
- QualType getQualifiedNameType(const CXXScopeSpec &SS, QualType T);
+ QualType getElaboratedType(ElaboratedTypeKeyword Keyword,
+ const CXXScopeSpec &SS, QualType T);
QualType BuildTypeofExprType(Expr *E);
QualType BuildDecltypeType(Expr *E);
@@ -901,11 +907,11 @@ public:
/// ParsedFreeStandingDeclSpec - This method is invoked when a declspec with
/// no declarator (e.g. "struct foo;") is parsed.
- virtual DeclPtrTy ParsedFreeStandingDeclSpec(Scope *S, DeclSpec &DS);
+ virtual DeclPtrTy ParsedFreeStandingDeclSpec(Scope *S, AccessSpecifier AS,
+ DeclSpec &DS);
- bool InjectAnonymousStructOrUnionMembers(Scope *S, DeclContext *Owner,
- RecordDecl *AnonRecord);
virtual DeclPtrTy BuildAnonymousStructOrUnion(Scope *S, DeclSpec &DS,
+ AccessSpecifier AS,
RecordDecl *Record);
bool isAcceptableTagRedeclaration(const TagDecl *Previous,
@@ -1161,6 +1167,9 @@ public:
ImplicitConversionSequence TryContextuallyConvertToBool(Expr *From);
bool PerformContextuallyConvertToBool(Expr *&From);
+ ImplicitConversionSequence TryContextuallyConvertToObjCId(Expr *From);
+ bool PerformContextuallyConvertToObjCId(Expr *&From);
+
bool PerformObjectMemberConversion(Expr *&From,
NestedNameSpecifier *Qualifier,
NamedDecl *FoundDecl,
@@ -1528,16 +1537,21 @@ public:
/// ImplMethodsVsClassMethods - This is main routine to warn if any method
/// remains unimplemented in the class or category @implementation.
- void ImplMethodsVsClassMethods(ObjCImplDecl* IMPDecl,
+ void ImplMethodsVsClassMethods(Scope *S, ObjCImplDecl* IMPDecl,
ObjCContainerDecl* IDecl,
bool IncompleteImpl = false);
/// DiagnoseUnimplementedProperties - This routine warns on those properties
/// which must be implemented by this implementation.
- void DiagnoseUnimplementedProperties(ObjCImplDecl* IMPDecl,
+ void DiagnoseUnimplementedProperties(Scope *S, ObjCImplDecl* IMPDecl,
ObjCContainerDecl *CDecl,
const llvm::DenseSet<Selector>& InsMap);
+ /// DefaultSynthesizeProperties - This routine default synthesizes all
+ /// properties which must be synthesized in class's @implementation.
+ void DefaultSynthesizeProperties (Scope *S, ObjCImplDecl* IMPDecl,
+ ObjCInterfaceDecl *IDecl);
+
/// CollectImmediateProperties - This routine collects all properties in
/// the class and its conforming protocols; but not those it its super class.
void CollectImmediateProperties(ObjCContainerDecl *CDecl,
@@ -1583,7 +1597,8 @@ public:
const bool isAssign,
const bool isReadWrite,
const unsigned Attributes, QualType T,
- tok::ObjCKeywordKind MethodImplKind);
+ tok::ObjCKeywordKind MethodImplKind,
+ DeclContext *lexicalDC = 0);
/// AtomicPropertySetterGetterRules - This routine enforces the rule (via
/// warning) when atomic property has one but not the other user-declared
@@ -1661,10 +1676,9 @@ public:
FullExprArg CondVal, DeclPtrTy CondVar,
StmtArg ThenVal,
SourceLocation ElseLoc, StmtArg ElseVal);
- virtual OwningStmtResult ActOnStartOfSwitchStmt(FullExprArg Cond,
+ virtual OwningStmtResult ActOnStartOfSwitchStmt(SourceLocation SwitchLoc,
+ ExprArg Cond,
DeclPtrTy CondVar);
- virtual void ActOnSwitchBodyError(SourceLocation SwitchLoc, StmtArg Switch,
- StmtArg Body);
virtual OwningStmtResult ActOnFinishSwitchStmt(SourceLocation SwitchLoc,
StmtArg Switch, StmtArg Body);
virtual OwningStmtResult ActOnWhileStmt(SourceLocation WhileLoc,
@@ -1762,7 +1776,8 @@ public:
/// DiagnoseUnusedExprResult - If the statement passed in is an expression
/// whose result is unused, warn.
void DiagnoseUnusedExprResult(const Stmt *S);
-
+ void DiagnoseUnusedDecl(const NamedDecl *ND);
+
ParsingDeclStackState PushParsingDeclaration();
void PopParsingDeclaration(ParsingDeclStackState S, DeclPtrTy D);
void EmitDeprecationWarning(NamedDecl *D, SourceLocation Loc);
@@ -1785,6 +1800,7 @@ public:
virtual void PopExpressionEvaluationContext();
void MarkDeclarationReferenced(SourceLocation Loc, Decl *D);
+ void MarkDeclarationsReferencedInType(SourceLocation Loc, QualType T);
bool DiagRuntimeBehavior(SourceLocation Loc, const PartialDiagnostic &PD);
// Primary Expressions.
@@ -1796,7 +1812,8 @@ public:
bool HasTrailingLParen,
bool IsAddressOfOperand);
- bool DiagnoseEmptyLookup(Scope *S, CXXScopeSpec &SS, LookupResult &R);
+ bool DiagnoseEmptyLookup(Scope *S, CXXScopeSpec &SS, LookupResult &R,
+ CorrectTypoContext CTC = CTC_Unknown);
OwningExprResult LookupInObjCMethod(LookupResult &R,
Scope *S,
@@ -2321,7 +2338,9 @@ public:
virtual DeclResult ActOnCXXConditionDeclaration(Scope *S,
Declarator &D);
- OwningExprResult CheckConditionVariable(VarDecl *ConditionVar);
+ OwningExprResult CheckConditionVariable(VarDecl *ConditionVar,
+ SourceLocation StmtLoc,
+ bool ConvertToBoolean);
/// ActOnUnaryTypeTrait - Parsed one of the unary type trait support
/// pseudo-functions.
@@ -2553,27 +2572,38 @@ public:
void MarkBaseAndMemberDestructorsReferenced(SourceLocation Loc,
CXXRecordDecl *Record);
- /// ClassesWithUnmarkedVirtualMembers - Contains record decls whose virtual
- /// members need to be marked as referenced at the end of the translation
- /// unit. It will contain polymorphic classes that do not have a key
- /// function or have a key function that has been defined.
- llvm::SmallVector<std::pair<CXXRecordDecl *, SourceLocation>, 4>
- ClassesWithUnmarkedVirtualMembers;
+ /// \brief The list of classes whose vtables have been used within
+ /// this translation unit, and the source locations at which the
+ /// first use occurred.
+ llvm::SmallVector<std::pair<CXXRecordDecl *, SourceLocation>, 16>
+ VTableUses;
- /// MaybeMarkVirtualMembersReferenced - If the passed in method is the
- /// key function of the record decl, will mark virtual member functions as
- /// referenced.
- void MaybeMarkVirtualMembersReferenced(SourceLocation Loc, CXXMethodDecl *MD);
+ /// \brief The set of classes whose vtables have been used within
+ /// this translation unit, and a bit that will be true if the vtable is
+ /// required to be emitted (otherwise, it should be emitted only if needed
+ /// by code generation).
+ llvm::DenseMap<CXXRecordDecl *, bool> VTablesUsed;
+
+ /// \brief A list of all of the dynamic classes in this translation
+ /// unit.
+ llvm::SmallVector<CXXRecordDecl *, 16> DynamicClasses;
+
+ /// \brief Note that the vtable for the given class was used at the
+ /// given location.
+ void MarkVTableUsed(SourceLocation Loc, CXXRecordDecl *Class,
+ bool DefinitionRequired = false);
/// MarkVirtualMembersReferenced - Will mark all virtual members of the given
/// CXXRecordDecl referenced.
void MarkVirtualMembersReferenced(SourceLocation Loc,
const CXXRecordDecl *RD);
- /// ProcessPendingClassesWithUnmarkedVirtualMembers - Will process classes
- /// that might need to have their virtual members marked as referenced.
- /// Returns false if no work was done.
- bool ProcessPendingClassesWithUnmarkedVirtualMembers();
+ /// \brief Define all of the vtables that have been used in this
+ /// translation unit and reference any virtual members used by those
+ /// vtables.
+ ///
+ /// \returns true if any work was done, false otherwise.
+ bool DefineUsedVTables();
void AddImplicitlyDeclaredMembersToClass(Scope *S, CXXRecordDecl *ClassDecl);
@@ -2657,6 +2687,8 @@ public:
void BuildBasePathArray(const CXXBasePaths &Paths,
CXXBaseSpecifierArray &BasePath);
+ bool BasePathInvolvesVirtualBase(const CXXBaseSpecifierArray &BasePath);
+
bool CheckDerivedToBaseConversion(QualType Derived, QualType Base,
SourceLocation Loc, SourceRange Range,
CXXBaseSpecifierArray *BasePath = 0,
@@ -2768,14 +2800,16 @@ public:
// C++ Templates [C++ 14]
//
void LookupTemplateName(LookupResult &R, Scope *S, CXXScopeSpec &SS,
- QualType ObjectType, bool EnteringContext);
+ QualType ObjectType, bool EnteringContext,
+ bool &MemberOfUnknownSpecialization);
virtual TemplateNameKind isTemplateName(Scope *S,
CXXScopeSpec &SS,
UnqualifiedId &Name,
TypeTy *ObjectType,
bool EnteringContext,
- TemplateTy &Template);
+ TemplateTy &Template,
+ bool &MemberOfUnknownSpecialization);
virtual bool DiagnoseUnknownTemplateName(const IdentifierInfo &II,
SourceLocation IILoc,
@@ -3085,7 +3119,9 @@ public:
QualType CheckTypenameType(ElaboratedTypeKeyword Keyword,
NestedNameSpecifier *NNS,
const IdentifierInfo &II,
- SourceRange Range);
+ SourceLocation KeywordLoc,
+ SourceRange NNSRange,
+ SourceLocation IILoc);
TypeSourceInfo *RebuildTypeInCurrentInstantiation(TypeSourceInfo *T,
SourceLocation Loc,
@@ -3568,6 +3604,24 @@ public:
}
};
+ /// \brief RAII class that determines when any errors have occurred
+ /// between the time the instance was created and the time it was
+ /// queried.
+ class ErrorTrap {
+ Sema &SemaRef;
+ unsigned PrevErrors;
+
+ public:
+ explicit ErrorTrap(Sema &SemaRef)
+ : SemaRef(SemaRef), PrevErrors(SemaRef.getDiagnostics().getNumErrors()) {}
+
+ /// \brief Determine whether any errors have occurred since this
+ /// object instance was created.
+ bool hasErrorOccurred() const {
+ return SemaRef.getDiagnostics().getNumErrors() > PrevErrors;
+ }
+ };
+
/// \brief A stack-allocated class that identifies which local
/// variable declaration instantiations are present in this scope.
///
@@ -3858,7 +3912,7 @@ public:
void MatchOneProtocolPropertiesInClass(Decl *CDecl,
ObjCProtocolDecl *PDecl);
- virtual void ActOnAtEnd(SourceRange AtEnd,
+ virtual void ActOnAtEnd(Scope *S, SourceRange AtEnd,
DeclPtrTy classDecl,
DeclPtrTy *allMethods = 0, unsigned allNum = 0,
DeclPtrTy *allProperties = 0, unsigned pNum = 0,
@@ -3871,7 +3925,8 @@ public:
bool *OverridingProperty,
tok::ObjCKeywordKind MethodImplKind);
- virtual DeclPtrTy ActOnPropertyImplDecl(SourceLocation AtLoc,
+ virtual DeclPtrTy ActOnPropertyImplDecl(Scope *S,
+ SourceLocation AtLoc,
SourceLocation PropertyLoc,
bool ImplKind,DeclPtrTy ClassImplDecl,
IdentifierInfo *PropertyId,
@@ -3960,6 +4015,11 @@ public:
MultiExprArg Args);
+ /// ActOnPragmaOptionsAlign - Called on well formed #pragma options align.
+ virtual void ActOnPragmaOptionsAlign(PragmaOptionsAlignKind Kind,
+ SourceLocation PragmaLoc,
+ SourceLocation KindLoc);
+
/// ActOnPragmaPack - Called on well formed #pragma pack(...).
virtual void ActOnPragmaPack(PragmaPackKind Kind,
IdentifierInfo *Name,
@@ -3990,9 +4050,9 @@ public:
SourceLocation WeakNameLoc,
SourceLocation AliasNameLoc);
- /// getPragmaPackAlignment() - Return the current alignment as specified by
- /// the current #pragma pack directive, or 0 if none is currently active.
- unsigned getPragmaPackAlignment() const;
+ /// AddAlignmentAttributesForRecord - Adds any needed alignment attributes to
+ /// a the record decl, to handle '#pragma pack' and '#pragma options align'.
+ void AddAlignmentAttributesForRecord(RecordDecl *RD);
/// FreePackedContext - Deallocate and null out PackContext.
void FreePackedContext();
@@ -4044,7 +4104,8 @@ public:
// DefaultVariadicArgumentPromotion - Like DefaultArgumentPromotion, but
// will warn if the resulting type is not a POD type.
- bool DefaultVariadicArgumentPromotion(Expr *&Expr, VariadicCallType CT);
+ bool DefaultVariadicArgumentPromotion(Expr *&Expr, VariadicCallType CT,
+ FunctionDecl *FDecl);
// UsualArithmeticConversions - performs the UsualUnaryConversions on it's
// operands and then handles various conversions that are common to binary
@@ -4215,9 +4276,9 @@ public:
SourceLocation questionLoc);
/// type checking for vector binary operators.
- inline QualType CheckVectorOperands(SourceLocation l, Expr *&lex, Expr *&rex);
- inline QualType CheckVectorCompareOperands(Expr *&lex, Expr *&rx,
- SourceLocation l, bool isRel);
+ QualType CheckVectorOperands(SourceLocation l, Expr *&lex, Expr *&rex);
+ QualType CheckVectorCompareOperands(Expr *&lex, Expr *&rx,
+ SourceLocation l, bool isRel);
/// type checking unary operators (subroutines of ActOnUnaryOp).
/// C99 6.5.3.1, 6.5.3.2, 6.5.3.4
@@ -4311,6 +4372,9 @@ public:
/// \return true iff there were any errors
bool CheckBooleanCondition(Expr *&CondExpr, SourceLocation Loc);
+ virtual OwningExprResult ActOnBooleanCondition(Scope *S, SourceLocation Loc,
+ ExprArg SubExpr);
+
/// DiagnoseAssignmentAsCondition - Given that an expression is
/// being used as a boolean condition, warn if it's an assignment.
void DiagnoseAssignmentAsCondition(Expr *E);
@@ -4455,9 +4519,7 @@ private:
void CheckReturnStackAddr(Expr *RetValExp, QualType lhsType,
SourceLocation ReturnLoc);
void CheckFloatComparison(SourceLocation loc, Expr* lex, Expr* rex);
- void CheckSignCompare(Expr *LHS, Expr *RHS, SourceLocation Loc,
- const BinaryOperator::Opcode* BinOpc = 0);
- void CheckImplicitConversion(Expr *E, QualType Target);
+ void CheckImplicitConversions(Expr *E);
};
//===--------------------------------------------------------------------===//
diff --git a/lib/Sema/SemaAttr.cpp b/lib/Sema/SemaAttr.cpp
index 095f537f7102..82978c956053 100644
--- a/lib/Sema/SemaAttr.cpp
+++ b/lib/Sema/SemaAttr.cpp
@@ -15,17 +15,28 @@
#include "Sema.h"
#include "Lookup.h"
#include "clang/AST/Expr.h"
+#include "clang/Basic/TargetInfo.h"
+#include "clang/Lex/Preprocessor.h"
using namespace clang;
//===----------------------------------------------------------------------===//
-// Pragma Packed
+// Pragma 'pack' and 'options align'
//===----------------------------------------------------------------------===//
namespace {
+ struct PackStackEntry {
+ // We just use a sentinel to represent when the stack is set to mac68k
+ // alignment.
+ static const unsigned kMac68kAlignmentSentinel = ~0U;
+
+ unsigned Alignment;
+ IdentifierInfo *Name;
+ };
+
/// PragmaPackStack - Simple class to wrap the stack used by #pragma
/// pack.
class PragmaPackStack {
- typedef std::vector< std::pair<unsigned, IdentifierInfo*> > stack_ty;
+ typedef std::vector<PackStackEntry> stack_ty;
/// Alignment - The current user specified alignment.
unsigned Alignment;
@@ -43,7 +54,8 @@ namespace {
/// push - Push the current alignment onto the stack, optionally
/// using the given \arg Name for the record, if non-zero.
void push(IdentifierInfo *Name) {
- Stack.push_back(std::make_pair(Alignment, Name));
+ PackStackEntry PSE = { Alignment, Name };
+ Stack.push_back(PSE);
}
/// pop - Pop a record from the stack and restore the current
@@ -60,7 +72,7 @@ bool PragmaPackStack::pop(IdentifierInfo *Name) {
// If name is empty just pop top.
if (!Name) {
- Alignment = Stack.back().first;
+ Alignment = Stack.back().Alignment;
Stack.pop_back();
return true;
}
@@ -68,9 +80,9 @@ bool PragmaPackStack::pop(IdentifierInfo *Name) {
// Otherwise, find the named record.
for (unsigned i = Stack.size(); i != 0; ) {
--i;
- if (Stack[i].second == Name) {
+ if (Stack[i].Name == Name) {
// Found it, pop up to and including this record.
- Alignment = Stack[i].first;
+ Alignment = Stack[i].Alignment;
Stack.erase(Stack.begin() + i, Stack.end());
return true;
}
@@ -86,12 +98,65 @@ void Sema::FreePackedContext() {
PackContext = 0;
}
-/// getPragmaPackAlignment() - Return the current alignment as specified by
-/// the current #pragma pack directive, or 0 if none is currently active.
-unsigned Sema::getPragmaPackAlignment() const {
- if (PackContext)
- return static_cast<PragmaPackStack*>(PackContext)->getAlignment();
- return 0;
+void Sema::AddAlignmentAttributesForRecord(RecordDecl *RD) {
+ // If there is no pack context, we don't need any attributes.
+ if (!PackContext)
+ return;
+
+ PragmaPackStack *Stack = static_cast<PragmaPackStack*>(PackContext);
+
+ // Otherwise, check to see if we need a max field alignment attribute.
+ if (unsigned Alignment = Stack->getAlignment()) {
+ if (Alignment == PackStackEntry::kMac68kAlignmentSentinel)
+ RD->addAttr(::new (Context) AlignMac68kAttr());
+ else
+ RD->addAttr(::new (Context) MaxFieldAlignmentAttr(Alignment * 8));
+ }
+}
+
+void Sema::ActOnPragmaOptionsAlign(PragmaOptionsAlignKind Kind,
+ SourceLocation PragmaLoc,
+ SourceLocation KindLoc) {
+ if (PackContext == 0)
+ PackContext = new PragmaPackStack();
+
+ PragmaPackStack *Context = static_cast<PragmaPackStack*>(PackContext);
+
+ // Reset just pops the top of the stack.
+ if (Kind == Action::POAK_Reset) {
+ // Do the pop.
+ if (!Context->pop(0)) {
+ // If a name was specified then failure indicates the name
+ // wasn't found. Otherwise failure indicates the stack was
+ // empty.
+ Diag(PragmaLoc, diag::warn_pragma_options_align_reset_failed)
+ << "stack empty";
+ }
+ return;
+ }
+
+ // We don't support #pragma options align=power.
+ switch (Kind) {
+ case POAK_Natural:
+ Context->push(0);
+ Context->setAlignment(0);
+ break;
+
+ case POAK_Mac68k:
+ // Check if the target supports this.
+ if (!PP.getTargetInfo().hasAlignMac68kSupport()) {
+ Diag(PragmaLoc, diag::err_pragma_options_align_mac68k_target_unsupported);
+ return;
+ }
+ Context->push(0);
+ Context->setAlignment(PackStackEntry::kMac68kAlignmentSentinel);
+ break;
+
+ default:
+ Diag(PragmaLoc, diag::warn_pragma_options_align_unsupported_option)
+ << KindLoc;
+ break;
+ }
}
void Sema::ActOnPragmaPack(PragmaPackKind Kind, IdentifierInfo *Name,
@@ -106,7 +171,9 @@ void Sema::ActOnPragmaPack(PragmaPackKind Kind, IdentifierInfo *Name,
// pack(0) is like pack(), which just works out since that is what
// we use 0 for in PackAttr.
- if (!Alignment->isIntegerConstantExpr(Val, Context) ||
+ if (Alignment->isTypeDependent() ||
+ Alignment->isValueDependent() ||
+ !Alignment->isIntegerConstantExpr(Val, Context) ||
!(Val == 0 || Val.isPowerOf2()) ||
Val.getZExtValue() > 16) {
Diag(PragmaLoc, diag::warn_pragma_pack_invalid_alignment);
@@ -134,7 +201,10 @@ void Sema::ActOnPragmaPack(PragmaPackKind Kind, IdentifierInfo *Name,
// FIXME: This should come from the target.
if (AlignmentVal == 0)
AlignmentVal = 8;
- Diag(PragmaLoc, diag::warn_pragma_pack_show) << AlignmentVal;
+ if (AlignmentVal == PackStackEntry::kMac68kAlignmentSentinel)
+ Diag(PragmaLoc, diag::warn_pragma_pack_show) << "mac68k";
+ else
+ Diag(PragmaLoc, diag::warn_pragma_pack_show) << AlignmentVal;
break;
case Action::PPK_Push: // pack(push [, id] [, [n])
diff --git a/lib/Sema/SemaCXXCast.cpp b/lib/Sema/SemaCXXCast.cpp
index ba7e1ff6341b..9b9555255489 100644
--- a/lib/Sema/SemaCXXCast.cpp
+++ b/lib/Sema/SemaCXXCast.cpp
@@ -388,6 +388,12 @@ CheckDynamicCast(Sema &Self, Expr *&SrcExpr, QualType DestType,
return;
Kind = CastExpr::CK_DerivedToBase;
+
+ // If we are casting to or through a virtual base class, we need a
+ // vtable.
+ if (Self.BasePathInvolvesVirtualBase(BasePath))
+ Self.MarkVTableUsed(OpRange.getBegin(),
+ cast<CXXRecordDecl>(SrcRecord->getDecl()));
return;
}
@@ -398,6 +404,8 @@ CheckDynamicCast(Sema &Self, Expr *&SrcExpr, QualType DestType,
Self.Diag(OpRange.getBegin(), diag::err_bad_dynamic_cast_not_polymorphic)
<< SrcPointee.getUnqualifiedType() << SrcExpr->getSourceRange();
}
+ Self.MarkVTableUsed(OpRange.getBegin(),
+ cast<CXXRecordDecl>(SrcRecord->getDecl()));
// Done. Everything else is run-time checks.
Kind = CastExpr::CK_Dynamic;
@@ -578,8 +586,9 @@ static TryCastResult TryStaticCast(Sema &Self, Expr *&SrcExpr,
return TC_Success;
}
}
- else if (CStyle && DestType->isObjCObjectPointerType()) {
- // allow c-style cast of objective-c pointers as they are pervasive.
+ else if (DestType->isObjCObjectPointerType()) {
+ // allow both c-style cast and static_cast of objective-c pointers as
+ // they are pervasive.
Kind = CastExpr::CK_AnyPointerToObjCPointerCast;
return TC_Success;
}
@@ -590,7 +599,11 @@ static TryCastResult TryStaticCast(Sema &Self, Expr *&SrcExpr,
}
}
}
-
+ // Allow arbitray objective-c pointer conversion with static casts.
+ if (SrcType->isObjCObjectPointerType() &&
+ DestType->isObjCObjectPointerType())
+ return TC_Success;
+
// We tried everything. Everything! Nothing works! :-(
return TC_NotApplicable;
}
@@ -846,7 +859,7 @@ TryStaticMemberPointerUpcast(Sema &Self, Expr *&SrcExpr, QualType SrcType,
}
// B is a base of D. But is it an allowed base? If not, it's a hard error.
- if (Paths.isAmbiguous(DestClass)) {
+ if (Paths.isAmbiguous(Self.Context.getCanonicalType(DestClass))) {
Paths.clear();
Paths.setRecordingPaths(true);
bool StillOkay = Self.IsDerivedFrom(SrcClass, DestClass, Paths);
@@ -970,7 +983,9 @@ static TryCastResult TryConstCast(Sema &Self, Expr *SrcExpr, QualType DestType,
// C++ 5.2.11p5: For a const_cast involving pointers to data members [...]
// the rules for const_cast are the same as those used for pointers.
- if (!DestType->isPointerType() && !DestType->isMemberPointerType()) {
+ if (!DestType->isPointerType() &&
+ !DestType->isMemberPointerType() &&
+ !DestType->isObjCObjectPointerType()) {
// Cannot cast to non-pointer, non-reference type. Note that, if DestType
// was a reference type, we converted it to a pointer above.
// The status of rvalue references isn't entirely clear, but it looks like
diff --git a/lib/Sema/SemaChecking.cpp b/lib/Sema/SemaChecking.cpp
index 7029711d446c..4f3f41b715f9 100644
--- a/lib/Sema/SemaChecking.cpp
+++ b/lib/Sema/SemaChecking.cpp
@@ -75,14 +75,15 @@ SourceLocation Sema::getLocationOfStringLiteralByte(const StringLiteral *SL,
TheLexer.LexFromRawLexer(TheTok);
// Use the StringLiteralParser to compute the length of the string in bytes.
- StringLiteralParser SLP(&TheTok, 1, PP);
+ StringLiteralParser SLP(&TheTok, 1, PP, /*Complain=*/false);
unsigned TokNumBytes = SLP.GetStringLength();
// If the byte is in this token, return the location of the byte.
if (ByteNo < TokNumBytes ||
(ByteNo == TokNumBytes && TokNo == SL->getNumConcatenated())) {
unsigned Offset =
- StringLiteralParser::getOffsetOfStringByte(TheTok, ByteNo, PP);
+ StringLiteralParser::getOffsetOfStringByte(TheTok, ByteNo, PP,
+ /*Complain=*/false);
// Now that we know the offset of the token in the spelling, use the
// preprocessor to get the offset in the original source.
@@ -607,12 +608,25 @@ bool Sema::SemaBuiltinFPClassification(CallExpr *TheCall, unsigned NumArgs) {
if (OrigArg->isTypeDependent())
return false;
- // This operation requires a floating-point number
+ // This operation requires a non-_Complex floating-point number.
if (!OrigArg->getType()->isRealFloatingType())
return Diag(OrigArg->getLocStart(),
diag::err_typecheck_call_invalid_unary_fp)
<< OrigArg->getType() << OrigArg->getSourceRange();
+ // If this is an implicit conversion from float -> double, remove it.
+ if (ImplicitCastExpr *Cast = dyn_cast<ImplicitCastExpr>(OrigArg)) {
+ Expr *CastArg = Cast->getSubExpr();
+ if (CastArg->getType()->isSpecificBuiltinType(BuiltinType::Float)) {
+ assert(Cast->getType()->isSpecificBuiltinType(BuiltinType::Double) &&
+ "promotion from float to double is the only expected cast here");
+ Cast->setSubExpr(0);
+ Cast->Destroy(Context);
+ TheCall->setArg(NumArgs-1, CastArg);
+ OrigArg = CastArg;
+ }
+ }
+
return false;
}
@@ -1718,8 +1732,14 @@ struct IntRange {
T = VT->getElementType().getTypePtr();
if (const ComplexType *CT = dyn_cast<ComplexType>(T))
T = CT->getElementType().getTypePtr();
- if (const EnumType *ET = dyn_cast<EnumType>(T))
- T = ET->getDecl()->getIntegerType().getTypePtr();
+
+ if (const EnumType *ET = dyn_cast<EnumType>(T)) {
+ EnumDecl *Enum = ET->getDecl();
+ unsigned NumPositive = Enum->getNumPositiveBits();
+ unsigned NumNegative = Enum->getNumNegativeBits();
+
+ return IntRange(std::max(NumPositive, NumNegative), NumNegative == 0);
+ }
const BuiltinType *BT = cast<BuiltinType>(T);
assert(BT->isInteger());
@@ -1961,6 +1981,10 @@ IntRange GetExprRange(ASTContext &C, Expr *E, unsigned MaxWidth) {
return IntRange::forType(C, E->getType());
}
+IntRange GetExprRange(ASTContext &C, Expr *E) {
+ return GetExprRange(C, E, C.getIntWidth(E->getType()));
+}
+
/// Checks whether the given value, which currently has the given
/// source semantics, has the same value when coerced through the
/// target semantics.
@@ -1999,7 +2023,40 @@ bool IsSameFloatAfterCast(const APValue &value,
IsSameFloatAfterCast(value.getComplexFloatImag(), Src, Tgt));
}
-} // end anonymous namespace
+void AnalyzeImplicitConversions(Sema &S, Expr *E);
+
+bool IsZero(Sema &S, Expr *E) {
+ llvm::APSInt Value;
+ return E->isIntegerConstantExpr(Value, S.Context) && Value == 0;
+}
+
+void CheckTrivialUnsignedComparison(Sema &S, BinaryOperator *E) {
+ BinaryOperator::Opcode op = E->getOpcode();
+ if (op == BinaryOperator::LT && IsZero(S, E->getRHS())) {
+ S.Diag(E->getOperatorLoc(), diag::warn_lunsigned_always_true_comparison)
+ << "< 0" << "false"
+ << E->getLHS()->getSourceRange() << E->getRHS()->getSourceRange();
+ } else if (op == BinaryOperator::GE && IsZero(S, E->getRHS())) {
+ S.Diag(E->getOperatorLoc(), diag::warn_lunsigned_always_true_comparison)
+ << ">= 0" << "true"
+ << E->getLHS()->getSourceRange() << E->getRHS()->getSourceRange();
+ } else if (op == BinaryOperator::GT && IsZero(S, E->getLHS())) {
+ S.Diag(E->getOperatorLoc(), diag::warn_runsigned_always_true_comparison)
+ << "0 >" << "false"
+ << E->getLHS()->getSourceRange() << E->getRHS()->getSourceRange();
+ } else if (op == BinaryOperator::LE && IsZero(S, E->getLHS())) {
+ S.Diag(E->getOperatorLoc(), diag::warn_runsigned_always_true_comparison)
+ << "0 <=" << "true"
+ << E->getLHS()->getSourceRange() << E->getRHS()->getSourceRange();
+ }
+}
+
+/// Analyze the operands of the given comparison. Implements the
+/// fallback case from AnalyzeComparison.
+void AnalyzeImpConvsInComparison(Sema &S, BinaryOperator *E) {
+ AnalyzeImplicitConversions(S, E->getLHS());
+ AnalyzeImplicitConversions(S, E->getRHS());
+}
/// \brief Implements -Wsign-compare.
///
@@ -2007,138 +2064,85 @@ bool IsSameFloatAfterCast(const APValue &value,
/// \param rex the right-hand expression
/// \param OpLoc the location of the joining operator
/// \param BinOpc binary opcode or 0
-void Sema::CheckSignCompare(Expr *lex, Expr *rex, SourceLocation OpLoc,
- const BinaryOperator::Opcode* BinOpc) {
- // Don't warn if we're in an unevaluated context.
- if (ExprEvalContexts.back().Context == Unevaluated)
- return;
-
- // If either expression is value-dependent, don't warn. We'll get another
- // chance at instantiation time.
- if (lex->isValueDependent() || rex->isValueDependent())
- return;
-
- QualType lt = lex->getType(), rt = rex->getType();
-
- // Only warn if both operands are integral.
- if (!lt->isIntegerType() || !rt->isIntegerType())
- return;
-
- // In C, the width of a bitfield determines its type, and the
- // declared type only contributes the signedness. This duplicates
- // the work that will later be done by UsualUnaryConversions.
- // Eventually, this check will be reorganized in a way that avoids
- // this duplication.
- if (!getLangOptions().CPlusPlus) {
- QualType tmp;
- tmp = Context.isPromotableBitField(lex);
- if (!tmp.isNull()) lt = tmp;
- tmp = Context.isPromotableBitField(rex);
- if (!tmp.isNull()) rt = tmp;
- }
-
- if (const EnumType *E = lt->getAs<EnumType>())
- lt = E->getDecl()->getPromotionType();
- if (const EnumType *E = rt->getAs<EnumType>())
- rt = E->getDecl()->getPromotionType();
-
- // The rule is that the signed operand becomes unsigned, so isolate the
- // signed operand.
- Expr *signedOperand = lex, *unsignedOperand = rex;
- QualType signedType = lt, unsignedType = rt;
- if (lt->isSignedIntegerType()) {
- if (rt->isSignedIntegerType()) return;
+void AnalyzeComparison(Sema &S, BinaryOperator *E) {
+ // The type the comparison is being performed in.
+ QualType T = E->getLHS()->getType();
+ assert(S.Context.hasSameUnqualifiedType(T, E->getRHS()->getType())
+ && "comparison with mismatched types");
+
+ // We don't do anything special if this isn't an unsigned integral
+ // comparison: we're only interested in integral comparisons, and
+ // signed comparisons only happen in cases we don't care to warn about.
+ if (!T->isUnsignedIntegerType())
+ return AnalyzeImpConvsInComparison(S, E);
+
+ Expr *lex = E->getLHS()->IgnoreParenImpCasts();
+ Expr *rex = E->getRHS()->IgnoreParenImpCasts();
+
+ // Check to see if one of the (unmodified) operands is of different
+ // signedness.
+ Expr *signedOperand, *unsignedOperand;
+ if (lex->getType()->isSignedIntegerType()) {
+ assert(!rex->getType()->isSignedIntegerType() &&
+ "unsigned comparison between two signed integer expressions?");
+ signedOperand = lex;
+ unsignedOperand = rex;
+ } else if (rex->getType()->isSignedIntegerType()) {
+ signedOperand = rex;
+ unsignedOperand = lex;
} else {
- if (!rt->isSignedIntegerType()) return;
- std::swap(signedOperand, unsignedOperand);
- std::swap(signedType, unsignedType);
+ CheckTrivialUnsignedComparison(S, E);
+ return AnalyzeImpConvsInComparison(S, E);
}
- unsigned unsignedWidth = Context.getIntWidth(unsignedType);
- unsigned signedWidth = Context.getIntWidth(signedType);
+ // Otherwise, calculate the effective range of the signed operand.
+ IntRange signedRange = GetExprRange(S.Context, signedOperand);
- // If the unsigned type is strictly smaller than the signed type,
- // then (1) the result type will be signed and (2) the unsigned
- // value will fit fully within the signed type, and thus the result
- // of the comparison will be exact.
- if (signedWidth > unsignedWidth)
- return;
+ // Go ahead and analyze implicit conversions in the operands. Note
+ // that we skip the implicit conversions on both sides.
+ AnalyzeImplicitConversions(S, lex);
+ AnalyzeImplicitConversions(S, rex);
- // Otherwise, calculate the effective ranges.
- IntRange signedRange = GetExprRange(Context, signedOperand, signedWidth);
- IntRange unsignedRange = GetExprRange(Context, unsignedOperand, unsignedWidth);
-
- // We should never be unable to prove that the unsigned operand is
- // non-negative.
- assert(unsignedRange.NonNegative && "unsigned range includes negative?");
-
- // If the signed operand is non-negative, then the signed->unsigned
- // conversion won't change it.
- if (signedRange.NonNegative) {
- // Emit warnings for comparisons of unsigned to integer constant 0.
- // always false: x < 0 (or 0 > x)
- // always true: x >= 0 (or 0 <= x)
- llvm::APSInt X;
- if (BinOpc && signedOperand->isIntegerConstantExpr(X, Context) && X == 0) {
- if (signedOperand != lex) {
- if (*BinOpc == BinaryOperator::LT) {
- Diag(OpLoc, diag::warn_lunsigned_always_true_comparison)
- << "< 0" << "false"
- << lex->getSourceRange() << rex->getSourceRange();
- }
- else if (*BinOpc == BinaryOperator::GE) {
- Diag(OpLoc, diag::warn_lunsigned_always_true_comparison)
- << ">= 0" << "true"
- << lex->getSourceRange() << rex->getSourceRange();
- }
- }
- else {
- if (*BinOpc == BinaryOperator::GT) {
- Diag(OpLoc, diag::warn_runsigned_always_true_comparison)
- << "0 >" << "false"
- << lex->getSourceRange() << rex->getSourceRange();
- }
- else if (*BinOpc == BinaryOperator::LE) {
- Diag(OpLoc, diag::warn_runsigned_always_true_comparison)
- << "0 <=" << "true"
- << lex->getSourceRange() << rex->getSourceRange();
- }
- }
- }
- return;
- }
+ // If the signed range is non-negative, -Wsign-compare won't fire,
+ // but we should still check for comparisons which are always true
+ // or false.
+ if (signedRange.NonNegative)
+ return CheckTrivialUnsignedComparison(S, E);
// For (in)equality comparisons, if the unsigned operand is a
// constant which cannot collide with a overflowed signed operand,
// then reinterpreting the signed operand as unsigned will not
// change the result of the comparison.
- if (BinOpc &&
- (*BinOpc == BinaryOperator::EQ || *BinOpc == BinaryOperator::NE) &&
- unsignedRange.Width < unsignedWidth)
- return;
+ if (E->isEqualityOp()) {
+ unsigned comparisonWidth = S.Context.getIntWidth(T);
+ IntRange unsignedRange = GetExprRange(S.Context, unsignedOperand);
+
+ // We should never be unable to prove that the unsigned operand is
+ // non-negative.
+ assert(unsignedRange.NonNegative && "unsigned range includes negative?");
+
+ if (unsignedRange.Width < comparisonWidth)
+ return;
+ }
- Diag(OpLoc, BinOpc ? diag::warn_mixed_sign_comparison
- : diag::warn_mixed_sign_conditional)
- << lt << rt << lex->getSourceRange() << rex->getSourceRange();
+ S.Diag(E->getOperatorLoc(), diag::warn_mixed_sign_comparison)
+ << lex->getType() << rex->getType()
+ << lex->getSourceRange() << rex->getSourceRange();
}
/// Diagnose an implicit cast; purely a helper for CheckImplicitConversion.
-static void DiagnoseImpCast(Sema &S, Expr *E, QualType T, unsigned diag) {
+void DiagnoseImpCast(Sema &S, Expr *E, QualType T, unsigned diag) {
S.Diag(E->getExprLoc(), diag) << E->getType() << T << E->getSourceRange();
}
-/// Implements -Wconversion.
-void Sema::CheckImplicitConversion(Expr *E, QualType T) {
- // Don't diagnose in unevaluated contexts.
- if (ExprEvalContexts.back().Context == Sema::Unevaluated)
- return;
+void CheckImplicitConversion(Sema &S, Expr *E, QualType T,
+ bool *ICContext = 0) {
+ if (E->isTypeDependent() || E->isValueDependent()) return;
- // Don't diagnose for value-dependent expressions.
- if (E->isValueDependent())
- return;
-
- const Type *Source = Context.getCanonicalType(E->getType()).getTypePtr();
- const Type *Target = Context.getCanonicalType(T).getTypePtr();
+ const Type *Source = S.Context.getCanonicalType(E->getType()).getTypePtr();
+ const Type *Target = S.Context.getCanonicalType(T).getTypePtr();
+ if (Source == Target) return;
+ if (Target->isDependentType()) return;
// Never diagnose implicit casts to bool.
if (Target->isSpecificBuiltinType(BuiltinType::Bool))
@@ -2147,7 +2151,7 @@ void Sema::CheckImplicitConversion(Expr *E, QualType T) {
// Strip vector types.
if (isa<VectorType>(Source)) {
if (!isa<VectorType>(Target))
- return DiagnoseImpCast(*this, E, T, diag::warn_impcast_vector_scalar);
+ return DiagnoseImpCast(S, E, T, diag::warn_impcast_vector_scalar);
Source = cast<VectorType>(Source)->getElementType().getTypePtr();
Target = cast<VectorType>(Target)->getElementType().getTypePtr();
@@ -2156,7 +2160,7 @@ void Sema::CheckImplicitConversion(Expr *E, QualType T) {
// Strip complex types.
if (isa<ComplexType>(Source)) {
if (!isa<ComplexType>(Target))
- return DiagnoseImpCast(*this, E, T, diag::warn_impcast_complex_scalar);
+ return DiagnoseImpCast(S, E, T, diag::warn_impcast_complex_scalar);
Source = cast<ComplexType>(Source)->getElementType().getTypePtr();
Target = cast<ComplexType>(Target)->getElementType().getTypePtr();
@@ -2176,15 +2180,15 @@ void Sema::CheckImplicitConversion(Expr *E, QualType T) {
// Don't warn about float constants that are precisely
// representable in the target type.
Expr::EvalResult result;
- if (E->Evaluate(result, Context)) {
+ if (E->Evaluate(result, S.Context)) {
// Value might be a float, a float vector, or a float complex.
if (IsSameFloatAfterCast(result.Val,
- Context.getFloatTypeSemantics(QualType(TargetBT, 0)),
- Context.getFloatTypeSemantics(QualType(SourceBT, 0))))
+ S.Context.getFloatTypeSemantics(QualType(TargetBT, 0)),
+ S.Context.getFloatTypeSemantics(QualType(SourceBT, 0))))
return;
}
- DiagnoseImpCast(*this, E, T, diag::warn_impcast_float_precision);
+ DiagnoseImpCast(S, E, T, diag::warn_impcast_float_precision);
}
return;
}
@@ -2192,7 +2196,7 @@ void Sema::CheckImplicitConversion(Expr *E, QualType T) {
// If the target is integral, always warn.
if ((TargetBT && TargetBT->isInteger()))
// TODO: don't warn for integer values?
- return DiagnoseImpCast(*this, E, T, diag::warn_impcast_float_integer);
+ DiagnoseImpCast(S, E, T, diag::warn_impcast_float_integer);
return;
}
@@ -2200,22 +2204,158 @@ void Sema::CheckImplicitConversion(Expr *E, QualType T) {
if (!Source->isIntegerType() || !Target->isIntegerType())
return;
- IntRange SourceRange = GetExprRange(Context, E, Context.getIntWidth(E->getType()));
- IntRange TargetRange = IntRange::forCanonicalType(Context, Target);
-
- // FIXME: also signed<->unsigned?
+ IntRange SourceRange = GetExprRange(S.Context, E);
+ IntRange TargetRange = IntRange::forCanonicalType(S.Context, Target);
if (SourceRange.Width > TargetRange.Width) {
// People want to build with -Wshorten-64-to-32 and not -Wconversion
// and by god we'll let them.
if (SourceRange.Width == 64 && TargetRange.Width == 32)
- return DiagnoseImpCast(*this, E, T, diag::warn_impcast_integer_64_32);
- return DiagnoseImpCast(*this, E, T, diag::warn_impcast_integer_precision);
+ return DiagnoseImpCast(S, E, T, diag::warn_impcast_integer_64_32);
+ return DiagnoseImpCast(S, E, T, diag::warn_impcast_integer_precision);
+ }
+
+ if ((TargetRange.NonNegative && !SourceRange.NonNegative) ||
+ (!TargetRange.NonNegative && SourceRange.NonNegative &&
+ SourceRange.Width == TargetRange.Width)) {
+ unsigned DiagID = diag::warn_impcast_integer_sign;
+
+ // Traditionally, gcc has warned about this under -Wsign-compare.
+ // We also want to warn about it in -Wconversion.
+ // So if -Wconversion is off, use a completely identical diagnostic
+ // in the sign-compare group.
+ // The conditional-checking code will
+ if (ICContext) {
+ DiagID = diag::warn_impcast_integer_sign_conditional;
+ *ICContext = true;
+ }
+
+ return DiagnoseImpCast(S, E, T, DiagID);
}
return;
}
+void CheckConditionalOperator(Sema &S, ConditionalOperator *E, QualType T);
+
+void CheckConditionalOperand(Sema &S, Expr *E, QualType T,
+ bool &ICContext) {
+ E = E->IgnoreParenImpCasts();
+
+ if (isa<ConditionalOperator>(E))
+ return CheckConditionalOperator(S, cast<ConditionalOperator>(E), T);
+
+ AnalyzeImplicitConversions(S, E);
+ if (E->getType() != T)
+ return CheckImplicitConversion(S, E, T, &ICContext);
+ return;
+}
+
+void CheckConditionalOperator(Sema &S, ConditionalOperator *E, QualType T) {
+ AnalyzeImplicitConversions(S, E->getCond());
+
+ bool Suspicious = false;
+ CheckConditionalOperand(S, E->getTrueExpr(), T, Suspicious);
+ CheckConditionalOperand(S, E->getFalseExpr(), T, Suspicious);
+
+ // If -Wconversion would have warned about either of the candidates
+ // for a signedness conversion to the context type...
+ if (!Suspicious) return;
+
+ // ...but it's currently ignored...
+ if (S.Diags.getDiagnosticLevel(diag::warn_impcast_integer_sign_conditional))
+ return;
+
+ // ...and -Wsign-compare isn't...
+ if (!S.Diags.getDiagnosticLevel(diag::warn_mixed_sign_conditional))
+ return;
+
+ // ...then check whether it would have warned about either of the
+ // candidates for a signedness conversion to the condition type.
+ if (E->getType() != T) {
+ Suspicious = false;
+ CheckImplicitConversion(S, E->getTrueExpr()->IgnoreParenImpCasts(),
+ E->getType(), &Suspicious);
+ if (!Suspicious)
+ CheckImplicitConversion(S, E->getFalseExpr()->IgnoreParenImpCasts(),
+ E->getType(), &Suspicious);
+ if (!Suspicious)
+ return;
+ }
+
+ // If so, emit a diagnostic under -Wsign-compare.
+ Expr *lex = E->getTrueExpr()->IgnoreParenImpCasts();
+ Expr *rex = E->getFalseExpr()->IgnoreParenImpCasts();
+ S.Diag(E->getQuestionLoc(), diag::warn_mixed_sign_conditional)
+ << lex->getType() << rex->getType()
+ << lex->getSourceRange() << rex->getSourceRange();
+}
+
+/// AnalyzeImplicitConversions - Find and report any interesting
+/// implicit conversions in the given expression. There are a couple
+/// of competing diagnostics here, -Wconversion and -Wsign-compare.
+void AnalyzeImplicitConversions(Sema &S, Expr *OrigE) {
+ QualType T = OrigE->getType();
+ Expr *E = OrigE->IgnoreParenImpCasts();
+
+ // For conditional operators, we analyze the arguments as if they
+ // were being fed directly into the output.
+ if (isa<ConditionalOperator>(E)) {
+ ConditionalOperator *CO = cast<ConditionalOperator>(E);
+ CheckConditionalOperator(S, CO, T);
+ return;
+ }
+
+ // Go ahead and check any implicit conversions we might have skipped.
+ // The non-canonical typecheck is just an optimization;
+ // CheckImplicitConversion will filter out dead implicit conversions.
+ if (E->getType() != T)
+ CheckImplicitConversion(S, E, T);
+
+ // Now continue drilling into this expression.
+
+ // Skip past explicit casts.
+ if (isa<ExplicitCastExpr>(E)) {
+ E = cast<ExplicitCastExpr>(E)->getSubExpr()->IgnoreParenImpCasts();
+ return AnalyzeImplicitConversions(S, E);
+ }
+
+ // Do a somewhat different check with comparison operators.
+ if (isa<BinaryOperator>(E) && cast<BinaryOperator>(E)->isComparisonOp())
+ return AnalyzeComparison(S, cast<BinaryOperator>(E));
+
+ // These break the otherwise-useful invariant below. Fortunately,
+ // we don't really need to recurse into them, because any internal
+ // expressions should have been analyzed already when they were
+ // built into statements.
+ if (isa<StmtExpr>(E)) return;
+
+ // Don't descend into unevaluated contexts.
+ if (isa<SizeOfAlignOfExpr>(E)) return;
+
+ // Now just recurse over the expression's children.
+ for (Stmt::child_iterator I = E->child_begin(), IE = E->child_end();
+ I != IE; ++I)
+ AnalyzeImplicitConversions(S, cast<Expr>(*I));
+}
+
+} // end anonymous namespace
+
+/// Diagnoses "dangerous" implicit conversions within the given
+/// expression (which is a full expression). Implements -Wconversion
+/// and -Wsign-compare.
+void Sema::CheckImplicitConversions(Expr *E) {
+ // Don't diagnose in unevaluated contexts.
+ if (ExprEvalContexts.back().Context == Sema::Unevaluated)
+ return;
+
+ // Don't diagnose for value- or type-dependent expressions.
+ if (E->isTypeDependent() || E->isValueDependent())
+ return;
+
+ AnalyzeImplicitConversions(*this, E);
+}
+
/// CheckParmsForFunctionDef - Check that the parameters of the given
/// function are appropriate for the definition of a function. This
/// takes care of any checks that cannot be performed on the
diff --git a/lib/Sema/SemaCodeComplete.cpp b/lib/Sema/SemaCodeComplete.cpp
index c075d161704e..d8c1a5cd7e3e 100644
--- a/lib/Sema/SemaCodeComplete.cpp
+++ b/lib/Sema/SemaCodeComplete.cpp
@@ -127,6 +127,13 @@ namespace {
explicit ResultBuilder(Sema &SemaRef, LookupFilter Filter = 0)
: SemaRef(SemaRef), Filter(Filter), AllowNestedNameSpecifiers(false) { }
+ /// \brief Whether we should include code patterns in the completion
+ /// results.
+ bool includeCodePatterns() const {
+ return SemaRef.CodeCompleter &&
+ SemaRef.CodeCompleter->includeCodePatterns();
+ }
+
/// \brief Set the filter used for code-completion results.
void setFilter(LookupFilter Filter) {
this->Filter = Filter;
@@ -532,8 +539,10 @@ void ResultBuilder::MaybeAddResult(Result R, DeclContext *CurContext) {
// If the filter is for nested-name-specifiers, then this result starts a
// nested-name-specifier.
- if (AsNestedNameSpecifier)
+ if (AsNestedNameSpecifier) {
R.StartsNestedNameSpecifier = true;
+ R.Priority = CCP_NestedNameSpecifier;
+ }
// If this result is supposed to have an informative qualifier, add one.
if (R.QualifierIsInformative && !R.Qualifier &&
@@ -581,8 +590,10 @@ void ResultBuilder::AddResult(Result R, DeclContext *CurContext,
// If the filter is for nested-name-specifiers, then this result starts a
// nested-name-specifier.
- if (AsNestedNameSpecifier)
+ if (AsNestedNameSpecifier) {
R.StartsNestedNameSpecifier = true;
+ R.Priority = CCP_NestedNameSpecifier;
+ }
else if (Filter == &ResultBuilder::IsMember && !R.Qualifier && InBaseClass &&
isa<CXXRecordDecl>(R.Declaration->getDeclContext()
->getLookupContext()))
@@ -601,6 +612,10 @@ void ResultBuilder::AddResult(Result R, DeclContext *CurContext,
R.QualifierIsInformative = false;
}
+ // Adjust the priority if this result comes from a base class.
+ if (InBaseClass)
+ R.Priority += CCD_InBaseClass;
+
// Insert this result into the set of results.
Results.push_back(R);
}
@@ -672,8 +687,8 @@ bool ResultBuilder::IsClassOrStruct(NamedDecl *ND) const {
ND = ClassTemplate->getTemplatedDecl();
if (RecordDecl *RD = dyn_cast<RecordDecl>(ND))
- return RD->getTagKind() == TagDecl::TK_class ||
- RD->getTagKind() == TagDecl::TK_struct;
+ return RD->getTagKind() == TTK_Class ||
+ RD->getTagKind() == TTK_Struct;
return false;
}
@@ -685,7 +700,7 @@ bool ResultBuilder::IsUnion(NamedDecl *ND) const {
ND = ClassTemplate->getTemplatedDecl();
if (RecordDecl *RD = dyn_cast<RecordDecl>(ND))
- return RD->getTagKind() == TagDecl::TK_union;
+ return RD->getTagKind() == TTK_Union;
return false;
}
@@ -744,47 +759,56 @@ namespace {
static void AddTypeSpecifierResults(const LangOptions &LangOpts,
ResultBuilder &Results) {
typedef CodeCompleteConsumer::Result Result;
- Results.AddResult(Result("short"));
- Results.AddResult(Result("long"));
- Results.AddResult(Result("signed"));
- Results.AddResult(Result("unsigned"));
- Results.AddResult(Result("void"));
- Results.AddResult(Result("char"));
- Results.AddResult(Result("int"));
- Results.AddResult(Result("float"));
- Results.AddResult(Result("double"));
- Results.AddResult(Result("enum"));
- Results.AddResult(Result("struct"));
- Results.AddResult(Result("union"));
- Results.AddResult(Result("const"));
- Results.AddResult(Result("volatile"));
+ Results.AddResult(Result("short", CCP_Type));
+ Results.AddResult(Result("long", CCP_Type));
+ Results.AddResult(Result("signed", CCP_Type));
+ Results.AddResult(Result("unsigned", CCP_Type));
+ Results.AddResult(Result("void", CCP_Type));
+ Results.AddResult(Result("char", CCP_Type));
+ Results.AddResult(Result("int", CCP_Type));
+ Results.AddResult(Result("float", CCP_Type));
+ Results.AddResult(Result("double", CCP_Type));
+ Results.AddResult(Result("enum", CCP_Type));
+ Results.AddResult(Result("struct", CCP_Type));
+ Results.AddResult(Result("union", CCP_Type));
+ Results.AddResult(Result("const", CCP_Type));
+ Results.AddResult(Result("volatile", CCP_Type));
if (LangOpts.C99) {
// C99-specific
- Results.AddResult(Result("_Complex"));
- Results.AddResult(Result("_Imaginary"));
- Results.AddResult(Result("_Bool"));
- Results.AddResult(Result("restrict"));
+ Results.AddResult(Result("_Complex", CCP_Type));
+ Results.AddResult(Result("_Imaginary", CCP_Type));
+ Results.AddResult(Result("_Bool", CCP_Type));
+ Results.AddResult(Result("restrict", CCP_Type));
}
if (LangOpts.CPlusPlus) {
// C++-specific
- Results.AddResult(Result("bool"));
- Results.AddResult(Result("class"));
- Results.AddResult(Result("wchar_t"));
+ Results.AddResult(Result("bool", CCP_Type));
+ Results.AddResult(Result("class", CCP_Type));
+ Results.AddResult(Result("wchar_t", CCP_Type));
+
+ if (Results.includeCodePatterns()) {
+ // typename qualified-id
+ CodeCompletionString *Pattern = new CodeCompletionString;
+ Pattern->AddTypedTextChunk("typename");
+ Pattern->AddChunk(CodeCompletionString::CK_HorizontalSpace);
+ Pattern->AddPlaceholderChunk("qualified-id");
+ Results.AddResult(Result(Pattern));
+ }
- // typename qualified-id
- CodeCompletionString *Pattern = new CodeCompletionString;
- Pattern->AddTypedTextChunk("typename");
- Pattern->AddChunk(CodeCompletionString::CK_HorizontalSpace);
- Pattern->AddPlaceholderChunk("qualified-id");
- Results.AddResult(Result(Pattern));
-
if (LangOpts.CPlusPlus0x) {
- Results.AddResult(Result("auto"));
- Results.AddResult(Result("char16_t"));
- Results.AddResult(Result("char32_t"));
- Results.AddResult(Result("decltype"));
+ Results.AddResult(Result("auto", CCP_Type));
+ Results.AddResult(Result("char16_t", CCP_Type));
+ Results.AddResult(Result("char32_t", CCP_Type));
+ if (Results.includeCodePatterns()) {
+ CodeCompletionString *Pattern = new CodeCompletionString;
+ Pattern->AddTypedTextChunk("decltype");
+ Pattern->AddChunk(CodeCompletionString::CK_LeftParen);
+ Pattern->AddPlaceholderChunk("expression-or-type");
+ Pattern->AddChunk(CodeCompletionString::CK_RightParen);
+ Results.AddResult(Result(Pattern));
+ }
}
}
@@ -795,12 +819,14 @@ static void AddTypeSpecifierResults(const LangOptions &LangOpts,
// Results.AddResult(Result("_Decimal64"));
// Results.AddResult(Result("_Decimal128"));
- CodeCompletionString *Pattern = new CodeCompletionString;
- Pattern->AddTypedTextChunk("typeof");
- Pattern->AddChunk(CodeCompletionString::CK_LeftParen);
- Pattern->AddPlaceholderChunk("expression-or-type");
- Pattern->AddChunk(CodeCompletionString::CK_RightParen);
- Results.AddResult(Result(Pattern));
+ if (Results.includeCodePatterns()) {
+ CodeCompletionString *Pattern = new CodeCompletionString;
+ Pattern->AddTypedTextChunk("typeof");
+ Pattern->AddChunk(CodeCompletionString::CK_LeftParen);
+ Pattern->AddPlaceholderChunk("expression-or-type");
+ Pattern->AddChunk(CodeCompletionString::CK_RightParen);
+ Results.AddResult(Result(Pattern));
+ }
}
}
@@ -843,6 +869,7 @@ static void AddFunctionSpecifiers(Action::CodeCompletionContext CCC,
case Action::CCC_Statement:
case Action::CCC_ForInit:
case Action::CCC_Condition:
+ case Action::CCC_RecoveryInFunction:
break;
}
}
@@ -868,7 +895,7 @@ static void AddOrdinaryNameResults(Action::CodeCompletionContext CCC,
typedef CodeCompleteConsumer::Result Result;
switch (CCC) {
case Action::CCC_Namespace:
- if (SemaRef.getLangOptions().CPlusPlus) {
+ if (SemaRef.getLangOptions().CPlusPlus && Results.includeCodePatterns()) {
// namespace <identifier> { }
CodeCompletionString *Pattern = new CodeCompletionString;
Pattern->AddTypedTextChunk("namespace");
@@ -920,8 +947,10 @@ static void AddOrdinaryNameResults(Action::CodeCompletionContext CCC,
// Fall through
case Action::CCC_Class:
- Results.AddResult(Result("typedef"));
- if (SemaRef.getLangOptions().CPlusPlus) {
+ if (Results.includeCodePatterns())
+ Results.AddResult(Result("typedef"));
+
+ if (SemaRef.getLangOptions().CPlusPlus && Results.includeCodePatterns()) {
// Using declaration
CodeCompletionString *Pattern = new CodeCompletionString;
Pattern->AddTypedTextChunk("using");
@@ -964,7 +993,7 @@ static void AddOrdinaryNameResults(Action::CodeCompletionContext CCC,
case Action::CCC_Template:
case Action::CCC_MemberTemplate:
- if (SemaRef.getLangOptions().CPlusPlus) {
+ if (SemaRef.getLangOptions().CPlusPlus && Results.includeCodePatterns()) {
// template < parameters >
CodeCompletionString *Pattern = new CodeCompletionString;
Pattern->AddTypedTextChunk("template");
@@ -994,11 +1023,13 @@ static void AddOrdinaryNameResults(Action::CodeCompletionContext CCC,
AddObjCVisibilityResults(SemaRef.getLangOptions(), Results, true);
break;
+ case Action::CCC_RecoveryInFunction:
case Action::CCC_Statement: {
- Results.AddResult(Result("typedef"));
+ if (Results.includeCodePatterns())
+ Results.AddResult(Result("typedef"));
CodeCompletionString *Pattern = 0;
- if (SemaRef.getLangOptions().CPlusPlus) {
+ if (SemaRef.getLangOptions().CPlusPlus && Results.includeCodePatterns()) {
Pattern = new CodeCompletionString;
Pattern->AddTypedTextChunk("try");
Pattern->AddChunk(CodeCompletionString::CK_LeftBrace);
@@ -1018,37 +1049,39 @@ static void AddOrdinaryNameResults(Action::CodeCompletionContext CCC,
if (SemaRef.getLangOptions().ObjC1)
AddObjCStatementResults(Results, true);
- // if (condition) { statements }
- Pattern = new CodeCompletionString;
- Pattern->AddTypedTextChunk("if");
- Pattern->AddChunk(CodeCompletionString::CK_LeftParen);
- if (SemaRef.getLangOptions().CPlusPlus)
- Pattern->AddPlaceholderChunk("condition");
- else
- Pattern->AddPlaceholderChunk("expression");
- Pattern->AddChunk(CodeCompletionString::CK_RightParen);
- Pattern->AddChunk(CodeCompletionString::CK_LeftBrace);
- Pattern->AddPlaceholderChunk("statements");
- Pattern->AddChunk(CodeCompletionString::CK_VerticalSpace);
- Pattern->AddChunk(CodeCompletionString::CK_RightBrace);
- Results.AddResult(Result(Pattern));
-
- // switch (condition) { }
- Pattern = new CodeCompletionString;
- Pattern->AddTypedTextChunk("switch");
- Pattern->AddChunk(CodeCompletionString::CK_LeftParen);
- if (SemaRef.getLangOptions().CPlusPlus)
- Pattern->AddPlaceholderChunk("condition");
- else
- Pattern->AddPlaceholderChunk("expression");
- Pattern->AddChunk(CodeCompletionString::CK_RightParen);
- Pattern->AddChunk(CodeCompletionString::CK_LeftBrace);
- Pattern->AddChunk(CodeCompletionString::CK_VerticalSpace);
- Pattern->AddChunk(CodeCompletionString::CK_RightBrace);
- Results.AddResult(Result(Pattern));
+ if (Results.includeCodePatterns()) {
+ // if (condition) { statements }
+ Pattern = new CodeCompletionString;
+ Pattern->AddTypedTextChunk("if");
+ Pattern->AddChunk(CodeCompletionString::CK_LeftParen);
+ if (SemaRef.getLangOptions().CPlusPlus)
+ Pattern->AddPlaceholderChunk("condition");
+ else
+ Pattern->AddPlaceholderChunk("expression");
+ Pattern->AddChunk(CodeCompletionString::CK_RightParen);
+ Pattern->AddChunk(CodeCompletionString::CK_LeftBrace);
+ Pattern->AddPlaceholderChunk("statements");
+ Pattern->AddChunk(CodeCompletionString::CK_VerticalSpace);
+ Pattern->AddChunk(CodeCompletionString::CK_RightBrace);
+ Results.AddResult(Result(Pattern));
+ // switch (condition) { }
+ Pattern = new CodeCompletionString;
+ Pattern->AddTypedTextChunk("switch");
+ Pattern->AddChunk(CodeCompletionString::CK_LeftParen);
+ if (SemaRef.getLangOptions().CPlusPlus)
+ Pattern->AddPlaceholderChunk("condition");
+ else
+ Pattern->AddPlaceholderChunk("expression");
+ Pattern->AddChunk(CodeCompletionString::CK_RightParen);
+ Pattern->AddChunk(CodeCompletionString::CK_LeftBrace);
+ Pattern->AddChunk(CodeCompletionString::CK_VerticalSpace);
+ Pattern->AddChunk(CodeCompletionString::CK_RightBrace);
+ Results.AddResult(Result(Pattern));
+ }
+
// Switch-specific statements.
- if (!SemaRef.getSwitchStack().empty()) {
+ if (!SemaRef.getSwitchStack().empty() && Results.includeCodePatterns()) {
// case expression:
Pattern = new CodeCompletionString;
Pattern->AddTypedTextChunk("case");
@@ -1063,52 +1096,54 @@ static void AddOrdinaryNameResults(Action::CodeCompletionContext CCC,
Results.AddResult(Result(Pattern));
}
- /// while (condition) { statements }
- Pattern = new CodeCompletionString;
- Pattern->AddTypedTextChunk("while");
- Pattern->AddChunk(CodeCompletionString::CK_LeftParen);
- if (SemaRef.getLangOptions().CPlusPlus)
- Pattern->AddPlaceholderChunk("condition");
- else
- Pattern->AddPlaceholderChunk("expression");
- Pattern->AddChunk(CodeCompletionString::CK_RightParen);
- Pattern->AddChunk(CodeCompletionString::CK_LeftBrace);
- Pattern->AddPlaceholderChunk("statements");
- Pattern->AddChunk(CodeCompletionString::CK_VerticalSpace);
- Pattern->AddChunk(CodeCompletionString::CK_RightBrace);
- Results.AddResult(Result(Pattern));
+ if (Results.includeCodePatterns()) {
+ /// while (condition) { statements }
+ Pattern = new CodeCompletionString;
+ Pattern->AddTypedTextChunk("while");
+ Pattern->AddChunk(CodeCompletionString::CK_LeftParen);
+ if (SemaRef.getLangOptions().CPlusPlus)
+ Pattern->AddPlaceholderChunk("condition");
+ else
+ Pattern->AddPlaceholderChunk("expression");
+ Pattern->AddChunk(CodeCompletionString::CK_RightParen);
+ Pattern->AddChunk(CodeCompletionString::CK_LeftBrace);
+ Pattern->AddPlaceholderChunk("statements");
+ Pattern->AddChunk(CodeCompletionString::CK_VerticalSpace);
+ Pattern->AddChunk(CodeCompletionString::CK_RightBrace);
+ Results.AddResult(Result(Pattern));
- // do { statements } while ( expression );
- Pattern = new CodeCompletionString;
- Pattern->AddTypedTextChunk("do");
- Pattern->AddChunk(CodeCompletionString::CK_LeftBrace);
- Pattern->AddPlaceholderChunk("statements");
- Pattern->AddChunk(CodeCompletionString::CK_VerticalSpace);
- Pattern->AddChunk(CodeCompletionString::CK_RightBrace);
- Pattern->AddTextChunk("while");
- Pattern->AddChunk(CodeCompletionString::CK_LeftParen);
- Pattern->AddPlaceholderChunk("expression");
- Pattern->AddChunk(CodeCompletionString::CK_RightParen);
- Results.AddResult(Result(Pattern));
+ // do { statements } while ( expression );
+ Pattern = new CodeCompletionString;
+ Pattern->AddTypedTextChunk("do");
+ Pattern->AddChunk(CodeCompletionString::CK_LeftBrace);
+ Pattern->AddPlaceholderChunk("statements");
+ Pattern->AddChunk(CodeCompletionString::CK_VerticalSpace);
+ Pattern->AddChunk(CodeCompletionString::CK_RightBrace);
+ Pattern->AddTextChunk("while");
+ Pattern->AddChunk(CodeCompletionString::CK_LeftParen);
+ Pattern->AddPlaceholderChunk("expression");
+ Pattern->AddChunk(CodeCompletionString::CK_RightParen);
+ Results.AddResult(Result(Pattern));
- // for ( for-init-statement ; condition ; expression ) { statements }
- Pattern = new CodeCompletionString;
- Pattern->AddTypedTextChunk("for");
- Pattern->AddChunk(CodeCompletionString::CK_LeftParen);
- if (SemaRef.getLangOptions().CPlusPlus || SemaRef.getLangOptions().C99)
- Pattern->AddPlaceholderChunk("init-statement");
- else
- Pattern->AddPlaceholderChunk("init-expression");
- Pattern->AddChunk(CodeCompletionString::CK_SemiColon);
- Pattern->AddPlaceholderChunk("condition");
- Pattern->AddChunk(CodeCompletionString::CK_SemiColon);
- Pattern->AddPlaceholderChunk("inc-expression");
- Pattern->AddChunk(CodeCompletionString::CK_RightParen);
- Pattern->AddChunk(CodeCompletionString::CK_LeftBrace);
- Pattern->AddPlaceholderChunk("statements");
- Pattern->AddChunk(CodeCompletionString::CK_VerticalSpace);
- Pattern->AddChunk(CodeCompletionString::CK_RightBrace);
- Results.AddResult(Result(Pattern));
+ // for ( for-init-statement ; condition ; expression ) { statements }
+ Pattern = new CodeCompletionString;
+ Pattern->AddTypedTextChunk("for");
+ Pattern->AddChunk(CodeCompletionString::CK_LeftParen);
+ if (SemaRef.getLangOptions().CPlusPlus || SemaRef.getLangOptions().C99)
+ Pattern->AddPlaceholderChunk("init-statement");
+ else
+ Pattern->AddPlaceholderChunk("init-expression");
+ Pattern->AddChunk(CodeCompletionString::CK_SemiColon);
+ Pattern->AddPlaceholderChunk("condition");
+ Pattern->AddChunk(CodeCompletionString::CK_SemiColon);
+ Pattern->AddPlaceholderChunk("inc-expression");
+ Pattern->AddChunk(CodeCompletionString::CK_RightParen);
+ Pattern->AddChunk(CodeCompletionString::CK_LeftBrace);
+ Pattern->AddPlaceholderChunk("statements");
+ Pattern->AddChunk(CodeCompletionString::CK_VerticalSpace);
+ Pattern->AddChunk(CodeCompletionString::CK_RightBrace);
+ Results.AddResult(Result(Pattern));
+ }
if (S->getContinueParent()) {
// continue ;
@@ -1143,21 +1178,23 @@ static void AddOrdinaryNameResults(Action::CodeCompletionContext CCC,
}
Results.AddResult(Result(Pattern));
- // goto identifier ;
- Pattern = new CodeCompletionString;
- Pattern->AddTypedTextChunk("goto");
- Pattern->AddChunk(CodeCompletionString::CK_HorizontalSpace);
- Pattern->AddPlaceholderChunk("identifier");
- Results.AddResult(Result(Pattern));
+ if (Results.includeCodePatterns()) {
+ // goto identifier ;
+ Pattern = new CodeCompletionString;
+ Pattern->AddTypedTextChunk("goto");
+ Pattern->AddChunk(CodeCompletionString::CK_HorizontalSpace);
+ Pattern->AddPlaceholderChunk("identifier");
+ Results.AddResult(Result(Pattern));
- // Using directives
- Pattern = new CodeCompletionString;
- Pattern->AddTypedTextChunk("using");
- Pattern->AddChunk(CodeCompletionString::CK_HorizontalSpace);
- Pattern->AddTextChunk("namespace");
- Pattern->AddChunk(CodeCompletionString::CK_HorizontalSpace);
- Pattern->AddPlaceholderChunk("identifier");
- Results.AddResult(Result(Pattern));
+ // Using directives
+ Pattern = new CodeCompletionString;
+ Pattern->AddTypedTextChunk("using");
+ Pattern->AddChunk(CodeCompletionString::CK_HorizontalSpace);
+ Pattern->AddTextChunk("namespace");
+ Pattern->AddChunk(CodeCompletionString::CK_HorizontalSpace);
+ Pattern->AddPlaceholderChunk("identifier");
+ Results.AddResult(Result(Pattern));
+ }
}
// Fall through (for statement expressions).
@@ -1178,103 +1215,107 @@ static void AddOrdinaryNameResults(Action::CodeCompletionContext CCC,
Results.AddResult(Result("true"));
Results.AddResult(Result("false"));
- // dynamic_cast < type-id > ( expression )
- Pattern = new CodeCompletionString;
- Pattern->AddTypedTextChunk("dynamic_cast");
- Pattern->AddChunk(CodeCompletionString::CK_LeftAngle);
- Pattern->AddPlaceholderChunk("type-id");
- Pattern->AddChunk(CodeCompletionString::CK_RightAngle);
- Pattern->AddChunk(CodeCompletionString::CK_LeftParen);
- Pattern->AddPlaceholderChunk("expression");
- Pattern->AddChunk(CodeCompletionString::CK_RightParen);
- Results.AddResult(Result(Pattern));
-
- // static_cast < type-id > ( expression )
- Pattern = new CodeCompletionString;
- Pattern->AddTypedTextChunk("static_cast");
- Pattern->AddChunk(CodeCompletionString::CK_LeftAngle);
- Pattern->AddPlaceholderChunk("type-id");
- Pattern->AddChunk(CodeCompletionString::CK_RightAngle);
- Pattern->AddChunk(CodeCompletionString::CK_LeftParen);
- Pattern->AddPlaceholderChunk("expression");
- Pattern->AddChunk(CodeCompletionString::CK_RightParen);
- Results.AddResult(Result(Pattern));
-
- // reinterpret_cast < type-id > ( expression )
- Pattern = new CodeCompletionString;
- Pattern->AddTypedTextChunk("reinterpret_cast");
- Pattern->AddChunk(CodeCompletionString::CK_LeftAngle);
- Pattern->AddPlaceholderChunk("type-id");
- Pattern->AddChunk(CodeCompletionString::CK_RightAngle);
- Pattern->AddChunk(CodeCompletionString::CK_LeftParen);
- Pattern->AddPlaceholderChunk("expression");
- Pattern->AddChunk(CodeCompletionString::CK_RightParen);
- Results.AddResult(Result(Pattern));
+ if (Results.includeCodePatterns()) {
+ // dynamic_cast < type-id > ( expression )
+ Pattern = new CodeCompletionString;
+ Pattern->AddTypedTextChunk("dynamic_cast");
+ Pattern->AddChunk(CodeCompletionString::CK_LeftAngle);
+ Pattern->AddPlaceholderChunk("type-id");
+ Pattern->AddChunk(CodeCompletionString::CK_RightAngle);
+ Pattern->AddChunk(CodeCompletionString::CK_LeftParen);
+ Pattern->AddPlaceholderChunk("expression");
+ Pattern->AddChunk(CodeCompletionString::CK_RightParen);
+ Results.AddResult(Result(Pattern));
+
+ // static_cast < type-id > ( expression )
+ Pattern = new CodeCompletionString;
+ Pattern->AddTypedTextChunk("static_cast");
+ Pattern->AddChunk(CodeCompletionString::CK_LeftAngle);
+ Pattern->AddPlaceholderChunk("type-id");
+ Pattern->AddChunk(CodeCompletionString::CK_RightAngle);
+ Pattern->AddChunk(CodeCompletionString::CK_LeftParen);
+ Pattern->AddPlaceholderChunk("expression");
+ Pattern->AddChunk(CodeCompletionString::CK_RightParen);
+ Results.AddResult(Result(Pattern));
- // const_cast < type-id > ( expression )
- Pattern = new CodeCompletionString;
- Pattern->AddTypedTextChunk("const_cast");
- Pattern->AddChunk(CodeCompletionString::CK_LeftAngle);
- Pattern->AddPlaceholderChunk("type-id");
- Pattern->AddChunk(CodeCompletionString::CK_RightAngle);
- Pattern->AddChunk(CodeCompletionString::CK_LeftParen);
- Pattern->AddPlaceholderChunk("expression");
- Pattern->AddChunk(CodeCompletionString::CK_RightParen);
- Results.AddResult(Result(Pattern));
+ // reinterpret_cast < type-id > ( expression )
+ Pattern = new CodeCompletionString;
+ Pattern->AddTypedTextChunk("reinterpret_cast");
+ Pattern->AddChunk(CodeCompletionString::CK_LeftAngle);
+ Pattern->AddPlaceholderChunk("type-id");
+ Pattern->AddChunk(CodeCompletionString::CK_RightAngle);
+ Pattern->AddChunk(CodeCompletionString::CK_LeftParen);
+ Pattern->AddPlaceholderChunk("expression");
+ Pattern->AddChunk(CodeCompletionString::CK_RightParen);
+ Results.AddResult(Result(Pattern));
- // typeid ( expression-or-type )
- Pattern = new CodeCompletionString;
- Pattern->AddTypedTextChunk("typeid");
- Pattern->AddChunk(CodeCompletionString::CK_LeftParen);
- Pattern->AddPlaceholderChunk("expression-or-type");
- Pattern->AddChunk(CodeCompletionString::CK_RightParen);
- Results.AddResult(Result(Pattern));
+ // const_cast < type-id > ( expression )
+ Pattern = new CodeCompletionString;
+ Pattern->AddTypedTextChunk("const_cast");
+ Pattern->AddChunk(CodeCompletionString::CK_LeftAngle);
+ Pattern->AddPlaceholderChunk("type-id");
+ Pattern->AddChunk(CodeCompletionString::CK_RightAngle);
+ Pattern->AddChunk(CodeCompletionString::CK_LeftParen);
+ Pattern->AddPlaceholderChunk("expression");
+ Pattern->AddChunk(CodeCompletionString::CK_RightParen);
+ Results.AddResult(Result(Pattern));
- // new T ( ... )
- Pattern = new CodeCompletionString;
- Pattern->AddTypedTextChunk("new");
- Pattern->AddChunk(CodeCompletionString::CK_HorizontalSpace);
- Pattern->AddPlaceholderChunk("type-id");
- Pattern->AddChunk(CodeCompletionString::CK_LeftParen);
- Pattern->AddPlaceholderChunk("expressions");
- Pattern->AddChunk(CodeCompletionString::CK_RightParen);
- Results.AddResult(Result(Pattern));
+ // typeid ( expression-or-type )
+ Pattern = new CodeCompletionString;
+ Pattern->AddTypedTextChunk("typeid");
+ Pattern->AddChunk(CodeCompletionString::CK_LeftParen);
+ Pattern->AddPlaceholderChunk("expression-or-type");
+ Pattern->AddChunk(CodeCompletionString::CK_RightParen);
+ Results.AddResult(Result(Pattern));
- // new T [ ] ( ... )
- Pattern = new CodeCompletionString;
- Pattern->AddTypedTextChunk("new");
- Pattern->AddChunk(CodeCompletionString::CK_HorizontalSpace);
- Pattern->AddPlaceholderChunk("type-id");
- Pattern->AddChunk(CodeCompletionString::CK_LeftBracket);
- Pattern->AddPlaceholderChunk("size");
- Pattern->AddChunk(CodeCompletionString::CK_RightBracket);
- Pattern->AddChunk(CodeCompletionString::CK_LeftParen);
- Pattern->AddPlaceholderChunk("expressions");
- Pattern->AddChunk(CodeCompletionString::CK_RightParen);
- Results.AddResult(Result(Pattern));
+ // new T ( ... )
+ Pattern = new CodeCompletionString;
+ Pattern->AddTypedTextChunk("new");
+ Pattern->AddChunk(CodeCompletionString::CK_HorizontalSpace);
+ Pattern->AddPlaceholderChunk("type-id");
+ Pattern->AddChunk(CodeCompletionString::CK_LeftParen);
+ Pattern->AddPlaceholderChunk("expressions");
+ Pattern->AddChunk(CodeCompletionString::CK_RightParen);
+ Results.AddResult(Result(Pattern));
- // delete expression
- Pattern = new CodeCompletionString;
- Pattern->AddTypedTextChunk("delete");
- Pattern->AddChunk(CodeCompletionString::CK_HorizontalSpace);
- Pattern->AddPlaceholderChunk("expression");
- Results.AddResult(Result(Pattern));
+ // new T [ ] ( ... )
+ Pattern = new CodeCompletionString;
+ Pattern->AddTypedTextChunk("new");
+ Pattern->AddChunk(CodeCompletionString::CK_HorizontalSpace);
+ Pattern->AddPlaceholderChunk("type-id");
+ Pattern->AddChunk(CodeCompletionString::CK_LeftBracket);
+ Pattern->AddPlaceholderChunk("size");
+ Pattern->AddChunk(CodeCompletionString::CK_RightBracket);
+ Pattern->AddChunk(CodeCompletionString::CK_LeftParen);
+ Pattern->AddPlaceholderChunk("expressions");
+ Pattern->AddChunk(CodeCompletionString::CK_RightParen);
+ Results.AddResult(Result(Pattern));
+
+ // delete expression
+ Pattern = new CodeCompletionString;
+ Pattern->AddTypedTextChunk("delete");
+ Pattern->AddChunk(CodeCompletionString::CK_HorizontalSpace);
+ Pattern->AddPlaceholderChunk("expression");
+ Results.AddResult(Result(Pattern));
- // delete [] expression
- Pattern = new CodeCompletionString;
- Pattern->AddTypedTextChunk("delete");
- Pattern->AddChunk(CodeCompletionString::CK_LeftBracket);
- Pattern->AddChunk(CodeCompletionString::CK_RightBracket);
- Pattern->AddChunk(CodeCompletionString::CK_HorizontalSpace);
- Pattern->AddPlaceholderChunk("expression");
- Results.AddResult(Result(Pattern));
+ // delete [] expression
+ Pattern = new CodeCompletionString;
+ Pattern->AddTypedTextChunk("delete");
+ Pattern->AddChunk(CodeCompletionString::CK_LeftBracket);
+ Pattern->AddChunk(CodeCompletionString::CK_RightBracket);
+ Pattern->AddChunk(CodeCompletionString::CK_HorizontalSpace);
+ Pattern->AddPlaceholderChunk("expression");
+ Results.AddResult(Result(Pattern));
- // throw expression
- Pattern = new CodeCompletionString;
- Pattern->AddTypedTextChunk("throw");
- Pattern->AddChunk(CodeCompletionString::CK_HorizontalSpace);
- Pattern->AddPlaceholderChunk("expression");
- Results.AddResult(Result(Pattern));
+ // throw expression
+ Pattern = new CodeCompletionString;
+ Pattern->AddTypedTextChunk("throw");
+ Pattern->AddChunk(CodeCompletionString::CK_HorizontalSpace);
+ Pattern->AddPlaceholderChunk("expression");
+ Results.AddResult(Result(Pattern));
+ }
+
+ // FIXME: Rethrow?
}
if (SemaRef.getLangOptions().ObjC1) {
@@ -1286,13 +1327,15 @@ static void AddOrdinaryNameResults(Action::CodeCompletionContext CCC,
AddObjCExpressionResults(Results, true);
}
- // sizeof expression
- Pattern = new CodeCompletionString;
- Pattern->AddTypedTextChunk("sizeof");
- Pattern->AddChunk(CodeCompletionString::CK_LeftParen);
- Pattern->AddPlaceholderChunk("expression-or-type");
- Pattern->AddChunk(CodeCompletionString::CK_RightParen);
- Results.AddResult(Result(Pattern));
+ if (Results.includeCodePatterns()) {
+ // sizeof expression
+ Pattern = new CodeCompletionString;
+ Pattern->AddTypedTextChunk("sizeof");
+ Pattern->AddChunk(CodeCompletionString::CK_LeftParen);
+ Pattern->AddPlaceholderChunk("expression-or-type");
+ Pattern->AddChunk(CodeCompletionString::CK_RightParen);
+ Results.AddResult(Result(Pattern));
+ }
break;
}
}
@@ -1543,7 +1586,7 @@ CodeCompleteConsumer::Result::CreateCodeCompletionString(Sema &S) {
return Result;
}
- assert(Kind == RK_Declaration && "Missed a macro kind?");
+ assert(Kind == RK_Declaration && "Missed a result kind?");
NamedDecl *ND = Declaration;
if (StartsNestedNameSpecifier) {
@@ -1925,6 +1968,10 @@ void Sema::CodeCompleteOrdinaryName(Scope *S,
case CCC_Condition:
Results.setFilter(&ResultBuilder::IsOrdinaryName);
break;
+
+ case CCC_RecoveryInFunction:
+ // Unfiltered
+ break;
}
CodeCompletionDeclConsumer Consumer(Results, CurContext);
@@ -2047,14 +2094,14 @@ void Sema::CodeCompleteMemberReferenceExpr(Scope *S, ExprTy *BaseE,
I != E; ++I)
AddObjCProperties(*I, true, CurContext, Results);
} else if ((IsArrow && BaseType->isObjCObjectPointerType()) ||
- (!IsArrow && BaseType->isObjCInterfaceType())) {
+ (!IsArrow && BaseType->isObjCObjectType())) {
// Objective-C instance variable access.
ObjCInterfaceDecl *Class = 0;
if (const ObjCObjectPointerType *ObjCPtr
= BaseType->getAs<ObjCObjectPointerType>())
Class = ObjCPtr->getInterfaceDecl();
else
- Class = BaseType->getAs<ObjCInterfaceType>()->getDecl();
+ Class = BaseType->getAs<ObjCObjectType>()->getInterface();
// Add all ivars from this class and its superclasses.
if (Class) {
@@ -2413,6 +2460,9 @@ void Sema::CodeCompleteOperatorName(Scope *S) {
static void AddObjCImplementationResults(const LangOptions &LangOpts,
ResultBuilder &Results,
bool NeedAt) {
+ if (!Results.includeCodePatterns())
+ return;
+
typedef CodeCompleteConsumer::Result Result;
// Since we have an implementation, we can end it.
Results.AddResult(Result(OBJC_AT_KEYWORD_NAME(NeedAt,end)));
@@ -2438,6 +2488,9 @@ static void AddObjCImplementationResults(const LangOptions &LangOpts,
static void AddObjCInterfaceResults(const LangOptions &LangOpts,
ResultBuilder &Results,
bool NeedAt) {
+ if (!Results.includeCodePatterns())
+ return;
+
typedef CodeCompleteConsumer::Result Result;
// Since we have an interface or protocol, we can end it.
@@ -2456,6 +2509,9 @@ static void AddObjCInterfaceResults(const LangOptions &LangOpts,
}
static void AddObjCTopLevelResults(ResultBuilder &Results, bool NeedAt) {
+ if (!Results.includeCodePatterns())
+ return;
+
typedef CodeCompleteConsumer::Result Result;
CodeCompletionString *Pattern = 0;
@@ -2515,6 +2571,9 @@ void Sema::CodeCompleteObjCAtDirective(Scope *S, DeclPtrTy ObjCImpDecl,
}
static void AddObjCExpressionResults(ResultBuilder &Results, bool NeedAt) {
+ if (!Results.includeCodePatterns())
+ return;
+
typedef CodeCompleteConsumer::Result Result;
CodeCompletionString *Pattern = 0;
@@ -2544,6 +2603,9 @@ static void AddObjCExpressionResults(ResultBuilder &Results, bool NeedAt) {
}
static void AddObjCStatementResults(ResultBuilder &Results, bool NeedAt) {
+ if (!Results.includeCodePatterns())
+ return;
+
typedef CodeCompleteConsumer::Result Result;
CodeCompletionString *Pattern = 0;
@@ -2590,6 +2652,9 @@ static void AddObjCStatementResults(ResultBuilder &Results, bool NeedAt) {
static void AddObjCVisibilityResults(const LangOptions &LangOpts,
ResultBuilder &Results,
bool NeedAt) {
+ if (!Results.includeCodePatterns())
+ return;
+
typedef CodeCompleteConsumer::Result Result;
Results.AddResult(Result(OBJC_AT_KEYWORD_NAME(NeedAt,private)));
Results.AddResult(Result(OBJC_AT_KEYWORD_NAME(NeedAt,protected)));
@@ -2911,9 +2976,9 @@ static ObjCInterfaceDecl *GetAssumedMessageSendExprType(Expr *E) {
ObjCInterfaceDecl *IFace = 0;
switch (Msg->getReceiverKind()) {
case ObjCMessageExpr::Class:
- if (const ObjCInterfaceType *IFaceType
- = Msg->getClassReceiver()->getAs<ObjCInterfaceType>())
- IFace = IFaceType->getDecl();
+ if (const ObjCObjectType *ObjType
+ = Msg->getClassReceiver()->getAs<ObjCObjectType>())
+ IFace = ObjType->getInterface();
break;
case ObjCMessageExpr::Instance: {
@@ -2994,9 +3059,9 @@ void Sema::CodeCompleteObjCSuperMessage(Scope *S, SourceLocation SuperLoc,
if ((CDecl = dyn_cast_or_null<ObjCInterfaceDecl>(ND))) {
// "super" names an interface. Use it.
} else if (TypeDecl *TD = dyn_cast_or_null<TypeDecl>(ND)) {
- if (const ObjCInterfaceType *Iface
- = Context.getTypeDeclType(TD)->getAs<ObjCInterfaceType>())
- CDecl = Iface->getDecl();
+ if (const ObjCObjectType *Iface
+ = Context.getTypeDeclType(TD)->getAs<ObjCObjectType>())
+ CDecl = Iface->getInterface();
} else if (ND && isa<UnresolvedUsingTypenameDecl>(ND)) {
// "super" names an unresolved type; we can't be more specific.
} else {
@@ -3030,8 +3095,8 @@ void Sema::CodeCompleteObjCClassMessage(Scope *S, TypeTy *Receiver,
if (Receiver) {
QualType T = GetTypeFromParser(Receiver, 0);
if (!T.isNull())
- if (const ObjCInterfaceType *Interface = T->getAs<ObjCInterfaceType>())
- CDecl = Interface->getDecl();
+ if (const ObjCObjectType *Interface = T->getAs<ObjCObjectType>())
+ CDecl = Interface->getInterface();
}
// Add all of the factory methods in this Objective-C class, its protocols,
@@ -3079,8 +3144,6 @@ void Sema::CodeCompleteObjCClassMessage(Scope *S, TypeTy *Receiver,
}
Results.ExitScope();
-
- // This also suppresses remaining diagnostics.
HandleCodeCompleteResults(this, CodeCompleter, Results.data(),Results.size());
}
diff --git a/lib/Sema/SemaDecl.cpp b/lib/Sema/SemaDecl.cpp
index a802679b26e1..af020990dda5 100644
--- a/lib/Sema/SemaDecl.cpp
+++ b/lib/Sema/SemaDecl.cpp
@@ -90,8 +90,9 @@ Sema::TypeTy *Sema::getTypeName(IdentifierInfo &II, SourceLocation NameLoc,
// We know from the grammar that this name refers to a type, so build a
// DependentNameType node to describe the type.
return CheckTypenameType(ETK_None,
- (NestedNameSpecifier *)SS->getScopeRep(),
- II, SS->getRange()).getAsOpaquePtr();
+ (NestedNameSpecifier *)SS->getScopeRep(), II,
+ SourceLocation(), SS->getRange(), NameLoc
+ ).getAsOpaquePtr();
}
return 0;
@@ -191,7 +192,7 @@ Sema::TypeTy *Sema::getTypeName(IdentifierInfo &II, SourceLocation NameLoc,
T = Context.getTypeDeclType(TD);
if (SS)
- T = getQualifiedNameType(*SS, T);
+ T = getElaboratedType(ETK_None, *SS, T);
} else if (ObjCInterfaceDecl *IDecl = dyn_cast<ObjCInterfaceDecl>(IIDecl)) {
T = Context.getObjCInterfaceType(IDecl);
@@ -223,10 +224,11 @@ DeclSpec::TST Sema::isTagName(IdentifierInfo &II, Scope *S) {
if (R.getResultKind() == LookupResult::Found)
if (const TagDecl *TD = R.getAsSingle<TagDecl>()) {
switch (TD->getTagKind()) {
- case TagDecl::TK_struct: return DeclSpec::TST_struct;
- case TagDecl::TK_union: return DeclSpec::TST_union;
- case TagDecl::TK_class: return DeclSpec::TST_class;
- case TagDecl::TK_enum: return DeclSpec::TST_enum;
+ default: return DeclSpec::TST_unspecified;
+ case TTK_Struct: return DeclSpec::TST_struct;
+ case TTK_Union: return DeclSpec::TST_union;
+ case TTK_Class: return DeclSpec::TST_class;
+ case TTK_Enum: return DeclSpec::TST_enum;
}
}
@@ -285,8 +287,9 @@ bool Sema::DiagnoseUnknownTypeName(const IdentifierInfo &II,
Name.setIdentifier(&II, IILoc);
CXXScopeSpec EmptySS;
TemplateTy TemplateResult;
- if (isTemplateName(S, SS ? *SS : EmptySS, Name, 0, true, TemplateResult)
- == TNK_Type_template) {
+ bool MemberOfUnknownSpecialization;
+ if (isTemplateName(S, SS ? *SS : EmptySS, Name, 0, true, TemplateResult,
+ MemberOfUnknownSpecialization) == TNK_Type_template) {
TemplateName TplName = TemplateResult.getAsVal<TemplateName>();
Diag(IILoc, diag::err_template_missing_args) << TplName;
if (TemplateDecl *TplDecl = TplName.getAsTemplateDecl()) {
@@ -544,9 +547,9 @@ static bool ShouldDiagnoseUnusedDecl(const NamedDecl *D) {
return false;
}
- // If we failed to complete the type for some reason, don't
- // diagnose the variable.
- if (Ty->isIncompleteType())
+ // If we failed to complete the type for some reason, or if the type is
+ // dependent, don't diagnose the variable.
+ if (Ty->isIncompleteType() || Ty->isDependentType())
return false;
if (const TagType *TT = Ty->getAs<TagType>()) {
@@ -555,9 +558,10 @@ static bool ShouldDiagnoseUnusedDecl(const NamedDecl *D) {
return false;
if (const CXXRecordDecl *RD = dyn_cast<CXXRecordDecl>(Tag)) {
- if (!RD->hasTrivialConstructor())
- return false;
- if (!RD->hasTrivialDestructor())
+ // FIXME: Checking for the presence of a user-declared constructor
+ // isn't completely accurate; we'd prefer to check that the initializer
+ // has no side effects.
+ if (RD->hasUserDeclaredConstructor() || !RD->hasTrivialDestructor())
return false;
}
}
@@ -568,6 +572,18 @@ static bool ShouldDiagnoseUnusedDecl(const NamedDecl *D) {
return true;
}
+void Sema::DiagnoseUnusedDecl(const NamedDecl *D) {
+ if (!ShouldDiagnoseUnusedDecl(D))
+ return;
+
+ if (isa<VarDecl>(D) && cast<VarDecl>(D)->isExceptionVariable())
+ Diag(D->getLocation(), diag::warn_unused_exception_param)
+ << D->getDeclName();
+ else
+ Diag(D->getLocation(), diag::warn_unused_variable)
+ << D->getDeclName();
+}
+
void Sema::ActOnPopScope(SourceLocation Loc, Scope *S) {
if (S->decl_empty()) return;
assert((S->getFlags() & (Scope::DeclScope | Scope::TemplateParamScope)) &&
@@ -584,15 +600,9 @@ void Sema::ActOnPopScope(SourceLocation Loc, Scope *S) {
if (!D->getDeclName()) continue;
// Diagnose unused variables in this scope.
- if (ShouldDiagnoseUnusedDecl(D) &&
- S->getNumErrorsAtStart() == getDiagnostics().getNumErrors()) {
- if (isa<VarDecl>(D) && cast<VarDecl>(D)->isExceptionVariable())
- Diag(D->getLocation(), diag::warn_unused_exception_param)
- << D->getDeclName();
- else
- Diag(D->getLocation(), diag::warn_unused_variable)
- << D->getDeclName();
- }
+ if (S->getNumErrorsAtStart() == getDiagnostics().getNumErrors())
+ DiagnoseUnusedDecl(D);
+
// Remove this name from our lexical scope.
IdResolver.RemoveDecl(D);
}
@@ -1069,10 +1079,18 @@ bool Sema::MergeFunctionDecl(FunctionDecl *New, Decl *OldD) {
= cast<FunctionType>(OldQType.getTypePtr())->getResultType();
QualType NewReturnType
= cast<FunctionType>(NewQType.getTypePtr())->getResultType();
+ QualType ResQT;
if (OldReturnType != NewReturnType) {
- Diag(New->getLocation(), diag::err_ovl_diff_return_type);
- Diag(Old->getLocation(), PrevDiag) << Old << Old->getType();
- return true;
+ if (NewReturnType->isObjCObjectPointerType()
+ && OldReturnType->isObjCObjectPointerType())
+ ResQT = Context.mergeObjCGCQualifiers(NewQType, OldQType);
+ if (ResQT.isNull()) {
+ Diag(New->getLocation(), diag::err_ovl_diff_return_type);
+ Diag(Old->getLocation(), PrevDiag) << Old << Old->getType();
+ return true;
+ }
+ else
+ NewQType = ResQT;
}
const CXXMethodDecl* OldMethod = dyn_cast<CXXMethodDecl>(Old);
@@ -1356,6 +1374,9 @@ void Sema::MergeVarDecl(VarDecl *New, LookupResult &Previous) {
= Context.getCanonicalType(New->getType())->getAs<ArrayType>();
if (OldArray->getElementType() == NewArray->getElementType())
MergedT = Old->getType();
+ } else if (New->getType()->isObjCObjectPointerType()
+ && Old->getType()->isObjCObjectPointerType()) {
+ MergedT = Context.mergeObjCGCQualifiers(New->getType(), Old->getType());
}
} else {
MergedT = Context.mergeTypes(New->getType(), Old->getType());
@@ -1435,7 +1456,8 @@ void Sema::MergeVarDecl(VarDecl *New, LookupResult &Previous) {
/// ParsedFreeStandingDeclSpec - This method is invoked when a declspec with
/// no declarator (e.g. "struct foo;") is parsed.
-Sema::DeclPtrTy Sema::ParsedFreeStandingDeclSpec(Scope *S, DeclSpec &DS) {
+Sema::DeclPtrTy Sema::ParsedFreeStandingDeclSpec(Scope *S, AccessSpecifier AS,
+ DeclSpec &DS) {
// FIXME: Error on auto/register at file scope
// FIXME: Error on inline/virtual/explicit
// FIXME: Warn on useless __thread
@@ -1485,7 +1507,7 @@ Sema::DeclPtrTy Sema::ParsedFreeStandingDeclSpec(Scope *S, DeclSpec &DS) {
DS.getStorageClassSpec() != DeclSpec::SCS_typedef) {
if (getLangOptions().CPlusPlus ||
Record->getDeclContext()->isRecord())
- return BuildAnonymousStructOrUnion(S, DS, Record);
+ return BuildAnonymousStructOrUnion(S, DS, AS, Record);
Diag(DS.getSourceRange().getBegin(), diag::ext_no_declarators)
<< DS.getSourceRange();
@@ -1563,8 +1585,10 @@ static bool CheckAnonMemberRedeclaration(Sema &SemaRef,
///
/// This routine is recursive, injecting the names of nested anonymous
/// structs/unions into the owning context and scope as well.
-bool Sema::InjectAnonymousStructOrUnionMembers(Scope *S, DeclContext *Owner,
- RecordDecl *AnonRecord) {
+static bool InjectAnonymousStructOrUnionMembers(Sema &SemaRef, Scope *S,
+ DeclContext *Owner,
+ RecordDecl *AnonRecord,
+ AccessSpecifier AS) {
unsigned diagKind
= AnonRecord->isUnion() ? diag::err_anonymous_union_member_redecl
: diag::err_anonymous_struct_member_redecl;
@@ -1574,7 +1598,7 @@ bool Sema::InjectAnonymousStructOrUnionMembers(Scope *S, DeclContext *Owner,
FEnd = AnonRecord->field_end();
F != FEnd; ++F) {
if ((*F)->getDeclName()) {
- if (CheckAnonMemberRedeclaration(*this, S, Owner, (*F)->getDeclName(),
+ if (CheckAnonMemberRedeclaration(SemaRef, S, Owner, (*F)->getDeclName(),
(*F)->getLocation(), diagKind)) {
// C++ [class.union]p2:
// The names of the members of an anonymous union shall be
@@ -1588,15 +1612,19 @@ bool Sema::InjectAnonymousStructOrUnionMembers(Scope *S, DeclContext *Owner,
// considered to have been defined in the scope in which the
// anonymous union is declared.
Owner->makeDeclVisibleInContext(*F);
- S->AddDecl(DeclPtrTy::make(*F));
- IdResolver.AddDecl(*F);
+ S->AddDecl(Sema::DeclPtrTy::make(*F));
+ SemaRef.IdResolver.AddDecl(*F);
+
+ // That includes picking up the appropriate access specifier.
+ if (AS != AS_none) (*F)->setAccess(AS);
}
} else if (const RecordType *InnerRecordType
= (*F)->getType()->getAs<RecordType>()) {
RecordDecl *InnerRecord = InnerRecordType->getDecl();
if (InnerRecord->isAnonymousStructOrUnion())
Invalid = Invalid ||
- InjectAnonymousStructOrUnionMembers(S, Owner, InnerRecord);
+ InjectAnonymousStructOrUnionMembers(SemaRef, S, Owner,
+ InnerRecord, AS);
}
}
@@ -1666,6 +1694,7 @@ StorageClassSpecToFunctionDeclStorageClass(DeclSpec::SCS StorageClassSpec,
/// (C++ [class.union]) and a GNU C extension; anonymous structures
/// are a GNU C and GNU C++ extension.
Sema::DeclPtrTy Sema::BuildAnonymousStructOrUnion(Scope *S, DeclSpec &DS,
+ AccessSpecifier AS,
RecordDecl *Record) {
DeclContext *Owner = Record->getDeclContext();
@@ -1720,7 +1749,8 @@ Sema::DeclPtrTy Sema::BuildAnonymousStructOrUnion(Scope *S, DeclSpec &DS,
// C++ [class.union]p3:
// An anonymous union shall not have private or protected
// members (clause 11).
- if (FD->getAccess() == AS_protected || FD->getAccess() == AS_private) {
+ assert(FD->getAccess() != AS_none);
+ if (FD->getAccess() != AS_public) {
Diag(FD->getLocation(), diag::err_anonymous_record_nonpublic_member)
<< (int)Record->isUnion() << (int)(FD->getAccess() == AS_protected);
Invalid = true;
@@ -1777,7 +1807,7 @@ Sema::DeclPtrTy Sema::BuildAnonymousStructOrUnion(Scope *S, DeclSpec &DS,
Context.getTypeDeclType(Record),
TInfo,
/*BitWidth=*/0, /*Mutable=*/false);
- Anon->setAccess(AS_public);
+ Anon->setAccess(AS);
if (getLangOptions().CPlusPlus) {
FieldCollector->Add(cast<FieldDecl>(Anon));
if (!cast<CXXRecordDecl>(Record)->isEmpty())
@@ -1814,7 +1844,7 @@ Sema::DeclPtrTy Sema::BuildAnonymousStructOrUnion(Scope *S, DeclSpec &DS,
// Inject the members of the anonymous struct/union into the owning
// context and into the identifier resolver chain for name lookup
// purposes.
- if (InjectAnonymousStructOrUnionMembers(S, Owner, Record))
+ if (InjectAnonymousStructOrUnionMembers(*this, S, Owner, Record, AS))
Invalid = true;
// Mark this as an anonymous struct/union type. Note that we do not
@@ -2711,7 +2741,7 @@ void Sema::CheckVariableDeclaration(VarDecl *NewVD,
QualType T = NewVD->getType();
- if (T->isObjCInterfaceType()) {
+ if (T->isObjCObjectType()) {
Diag(NewVD->getLocation(), diag::err_statically_allocated_object);
return NewVD->setInvalidDecl();
}
@@ -2929,7 +2959,7 @@ Sema::ActOnFunctionDeclarator(Scope* S, Declarator& D, DeclContext* DC,
D.setInvalidType();
// Do not allow returning a objc interface by-value.
- if (R->getAs<FunctionType>()->getResultType()->isObjCInterfaceType()) {
+ if (R->getAs<FunctionType>()->getResultType()->isObjCObjectType()) {
Diag(D.getIdentifierLoc(),
diag::err_object_cannot_be_passed_returned_by_value) << 0
<< R->getAs<FunctionType>()->getResultType();
@@ -4322,7 +4352,7 @@ ParmVarDecl *Sema::CheckParameter(DeclContext *DC,
// Parameter declarators cannot be interface types. All ObjC objects are
// passed by reference.
- if (T->isObjCInterfaceType()) {
+ if (T->isObjCObjectType()) {
Diag(NameLoc,
diag::err_object_cannot_be_passed_returned_by_value) << 1 << T;
New->setInvalidDecl();
@@ -4540,6 +4570,38 @@ Sema::DeclPtrTy Sema::ActOnStartOfFunctionDef(Scope *FnBodyScope, DeclPtrTy D) {
return DeclPtrTy::make(FD);
}
+/// \brief Given the set of return statements within a function body,
+/// compute the variables that are subject to the named return value
+/// optimization.
+///
+/// Each of the variables that is subject to the named return value
+/// optimization will be marked as NRVO variables in the AST, and any
+/// return statement that has a marked NRVO variable as its NRVO candidate can
+/// use the named return value optimization.
+///
+/// This function applies a very simplistic algorithm for NRVO: if every return
+/// statement in the function has the same NRVO candidate, that candidate is
+/// the NRVO variable.
+///
+/// FIXME: Employ a smarter algorithm that accounts for multiple return
+/// statements and the lifetimes of the NRVO candidates. We should be able to
+/// find a maximal set of NRVO variables.
+static void ComputeNRVO(Stmt *Body, ReturnStmt **Returns, unsigned NumReturns) {
+ const VarDecl *NRVOCandidate = 0;
+ for (unsigned I = 0; I != NumReturns; ++I) {
+ if (!Returns[I]->getNRVOCandidate())
+ return;
+
+ if (!NRVOCandidate)
+ NRVOCandidate = Returns[I]->getNRVOCandidate();
+ else if (NRVOCandidate != Returns[I]->getNRVOCandidate())
+ return;
+ }
+
+ if (NRVOCandidate)
+ const_cast<VarDecl*>(NRVOCandidate)->setNRVOVariable(true);
+}
+
Sema::DeclPtrTy Sema::ActOnFinishFunctionBody(DeclPtrTy D, StmtArg BodyArg) {
return ActOnFinishFunctionBody(D, move(BodyArg), false);
}
@@ -4567,12 +4629,17 @@ Sema::DeclPtrTy Sema::ActOnFinishFunctionBody(DeclPtrTy D, StmtArg BodyArg,
WP.disableCheckFallThrough();
}
- if (!FD->isInvalidDecl())
+ if (!FD->isInvalidDecl()) {
DiagnoseUnusedParameters(FD->param_begin(), FD->param_end());
-
- if (CXXMethodDecl *Method = dyn_cast<CXXMethodDecl>(FD))
- MaybeMarkVirtualMembersReferenced(Method->getLocation(), Method);
-
+
+ // If this is a constructor, we need a vtable.
+ if (CXXConstructorDecl *Constructor = dyn_cast<CXXConstructorDecl>(FD))
+ MarkVTableUsed(FD->getLocation(), Constructor->getParent());
+
+ ComputeNRVO(Body, FunctionScopes.back()->Returns.data(),
+ FunctionScopes.back()->Returns.size());
+ }
+
assert(FD == getCurFunctionDecl() && "Function parsing confused");
} else if (ObjCMethodDecl *MD = dyn_cast_or_null<ObjCMethodDecl>(dcl)) {
assert(MD == getCurMethodDecl() && "Method parsing confused");
@@ -4636,7 +4703,9 @@ Sema::DeclPtrTy Sema::ActOnFinishFunctionBody(DeclPtrTy D, StmtArg BodyArg,
// Verify that that gotos and switch cases don't jump into scopes illegally.
// Verify that that gotos and switch cases don't jump into scopes illegally.
- if (FunctionNeedsScopeChecking() && !hasAnyErrorsInThisFunction())
+ if (FunctionNeedsScopeChecking() &&
+ !dcl->isInvalidDecl() &&
+ !hasAnyErrorsInThisFunction())
DiagnoseInvalidJumps(Body);
if (CXXDestructorDecl *Destructor = dyn_cast<CXXDestructorDecl>(dcl))
@@ -4838,38 +4907,38 @@ TypedefDecl *Sema::ParseTypedefDecl(Scope *S, Declarator &D, QualType T,
///
/// \returns true if the new tag kind is acceptable, false otherwise.
bool Sema::isAcceptableTagRedeclaration(const TagDecl *Previous,
- TagDecl::TagKind NewTag,
+ TagTypeKind NewTag,
SourceLocation NewTagLoc,
const IdentifierInfo &Name) {
// C++ [dcl.type.elab]p3:
// The class-key or enum keyword present in the
// elaborated-type-specifier shall agree in kind with the
- // declaration to which the name in theelaborated-type-specifier
+ // declaration to which the name in the elaborated-type-specifier
// refers. This rule also applies to the form of
// elaborated-type-specifier that declares a class-name or
// friend class since it can be construed as referring to the
// definition of the class. Thus, in any
// elaborated-type-specifier, the enum keyword shall be used to
- // refer to an enumeration (7.2), the union class-keyshall be
+ // refer to an enumeration (7.2), the union class-key shall be
// used to refer to a union (clause 9), and either the class or
// struct class-key shall be used to refer to a class (clause 9)
// declared using the class or struct class-key.
- TagDecl::TagKind OldTag = Previous->getTagKind();
+ TagTypeKind OldTag = Previous->getTagKind();
if (OldTag == NewTag)
return true;
- if ((OldTag == TagDecl::TK_struct || OldTag == TagDecl::TK_class) &&
- (NewTag == TagDecl::TK_struct || NewTag == TagDecl::TK_class)) {
+ if ((OldTag == TTK_Struct || OldTag == TTK_Class) &&
+ (NewTag == TTK_Struct || NewTag == TTK_Class)) {
// Warn about the struct/class tag mismatch.
bool isTemplate = false;
if (const CXXRecordDecl *Record = dyn_cast<CXXRecordDecl>(Previous))
isTemplate = Record->getDescribedClassTemplate();
Diag(NewTagLoc, diag::warn_struct_class_tag_mismatch)
- << (NewTag == TagDecl::TK_class)
+ << (NewTag == TTK_Class)
<< isTemplate << &Name
<< FixItHint::CreateReplacement(SourceRange(NewTagLoc),
- OldTag == TagDecl::TK_class? "class" : "struct");
+ OldTag == TTK_Class? "class" : "struct");
Diag(Previous->getLocation(), diag::note_previous_use);
return true;
}
@@ -4891,7 +4960,7 @@ Sema::DeclPtrTy Sema::ActOnTag(Scope *S, unsigned TagSpec, TagUseKind TUK,
"Nameless record must be a definition!");
OwnedDecl = false;
- TagDecl::TagKind Kind = TagDecl::getTagKindForTypeSpec(TagSpec);
+ TagTypeKind Kind = TypeWithKeyword::getTagTypeKindForTypeSpec(TagSpec);
// FIXME: Check explicit specializations more carefully.
bool isExplicitSpecialization = false;
@@ -4915,7 +4984,7 @@ Sema::DeclPtrTy Sema::ActOnTag(Scope *S, unsigned TagSpec, TagUseKind TUK,
} else {
// The "template<>" header is extraneous.
Diag(TemplateParams->getTemplateLoc(), diag::err_template_tag_noparams)
- << ElaboratedType::getNameForTagKind(Kind) << Name;
+ << TypeWithKeyword::getTagTypeKindName(Kind) << Name;
isExplicitSpecialization = true;
}
}
@@ -5134,8 +5203,8 @@ Sema::DeclPtrTy Sema::ActOnTag(Scope *S, unsigned TagSpec, TagUseKind TUK,
// struct or something similar.
if (!isAcceptableTagRedeclaration(PrevTagDecl, Kind, KWLoc, *Name)) {
bool SafeToContinue
- = (PrevTagDecl->getTagKind() != TagDecl::TK_enum &&
- Kind != TagDecl::TK_enum);
+ = (PrevTagDecl->getTagKind() != TTK_Enum &&
+ Kind != TTK_Enum);
if (SafeToContinue)
Diag(KWLoc, diag::err_use_with_wrong_tag)
<< Name
@@ -5289,7 +5358,7 @@ CreateNewDecl:
// PrevDecl.
TagDecl *New;
- if (Kind == TagDecl::TK_enum) {
+ if (Kind == TTK_Enum) {
// FIXME: Tag decls should be chained to any simultaneous vardecls, e.g.:
// enum X { A, B, C } D; D should chain to X.
New = EnumDecl::Create(Context, SearchDC, Loc, Name, KWLoc,
@@ -5319,16 +5388,18 @@ CreateNewDecl:
// Maybe add qualifier info.
if (SS.isNotEmpty()) {
- NestedNameSpecifier *NNS
- = static_cast<NestedNameSpecifier*>(SS.getScopeRep());
- New->setQualifierInfo(NNS, SS.getRange());
+ if (SS.isSet()) {
+ NestedNameSpecifier *NNS
+ = static_cast<NestedNameSpecifier*>(SS.getScopeRep());
+ New->setQualifierInfo(NNS, SS.getRange());
+ }
+ else
+ Invalid = true;
}
- if (Kind != TagDecl::TK_enum) {
- // Handle #pragma pack: if the #pragma pack stack has non-default
- // alignment, make up a packed attribute for this decl. These
- // attributes are checked when the ASTContext lays out the
- // structure.
+ if (RecordDecl *RD = dyn_cast<RecordDecl>(New)) {
+ // Add alignment attributes if necessary; these attributes are checked when
+ // the ASTContext lays out the structure.
//
// It is important for implementing the correct semantics that this
// happen here (in act on tag decl). The #pragma pack stack is
@@ -5336,15 +5407,14 @@ CreateNewDecl:
// many points during the parsing of a struct declaration (because
// the #pragma tokens are effectively skipped over during the
// parsing of the struct).
- if (unsigned Alignment = getPragmaPackAlignment())
- New->addAttr(::new (Context) PragmaPackAttr(Alignment * 8));
+ AddAlignmentAttributesForRecord(RD);
}
// If this is a specialization of a member class (of a class template),
// check the specialization.
if (isExplicitSpecialization && CheckMemberSpecialization(New, Previous))
Invalid = true;
-
+
if (Invalid)
New->setInvalidDecl();
@@ -5439,37 +5509,6 @@ void Sema::ActOnStartCXXMemberDeclarations(Scope *S, DeclPtrTy TagD,
"Broken injected-class-name");
}
-// Traverses the class and any nested classes, making a note of any
-// dynamic classes that have no key function so that we can mark all of
-// their virtual member functions as "used" at the end of the translation
-// unit. This ensures that all functions needed by the vtable will get
-// instantiated/synthesized.
-static void
-RecordDynamicClassesWithNoKeyFunction(Sema &S, CXXRecordDecl *Record,
- SourceLocation Loc) {
- // We don't look at dependent or undefined classes.
- if (Record->isDependentContext() || !Record->isDefinition())
- return;
-
- if (Record->isDynamicClass()) {
- const CXXMethodDecl *KeyFunction = S.Context.getKeyFunction(Record);
-
- if (!KeyFunction)
- S.ClassesWithUnmarkedVirtualMembers.push_back(std::make_pair(Record,
- Loc));
-
- if ((!KeyFunction || (KeyFunction->getBody() && KeyFunction->isInlined()))
- && Record->getLinkage() == ExternalLinkage)
- S.Diag(Record->getLocation(), diag::warn_weak_vtable) << Record;
- }
- for (DeclContext::decl_iterator D = Record->decls_begin(),
- DEnd = Record->decls_end();
- D != DEnd; ++D) {
- if (CXXRecordDecl *Nested = dyn_cast<CXXRecordDecl>(*D))
- RecordDynamicClassesWithNoKeyFunction(S, Nested, Loc);
- }
-}
-
void Sema::ActOnTagFinishDefinition(Scope *S, DeclPtrTy TagD,
SourceLocation RBraceLoc) {
AdjustDeclIfTemplate(TagD);
@@ -5481,10 +5520,6 @@ void Sema::ActOnTagFinishDefinition(Scope *S, DeclPtrTy TagD,
// Exit this scope of this tag's definition.
PopDeclContext();
-
- if (isa<CXXRecordDecl>(Tag) && !Tag->getLexicalDeclContext()->isRecord())
- RecordDynamicClassesWithNoKeyFunction(*this, cast<CXXRecordDecl>(Tag),
- RBraceLoc);
// Notify the consumer that we've defined a tag.
Consumer.HandleTagDeclDefinition(Tag);
@@ -6098,6 +6133,15 @@ void Sema::ActOnFields(Scope* S,
EnclosingDecl->setInvalidDecl();
continue;
}
+ if (!FD->getType()->isDependentType() &&
+ !Context.getBaseElementType(FD->getType())->isPODType()) {
+ Diag(FD->getLocation(), diag::err_flexible_array_has_nonpod_type)
+ << FD->getDeclName() << FD->getType();
+ FD->setInvalidDecl();
+ EnclosingDecl->setInvalidDecl();
+ continue;
+ }
+
// Okay, we have a legal flexible array member at the end of the struct.
if (Record)
Record->setHasFlexibleArrayMember(true);
@@ -6132,7 +6176,7 @@ void Sema::ActOnFields(Scope* S,
}
if (Record && FDTTy->getDecl()->hasObjectMember())
Record->setHasObjectMember(true);
- } else if (FDTy->isObjCInterfaceType()) {
+ } else if (FDTy->isObjCObjectType()) {
/// A field cannot be an Objective-c object
Diag(FD->getLocation(), diag::err_statically_allocated_object);
FD->setInvalidDecl();
@@ -6435,7 +6479,7 @@ void Sema::ActOnEnumBody(SourceLocation EnumLoc, SourceLocation LBraceLoc,
ECD->setType(EnumType);
}
- Enum->completeDefinition(Context.DependentTy, Context.DependentTy);
+ Enum->completeDefinition(Context.DependentTy, Context.DependentTy, 0, 0);
return;
}
@@ -6616,7 +6660,8 @@ void Sema::ActOnEnumBody(SourceLocation EnumLoc, SourceLocation LBraceLoc,
ECD->setType(NewTy);
}
- Enum->completeDefinition(BestType, BestPromotionType);
+ Enum->completeDefinition(BestType, BestPromotionType,
+ NumPositiveBits, NumNegativeBits);
}
Sema::DeclPtrTy Sema::ActOnFileScopeAsmDecl(SourceLocation Loc,
diff --git a/lib/Sema/SemaDeclAttr.cpp b/lib/Sema/SemaDeclAttr.cpp
index 90aa9c1c130d..c6dcc3b97b2a 100644
--- a/lib/Sema/SemaDeclAttr.cpp
+++ b/lib/Sema/SemaDeclAttr.cpp
@@ -129,11 +129,11 @@ static inline bool isNSStringType(QualType T, ASTContext &Ctx) {
if (!PT)
return false;
- const ObjCInterfaceType *ClsT =PT->getPointeeType()->getAs<ObjCInterfaceType>();
- if (!ClsT)
+ ObjCInterfaceDecl *Cls = PT->getObjectType()->getInterface();
+ if (!Cls)
return false;
- IdentifierInfo* ClsName = ClsT->getDecl()->getIdentifier();
+ IdentifierInfo* ClsName = Cls->getIdentifier();
// FIXME: Should we walk the chain of classes?
return ClsName == &Ctx.Idents.get("NSString") ||
@@ -150,7 +150,7 @@ static inline bool isCFStringType(QualType T, ASTContext &Ctx) {
return false;
const RecordDecl *RD = RT->getDecl();
- if (RD->getTagKind() != TagDecl::TK_struct)
+ if (RD->getTagKind() != TTK_Struct)
return false;
return RD->getIdentifier() == &Ctx.Idents.get("__CFString");
@@ -259,6 +259,26 @@ static void HandleIBOutlet(Decl *d, const AttributeList &Attr, Sema &S) {
S.Diag(Attr.getLoc(), diag::err_attribute_iboutlet) << Attr.getName();
}
+static void HandleIBOutletCollection(Decl *d, const AttributeList &Attr,
+ Sema &S) {
+
+ // The iboutletcollection attribute can have zero or one arguments.
+ if (Attr.getNumArgs() > 1) {
+ S.Diag(Attr.getLoc(), diag::err_attribute_wrong_number_arguments) << 1;
+ return;
+ }
+
+ // The IBOutletCollection attributes only apply to instance variables of
+ // Objective-C classes.
+ if (!(isa<ObjCIvarDecl>(d) || isa<ObjCPropertyDecl>(d))) {
+ S.Diag(Attr.getLoc(), diag::err_attribute_iboutlet) << Attr.getName();
+ return;
+ }
+
+ // FIXME: Eventually accept the type argument.
+ d->addAttr(::new (S.Context) IBOutletCollectionAttr());
+}
+
static void HandleNonNullAttr(Decl *d, const AttributeList &Attr, Sema &S) {
// GCC ignores the nonnull attribute on K&R style function prototypes, so we
// ignore it as well
@@ -280,7 +300,8 @@ static void HandleNonNullAttr(Decl *d, const AttributeList &Attr, Sema &S) {
// The argument must be an integer constant expression.
Expr *Ex = static_cast<Expr *>(*I);
llvm::APSInt ArgNum(32);
- if (!Ex->isIntegerConstantExpr(ArgNum, S.Context)) {
+ if (Ex->isTypeDependent() || Ex->isValueDependent() ||
+ !Ex->isIntegerConstantExpr(ArgNum, S.Context)) {
S.Diag(Attr.getLoc(), diag::err_attribute_argument_not_int)
<< "nonnull" << Ex->getSourceRange();
return;
@@ -560,7 +581,8 @@ static void HandleConstructorAttr(Decl *d, const AttributeList &Attr, Sema &S) {
if (Attr.getNumArgs() > 0) {
Expr *E = static_cast<Expr *>(Attr.getArg(0));
llvm::APSInt Idx(32);
- if (!E->isIntegerConstantExpr(Idx, S.Context)) {
+ if (E->isTypeDependent() || E->isValueDependent() ||
+ !E->isIntegerConstantExpr(Idx, S.Context)) {
S.Diag(Attr.getLoc(), diag::err_attribute_argument_n_not_int)
<< "constructor" << 1 << E->getSourceRange();
return;
@@ -589,7 +611,8 @@ static void HandleDestructorAttr(Decl *d, const AttributeList &Attr, Sema &S) {
if (Attr.getNumArgs() > 0) {
Expr *E = static_cast<Expr *>(Attr.getArg(0));
llvm::APSInt Idx(32);
- if (!E->isIntegerConstantExpr(Idx, S.Context)) {
+ if (E->isTypeDependent() || E->isValueDependent() ||
+ !E->isIntegerConstantExpr(Idx, S.Context)) {
S.Diag(Attr.getLoc(), diag::err_attribute_argument_n_not_int)
<< "destructor" << 1 << E->getSourceRange();
return;
@@ -745,7 +768,8 @@ static void HandleSentinelAttr(Decl *d, const AttributeList &Attr, Sema &S) {
if (Attr.getNumArgs() > 0) {
Expr *E = static_cast<Expr *>(Attr.getArg(0));
llvm::APSInt Idx(32);
- if (!E->isIntegerConstantExpr(Idx, S.Context)) {
+ if (E->isTypeDependent() || E->isValueDependent() ||
+ !E->isIntegerConstantExpr(Idx, S.Context)) {
S.Diag(Attr.getLoc(), diag::err_attribute_argument_n_not_int)
<< "sentinel" << 1 << E->getSourceRange();
return;
@@ -763,7 +787,8 @@ static void HandleSentinelAttr(Decl *d, const AttributeList &Attr, Sema &S) {
if (Attr.getNumArgs() > 1) {
Expr *E = static_cast<Expr *>(Attr.getArg(1));
llvm::APSInt Idx(32);
- if (!E->isIntegerConstantExpr(Idx, S.Context)) {
+ if (E->isTypeDependent() || E->isValueDependent() ||
+ !E->isIntegerConstantExpr(Idx, S.Context)) {
S.Diag(Attr.getLoc(), diag::err_attribute_argument_n_not_int)
<< "sentinel" << 2 << E->getSourceRange();
return;
@@ -924,7 +949,8 @@ static void HandleReqdWorkGroupSize(Decl *D, const AttributeList &Attr,
for (unsigned i = 0; i < 3; ++i) {
Expr *E = static_cast<Expr *>(Attr.getArg(i));
llvm::APSInt ArgNum(32);
- if (!E->isIntegerConstantExpr(ArgNum, S.Context)) {
+ if (E->isTypeDependent() || E->isValueDependent() ||
+ !E->isIntegerConstantExpr(ArgNum, S.Context)) {
S.Diag(Attr.getLoc(), diag::err_attribute_argument_not_int)
<< "reqd_work_group_size" << E->getSourceRange();
return;
@@ -1076,7 +1102,8 @@ static void HandleFormatArgAttr(Decl *d, const AttributeList &Attr, Sema &S) {
// checks for the 2nd argument
Expr *IdxExpr = static_cast<Expr *>(Attr.getArg(0));
llvm::APSInt Idx(32);
- if (!IdxExpr->isIntegerConstantExpr(Idx, S.Context)) {
+ if (IdxExpr->isTypeDependent() || IdxExpr->isValueDependent() ||
+ !IdxExpr->isIntegerConstantExpr(Idx, S.Context)) {
S.Diag(Attr.getLoc(), diag::err_attribute_argument_n_not_int)
<< "format" << 2 << IdxExpr->getSourceRange();
return;
@@ -1198,7 +1225,8 @@ static void HandleFormatAttr(Decl *d, const AttributeList &Attr, Sema &S) {
// checks for the 2nd argument
Expr *IdxExpr = static_cast<Expr *>(Attr.getArg(0));
llvm::APSInt Idx(32);
- if (!IdxExpr->isIntegerConstantExpr(Idx, S.Context)) {
+ if (IdxExpr->isTypeDependent() || IdxExpr->isValueDependent() ||
+ !IdxExpr->isIntegerConstantExpr(Idx, S.Context)) {
S.Diag(Attr.getLoc(), diag::err_attribute_argument_n_not_int)
<< "format" << 2 << IdxExpr->getSourceRange();
return;
@@ -1261,7 +1289,8 @@ static void HandleFormatAttr(Decl *d, const AttributeList &Attr, Sema &S) {
// check the 3rd argument
Expr *FirstArgExpr = static_cast<Expr *>(Attr.getArg(1));
llvm::APSInt FirstArg(32);
- if (!FirstArgExpr->isIntegerConstantExpr(FirstArg, S.Context)) {
+ if (FirstArgExpr->isTypeDependent() || FirstArgExpr->isValueDependent() ||
+ !FirstArgExpr->isIntegerConstantExpr(FirstArg, S.Context)) {
S.Diag(Attr.getLoc(), diag::err_attribute_argument_n_not_int)
<< "format" << 3 << FirstArgExpr->getSourceRange();
return;
@@ -1403,7 +1432,8 @@ static void HandleAlignedAttr(Decl *d, const AttributeList &Attr, Sema &S) {
Expr *alignmentExpr = static_cast<Expr *>(Attr.getArg(0));
llvm::APSInt Alignment(32);
- if (!alignmentExpr->isIntegerConstantExpr(Alignment, S.Context)) {
+ if (alignmentExpr->isTypeDependent() || alignmentExpr->isValueDependent() ||
+ !alignmentExpr->isIntegerConstantExpr(Alignment, S.Context)) {
S.Diag(Attr.getLoc(), diag::err_attribute_argument_not_int)
<< "aligned" << alignmentExpr->getSourceRange();
return;
@@ -1654,6 +1684,8 @@ static void HandleCallConvAttr(Decl *d, const AttributeList &Attr, Sema &S) {
case AttributeList::AT_stdcall:
d->addAttr(::new (S.Context) StdCallAttr());
return;
+ case AttributeList::AT_thiscall:
+ d->addAttr(::new (S.Context) ThisCallAttr());
case AttributeList::AT_cdecl:
d->addAttr(::new (S.Context) CDeclAttr());
return;
@@ -1678,7 +1710,8 @@ static void HandleRegparmAttr(Decl *d, const AttributeList &Attr, Sema &S) {
Expr *NumParamsExpr = static_cast<Expr *>(Attr.getArg(0));
llvm::APSInt NumParams(32);
- if (!NumParamsExpr->isIntegerConstantExpr(NumParams, S.Context)) {
+ if (NumParamsExpr->isTypeDependent() || NumParamsExpr->isValueDependent() ||
+ !NumParamsExpr->isIntegerConstantExpr(NumParams, S.Context)) {
S.Diag(Attr.getLoc(), diag::err_attribute_argument_not_int)
<< "regparm" << NumParamsExpr->getSourceRange();
return;
@@ -1871,7 +1904,9 @@ static void ProcessDeclAttribute(Scope *scope, Decl *D,
return;
switch (Attr.getKind()) {
case AttributeList::AT_IBAction: HandleIBAction(D, Attr, S); break;
- case AttributeList::AT_IBOutlet: HandleIBOutlet(D, Attr, S); break;
+ case AttributeList::AT_IBOutlet: HandleIBOutlet(D, Attr, S); break;
+ case AttributeList::AT_IBOutletCollection:
+ HandleIBOutletCollection(D, Attr, S); break;
case AttributeList::AT_address_space:
case AttributeList::AT_objc_gc:
case AttributeList::AT_vector_size:
@@ -1950,6 +1985,7 @@ static void ProcessDeclAttribute(Scope *scope, Decl *D,
case AttributeList::AT_stdcall:
case AttributeList::AT_cdecl:
case AttributeList::AT_fastcall:
+ case AttributeList::AT_thiscall:
HandleCallConvAttr(D, Attr, S);
break;
default:
diff --git a/lib/Sema/SemaDeclCXX.cpp b/lib/Sema/SemaDeclCXX.cpp
index b9c7d7948f2c..148d1463c201 100644
--- a/lib/Sema/SemaDeclCXX.cpp
+++ b/lib/Sema/SemaDeclCXX.cpp
@@ -461,7 +461,7 @@ Sema::CheckBaseSpecifier(CXXRecordDecl *Class,
if (BaseType->isDependentType())
return new (Context) CXXBaseSpecifier(SpecifierRange, Virtual,
- Class->getTagKind() == RecordDecl::TK_class,
+ Class->getTagKind() == TTK_Class,
Access, BaseType);
// Base specifiers must be record types.
@@ -504,9 +504,8 @@ Sema::CheckBaseSpecifier(CXXRecordDecl *Class,
SetClassDeclAttributesFromBase(Class, CXXBaseDecl, Virtual);
// Create the base specifier.
- // FIXME: Allocate via ASTContext?
return new (Context) CXXBaseSpecifier(SpecifierRange, Virtual,
- Class->getTagKind() == RecordDecl::TK_class,
+ Class->getTagKind() == TTK_Class,
Access, BaseType);
}
@@ -623,7 +622,13 @@ bool Sema::AttachBaseSpecifiers(CXXRecordDecl *Class, CXXBaseSpecifier **Bases,
QualType NewBaseType
= Context.getCanonicalType(Bases[idx]->getType());
NewBaseType = NewBaseType.getLocalUnqualifiedType();
-
+ if (!Class->hasObjectMember()) {
+ if (const RecordType *FDTTy =
+ NewBaseType.getTypePtr()->getAs<RecordType>())
+ if (FDTTy->getDecl()->hasObjectMember())
+ Class->setHasObjectMember(true);
+ }
+
if (KnownBaseTypes[NewBaseType]) {
// C++ [class.mi]p3:
// A class shall not be specified as a direct base class of a
@@ -736,6 +741,18 @@ void Sema::BuildBasePathArray(const CXXBasePaths &Paths,
BasePathArray.push_back(Path[I].Base);
}
+/// \brief Determine whether the given base path includes a virtual
+/// base class.
+bool Sema::BasePathInvolvesVirtualBase(const CXXBaseSpecifierArray &BasePath) {
+ for (CXXBaseSpecifierArray::iterator B = BasePath.begin(),
+ BEnd = BasePath.end();
+ B != BEnd; ++B)
+ if ((*B)->isVirtual())
+ return true;
+
+ return false;
+}
+
/// CheckDerivedToBaseConversion - Check whether the Derived-to-Base
/// conversion (where Derived and Base are class types) is
/// well-formed, meaning that the conversion is unambiguous (and
@@ -1125,7 +1142,8 @@ Sema::ActOnMemInitializer(DeclPtrTy ConstructorD,
// specialization, we take it as a type name.
BaseType = CheckTypenameType(ETK_None,
(NestedNameSpecifier *)SS.getScopeRep(),
- *MemberOrBase, SS.getRange());
+ *MemberOrBase, SourceLocation(),
+ SS.getRange(), IdLoc);
if (BaseType.isNull())
return true;
@@ -1192,7 +1210,7 @@ Sema::ActOnMemInitializer(DeclPtrTy ConstructorD,
static_cast<NestedNameSpecifier*>(SS.getScopeRep());
// FIXME: preserve source range information
- BaseType = Context.getQualifiedNameType(Qualifier, BaseType);
+ BaseType = Context.getElaboratedType(ETK_None, Qualifier, BaseType);
}
}
}
@@ -1357,7 +1375,7 @@ Sema::BuildBaseInitializer(QualType BaseType, TypeSourceInfo *BaseTInfo,
for (unsigned i = 0; i < NumArgs; i++)
HasDependentArg |= Args[i]->isTypeDependent();
- SourceLocation BaseLoc = BaseTInfo->getTypeLoc().getSourceRange().getBegin();
+ SourceLocation BaseLoc = BaseTInfo->getTypeLoc().getLocalSourceRange().getBegin();
if (BaseType->isDependentType() || HasDependentArg) {
// Can't check initialization for a base of dependent type or when
// any of the arguments are type-dependent expressions.
@@ -1381,7 +1399,7 @@ Sema::BuildBaseInitializer(QualType BaseType, TypeSourceInfo *BaseTInfo,
if (!BaseType->isRecordType())
return Diag(BaseLoc, diag::err_base_init_does_not_name_class)
- << BaseType << BaseTInfo->getTypeLoc().getSourceRange();
+ << BaseType << BaseTInfo->getTypeLoc().getLocalSourceRange();
// C++ [class.base.init]p2:
// [...] Unless the mem-initializer-id names a nonstatic data
@@ -1402,7 +1420,7 @@ Sema::BuildBaseInitializer(QualType BaseType, TypeSourceInfo *BaseTInfo,
// class, the mem-initializer is ill-formed.
if (DirectBaseSpec && VirtualBaseSpec)
return Diag(BaseLoc, diag::err_base_init_direct_and_virtual)
- << BaseType << BaseTInfo->getTypeLoc().getSourceRange();
+ << BaseType << BaseTInfo->getTypeLoc().getLocalSourceRange();
// C++ [base.class.init]p2:
// Unless the mem-initializer-id names a nonstatic data membeer of the
// constructor's class ot a direst or virtual base of that class, the
@@ -1410,7 +1428,7 @@ Sema::BuildBaseInitializer(QualType BaseType, TypeSourceInfo *BaseTInfo,
if (!DirectBaseSpec && !VirtualBaseSpec)
return Diag(BaseLoc, diag::err_not_direct_base_or_virtual)
<< BaseType << Context.getTypeDeclType(ClassDecl)
- << BaseTInfo->getTypeLoc().getSourceRange();
+ << BaseTInfo->getTypeLoc().getLocalSourceRange();
CXXBaseSpecifier *BaseSpec
= const_cast<CXXBaseSpecifier *>(DirectBaseSpec);
@@ -1550,42 +1568,107 @@ BuildImplicitMemberInitializer(Sema &SemaRef, CXXConstructorDecl *Constructor,
ImplicitInitializerKind ImplicitInitKind,
FieldDecl *Field,
CXXBaseOrMemberInitializer *&CXXMemberInit) {
+ if (Field->isInvalidDecl())
+ return true;
+
if (ImplicitInitKind == IIK_Copy) {
- // FIXME: We should not return early here, but will do so until
- // we know how to handle copy initialization of arrays.
- CXXMemberInit = 0;
- return false;
-
+ SourceLocation Loc = Constructor->getLocation();
ParmVarDecl *Param = Constructor->getParamDecl(0);
QualType ParamType = Param->getType().getNonReferenceType();
Expr *MemberExprBase =
DeclRefExpr::Create(SemaRef.Context, 0, SourceRange(), Param,
- SourceLocation(), ParamType, 0);
+ Loc, ParamType, 0);
+
+ // Build a reference to this field within the parameter.
+ CXXScopeSpec SS;
+ LookupResult MemberLookup(SemaRef, Field->getDeclName(), Loc,
+ Sema::LookupMemberName);
+ MemberLookup.addDecl(Field, AS_public);
+ MemberLookup.resolveKind();
+ Sema::OwningExprResult CopyCtorArg
+ = SemaRef.BuildMemberReferenceExpr(SemaRef.Owned(MemberExprBase),
+ ParamType, Loc,
+ /*IsArrow=*/false,
+ SS,
+ /*FirstQualifierInScope=*/0,
+ MemberLookup,
+ /*TemplateArgs=*/0);
+ if (CopyCtorArg.isInvalid())
+ return true;
+ // When the field we are copying is an array, create index variables for
+ // each dimension of the array. We use these index variables to subscript
+ // the source array, and other clients (e.g., CodeGen) will perform the
+ // necessary iteration with these index variables.
+ llvm::SmallVector<VarDecl *, 4> IndexVariables;
+ QualType BaseType = Field->getType();
+ QualType SizeType = SemaRef.Context.getSizeType();
+ while (const ConstantArrayType *Array
+ = SemaRef.Context.getAsConstantArrayType(BaseType)) {
+ // Create the iteration variable for this array index.
+ IdentifierInfo *IterationVarName = 0;
+ {
+ llvm::SmallString<8> Str;
+ llvm::raw_svector_ostream OS(Str);
+ OS << "__i" << IndexVariables.size();
+ IterationVarName = &SemaRef.Context.Idents.get(OS.str());
+ }
+ VarDecl *IterationVar
+ = VarDecl::Create(SemaRef.Context, SemaRef.CurContext, Loc,
+ IterationVarName, SizeType,
+ SemaRef.Context.getTrivialTypeSourceInfo(SizeType, Loc),
+ VarDecl::None, VarDecl::None);
+ IndexVariables.push_back(IterationVar);
+
+ // Create a reference to the iteration variable.
+ Sema::OwningExprResult IterationVarRef
+ = SemaRef.BuildDeclRefExpr(IterationVar, SizeType, Loc);
+ assert(!IterationVarRef.isInvalid() &&
+ "Reference to invented variable cannot fail!");
+
+ // Subscript the array with this iteration variable.
+ CopyCtorArg = SemaRef.CreateBuiltinArraySubscriptExpr(move(CopyCtorArg),
+ Loc,
+ move(IterationVarRef),
+ Loc);
+ if (CopyCtorArg.isInvalid())
+ return true;
+
+ BaseType = Array->getElementType();
+ }
- Expr *CopyCtorArg =
- MemberExpr::Create(SemaRef.Context, MemberExprBase, /*IsArrow=*/false,
- 0, SourceRange(), Field,
- DeclAccessPair::make(Field, Field->getAccess()),
- SourceLocation(), 0,
- Field->getType().getNonReferenceType());
+ // Construct the entity that we will be initializing. For an array, this
+ // will be first element in the array, which may require several levels
+ // of array-subscript entities.
+ llvm::SmallVector<InitializedEntity, 4> Entities;
+ Entities.reserve(1 + IndexVariables.size());
+ Entities.push_back(InitializedEntity::InitializeMember(Field));
+ for (unsigned I = 0, N = IndexVariables.size(); I != N; ++I)
+ Entities.push_back(InitializedEntity::InitializeElement(SemaRef.Context,
+ 0,
+ Entities.back()));
- InitializedEntity InitEntity = InitializedEntity::InitializeMember(Field);
+ // Direct-initialize to use the copy constructor.
InitializationKind InitKind =
- InitializationKind::CreateDirect(Constructor->getLocation(),
- SourceLocation(), SourceLocation());
+ InitializationKind::CreateDirect(Loc, SourceLocation(), SourceLocation());
- InitializationSequence InitSeq(SemaRef, InitEntity, InitKind,
- &CopyCtorArg, 1);
+ Expr *CopyCtorArgE = CopyCtorArg.takeAs<Expr>();
+ InitializationSequence InitSeq(SemaRef, Entities.back(), InitKind,
+ &CopyCtorArgE, 1);
- Sema::OwningExprResult MemberInit =
- InitSeq.Perform(SemaRef, InitEntity, InitKind,
- Sema::MultiExprArg(SemaRef, (void**)&CopyCtorArg, 1), 0);
+ Sema::OwningExprResult MemberInit
+ = InitSeq.Perform(SemaRef, Entities.back(), InitKind,
+ Sema::MultiExprArg(SemaRef, (void**)&CopyCtorArgE, 1));
+ MemberInit = SemaRef.MaybeCreateCXXExprWithTemporaries(move(MemberInit));
if (MemberInit.isInvalid())
return true;
-
- CXXMemberInit = 0;
+
+ CXXMemberInit
+ = CXXBaseOrMemberInitializer::Create(SemaRef.Context, Field, Loc, Loc,
+ MemberInit.takeAs<Expr>(), Loc,
+ IndexVariables.data(),
+ IndexVariables.size());
return false;
}
@@ -1640,6 +1723,81 @@ BuildImplicitMemberInitializer(Sema &SemaRef, CXXConstructorDecl *Constructor,
CXXMemberInit = 0;
return false;
}
+
+namespace {
+struct BaseAndFieldInfo {
+ Sema &S;
+ CXXConstructorDecl *Ctor;
+ bool AnyErrorsInInits;
+ ImplicitInitializerKind IIK;
+ llvm::DenseMap<const void *, CXXBaseOrMemberInitializer*> AllBaseFields;
+ llvm::SmallVector<CXXBaseOrMemberInitializer*, 8> AllToInit;
+
+ BaseAndFieldInfo(Sema &S, CXXConstructorDecl *Ctor, bool ErrorsInInits)
+ : S(S), Ctor(Ctor), AnyErrorsInInits(ErrorsInInits) {
+ // FIXME: Handle implicit move constructors.
+ if (Ctor->isImplicit() && Ctor->isCopyConstructor())
+ IIK = IIK_Copy;
+ else
+ IIK = IIK_Default;
+ }
+};
+}
+
+static bool CollectFieldInitializer(BaseAndFieldInfo &Info,
+ FieldDecl *Top, FieldDecl *Field) {
+
+ // Overwhelmingly common case: we have a direct initializer for this field.
+ if (CXXBaseOrMemberInitializer *Init = Info.AllBaseFields.lookup(Field)) {
+ Info.AllToInit.push_back(Init);
+
+ if (Field != Top) {
+ Init->setMember(Top);
+ Init->setAnonUnionMember(Field);
+ }
+ return false;
+ }
+
+ if (Info.IIK == IIK_Default && Field->isAnonymousStructOrUnion()) {
+ const RecordType *FieldClassType = Field->getType()->getAs<RecordType>();
+ assert(FieldClassType && "anonymous struct/union without record type");
+
+ // Walk through the members, tying in any initializers for fields
+ // we find. The earlier semantic checks should prevent redundant
+ // initialization of union members, given the requirement that
+ // union members never have non-trivial default constructors.
+
+ // TODO: in C++0x, it might be legal to have union members with
+ // non-trivial default constructors in unions. Revise this
+ // implementation then with the appropriate semantics.
+ CXXRecordDecl *FieldClassDecl
+ = cast<CXXRecordDecl>(FieldClassType->getDecl());
+ for (RecordDecl::field_iterator FA = FieldClassDecl->field_begin(),
+ EA = FieldClassDecl->field_end(); FA != EA; FA++)
+ if (CollectFieldInitializer(Info, Top, *FA))
+ return true;
+ }
+
+ // Don't try to build an implicit initializer if there were semantic
+ // errors in any of the initializers (and therefore we might be
+ // missing some that the user actually wrote).
+ if (Info.AnyErrorsInInits)
+ return false;
+
+ CXXBaseOrMemberInitializer *Init = 0;
+ if (BuildImplicitMemberInitializer(Info.S, Info.Ctor, Info.IIK, Field, Init))
+ return true;
+
+ // If the member doesn't need to be initialized, Init will still be null.
+ if (!Init) return false;
+
+ Info.AllToInit.push_back(Init);
+ if (Top != Field) {
+ Init->setMember(Top);
+ Init->setAnonUnionMember(Field);
+ }
+ return false;
+}
bool
Sema::SetBaseOrMemberInitializers(CXXConstructorDecl *Constructor,
@@ -1661,11 +1819,7 @@ Sema::SetBaseOrMemberInitializers(CXXConstructorDecl *Constructor,
return false;
}
- ImplicitInitializerKind ImplicitInitKind = IIK_Default;
-
- // FIXME: Handle implicit move constructors.
- if (Constructor->isImplicit() && Constructor->isCopyConstructor())
- ImplicitInitKind = IIK_Copy;
+ BaseAndFieldInfo Info(*this, Constructor, AnyErrors);
// We need to build the initializer AST according to order of construction
// and not what user specified in the Initializers list.
@@ -1673,17 +1827,15 @@ Sema::SetBaseOrMemberInitializers(CXXConstructorDecl *Constructor,
if (!ClassDecl)
return true;
- llvm::SmallVector<CXXBaseOrMemberInitializer*, 32> AllToInit;
- llvm::DenseMap<const void *, CXXBaseOrMemberInitializer*> AllBaseFields;
bool HadError = false;
for (unsigned i = 0; i < NumInitializers; i++) {
CXXBaseOrMemberInitializer *Member = Initializers[i];
if (Member->isBaseInitializer())
- AllBaseFields[Member->getBaseClass()->getAs<RecordType>()] = Member;
+ Info.AllBaseFields[Member->getBaseClass()->getAs<RecordType>()] = Member;
else
- AllBaseFields[Member->getMember()] = Member;
+ Info.AllBaseFields[Member->getMember()] = Member;
}
// Keep track of the direct virtual bases.
@@ -1699,22 +1851,23 @@ Sema::SetBaseOrMemberInitializers(CXXConstructorDecl *Constructor,
E = ClassDecl->vbases_end(); VBase != E; ++VBase) {
if (CXXBaseOrMemberInitializer *Value
- = AllBaseFields.lookup(VBase->getType()->getAs<RecordType>())) {
- AllToInit.push_back(Value);
+ = Info.AllBaseFields.lookup(VBase->getType()->getAs<RecordType>())) {
+ Info.AllToInit.push_back(Value);
} else if (!AnyErrors) {
bool IsInheritedVirtualBase = !DirectVBases.count(VBase);
CXXBaseOrMemberInitializer *CXXBaseInit;
- if (BuildImplicitBaseInitializer(*this, Constructor, ImplicitInitKind,
+ if (BuildImplicitBaseInitializer(*this, Constructor, Info.IIK,
VBase, IsInheritedVirtualBase,
CXXBaseInit)) {
HadError = true;
continue;
}
- AllToInit.push_back(CXXBaseInit);
+ Info.AllToInit.push_back(CXXBaseInit);
}
}
+ // Non-virtual bases.
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.
@@ -1722,70 +1875,39 @@ Sema::SetBaseOrMemberInitializers(CXXConstructorDecl *Constructor,
continue;
if (CXXBaseOrMemberInitializer *Value
- = AllBaseFields.lookup(Base->getType()->getAs<RecordType>())) {
- AllToInit.push_back(Value);
+ = Info.AllBaseFields.lookup(Base->getType()->getAs<RecordType>())) {
+ Info.AllToInit.push_back(Value);
} else if (!AnyErrors) {
CXXBaseOrMemberInitializer *CXXBaseInit;
- if (BuildImplicitBaseInitializer(*this, Constructor, ImplicitInitKind,
+ if (BuildImplicitBaseInitializer(*this, Constructor, Info.IIK,
Base, /*IsInheritedVirtualBase=*/false,
CXXBaseInit)) {
HadError = true;
continue;
}
- AllToInit.push_back(CXXBaseInit);
+ Info.AllToInit.push_back(CXXBaseInit);
}
}
- // non-static data members.
+ // Fields.
for (CXXRecordDecl::field_iterator Field = ClassDecl->field_begin(),
E = ClassDecl->field_end(); Field != E; ++Field) {
- if ((*Field)->isAnonymousStructOrUnion()) {
- if (const RecordType *FieldClassType =
- Field->getType()->getAs<RecordType>()) {
- CXXRecordDecl *FieldClassDecl
- = cast<CXXRecordDecl>(FieldClassType->getDecl());
- for (RecordDecl::field_iterator FA = FieldClassDecl->field_begin(),
- EA = FieldClassDecl->field_end(); FA != EA; FA++) {
- if (CXXBaseOrMemberInitializer *Value = AllBaseFields.lookup(*FA)) {
- // 'Member' is the anonymous union field and 'AnonUnionMember' is
- // set to the anonymous union data member used in the initializer
- // list.
- Value->setMember(*Field);
- Value->setAnonUnionMember(*FA);
- AllToInit.push_back(Value);
- break;
- }
- }
- }
- continue;
- }
- if (CXXBaseOrMemberInitializer *Value = AllBaseFields.lookup(*Field)) {
- AllToInit.push_back(Value);
+ if ((*Field)->getType()->isIncompleteArrayType()) {
+ assert(ClassDecl->hasFlexibleArrayMember() &&
+ "Incomplete array type is not valid");
continue;
}
-
- if (AnyErrors)
- continue;
-
- CXXBaseOrMemberInitializer *Member;
- if (BuildImplicitMemberInitializer(*this, Constructor, ImplicitInitKind,
- *Field, Member)) {
+ if (CollectFieldInitializer(Info, *Field, *Field))
HadError = true;
- continue;
- }
-
- // If the member doesn't need to be initialized, it will be null.
- if (Member)
- AllToInit.push_back(Member);
}
- NumInitializers = AllToInit.size();
+ NumInitializers = Info.AllToInit.size();
if (NumInitializers > 0) {
Constructor->setNumBaseOrMemberInitializers(NumInitializers);
CXXBaseOrMemberInitializer **baseOrMemberInitializers =
new (Context) CXXBaseOrMemberInitializer*[NumInitializers];
- memcpy(baseOrMemberInitializers, AllToInit.data(),
+ memcpy(baseOrMemberInitializers, Info.AllToInit.data(),
NumInitializers * sizeof(CXXBaseOrMemberInitializer*));
Constructor->setBaseOrMemberInitializers(baseOrMemberInitializers);
@@ -1900,9 +2022,7 @@ DiagnoseBaseOrMemInitializerOrder(Sema &SemaRef,
// If we didn't find this initializer, it must be because we
// scanned past it on a previous iteration. That can only
// happen if we're out of order; emit a warning.
- if (IdealIndex == NumIdealInits) {
- assert(PrevInit && "initializer not found in initializer list");
-
+ if (IdealIndex == NumIdealInits && PrevInit) {
Sema::SemaDiagnosticBuilder D =
SemaRef.Diag(PrevInit->getSourceLocation(),
diag::warn_initializer_out_of_order);
@@ -2028,6 +2148,9 @@ void Sema::ActOnMemInitializers(DeclPtrTy ConstructorDecl,
for (unsigned i = 0; i < NumMemInits; i++) {
CXXBaseOrMemberInitializer *Init = MemInits[i];
+ // Set the source order index.
+ Init->setSourceOrder(i);
+
if (Init->isMemberInitializer()) {
FieldDecl *Field = Init->getMember();
if (CheckRedundantInit(*this, Init, Members[Field]) ||
@@ -2064,7 +2187,8 @@ Sema::MarkBaseAndMemberDestructorsReferenced(SourceLocation Location,
for (CXXRecordDecl::field_iterator I = ClassDecl->field_begin(),
E = ClassDecl->field_end(); I != E; ++I) {
FieldDecl *Field = *I;
-
+ if (Field->isInvalidDecl())
+ continue;
QualType FieldType = Context.getBaseElementType(Field->getType());
const RecordType* RT = FieldType->getAs<RecordType>();
@@ -2403,6 +2527,9 @@ void Sema::CheckCompletedCXXClass(Scope *S, CXXRecordDecl *Record) {
}
}
}
+
+ if (Record->isDynamicClass())
+ DynamicClasses.push_back(Record);
}
void Sema::ActOnFinishCXXMemberSpecification(Scope* S, SourceLocation RLoc,
@@ -2530,7 +2657,7 @@ void Sema::AddImplicitlyDeclaredMembersToClass(Scope *S,
Context.getFunctionType(Context.VoidTy,
&ArgType, 1,
false, 0,
- /*FIXME:*/false,
+ /*FIXME: hasExceptionSpec*/false,
false, 0, 0,
FunctionType::ExtInfo()),
/*TInfo=*/0,
@@ -2623,7 +2750,7 @@ void Sema::AddImplicitlyDeclaredMembersToClass(Scope *S,
CXXMethodDecl::Create(Context, ClassDecl, ClassDecl->getLocation(), Name,
Context.getFunctionType(RetType, &ArgType, 1,
false, 0,
- /*FIXME:*/false,
+ /*FIXME: hasExceptionSpec*/false,
false, 0, 0,
FunctionType::ExtInfo()),
/*TInfo=*/0, /*isStatic=*/false,
@@ -2659,7 +2786,7 @@ void Sema::AddImplicitlyDeclaredMembersToClass(Scope *S,
// inline public member of its class.
QualType Ty = Context.getFunctionType(Context.VoidTy,
0, 0, false, 0,
- /*FIXME:*/false,
+ /*FIXME: hasExceptionSpec*/false,
false, 0, 0, FunctionType::ExtInfo());
DeclarationName Name
@@ -3817,8 +3944,9 @@ bool Sema::CheckUsingDeclRedeclaration(SourceLocation UsingLoc,
// A using-declaration is a declaration and can therefore be used
// repeatedly where (and only where) multiple declarations are
// allowed.
- // That's only in file contexts.
- if (CurContext->getLookupContext()->isFileContext())
+ //
+ // That's in non-member contexts.
+ if (!CurContext->getLookupContext()->isRecord())
return false;
NestedNameSpecifier *Qual
@@ -4082,12 +4210,15 @@ void Sema::DefineImplicitDefaultConstructor(SourceLocation CurrentLocation,
assert(ClassDecl && "DefineImplicitDefaultConstructor - invalid constructor");
ImplicitlyDefinedFunctionScope Scope(*this, Constructor);
- if (SetBaseOrMemberInitializers(Constructor, 0, 0, /*AnyErrors=*/false)) {
+ ErrorTrap Trap(*this);
+ if (SetBaseOrMemberInitializers(Constructor, 0, 0, /*AnyErrors=*/false) ||
+ Trap.hasErrorOccurred()) {
Diag(CurrentLocation, diag::note_member_synthesized_at)
<< CXXConstructor << Context.getTagDeclType(ClassDecl);
Constructor->setInvalidDecl();
} else {
Constructor->setUsed();
+ MarkVTableUsed(CurrentLocation, ClassDecl);
}
}
@@ -4098,14 +4229,16 @@ void Sema::DefineImplicitDestructor(SourceLocation CurrentLocation,
CXXRecordDecl *ClassDecl = Destructor->getParent();
assert(ClassDecl && "DefineImplicitDestructor - invalid destructor");
+ if (Destructor->isInvalidDecl())
+ return;
+
ImplicitlyDefinedFunctionScope Scope(*this, Destructor);
+ ErrorTrap Trap(*this);
MarkBaseAndMemberDestructorsReferenced(Destructor->getLocation(),
Destructor->getParent());
- // FIXME: If CheckDestructor fails, we should emit a note about where the
- // implicit destructor was needed.
- if (CheckDestructor(Destructor)) {
+ if (CheckDestructor(Destructor) || Trap.hasErrorOccurred()) {
Diag(CurrentLocation, diag::note_member_synthesized_at)
<< CXXDestructor << Context.getTagDeclType(ClassDecl);
@@ -4114,6 +4247,7 @@ void Sema::DefineImplicitDestructor(SourceLocation CurrentLocation,
}
Destructor->setUsed();
+ MarkVTableUsed(CurrentLocation, ClassDecl);
}
/// \brief Builds a statement that copies the given entity from \p From to
@@ -4332,6 +4466,7 @@ void Sema::DefineImplicitCopyAssignment(SourceLocation CurrentLocation,
CopyAssignOperator->setUsed();
ImplicitlyDefinedFunctionScope Scope(*this, CopyAssignOperator);
+ ErrorTrap Trap(*this);
// C++0x [class.copy]p30:
// The implicitly-defined or explicitly-defaulted copy assignment operator
@@ -4407,8 +4542,10 @@ void Sema::DefineImplicitCopyAssignment(SourceLocation CurrentLocation,
move(To), Owned(From),
/*CopyingBaseSubobject=*/true);
if (Copy.isInvalid()) {
- Invalid = true;
- continue;
+ Diag(CurrentLocation, diag::note_member_synthesized_at)
+ << CXXCopyAssignment << Context.getTagDeclType(ClassDecl);
+ CopyAssignOperator->setInvalidDecl();
+ return;
}
// Success! Record the copy.
@@ -4427,7 +4564,8 @@ void Sema::DefineImplicitCopyAssignment(SourceLocation CurrentLocation,
Diag(ClassDecl->getLocation(), diag::err_uninitialized_member_for_assign)
<< Context.getTagDeclType(ClassDecl) << 0 << Field->getDeclName();
Diag(Field->getLocation(), diag::note_declared_at);
- Diag(Loc, diag::note_first_required_here);
+ Diag(CurrentLocation, diag::note_member_synthesized_at)
+ << CXXCopyAssignment << Context.getTagDeclType(ClassDecl);
Invalid = true;
continue;
}
@@ -4438,12 +4576,18 @@ void Sema::DefineImplicitCopyAssignment(SourceLocation CurrentLocation,
Diag(ClassDecl->getLocation(), diag::err_uninitialized_member_for_assign)
<< Context.getTagDeclType(ClassDecl) << 1 << Field->getDeclName();
Diag(Field->getLocation(), diag::note_declared_at);
- Diag(Loc, diag::note_first_required_here);
+ Diag(CurrentLocation, diag::note_member_synthesized_at)
+ << CXXCopyAssignment << Context.getTagDeclType(ClassDecl);
Invalid = true;
continue;
}
QualType FieldType = Field->getType().getNonReferenceType();
+ if (FieldType->isIncompleteArrayType()) {
+ assert(ClassDecl->hasFlexibleArrayMember() &&
+ "Incomplete array type is not valid");
+ continue;
+ }
// Build references to the field in the object we're copying from and to.
CXXScopeSpec SS; // Intentionally empty
@@ -4528,8 +4672,10 @@ void Sema::DefineImplicitCopyAssignment(SourceLocation CurrentLocation,
move(To), move(From),
/*CopyingBaseSubobject=*/false);
if (Copy.isInvalid()) {
- Invalid = true;
- continue;
+ Diag(CurrentLocation, diag::note_member_synthesized_at)
+ << CXXCopyAssignment << Context.getTagDeclType(ClassDecl);
+ CopyAssignOperator->setInvalidDecl();
+ return;
}
// Success! Record the copy.
@@ -4546,6 +4692,12 @@ void Sema::DefineImplicitCopyAssignment(SourceLocation CurrentLocation,
Invalid = true;
else {
Statements.push_back(Return.takeAs<Stmt>());
+
+ if (Trap.hasErrorOccurred()) {
+ Diag(CurrentLocation, diag::note_member_synthesized_at)
+ << CXXCopyAssignment << Context.getTagDeclType(ClassDecl);
+ Invalid = true;
+ }
}
}
@@ -4572,37 +4724,22 @@ void Sema::DefineImplicitCopyConstructor(SourceLocation CurrentLocation,
assert(ClassDecl && "DefineImplicitCopyConstructor - invalid constructor");
ImplicitlyDefinedFunctionScope Scope(*this, CopyConstructor);
+ ErrorTrap Trap(*this);
- if (SetBaseOrMemberInitializers(CopyConstructor, 0, 0, /*AnyErrors=*/false)) {
+ if (SetBaseOrMemberInitializers(CopyConstructor, 0, 0, /*AnyErrors=*/false) ||
+ Trap.hasErrorOccurred()) {
Diag(CurrentLocation, diag::note_member_synthesized_at)
- << CXXCopyConstructor << Context.getTagDeclType(ClassDecl);
+ << CXXCopyConstructor << Context.getTagDeclType(ClassDecl);
CopyConstructor->setInvalidDecl();
- } else {
- CopyConstructor->setUsed();
- }
-
- // FIXME: Once SetBaseOrMemberInitializers can handle copy initialization of
- // fields, this code below should be removed.
- for (CXXRecordDecl::field_iterator Field = ClassDecl->field_begin(),
- FieldEnd = ClassDecl->field_end();
- Field != FieldEnd; ++Field) {
- QualType FieldType = Context.getCanonicalType((*Field)->getType());
- if (const ArrayType *Array = Context.getAsArrayType(FieldType))
- FieldType = Array->getElementType();
- if (const RecordType *FieldClassType = FieldType->getAs<RecordType>()) {
- CXXRecordDecl *FieldClassDecl
- = cast<CXXRecordDecl>(FieldClassType->getDecl());
- if (CXXConstructorDecl *FieldCopyCtor =
- FieldClassDecl->getCopyConstructor(Context, TypeQuals)) {
- CheckDirectMemberAccess(Field->getLocation(),
- FieldCopyCtor,
- PDiag(diag::err_access_copy_field)
- << Field->getDeclName() << Field->getType());
-
- MarkDeclarationReferenced(CurrentLocation, FieldCopyCtor);
- }
- }
+ } else {
+ CopyConstructor->setBody(ActOnCompoundStmt(CopyConstructor->getLocation(),
+ CopyConstructor->getLocation(),
+ MultiStmtArg(*this, 0, 0),
+ /*isStmtExpr=*/false)
+ .takeAs<Stmt>());
}
+
+ CopyConstructor->setUsed();
}
Sema::OwningExprResult
@@ -4672,7 +4809,7 @@ bool Sema::InitializeVarWithConstructor(VarDecl *VD,
void Sema::FinalizeVarWithDestructor(VarDecl *VD, const RecordType *Record) {
CXXRecordDecl *ClassDecl = cast<CXXRecordDecl>(Record->getDecl());
if (!ClassDecl->isInvalidDecl() && !VD->isInvalidDecl() &&
- !ClassDecl->hasTrivialDestructor()) {
+ !ClassDecl->hasTrivialDestructor() && !ClassDecl->isDependentContext()) {
CXXDestructorDecl *Destructor = ClassDecl->getDestructor(Context);
MarkDeclarationReferenced(VD->getLocation(), Destructor);
CheckDestructorAccess(VD->getLocation(), Destructor,
@@ -5419,7 +5556,7 @@ FriendDecl *Sema::CheckFriendTypeDecl(SourceLocation FriendLoc,
assert(TSInfo && "NULL TypeSourceInfo for friend type declaration");
QualType T = TSInfo->getType();
- SourceRange TypeRange = TSInfo->getTypeLoc().getSourceRange();
+ SourceRange TypeRange = TSInfo->getTypeLoc().getLocalSourceRange();
if (!getLangOptions().CPlusPlus0x) {
// C++03 [class.friend]p2:
@@ -5948,90 +6085,125 @@ Sema::ActOnCXXConditionDeclaration(Scope *S, Declarator &D) {
return Dcl;
}
-static bool needsVTable(CXXMethodDecl *MD, ASTContext &Context) {
- // Ignore dependent types.
- if (MD->isDependentContext())
- return false;
-
- // Ignore declarations that are not definitions.
- if (!MD->isThisDeclarationADefinition())
- return false;
-
- CXXRecordDecl *RD = MD->getParent();
-
- // Ignore classes without a vtable.
- if (!RD->isDynamicClass())
- return false;
-
- switch (MD->getParent()->getTemplateSpecializationKind()) {
- case TSK_Undeclared:
- case TSK_ExplicitSpecialization:
- // Classes that aren't instantiations of templates don't need their
- // virtual methods marked until we see the definition of the key
- // function.
- break;
+void Sema::MarkVTableUsed(SourceLocation Loc, CXXRecordDecl *Class,
+ bool DefinitionRequired) {
+ // Ignore any vtable uses in unevaluated operands or for classes that do
+ // not have a vtable.
+ if (!Class->isDynamicClass() || Class->isDependentContext() ||
+ CurContext->isDependentContext() ||
+ ExprEvalContexts.back().Context == Unevaluated)
+ return;
- case TSK_ImplicitInstantiation:
- // This is a constructor of a class template; mark all of the virtual
- // members as referenced to ensure that they get instantiatied.
- if (isa<CXXConstructorDecl>(MD) || isa<CXXDestructorDecl>(MD))
- return true;
- break;
+ // Try to insert this class into the map.
+ Class = cast<CXXRecordDecl>(Class->getCanonicalDecl());
+ std::pair<llvm::DenseMap<CXXRecordDecl *, bool>::iterator, bool>
+ Pos = VTablesUsed.insert(std::make_pair(Class, DefinitionRequired));
+ if (!Pos.second) {
+ // If we already had an entry, check to see if we are promoting this vtable
+ // to required a definition. If so, we need to reappend to the VTableUses
+ // list, since we may have already processed the first entry.
+ if (DefinitionRequired && !Pos.first->second) {
+ Pos.first->second = true;
+ } else {
+ // Otherwise, we can early exit.
+ return;
+ }
+ }
- case TSK_ExplicitInstantiationDeclaration:
- return false;
+ // Local classes need to have their virtual members marked
+ // immediately. For all other classes, we mark their virtual members
+ // at the end of the translation unit.
+ if (Class->isLocalClass())
+ MarkVirtualMembersReferenced(Loc, Class);
+ else
+ VTableUses.push_back(std::make_pair(Class, Loc));
+}
- case TSK_ExplicitInstantiationDefinition:
- // This is method of a explicit instantiation; mark all of the virtual
- // members as referenced to ensure that they get instantiatied.
- return true;
+bool Sema::DefineUsedVTables() {
+ // If any dynamic classes have their key function defined within
+ // this translation unit, then those vtables are considered "used" and must
+ // be emitted.
+ for (unsigned I = 0, N = DynamicClasses.size(); I != N; ++I) {
+ if (const CXXMethodDecl *KeyFunction
+ = Context.getKeyFunction(DynamicClasses[I])) {
+ const FunctionDecl *Definition = 0;
+ if (KeyFunction->getBody(Definition))
+ MarkVTableUsed(Definition->getLocation(), DynamicClasses[I], true);
+ }
}
- // Consider only out-of-line definitions of member functions. When we see
- // an inline definition, it's too early to compute the key function.
- if (!MD->isOutOfLine())
+ if (VTableUses.empty())
return false;
+
+ // Note: The VTableUses vector could grow as a result of marking
+ // the members of a class as "used", so we check the size each
+ // time through the loop and prefer indices (with are stable) to
+ // iterators (which are not).
+ for (unsigned I = 0; I != VTableUses.size(); ++I) {
+ CXXRecordDecl *Class = VTableUses[I].first->getDefinition();
+ if (!Class)
+ continue;
- const CXXMethodDecl *KeyFunction = Context.getKeyFunction(RD);
-
- // If there is no key function, we will need a copy of the vtable.
- if (!KeyFunction)
- return true;
-
- // If this is the key function, we need to mark virtual members.
- if (KeyFunction->getCanonicalDecl() == MD->getCanonicalDecl())
- return true;
-
- return false;
-}
-
-void Sema::MaybeMarkVirtualMembersReferenced(SourceLocation Loc,
- CXXMethodDecl *MD) {
- CXXRecordDecl *RD = MD->getParent();
+ SourceLocation Loc = VTableUses[I].second;
+
+ // If this class has a key function, but that key function is
+ // defined in another translation unit, we don't need to emit the
+ // vtable even though we're using it.
+ const CXXMethodDecl *KeyFunction = Context.getKeyFunction(Class);
+ if (KeyFunction && !KeyFunction->getBody()) {
+ switch (KeyFunction->getTemplateSpecializationKind()) {
+ case TSK_Undeclared:
+ case TSK_ExplicitSpecialization:
+ case TSK_ExplicitInstantiationDeclaration:
+ // The key function is in another translation unit.
+ continue;
- // We will need to mark all of the virtual members as referenced to build the
- // vtable.
- if (!needsVTable(MD, Context))
- return;
+ case TSK_ExplicitInstantiationDefinition:
+ case TSK_ImplicitInstantiation:
+ // We will be instantiating the key function.
+ break;
+ }
+ } else if (!KeyFunction) {
+ // If we have a class with no key function that is the subject
+ // of an explicit instantiation declaration, suppress the
+ // vtable; it will live with the explicit instantiation
+ // definition.
+ bool IsExplicitInstantiationDeclaration
+ = Class->getTemplateSpecializationKind()
+ == TSK_ExplicitInstantiationDeclaration;
+ for (TagDecl::redecl_iterator R = Class->redecls_begin(),
+ REnd = Class->redecls_end();
+ R != REnd; ++R) {
+ TemplateSpecializationKind TSK
+ = cast<CXXRecordDecl>(*R)->getTemplateSpecializationKind();
+ if (TSK == TSK_ExplicitInstantiationDeclaration)
+ IsExplicitInstantiationDeclaration = true;
+ else if (TSK == TSK_ExplicitInstantiationDefinition) {
+ IsExplicitInstantiationDeclaration = false;
+ break;
+ }
+ }
- TemplateSpecializationKind kind = RD->getTemplateSpecializationKind();
- if (kind == TSK_ImplicitInstantiation)
- ClassesWithUnmarkedVirtualMembers.push_back(std::make_pair(RD, Loc));
- else
- MarkVirtualMembersReferenced(Loc, RD);
-}
+ if (IsExplicitInstantiationDeclaration)
+ continue;
+ }
-bool Sema::ProcessPendingClassesWithUnmarkedVirtualMembers() {
- if (ClassesWithUnmarkedVirtualMembers.empty())
- return false;
-
- while (!ClassesWithUnmarkedVirtualMembers.empty()) {
- CXXRecordDecl *RD = ClassesWithUnmarkedVirtualMembers.back().first;
- SourceLocation Loc = ClassesWithUnmarkedVirtualMembers.back().second;
- ClassesWithUnmarkedVirtualMembers.pop_back();
- MarkVirtualMembersReferenced(Loc, RD);
+ // Mark all of the virtual members of this class as referenced, so
+ // that we can build a vtable. Then, tell the AST consumer that a
+ // vtable for this class is required.
+ MarkVirtualMembersReferenced(Loc, Class);
+ CXXRecordDecl *Canonical = cast<CXXRecordDecl>(Class->getCanonicalDecl());
+ Consumer.HandleVTable(Class, VTablesUsed[Canonical]);
+
+ // Optionally warn if we're emitting a weak vtable.
+ if (Class->getLinkage() == ExternalLinkage &&
+ Class->getTemplateSpecializationKind() != TSK_ImplicitInstantiation) {
+ if (!KeyFunction || (KeyFunction->getBody() && KeyFunction->isInlined()))
+ Diag(Class->getLocation(), diag::warn_weak_vtable) << Class;
+ }
}
-
+ VTableUses.clear();
+
return true;
}
@@ -6076,6 +6248,9 @@ void Sema::SetIvarInitializers(ObjCImplementationDecl *ObjCImplementation) {
llvm::SmallVector<CXXBaseOrMemberInitializer*, 32> AllToInit;
for (unsigned i = 0; i < ivars.size(); i++) {
FieldDecl *Field = ivars[i];
+ if (Field->isInvalidDecl())
+ continue;
+
CXXBaseOrMemberInitializer *Member;
InitializedEntity InitEntity = InitializedEntity::InitializeMember(Field);
InitializationKind InitKind =
@@ -6098,6 +6273,20 @@ void Sema::SetIvarInitializers(ObjCImplementationDecl *ObjCImplementation) {
MemberInit.takeAs<Expr>(),
SourceLocation());
AllToInit.push_back(Member);
+
+ // Be sure that the destructor is accessible and is marked as referenced.
+ if (const RecordType *RecordTy
+ = Context.getBaseElementType(Field->getType())
+ ->getAs<RecordType>()) {
+ CXXRecordDecl *RD = cast<CXXRecordDecl>(RecordTy->getDecl());
+ if (CXXDestructorDecl *Destructor
+ = const_cast<CXXDestructorDecl*>(RD->getDestructor(Context))) {
+ MarkDeclarationReferenced(Field->getLocation(), Destructor);
+ CheckDestructorAccess(Field->getLocation(), Destructor,
+ PDiag(diag::err_access_dtor_ivar)
+ << Context.getBaseElementType(Field->getType()));
+ }
+ }
}
ObjCImplementation->setIvarInitializers(Context,
AllToInit.data(), AllToInit.size());
diff --git a/lib/Sema/SemaDeclObjC.cpp b/lib/Sema/SemaDeclObjC.cpp
index d446cc13da26..3b05f5ac28da 100644
--- a/lib/Sema/SemaDeclObjC.cpp
+++ b/lib/Sema/SemaDeclObjC.cpp
@@ -142,8 +142,8 @@ ActOnStartClassInterface(SourceLocation AtInterfaceLoc,
// typedef. If we do, get the underlying class type.
if (const TypedefDecl *TDecl = dyn_cast_or_null<TypedefDecl>(PrevDecl)) {
QualType T = TDecl->getUnderlyingType();
- if (T->isObjCInterfaceType()) {
- if (NamedDecl *IDecl = T->getAs<ObjCInterfaceType>()->getDecl())
+ if (T->isObjCObjectType()) {
+ if (NamedDecl *IDecl = T->getAs<ObjCObjectType>()->getInterface())
SuperClassDecl = dyn_cast<ObjCInterfaceDecl>(IDecl);
}
}
@@ -210,8 +210,8 @@ Sema::DeclPtrTy Sema::ActOnCompatiblityAlias(SourceLocation AtLoc,
LookupOrdinaryName, ForRedeclaration);
if (const TypedefDecl *TDecl = dyn_cast_or_null<TypedefDecl>(CDeclU)) {
QualType T = TDecl->getUnderlyingType();
- if (T->isObjCInterfaceType()) {
- if (NamedDecl *IDecl = T->getAs<ObjCInterfaceType>()->getDecl()) {
+ if (T->isObjCObjectType()) {
+ if (NamedDecl *IDecl = T->getAs<ObjCObjectType>()->getInterface()) {
ClassName = IDecl->getIdentifier();
CDeclU = LookupSingleName(TUScope, ClassName, ClassLocation,
LookupOrdinaryName, ForRedeclaration);
@@ -763,6 +763,10 @@ void Sema::WarnConflictingTypedMethods(ObjCMethodDecl *ImpMethodDecl,
<< (*IM)->getType();
Diag((*IF)->getLocation(), diag::note_previous_definition);
}
+ if (ImpMethodDecl->isVariadic() != IntfMethodDecl->isVariadic()) {
+ Diag(ImpMethodDecl->getLocation(), diag::warn_conflicting_variadic);
+ Diag(IntfMethodDecl->getLocation(), diag::note_previous_declaration);
+ }
}
/// FIXME: Type hierarchies in Objective-C can be deep. We could most likely
@@ -925,7 +929,7 @@ void Sema::MatchAllMethodDeclarations(const llvm::DenseSet<Selector> &InsMap,
}
}
-void Sema::ImplMethodsVsClassMethods(ObjCImplDecl* IMPDecl,
+void Sema::ImplMethodsVsClassMethods(Scope *S, ObjCImplDecl* IMPDecl,
ObjCContainerDecl* CDecl,
bool IncompleteImpl) {
llvm::DenseSet<Selector> InsMap;
@@ -938,8 +942,8 @@ void Sema::ImplMethodsVsClassMethods(ObjCImplDecl* IMPDecl,
// Check and see if properties declared in the interface have either 1)
// an implementation or 2) there is a @synthesize/@dynamic implementation
// of the property in the @implementation.
- if (isa<ObjCInterfaceDecl>(CDecl))
- DiagnoseUnimplementedProperties(IMPDecl, CDecl, InsMap);
+ if (isa<ObjCInterfaceDecl>(CDecl) && !LangOpts.ObjCNonFragileABI2)
+ DiagnoseUnimplementedProperties(S, IMPDecl, CDecl, InsMap);
llvm::DenseSet<Selector> ClsMap;
for (ObjCImplementationDecl::classmeth_iterator
@@ -968,7 +972,7 @@ void Sema::ImplMethodsVsClassMethods(ObjCImplDecl* IMPDecl,
for (ObjCCategoryDecl *Categories = I->getCategoryList();
Categories; Categories = Categories->getNextClassCategory()) {
if (Categories->IsClassExtension()) {
- ImplMethodsVsClassMethods(IMPDecl, Categories, IncompleteImpl);
+ ImplMethodsVsClassMethods(S, IMPDecl, Categories, IncompleteImpl);
break;
}
}
@@ -990,7 +994,7 @@ void Sema::ImplMethodsVsClassMethods(ObjCImplDecl* IMPDecl,
I = IMP->instmeth_begin(), E = IMP->instmeth_end(); I!=E; ++I)
InsMap.insert((*I)->getSelector());
}
- DiagnoseUnimplementedProperties(IMPDecl, CDecl, InsMap);
+ DiagnoseUnimplementedProperties(S, IMPDecl, CDecl, InsMap);
}
} else
assert(false && "invalid ObjCContainerDecl type.");
@@ -1024,15 +1028,15 @@ Sema::ActOnForwardClassDeclaration(SourceLocation AtClassLoc,
//
// FIXME: Make an extension?
TypedefDecl *TDD = dyn_cast<TypedefDecl>(PrevDecl);
- if (!TDD || !isa<ObjCInterfaceType>(TDD->getUnderlyingType())) {
+ if (!TDD || !TDD->getUnderlyingType()->isObjCObjectType()) {
Diag(AtClassLoc, diag::err_redefinition_different_kind) << IdentList[i];
Diag(PrevDecl->getLocation(), diag::note_previous_definition);
- } else if (TDD) {
+ } else {
// a forward class declaration matching a typedef name of a class refers
// to the underlying class.
- if (ObjCInterfaceType * OI =
- dyn_cast<ObjCInterfaceType>(TDD->getUnderlyingType()))
- PrevDecl = OI->getDecl();
+ if (const ObjCObjectType *OI =
+ TDD->getUnderlyingType()->getAs<ObjCObjectType>())
+ PrevDecl = OI->getInterface();
}
}
ObjCInterfaceDecl *IDecl = dyn_cast_or_null<ObjCInterfaceDecl>(PrevDecl);
@@ -1326,7 +1330,7 @@ void Sema::DiagnoseDuplicateIvars(ObjCInterfaceDecl *ID,
// Note: For class/category implemenations, allMethods/allProperties is
// always null.
-void Sema::ActOnAtEnd(SourceRange AtEnd,
+void Sema::ActOnAtEnd(Scope *S, SourceRange AtEnd,
DeclPtrTy classDecl,
DeclPtrTy *allMethods, unsigned allNum,
DeclPtrTy *allProperties, unsigned pNum,
@@ -1433,7 +1437,9 @@ void Sema::ActOnAtEnd(SourceRange AtEnd,
if (ObjCImplementationDecl *IC=dyn_cast<ObjCImplementationDecl>(ClassDecl)) {
IC->setAtEndRange(AtEnd);
if (ObjCInterfaceDecl* IDecl = IC->getClassInterface()) {
- ImplMethodsVsClassMethods(IC, IDecl);
+ if (LangOpts.ObjCNonFragileABI2)
+ DefaultSynthesizeProperties(S, IC, IDecl);
+ ImplMethodsVsClassMethods(S, IC, IDecl);
AtomicPropertySetterGetterRules(IC, IDecl);
if (LangOpts.ObjCNonFragileABI2)
while (IDecl->getSuperClass()) {
@@ -1452,7 +1458,7 @@ void Sema::ActOnAtEnd(SourceRange AtEnd,
for (ObjCCategoryDecl *Categories = IDecl->getCategoryList();
Categories; Categories = Categories->getNextClassCategory()) {
if (Categories->getIdentifier() == CatImplClass->getIdentifier()) {
- ImplMethodsVsClassMethods(CatImplClass, Categories);
+ ImplMethodsVsClassMethods(S, CatImplClass, Categories);
break;
}
}
@@ -1530,7 +1536,7 @@ Sema::DeclPtrTy Sema::ActOnMethodDeclaration(
// Methods cannot return interface types. All ObjC objects are
// passed by reference.
- if (resultDeclType->isObjCInterfaceType()) {
+ if (resultDeclType->isObjCObjectType()) {
Diag(MethodLoc, diag::err_object_cannot_be_passed_returned_by_value)
<< 0 << resultDeclType;
return DeclPtrTy();
@@ -1568,7 +1574,7 @@ Sema::DeclPtrTy Sema::ActOnMethodDeclaration(
ArgInfo[i].Name, ArgType, DI,
VarDecl::None, VarDecl::None, 0);
- if (ArgType->isObjCInterfaceType()) {
+ if (ArgType->isObjCObjectType()) {
Diag(ArgInfo[i].NameLoc,
diag::err_object_cannot_be_passed_returned_by_value)
<< 1 << ArgType;
@@ -1592,7 +1598,7 @@ Sema::DeclPtrTy Sema::ActOnMethodDeclaration(
else
// Perform the default array/function conversions (C99 6.7.5.3p[7,8]).
ArgType = adjustParameterType(ArgType);
- if (ArgType->isObjCInterfaceType()) {
+ if (ArgType->isObjCObjectType()) {
Diag(Param->getLocation(),
diag::err_object_cannot_be_passed_returned_by_value)
<< 1 << ArgType;
@@ -1810,7 +1816,7 @@ void Sema::CollectIvarsToConstructOrDestruct(const ObjCInterfaceDecl *OI,
E = OI->ivar_end(); I != E; ++I) {
ObjCIvarDecl *Iv = (*I);
QualType QT = Context.getBaseElementType(Iv->getType());
- if (isa<RecordType>(QT))
+ if (QT->isRecordType())
Ivars.push_back(*I);
}
@@ -1820,7 +1826,7 @@ void Sema::CollectIvarsToConstructOrDestruct(const ObjCInterfaceDecl *OI,
E = CDecl->ivar_end(); I != E; ++I) {
ObjCIvarDecl *Iv = (*I);
QualType QT = Context.getBaseElementType(Iv->getType());
- if (isa<RecordType>(QT))
+ if (QT->isRecordType())
Ivars.push_back(*I);
}
}
@@ -1832,7 +1838,7 @@ void Sema::CollectIvarsToConstructOrDestruct(const ObjCInterfaceDecl *OI,
E = ImplDecl->ivar_end(); I != E; ++I) {
ObjCIvarDecl *Iv = (*I);
QualType QT = Context.getBaseElementType(Iv->getType());
- if (isa<RecordType>(QT))
+ if (QT->isRecordType())
Ivars.push_back(*I);
}
}
diff --git a/lib/Sema/SemaExceptionSpec.cpp b/lib/Sema/SemaExceptionSpec.cpp
index 53e9385749fb..7d73fe4777bd 100644
--- a/lib/Sema/SemaExceptionSpec.cpp
+++ b/lib/Sema/SemaExceptionSpec.cpp
@@ -389,7 +389,7 @@ bool Sema::CheckExceptionSpecSubset(
if (!IsDerivedFrom(CanonicalSubT, CanonicalSuperT, Paths))
continue;
- if (Paths.isAmbiguous(CanonicalSuperT))
+ if (Paths.isAmbiguous(Context.getCanonicalType(CanonicalSuperT)))
continue;
// Do this check from a context without privileges.
diff --git a/lib/Sema/SemaExpr.cpp b/lib/Sema/SemaExpr.cpp
index 869d6df2f094..f745352d998f 100644
--- a/lib/Sema/SemaExpr.cpp
+++ b/lib/Sema/SemaExpr.cpp
@@ -22,6 +22,7 @@
#include "clang/AST/Expr.h"
#include "clang/AST/ExprCXX.h"
#include "clang/AST/ExprObjC.h"
+#include "clang/AST/RecursiveASTVisitor.h"
#include "clang/AST/TypeLoc.h"
#include "clang/Basic/PartialDiagnostic.h"
#include "clang/Basic/SourceManager.h"
@@ -160,16 +161,19 @@ void Sema::DiagnoseSentinelCalls(NamedDecl *D, SourceLocation Loc,
++sentinel;
}
Expr *sentinelExpr = Args[sentinel];
- if (sentinelExpr && (!isa<GNUNullExpr>(sentinelExpr) &&
- !sentinelExpr->isTypeDependent() &&
- !sentinelExpr->isValueDependent() &&
- (!sentinelExpr->getType()->isPointerType() ||
- !sentinelExpr->isNullPointerConstant(Context,
- Expr::NPC_ValueDependentIsNull)))) {
- Diag(Loc, diag::warn_missing_sentinel) << isMethod;
- Diag(D->getLocation(), diag::note_sentinel_here) << isMethod;
- }
- return;
+ if (!sentinelExpr) return;
+ if (sentinelExpr->isTypeDependent()) return;
+ if (sentinelExpr->isValueDependent()) return;
+ if (sentinelExpr->getType()->isPointerType() &&
+ sentinelExpr->IgnoreParenCasts()->isNullPointerConstant(Context,
+ Expr::NPC_ValueDependentIsNull))
+ return;
+
+ // Unfortunately, __null has type 'int'.
+ if (isa<GNUNullExpr>(sentinelExpr)) return;
+
+ Diag(Loc, diag::warn_missing_sentinel) << isMethod;
+ Diag(D->getLocation(), diag::note_sentinel_here) << isMethod;
}
SourceRange Sema::getExprRange(ExprTy *E) const {
@@ -275,10 +279,9 @@ void Sema::DefaultArgumentPromotion(Expr *&Expr) {
assert(!Ty.isNull() && "DefaultArgumentPromotion - missing type");
// If this is a 'float' (CVR qualified or typedef) promote to double.
- if (const BuiltinType *BT = Ty->getAs<BuiltinType>())
- if (BT->getKind() == BuiltinType::Float)
- return ImpCastExprToType(Expr, Context.DoubleTy,
- CastExpr::CK_FloatingCast);
+ if (Ty->isSpecificBuiltinType(BuiltinType::Float))
+ return ImpCastExprToType(Expr, Context.DoubleTy,
+ CastExpr::CK_FloatingCast);
UsualUnaryConversions(Expr);
}
@@ -287,10 +290,17 @@ void Sema::DefaultArgumentPromotion(Expr *&Expr) {
/// will warn if the resulting type is not a POD type, and rejects ObjC
/// interfaces passed by value. This returns true if the argument type is
/// completely illegal.
-bool Sema::DefaultVariadicArgumentPromotion(Expr *&Expr, VariadicCallType CT) {
+bool Sema::DefaultVariadicArgumentPromotion(Expr *&Expr, VariadicCallType CT,
+ FunctionDecl *FDecl) {
DefaultArgumentPromotion(Expr);
- if (Expr->getType()->isObjCInterfaceType() &&
+ // __builtin_va_start takes the second argument as a "varargs" argument, but
+ // it doesn't actually do anything with it. It doesn't need to be non-pod
+ // etc.
+ if (FDecl && FDecl->getBuiltinID() == Builtin::BI__builtin_va_start)
+ return false;
+
+ if (Expr->getType()->isObjCObjectType() &&
DiagRuntimeBehavior(Expr->getLocStart(),
PDiag(diag::err_cannot_pass_objc_interface_to_vararg)
<< Expr->getType() << CT))
@@ -486,35 +496,6 @@ Sema::BuildDeclRefExpr(ValueDecl *D, QualType Ty, SourceLocation Loc,
D, Loc, Ty));
}
-/// getObjectForAnonymousRecordDecl - Retrieve the (unnamed) field or
-/// variable corresponding to the anonymous union or struct whose type
-/// is Record.
-static Decl *getObjectForAnonymousRecordDecl(ASTContext &Context,
- RecordDecl *Record) {
- assert(Record->isAnonymousStructOrUnion() &&
- "Record must be an anonymous struct or union!");
-
- // FIXME: Once Decls are directly linked together, this will be an O(1)
- // operation rather than a slow walk through DeclContext's vector (which
- // itself will be eliminated). DeclGroups might make this even better.
- DeclContext *Ctx = Record->getDeclContext();
- for (DeclContext::decl_iterator D = Ctx->decls_begin(),
- DEnd = Ctx->decls_end();
- D != DEnd; ++D) {
- if (*D == Record) {
- // The object for the anonymous struct/union directly
- // follows its type in the list of declarations.
- ++D;
- assert(D != DEnd && "Missing object for anonymous record");
- assert(!cast<NamedDecl>(*D)->getDeclName() && "Decl should be unnamed");
- return *D;
- }
- }
-
- assert(false && "Missing object for anonymous record");
- return 0;
-}
-
/// \brief Given a field that represents a member of an anonymous
/// struct/union, build the path from that field's context to the
/// actual member.
@@ -539,7 +520,7 @@ VarDecl *Sema::BuildAnonymousStructUnionMemberPath(FieldDecl *Field,
DeclContext *Ctx = Field->getDeclContext();
do {
RecordDecl *Record = cast<RecordDecl>(Ctx);
- Decl *AnonObject = getObjectForAnonymousRecordDecl(Context, Record);
+ ValueDecl *AnonObject = Record->getAnonymousStructOrUnionObject();
if (FieldDecl *AnonField = dyn_cast<FieldDecl>(AnonObject))
Path.push_back(AnonField);
else {
@@ -592,7 +573,8 @@ Sema::BuildAnonymousStructUnionMemberReference(SourceLocation Loc,
// We've found a member of an anonymous struct/union that is
// inside a non-anonymous struct/union, so in a well-formed
// program our base object expression is "this".
- if (CXXMethodDecl *MD = dyn_cast<CXXMethodDecl>(CurContext)) {
+ DeclContext *DC = getFunctionLevelDeclContext();
+ if (CXXMethodDecl *MD = dyn_cast<CXXMethodDecl>(DC)) {
if (!MD->isStatic()) {
QualType AnonFieldType
= Context.getTagDeclType(
@@ -828,9 +810,10 @@ static IMAKind ClassifyImplicitMemberAccess(Sema &SemaRef,
const LookupResult &R) {
assert(!R.empty() && (*R.begin())->isCXXClassMember());
+ DeclContext *DC = SemaRef.getFunctionLevelDeclContext();
bool isStaticContext =
- (!isa<CXXMethodDecl>(SemaRef.CurContext) ||
- cast<CXXMethodDecl>(SemaRef.CurContext)->isStatic());
+ (!isa<CXXMethodDecl>(DC) ||
+ cast<CXXMethodDecl>(DC)->isStatic());
if (R.isUnresolvableResult())
return isStaticContext ? IMA_Unresolved_StaticContext : IMA_Unresolved;
@@ -870,7 +853,7 @@ static IMAKind ClassifyImplicitMemberAccess(Sema &SemaRef,
// declaring classes, it can't be an implicit member reference (in
// which case it's an error if any of those members are selected).
if (IsProvablyNotDerivedFrom(SemaRef,
- cast<CXXMethodDecl>(SemaRef.CurContext)->getParent(),
+ cast<CXXMethodDecl>(DC)->getParent(),
Classes))
return (hasNonInstance ? IMA_Mixed_Unrelated : IMA_Error_Unrelated);
@@ -907,7 +890,7 @@ static void DiagnoseInstanceReference(Sema &SemaRef,
///
/// \return false if new lookup candidates were found
bool Sema::DiagnoseEmptyLookup(Scope *S, CXXScopeSpec &SS,
- LookupResult &R) {
+ LookupResult &R, CorrectTypoContext CTC) {
DeclarationName Name = R.getLookupName();
unsigned diagnostic = diag::err_undeclared_var_use;
@@ -958,7 +941,7 @@ bool Sema::DiagnoseEmptyLookup(Scope *S, CXXScopeSpec &SS,
// We didn't find anything, so try to correct for a typo.
DeclarationName Corrected;
- if (S && (Corrected = CorrectTypo(R, S, &SS))) {
+ if (S && (Corrected = CorrectTypo(R, S, &SS, false, CTC))) {
if (!R.empty()) {
if (isa<ValueDecl>(*R.begin()) || isa<FunctionTemplateDecl>(*R.begin())) {
if (SS.isEmpty())
@@ -1067,17 +1050,14 @@ Sema::OwningExprResult Sema::ActOnIdExpression(Scope *S,
// Perform the required lookup.
LookupResult R(*this, Name, NameLoc, LookupOrdinaryName);
if (TemplateArgs) {
- // Just re-use the lookup done by isTemplateName.
- DecomposeTemplateName(R, Id);
-
- // Re-derive the naming class.
- if (SS.isSet()) {
- NestedNameSpecifier *Qualifier
- = static_cast<NestedNameSpecifier *>(SS.getScopeRep());
- if (const Type *Ty = Qualifier->getAsType())
- if (CXXRecordDecl *NamingClass = Ty->getAsCXXRecordDecl())
- R.setNamingClass(NamingClass);
- }
+ // Lookup the template name again to correctly establish the context in
+ // which it was found. This is really unfortunate as we already did the
+ // lookup to determine that it was a template name in the first place. If
+ // this becomes a performance hit, we can work harder to preserve those
+ // results until we get here but it's likely not worth it.
+ bool MemberOfUnknownSpecialization;
+ LookupTemplateName(R, S, SS, QualType(), /*EnteringContext=*/false,
+ MemberOfUnknownSpecialization);
} else {
bool IvarLookupFollowUp = (!SS.isSet() && II && getCurMethodDecl());
LookupParsedName(R, S, &SS, !IvarLookupFollowUp);
@@ -1112,7 +1092,7 @@ Sema::OwningExprResult Sema::ActOnIdExpression(Scope *S,
// If this name wasn't predeclared and if this is not a function
// call, diagnose the problem.
if (R.empty()) {
- if (DiagnoseEmptyLookup(S, SS, R))
+ if (DiagnoseEmptyLookup(S, SS, R, CTC_Unknown))
return ExprError();
assert(!R.empty() &&
@@ -1166,7 +1146,8 @@ Sema::OwningExprResult Sema::ActOnIdExpression(Scope *S,
QualType T = Func->getType();
QualType NoProtoType = T;
if (const FunctionProtoType *Proto = T->getAs<FunctionProtoType>())
- NoProtoType = Context.getFunctionNoProtoType(Proto->getResultType());
+ NoProtoType = Context.getFunctionNoProtoType(Proto->getResultType(),
+ Proto->getExtInfo());
return BuildDeclRefExpr(Func, NoProtoType, NameLoc, &SS);
}
}
@@ -1423,6 +1404,9 @@ Sema::PerformObjectMemberConversion(Expr *&From,
SourceRange FromRange = From->getSourceRange();
SourceLocation FromLoc = FromRange.getBegin();
+ bool isLvalue
+ = (From->isLvalue(Context) == Expr::LV_Valid) && !PointerConversions;
+
// C++ [class.member.lookup]p8:
// [...] Ambiguities can often be resolved by qualifying a name with its
// class name.
@@ -1460,7 +1444,7 @@ Sema::PerformObjectMemberConversion(Expr *&From,
if (PointerConversions)
QType = Context.getPointerType(QType);
ImpCastExprToType(From, QType, CastExpr::CK_UncheckedDerivedToBase,
- /*isLvalue=*/!PointerConversions, BasePath);
+ isLvalue, BasePath);
FromType = QType;
FromRecordType = QRecordType;
@@ -1497,7 +1481,7 @@ Sema::PerformObjectMemberConversion(Expr *&From,
if (PointerConversions)
UType = Context.getPointerType(UType);
ImpCastExprToType(From, UType, CastExpr::CK_UncheckedDerivedToBase,
- /*isLvalue=*/!PointerConversions, BasePath);
+ isLvalue, BasePath);
FromType = UType;
FromRecordType = URecordType;
}
@@ -1514,7 +1498,7 @@ Sema::PerformObjectMemberConversion(Expr *&From,
return true;
ImpCastExprToType(From, DestType, CastExpr::CK_UncheckedDerivedToBase,
- /*isLvalue=*/!PointerConversions, BasePath);
+ isLvalue, BasePath);
return false;
}
@@ -1558,7 +1542,8 @@ Sema::BuildImplicitMemberExpr(const CXXScopeSpec &SS,
// If this is known to be an instance access, go ahead and build a
// 'this' expression now.
- QualType ThisType = cast<CXXMethodDecl>(CurContext)->getThisType(Context);
+ DeclContext *DC = getFunctionLevelDeclContext();
+ QualType ThisType = cast<CXXMethodDecl>(DC)->getThisType(Context);
Expr *This = 0; // null signifies implicit access
if (IsKnownInstance) {
SourceLocation Loc = R.getNameLoc();
@@ -1682,8 +1667,8 @@ Sema::BuildDeclarationNameExpr(const CXXScopeSpec &SS,
(NestedNameSpecifier*) SS.getScopeRep(),
SS.getRange(),
R.getLookupName(), R.getNameLoc(),
- NeedsADL, R.isOverloadedResult());
- ULE->addDecls(R.begin(), R.end());
+ NeedsADL, R.isOverloadedResult(),
+ R.begin(), R.end());
return Owned(ULE);
}
@@ -2036,12 +2021,18 @@ bool Sema::CheckSizeOfAlignOfOperand(QualType exprType,
return true;
// Reject sizeof(interface) and sizeof(interface<proto>) in 64-bit mode.
- if (LangOpts.ObjCNonFragileABI && exprType->isObjCInterfaceType()) {
+ if (LangOpts.ObjCNonFragileABI && exprType->isObjCObjectType()) {
Diag(OpLoc, diag::err_sizeof_nonfragile_interface)
<< exprType << isSizeof << ExprRange;
return true;
}
+ if (Context.hasSameUnqualifiedType(exprType, Context.OverloadTy)) {
+ Diag(OpLoc, diag::err_sizeof_alignof_overloaded_function_type)
+ << !isSizeof << ExprRange;
+ return true;
+ }
+
return false;
}
@@ -2312,7 +2303,7 @@ Sema::CreateBuiltinArraySubscriptExpr(ExprArg Base, SourceLocation LLoc,
return ExprError();
// Diagnose bad cases where we step over interface counts.
- if (ResultType->isObjCInterfaceType() && LangOpts.ObjCNonFragileABI) {
+ if (ResultType->isObjCObjectType() && LangOpts.ObjCNonFragileABI) {
Diag(LLoc, diag::err_subscript_nonfragile_interface)
<< ResultType << BaseExpr->getSourceRange();
return ExprError();
@@ -2665,6 +2656,9 @@ Sema::BuildMemberReferenceExpr(ExprArg BaseArg, QualType BaseType,
if (Result.get())
return move(Result);
+
+ // LookupMemberExpr can modify Base, and thus change BaseType
+ BaseType = Base->getType();
}
return BuildMemberReferenceExpr(ExprArg(*this, Base), BaseType,
@@ -2741,8 +2735,7 @@ Sema::BuildMemberReferenceExpr(ExprArg Base, QualType BaseExprType,
IsArrow, OpLoc,
Qualifier, SS.getRange(),
MemberName, MemberLoc,
- TemplateArgs);
- MemExpr->addDecls(R.begin(), R.end());
+ TemplateArgs, R.begin(), R.end());
return Owned(MemExpr);
}
@@ -2917,7 +2910,7 @@ Sema::LookupMemberExpr(LookupResult &R, Expr *&BaseExpr,
// Handle the following exceptional case PObj->isa.
if (const ObjCObjectPointerType *OPT =
BaseType->getAs<ObjCObjectPointerType>()) {
- if (OPT->getPointeeType()->isSpecificBuiltinType(BuiltinType::ObjCId) &&
+ if (OPT->getObjectType()->isObjCId() &&
MemberName.getAsIdentifierInfo()->isStr("isa"))
return Owned(new (Context) ObjCIsaExpr(BaseExpr, true, MemberLoc,
Context.getObjCClassType()));
@@ -3041,8 +3034,7 @@ Sema::LookupMemberExpr(LookupResult &R, Expr *&BaseExpr,
}
}
- // Handle field access to simple records. This also handles access
- // to fields of the ObjC 'id' struct.
+ // Handle field access to simple records.
if (const RecordType *RTy = BaseType->getAs<RecordType>()) {
if (LookupMemberExprInRecord(*this, R, BaseExpr->getSourceRange(),
RTy, OpLoc, SS))
@@ -3053,14 +3045,14 @@ Sema::LookupMemberExpr(LookupResult &R, Expr *&BaseExpr,
// Handle access to Objective-C instance variables, such as "Obj->ivar" and
// (*Obj).ivar.
if ((IsArrow && BaseType->isObjCObjectPointerType()) ||
- (!IsArrow && BaseType->isObjCInterfaceType())) {
+ (!IsArrow && BaseType->isObjCObjectType())) {
const ObjCObjectPointerType *OPT = BaseType->getAs<ObjCObjectPointerType>();
- const ObjCInterfaceType *IFaceT =
- OPT ? OPT->getInterfaceType() : BaseType->getAs<ObjCInterfaceType>();
- if (IFaceT) {
+ ObjCInterfaceDecl *IDecl =
+ OPT ? OPT->getInterfaceDecl()
+ : BaseType->getAs<ObjCObjectType>()->getInterface();
+ if (IDecl) {
IdentifierInfo *Member = MemberName.getAsIdentifierInfo();
- ObjCInterfaceDecl *IDecl = IFaceT->getDecl();
ObjCInterfaceDecl *ClassDeclared;
ObjCIvarDecl *IV = IDecl->lookupInstanceVariable(Member, ClassDeclared);
@@ -3173,7 +3165,8 @@ Sema::LookupMemberExpr(LookupResult &R, Expr *&BaseExpr,
// Handle the following exceptional case (*Obj).isa.
if (!IsArrow &&
- BaseType->isSpecificBuiltinType(BuiltinType::ObjCId) &&
+ BaseType->isObjCObjectType() &&
+ BaseType->getAs<ObjCObjectType>()->isObjCId() &&
MemberName.getAsIdentifierInfo()->isStr("isa"))
return Owned(new (Context) ObjCIsaExpr(BaseExpr, false, MemberLoc,
Context.getObjCClassType()));
@@ -3471,9 +3464,9 @@ bool Sema::GatherArgumentsForCall(SourceLocation CallLoc,
// If this is a variadic call, handle args passed through "...".
if (CallType != VariadicDoesNotApply) {
// Promote the arguments (C99 6.5.2.2p7).
- for (unsigned i = ArgIx; i < NumArgs; i++) {
+ for (unsigned i = ArgIx; i != NumArgs; ++i) {
Expr *Arg = Args[i];
- Invalid |= DefaultVariadicArgumentPromotion(Arg, CallType);
+ Invalid |= DefaultVariadicArgumentPromotion(Arg, CallType, FDecl);
AllArgs.push_back(Arg);
}
}
@@ -4081,8 +4074,6 @@ QualType Sema::CheckConditionalOperands(Expr *&Cond, Expr *&LHS, Expr *&RHS,
if (getLangOptions().CPlusPlus)
return CXXCheckConditionalOperands(Cond, LHS, RHS, QuestionLoc);
- CheckSignCompare(LHS, RHS, QuestionLoc);
-
UsualUnaryConversions(Cond);
UsualUnaryConversions(LHS);
UsualUnaryConversions(RHS);
@@ -4659,7 +4650,8 @@ Sema::CheckAssignmentConstraints(QualType lhsType, QualType rhsType) {
return Incompatible;
}
- if (lhsType->isArithmeticType() && rhsType->isArithmeticType())
+ if (lhsType->isArithmeticType() && rhsType->isArithmeticType() &&
+ !(getLangOptions().CPlusPlus && lhsType->isEnumeralType()))
return Compatible;
if (isa<PointerType>(lhsType)) {
@@ -4917,7 +4909,13 @@ QualType Sema::CheckVectorOperands(SourceLocation Loc, Expr *&lex, Expr *&rex) {
if (const VectorType *RV = rhsType->getAs<VectorType>())
if (LV->getElementType() == RV->getElementType() &&
LV->getNumElements() == RV->getNumElements()) {
- return lhsType->isExtVectorType() ? lhsType : rhsType;
+ if (lhsType->isExtVectorType()) {
+ ImpCastExprToType(rex, lhsType, CastExpr::CK_BitCast);
+ return lhsType;
+ }
+
+ ImpCastExprToType(lex, rhsType, CastExpr::CK_BitCast);
+ return rhsType;
}
}
}
@@ -5059,7 +5057,7 @@ QualType Sema::CheckAdditionOperands( // C99 6.5.6
return QualType();
}
// Diagnose bad cases where we step over interface counts.
- if (PointeeTy->isObjCInterfaceType() && LangOpts.ObjCNonFragileABI) {
+ if (PointeeTy->isObjCObjectType() && LangOpts.ObjCNonFragileABI) {
Diag(Loc, diag::err_arithmetic_nonfragile_interface)
<< PointeeTy << PExp->getSourceRange();
return QualType();
@@ -5135,7 +5133,7 @@ QualType Sema::CheckSubtractionOperands(Expr *&lex, Expr *&rex,
return QualType();
// Diagnose bad cases where we step over interface counts.
- if (lpointee->isObjCInterfaceType() && LangOpts.ObjCNonFragileABI) {
+ if (lpointee->isObjCObjectType() && LangOpts.ObjCNonFragileABI) {
Diag(Loc, diag::err_arithmetic_nonfragile_interface)
<< lpointee << lex->getSourceRange();
return QualType();
@@ -5274,8 +5272,6 @@ QualType Sema::CheckCompareOperands(Expr *&lex, Expr *&rex, SourceLocation Loc,
if (lex->getType()->isVectorType() || rex->getType()->isVectorType())
return CheckVectorCompareOperands(lex, rex, Loc, isRelational);
- CheckSignCompare(lex, rex, Loc, &Opc);
-
// C99 6.5.8p3 / C99 6.5.9p4
if (lex->getType()->isArithmeticType() && rex->getType()->isArithmeticType())
UsualArithmeticConversions(lex, rex);
@@ -5904,7 +5900,7 @@ QualType Sema::CheckIncrementDecrementOperand(Expr *Op, SourceLocation OpLoc,
<< ResType))
return QualType();
// Diagnose bad cases where we step over interface counts.
- else if (PointeeTy->isObjCInterfaceType() && LangOpts.ObjCNonFragileABI) {
+ else if (PointeeTy->isObjCObjectType() && LangOpts.ObjCNonFragileABI) {
Diag(OpLoc, diag::err_arithmetic_nonfragile_interface)
<< PointeeTy << Op->getSourceRange();
return QualType();
@@ -6626,7 +6622,7 @@ Sema::OwningExprResult Sema::BuildBuiltinOffsetOf(SourceLocation BuiltinLoc,
SourceLocation RParenLoc) {
QualType ArgTy = TInfo->getType();
bool Dependent = ArgTy->isDependentType();
- SourceRange TypeRange = TInfo->getTypeLoc().getSourceRange();
+ SourceRange TypeRange = TInfo->getTypeLoc().getLocalSourceRange();
// We must have at least one component that refers to the type, and the first
// one is known to be a field designator. Verify that the ArgTy represents
@@ -7018,7 +7014,7 @@ void Sema::ActOnBlockArguments(Declarator &ParamInfo, Scope *CurScope) {
QualType RetTy = T.getTypePtr()->getAs<FunctionType>()->getResultType();
// Do not allow returning a objc interface by-value.
- if (RetTy->isObjCInterfaceType()) {
+ if (RetTy->isObjCObjectType()) {
Diag(ParamInfo.getSourceRange().getBegin(),
diag::err_object_cannot_be_passed_returned_by_value) << 0 << RetTy;
return;
@@ -7090,7 +7086,7 @@ void Sema::ActOnBlockArguments(Declarator &ParamInfo, Scope *CurScope) {
QualType RetTy = T->getAs<FunctionType>()->getResultType();
// Do not allow returning a objc interface by-value.
- if (RetTy->isObjCInterfaceType()) {
+ if (RetTy->isObjCObjectType()) {
Diag(ParamInfo.getSourceRange().getBegin(),
diag::err_object_cannot_be_passed_returned_by_value) << 0 << RetTy;
} else if (!RetTy->isDependentType())
@@ -7500,22 +7496,24 @@ void Sema::MarkDeclarationReferenced(SourceLocation Loc, Decl *D) {
DefineImplicitCopyConstructor(Loc, Constructor, TypeQuals);
}
- MaybeMarkVirtualMembersReferenced(Loc, Constructor);
+ MarkVTableUsed(Loc, Constructor->getParent());
} else if (CXXDestructorDecl *Destructor = dyn_cast<CXXDestructorDecl>(D)) {
if (Destructor->isImplicit() && !Destructor->isUsed())
DefineImplicitDestructor(Loc, Destructor);
-
+ if (Destructor->isVirtual())
+ MarkVTableUsed(Loc, Destructor->getParent());
} else if (CXXMethodDecl *MethodDecl = dyn_cast<CXXMethodDecl>(D)) {
if (MethodDecl->isImplicit() && MethodDecl->isOverloadedOperator() &&
MethodDecl->getOverloadedOperator() == OO_Equal) {
if (!MethodDecl->isUsed())
DefineImplicitCopyAssignment(Loc, MethodDecl);
- }
+ } else if (MethodDecl->isVirtual())
+ MarkVTableUsed(Loc, MethodDecl->getParent());
}
if (FunctionDecl *Function = dyn_cast<FunctionDecl>(D)) {
// Implicit instantiation of function templates and member functions of
// class templates.
- if (!Function->getBody() && Function->isImplicitlyInstantiable()) {
+ if (Function->isImplicitlyInstantiable()) {
bool AlreadyInstantiated = false;
if (FunctionTemplateSpecializationInfo *SpecInfo
= Function->getTemplateSpecializationInfo()) {
@@ -7570,6 +7568,48 @@ void Sema::MarkDeclarationReferenced(SourceLocation Loc, Decl *D) {
}
}
+namespace {
+ // Mark all of the declarations referenced
+ // FIXME: Not fully implemented yet! We need to have a better understanding
+ // of when we're entering
+ class MarkReferencedDecls : public RecursiveASTVisitor<MarkReferencedDecls> {
+ Sema &S;
+ SourceLocation Loc;
+
+ public:
+ typedef RecursiveASTVisitor<MarkReferencedDecls> Inherited;
+
+ MarkReferencedDecls(Sema &S, SourceLocation Loc) : S(S), Loc(Loc) { }
+
+ bool VisitTemplateArgument(const TemplateArgument &Arg);
+ bool VisitRecordType(RecordType *T);
+ };
+}
+
+bool MarkReferencedDecls::VisitTemplateArgument(const TemplateArgument &Arg) {
+ if (Arg.getKind() == TemplateArgument::Declaration) {
+ S.MarkDeclarationReferenced(Loc, Arg.getAsDecl());
+ }
+
+ return Inherited::VisitTemplateArgument(Arg);
+}
+
+bool MarkReferencedDecls::VisitRecordType(RecordType *T) {
+ if (ClassTemplateSpecializationDecl *Spec
+ = dyn_cast<ClassTemplateSpecializationDecl>(T->getDecl())) {
+ const TemplateArgumentList &Args = Spec->getTemplateArgs();
+ return VisitTemplateArguments(Args.getFlatArgumentList(),
+ Args.flat_size());
+ }
+
+ return false;
+}
+
+void Sema::MarkDeclarationsReferencedInType(SourceLocation Loc, QualType T) {
+ MarkReferencedDecls Marker(*this, Loc);
+ Marker.Visit(Context.getCanonicalType(T));
+}
+
/// \brief Emit a diagnostic that describes an effect on the run-time behavior
/// of the program being compiled.
///
@@ -7698,3 +7738,17 @@ bool Sema::CheckBooleanCondition(Expr *&E, SourceLocation Loc) {
return false;
}
+
+Sema::OwningExprResult Sema::ActOnBooleanCondition(Scope *S, SourceLocation Loc,
+ ExprArg SubExpr) {
+ Expr *Sub = SubExpr.takeAs<Expr>();
+ if (!Sub)
+ return ExprError();
+
+ if (CheckBooleanCondition(Sub, Loc)) {
+ Sub->Destroy(Context);
+ return ExprError();
+ }
+
+ return Owned(Sub);
+}
diff --git a/lib/Sema/SemaExprCXX.cpp b/lib/Sema/SemaExprCXX.cpp
index 425fc2d15aa5..97de96aacbbd 100644
--- a/lib/Sema/SemaExprCXX.cpp
+++ b/lib/Sema/SemaExprCXX.cpp
@@ -261,7 +261,8 @@ Action::TypeTy *Sema::getDestructorName(SourceLocation TildeLoc,
Range = SourceRange(NameLoc);
}
- return CheckTypenameType(ETK_None, NNS, II, Range).getAsOpaquePtr();
+ return CheckTypenameType(ETK_None, NNS, II, SourceLocation(),
+ Range, NameLoc).getAsOpaquePtr();
}
if (ObjectTypePtr)
@@ -314,8 +315,12 @@ Sema::OwningExprResult Sema::BuildCXXTypeId(QualType TypeInfoType,
// When typeid is applied to an expression other than an lvalue of a
// polymorphic class type [...] [the] expression is an unevaluated
// operand. [...]
- if (RecordD->isPolymorphic() && E->isLvalue(Context) == Expr::LV_Valid)
+ if (RecordD->isPolymorphic() && E->isLvalue(Context) == Expr::LV_Valid) {
isUnevaluatedOperand = false;
+
+ // We require a vtable to query the type at run time.
+ MarkVTableUsed(TypeidLoc, RecordD);
+ }
}
// C++ [expr.typeid]p4:
@@ -437,14 +442,22 @@ bool Sema::CheckCXXThrowOperand(SourceLocation ThrowLoc, Expr *&E) {
// Initialize the exception result. This implicitly weeds out
// abstract types or types with inaccessible copy constructors.
+ // FIXME: Determine whether we can elide this copy per C++0x [class.copy]p34.
InitializedEntity Entity =
- InitializedEntity::InitializeException(ThrowLoc, E->getType());
+ InitializedEntity::InitializeException(ThrowLoc, E->getType(),
+ /*NRVO=*/false);
OwningExprResult Res = PerformCopyInitialization(Entity,
SourceLocation(),
Owned(E));
if (Res.isInvalid())
return true;
E = Res.takeAs<Expr>();
+
+ // If we are throwing a polymorphic class type or pointer thereof,
+ // exception handling will make use of the vtable.
+ if (const RecordType *RecordTy = Ty->getAs<RecordType>())
+ MarkVTableUsed(ThrowLoc, cast<CXXRecordDecl>(RecordTy->getDecl()));
+
return false;
}
@@ -453,10 +466,8 @@ Action::OwningExprResult Sema::ActOnCXXThis(SourceLocation ThisLoc) {
/// is a non-lvalue expression whose value is the address of the object for
/// which the function is called.
- if (!isa<FunctionDecl>(CurContext))
- return ExprError(Diag(ThisLoc, diag::err_invalid_this_use));
-
- if (CXXMethodDecl *MD = dyn_cast<CXXMethodDecl>(CurContext))
+ DeclContext *DC = getFunctionLevelDeclContext();
+ if (CXXMethodDecl *MD = dyn_cast<CXXMethodDecl>(DC))
if (MD->isInstance())
return Owned(new (Context) CXXThisExpr(ThisLoc,
MD->getThisType(Context),
@@ -668,10 +679,19 @@ Sema::BuildCXXNew(SourceLocation StartLoc, bool UseGlobal,
if (CheckAllocatedType(AllocType, TypeLoc, TypeRange))
return ExprError();
- QualType ResultType = Context.getPointerType(AllocType);
+ // Per C++0x [expr.new]p5, the type being constructed may be a
+ // typedef of an array type.
+ if (!ArraySizeE.get()) {
+ if (const ConstantArrayType *Array
+ = Context.getAsConstantArrayType(AllocType)) {
+ ArraySizeE = Owned(new (Context) IntegerLiteral(Array->getSize(),
+ Context.getSizeType(),
+ TypeRange.getEnd()));
+ AllocType = Array->getElementType();
+ }
+ }
- // That every array dimension except the first is constant was already
- // checked by the type check above.
+ QualType ResultType = Context.getPointerType(AllocType);
// C++ 5.3.4p6: "The expression in a direct-new-declarator shall have integral
// or enumeration type with a non-negative value."
@@ -739,7 +759,7 @@ Sema::BuildCXXNew(SourceLocation StartLoc, bool UseGlobal,
ASTOwningVector<&ActionBase::DeleteExpr> ConvertedConstructorArgs(*this);
// Array 'new' can't have any initializers.
- if (NumConsArgs && ArraySize) {
+ if (NumConsArgs && (ResultType->isArrayType() || ArraySize)) {
SourceRange InitRange(ConsArgs[0]->getLocStart(),
ConsArgs[NumConsArgs - 1]->getLocEnd());
@@ -1173,7 +1193,7 @@ void Sema::DeclareGlobalNewDelete() {
if (!StdBadAlloc) {
// The "std::bad_alloc" class has not yet been declared, so build it
// implicitly.
- StdBadAlloc = CXXRecordDecl::Create(Context, TagDecl::TK_class,
+ StdBadAlloc = CXXRecordDecl::Create(Context, TTK_Class,
StdNamespace,
SourceLocation(),
&PP.getIdentifierTable().get("bad_alloc"),
@@ -1378,7 +1398,13 @@ Sema::ActOnCXXDelete(SourceLocation StartLoc, bool UseGlobal,
<< Type << Ex->getSourceRange());
QualType Pointee = Type->getAs<PointerType>()->getPointeeType();
- if (Pointee->isFunctionType() || Pointee->isVoidType())
+ if (Pointee->isVoidType() && !isSFINAEContext()) {
+ // The C++ standard bans deleting a pointer to a non-object type, which
+ // effectively bans deletion of "void*". However, most compilers support
+ // this, so we treat it as a warning unless we're in a SFINAE context.
+ Diag(StartLoc, diag::ext_delete_void_ptr_operand)
+ << Type << Ex->getSourceRange();
+ } else if (Pointee->isFunctionType() || Pointee->isVoidType())
return ExprError(Diag(StartLoc, diag::err_delete_operand)
<< Type << Ex->getSourceRange());
else if (!Pointee->isDependentType() &&
@@ -1437,7 +1463,9 @@ Sema::ActOnCXXDelete(SourceLocation StartLoc, bool UseGlobal,
/// \brief Check the use of the given variable as a C++ condition in an if,
/// while, do-while, or switch statement.
-Action::OwningExprResult Sema::CheckConditionVariable(VarDecl *ConditionVar) {
+Action::OwningExprResult Sema::CheckConditionVariable(VarDecl *ConditionVar,
+ SourceLocation StmtLoc,
+ bool ConvertToBoolean) {
QualType T = ConditionVar->getType();
// C++ [stmt.select]p2:
@@ -1451,9 +1479,15 @@ Action::OwningExprResult Sema::CheckConditionVariable(VarDecl *ConditionVar) {
diag::err_invalid_use_of_array_type)
<< ConditionVar->getSourceRange());
- return Owned(DeclRefExpr::Create(Context, 0, SourceRange(), ConditionVar,
- ConditionVar->getLocation(),
- ConditionVar->getType().getNonReferenceType()));
+ Expr *Condition = DeclRefExpr::Create(Context, 0, SourceRange(), ConditionVar,
+ ConditionVar->getLocation(),
+ ConditionVar->getType().getNonReferenceType());
+ if (ConvertToBoolean && CheckBooleanCondition(Condition, StmtLoc)) {
+ Condition->Destroy(Context);
+ return ExprError();
+ }
+
+ return Owned(Condition);
}
/// CheckCXXBooleanCondition - Returns true if a conversion to bool is invalid.
@@ -1748,10 +1782,6 @@ Sema::PerformImplicitConversion(Expr *&From, QualType ToType,
ImpCastExprToType(From, ToType, CastExpr::CK_FloatingToIntegral);
break;
- case ICK_Complex_Real:
- ImpCastExprToType(From, ToType, CastExpr::CK_Unknown);
- break;
-
case ICK_Compatible_Conversion:
ImpCastExprToType(From, ToType, CastExpr::CK_NoOp);
break;
@@ -1794,18 +1824,41 @@ Sema::PerformImplicitConversion(Expr *&From, QualType ToType,
break;
}
- case ICK_Derived_To_Base:
+ case ICK_Derived_To_Base: {
+ CXXBaseSpecifierArray BasePath;
if (CheckDerivedToBaseConversion(From->getType(),
ToType.getNonReferenceType(),
From->getLocStart(),
- From->getSourceRange(), 0,
+ From->getSourceRange(),
+ &BasePath,
IgnoreBaseAccess))
return true;
+
ImpCastExprToType(From, ToType.getNonReferenceType(),
- CastExpr::CK_DerivedToBase);
+ CastExpr::CK_DerivedToBase,
+ /*isLvalue=*/(From->getType()->isRecordType() &&
+ From->isLvalue(Context) == Expr::LV_Valid),
+ BasePath);
+ break;
+ }
+
+ case ICK_Vector_Conversion:
+ ImpCastExprToType(From, ToType, CastExpr::CK_BitCast);
+ break;
+
+ case ICK_Vector_Splat:
+ ImpCastExprToType(From, ToType, CastExpr::CK_VectorSplat);
break;
- default:
+ case ICK_Complex_Real:
+ ImpCastExprToType(From, ToType, CastExpr::CK_Unknown);
+ break;
+
+ case ICK_Lvalue_To_Rvalue:
+ case ICK_Array_To_Pointer:
+ case ICK_Function_To_Pointer:
+ case ICK_Qualification:
+ case ICK_Num_Conversion_Kinds:
assert(false && "Improper second standard conversion");
break;
}
@@ -1828,7 +1881,7 @@ Sema::PerformImplicitConversion(Expr *&From, QualType ToType,
break;
default:
- assert(false && "Improper second standard conversion");
+ assert(false && "Improper third standard conversion");
break;
}
@@ -2113,8 +2166,6 @@ QualType Sema::CXXCheckConditionalOperands(Expr *&Cond, Expr *&LHS, Expr *&RHS,
if (LHS->isTypeDependent() || RHS->isTypeDependent())
return Context.DependentTy;
- CheckSignCompare(LHS, RHS, QuestionLoc);
-
// C++0x 5.16p2
// If either the second or the third operand has type (cv) void, ...
QualType LTy = LHS->getType();
@@ -2218,9 +2269,36 @@ QualType Sema::CXXCheckConditionalOperands(Expr *&Cond, Expr *&LHS, Expr *&RHS,
// After those conversions, one of the following shall hold:
// -- The second and third operands have the same type; the result
- // is of that type.
- if (Context.getCanonicalType(LTy) == Context.getCanonicalType(RTy))
+ // is of that type. If the operands have class type, the result
+ // is a prvalue temporary of the result type, which is
+ // copy-initialized from either the second operand or the third
+ // operand depending on the value of the first operand.
+ if (Context.getCanonicalType(LTy) == Context.getCanonicalType(RTy)) {
+ if (LTy->isRecordType()) {
+ // The operands have class type. Make a temporary copy.
+ InitializedEntity Entity = InitializedEntity::InitializeTemporary(LTy);
+ OwningExprResult LHSCopy = PerformCopyInitialization(Entity,
+ SourceLocation(),
+ Owned(LHS));
+ if (LHSCopy.isInvalid())
+ return QualType();
+
+ OwningExprResult RHSCopy = PerformCopyInitialization(Entity,
+ SourceLocation(),
+ Owned(RHS));
+ if (RHSCopy.isInvalid())
+ return QualType();
+
+ LHS = LHSCopy.takeAs<Expr>();
+ RHS = RHSCopy.takeAs<Expr>();
+ }
+
return LTy;
+ }
+
+ // Extension: conditional operator involving vector types.
+ if (LTy->isVectorType() || RTy->isVectorType())
+ return CheckVectorOperands(QuestionLoc, LHS, RHS);
// -- The second and third operands have arithmetic or enumeration type;
// the usual arithmetic conversions are performed to bring them to a
@@ -2529,6 +2607,9 @@ Sema::OwningExprResult Sema::MaybeBindToTemporary(Expr *E) {
Expr *Sema::MaybeCreateCXXExprWithTemporaries(Expr *SubExpr) {
assert(SubExpr && "sub expression can't be null!");
+ // Check any implicit conversions within the expression.
+ CheckImplicitConversions(SubExpr);
+
unsigned FirstTemporary = ExprEvalContexts.back().NumTemporaries;
assert(ExprTemporaries.size() >= FirstTemporary);
if (ExprTemporaries.size() == FirstTemporary)
@@ -2713,12 +2794,12 @@ Sema::OwningExprResult Sema::BuildPseudoDestructorExpr(ExprArg Base,
if (DestructedTypeInfo) {
QualType DestructedType = DestructedTypeInfo->getType();
SourceLocation DestructedTypeStart
- = DestructedTypeInfo->getTypeLoc().getSourceRange().getBegin();
+ = DestructedTypeInfo->getTypeLoc().getLocalSourceRange().getBegin();
if (!DestructedType->isDependentType() && !ObjectType->isDependentType() &&
!Context.hasSameUnqualifiedType(DestructedType, ObjectType)) {
Diag(DestructedTypeStart, diag::err_pseudo_dtor_type_mismatch)
<< ObjectType << DestructedType << BaseE->getSourceRange()
- << DestructedTypeInfo->getTypeLoc().getSourceRange();
+ << DestructedTypeInfo->getTypeLoc().getLocalSourceRange();
// Recover by setting the destructed type to the object type.
DestructedType = ObjectType;
@@ -2740,10 +2821,10 @@ Sema::OwningExprResult Sema::BuildPseudoDestructorExpr(ExprArg Base,
if (!ScopeType->isDependentType() && !ObjectType->isDependentType() &&
!Context.hasSameType(ScopeType, ObjectType)) {
- Diag(ScopeTypeInfo->getTypeLoc().getSourceRange().getBegin(),
+ Diag(ScopeTypeInfo->getTypeLoc().getLocalSourceRange().getBegin(),
diag::err_pseudo_dtor_type_mismatch)
<< ObjectType << ScopeType << BaseE->getSourceRange()
- << ScopeTypeInfo->getTypeLoc().getSourceRange();
+ << ScopeTypeInfo->getTypeLoc().getLocalSourceRange();
ScopeType = QualType();
ScopeTypeInfo = 0;
@@ -2943,6 +3024,8 @@ Sema::OwningExprResult Sema::ActOnFinishFullExpr(ExprArg Arg) {
Expr *FullExpr = Arg.takeAs<Expr>();
if (FullExpr)
FullExpr = MaybeCreateCXXExprWithTemporaries(FullExpr);
-
+ else
+ return ExprError();
+
return Owned(FullExpr);
}
diff --git a/lib/Sema/SemaExprObjC.cpp b/lib/Sema/SemaExprObjC.cpp
index db9a2e238f95..695a1beca15e 100644
--- a/lib/Sema/SemaExprObjC.cpp
+++ b/lib/Sema/SemaExprObjC.cpp
@@ -254,7 +254,7 @@ bool Sema::CheckMessageArgumentTypes(Expr **Args, unsigned NumArgs,
if (Args[i]->isTypeDependent())
continue;
- IsError |= DefaultVariadicArgumentPromotion(Args[i], VariadicMethod);
+ IsError |= DefaultVariadicArgumentPromotion(Args[i], VariadicMethod, 0);
}
} else {
// Check for extra arguments to non-variadic methods.
@@ -718,14 +718,12 @@ Sema::OwningExprResult Sema::BuildClassMessage(TypeSourceInfo *ReceiverTypeInfo,
}
SourceLocation Loc = SuperLoc.isValid()? SuperLoc
- : ReceiverTypeInfo->getTypeLoc().getSourceRange().getBegin();
+ : ReceiverTypeInfo->getTypeLoc().getLocalSourceRange().getBegin();
// Find the class to which we are sending this message.
ObjCInterfaceDecl *Class = 0;
- if (const ObjCInterfaceType *ClassType
- = ReceiverType->getAs<ObjCInterfaceType>())
- Class = ClassType->getDecl();
- else {
+ const ObjCObjectType *ClassType = ReceiverType->getAs<ObjCObjectType>();
+ if (!ClassType || !(Class = ClassType->getInterface())) {
Diag(Loc, diag::err_invalid_receiver_class_message)
<< ReceiverType;
return ExprError();
@@ -766,15 +764,17 @@ Sema::OwningExprResult Sema::BuildClassMessage(TypeSourceInfo *ReceiverTypeInfo,
}
// Construct the appropriate ObjCMessageExpr.
+ Expr *Result;
if (SuperLoc.isValid())
- return Owned(ObjCMessageExpr::Create(Context, ReturnType, LBracLoc,
- SuperLoc, /*IsInstanceSuper=*/false,
- ReceiverType, Sel, Method, Args,
- NumArgs, RBracLoc));
-
- return Owned(ObjCMessageExpr::Create(Context, ReturnType, LBracLoc,
- ReceiverTypeInfo, Sel, Method, Args,
- NumArgs, RBracLoc));
+ Result = ObjCMessageExpr::Create(Context, ReturnType, LBracLoc,
+ SuperLoc, /*IsInstanceSuper=*/false,
+ ReceiverType, Sel, Method, Args,
+ NumArgs, RBracLoc);
+ else
+ Result = ObjCMessageExpr::Create(Context, ReturnType, LBracLoc,
+ ReceiverTypeInfo, Sel, Method, Args,
+ NumArgs, RBracLoc);
+ return MaybeBindToTemporary(Result);
}
// ActOnClassMessage - used for both unary and keyword messages.
@@ -976,6 +976,21 @@ Sema::OwningExprResult Sema::BuildInstanceMessage(ExprArg ReceiverE,
ImpCastExprToType(Receiver, Context.getObjCIdType(),
CastExpr::CK_IntegralToPointer);
ReceiverType = Receiver->getType();
+ }
+ else if (getLangOptions().CPlusPlus &&
+ !PerformContextuallyConvertToObjCId(Receiver)) {
+ if (ImplicitCastExpr *ICE = dyn_cast<ImplicitCastExpr>(Receiver)) {
+ Receiver = ICE->getSubExpr();
+ ReceiverType = Receiver->getType();
+ }
+ return BuildInstanceMessage(Owned(Receiver),
+ ReceiverType,
+ SuperLoc,
+ Sel,
+ Method,
+ LBracLoc,
+ RBracLoc,
+ move(ArgsIn));
} else {
// Reject other random receiver types (e.g. structs).
Diag(Loc, diag::err_bad_receiver_type)
@@ -994,14 +1009,16 @@ Sema::OwningExprResult Sema::BuildInstanceMessage(ExprArg ReceiverE,
return ExprError();
// Construct the appropriate ObjCMessageExpr instance.
+ Expr *Result;
if (SuperLoc.isValid())
- return Owned(ObjCMessageExpr::Create(Context, ReturnType, LBracLoc,
- SuperLoc, /*IsInstanceSuper=*/true,
- ReceiverType, Sel, Method,
- Args, NumArgs, RBracLoc));
-
- return Owned(ObjCMessageExpr::Create(Context, ReturnType, LBracLoc, Receiver,
- Sel, Method, Args, NumArgs, RBracLoc));
+ Result = ObjCMessageExpr::Create(Context, ReturnType, LBracLoc,
+ SuperLoc, /*IsInstanceSuper=*/true,
+ ReceiverType, Sel, Method,
+ Args, NumArgs, RBracLoc);
+ else
+ Result = ObjCMessageExpr::Create(Context, ReturnType, LBracLoc, Receiver,
+ Sel, Method, Args, NumArgs, RBracLoc);
+ return MaybeBindToTemporary(Result);
}
// ActOnInstanceMessage - used for both unary and keyword messages.
diff --git a/lib/Sema/SemaInit.cpp b/lib/Sema/SemaInit.cpp
index 0aa344617763..20f0c79c48c6 100644
--- a/lib/Sema/SemaInit.cpp
+++ b/lib/Sema/SemaInit.cpp
@@ -624,7 +624,7 @@ void InitListChecker::CheckListElementTypes(const InitializedEntity &Entity,
} else if (DeclType->isReferenceType()) {
CheckReferenceType(Entity, IList, DeclType, Index,
StructuredList, StructuredIndex);
- } else if (DeclType->isObjCInterfaceType()) {
+ } else if (DeclType->isObjCObjectType()) {
SemaRef.Diag(IList->getLocStart(), diag::err_init_objc_class)
<< DeclType;
hadError = true;
@@ -1984,6 +1984,26 @@ DeclaratorDecl *InitializedEntity::getDecl() const {
return 0;
}
+bool InitializedEntity::allowsNRVO() const {
+ switch (getKind()) {
+ case EK_Result:
+ case EK_Exception:
+ return LocAndNRVO.NRVO;
+
+ case EK_Variable:
+ case EK_Parameter:
+ case EK_Member:
+ case EK_New:
+ case EK_Temporary:
+ case EK_Base:
+ case EK_ArrayElement:
+ case EK_VectorElement:
+ break;
+ }
+
+ return false;
+}
+
//===----------------------------------------------------------------------===//
// Initialization sequence
//===----------------------------------------------------------------------===//
@@ -2034,6 +2054,7 @@ bool InitializationSequence::isAmbiguous() const {
case FK_ReferenceBindingToInitList:
case FK_InitListBadDestinationType:
case FK_DefaultInitOfConst:
+ case FK_Incomplete:
return false;
case FK_ReferenceInitOverloadFailed:
@@ -2245,11 +2266,11 @@ static OverloadingResult TryRefInitWithConversionFunction(Sema &S,
bool AllowExplicit = Kind.getKind() == InitializationKind::IK_Direct;
const RecordType *T1RecordType = 0;
- if (AllowRValues && (T1RecordType = T1->getAs<RecordType>())) {
+ if (AllowRValues && (T1RecordType = T1->getAs<RecordType>()) &&
+ !S.RequireCompleteType(Kind.getLocation(), T1, 0)) {
// The type we're converting to is a class type. Enumerate its constructors
// to see if there is a suitable conversion.
CXXRecordDecl *T1RecordDecl = cast<CXXRecordDecl>(T1RecordType->getDecl());
-
DeclarationName ConstructorName
= S.Context.DeclarationNames.getCXXConstructorName(
S.Context.getCanonicalType(T1).getUnqualifiedType());
@@ -2281,7 +2302,9 @@ static OverloadingResult TryRefInitWithConversionFunction(Sema &S,
}
}
- if (const RecordType *T2RecordType = T2->getAs<RecordType>()) {
+ const RecordType *T2RecordType = 0;
+ if ((T2RecordType = T2->getAs<RecordType>()) &&
+ !S.RequireCompleteType(Kind.getLocation(), T2, 0)) {
// The type we're converting from is a class type, enumerate its conversion
// functions.
CXXRecordDecl *T2RecordDecl = cast<CXXRecordDecl>(T2RecordType->getDecl());
@@ -2627,7 +2650,7 @@ static void TryConstructorInitialization(Sema &S,
// The type we're constructing needs to be complete.
if (S.RequireCompleteType(Kind.getLocation(), DestType, 0)) {
- Sequence.SetFailed(InitializationSequence::FK_ConversionFailed);
+ Sequence.SetFailed(InitializationSequence::FK_Incomplete);
return;
}
@@ -2740,8 +2763,8 @@ static void TryValueInitialization(Sema &S,
// without a user-provided constructor, then the object is
// zero-initialized and, if T’s implicitly-declared default
// constructor is non-trivial, that constructor is called.
- if ((ClassDecl->getTagKind() == TagDecl::TK_class ||
- ClassDecl->getTagKind() == TagDecl::TK_struct) &&
+ if ((ClassDecl->getTagKind() == TTK_Class ||
+ ClassDecl->getTagKind() == TTK_Struct) &&
!ClassDecl->hasTrivialConstructor()) {
Sequence.AddZeroInitializationStep(Entity.getType());
return TryConstructorInitialization(S, Entity, Kind, 0, 0, T, Sequence);
@@ -3240,9 +3263,9 @@ static Sema::OwningExprResult CopyObject(Sema &S,
// directly into the target of the omitted copy/move
//
// Note that the other three bullets are handled elsewhere. Copy
- // elision for return statements and throw expressions are (FIXME:
- // not yet) handled as part of constructor initialization, while
- // copy elision for exception handlers is handled by the run-time.
+ // elision for return statements and throw expressions are handled as part
+ // of constructor initialization, while copy elision for exception handlers
+ // is handled by the run-time.
bool Elidable = CurInitExpr->isTemporaryObject() &&
S.Context.hasSameUnqualifiedType(T, CurInitExpr->getType());
SourceLocation Loc;
@@ -3517,6 +3540,7 @@ InitializationSequence::Perform(Sema &S,
// Overload resolution determined which function invoke; update the
// initializer to reflect that choice.
S.CheckAddressOfMemberAccess(CurInitExpr, Step->Function.FoundDecl);
+ S.DiagnoseUseOfDecl(Step->Function.FoundDecl, Kind.getLocation());
CurInit = S.FixOverloadedFunctionReference(move(CurInit),
Step->Function.FoundDecl,
Step->Function.Function);
@@ -3537,6 +3561,15 @@ InitializationSequence::Perform(Sema &S,
&BasePath, IgnoreBaseAccess))
return S.ExprError();
+ if (S.BasePathInvolvesVirtualBase(BasePath)) {
+ QualType T = SourceType;
+ if (const PointerType *Pointer = T->getAs<PointerType>())
+ T = Pointer->getPointeeType();
+ if (const RecordType *RecordTy = T->getAs<RecordType>())
+ S.MarkVTableUsed(CurInitExpr->getLocStart(),
+ cast<CXXRecordDecl>(RecordTy->getDecl()));
+ }
+
CurInit = S.Owned(new (S.Context) ImplicitCastExpr(Step->Type,
CastExpr::CK_DerivedToBase,
(Expr*)CurInit.release(),
@@ -3619,6 +3652,7 @@ InitializationSequence::Perform(Sema &S,
S.CheckConstructorAccess(Kind.getLocation(), Constructor, Entity,
FoundFn.getAccess());
+ S.DiagnoseUseOfDecl(FoundFn, Kind.getLocation());
CastKind = CastExpr::CK_ConstructorConversion;
QualType Class = S.Context.getTypeDeclType(Constructor->getParent());
@@ -3633,6 +3667,7 @@ InitializationSequence::Perform(Sema &S,
IsLvalue = Conversion->getResultType()->isLValueReferenceType();
S.CheckMemberOperatorAccess(Kind.getLocation(), CurInitExpr, 0,
FoundFn);
+ S.DiagnoseUseOfDecl(FoundFn, Kind.getLocation());
// FIXME: Should we move this initialization into a separate
// derived-to-base conversion? I believe the answer is "no", because
@@ -3723,7 +3758,7 @@ InitializationSequence::Perform(Sema &S,
unsigned NumArgs = Args.size();
CXXConstructorDecl *Constructor
= cast<CXXConstructorDecl>(Step->Function.Function);
-
+
// Build a call to the selected constructor.
ASTOwningVector<&ActionBase::DeleteExpr> ConstructorArgs(S);
SourceLocation Loc = Kind.getLocation();
@@ -3760,11 +3795,21 @@ InitializationSequence::Perform(Sema &S,
CXXConstructExpr::CK_VirtualBase :
CXXConstructExpr::CK_NonVirtualBase;
}
- CurInit = S.BuildCXXConstructExpr(Loc, Entity.getType(),
- Constructor,
- move_arg(ConstructorArgs),
- ConstructorInitRequiresZeroInit,
- ConstructKind);
+
+ // If the entity allows NRVO, mark the construction as elidable
+ // unconditionally.
+ if (Entity.allowsNRVO())
+ CurInit = S.BuildCXXConstructExpr(Loc, Entity.getType(),
+ Constructor, /*Elidable=*/true,
+ move_arg(ConstructorArgs),
+ ConstructorInitRequiresZeroInit,
+ ConstructKind);
+ else
+ CurInit = S.BuildCXXConstructExpr(Loc, Entity.getType(),
+ Constructor,
+ move_arg(ConstructorArgs),
+ ConstructorInitRequiresZeroInit,
+ ConstructKind);
}
if (CurInit.isInvalid())
return S.ExprError();
@@ -3772,6 +3817,7 @@ InitializationSequence::Perform(Sema &S,
// Only check access if all of that succeeded.
S.CheckConstructorAccess(Loc, Constructor, Entity,
Step->Function.FoundDecl.getAccess());
+ S.DiagnoseUseOfDecl(Step->Function.FoundDecl, Loc);
if (shouldBindAsTemporary(Entity))
CurInit = S.MaybeBindToTemporary(CurInit.takeAs<Expr>());
@@ -4092,6 +4138,11 @@ bool InitializationSequence::Diagnose(Sema &S,
<< DestType << (bool)DestType->getAs<RecordType>();
}
break;
+
+ case FK_Incomplete:
+ S.RequireCompleteType(Kind.getLocation(), DestType,
+ diag::err_init_incomplete_type);
+ break;
}
PrintInitLocationNote(S, Entity);
@@ -4170,6 +4221,10 @@ void InitializationSequence::dump(llvm::raw_ostream &OS) const {
case FK_DefaultInitOfConst:
OS << "default initialization of a const variable";
break;
+
+ case FK_Incomplete:
+ OS << "initialization of incomplete type";
+ break;
}
OS << '\n';
return;
diff --git a/lib/Sema/SemaInit.h b/lib/Sema/SemaInit.h
index 5f2592fb77cf..a9064ede6d34 100644
--- a/lib/Sema/SemaInit.h
+++ b/lib/Sema/SemaInit.h
@@ -85,11 +85,16 @@ private:
/// the VarDecl, ParmVarDecl, or FieldDecl, respectively.
DeclaratorDecl *VariableOrMember;
- /// \brief When Kind == EK_Result, EK_Exception, or EK_New, the
- /// location of the 'return', 'throw', or 'new' keyword,
- /// respectively. When Kind == EK_Temporary, the location where
- /// the temporary is being created.
- unsigned Location;
+ struct {
+ /// \brief When Kind == EK_Result, EK_Exception, or EK_New, the
+ /// location of the 'return', 'throw', or 'new' keyword,
+ /// respectively. When Kind == EK_Temporary, the location where
+ /// the temporary is being created.
+ unsigned Location;
+
+ /// \brief Whether the
+ bool NRVO;
+ } LocAndNRVO;
/// \brief When Kind == EK_Base, the base specifier that provides the
/// base class. The lower bit specifies whether the base is an inherited
@@ -116,8 +121,13 @@ private:
/// \brief Create the initialization entity for the result of a
/// function, throwing an object, performing an explicit cast, or
/// initializing a parameter for which there is no declaration.
- InitializedEntity(EntityKind Kind, SourceLocation Loc, QualType Type)
- : Kind(Kind), Parent(0), Type(Type), Location(Loc.getRawEncoding()) { }
+ InitializedEntity(EntityKind Kind, SourceLocation Loc, QualType Type,
+ bool NRVO = false)
+ : Kind(Kind), Parent(0), Type(Type)
+ {
+ LocAndNRVO.Location = Loc.getRawEncoding();
+ LocAndNRVO.NRVO = NRVO;
+ }
/// \brief Create the initialization entity for a member subobject.
InitializedEntity(FieldDecl *Member, const InitializedEntity *Parent)
@@ -152,14 +162,14 @@ public:
/// \brief Create the initialization entity for the result of a function.
static InitializedEntity InitializeResult(SourceLocation ReturnLoc,
- QualType Type) {
- return InitializedEntity(EK_Result, ReturnLoc, Type);
+ QualType Type, bool NRVO) {
+ return InitializedEntity(EK_Result, ReturnLoc, Type, NRVO);
}
/// \brief Create the initialization entity for an exception object.
static InitializedEntity InitializeException(SourceLocation ThrowLoc,
- QualType Type) {
- return InitializedEntity(EK_Exception, ThrowLoc, Type);
+ QualType Type, bool NRVO) {
+ return InitializedEntity(EK_Exception, ThrowLoc, Type, NRVO);
}
/// \brief Create the initialization entity for an object allocated via new.
@@ -208,6 +218,10 @@ public:
/// initialized.
DeclaratorDecl *getDecl() const;
+ /// \brief Determine whether this initialization allows the named return
+ /// value optimization, which also applies to thrown objects.
+ bool allowsNRVO() const;
+
/// \brief Retrieve the base specifier.
CXXBaseSpecifier *getBaseSpecifier() const {
assert(getKind() == EK_Base && "Not a base specifier");
@@ -224,14 +238,14 @@ public:
/// the result of a function call.
SourceLocation getReturnLoc() const {
assert(getKind() == EK_Result && "No 'return' location!");
- return SourceLocation::getFromRawEncoding(Location);
+ return SourceLocation::getFromRawEncoding(LocAndNRVO.Location);
}
/// \brief Determine the location of the 'throw' keyword when initializing
/// an exception object.
SourceLocation getThrowLoc() const {
assert(getKind() == EK_Exception && "No 'throw' location!");
- return SourceLocation::getFromRawEncoding(Location);
+ return SourceLocation::getFromRawEncoding(LocAndNRVO.Location);
}
/// \brief If this is already the initializer for an array or vector
@@ -530,7 +544,9 @@ public:
/// \brief Overloaded for initialization by constructor failed.
FK_ConstructorOverloadFailed,
/// \brief Default-initialization of a 'const' object.
- FK_DefaultInitOfConst
+ FK_DefaultInitOfConst,
+ /// \brief Initialization of an incomplete type.
+ FK_Incomplete
};
private:
diff --git a/lib/Sema/SemaLookup.cpp b/lib/Sema/SemaLookup.cpp
index 337a4a3ce3f7..4555a86e01c8 100644
--- a/lib/Sema/SemaLookup.cpp
+++ b/lib/Sema/SemaLookup.cpp
@@ -665,6 +665,8 @@ bool Sema::CppLookupName(LookupResult &R, Scope *S) {
//
DeclContext *OutsideOfTemplateParamDC = 0;
for (; S && !isNamespaceOrTranslationUnitScope(S); S = S->getParent()) {
+ DeclContext *Ctx = static_cast<DeclContext*>(S->getEntity());
+
// Check whether the IdResolver has anything in this scope.
bool Found = false;
for (; I != IEnd && S->isDeclScope(DeclPtrTy::make(*I)); ++I) {
@@ -675,10 +677,12 @@ bool Sema::CppLookupName(LookupResult &R, Scope *S) {
}
if (Found) {
R.resolveKind();
+ if (S->isClassScope())
+ if (CXXRecordDecl *Record = dyn_cast_or_null<CXXRecordDecl>(Ctx))
+ R.setNamingClass(Record);
return true;
}
- DeclContext *Ctx = static_cast<DeclContext*>(S->getEntity());
if (!Ctx && S->isTemplateParamScope() && OutsideOfTemplateParamDC &&
S->getParent() && !S->getParent()->isTemplateParamScope()) {
// We've just searched the last template parameter scope and
@@ -761,10 +765,6 @@ bool Sema::CppLookupName(LookupResult &R, Scope *S) {
// context as well as walking through the scopes.
for (; S; S = S->getParent()) {
- DeclContext *Ctx = static_cast<DeclContext *>(S->getEntity());
- if (Ctx && Ctx->isTransparentContext())
- continue;
-
// Check whether the IdResolver has anything in this scope.
bool Found = false;
for (; I != IEnd && S->isDeclScope(DeclPtrTy::make(*I)); ++I) {
@@ -778,21 +778,57 @@ bool Sema::CppLookupName(LookupResult &R, Scope *S) {
}
}
- // If we have a context, and it's not a context stashed in the
- // template parameter scope for an out-of-line definition, also
- // look into that context.
- if (Ctx && !(Found && S && S->isTemplateParamScope())) {
- assert(Ctx->isFileContext() &&
- "We should have been looking only at file context here already.");
+ if (Found && S->isTemplateParamScope()) {
+ R.resolveKind();
+ return true;
+ }
- // Look into context considering using-directives.
- if (CppNamespaceLookup(*this, R, Context, Ctx, UDirs))
- Found = true;
+ DeclContext *Ctx = static_cast<DeclContext *>(S->getEntity());
+ if (!Ctx && S->isTemplateParamScope() && OutsideOfTemplateParamDC &&
+ S->getParent() && !S->getParent()->isTemplateParamScope()) {
+ // We've just searched the last template parameter scope and
+ // found nothing, so look into the the contexts between the
+ // lexical and semantic declaration contexts returned by
+ // findOuterContext(). This implements the name lookup behavior
+ // of C++ [temp.local]p8.
+ Ctx = OutsideOfTemplateParamDC;
+ OutsideOfTemplateParamDC = 0;
}
+
+ if (Ctx) {
+ DeclContext *OuterCtx;
+ bool SearchAfterTemplateScope;
+ llvm::tie(OuterCtx, SearchAfterTemplateScope) = findOuterContext(S);
+ if (SearchAfterTemplateScope)
+ OutsideOfTemplateParamDC = OuterCtx;
- if (Found) {
- R.resolveKind();
- return true;
+ for (; Ctx && !Ctx->Equals(OuterCtx); Ctx = Ctx->getLookupParent()) {
+ // We do not directly look into transparent contexts, since
+ // those entities will be found in the nearest enclosing
+ // non-transparent context.
+ if (Ctx->isTransparentContext())
+ continue;
+
+ // If we have a context, and it's not a context stashed in the
+ // template parameter scope for an out-of-line definition, also
+ // look into that context.
+ if (!(Found && S && S->isTemplateParamScope())) {
+ assert(Ctx->isFileContext() &&
+ "We should have been looking only at file context here already.");
+
+ // Look into context considering using-directives.
+ if (CppNamespaceLookup(*this, R, Context, Ctx, UDirs))
+ Found = true;
+ }
+
+ if (Found) {
+ R.resolveKind();
+ return true;
+ }
+
+ if (R.isForRedeclaration() && !Ctx->isTransparentContext())
+ return false;
+ }
}
if (R.isForRedeclaration() && Ctx && !Ctx->isTransparentContext())
@@ -2580,6 +2616,12 @@ DeclarationName Sema::CorrectTypo(LookupResult &Res, Scope *S, CXXScopeSpec *SS,
WantExpressionKeywords = true;
WantCXXNamedCasts = true;
WantRemainingKeywords = true;
+
+ if (ObjCMethodDecl *Method = getCurMethodDecl())
+ if (Method->getClassInterface() &&
+ Method->getClassInterface()->getSuperClass())
+ Consumer.addKeywordResult(Context, "super");
+
break;
case CTC_NoKeywords:
@@ -2646,7 +2688,7 @@ DeclarationName Sema::CorrectTypo(LookupResult &Res, Scope *S, CXXScopeSpec *SS,
Consumer.addKeywordResult(Context, "typeof");
}
- if (WantCXXNamedCasts) {
+ if (WantCXXNamedCasts && getLangOptions().CPlusPlus) {
Consumer.addKeywordResult(Context, "const_cast");
Consumer.addKeywordResult(Context, "dynamic_cast");
Consumer.addKeywordResult(Context, "reinterpret_cast");
@@ -2776,6 +2818,25 @@ DeclarationName Sema::CorrectTypo(LookupResult &Res, Scope *S, CXXScopeSpec *SS,
BestIvarOrPropertyDecl = 0;
FoundIvarOrPropertyDecl = false;
Consumer.clear_decls();
+ } else if (CTC == CTC_ObjCMessageReceiver &&
+ (*Consumer.keyword_begin())->isStr("super")) {
+ // In an Objective-C message send, give the "super" keyword a slight
+ // edge over entities not in function or method scope.
+ for (TypoCorrectionConsumer::iterator I = Consumer.begin(),
+ IEnd = Consumer.end();
+ I != IEnd; ++I) {
+ if ((*I)->getDeclName() == BestName) {
+ if ((*I)->getDeclContext()->isFunctionOrMethod())
+ return DeclarationName();
+ }
+ }
+
+ // Everything found was outside a function or method; the 'super'
+ // keyword takes precedence.
+ BestIvarOrPropertyDecl = 0;
+ FoundIvarOrPropertyDecl = false;
+ Consumer.clear_decls();
+ BestName = *Consumer.keyword_begin();
} else {
// Name collision; we will not correct typos.
return DeclarationName();
diff --git a/lib/Sema/SemaObjCProperty.cpp b/lib/Sema/SemaObjCProperty.cpp
index b73739fc5551..4c89a118bc9a 100644
--- a/lib/Sema/SemaObjCProperty.cpp
+++ b/lib/Sema/SemaObjCProperty.cpp
@@ -13,6 +13,8 @@
//===----------------------------------------------------------------------===//
#include "Sema.h"
+#include "SemaInit.h"
+#include "clang/AST/ExprObjC.h"
using namespace clang;
@@ -119,7 +121,7 @@ Sema::HandlePropertyInClassExtension(Scope *S, ObjCCategoryDecl *CDecl,
ObjCPropertyDecl *PDecl =
CreatePropertyDecl(S, CCPrimary, AtLoc,
FD, GetterSel, SetterSel, isAssign, isReadWrite,
- Attributes, T, MethodImplKind);
+ Attributes, T, MethodImplKind, DC);
// A case of continuation class adding a new property in the class. This
// is not what it was meant for. However, gcc supports it and so should we.
@@ -189,7 +191,8 @@ ObjCPropertyDecl *Sema::CreatePropertyDecl(Scope *S,
const bool isReadWrite,
const unsigned Attributes,
QualType T,
- tok::ObjCKeywordKind MethodImplKind){
+ tok::ObjCKeywordKind MethodImplKind,
+ DeclContext *lexicalDC){
IdentifierInfo *PropertyId = FD.D.getIdentifier();
@@ -197,19 +200,16 @@ ObjCPropertyDecl *Sema::CreatePropertyDecl(Scope *S,
// gc'able conforms to NSCopying protocol
if (getLangOptions().getGCMode() != LangOptions::NonGC &&
isAssign && !(Attributes & ObjCDeclSpec::DQ_PR_assign))
- if (T->isObjCObjectPointerType()) {
- QualType InterfaceTy = T->getPointeeType();
- if (const ObjCInterfaceType *OIT =
- InterfaceTy->getAs<ObjCInterfaceType>()) {
- ObjCInterfaceDecl *IDecl = OIT->getDecl();
- if (IDecl)
- if (ObjCProtocolDecl* PNSCopying =
- LookupProtocol(&Context.Idents.get("NSCopying"), AtLoc))
- if (IDecl->ClassImplementsProtocol(PNSCopying, true))
- Diag(AtLoc, diag::warn_implements_nscopying) << PropertyId;
- }
+ if (const ObjCObjectPointerType *ObjPtrTy =
+ T->getAs<ObjCObjectPointerType>()) {
+ ObjCInterfaceDecl *IDecl = ObjPtrTy->getObjectType()->getInterface();
+ if (IDecl)
+ if (ObjCProtocolDecl* PNSCopying =
+ LookupProtocol(&Context.Idents.get("NSCopying"), AtLoc))
+ if (IDecl->ClassImplementsProtocol(PNSCopying, true))
+ Diag(AtLoc, diag::warn_implements_nscopying) << PropertyId;
}
- if (T->isObjCInterfaceType())
+ if (T->isObjCObjectType())
Diag(FD.D.getIdentifierLoc(), diag::err_statically_allocated_object);
DeclContext *DC = cast<DeclContext>(CDecl);
@@ -223,8 +223,11 @@ ObjCPropertyDecl *Sema::CreatePropertyDecl(Scope *S,
Diag(prevDecl->getLocation(), diag::note_property_declare);
PDecl->setInvalidDecl();
}
- else
+ else {
DC->addDecl(PDecl);
+ if (lexicalDC)
+ PDecl->setLexicalDeclContext(lexicalDC);
+ }
if (T->isArrayType() || T->isFunctionType()) {
Diag(AtLoc, diag::err_property_type) << T;
@@ -275,7 +278,8 @@ ObjCPropertyDecl *Sema::CreatePropertyDecl(Scope *S,
/// builds the AST node for a property implementation declaration; declared
/// as @synthesize or @dynamic.
///
-Sema::DeclPtrTy Sema::ActOnPropertyImplDecl(SourceLocation AtLoc,
+Sema::DeclPtrTy Sema::ActOnPropertyImplDecl(Scope *S,
+ SourceLocation AtLoc,
SourceLocation PropertyLoc,
bool Synthesize,
DeclPtrTy ClassCatImpDecl,
@@ -379,7 +383,16 @@ Sema::DeclPtrTy Sema::ActOnPropertyImplDecl(SourceLocation AtLoc,
// Check that type of property and its ivar are type compatible.
if (PropType != IvarType) {
- if (CheckAssignmentConstraints(PropType, IvarType) != Compatible) {
+ bool compat = false;
+ if (isa<ObjCObjectPointerType>(PropType)
+ && isa<ObjCObjectPointerType>(IvarType))
+ compat =
+ Context.canAssignObjCInterfaces(
+ PropType->getAs<ObjCObjectPointerType>(),
+ IvarType->getAs<ObjCObjectPointerType>());
+ else
+ compat = (CheckAssignmentConstraints(PropType, IvarType) == Compatible);
+ if (!compat) {
Diag(PropertyLoc, diag::error_property_ivar_type)
<< property->getDeclName() << PropType
<< Ivar->getDeclName() << IvarType;
@@ -427,6 +440,55 @@ Sema::DeclPtrTy Sema::ActOnPropertyImplDecl(SourceLocation AtLoc,
ObjCPropertyImplDecl::Synthesize
: ObjCPropertyImplDecl::Dynamic),
Ivar);
+ if (ObjCMethodDecl *getterMethod = property->getGetterMethodDecl()) {
+ getterMethod->createImplicitParams(Context, IDecl);
+ if (getLangOptions().CPlusPlus && Synthesize) {
+ // For Objective-C++, need to synthesize the AST for the IVAR object to be
+ // returned by the getter as it must conform to C++'s copy-return rules.
+ // FIXME. Eventually we want to do this for Objective-C as well.
+ ImplicitParamDecl *SelfDecl = getterMethod->getSelfDecl();
+ DeclRefExpr *SelfExpr =
+ new (Context) DeclRefExpr(SelfDecl,SelfDecl->getType(),
+ SourceLocation());
+ Expr *IvarRefExpr =
+ new (Context) ObjCIvarRefExpr(Ivar, Ivar->getType(), AtLoc,
+ SelfExpr, true, true);
+ OwningExprResult Res =
+ PerformCopyInitialization(InitializedEntity::InitializeResult(
+ SourceLocation(),
+ getterMethod->getResultType(),
+ /*NRVO=*/false),
+ SourceLocation(),
+ Owned(IvarRefExpr));
+ if (!Res.isInvalid()) {
+ Expr *ResExpr = Res.takeAs<Expr>();
+ if (ResExpr)
+ ResExpr = MaybeCreateCXXExprWithTemporaries(ResExpr);
+ PIDecl->setGetterCXXConstructor(ResExpr);
+ }
+ }
+ }
+ if (ObjCMethodDecl *setterMethod = property->getSetterMethodDecl()) {
+ setterMethod->createImplicitParams(Context, IDecl);
+ if (getLangOptions().CPlusPlus && Synthesize) {
+ // FIXME. Eventually we want to do this for Objective-C as well.
+ ImplicitParamDecl *SelfDecl = setterMethod->getSelfDecl();
+ DeclRefExpr *SelfExpr =
+ new (Context) DeclRefExpr(SelfDecl,SelfDecl->getType(),
+ SourceLocation());
+ Expr *lhs =
+ new (Context) ObjCIvarRefExpr(Ivar, Ivar->getType(), AtLoc,
+ SelfExpr, true, true);
+ ObjCMethodDecl::param_iterator P = setterMethod->param_begin();
+ ParmVarDecl *Param = (*P);
+ Expr *rhs = new (Context) DeclRefExpr(Param,Param->getType(),
+ SourceLocation());
+ OwningExprResult Res = BuildBinOp(S, SourceLocation(),
+ BinaryOperator::Assign, lhs, rhs);
+ PIDecl->setSetterCXXAssignment(Res.takeAs<Expr>());
+ }
+ }
+
if (IC) {
if (Synthesize)
if (ObjCPropertyImplDecl *PPIDecl =
@@ -751,6 +813,47 @@ void Sema::CollectImmediateProperties(ObjCContainerDecl *CDecl,
}
}
+/// CollectClassPropertyImplementations - This routine collects list of
+/// properties to be implemented in the class. This includes, class's
+/// and its conforming protocols' properties.
+static void CollectClassPropertyImplementations(ObjCContainerDecl *CDecl,
+ llvm::DenseMap<IdentifierInfo *, ObjCPropertyDecl*>& PropMap) {
+ if (ObjCInterfaceDecl *IDecl = dyn_cast<ObjCInterfaceDecl>(CDecl)) {
+ for (ObjCContainerDecl::prop_iterator P = IDecl->prop_begin(),
+ E = IDecl->prop_end(); P != E; ++P) {
+ ObjCPropertyDecl *Prop = (*P);
+ PropMap[Prop->getIdentifier()] = Prop;
+ }
+ for (ObjCInterfaceDecl::protocol_iterator PI = IDecl->protocol_begin(),
+ E = IDecl->protocol_end(); PI != E; ++PI)
+ CollectClassPropertyImplementations((*PI), PropMap);
+ }
+ else if (ObjCProtocolDecl *PDecl = dyn_cast<ObjCProtocolDecl>(CDecl)) {
+ for (ObjCProtocolDecl::prop_iterator P = PDecl->prop_begin(),
+ E = PDecl->prop_end(); P != E; ++P) {
+ ObjCPropertyDecl *Prop = (*P);
+ PropMap[Prop->getIdentifier()] = Prop;
+ }
+ // scan through protocol's protocols.
+ for (ObjCProtocolDecl::protocol_iterator PI = PDecl->protocol_begin(),
+ E = PDecl->protocol_end(); PI != E; ++PI)
+ CollectClassPropertyImplementations((*PI), PropMap);
+ }
+}
+
+/// CollectSuperClassPropertyImplementations - This routine collects list of
+/// properties to be implemented in super class(s) and also coming from their
+/// conforming protocols.
+static void CollectSuperClassPropertyImplementations(ObjCInterfaceDecl *CDecl,
+ llvm::DenseMap<IdentifierInfo *, ObjCPropertyDecl*>& PropMap) {
+ if (ObjCInterfaceDecl *SDecl = CDecl->getSuperClass()) {
+ while (SDecl) {
+ CollectClassPropertyImplementations(SDecl, PropMap);
+ SDecl = SDecl->getSuperClass();
+ }
+ }
+}
+
/// ProtocolConformsToSuperClass - Returns true if class's given protocol
/// conforms to one of its super class's protocols.
bool Sema::ProtocolConformsToSuperClass(const ObjCInterfaceDecl *IDecl,
@@ -817,8 +920,36 @@ ObjCPropertyDecl *Sema::LookupPropertyDecl(const ObjCContainerDecl *CDecl,
return 0;
}
+/// DefaultSynthesizeProperties - This routine default synthesizes all
+/// properties which must be synthesized in class's @implementation.
+void Sema::DefaultSynthesizeProperties (Scope *S, ObjCImplDecl* IMPDecl,
+ ObjCInterfaceDecl *IDecl) {
+
+ llvm::DenseMap<IdentifierInfo *, ObjCPropertyDecl*> PropMap;
+ CollectClassPropertyImplementations(IDecl, PropMap);
+ if (PropMap.empty())
+ return;
+ llvm::DenseMap<IdentifierInfo *, ObjCPropertyDecl*> SuperPropMap;
+ CollectSuperClassPropertyImplementations(IDecl, SuperPropMap);
+
+ for (llvm::DenseMap<IdentifierInfo *, ObjCPropertyDecl*>::iterator
+ P = PropMap.begin(), E = PropMap.end(); P != E; ++P) {
+ ObjCPropertyDecl *Prop = P->second;
+ // If property to be implemented in the super class, ignore.
+ if (SuperPropMap[Prop->getIdentifier()])
+ continue;
+ // Is there a matching propery synthesize/dynamic?
+ if (Prop->isInvalidDecl() ||
+ Prop->getPropertyImplementation() == ObjCPropertyDecl::Optional ||
+ IMPDecl->FindPropertyImplIvarDecl(Prop->getIdentifier()))
+ continue;
+ ActOnPropertyImplDecl(S, IMPDecl->getLocation(), IMPDecl->getLocation(),
+ true, DeclPtrTy::make(IMPDecl),
+ Prop->getIdentifier(), Prop->getIdentifier());
+ }
+}
-void Sema::DiagnoseUnimplementedProperties(ObjCImplDecl* IMPDecl,
+void Sema::DiagnoseUnimplementedProperties(Scope *S, ObjCImplDecl* IMPDecl,
ObjCContainerDecl *CDecl,
const llvm::DenseSet<Selector>& InsMap) {
llvm::DenseMap<IdentifierInfo *, ObjCPropertyDecl*> PropMap;
@@ -840,14 +971,6 @@ void Sema::DiagnoseUnimplementedProperties(ObjCImplDecl* IMPDecl,
Prop->getPropertyImplementation() == ObjCPropertyDecl::Optional ||
PropImplMap.count(Prop))
continue;
- if (LangOpts.ObjCNonFragileABI2 && !isa<ObjCCategoryImplDecl>(IMPDecl)) {
- ActOnPropertyImplDecl(IMPDecl->getLocation(),
- IMPDecl->getLocation(),
- true, DeclPtrTy::make(IMPDecl),
- Prop->getIdentifier(),
- Prop->getIdentifier());
- continue;
- }
if (!InsMap.count(Prop->getGetterName())) {
Diag(Prop->getLocation(),
isa<ObjCCategoryDecl>(CDecl) ?
@@ -954,6 +1077,11 @@ void Sema::ProcessPropertyDecl(ObjCPropertyDecl *property,
ObjCMethodDecl::Optional :
ObjCMethodDecl::Required);
CD->addDecl(GetterMethod);
+ // FIXME: Eventually this shouldn't be needed, as the lexical context
+ // and the real context should be the same.
+ if (DeclContext *lexicalDC = property->getLexicalDeclContext())
+ GetterMethod->setLexicalDeclContext(lexicalDC);
+
} else
// A user declared getter will be synthesize when @synthesize of
// the property with the same name is seen in the @implementation
@@ -987,6 +1115,10 @@ void Sema::ProcessPropertyDecl(ObjCPropertyDecl *property,
0);
SetterMethod->setMethodParams(Context, &Argument, 1, 1);
CD->addDecl(SetterMethod);
+ // FIXME: Eventually this shouldn't be needed, as the lexical context
+ // and the real context should be the same.
+ if (DeclContext *lexicalDC = property->getLexicalDeclContext())
+ SetterMethod->setLexicalDeclContext(lexicalDC);
} else
// A user declared setter will be synthesize when @synthesize of
// the property with the same name is seen in the @implementation
diff --git a/lib/Sema/SemaOverload.cpp b/lib/Sema/SemaOverload.cpp
index b87fa7d51ea1..2754d443b25a 100644
--- a/lib/Sema/SemaOverload.cpp
+++ b/lib/Sema/SemaOverload.cpp
@@ -52,6 +52,8 @@ GetConversionCategory(ImplicitConversionKind Kind) {
ICC_Conversion,
ICC_Conversion,
ICC_Conversion,
+ ICC_Conversion,
+ ICC_Conversion,
ICC_Conversion
};
return Category[(int)Kind];
@@ -80,6 +82,8 @@ ImplicitConversionRank GetConversionRank(ImplicitConversionKind Kind) {
ICR_Conversion,
ICR_Conversion,
ICR_Conversion,
+ ICR_Conversion,
+ ICR_Conversion,
ICR_Complex_Real_Conversion
};
return Rank[(int)Kind];
@@ -102,12 +106,14 @@ const char* GetImplicitConversionName(ImplicitConversionKind Kind) {
"Floating conversion",
"Complex conversion",
"Floating-integral conversion",
- "Complex-real conversion",
"Pointer conversion",
"Pointer-to-member conversion",
"Boolean conversion",
"Compatible-types conversion",
- "Derived-to-base conversion"
+ "Derived-to-base conversion",
+ "Vector conversion",
+ "Vector splat",
+ "Complex-real conversion"
};
return Name[Kind];
}
@@ -275,7 +281,194 @@ AmbiguousConversionSequence::copyFrom(const AmbiguousConversionSequence &O) {
new (&conversions()) ConversionSet(O.conversions());
}
+namespace {
+ // Structure used by OverloadCandidate::DeductionFailureInfo to store
+ // template parameter and template argument information.
+ struct DFIParamWithArguments {
+ TemplateParameter Param;
+ TemplateArgument FirstArg;
+ TemplateArgument SecondArg;
+ };
+}
+
+/// \brief Convert from Sema's representation of template deduction information
+/// to the form used in overload-candidate information.
+OverloadCandidate::DeductionFailureInfo
+static MakeDeductionFailureInfo(ASTContext &Context,
+ Sema::TemplateDeductionResult TDK,
+ Sema::TemplateDeductionInfo &Info) {
+ OverloadCandidate::DeductionFailureInfo Result;
+ Result.Result = static_cast<unsigned>(TDK);
+ Result.Data = 0;
+ switch (TDK) {
+ case Sema::TDK_Success:
+ case Sema::TDK_InstantiationDepth:
+ case Sema::TDK_TooManyArguments:
+ case Sema::TDK_TooFewArguments:
+ break;
+
+ case Sema::TDK_Incomplete:
+ case Sema::TDK_InvalidExplicitArguments:
+ Result.Data = Info.Param.getOpaqueValue();
+ break;
+
+ case Sema::TDK_Inconsistent:
+ case Sema::TDK_InconsistentQuals: {
+ // FIXME: Should allocate from normal heap so that we can free this later.
+ DFIParamWithArguments *Saved = new (Context) DFIParamWithArguments;
+ Saved->Param = Info.Param;
+ Saved->FirstArg = Info.FirstArg;
+ Saved->SecondArg = Info.SecondArg;
+ Result.Data = Saved;
+ break;
+ }
+
+ case Sema::TDK_SubstitutionFailure:
+ Result.Data = Info.take();
+ break;
+
+ case Sema::TDK_NonDeducedMismatch:
+ case Sema::TDK_FailedOverloadResolution:
+ break;
+ }
+
+ return Result;
+}
+
+void OverloadCandidate::DeductionFailureInfo::Destroy() {
+ switch (static_cast<Sema::TemplateDeductionResult>(Result)) {
+ case Sema::TDK_Success:
+ case Sema::TDK_InstantiationDepth:
+ case Sema::TDK_Incomplete:
+ case Sema::TDK_TooManyArguments:
+ case Sema::TDK_TooFewArguments:
+ case Sema::TDK_InvalidExplicitArguments:
+ break;
+
+ case Sema::TDK_Inconsistent:
+ case Sema::TDK_InconsistentQuals:
+ // FIXME: Destroy the data?
+ Data = 0;
+ break;
+ case Sema::TDK_SubstitutionFailure:
+ // FIXME: Destroy the template arugment list?
+ Data = 0;
+ break;
+
+ // Unhandled
+ case Sema::TDK_NonDeducedMismatch:
+ case Sema::TDK_FailedOverloadResolution:
+ break;
+ }
+}
+
+TemplateParameter
+OverloadCandidate::DeductionFailureInfo::getTemplateParameter() {
+ switch (static_cast<Sema::TemplateDeductionResult>(Result)) {
+ case Sema::TDK_Success:
+ case Sema::TDK_InstantiationDepth:
+ case Sema::TDK_TooManyArguments:
+ case Sema::TDK_TooFewArguments:
+ case Sema::TDK_SubstitutionFailure:
+ return TemplateParameter();
+
+ case Sema::TDK_Incomplete:
+ case Sema::TDK_InvalidExplicitArguments:
+ return TemplateParameter::getFromOpaqueValue(Data);
+
+ case Sema::TDK_Inconsistent:
+ case Sema::TDK_InconsistentQuals:
+ return static_cast<DFIParamWithArguments*>(Data)->Param;
+
+ // Unhandled
+ case Sema::TDK_NonDeducedMismatch:
+ case Sema::TDK_FailedOverloadResolution:
+ break;
+ }
+
+ return TemplateParameter();
+}
+
+TemplateArgumentList *
+OverloadCandidate::DeductionFailureInfo::getTemplateArgumentList() {
+ switch (static_cast<Sema::TemplateDeductionResult>(Result)) {
+ case Sema::TDK_Success:
+ case Sema::TDK_InstantiationDepth:
+ case Sema::TDK_TooManyArguments:
+ case Sema::TDK_TooFewArguments:
+ case Sema::TDK_Incomplete:
+ case Sema::TDK_InvalidExplicitArguments:
+ case Sema::TDK_Inconsistent:
+ case Sema::TDK_InconsistentQuals:
+ return 0;
+
+ case Sema::TDK_SubstitutionFailure:
+ return static_cast<TemplateArgumentList*>(Data);
+
+ // Unhandled
+ case Sema::TDK_NonDeducedMismatch:
+ case Sema::TDK_FailedOverloadResolution:
+ break;
+ }
+
+ return 0;
+}
+
+const TemplateArgument *OverloadCandidate::DeductionFailureInfo::getFirstArg() {
+ switch (static_cast<Sema::TemplateDeductionResult>(Result)) {
+ case Sema::TDK_Success:
+ case Sema::TDK_InstantiationDepth:
+ case Sema::TDK_Incomplete:
+ case Sema::TDK_TooManyArguments:
+ case Sema::TDK_TooFewArguments:
+ case Sema::TDK_InvalidExplicitArguments:
+ case Sema::TDK_SubstitutionFailure:
+ return 0;
+
+ case Sema::TDK_Inconsistent:
+ case Sema::TDK_InconsistentQuals:
+ return &static_cast<DFIParamWithArguments*>(Data)->FirstArg;
+
+ // Unhandled
+ case Sema::TDK_NonDeducedMismatch:
+ case Sema::TDK_FailedOverloadResolution:
+ break;
+ }
+
+ return 0;
+}
+
+const TemplateArgument *
+OverloadCandidate::DeductionFailureInfo::getSecondArg() {
+ switch (static_cast<Sema::TemplateDeductionResult>(Result)) {
+ case Sema::TDK_Success:
+ case Sema::TDK_InstantiationDepth:
+ case Sema::TDK_Incomplete:
+ case Sema::TDK_TooManyArguments:
+ case Sema::TDK_TooFewArguments:
+ case Sema::TDK_InvalidExplicitArguments:
+ case Sema::TDK_SubstitutionFailure:
+ return 0;
+
+ case Sema::TDK_Inconsistent:
+ case Sema::TDK_InconsistentQuals:
+ return &static_cast<DFIParamWithArguments*>(Data)->SecondArg;
+
+ // Unhandled
+ case Sema::TDK_NonDeducedMismatch:
+ case Sema::TDK_FailedOverloadResolution:
+ break;
+ }
+
+ return 0;
+}
+
+void OverloadCandidateSet::clear() {
+ inherited::clear();
+ Functions.clear();
+}
+
// IsOverload - Determine whether the given New declaration is an
// overload of the declarations in Old. This routine returns false if
// New and Old cannot be overloaded, e.g., if New has the same
@@ -586,6 +779,48 @@ static bool IsNoReturnConversion(ASTContext &Context, QualType FromType,
ResultTy = FromType;
return true;
}
+
+/// \brief Determine whether the conversion from FromType to ToType is a valid
+/// vector conversion.
+///
+/// \param ICK Will be set to the vector conversion kind, if this is a vector
+/// conversion.
+static bool IsVectorConversion(ASTContext &Context, QualType FromType,
+ QualType ToType, ImplicitConversionKind &ICK) {
+ // We need at least one of these types to be a vector type to have a vector
+ // conversion.
+ if (!ToType->isVectorType() && !FromType->isVectorType())
+ return false;
+
+ // Identical types require no conversions.
+ if (Context.hasSameUnqualifiedType(FromType, ToType))
+ return false;
+
+ // There are no conversions between extended vector types, only identity.
+ if (ToType->isExtVectorType()) {
+ // There are no conversions between extended vector types other than the
+ // identity conversion.
+ if (FromType->isExtVectorType())
+ return false;
+
+ // Vector splat from any arithmetic type to a vector.
+ if (!FromType->isVectorType() && FromType->isArithmeticType()) {
+ ICK = ICK_Vector_Splat;
+ return true;
+ }
+ }
+
+ // If lax vector conversions are permitted and the vector types are of the
+ // same size, we can perform the conversion.
+ if (Context.getLangOptions().LaxVectorConversions &&
+ FromType->isVectorType() && ToType->isVectorType() &&
+ Context.getTypeSize(FromType) == Context.getTypeSize(ToType)) {
+ ICK = ICK_Vector_Conversion;
+ return true;
+ }
+
+ return false;
+}
/// IsStandardConversion - Determines whether there is a standard
/// conversion sequence (C++ [conv], C++ [over.ics.scs]) from the
@@ -708,6 +943,7 @@ Sema::IsStandardConversion(Expr* From, QualType ToType,
// For overloading in C, this can also be a "compatible-type"
// conversion.
bool IncompatibleObjC = false;
+ ImplicitConversionKind SecondICK = ICK_Identity;
if (Context.hasSameUnqualifiedType(FromType, ToType)) {
// The unqualified versions of the types are the same: there's no
// conversion to do.
@@ -769,10 +1005,14 @@ Sema::IsStandardConversion(Expr* From, QualType ToType,
// Boolean conversions (C++ 4.12).
SCS.Second = ICK_Boolean_Conversion;
FromType = Context.BoolTy;
+ } else if (IsVectorConversion(Context, FromType, ToType, SecondICK)) {
+ SCS.Second = SecondICK;
+ FromType = ToType.getUnqualifiedType();
} else if (!getLangOptions().CPlusPlus &&
Context.typesAreCompatible(ToType, FromType)) {
// Compatible conversions (Clang extension for C function overloading)
SCS.Second = ICK_Compatible_Conversion;
+ FromType = ToType.getUnqualifiedType();
} else if (IsNoReturnConversion(Context, FromType, ToType, FromType)) {
// Treat a conversion that strips "noreturn" as an identity conversion.
SCS.Second = ICK_NoReturn_Adjustment;
@@ -802,7 +1042,8 @@ Sema::IsStandardConversion(Expr* From, QualType ToType,
CanonTo = Context.getCanonicalType(ToType);
if (CanonFrom.getLocalUnqualifiedType()
== CanonTo.getLocalUnqualifiedType() &&
- CanonFrom.getLocalCVRQualifiers() != CanonTo.getLocalCVRQualifiers()) {
+ (CanonFrom.getLocalCVRQualifiers() != CanonTo.getLocalCVRQualifiers()
+ || CanonFrom.getObjCGCAttr() != CanonTo.getObjCGCAttr())) {
FromType = ToType;
CanonFrom = CanonTo;
}
@@ -992,7 +1233,7 @@ BuildSimilarlyQualifiedPointerType(const PointerType *FromPtr,
if (CanonToPointee.getLocalQualifiers() == Quals) {
// ToType is exactly what we need. Return it.
if (!ToType.isNull())
- return ToType;
+ return ToType.getUnqualifiedType();
// Build a pointer to ToPointee. It has the right qualifiers
// already.
@@ -1350,22 +1591,18 @@ bool Sema::FunctionArgTypesAreEqual(FunctionProtoType* OldType,
if (ToType != FromType) {
if (const PointerType *PTTo = ToType->getAs<PointerType>()) {
if (const PointerType *PTFr = FromType->getAs<PointerType>())
- if (PTTo->getPointeeType()->isObjCQualifiedIdType() &&
- PTFr->getPointeeType()->isObjCQualifiedIdType() ||
- PTTo->getPointeeType()->isObjCQualifiedClassType() &&
- PTFr->getPointeeType()->isObjCQualifiedClassType())
+ if ((PTTo->getPointeeType()->isObjCQualifiedIdType() &&
+ PTFr->getPointeeType()->isObjCQualifiedIdType()) ||
+ (PTTo->getPointeeType()->isObjCQualifiedClassType() &&
+ PTFr->getPointeeType()->isObjCQualifiedClassType()))
continue;
}
- else if (ToType->isObjCObjectPointerType() &&
- FromType->isObjCObjectPointerType()) {
- QualType ToInterfaceTy = ToType->getPointeeType();
- QualType FromInterfaceTy = FromType->getPointeeType();
- if (const ObjCInterfaceType *OITTo =
- ToInterfaceTy->getAs<ObjCInterfaceType>())
- if (const ObjCInterfaceType *OITFr =
- FromInterfaceTy->getAs<ObjCInterfaceType>())
- if (OITTo->getDecl() == OITFr->getDecl())
- continue;
+ else if (const ObjCObjectPointerType *PTTo =
+ ToType->getAs<ObjCObjectPointerType>()) {
+ if (const ObjCObjectPointerType *PTFr =
+ FromType->getAs<ObjCObjectPointerType>())
+ if (PTTo->getInterfaceDecl() == PTFr->getInterfaceDecl())
+ continue;
}
return false;
}
@@ -1839,6 +2076,15 @@ compareStandardConversionSubsets(ASTContext &Context,
ImplicitConversionSequence::CompareKind Result
= ImplicitConversionSequence::Indistinguishable;
+ // the identity conversion sequence is considered to be a subsequence of
+ // any non-identity conversion sequence
+ if (SCS1.ReferenceBinding == SCS2.ReferenceBinding) {
+ if (SCS1.isIdentityConversion() && !SCS2.isIdentityConversion())
+ return ImplicitConversionSequence::Better;
+ else if (!SCS1.isIdentityConversion() && SCS2.isIdentityConversion())
+ return ImplicitConversionSequence::Worse;
+ }
+
if (SCS1.Second != SCS2.Second) {
if (SCS1.Second == ICK_Identity)
Result = ImplicitConversionSequence::Better;
@@ -1954,8 +2200,8 @@ Sema::CompareStandardConversionSequences(const StandardConversionSequence& SCS1,
// Objective-C++: If one interface is more specific than the
// other, it is the better one.
- const ObjCInterfaceType* FromIface1 = FromPointee1->getAs<ObjCInterfaceType>();
- const ObjCInterfaceType* FromIface2 = FromPointee2->getAs<ObjCInterfaceType>();
+ const ObjCObjectType* FromIface1 = FromPointee1->getAs<ObjCObjectType>();
+ const ObjCObjectType* FromIface2 = FromPointee2->getAs<ObjCObjectType>();
if (FromIface1 && FromIface1) {
if (Context.canAssignObjCInterfaces(FromIface2, FromIface1))
return ImplicitConversionSequence::Better;
@@ -2161,10 +2407,10 @@ Sema::CompareDerivedToBaseConversions(const StandardConversionSequence& SCS1,
QualType ToPointee2
= ToType2->getAs<PointerType>()->getPointeeType().getUnqualifiedType();
- const ObjCInterfaceType* FromIface1 = FromPointee1->getAs<ObjCInterfaceType>();
- const ObjCInterfaceType* FromIface2 = FromPointee2->getAs<ObjCInterfaceType>();
- const ObjCInterfaceType* ToIface1 = ToPointee1->getAs<ObjCInterfaceType>();
- const ObjCInterfaceType* ToIface2 = ToPointee2->getAs<ObjCInterfaceType>();
+ const ObjCObjectType* FromIface1 = FromPointee1->getAs<ObjCObjectType>();
+ const ObjCObjectType* FromIface2 = FromPointee2->getAs<ObjCObjectType>();
+ const ObjCObjectType* ToIface1 = ToPointee1->getAs<ObjCObjectType>();
+ const ObjCObjectType* ToIface2 = ToPointee2->getAs<ObjCObjectType>();
// -- conversion of C* to B* is better than conversion of C* to A*,
if (FromPointee1 == FromPointee2 && ToPointee1 != ToPointee2) {
@@ -2289,8 +2535,7 @@ Sema::CompareReferenceRelationship(SourceLocation Loc,
// T1 is a base class of T2.
if (UnqualT1 == UnqualT2)
DerivedToBase = false;
- else if (!RequireCompleteType(Loc, OrigT1, PDiag()) &&
- !RequireCompleteType(Loc, OrigT2, PDiag()) &&
+ else if (!RequireCompleteType(Loc, OrigT2, PDiag()) &&
IsDerivedFrom(UnqualT2, UnqualT1))
DerivedToBase = true;
else
@@ -2724,6 +2969,7 @@ Sema::PerformObjectArgumentInitialization(Expr *&From,
/// TryContextuallyConvertToBool - Attempt to contextually convert the
/// expression From to bool (C++0x [conv]p3).
ImplicitConversionSequence Sema::TryContextuallyConvertToBool(Expr *From) {
+ // FIXME: This is pretty broken.
return TryImplicitConversion(From, Context.BoolTy,
// FIXME: Are these flags correct?
/*SuppressUserConversions=*/false,
@@ -2744,6 +2990,27 @@ bool Sema::PerformContextuallyConvertToBool(Expr *&From) {
<< From->getType() << From->getSourceRange();
return true;
}
+
+/// TryContextuallyConvertToObjCId - Attempt to contextually convert the
+/// expression From to 'id'.
+ImplicitConversionSequence Sema::TryContextuallyConvertToObjCId(Expr *From) {
+ QualType Ty = Context.getObjCIdType();
+ return TryImplicitConversion(From, Ty,
+ // FIXME: Are these flags correct?
+ /*SuppressUserConversions=*/false,
+ /*AllowExplicit=*/true,
+ /*InOverloadResolution=*/false);
+}
+
+/// PerformContextuallyConvertToObjCId - Perform a contextual conversion
+/// of the expression From to 'id'.
+bool Sema::PerformContextuallyConvertToObjCId(Expr *&From) {
+ QualType Ty = Context.getObjCIdType();
+ ImplicitConversionSequence ICS = TryContextuallyConvertToObjCId(From);
+ if (!ICS.isBad())
+ return PerformImplicitConversion(From, Ty, ICS, AA_Converting);
+ return true;
+}
/// AddOverloadCandidate - Adds the given function to the set of
/// candidate functions, using the given function call arguments. If
@@ -3029,7 +3296,7 @@ Sema::AddMethodCandidate(CXXMethodDecl *Method, DeclAccessPair FoundDecl,
}
}
}
-
+
/// \brief Add a C++ member function template as a candidate to the candidate
/// set, using template argument deduction to produce an appropriate member
/// function template specialization.
@@ -3059,11 +3326,18 @@ Sema::AddMethodTemplateCandidate(FunctionTemplateDecl *MethodTmpl,
if (TemplateDeductionResult Result
= DeduceTemplateArguments(MethodTmpl, ExplicitTemplateArgs,
Args, NumArgs, Specialization, Info)) {
- // FIXME: Record what happened with template argument deduction, so
- // that we can give the user a beautiful diagnostic.
- (void)Result;
- return;
- }
+ CandidateSet.push_back(OverloadCandidate());
+ OverloadCandidate &Candidate = CandidateSet.back();
+ Candidate.FoundDecl = FoundDecl;
+ Candidate.Function = MethodTmpl->getTemplatedDecl();
+ Candidate.Viable = false;
+ Candidate.FailureKind = ovl_fail_bad_deduction;
+ Candidate.IsSurrogate = false;
+ Candidate.IgnoreObjectArgument = false;
+ Candidate.DeductionFailure = MakeDeductionFailureInfo(Context, Result,
+ Info);
+ return;
+ }
// Add the function template specialization produced by template argument
// deduction as a candidate.
@@ -3110,10 +3384,8 @@ Sema::AddTemplateOverloadCandidate(FunctionTemplateDecl *FunctionTemplate,
Candidate.FailureKind = ovl_fail_bad_deduction;
Candidate.IsSurrogate = false;
Candidate.IgnoreObjectArgument = false;
-
- // TODO: record more information about failed template arguments
- Candidate.DeductionFailure.Result = Result;
- Candidate.DeductionFailure.TemplateParameter = Info.Param.getOpaqueValue();
+ Candidate.DeductionFailure = MakeDeductionFailureInfo(Context, Result,
+ Info);
return;
}
@@ -3260,9 +3532,16 @@ Sema::AddTemplateConversionCandidate(FunctionTemplateDecl *FunctionTemplate,
if (TemplateDeductionResult Result
= DeduceTemplateArguments(FunctionTemplate, ToType,
Specialization, Info)) {
- // FIXME: Record what happened with template argument deduction, so
- // that we can give the user a beautiful diagnostic.
- (void)Result;
+ CandidateSet.push_back(OverloadCandidate());
+ OverloadCandidate &Candidate = CandidateSet.back();
+ Candidate.FoundDecl = FoundDecl;
+ Candidate.Function = FunctionTemplate->getTemplatedDecl();
+ Candidate.Viable = false;
+ Candidate.FailureKind = ovl_fail_bad_deduction;
+ Candidate.IsSurrogate = false;
+ Candidate.IgnoreObjectArgument = false;
+ Candidate.DeductionFailure = MakeDeductionFailureInfo(Context, Result,
+ Info);
return;
}
@@ -3504,6 +3783,10 @@ class BuiltinCandidateTypeSet {
/// used in the built-in candidates.
TypeSet EnumerationTypes;
+ /// \brief The set of vector types that will be used in the built-in
+ /// candidates.
+ TypeSet VectorTypes;
+
/// Sema - The semantic analysis instance where we are building the
/// candidate type set.
Sema &SemaRef;
@@ -3545,6 +3828,9 @@ public:
/// enumeration_end - Past the last enumeration type found;
iterator enumeration_end() { return EnumerationTypes.end(); }
+
+ iterator vector_begin() { return VectorTypes.begin(); }
+ iterator vector_end() { return VectorTypes.end(); }
};
/// AddPointerWithMoreQualifiedTypeVariants - Add the pointer type @p Ty to
@@ -3677,6 +3963,8 @@ BuiltinCandidateTypeSet::AddTypesConvertedFrom(QualType Ty,
return;
} else if (Ty->isEnumeralType()) {
EnumerationTypes.insert(Ty);
+ } else if (Ty->isVectorType()) {
+ VectorTypes.insert(Ty);
} else if (AllowUserConversions) {
if (const RecordType *TyRec = Ty->getAs<RecordType>()) {
if (SemaRef.RequireCompleteType(Loc, Ty, 0)) {
@@ -3841,21 +4129,14 @@ Sema::AddBuiltinOperatorCandidates(OverloadedOperatorKind Op,
VisibleTypeConversionsQuals += CollectVRQualifiers(Context, Args[ArgIdx]);
BuiltinCandidateTypeSet CandidateTypes(*this);
- if (Op == OO_Less || Op == OO_Greater || Op == OO_LessEqual ||
- Op == OO_GreaterEqual || Op == OO_EqualEqual || Op == OO_ExclaimEqual ||
- Op == OO_Plus || (Op == OO_Minus && NumArgs == 2) || Op == OO_Equal ||
- Op == OO_PlusEqual || Op == OO_MinusEqual || Op == OO_Subscript ||
- Op == OO_ArrowStar || Op == OO_PlusPlus || Op == OO_MinusMinus ||
- (Op == OO_Star && NumArgs == 1) || Op == OO_Conditional) {
- for (unsigned ArgIdx = 0; ArgIdx < NumArgs; ++ArgIdx)
- CandidateTypes.AddTypesConvertedFrom(Args[ArgIdx]->getType(),
- OpLoc,
- true,
- (Op == OO_Exclaim ||
- Op == OO_AmpAmp ||
- Op == OO_PipePipe),
- VisibleTypeConversionsQuals);
- }
+ for (unsigned ArgIdx = 0; ArgIdx < NumArgs; ++ArgIdx)
+ CandidateTypes.AddTypesConvertedFrom(Args[ArgIdx]->getType(),
+ OpLoc,
+ true,
+ (Op == OO_Exclaim ||
+ Op == OO_AmpAmp ||
+ Op == OO_PipePipe),
+ VisibleTypeConversionsQuals);
bool isComparison = false;
switch (Op) {
@@ -4019,6 +4300,14 @@ Sema::AddBuiltinOperatorCandidates(OverloadedOperatorKind Op,
QualType ArithTy = ArithmeticTypes[Arith];
AddBuiltinCandidate(ArithTy, &ArithTy, Args, 1, CandidateSet);
}
+
+ // Extension: We also add these operators for vector types.
+ for (BuiltinCandidateTypeSet::iterator Vec = CandidateTypes.vector_begin(),
+ VecEnd = CandidateTypes.vector_end();
+ Vec != VecEnd; ++Vec) {
+ QualType VecTy = *Vec;
+ AddBuiltinCandidate(VecTy, &VecTy, Args, 1, CandidateSet);
+ }
break;
case OO_Tilde:
@@ -4032,6 +4321,14 @@ Sema::AddBuiltinOperatorCandidates(OverloadedOperatorKind Op,
QualType IntTy = ArithmeticTypes[Int];
AddBuiltinCandidate(IntTy, &IntTy, Args, 1, CandidateSet);
}
+
+ // Extension: We also add this operator for vector types.
+ for (BuiltinCandidateTypeSet::iterator Vec = CandidateTypes.vector_begin(),
+ VecEnd = CandidateTypes.vector_end();
+ Vec != VecEnd; ++Vec) {
+ QualType VecTy = *Vec;
+ AddBuiltinCandidate(VecTy, &VecTy, Args, 1, CandidateSet);
+ }
break;
case OO_New:
@@ -4188,6 +4485,30 @@ Sema::AddBuiltinOperatorCandidates(OverloadedOperatorKind Op,
AddBuiltinCandidate(Result, LandR, Args, 2, CandidateSet);
}
}
+
+ // Extension: Add the binary operators ==, !=, <, <=, >=, >, *, /, and the
+ // conditional operator for vector types.
+ for (BuiltinCandidateTypeSet::iterator Vec1 = CandidateTypes.vector_begin(),
+ Vec1End = CandidateTypes.vector_end();
+ Vec1 != Vec1End; ++Vec1)
+ for (BuiltinCandidateTypeSet::iterator
+ Vec2 = CandidateTypes.vector_begin(),
+ Vec2End = CandidateTypes.vector_end();
+ Vec2 != Vec2End; ++Vec2) {
+ QualType LandR[2] = { *Vec1, *Vec2 };
+ QualType Result;
+ if (isComparison)
+ Result = Context.BoolTy;
+ else {
+ if ((*Vec1)->isExtVectorType() || !(*Vec2)->isExtVectorType())
+ Result = *Vec1;
+ else
+ Result = *Vec2;
+ }
+
+ AddBuiltinCandidate(Result, LandR, Args, 2, CandidateSet);
+ }
+
break;
case OO_Percent:
@@ -4243,7 +4564,8 @@ Sema::AddBuiltinOperatorCandidates(OverloadedOperatorKind Op,
MemPtr != MemPtrEnd; ++MemPtr)
AddBuiltinAssignmentOperatorCandidates(*this, *MemPtr, Args, 2,
CandidateSet);
- // Fall through.
+
+ // Fall through.
case OO_PlusEqual:
case OO_MinusEqual:
@@ -4318,6 +4640,30 @@ Sema::AddBuiltinOperatorCandidates(OverloadedOperatorKind Op,
}
}
}
+
+ // Extension: Add the binary operators =, +=, -=, *=, /= for vector types.
+ for (BuiltinCandidateTypeSet::iterator Vec1 = CandidateTypes.vector_begin(),
+ Vec1End = CandidateTypes.vector_end();
+ Vec1 != Vec1End; ++Vec1)
+ for (BuiltinCandidateTypeSet::iterator
+ Vec2 = CandidateTypes.vector_begin(),
+ Vec2End = CandidateTypes.vector_end();
+ Vec2 != Vec2End; ++Vec2) {
+ QualType ParamTypes[2];
+ ParamTypes[1] = *Vec2;
+ // Add this built-in operator as a candidate (VQ is empty).
+ ParamTypes[0] = Context.getLValueReferenceType(*Vec1);
+ AddBuiltinCandidate(ParamTypes[0], ParamTypes, Args, 2, CandidateSet,
+ /*IsAssigmentOperator=*/Op == OO_Equal);
+
+ // Add this built-in operator as a candidate (VQ is 'volatile').
+ if (VisibleTypeConversionsQuals.hasVolatile()) {
+ ParamTypes[0] = Context.getVolatileType(*Vec1);
+ ParamTypes[0] = Context.getLValueReferenceType(ParamTypes[0]);
+ AddBuiltinCandidate(ParamTypes[0], ParamTypes, Args, 2, CandidateSet,
+ /*IsAssigmentOperator=*/Op == OO_Equal);
+ }
+ }
break;
case OO_PercentEqual:
@@ -4413,7 +4759,7 @@ Sema::AddBuiltinOperatorCandidates(OverloadedOperatorKind Op,
ParamTypes[0] = ParamTypes[1];
ParamTypes[1] = *Ptr;
AddBuiltinCandidate(ResultTy, ParamTypes, Args, 2, CandidateSet);
- }
+ }
break;
case OO_ArrowStar:
@@ -4901,16 +5247,21 @@ void DiagnoseArityMismatch(Sema &S, OverloadCandidate *Cand,
unsigned MinParams = Fn->getMinRequiredArguments();
// at least / at most / exactly
+ // FIXME: variadic templates "at most" should account for parameter packs
unsigned mode, modeCount;
if (NumFormalArgs < MinParams) {
- assert(Cand->FailureKind == ovl_fail_too_few_arguments);
+ assert((Cand->FailureKind == ovl_fail_too_few_arguments) ||
+ (Cand->FailureKind == ovl_fail_bad_deduction &&
+ Cand->DeductionFailure.Result == Sema::TDK_TooFewArguments));
if (MinParams != FnTy->getNumArgs() || FnTy->isVariadic())
mode = 0; // "at least"
else
mode = 2; // "exactly"
modeCount = MinParams;
} else {
- assert(Cand->FailureKind == ovl_fail_too_many_arguments);
+ assert((Cand->FailureKind == ovl_fail_too_many_arguments) ||
+ (Cand->FailureKind == ovl_fail_bad_deduction &&
+ Cand->DeductionFailure.Result == Sema::TDK_TooManyArguments));
if (MinParams != FnTy->getNumArgs())
mode = 1; // "at most"
else
@@ -4922,7 +5273,8 @@ void DiagnoseArityMismatch(Sema &S, OverloadCandidate *Cand,
OverloadCandidateKind FnKind = ClassifyOverloadCandidate(S, Fn, Description);
S.Diag(Fn->getLocation(), diag::note_ovl_candidate_arity)
- << (unsigned) FnKind << Description << mode << modeCount << NumFormalArgs;
+ << (unsigned) FnKind << (Fn->getDescribedFunctionTemplate() != 0) << mode
+ << modeCount << NumFormalArgs;
}
/// Diagnose a failed template-argument deduction.
@@ -4930,34 +5282,86 @@ void DiagnoseBadDeduction(Sema &S, OverloadCandidate *Cand,
Expr **Args, unsigned NumArgs) {
FunctionDecl *Fn = Cand->Function; // pattern
- TemplateParameter Param = TemplateParameter::getFromOpaqueValue(
- Cand->DeductionFailure.TemplateParameter);
-
+ TemplateParameter Param = Cand->DeductionFailure.getTemplateParameter();
+ NamedDecl *ParamD;
+ (ParamD = Param.dyn_cast<TemplateTypeParmDecl*>()) ||
+ (ParamD = Param.dyn_cast<NonTypeTemplateParmDecl*>()) ||
+ (ParamD = Param.dyn_cast<TemplateTemplateParmDecl*>());
switch (Cand->DeductionFailure.Result) {
case Sema::TDK_Success:
llvm_unreachable("TDK_success while diagnosing bad deduction");
case Sema::TDK_Incomplete: {
- NamedDecl *ParamD;
- (ParamD = Param.dyn_cast<TemplateTypeParmDecl*>()) ||
- (ParamD = Param.dyn_cast<NonTypeTemplateParmDecl*>()) ||
- (ParamD = Param.dyn_cast<TemplateTemplateParmDecl*>());
assert(ParamD && "no parameter found for incomplete deduction result");
S.Diag(Fn->getLocation(), diag::note_ovl_candidate_incomplete_deduction)
<< ParamD->getDeclName();
return;
}
- // TODO: diagnose these individually, then kill off
- // note_ovl_candidate_bad_deduction, which is uselessly vague.
- case Sema::TDK_InstantiationDepth:
case Sema::TDK_Inconsistent:
- case Sema::TDK_InconsistentQuals:
- case Sema::TDK_SubstitutionFailure:
- case Sema::TDK_NonDeducedMismatch:
+ case Sema::TDK_InconsistentQuals: {
+ assert(ParamD && "no parameter found for inconsistent deduction result");
+ int which = 0;
+ if (isa<TemplateTypeParmDecl>(ParamD))
+ which = 0;
+ else if (isa<NonTypeTemplateParmDecl>(ParamD))
+ which = 1;
+ else {
+ which = 2;
+ }
+
+ S.Diag(Fn->getLocation(), diag::note_ovl_candidate_inconsistent_deduction)
+ << which << ParamD->getDeclName()
+ << *Cand->DeductionFailure.getFirstArg()
+ << *Cand->DeductionFailure.getSecondArg();
+ return;
+ }
+
+ case Sema::TDK_InvalidExplicitArguments:
+ assert(ParamD && "no parameter found for invalid explicit arguments");
+ if (ParamD->getDeclName())
+ S.Diag(Fn->getLocation(),
+ diag::note_ovl_candidate_explicit_arg_mismatch_named)
+ << ParamD->getDeclName();
+ else {
+ int index = 0;
+ if (TemplateTypeParmDecl *TTP = dyn_cast<TemplateTypeParmDecl>(ParamD))
+ index = TTP->getIndex();
+ else if (NonTypeTemplateParmDecl *NTTP
+ = dyn_cast<NonTypeTemplateParmDecl>(ParamD))
+ index = NTTP->getIndex();
+ else
+ index = cast<TemplateTemplateParmDecl>(ParamD)->getIndex();
+ S.Diag(Fn->getLocation(),
+ diag::note_ovl_candidate_explicit_arg_mismatch_unnamed)
+ << (index + 1);
+ }
+ return;
+
case Sema::TDK_TooManyArguments:
case Sema::TDK_TooFewArguments:
- case Sema::TDK_InvalidExplicitArguments:
+ DiagnoseArityMismatch(S, Cand, NumArgs);
+ return;
+
+ case Sema::TDK_InstantiationDepth:
+ S.Diag(Fn->getLocation(), diag::note_ovl_candidate_instantiation_depth);
+ return;
+
+ case Sema::TDK_SubstitutionFailure: {
+ std::string ArgString;
+ if (TemplateArgumentList *Args
+ = Cand->DeductionFailure.getTemplateArgumentList())
+ ArgString = S.getTemplateArgumentBindingsText(
+ Fn->getDescribedFunctionTemplate()->getTemplateParameters(),
+ *Args);
+ S.Diag(Fn->getLocation(), diag::note_ovl_candidate_substitution_failure)
+ << ArgString;
+ return;
+ }
+
+ // TODO: diagnose these individually, then kill off
+ // note_ovl_candidate_bad_deduction, which is uselessly vague.
+ case Sema::TDK_NonDeducedMismatch:
case Sema::TDK_FailedOverloadResolution:
S.Diag(Fn->getLocation(), diag::note_ovl_candidate_bad_deduction);
return;
@@ -5500,8 +5904,10 @@ Sema::ResolveAddressOfOverloadedFunction(Expr *From, QualType ToType,
assert(Result != MatchesCopy.end() && "no most-specialized template");
MarkDeclarationReferenced(From->getLocStart(), *Result);
FoundResult = Matches[Result - MatchesCopy.begin()].first;
- if (Complain)
+ if (Complain) {
CheckUnresolvedAccess(*this, OvlExpr, FoundResult);
+ DiagnoseUseOfDecl(FoundResult, OvlExpr->getNameLoc());
+ }
return cast<FunctionDecl>(*Result);
}
@@ -5521,8 +5927,10 @@ Sema::ResolveAddressOfOverloadedFunction(Expr *From, QualType ToType,
if (Matches.size() == 1) {
MarkDeclarationReferenced(From->getLocStart(), Matches[0].second);
FoundResult = Matches[0].first;
- if (Complain)
+ if (Complain) {
CheckUnresolvedAccess(*this, OvlExpr, Matches[0].first);
+ DiagnoseUseOfDecl(Matches[0].first, OvlExpr->getNameLoc());
+ }
return cast<FunctionDecl>(Matches[0].second);
}
@@ -5724,7 +6132,7 @@ BuildRecoveryCallExpr(Sema &SemaRef, Scope *S, Expr *Fn,
LookupResult R(SemaRef, ULE->getName(), ULE->getNameLoc(),
Sema::LookupOrdinaryName);
- if (SemaRef.DiagnoseEmptyLookup(S, SS, R))
+ if (SemaRef.DiagnoseEmptyLookup(S, SS, R, Sema::CTC_Expression))
return Destroy(SemaRef, Fn, Args, NumArgs);
assert(!R.empty() && "lookup results empty despite recovery");
@@ -5801,6 +6209,7 @@ Sema::BuildOverloadedCallExpr(Scope *S, Expr *Fn, UnresolvedLookupExpr *ULE,
case OR_Success: {
FunctionDecl *FDecl = Best->Function;
CheckUnresolvedLookupAccess(ULE, Best->FoundDecl);
+ DiagnoseUseOfDecl(Best->FoundDecl, ULE->getNameLoc());
Fn = FixOverloadedFunctionReference(Fn, Best->FoundDecl, FDecl);
return BuildResolvedCallExpr(Fn, FDecl, LParenLoc, Args, NumArgs, RParenLoc);
}
@@ -5885,9 +6294,8 @@ Sema::CreateOverloadedUnaryOp(SourceLocation OpLoc, unsigned OpcIn,
UnresolvedLookupExpr *Fn
= UnresolvedLookupExpr::Create(Context, /*Dependent*/ true, NamingClass,
0, SourceRange(), OpName, OpLoc,
- /*ADL*/ true, IsOverloaded(Fns));
- Fn->addDecls(Fns.begin(), Fns.end());
-
+ /*ADL*/ true, IsOverloaded(Fns),
+ Fns.begin(), Fns.end());
input.release();
return Owned(new (Context) CXXOperatorCallExpr(Context, Op, Fn,
&Args[0], NumArgs,
@@ -5945,6 +6353,8 @@ Sema::CreateOverloadedUnaryOp(SourceLocation OpLoc, unsigned OpcIn,
Input = (Expr *)input.get();
}
+ DiagnoseUseOfDecl(Best->FoundDecl, OpLoc);
+
// Determine the result type
QualType ResultTy = FnDecl->getResultType().getNonReferenceType();
@@ -5958,7 +6368,7 @@ Sema::CreateOverloadedUnaryOp(SourceLocation OpLoc, unsigned OpcIn,
ExprOwningPtr<CallExpr> TheCall(this,
new (Context) CXXOperatorCallExpr(Context, Op, FnExpr,
Args, NumArgs, ResultTy, OpLoc));
-
+
if (CheckCallReturnType(FnDecl->getResultType(), OpLoc, TheCall.get(),
FnDecl))
return ExprError();
@@ -6056,9 +6466,8 @@ Sema::CreateOverloadedBinOp(SourceLocation OpLoc,
UnresolvedLookupExpr *Fn
= UnresolvedLookupExpr::Create(Context, /*Dependent*/ true, NamingClass,
0, SourceRange(), OpName, OpLoc,
- /*ADL*/ true, IsOverloaded(Fns));
-
- Fn->addDecls(Fns.begin(), Fns.end());
+ /*ADL*/ true, IsOverloaded(Fns),
+ Fns.begin(), Fns.end());
return Owned(new (Context) CXXOperatorCallExpr(Context, Op, Fn,
Args, 2,
Context.DependentTy,
@@ -6150,6 +6559,8 @@ Sema::CreateOverloadedBinOp(SourceLocation OpLoc,
Args[1] = RHS = Arg1.takeAs<Expr>();
}
+ DiagnoseUseOfDecl(Best->FoundDecl, OpLoc);
+
// Determine the result type
QualType ResultTy
= FnDecl->getType()->getAs<FunctionType>()->getResultType();
@@ -6252,7 +6663,9 @@ Sema::CreateOverloadedArraySubscriptExpr(SourceLocation LLoc,
UnresolvedLookupExpr *Fn
= UnresolvedLookupExpr::Create(Context, /*Dependent*/ true, NamingClass,
0, SourceRange(), OpName, LLoc,
- /*ADL*/ true, /*Overloaded*/ false);
+ /*ADL*/ true, /*Overloaded*/ false,
+ UnresolvedSetIterator(),
+ UnresolvedSetIterator());
// Can't add any actual overloads yet
Base.release();
@@ -6286,6 +6699,7 @@ Sema::CreateOverloadedArraySubscriptExpr(SourceLocation LLoc,
// operator.
CheckMemberOperatorAccess(LLoc, Args[0], Args[1], Best->FoundDecl);
+ DiagnoseUseOfDecl(Best->FoundDecl, LLoc);
// Convert the arguments.
CXXMethodDecl *Method = cast<CXXMethodDecl>(FnDecl);
@@ -6452,6 +6866,7 @@ Sema::BuildCallToMemberFunction(Scope *S, Expr *MemExprE,
Method = cast<CXXMethodDecl>(Best->Function);
FoundDecl = Best->FoundDecl;
CheckUnresolvedMemberAccess(UnresExpr, Best->FoundDecl);
+ DiagnoseUseOfDecl(Best->FoundDecl, UnresExpr->getNameLoc());
break;
case OR_No_Viable_Function:
@@ -6661,6 +7076,7 @@ Sema::BuildCallToObjectOfClassType(Scope *S, Expr *Object,
Best->Conversions[0].UserDefined.ConversionFunction);
CheckMemberOperatorAccess(LParenLoc, Object, 0, Best->FoundDecl);
+ DiagnoseUseOfDecl(Best->FoundDecl, LParenLoc);
// We selected one of the surrogate functions that converts the
// object parameter to a function pointer. Perform the conversion
@@ -6677,6 +7093,7 @@ Sema::BuildCallToObjectOfClassType(Scope *S, Expr *Object,
}
CheckMemberOperatorAccess(LParenLoc, Object, 0, Best->FoundDecl);
+ DiagnoseUseOfDecl(Best->FoundDecl, LParenLoc);
// We found an overloaded operator(). Build a CXXOperatorCallExpr
// that calls this method, using Object for the implicit object
@@ -6767,7 +7184,7 @@ Sema::BuildCallToObjectOfClassType(Scope *S, Expr *Object,
// Promote the arguments (C99 6.5.2.2p7).
for (unsigned i = NumArgsInProto; i != NumArgs; i++) {
Expr *Arg = Args[i];
- IsError |= DefaultVariadicArgumentPromotion(Arg, VariadicMethod);
+ IsError |= DefaultVariadicArgumentPromotion(Arg, VariadicMethod, 0);
TheCall->setArg(i + 1, Arg);
}
}
@@ -6847,6 +7264,7 @@ Sema::BuildOverloadedArrowExpr(Scope *S, ExprArg BaseIn, SourceLocation OpLoc) {
}
CheckMemberOperatorAccess(OpLoc, Base, 0, Best->FoundDecl);
+ DiagnoseUseOfDecl(Best->FoundDecl, OpLoc);
// Convert the object parameter.
CXXMethodDecl *Method = cast<CXXMethodDecl>(Best->Function);
diff --git a/lib/Sema/SemaOverload.h b/lib/Sema/SemaOverload.h
index 5e611113083f..eb4fc6581796 100644
--- a/lib/Sema/SemaOverload.h
+++ b/lib/Sema/SemaOverload.h
@@ -16,7 +16,9 @@
#define LLVM_CLANG_SEMA_OVERLOAD_H
#include "clang/AST/Decl.h"
+#include "clang/AST/DeclTemplate.h"
#include "clang/AST/Expr.h"
+#include "clang/AST/TemplateBase.h"
#include "clang/AST/Type.h"
#include "clang/AST/UnresolvedSet.h"
#include "llvm/ADT/SmallPtrSet.h"
@@ -60,6 +62,8 @@ namespace clang {
ICK_Boolean_Conversion, ///< Boolean conversions (C++ 4.12)
ICK_Compatible_Conversion, ///< Conversions between compatible types in C99
ICK_Derived_To_Base, ///< Derived-to-base (C++ [over.best.ics])
+ ICK_Vector_Conversion, ///< Vector conversions
+ ICK_Vector_Splat, ///< A vector splat from an arithmetic type
ICK_Complex_Real, ///< Complex-real conversions (C99 6.3.1.7)
ICK_Num_Conversion_Kinds ///< The number of conversion kinds
};
@@ -173,6 +177,12 @@ namespace clang {
}
void setAsIdentityConversion();
+
+ bool isIdentityConversion() const {
+ return First == ICK_Identity && Second == ICK_Identity &&
+ Third == ICK_Identity;
+ }
+
ImplicitConversionRank getRank() const;
bool isPointerConversionToBool() const;
bool isPointerConversionToVoidPointer(ASTContext& Context) const;
@@ -529,8 +539,28 @@ namespace clang {
// A Sema::TemplateDeductionResult.
unsigned Result;
- // A TemplateParameter.
- void *TemplateParameter;
+ /// \brief Opaque pointer containing additional data about
+ /// this deduction failure.
+ void *Data;
+
+ /// \brief Retrieve the template parameter this deduction failure
+ /// refers to, if any.
+ TemplateParameter getTemplateParameter();
+
+ /// \brief Retrieve the template argument list associated with this
+ /// deduction failure, if any.
+ TemplateArgumentList *getTemplateArgumentList();
+
+ /// \brief Return the first template argument this deduction failure
+ /// refers to, if any.
+ const TemplateArgument *getFirstArg();
+
+ /// \brief Return the second template argument this deduction failure
+ /// refers to, if any.
+ const TemplateArgument *getSecondArg();
+
+ /// \brief Free any memory associated with this deduction failure.
+ void Destroy();
};
union {
@@ -562,6 +592,10 @@ namespace clang {
llvm::SmallPtrSet<Decl *, 16> Functions;
SourceLocation Loc;
+
+ OverloadCandidateSet(const OverloadCandidateSet &);
+ OverloadCandidateSet &operator=(const OverloadCandidateSet &);
+
public:
OverloadCandidateSet(SourceLocation Loc) : Loc(Loc) {}
@@ -574,10 +608,9 @@ namespace clang {
}
/// \brief Clear out all of the candidates.
- void clear() {
- inherited::clear();
- Functions.clear();
- }
+ void clear();
+
+ ~OverloadCandidateSet() { clear(); }
};
} // end namespace clang
diff --git a/lib/Sema/SemaStmt.cpp b/lib/Sema/SemaStmt.cpp
index 9d6132d050c6..875b160d712f 100644
--- a/lib/Sema/SemaStmt.cpp
+++ b/lib/Sema/SemaStmt.cpp
@@ -30,7 +30,7 @@ using namespace clang;
Sema::OwningStmtResult Sema::ActOnExprStmt(FullExprArg expr) {
Expr *E = expr->takeAs<Expr>();
assert(E && "ActOnExprStmt(): missing expression");
- if (E->getType()->isObjCInterfaceType()) {
+ if (E->getType()->isObjCObjectType()) {
if (LangOpts.ObjCNonFragileABI)
Diag(E->getLocEnd(), diag::err_indirection_requires_nonfragile_object)
<< E->getType();
@@ -280,7 +280,7 @@ Sema::ActOnIfStmt(SourceLocation IfLoc, FullExprArg CondVal, DeclPtrTy CondVar,
VarDecl *ConditionVar = 0;
if (CondVar.get()) {
ConditionVar = CondVar.getAs<VarDecl>();
- CondResult = CheckConditionVariable(ConditionVar);
+ CondResult = CheckConditionVariable(ConditionVar, IfLoc, true);
if (CondResult.isInvalid())
return StmtError();
}
@@ -288,11 +288,6 @@ Sema::ActOnIfStmt(SourceLocation IfLoc, FullExprArg CondVal, DeclPtrTy CondVar,
if (!ConditionExpr)
return StmtError();
- if (CheckBooleanCondition(ConditionExpr, IfLoc)) {
- CondResult = ConditionExpr;
- return StmtError();
- }
-
Stmt *thenStmt = ThenVal.takeAs<Stmt>();
DiagnoseUnusedExprResult(thenStmt);
@@ -313,23 +308,6 @@ Sema::ActOnIfStmt(SourceLocation IfLoc, FullExprArg CondVal, DeclPtrTy CondVar,
thenStmt, ElseLoc, elseStmt));
}
-Action::OwningStmtResult
-Sema::ActOnStartOfSwitchStmt(FullExprArg cond, DeclPtrTy CondVar) {
- OwningExprResult CondResult(cond.release());
-
- VarDecl *ConditionVar = 0;
- if (CondVar.get()) {
- ConditionVar = CondVar.getAs<VarDecl>();
- CondResult = CheckConditionVariable(ConditionVar);
- if (CondResult.isInvalid())
- return StmtError();
- }
- SwitchStmt *SS = new (Context) SwitchStmt(ConditionVar,
- CondResult.takeAs<Expr>());
- getSwitchStack().push_back(SS);
- return Owned(SS);
-}
-
/// ConvertIntegerToTypeWarnOnOverflow - Convert the specified APInt to have
/// the specified width and sign. If an overflow occurs, detect it and emit
/// the specified diagnostic.
@@ -540,14 +518,36 @@ static bool CheckCXXSwitchCondition(Sema &S, SourceLocation SwitchLoc,
return false;
}
-/// ActOnSwitchBodyError - This is called if there is an error parsing the
-/// body of the switch stmt instead of ActOnFinishSwitchStmt.
-void Sema::ActOnSwitchBodyError(SourceLocation SwitchLoc, StmtArg Switch,
- StmtArg Body) {
- // Keep the switch stack balanced.
- assert(getSwitchStack().back() == (SwitchStmt*)Switch.get() &&
- "switch stack missing push/pop!");
- getSwitchStack().pop_back();
+Action::OwningStmtResult
+Sema::ActOnStartOfSwitchStmt(SourceLocation SwitchLoc, ExprArg Cond,
+ DeclPtrTy CondVar) {
+ VarDecl *ConditionVar = 0;
+ if (CondVar.get()) {
+ ConditionVar = CondVar.getAs<VarDecl>();
+ OwningExprResult CondE = CheckConditionVariable(ConditionVar, SourceLocation(), false);
+ if (CondE.isInvalid())
+ return StmtError();
+
+ Cond = move(CondE);
+ }
+
+ Expr *CondExpr = Cond.takeAs<Expr>();
+ if (!CondExpr)
+ return StmtError();
+
+ if (getLangOptions().CPlusPlus &&
+ CheckCXXSwitchCondition(*this, SwitchLoc, CondExpr))
+ return StmtError();
+
+ if (!CondVar.get()) {
+ CondExpr = MaybeCreateCXXExprWithTemporaries(CondExpr);
+ if (!CondExpr)
+ return StmtError();
+ }
+
+ SwitchStmt *SS = new (Context) SwitchStmt(ConditionVar, CondExpr);
+ getSwitchStack().push_back(SS);
+ return Owned(SS);
}
Action::OwningStmtResult
@@ -567,13 +567,10 @@ Sema::ActOnFinishSwitchStmt(SourceLocation SwitchLoc, StmtArg Switch,
}
Expr *CondExpr = SS->getCond();
+ Expr *CondExprBeforePromotion = CondExpr;
QualType CondTypeBeforePromotion =
GetTypeBeforeIntegralPromotion(CondExpr);
- if (getLangOptions().CPlusPlus &&
- CheckCXXSwitchCondition(*this, SwitchLoc, CondExpr))
- return StmtError();
-
// C99 6.8.4.2p5 - Integer promotions are performed on the controlling expr.
UsualUnaryConversions(CondExpr);
QualType CondType = CondExpr->getType();
@@ -679,16 +676,38 @@ Sema::ActOnFinishSwitchStmt(SourceLocation SwitchLoc, StmtArg Switch,
}
if (!HasDependentValue) {
+ // If we don't have a default statement, check whether the
+ // condition is constant.
+ llvm::APSInt ConstantCondValue;
+ bool HasConstantCond = false;
+ bool ShouldCheckConstantCond = false;
+ if (!HasDependentValue && !TheDefaultStmt) {
+ Expr::EvalResult Result;
+ HasConstantCond = CondExprBeforePromotion->Evaluate(Result, Context);
+ if (HasConstantCond) {
+ assert(Result.Val.isInt() && "switch condition evaluated to non-int");
+ ConstantCondValue = Result.Val.getInt();
+ ShouldCheckConstantCond = true;
+
+ assert(ConstantCondValue.getBitWidth() == CondWidth &&
+ ConstantCondValue.isSigned() == CondIsSigned);
+ }
+ }
+
// Sort all the scalar case values so we can easily detect duplicates.
std::stable_sort(CaseVals.begin(), CaseVals.end(), CmpCaseVals);
if (!CaseVals.empty()) {
- for (unsigned i = 0, e = CaseVals.size()-1; i != e; ++i) {
- if (CaseVals[i].first == CaseVals[i+1].first) {
+ for (unsigned i = 0, e = CaseVals.size(); i != e; ++i) {
+ if (ShouldCheckConstantCond &&
+ CaseVals[i].first == ConstantCondValue)
+ ShouldCheckConstantCond = false;
+
+ if (i != 0 && CaseVals[i].first == CaseVals[i-1].first) {
// If we have a duplicate, report it.
- Diag(CaseVals[i+1].second->getLHS()->getLocStart(),
- diag::err_duplicate_case) << CaseVals[i].first.toString(10);
Diag(CaseVals[i].second->getLHS()->getLocStart(),
+ diag::err_duplicate_case) << CaseVals[i].first.toString(10);
+ Diag(CaseVals[i-1].second->getLHS()->getLocStart(),
diag::note_duplicate_case_prev);
// FIXME: We really want to remove the bogus case stmt from the
// substmt, but we have no way to do this right now.
@@ -707,6 +726,7 @@ Sema::ActOnFinishSwitchStmt(SourceLocation SwitchLoc, StmtArg Switch,
// Scan the ranges, computing the high values and removing empty ranges.
std::vector<llvm::APSInt> HiVals;
for (unsigned i = 0, e = CaseRanges.size(); i != e; ++i) {
+ llvm::APSInt &LoVal = CaseRanges[i].first;
CaseStmt *CR = CaseRanges[i].second;
Expr *Hi = CR->getRHS();
llvm::APSInt HiVal = Hi->EvaluateAsInt(Context);
@@ -722,7 +742,7 @@ Sema::ActOnFinishSwitchStmt(SourceLocation SwitchLoc, StmtArg Switch,
CR->setRHS(Hi);
// If the low value is bigger than the high value, the case is empty.
- if (CaseRanges[i].first > HiVal) {
+ if (LoVal > HiVal) {
Diag(CR->getLHS()->getLocStart(), diag::warn_case_empty_range)
<< SourceRange(CR->getLHS()->getLocStart(),
CR->getRHS()->getLocEnd());
@@ -730,6 +750,12 @@ Sema::ActOnFinishSwitchStmt(SourceLocation SwitchLoc, StmtArg Switch,
--i, --e;
continue;
}
+
+ if (ShouldCheckConstantCond &&
+ LoVal <= ConstantCondValue &&
+ ConstantCondValue <= HiVal)
+ ShouldCheckConstantCond = false;
+
HiVals.push_back(HiVal);
}
@@ -783,18 +809,32 @@ Sema::ActOnFinishSwitchStmt(SourceLocation SwitchLoc, StmtArg Switch,
}
}
- // Check to see if switch is over an Enum and handles all of its
- // values
+ // Complain if we have a constant condition and we didn't find a match.
+ if (!CaseListIsErroneous && ShouldCheckConstantCond) {
+ // TODO: it would be nice if we printed enums as enums, chars as
+ // chars, etc.
+ Diag(CondExpr->getExprLoc(), diag::warn_missing_case_for_condition)
+ << ConstantCondValue.toString(10)
+ << CondExpr->getSourceRange();
+ }
+
+ // Check to see if switch is over an Enum and handles all of its
+ // values. We don't need to do this if there's a default
+ // statement or if we have a constant condition.
+ //
+ // TODO: we might want to check whether case values are out of the
+ // enum even if we don't want to check whether all cases are handled.
const EnumType* ET = CondTypeBeforePromotion->getAs<EnumType>();
// If switch has default case, then ignore it.
- if (!CaseListIsErroneous && !TheDefaultStmt && ET) {
+ if (!CaseListIsErroneous && !TheDefaultStmt && !HasConstantCond && ET) {
const EnumDecl *ED = ET->getDecl();
typedef llvm::SmallVector<std::pair<llvm::APSInt, EnumConstantDecl*>, 64> EnumValsTy;
EnumValsTy EnumVals;
- // Gather all enum values, set their type and sort them, allowing easier comparison
- // with CaseVals.
- for (EnumDecl::enumerator_iterator EDI = ED->enumerator_begin(); EDI != ED->enumerator_end(); EDI++) {
+ // Gather all enum values, set their type and sort them,
+ // allowing easier comparison with CaseVals.
+ for (EnumDecl::enumerator_iterator EDI = ED->enumerator_begin();
+ EDI != ED->enumerator_end(); EDI++) {
llvm::APSInt Val = (*EDI)->getInitVal();
if(Val.getBitWidth() < CondWidth)
Val.extend(CondWidth);
@@ -802,30 +842,36 @@ Sema::ActOnFinishSwitchStmt(SourceLocation SwitchLoc, StmtArg Switch,
EnumVals.push_back(std::make_pair(Val, (*EDI)));
}
std::stable_sort(EnumVals.begin(), EnumVals.end(), CmpEnumVals);
- EnumValsTy::iterator EIend = std::unique(EnumVals.begin(), EnumVals.end(), EqEnumVals);
+ EnumValsTy::iterator EIend =
+ std::unique(EnumVals.begin(), EnumVals.end(), EqEnumVals);
// See which case values aren't in enum
EnumValsTy::const_iterator EI = EnumVals.begin();
- for (CaseValsTy::const_iterator CI = CaseVals.begin(); CI != CaseVals.end(); CI++) {
+ for (CaseValsTy::const_iterator CI = CaseVals.begin();
+ CI != CaseVals.end(); CI++) {
while (EI != EIend && EI->first < CI->first)
EI++;
if (EI == EIend || EI->first > CI->first)
- Diag(CI->second->getLHS()->getExprLoc(), diag::not_in_enum) << ED->getDeclName();
+ Diag(CI->second->getLHS()->getExprLoc(), diag::warn_not_in_enum)
+ << ED->getDeclName();
}
// See which of case ranges aren't in enum
EI = EnumVals.begin();
- for (CaseRangesTy::const_iterator RI = CaseRanges.begin(); RI != CaseRanges.end() && EI != EIend; RI++) {
+ for (CaseRangesTy::const_iterator RI = CaseRanges.begin();
+ RI != CaseRanges.end() && EI != EIend; RI++) {
while (EI != EIend && EI->first < RI->first)
EI++;
if (EI == EIend || EI->first != RI->first) {
- Diag(RI->second->getLHS()->getExprLoc(), diag::not_in_enum) << ED->getDeclName();
+ Diag(RI->second->getLHS()->getExprLoc(), diag::warn_not_in_enum)
+ << ED->getDeclName();
}
llvm::APSInt Hi = RI->second->getRHS()->EvaluateAsInt(Context);
while (EI != EIend && EI->first < Hi)
EI++;
if (EI == EIend || EI->first != Hi)
- Diag(RI->second->getRHS()->getExprLoc(), diag::not_in_enum) << ED->getDeclName();
+ Diag(RI->second->getRHS()->getExprLoc(), diag::warn_not_in_enum)
+ << ED->getDeclName();
}
//Check which enum vals aren't in switch
CaseValsTy::const_iterator CI = CaseVals.begin();
@@ -848,7 +894,8 @@ Sema::ActOnFinishSwitchStmt(SourceLocation SwitchLoc, StmtArg Switch,
}
if (RI == CaseRanges.end() || EI->first < RI->first)
- Diag(CondExpr->getExprLoc(), diag::warn_missing_cases) << EI->second->getDeclName();
+ Diag(CondExpr->getExprLoc(), diag::warn_missing_cases)
+ << EI->second->getDeclName();
}
}
}
@@ -870,7 +917,7 @@ Sema::ActOnWhileStmt(SourceLocation WhileLoc, FullExprArg Cond,
VarDecl *ConditionVar = 0;
if (CondVar.get()) {
ConditionVar = CondVar.getAs<VarDecl>();
- CondResult = CheckConditionVariable(ConditionVar);
+ CondResult = CheckConditionVariable(ConditionVar, WhileLoc, true);
if (CondResult.isInvalid())
return StmtError();
}
@@ -878,11 +925,6 @@ Sema::ActOnWhileStmt(SourceLocation WhileLoc, FullExprArg Cond,
if (!ConditionExpr)
return StmtError();
- if (CheckBooleanCondition(ConditionExpr, WhileLoc)) {
- CondResult = ConditionExpr;
- return StmtError();
- }
-
Stmt *bodyStmt = Body.takeAs<Stmt>();
DiagnoseUnusedExprResult(bodyStmt);
@@ -903,6 +945,10 @@ Sema::ActOnDoStmt(SourceLocation DoLoc, StmtArg Body,
return StmtError();
}
+ condExpr = MaybeCreateCXXExprWithTemporaries(condExpr);
+ if (!condExpr)
+ return StmtError();
+
Stmt *bodyStmt = Body.takeAs<Stmt>();
DiagnoseUnusedExprResult(bodyStmt);
@@ -939,17 +985,11 @@ Sema::ActOnForStmt(SourceLocation ForLoc, SourceLocation LParenLoc,
VarDecl *ConditionVar = 0;
if (secondVar.get()) {
ConditionVar = secondVar.getAs<VarDecl>();
- SecondResult = CheckConditionVariable(ConditionVar);
+ SecondResult = CheckConditionVariable(ConditionVar, ForLoc, true);
if (SecondResult.isInvalid())
return StmtError();
}
- Expr *Second = SecondResult.takeAs<Expr>();
- if (Second && CheckBooleanCondition(Second, ForLoc)) {
- SecondResult = Second;
- return StmtError();
- }
-
Expr *Third = third.release().takeAs<Expr>();
Stmt *Body = static_cast<Stmt*>(body.get());
@@ -959,7 +999,8 @@ Sema::ActOnForStmt(SourceLocation ForLoc, SourceLocation LParenLoc,
first.release();
body.release();
- return Owned(new (Context) ForStmt(First, Second, ConditionVar, Third, Body,
+ return Owned(new (Context) ForStmt(First, SecondResult.takeAs<Expr>(),
+ ConditionVar, Third, Body,
ForLoc, LParenLoc, RParenLoc));
}
@@ -1068,6 +1109,45 @@ Sema::ActOnBreakStmt(SourceLocation BreakLoc, Scope *CurScope) {
return Owned(new (Context) BreakStmt(BreakLoc));
}
+/// \brief Determine whether a return statement is a candidate for the named
+/// return value optimization (C++0x 12.8p34, bullet 1).
+///
+/// \param Ctx The context in which the return expression and type occur.
+///
+/// \param RetType The return type of the function or block.
+///
+/// \param RetExpr The expression being returned from the function or block.
+///
+/// \returns The NRVO candidate variable, if the return statement may use the
+/// NRVO, or NULL if there is no such candidate.
+static const VarDecl *getNRVOCandidate(ASTContext &Ctx, QualType RetType,
+ Expr *RetExpr) {
+ QualType ExprType = RetExpr->getType();
+ // - in a return statement in a function with ...
+ // ... a class return type ...
+ if (!RetType->isRecordType())
+ return 0;
+ // ... the same cv-unqualified type as the function return type ...
+ if (!Ctx.hasSameUnqualifiedType(RetType, ExprType))
+ return 0;
+ // ... the expression is the name of a non-volatile automatic object ...
+ // We ignore parentheses here.
+ // FIXME: Is this compliant? (Everyone else does it)
+ const DeclRefExpr *DR = dyn_cast<DeclRefExpr>(RetExpr->IgnoreParens());
+ if (!DR)
+ return 0;
+ const VarDecl *VD = dyn_cast<VarDecl>(DR->getDecl());
+ if (!VD)
+ return 0;
+
+ if (VD->getKind() == Decl::Var && VD->hasLocalStorage() &&
+ !VD->getType()->isReferenceType() && !VD->hasAttr<BlocksAttr>() &&
+ !VD->getType().isVolatileQualified())
+ return VD;
+
+ return 0;
+}
+
/// ActOnBlockReturnStmt - Utility routine to figure out block's return type.
///
Action::OwningStmtResult
@@ -1102,68 +1182,58 @@ Sema::ActOnBlockReturnStmt(SourceLocation ReturnLoc, Expr *RetValExp) {
// Otherwise, verify that this result type matches the previous one. We are
// pickier with blocks than for normal functions because we don't have GCC
// compatibility to worry about here.
+ ReturnStmt *Result = 0;
if (CurBlock->ReturnType->isVoidType()) {
if (RetValExp) {
Diag(ReturnLoc, diag::err_return_block_has_expr);
RetValExp->Destroy(Context);
RetValExp = 0;
}
- return Owned(new (Context) ReturnStmt(ReturnLoc, RetValExp));
- }
-
- if (!RetValExp)
+ Result = new (Context) ReturnStmt(ReturnLoc, RetValExp, 0);
+ } else if (!RetValExp) {
return StmtError(Diag(ReturnLoc, diag::err_block_return_missing_expr));
+ } else {
+ const VarDecl *NRVOCandidate = 0;
+
+ if (!FnRetType->isDependentType() && !RetValExp->isTypeDependent()) {
+ // we have a non-void block with an expression, continue checking
+
+ // C99 6.8.6.4p3(136): The return statement is not an assignment. The
+ // overlap restriction of subclause 6.5.16.1 does not apply to the case of
+ // function return.
+
+ // In C++ the return statement is handled via a copy initialization.
+ // the C version of which boils down to CheckSingleAssignmentConstraints.
+ NRVOCandidate = getNRVOCandidate(Context, FnRetType, RetValExp);
+ OwningExprResult Res = PerformCopyInitialization(
+ InitializedEntity::InitializeResult(ReturnLoc,
+ FnRetType,
+ NRVOCandidate != 0),
+ SourceLocation(),
+ Owned(RetValExp));
+ if (Res.isInvalid()) {
+ // FIXME: Cleanup temporaries here, anyway?
+ return StmtError();
+ }
+
+ if (RetValExp)
+ RetValExp = MaybeCreateCXXExprWithTemporaries(RetValExp);
- if (!FnRetType->isDependentType() && !RetValExp->isTypeDependent()) {
- // we have a non-void block with an expression, continue checking
-
- // C99 6.8.6.4p3(136): The return statement is not an assignment. The
- // overlap restriction of subclause 6.5.16.1 does not apply to the case of
- // function return.
-
- // In C++ the return statement is handled via a copy initialization.
- // the C version of which boils down to CheckSingleAssignmentConstraints.
- OwningExprResult Res = PerformCopyInitialization(
- InitializedEntity::InitializeResult(ReturnLoc,
- FnRetType),
- SourceLocation(),
- Owned(RetValExp));
- if (Res.isInvalid()) {
- // FIXME: Cleanup temporaries here, anyway?
- return StmtError();
+ RetValExp = Res.takeAs<Expr>();
+ if (RetValExp)
+ CheckReturnStackAddr(RetValExp, FnRetType, ReturnLoc);
}
- RetValExp = Res.takeAs<Expr>();
- if (RetValExp)
- CheckReturnStackAddr(RetValExp, FnRetType, ReturnLoc);
+ Result = new (Context) ReturnStmt(ReturnLoc, RetValExp, NRVOCandidate);
}
- return Owned(new (Context) ReturnStmt(ReturnLoc, RetValExp));
-}
-
-/// IsReturnCopyElidable - Whether returning @p RetExpr from a function that
-/// returns a @p RetType fulfills the criteria for copy elision (C++0x 12.8p15).
-static bool IsReturnCopyElidable(ASTContext &Ctx, QualType RetType,
- Expr *RetExpr) {
- QualType ExprType = RetExpr->getType();
- // - in a return statement in a function with ...
- // ... a class return type ...
- if (!RetType->isRecordType())
- return false;
- // ... the same cv-unqualified type as the function return type ...
- if (!Ctx.hasSameUnqualifiedType(RetType, ExprType))
- return false;
- // ... the expression is the name of a non-volatile automatic object ...
- // We ignore parentheses here.
- // FIXME: Is this compliant?
- const DeclRefExpr *DR = dyn_cast<DeclRefExpr>(RetExpr->IgnoreParens());
- if (!DR)
- return false;
- const VarDecl *VD = dyn_cast<VarDecl>(DR->getDecl());
- if (!VD)
- return false;
- return VD->hasLocalStorage() && !VD->getType()->isReferenceType()
- && !VD->getType().isVolatileQualified();
+ // If we need to check for the named return value optimization, save the
+ // return statement in our scope for later processing.
+ if (getLangOptions().CPlusPlus && FnRetType->isRecordType() &&
+ !CurContext->isDependentContext())
+ FunctionScopes.back()->Returns.push_back(Result);
+
+ return Owned(Result);
}
Action::OwningStmtResult
@@ -1184,6 +1254,7 @@ Sema::ActOnReturnStmt(SourceLocation ReturnLoc, ExprArg rex) {
else // If we don't have a function/method context, bail.
return StmtError();
+ ReturnStmt *Result = 0;
if (FnRetType->isVoidType()) {
if (RetValExp && !RetValExp->isTypeDependent()) {
// C99 6.8.6.4p1 (ext_ since GCC warns)
@@ -1202,10 +1273,9 @@ Sema::ActOnReturnStmt(SourceLocation ReturnLoc, ExprArg rex) {
RetValExp = MaybeCreateCXXExprWithTemporaries(RetValExp);
}
- return Owned(new (Context) ReturnStmt(ReturnLoc, RetValExp));
- }
-
- if (!RetValExp && !FnRetType->isDependentType()) {
+
+ Result = new (Context) ReturnStmt(ReturnLoc, RetValExp, 0);
+ } else if (!RetValExp && !FnRetType->isDependentType()) {
unsigned DiagID = diag::warn_return_missing_expr; // C90 6.6.6.4p4
// C99 6.8.6.4p1 (ext_ since GCC warns)
if (getLangOptions().C99) DiagID = diag::ext_return_missing_expr;
@@ -1214,54 +1284,47 @@ Sema::ActOnReturnStmt(SourceLocation ReturnLoc, ExprArg rex) {
Diag(ReturnLoc, DiagID) << FD->getIdentifier() << 0/*fn*/;
else
Diag(ReturnLoc, DiagID) << getCurMethodDecl()->getDeclName() << 1/*meth*/;
- return Owned(new (Context) ReturnStmt(ReturnLoc, (Expr*)0));
- }
+ Result = new (Context) ReturnStmt(ReturnLoc);
+ } else {
+ const VarDecl *NRVOCandidate = 0;
+ if (!FnRetType->isDependentType() && !RetValExp->isTypeDependent()) {
+ // we have a non-void function with an expression, continue checking
+
+ // C99 6.8.6.4p3(136): The return statement is not an assignment. The
+ // overlap restriction of subclause 6.5.16.1 does not apply to the case of
+ // function return.
+
+ // In C++ the return statement is handled via a copy initialization.
+ // the C version of which boils down to CheckSingleAssignmentConstraints.
+ NRVOCandidate = getNRVOCandidate(Context, FnRetType, RetValExp);
+ OwningExprResult Res = PerformCopyInitialization(
+ InitializedEntity::InitializeResult(ReturnLoc,
+ FnRetType,
+ NRVOCandidate != 0),
+ SourceLocation(),
+ Owned(RetValExp));
+ if (Res.isInvalid()) {
+ // FIXME: Cleanup temporaries here, anyway?
+ return StmtError();
+ }
- if (!FnRetType->isDependentType() && !RetValExp->isTypeDependent()) {
- // we have a non-void function with an expression, continue checking
-
- // C99 6.8.6.4p3(136): The return statement is not an assignment. The
- // overlap restriction of subclause 6.5.16.1 does not apply to the case of
- // function return.
-
- // C++0x 12.8p15: When certain criteria are met, an implementation is
- // allowed to omit the copy construction of a class object, [...]
- // - in a return statement in a function with a class return type, when
- // the expression is the name of a non-volatile automatic object with
- // the same cv-unqualified type as the function return type, the copy
- // operation can be omitted [...]
- // C++0x 12.8p16: When the criteria for elision of a copy operation are met
- // and the object to be copied is designated by an lvalue, overload
- // resolution to select the constructor for the copy is first performed
- // as if the object were designated by an rvalue.
- // Note that we only compute Elidable if we're in C++0x, since we don't
- // care otherwise.
- bool Elidable = getLangOptions().CPlusPlus0x ?
- IsReturnCopyElidable(Context, FnRetType, RetValExp) :
- false;
- // FIXME: Elidable
- (void)Elidable;
-
- // In C++ the return statement is handled via a copy initialization.
- // the C version of which boils down to CheckSingleAssignmentConstraints.
- OwningExprResult Res = PerformCopyInitialization(
- InitializedEntity::InitializeResult(ReturnLoc,
- FnRetType),
- SourceLocation(),
- Owned(RetValExp));
- if (Res.isInvalid()) {
- // FIXME: Cleanup temporaries here, anyway?
- return StmtError();
+ RetValExp = Res.takeAs<Expr>();
+ if (RetValExp)
+ CheckReturnStackAddr(RetValExp, FnRetType, ReturnLoc);
}
-
- RetValExp = Res.takeAs<Expr>();
- if (RetValExp)
- CheckReturnStackAddr(RetValExp, FnRetType, ReturnLoc);
+
+ if (RetValExp)
+ RetValExp = MaybeCreateCXXExprWithTemporaries(RetValExp);
+ Result = new (Context) ReturnStmt(ReturnLoc, RetValExp, NRVOCandidate);
}
-
- if (RetValExp)
- RetValExp = MaybeCreateCXXExprWithTemporaries(RetValExp);
- return Owned(new (Context) ReturnStmt(ReturnLoc, RetValExp));
+
+ // If we need to check for the named return value optimization, save the
+ // return statement in our scope for later processing.
+ if (getLangOptions().CPlusPlus && FnRetType->isRecordType() &&
+ !CurContext->isDependentContext())
+ FunctionScopes.back()->Returns.push_back(Result);
+
+ return Owned(Result);
}
/// CheckAsmLValue - GNU C has an extremely ugly extension whereby they silently
diff --git a/lib/Sema/SemaTemplate.cpp b/lib/Sema/SemaTemplate.cpp
index 694b21c8393f..307be9d78658 100644
--- a/lib/Sema/SemaTemplate.cpp
+++ b/lib/Sema/SemaTemplate.cpp
@@ -100,10 +100,12 @@ TemplateNameKind Sema::isTemplateName(Scope *S,
UnqualifiedId &Name,
TypeTy *ObjectTypePtr,
bool EnteringContext,
- TemplateTy &TemplateResult) {
+ TemplateTy &TemplateResult,
+ bool &MemberOfUnknownSpecialization) {
assert(getLangOptions().CPlusPlus && "No template names in C!");
DeclarationName TName;
+ MemberOfUnknownSpecialization = false;
switch (Name.getKind()) {
case UnqualifiedId::IK_Identifier:
@@ -128,7 +130,8 @@ TemplateNameKind Sema::isTemplateName(Scope *S,
LookupResult R(*this, TName, Name.getSourceRange().getBegin(),
LookupOrdinaryName);
R.suppressDiagnostics();
- LookupTemplateName(R, S, SS, ObjectType, EnteringContext);
+ LookupTemplateName(R, S, SS, ObjectType, EnteringContext,
+ MemberOfUnknownSpecialization);
if (R.empty() || R.isAmbiguous())
return TNK_Non_template;
@@ -172,6 +175,7 @@ bool Sema::DiagnoseUnknownTemplateName(const IdentifierInfo &II,
TemplateNameKind &SuggestedKind) {
// We can't recover unless there's a dependent scope specifier preceding the
// template name.
+ // FIXME: Typo correction?
if (!SS || !SS->isSet() || !isDependentScopeSpecifier(*SS) ||
computeDeclContext(*SS))
return false;
@@ -191,8 +195,10 @@ bool Sema::DiagnoseUnknownTemplateName(const IdentifierInfo &II,
void Sema::LookupTemplateName(LookupResult &Found,
Scope *S, CXXScopeSpec &SS,
QualType ObjectType,
- bool EnteringContext) {
+ bool EnteringContext,
+ bool &MemberOfUnknownSpecialization) {
// Determine where to perform name lookup
+ MemberOfUnknownSpecialization = false;
DeclContext *LookupCtx = 0;
bool isDependent = false;
if (!ObjectType.isNull()) {
@@ -241,6 +247,7 @@ void Sema::LookupTemplateName(LookupResult &Found,
} else if (isDependent) {
// We cannot look into a dependent object type or nested nme
// specifier.
+ MemberOfUnknownSpecialization = true;
return;
} else {
// Perform unqualified name lookup in the current scope.
@@ -330,11 +337,13 @@ Sema::ActOnDependentIdExpression(const CXXScopeSpec &SS,
const TemplateArgumentListInfo *TemplateArgs) {
NestedNameSpecifier *Qualifier
= static_cast<NestedNameSpecifier*>(SS.getScopeRep());
+
+ DeclContext *DC = getFunctionLevelDeclContext();
if (!isAddressOfOperand &&
- isa<CXXMethodDecl>(CurContext) &&
- cast<CXXMethodDecl>(CurContext)->isInstance()) {
- QualType ThisType = cast<CXXMethodDecl>(CurContext)->getThisType(Context);
+ isa<CXXMethodDecl>(DC) &&
+ cast<CXXMethodDecl>(DC)->isInstance()) {
+ QualType ThisType = cast<CXXMethodDecl>(DC)->getThisType(Context);
// Since the 'this' expression is synthesized, we don't need to
// perform the double-lookup check.
@@ -525,6 +534,14 @@ void Sema::ActOnTypeParameterDefault(DeclPtrTy TypeParam,
/// otherwise, produces a diagnostic and returns a NULL type.
QualType
Sema::CheckNonTypeTemplateParameterType(QualType T, SourceLocation Loc) {
+ // We don't allow variably-modified types as the type of non-type template
+ // parameters.
+ if (T->isVariablyModifiedType()) {
+ Diag(Loc, diag::err_variably_modified_nontype_template_param)
+ << T;
+ return QualType();
+ }
+
// C++ [temp.param]p4:
//
// A non-type template-parameter shall have one of the following
@@ -555,7 +572,7 @@ Sema::CheckNonTypeTemplateParameterType(QualType T, SourceLocation Loc) {
else if (T->isFunctionType())
// FIXME: Keep the type prior to promotion?
return Context.getPointerType(T);
-
+
Diag(Loc, diag::err_template_nontype_parm_bad_type)
<< T;
@@ -739,8 +756,8 @@ Sema::CheckClassTemplate(Scope *S, unsigned TagSpec, TagUseKind TUK,
if (CheckTemplateDeclScope(S, TemplateParams))
return true;
- TagDecl::TagKind Kind = TagDecl::getTagKindForTypeSpec(TagSpec);
- assert(Kind != TagDecl::TK_enum && "can't build template of enumerated type");
+ TagTypeKind Kind = TypeWithKeyword::getTagTypeKindForTypeSpec(TagSpec);
+ assert(Kind != TTK_Enum && "can't build template of enumerated type");
// There is no such thing as an unnamed class template.
if (!Name) {
@@ -1088,7 +1105,7 @@ bool Sema::CheckTemplateParameterList(TemplateParameterList *NewParams,
DiagnoseDefaultTemplateArgument(*this, TPC,
NewTypeParm->getLocation(),
NewTypeParm->getDefaultArgumentInfo()->getTypeLoc()
- .getFullSourceRange()))
+ .getSourceRange()))
NewTypeParm->removeDefaultArgument();
// Merge default arguments for template type parameters.
@@ -1506,10 +1523,11 @@ QualType Sema::CheckTemplateIdType(TemplateName Name,
// specialization. Create the canonical declaration and add it to
// the set of specializations.
Decl = ClassTemplateSpecializationDecl::Create(Context,
- ClassTemplate->getDeclContext(),
- ClassTemplate->getLocation(),
- ClassTemplate,
- Converted, 0);
+ ClassTemplate->getTemplatedDecl()->getTagKind(),
+ ClassTemplate->getDeclContext(),
+ ClassTemplate->getLocation(),
+ ClassTemplate,
+ Converted, 0);
ClassTemplate->getSpecializations().InsertNode(Decl, InsertPos);
Decl->setLexicalDeclContext(CurContext);
}
@@ -1567,7 +1585,7 @@ Sema::TypeResult Sema::ActOnTagTemplateIdType(TypeResult TypeResult,
QualType Type = GetTypeFromParser(TypeResult.get(), &DI);
// Verify the tag specifier.
- TagDecl::TagKind TagKind = TagDecl::getTagKindForTypeSpec(TagSpec);
+ TagTypeKind TagKind = TypeWithKeyword::getTagTypeKindForTypeSpec(TagSpec);
if (const RecordType *RT = Type->getAs<RecordType>()) {
RecordDecl *D = RT->getDecl();
@@ -1583,7 +1601,9 @@ Sema::TypeResult Sema::ActOnTagTemplateIdType(TypeResult TypeResult,
}
}
- QualType ElabType = Context.getElaboratedType(Type, TagKind);
+ ElaboratedTypeKeyword Keyword
+ = TypeWithKeyword::getKeywordForTagTypeKind(TagKind);
+ QualType ElabType = Context.getElaboratedType(Keyword, /*NNS=*/0, Type);
return ElabType.getAsOpaquePtr();
}
@@ -1618,8 +1638,8 @@ Sema::OwningExprResult Sema::BuildTemplateIdExpr(const CXXScopeSpec &SS,
= UnresolvedLookupExpr::Create(Context, Dependent, R.getNamingClass(),
Qualifier, QualifierRange,
R.getLookupName(), R.getNameLoc(),
- RequiresADL, TemplateArgs);
- ULE->addDecls(R.begin(), R.end());
+ RequiresADL, TemplateArgs,
+ R.begin(), R.end());
return Owned(ULE);
}
@@ -1636,8 +1656,10 @@ Sema::BuildQualifiedTemplateIdExpr(CXXScopeSpec &SS,
RequireCompleteDeclContext(SS, DC))
return BuildDependentDeclRefExpr(SS, Name, NameLoc, &TemplateArgs);
+ bool MemberOfUnknownSpecialization;
LookupResult R(*this, Name, NameLoc, LookupOrdinaryName);
- LookupTemplateName(R, (Scope*) 0, SS, QualType(), /*Entering*/ false);
+ LookupTemplateName(R, (Scope*) 0, SS, QualType(), /*Entering*/ false,
+ MemberOfUnknownSpecialization);
if (R.isAmbiguous())
return ExprError();
@@ -1694,8 +1716,10 @@ Sema::ActOnDependentTemplateName(SourceLocation TemplateKWLoc,
// "template" keyword is now permitted). We follow the C++0x
// rules, even in C++03 mode, retroactively applying the DR.
TemplateTy Template;
+ bool MemberOfUnknownSpecialization;
TemplateNameKind TNK = isTemplateName(0, SS, Name, ObjectType,
- EnteringContext, Template);
+ EnteringContext, Template,
+ MemberOfUnknownSpecialization);
if (TNK == TNK_Non_template && LookupCtx->isDependentContext() &&
isa<CXXRecordDecl>(LookupCtx) &&
cast<CXXRecordDecl>(LookupCtx)->hasAnyDependentBases()) {
@@ -1704,7 +1728,8 @@ Sema::ActOnDependentTemplateName(SourceLocation TemplateKWLoc,
Diag(Name.getSourceRange().getBegin(),
diag::err_template_kw_refers_to_non_template)
<< GetNameFromUnqualifiedId(Name)
- << Name.getSourceRange();
+ << Name.getSourceRange()
+ << TemplateKWLoc;
return TemplateTy();
} else {
// We found something; return it.
@@ -1734,7 +1759,8 @@ Sema::ActOnDependentTemplateName(SourceLocation TemplateKWLoc,
Diag(Name.getSourceRange().getBegin(),
diag::err_template_kw_refers_to_non_template)
<< GetNameFromUnqualifiedId(Name)
- << Name.getSourceRange();
+ << Name.getSourceRange()
+ << TemplateKWLoc;
return TemplateTy();
}
@@ -2336,24 +2362,27 @@ bool Sema::CheckTemplateArgument(TemplateTypeParmDecl *Param,
// compounded from any of these types shall not be used as a
// template-argument for a template type-parameter.
//
- // FIXME: Perform the recursive and no-linkage type checks.
+ // FIXME: Perform the unnamed type check.
+ SourceRange SR = ArgInfo->getTypeLoc().getSourceRange();
const TagType *Tag = 0;
if (const EnumType *EnumT = Arg->getAs<EnumType>())
Tag = EnumT;
else if (const RecordType *RecordT = Arg->getAs<RecordType>())
Tag = RecordT;
if (Tag && Tag->getDecl()->getDeclContext()->isFunctionOrMethod()) {
- SourceRange SR = ArgInfo->getTypeLoc().getFullSourceRange();
+ SourceRange SR = ArgInfo->getTypeLoc().getSourceRange();
return Diag(SR.getBegin(), diag::err_template_arg_local_type)
<< QualType(Tag, 0) << SR;
} else if (Tag && !Tag->getDecl()->getDeclName() &&
!Tag->getDecl()->getTypedefForAnonDecl()) {
- SourceRange SR = ArgInfo->getTypeLoc().getFullSourceRange();
Diag(SR.getBegin(), diag::err_template_arg_unnamed_type) << SR;
Diag(Tag->getDecl()->getLocation(), diag::note_template_unnamed_type_here);
return true;
+ } else if (Arg->isVariablyModifiedType()) {
+ Diag(SR.getBegin(), diag::err_variably_modified_template_arg)
+ << Arg;
+ return true;
} else if (Context.hasSameUnqualifiedType(Arg, Context.OverloadTy)) {
- SourceRange SR = ArgInfo->getTypeLoc().getFullSourceRange();
return Diag(SR.getBegin(), diag::err_template_arg_overload_type) << SR;
}
@@ -3661,13 +3690,8 @@ Sema::ActOnClassTemplateSpecialization(Scope *S, unsigned TagSpec,
// Check that the specialization uses the same tag kind as the
// original template.
- TagDecl::TagKind Kind;
- switch (TagSpec) {
- default: assert(0 && "Unknown tag type!");
- case DeclSpec::TST_struct: Kind = TagDecl::TK_struct; break;
- case DeclSpec::TST_union: Kind = TagDecl::TK_union; break;
- case DeclSpec::TST_class: Kind = TagDecl::TK_class; break;
- }
+ TagTypeKind Kind = TypeWithKeyword::getTagTypeKindForTypeSpec(TagSpec);
+ assert(Kind != TTK_Enum && "Invalid enum tag in class template spec!");
if (!isAcceptableTagRedeclaration(ClassTemplate->getTemplatedDecl(),
Kind, KWLoc,
*ClassTemplate->getIdentifier())) {
@@ -3796,7 +3820,7 @@ Sema::ActOnClassTemplateSpecialization(Scope *S, unsigned TagSpec,
unsigned SequenceNumber = PrevPartial? PrevPartial->getSequenceNumber()
: ClassTemplate->getPartialSpecializations().size();
ClassTemplatePartialSpecializationDecl *Partial
- = ClassTemplatePartialSpecializationDecl::Create(Context,
+ = ClassTemplatePartialSpecializationDecl::Create(Context, Kind,
ClassTemplate->getDeclContext(),
TemplateNameLoc,
TemplateParams,
@@ -3857,7 +3881,7 @@ Sema::ActOnClassTemplateSpecialization(Scope *S, unsigned TagSpec,
// Create a new class template specialization declaration node for
// this explicit specialization or friend declaration.
Specialization
- = ClassTemplateSpecializationDecl::Create(Context,
+ = ClassTemplateSpecializationDecl::Create(Context, Kind,
ClassTemplate->getDeclContext(),
TemplateNameLoc,
ClassTemplate,
@@ -4217,10 +4241,10 @@ Sema::CheckDependentFunctionTemplateSpecialization(FunctionDecl *FD,
return false;
}
-/// \brief Perform semantic analysis for the given function template
+/// \brief Perform semantic analysis for the given function template
/// specialization.
///
-/// This routine performs all of the semantic analysis required for an
+/// This routine performs all of the semantic analysis required for an
/// explicit function template specialization. On successful completion,
/// the function declaration \p FD will become a function template
/// specialization.
@@ -4228,24 +4252,14 @@ Sema::CheckDependentFunctionTemplateSpecialization(FunctionDecl *FD,
/// \param FD the function declaration, which will be updated to become a
/// function template specialization.
///
-/// \param HasExplicitTemplateArgs whether any template arguments were
-/// explicitly provided.
-///
-/// \param LAngleLoc the location of the left angle bracket ('<'), if
-/// template arguments were explicitly provided.
-///
-/// \param ExplicitTemplateArgs the explicitly-provided template arguments,
-/// if any.
-///
-/// \param NumExplicitTemplateArgs the number of explicitly-provided template
-/// arguments. This number may be zero even when HasExplicitTemplateArgs is
-/// true as in, e.g., \c void sort<>(char*, char*);
+/// \param ExplicitTemplateArgs the explicitly-provided template arguments,
+/// if any. Note that this may be valid info even when 0 arguments are
+/// explicitly provided as in, e.g., \c void sort<>(char*, char*);
+/// as it anyway contains info on the angle brackets locations.
///
-/// \param RAngleLoc the location of the right angle bracket ('>'), if
-/// template arguments were explicitly provided.
-///
-/// \param PrevDecl the set of declarations that
-bool
+/// \param PrevDecl the set of declarations that may be specialized by
+/// this function specialization.
+bool
Sema::CheckFunctionTemplateSpecialization(FunctionDecl *FD,
const TemplateArgumentListInfo *ExplicitTemplateArgs,
LookupResult &Previous) {
@@ -4347,12 +4361,16 @@ Sema::CheckFunctionTemplateSpecialization(FunctionDecl *FD,
// Turn the given function declaration into a function template
// specialization, with the template arguments from the previous
// specialization.
+ // Take copies of (semantic and syntactic) template argument lists.
+ const TemplateArgumentList* TemplArgs = new (Context)
+ TemplateArgumentList(Specialization->getTemplateSpecializationArgs());
+ const TemplateArgumentListInfo* TemplArgsAsWritten = ExplicitTemplateArgs
+ ? new (Context) TemplateArgumentListInfo(*ExplicitTemplateArgs) : 0;
FD->setFunctionTemplateSpecialization(Specialization->getPrimaryTemplate(),
- new (Context) TemplateArgumentList(
- *Specialization->getTemplateSpecializationArgs()),
- /*InsertPos=*/0,
- SpecInfo->getTemplateSpecializationKind());
-
+ TemplArgs, /*InsertPos=*/0,
+ SpecInfo->getTemplateSpecializationKind(),
+ TemplArgsAsWritten);
+
// The "previous declaration" for this function template specialization is
// the prior function template specialization.
Previous.clear();
@@ -4541,10 +4559,16 @@ static void CheckExplicitInstantiationScope(Sema &S, NamedDecl *D,
if (S.getLangOptions().CPlusPlus0x &&
!CurContext->Encloses(ExpectedContext)) {
if (NamespaceDecl *NS = dyn_cast<NamespaceDecl>(ExpectedContext))
- S.Diag(InstLoc, diag::err_explicit_instantiation_out_of_scope)
+ S.Diag(InstLoc,
+ S.getLangOptions().CPlusPlus0x?
+ diag::err_explicit_instantiation_out_of_scope
+ : diag::warn_explicit_instantiation_out_of_scope_0x)
<< D << NS;
else
- S.Diag(InstLoc, diag::err_explicit_instantiation_must_be_global)
+ S.Diag(InstLoc,
+ S.getLangOptions().CPlusPlus0x?
+ diag::err_explicit_instantiation_must_be_global
+ : diag::warn_explicit_instantiation_out_of_scope_0x)
<< D;
S.Diag(D->getLocation(), diag::note_explicit_instantiation_here);
return;
@@ -4561,7 +4585,10 @@ static void CheckExplicitInstantiationScope(Sema &S, NamedDecl *D,
if (CurContext->Equals(ExpectedContext))
return;
- S.Diag(InstLoc, diag::err_explicit_instantiation_unqualified_wrong_namespace)
+ S.Diag(InstLoc,
+ S.getLangOptions().CPlusPlus0x?
+ diag::err_explicit_instantiation_unqualified_wrong_namespace
+ : diag::warn_explicit_instantiation_unqualified_wrong_namespace_0x)
<< D << ExpectedContext;
S.Diag(D->getLocation(), diag::note_explicit_instantiation_here);
}
@@ -4588,7 +4615,6 @@ static bool ScopeSpecifierHasTemplateId(const CXXScopeSpec &SS) {
}
// Explicit instantiation of a class template specialization
-// FIXME: Implement extern template semantics
Sema::DeclResult
Sema::ActOnExplicitInstantiation(Scope *S,
SourceLocation ExternLoc,
@@ -4609,13 +4635,9 @@ Sema::ActOnExplicitInstantiation(Scope *S,
// Check that the specialization uses the same tag kind as the
// original template.
- TagDecl::TagKind Kind;
- switch (TagSpec) {
- default: assert(0 && "Unknown tag type!");
- case DeclSpec::TST_struct: Kind = TagDecl::TK_struct; break;
- case DeclSpec::TST_union: Kind = TagDecl::TK_union; break;
- case DeclSpec::TST_class: Kind = TagDecl::TK_class; break;
- }
+ TagTypeKind Kind = TypeWithKeyword::getTagTypeKindForTypeSpec(TagSpec);
+ assert(Kind != TTK_Enum &&
+ "Invalid enum tag in class template explicit instantiation!");
if (!isAcceptableTagRedeclaration(ClassTemplate->getTemplatedDecl(),
Kind, KWLoc,
*ClassTemplate->getIdentifier())) {
@@ -4703,7 +4725,7 @@ Sema::ActOnExplicitInstantiation(Scope *S,
// Create a new class template specialization declaration node for
// this explicit specialization.
Specialization
- = ClassTemplateSpecializationDecl::Create(Context,
+ = ClassTemplateSpecializationDecl::Create(Context, Kind,
ClassTemplate->getDeclContext(),
TemplateNameLoc,
ClassTemplate,
@@ -4755,7 +4777,9 @@ Sema::ActOnExplicitInstantiation(Scope *S,
Specialization->getDefinition());
if (!Def)
InstantiateClassTemplateSpecialization(TemplateNameLoc, Specialization, TSK);
-
+ else if (TSK == TSK_ExplicitInstantiationDefinition)
+ MarkVTableUsed(TemplateNameLoc, Specialization, true);
+
// Instantiate the members of this class template specialization.
Def = cast_or_null<ClassTemplateSpecializationDecl>(
Specialization->getDefinition());
@@ -4890,6 +4914,9 @@ Sema::ActOnExplicitInstantiation(Scope *S,
InstantiateClassMembers(NameLoc, RecordDef,
getTemplateInstantiationArgs(Record), TSK);
+ if (TSK == TSK_ExplicitInstantiationDefinition)
+ MarkVTableUsed(NameLoc, RecordDef, true);
+
// FIXME: We don't have any representation for explicit instantiations of
// member classes. Such a representation is not needed for compilation, but it
// should be available for clients that want to see all of the declarations in
@@ -5161,37 +5188,33 @@ Sema::ActOnDependentTag(Scope *S, unsigned TagSpec, TagUseKind TUK,
if (!NNS)
return true;
- 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!");
+ TagTypeKind Kind = TypeWithKeyword::getTagTypeKindForTypeSpec(TagSpec);
if (TUK == TUK_Declaration || TUK == TUK_Definition) {
Diag(NameLoc, diag::err_dependent_tag_decl)
- << (TUK == TUK_Definition) << TagDecl::getTagKindForTypeSpec(TagSpec)
- << SS.getRange();
+ << (TUK == TUK_Definition) << Kind << SS.getRange();
return true;
}
-
- return Context.getDependentNameType(Keyword, NNS, Name).getAsOpaquePtr();
+
+ ElaboratedTypeKeyword Kwd = TypeWithKeyword::getKeywordForTagTypeKind(Kind);
+ return Context.getDependentNameType(Kwd, NNS, Name).getAsOpaquePtr();
}
static void FillTypeLoc(DependentNameTypeLoc TL,
SourceLocation TypenameLoc,
- SourceRange QualifierRange) {
- // FIXME: typename, qualifier range
- TL.setNameLoc(TypenameLoc);
+ SourceRange QualifierRange,
+ SourceLocation NameLoc) {
+ TL.setKeywordLoc(TypenameLoc);
+ TL.setQualifierRange(QualifierRange);
+ TL.setNameLoc(NameLoc);
}
-static void FillTypeLoc(QualifiedNameTypeLoc TL,
+static void FillTypeLoc(ElaboratedTypeLoc TL,
SourceLocation TypenameLoc,
SourceRange QualifierRange) {
- // FIXME: typename, qualifier range
- TL.setNameLoc(TypenameLoc);
+ // FIXME: inner locations.
+ TL.setKeywordLoc(TypenameLoc);
+ TL.setQualifierRange(QualifierRange);
}
Sema::TypeResult
@@ -5203,7 +5226,7 @@ Sema::ActOnTypenameType(SourceLocation TypenameLoc, const CXXScopeSpec &SS,
return true;
QualType T = CheckTypenameType(ETK_Typename, NNS, II,
- SourceRange(TypenameLoc, IdLoc));
+ TypenameLoc, SS.getRange(), IdLoc);
if (T.isNull())
return true;
@@ -5211,9 +5234,9 @@ Sema::ActOnTypenameType(SourceLocation TypenameLoc, const CXXScopeSpec &SS,
if (isa<DependentNameType>(T)) {
DependentNameTypeLoc TL = cast<DependentNameTypeLoc>(TSI->getTypeLoc());
// FIXME: fill inner type loc
- FillTypeLoc(TL, TypenameLoc, SS.getRange());
+ FillTypeLoc(TL, TypenameLoc, SS.getRange(), IdLoc);
} else {
- QualifiedNameTypeLoc TL = cast<QualifiedNameTypeLoc>(TSI->getTypeLoc());
+ ElaboratedTypeLoc TL = cast<ElaboratedTypeLoc>(TSI->getTypeLoc());
// FIXME: fill inner type loc
FillTypeLoc(TL, TypenameLoc, SS.getRange());
}
@@ -5233,14 +5256,11 @@ Sema::ActOnTypenameType(SourceLocation TypenameLoc, const CXXScopeSpec &SS,
if (computeDeclContext(SS, false)) {
// If we can compute a declaration context, then the "typename"
- // keyword was superfluous. Just build a QualifiedNameType to keep
+ // keyword was superfluous. Just build an ElaboratedType to keep
// track of the nested-name-specifier.
-
- // FIXME: Note that the QualifiedNameType had the "typename" keyword!
-
- T = Context.getQualifiedNameType(NNS, T);
+ T = Context.getElaboratedType(ETK_Typename, NNS, T);
TypeSourceInfo *TSI = Context.CreateTypeSourceInfo(T);
- QualifiedNameTypeLoc TL = cast<QualifiedNameTypeLoc>(TSI->getTypeLoc());
+ ElaboratedTypeLoc TL = cast<ElaboratedTypeLoc>(TSI->getTypeLoc());
// FIXME: fill inner type loc
FillTypeLoc(TL, TypenameLoc, SS.getRange());
return CreateLocInfoType(T, TSI).getAsOpaquePtr();
@@ -5250,7 +5270,7 @@ Sema::ActOnTypenameType(SourceLocation TypenameLoc, const CXXScopeSpec &SS,
TypeSourceInfo *TSI = Context.CreateTypeSourceInfo(T);
DependentNameTypeLoc TL = cast<DependentNameTypeLoc>(TSI->getTypeLoc());
// FIXME: fill inner type loc
- FillTypeLoc(TL, TypenameLoc, SS.getRange());
+ FillTypeLoc(TL, TypenameLoc, SS.getRange(), TemplateLoc);
return CreateLocInfoType(T, TSI).getAsOpaquePtr();
}
@@ -5259,10 +5279,11 @@ Sema::ActOnTypenameType(SourceLocation TypenameLoc, const CXXScopeSpec &SS,
QualType
Sema::CheckTypenameType(ElaboratedTypeKeyword Keyword,
NestedNameSpecifier *NNS, const IdentifierInfo &II,
- SourceRange Range) {
+ SourceLocation KeywordLoc, SourceRange NNSRange,
+ SourceLocation IILoc) {
CXXScopeSpec SS;
SS.setScopeRep(NNS);
- SS.setRange(Range);
+ SS.setRange(NNSRange);
DeclContext *Ctx = computeDeclContext(SS);
if (!Ctx) {
@@ -5282,7 +5303,7 @@ Sema::CheckTypenameType(ElaboratedTypeKeyword Keyword,
return QualType();
DeclarationName Name(&II);
- LookupResult Result(*this, Name, Range.getEnd(), LookupOrdinaryName);
+ LookupResult Result(*this, Name, IILoc, LookupOrdinaryName);
LookupQualifiedName(Result, Ctx);
unsigned DiagID = 0;
Decl *Referenced = 0;
@@ -5297,10 +5318,10 @@ Sema::CheckTypenameType(ElaboratedTypeKeyword Keyword,
case LookupResult::Found:
if (TypeDecl *Type = dyn_cast<TypeDecl>(Result.getFoundDecl())) {
- // We found a type. Build a QualifiedNameType, since the
- // typename-specifier was just sugar. FIXME: Tell
- // QualifiedNameType that it has a "typename" prefix.
- return Context.getQualifiedNameType(NNS, Context.getTypeDeclType(Type));
+ // We found a type. Build an ElaboratedType, since the
+ // typename-specifier was just sugar.
+ return Context.getElaboratedType(ETK_Typename, NNS,
+ Context.getTypeDeclType(Type));
}
DiagID = diag::err_typename_nested_not_type;
@@ -5322,7 +5343,9 @@ Sema::CheckTypenameType(ElaboratedTypeKeyword Keyword,
// If we get here, it's because name lookup did not find a
// type. Emit an appropriate diagnostic and return an error.
- Diag(Range.getEnd(), DiagID) << Range << Name << Ctx;
+ SourceRange FullRange(KeywordLoc.isValid() ? KeywordLoc : NNSRange.getBegin(),
+ IILoc);
+ Diag(IILoc, DiagID) << FullRange << Name << Ctx;
if (Referenced)
Diag(Referenced->getLocation(), diag::note_typename_refers_here)
<< Name;
@@ -5379,9 +5402,10 @@ 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 TransformDependentNameType(TypeLocBuilder &TLB, DependentNameTypeLoc TL,
- QualType ObjectType);
+ /// type-checking and building an ElaboratedType (when possible).
+ QualType TransformDependentNameType(TypeLocBuilder &TLB,
+ DependentNameTypeLoc TL,
+ QualType ObjectType);
};
}
@@ -5393,7 +5417,7 @@ CurrentInstantiationRebuilder::TransformDependentNameType(TypeLocBuilder &TLB,
NestedNameSpecifier *NNS
= TransformNestedNameSpecifier(T->getQualifier(),
- /*FIXME:*/SourceRange(getBaseLocation()),
+ TL.getQualifierRange(),
ObjectType);
if (!NNS)
return QualType();
@@ -5402,7 +5426,7 @@ CurrentInstantiationRebuilder::TransformDependentNameType(TypeLocBuilder &TLB,
// context corresponding to the nested-name-specifier, then this
// typename type will not change; exit early.
CXXScopeSpec SS;
- SS.setRange(SourceRange(getBaseLocation()));
+ SS.setRange(TL.getQualifierRange());
SS.setScopeRep(NNS);
QualType Result;
@@ -5410,7 +5434,7 @@ CurrentInstantiationRebuilder::TransformDependentNameType(TypeLocBuilder &TLB,
Result = QualType(T, 0);
// Rebuild the typename type, which will probably turn into a
- // QualifiedNameType.
+ // ElaboratedType.
else if (const TemplateSpecializationType *TemplateId = T->getTemplateId()) {
QualType NewTemplateId
= TransformType(QualType(TemplateId, 0));
@@ -5421,18 +5445,38 @@ CurrentInstantiationRebuilder::TransformDependentNameType(TypeLocBuilder &TLB,
NewTemplateId == QualType(TemplateId, 0))
Result = QualType(T, 0);
else
- Result = getDerived().RebuildDependentNameType(T->getKeyword(),
+ Result = getDerived().RebuildDependentNameType(T->getKeyword(),
NNS, NewTemplateId);
} else
- Result = getDerived().RebuildDependentNameType(T->getKeyword(),
- NNS, T->getIdentifier(),
- SourceRange(TL.getNameLoc()));
+ Result = getDerived().RebuildDependentNameType(T->getKeyword(), NNS,
+ T->getIdentifier(),
+ TL.getKeywordLoc(),
+ TL.getQualifierRange(),
+ TL.getNameLoc());
if (Result.isNull())
return QualType();
- DependentNameTypeLoc NewTL = TLB.push<DependentNameTypeLoc>(Result);
- NewTL.setNameLoc(TL.getNameLoc());
+ if (const ElaboratedType* ElabT = Result->getAs<ElaboratedType>()) {
+ QualType NamedT = ElabT->getNamedType();
+ if (isa<TemplateSpecializationType>(NamedT)) {
+ TemplateSpecializationTypeLoc NamedTLoc
+ = TLB.push<TemplateSpecializationTypeLoc>(NamedT);
+ // FIXME: fill locations
+ NamedTLoc.initializeLocal(TL.getNameLoc());
+ } else {
+ TLB.pushTypeSpec(NamedT).setNameLoc(TL.getNameLoc());
+ }
+ ElaboratedTypeLoc NewTL = TLB.push<ElaboratedTypeLoc>(Result);
+ NewTL.setKeywordLoc(TL.getKeywordLoc());
+ NewTL.setQualifierRange(TL.getQualifierRange());
+ }
+ else {
+ DependentNameTypeLoc NewTL = TLB.push<DependentNameTypeLoc>(Result);
+ NewTL.setKeywordLoc(TL.getKeywordLoc());
+ NewTL.setQualifierRange(TL.getQualifierRange());
+ NewTL.setNameLoc(TL.getNameLoc());
+ }
return Result;
}
@@ -5459,7 +5503,7 @@ CurrentInstantiationRebuilder::TransformDependentNameType(TypeLocBuilder &TLB,
/// 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
+/// in X<T> and returning an ElaboratedType whose canonical type is the same
/// as the canonical type of T*, allowing the return types of the out-of-line
/// definition and the declaration to match.
TypeSourceInfo *Sema::RebuildTypeInCurrentInstantiation(TypeSourceInfo *T,
diff --git a/lib/Sema/SemaTemplateDeduction.cpp b/lib/Sema/SemaTemplateDeduction.cpp
index 2bb97eba11cb..88ceeca58a66 100644
--- a/lib/Sema/SemaTemplateDeduction.cpp
+++ b/lib/Sema/SemaTemplateDeduction.cpp
@@ -482,14 +482,20 @@ DeduceTemplateArguments(Sema &S,
// T *
case Type::Pointer: {
- const PointerType *PointerArg = Arg->getAs<PointerType>();
- if (!PointerArg)
+ QualType PointeeType;
+ if (const PointerType *PointerArg = Arg->getAs<PointerType>()) {
+ PointeeType = PointerArg->getPointeeType();
+ } else if (const ObjCObjectPointerType *PointerArg
+ = Arg->getAs<ObjCObjectPointerType>()) {
+ PointeeType = PointerArg->getPointeeType();
+ } else {
return Sema::TDK_NonDeducedMismatch;
+ }
unsigned SubTDF = TDF & (TDF_IgnoreQualifiers | TDF_DerivedClass);
return DeduceTemplateArguments(S, TemplateParams,
cast<PointerType>(Param)->getPointeeType(),
- PointerArg->getPointeeType(),
+ PointeeType,
Info, Deduced, SubTDF);
}
@@ -1030,10 +1036,8 @@ FinishTemplateArgumentDeduction(Sema &S,
ClassTemplate->getTemplateParameters(), N);
if (S.CheckTemplateArgumentList(ClassTemplate, Partial->getLocation(),
- InstArgs, false, ConvertedInstArgs)) {
- // FIXME: fail with more useful information?
+ InstArgs, false, ConvertedInstArgs))
return Sema::TDK_SubstitutionFailure;
- }
for (unsigned I = 0, E = ConvertedInstArgs.flatSize(); I != E; ++I) {
TemplateArgument InstArg = ConvertedInstArgs.getFlatArguments()[I];
@@ -1190,8 +1194,13 @@ Sema::SubstituteExplicitTemplateArguments(
SourceLocation(),
ExplicitTemplateArgs,
true,
- Builder) || Trap.hasErrorOccurred())
+ Builder) || Trap.hasErrorOccurred()) {
+ unsigned Index = Builder.structuredSize();
+ if (Index >= TemplateParams->size())
+ Index = TemplateParams->size() - 1;
+ Info.Param = makeTemplateParameter(TemplateParams->getParam(Index));
return TDK_InvalidExplicitArguments;
+ }
// Form the template argument list from the explicitly-specified
// template arguments.
@@ -1374,6 +1383,8 @@ Sema::FinishTemplateArgumentDeduction(FunctionTemplateDecl *FunctionTemplate,
NTTP->getDeclName());
if (NTTPType.isNull()) {
Info.Param = makeTemplateParameter(Param);
+ Info.reset(new (Context) TemplateArgumentList(Context, Builder,
+ /*TakeArgs=*/true));
return TDK_SubstitutionFailure;
}
}
@@ -1399,6 +1410,8 @@ Sema::FinishTemplateArgumentDeduction(FunctionTemplateDecl *FunctionTemplate,
: CTAK_Deduced)) {
Info.Param = makeTemplateParameter(
const_cast<NamedDecl *>(TemplateParams->getParam(I)));
+ Info.reset(new (Context) TemplateArgumentList(Context, Builder,
+ /*TakeArgs=*/true));
return TDK_SubstitutionFailure;
}
@@ -1429,6 +1442,8 @@ Sema::FinishTemplateArgumentDeduction(FunctionTemplateDecl *FunctionTemplate,
CTAK_Deduced)) {
Info.Param = makeTemplateParameter(
const_cast<NamedDecl *>(TemplateParams->getParam(I)));
+ Info.reset(new (Context) TemplateArgumentList(Context, Builder,
+ /*TakeArgs=*/true));
return TDK_SubstitutionFailure;
}
@@ -1456,7 +1471,8 @@ Sema::FinishTemplateArgumentDeduction(FunctionTemplateDecl *FunctionTemplate,
// If the template argument list is owned by the function template
// specialization, release it.
- if (Specialization->getTemplateSpecializationArgs() == DeducedArgumentList)
+ if (Specialization->getTemplateSpecializationArgs() == DeducedArgumentList &&
+ !Trap.hasErrorOccurred())
Info.take();
// There may have been an error that did not prevent us from constructing a
@@ -2636,6 +2652,7 @@ MarkUsedTemplateParameters(Sema &SemaRef, QualType T,
case Type::Record:
case Type::Enum:
case Type::ObjCInterface:
+ case Type::ObjCObject:
case Type::ObjCObjectPointer:
case Type::UnresolvedUsing:
#define TYPE(Class, Base)
diff --git a/lib/Sema/SemaTemplateInstantiate.cpp b/lib/Sema/SemaTemplateInstantiate.cpp
index 14bd24320104..1adf594c1eff 100644
--- a/lib/Sema/SemaTemplateInstantiate.cpp
+++ b/lib/Sema/SemaTemplateInstantiate.cpp
@@ -560,9 +560,7 @@ namespace {
///
/// For the purposes of template instantiation, a type has already been
/// transformed if it is NULL or if it is not dependent.
- bool AlreadyTransformed(QualType T) {
- return T.isNull() || !T->isDependentType();
- }
+ bool AlreadyTransformed(QualType T);
/// \brief Returns the location of the entity being instantiated, if known.
SourceLocation getBaseLocation() { return Loc; }
@@ -603,7 +601,8 @@ namespace {
/// \brief Check for tag mismatches when instantiating an
/// elaborated type.
- QualType RebuildElaboratedType(QualType T, ElaboratedType::TagKind Tag);
+ QualType RebuildElaboratedType(ElaboratedTypeKeyword Keyword,
+ NestedNameSpecifier *NNS, QualType T);
Sema::OwningExprResult TransformPredefinedExpr(PredefinedExpr *E);
Sema::OwningExprResult TransformDeclRefExpr(DeclRefExpr *E);
@@ -624,6 +623,17 @@ namespace {
};
}
+bool TemplateInstantiator::AlreadyTransformed(QualType T) {
+ if (T.isNull())
+ return true;
+
+ if (T->isDependentType() || T->isVariablyModifiedType())
+ return false;
+
+ getSema().MarkDeclarationsReferencedInType(Loc, T);
+ return true;
+}
+
Decl *TemplateInstantiator::TransformDecl(SourceLocation Loc, Decl *D) {
if (!D)
return 0;
@@ -710,8 +720,9 @@ VarDecl *TemplateInstantiator::RebuildObjCExceptionDecl(VarDecl *ExceptionDecl,
}
QualType
-TemplateInstantiator::RebuildElaboratedType(QualType T,
- ElaboratedType::TagKind Tag) {
+TemplateInstantiator::RebuildElaboratedType(ElaboratedTypeKeyword Keyword,
+ NestedNameSpecifier *NNS,
+ QualType T) {
if (const TagType *TT = T->getAs<TagType>()) {
TagDecl* TD = TT->getDecl();
@@ -723,16 +734,20 @@ TemplateInstantiator::RebuildElaboratedType(QualType T,
// TODO: should we even warn on struct/class mismatches for this? Seems
// like it's likely to produce a lot of spurious errors.
- if (!SemaRef.isAcceptableTagRedeclaration(TD, Tag, TagLocation, *Id)) {
- SemaRef.Diag(TagLocation, diag::err_use_with_wrong_tag)
- << Id
- << FixItHint::CreateReplacement(SourceRange(TagLocation),
- TD->getKindName());
- SemaRef.Diag(TD->getLocation(), diag::note_previous_use);
+ if (Keyword != ETK_None && Keyword != ETK_Typename) {
+ TagTypeKind Kind = TypeWithKeyword::getTagTypeKindForKeyword(Keyword);
+ if (!SemaRef.isAcceptableTagRedeclaration(TD, Kind, TagLocation, *Id)) {
+ SemaRef.Diag(TagLocation, diag::err_use_with_wrong_tag)
+ << Id
+ << FixItHint::CreateReplacement(SourceRange(TagLocation),
+ TD->getKindName());
+ SemaRef.Diag(TD->getLocation(), diag::note_previous_use);
+ }
}
}
- return TreeTransform<TemplateInstantiator>::RebuildElaboratedType(T, Tag);
+ return TreeTransform<TemplateInstantiator>::RebuildElaboratedType(Keyword,
+ NNS, T);
}
Sema::OwningExprResult
@@ -927,7 +942,8 @@ TypeSourceInfo *Sema::SubstType(TypeSourceInfo *T,
"Cannot perform an instantiation without some context on the "
"instantiation stack");
- if (!T->getType()->isDependentType())
+ if (!T->getType()->isDependentType() &&
+ !T->getType()->isVariablyModifiedType())
return T;
TemplateInstantiator Instantiator(*this, Args, Loc, Entity);
@@ -942,8 +958,9 @@ QualType Sema::SubstType(QualType T,
"Cannot perform an instantiation without some context on the "
"instantiation stack");
- // If T is not a dependent type, there is nothing to do.
- if (!T->isDependentType())
+ // If T is not a dependent type or a variably-modified type, there
+ // is nothing to do.
+ if (!T->isDependentType() && !T->isVariablyModifiedType())
return T;
TemplateInstantiator Instantiator(*this, TemplateArgs, Loc, Entity);
@@ -951,7 +968,7 @@ QualType Sema::SubstType(QualType T,
}
static bool NeedsInstantiationAsFunctionType(TypeSourceInfo *T) {
- if (T->getType()->isDependentType())
+ if (T->getType()->isDependentType() || T->getType()->isVariablyModifiedType())
return true;
TypeLoc TL = T->getTypeLoc();
@@ -1160,6 +1177,8 @@ Sema::InstantiateClass(SourceLocation PointOfInstantiation,
// Enter the scope of this instantiation. We don't use
// PushDeclContext because we don't have a scope.
ContextRAII SavedContext(*this, Instantiation);
+ EnterExpressionEvaluationContext EvalContext(*this,
+ Action::PotentiallyEvaluated);
// If this is an instantiation of a local class, merge this local
// instantiation scope with the enclosing scope. Otherwise, every
@@ -1169,6 +1188,8 @@ Sema::InstantiateClass(SourceLocation PointOfInstantiation,
// Start the definition of this instantiation.
Instantiation->startDefinition();
+
+ Instantiation->setTagKind(Pattern->getTagKind());
// Do substitution on the base class specifiers.
if (SubstBaseSpecifiers(Instantiation, Pattern, TemplateArgs))
@@ -1202,25 +1223,15 @@ Sema::InstantiateClass(SourceLocation PointOfInstantiation,
// Exit the scope of this instantiation.
SavedContext.pop();
- // If this is a polymorphic C++ class without a key function, we'll
- // have to mark all of the virtual members to allow emission of a vtable
- // in this translation unit.
- if (Instantiation->isDynamicClass() &&
- !Context.getKeyFunction(Instantiation)) {
- // Local classes need to have their methods instantiated immediately in
- // order to have the correct instantiation scope.
- if (Instantiation->isLocalClass()) {
- MarkVirtualMembersReferenced(PointOfInstantiation,
- Instantiation);
- } else {
- ClassesWithUnmarkedVirtualMembers.push_back(std::make_pair(Instantiation,
- PointOfInstantiation));
- }
- }
-
- if (!Invalid)
+ if (!Invalid) {
Consumer.HandleTagDeclDefinition(Instantiation);
+ // Always emit the vtable for an explicit instantiation definition
+ // of a polymorphic class template specialization.
+ if (TSK == TSK_ExplicitInstantiationDefinition)
+ MarkVTableUsed(PointOfInstantiation, Instantiation, true);
+ }
+
return Invalid;
}
@@ -1244,6 +1255,12 @@ Sema::InstantiateClassTemplateSpecialization(
// declaration (C++0x [temp.explicit]p10); go ahead and perform the
// explicit instantiation.
ClassTemplateSpec->setSpecializationKind(TSK);
+
+ // If this is an explicit instantiation definition, mark the
+ // vtable as used.
+ if (TSK == TSK_ExplicitInstantiationDefinition)
+ MarkVTableUsed(PointOfInstantiation, ClassTemplateSpec, true);
+
return false;
}
diff --git a/lib/Sema/SemaTemplateInstantiateDecl.cpp b/lib/Sema/SemaTemplateInstantiateDecl.cpp
index da8480633d5b..834b86da9a0f 100644
--- a/lib/Sema/SemaTemplateInstantiateDecl.cpp
+++ b/lib/Sema/SemaTemplateInstantiateDecl.cpp
@@ -184,13 +184,16 @@ TemplateDeclInstantiator::VisitNamespaceAliasDecl(NamespaceAliasDecl *D) {
Decl *TemplateDeclInstantiator::VisitTypedefDecl(TypedefDecl *D) {
bool Invalid = false;
TypeSourceInfo *DI = D->getTypeSourceInfo();
- if (DI->getType()->isDependentType()) {
+ if (DI->getType()->isDependentType() ||
+ DI->getType()->isVariablyModifiedType()) {
DI = SemaRef.SubstType(DI, TemplateArgs,
D->getLocation(), D->getDeclName());
if (!DI) {
Invalid = true;
DI = SemaRef.Context.getTrivialTypeSourceInfo(SemaRef.Context.IntTy);
}
+ } else {
+ SemaRef.MarkDeclarationsReferencedInType(D->getLocation(), DI->getType());
}
// Create the new typedef
@@ -215,6 +218,7 @@ Decl *TemplateDeclInstantiator::VisitTypedefDecl(TypedefDecl *D) {
Typedef->setPreviousDeclaration(cast<TypedefDecl>(InstPrev));
}
+ InstantiateAttrs(D, Typedef);
Typedef->setAccess(D->getAccess());
Owner->addDecl(Typedef);
@@ -320,6 +324,13 @@ static bool InstantiateInitializer(Sema &S, Expr *Init,
}
Decl *TemplateDeclInstantiator::VisitVarDecl(VarDecl *D) {
+ // If this is the variable for an anonymous struct or union,
+ // instantiate the anonymous struct/union type first.
+ if (const RecordType *RecordTy = D->getType()->getAs<RecordType>())
+ if (RecordTy->getDecl()->isAnonymousStructOrUnion())
+ if (!VisitCXXRecordDecl(cast<CXXRecordDecl>(RecordTy->getDecl())))
+ return 0;
+
// Do substitution on the type of the declaration
TypeSourceInfo *DI = SemaRef.SubstType(D->getTypeSourceInfo(),
TemplateArgs,
@@ -349,7 +360,8 @@ Decl *TemplateDeclInstantiator::VisitVarDecl(VarDecl *D) {
Var->setLexicalDeclContext(D->getLexicalDeclContext());
Var->setAccess(D->getAccess());
-
+ Var->setUsed(D->isUsed());
+
// FIXME: In theory, we could have a previous declaration for variables that
// are not static data members.
bool Redeclaration = false;
@@ -417,13 +429,18 @@ Decl *TemplateDeclInstantiator::VisitVarDecl(VarDecl *D) {
} else if (!Var->isStaticDataMember() || Var->isOutOfLine())
SemaRef.ActOnUninitializedDecl(Sema::DeclPtrTy::make(Var), false);
+ // Diagnose unused local variables.
+ if (!Var->isInvalidDecl() && Owner->isFunctionOrMethod() && !Var->isUsed())
+ SemaRef.DiagnoseUnusedDecl(Var);
+
return Var;
}
Decl *TemplateDeclInstantiator::VisitFieldDecl(FieldDecl *D) {
bool Invalid = false;
TypeSourceInfo *DI = D->getTypeSourceInfo();
- if (DI->getType()->isDependentType()) {
+ if (DI->getType()->isDependentType() ||
+ DI->getType()->isVariablyModifiedType()) {
DI = SemaRef.SubstType(DI, TemplateArgs,
D->getLocation(), D->getDeclName());
if (!DI) {
@@ -440,6 +457,8 @@ Decl *TemplateDeclInstantiator::VisitFieldDecl(FieldDecl *D) {
<< DI->getType();
Invalid = true;
}
+ } else {
+ SemaRef.MarkDeclarationsReferencedInType(D->getLocation(), DI->getType());
}
Expr *BitWidth = D->getBitWidth();
@@ -480,6 +499,11 @@ Decl *TemplateDeclInstantiator::VisitFieldDecl(FieldDecl *D) {
if (!Field->getDeclName()) {
// Keep track of where this decl came from.
SemaRef.Context.setInstantiatedFromUnnamedFieldDecl(Field, D);
+ }
+ if (CXXRecordDecl *Parent= dyn_cast<CXXRecordDecl>(Field->getDeclContext())) {
+ if (Parent->isAnonymousStructOrUnion() &&
+ Parent->getLookupContext()->isFunctionOrMethod())
+ SemaRef.CurrentInstantiationScope->InstantiatedLocal(D, Field);
}
Field->setImplicit(D->isImplicit());
@@ -903,7 +927,12 @@ Decl *TemplateDeclInstantiator::VisitCXXRecordDecl(CXXRecordDecl *D) {
if (Decl::FriendObjectKind FOK = D->getFriendObjectKind())
Record->setObjectOfFriendDecl(FOK == Decl::FOK_Declared);
- Record->setAnonymousStructOrUnion(D->isAnonymousStructOrUnion());
+ // Make sure that anonymous structs and unions are recorded.
+ if (D->isAnonymousStructOrUnion()) {
+ Record->setAnonymousStructOrUnion(true);
+ if (Record->getDeclContext()->getLookupContext()->isFunctionOrMethod())
+ SemaRef.CurrentInstantiationScope->InstantiatedLocal(D, Record);
+ }
Owner->addDecl(Record);
return Record;
@@ -943,6 +972,7 @@ Decl *TemplateDeclInstantiator::VisitFunctionDecl(FunctionDecl *D,
isFriend = (D->getFriendObjectKind() != Decl::FOK_None);
bool MergeWithParentScope = (TemplateParams != 0) ||
+ Owner->isFunctionOrMethod() ||
!(isa<Decl>(Owner) &&
cast<Decl>(Owner)->isDefinedOutsideFunctionOrMethod());
Sema::LocalInstantiationScope Scope(SemaRef, MergeWithParentScope);
@@ -1000,6 +1030,7 @@ Decl *TemplateDeclInstantiator::VisitFunctionDecl(FunctionDecl *D,
Params[P]->setOwningFunction(Function);
Function->setParams(Params.data(), Params.size());
+ SourceLocation InstantiateAtPOI;
if (TemplateParams) {
// Our resulting instantiation is actually a function template, since we
// are substituting only the outer template parameters. For example, given
@@ -1118,6 +1149,38 @@ Decl *TemplateDeclInstantiator::VisitFunctionDecl(FunctionDecl *D,
PrincipalDecl->setObjectOfFriendDecl(PrevDecl != 0);
DC->makeDeclVisibleInContext(PrincipalDecl, /*Recoverable=*/ false);
+
+ if (!SemaRef.getLangOptions().CPlusPlus0x &&
+ D->isThisDeclarationADefinition()) {
+ // Check for a function body.
+ const FunctionDecl *Definition = 0;
+ if (Function->getBody(Definition) &&
+ Definition->getTemplateSpecializationKind() == TSK_Undeclared) {
+ SemaRef.Diag(Function->getLocation(), diag::err_redefinition)
+ << Function->getDeclName();
+ SemaRef.Diag(Definition->getLocation(), diag::note_previous_definition);
+ Function->setInvalidDecl();
+ }
+ // Check for redefinitions due to other instantiations of this or
+ // a similar friend function.
+ else for (FunctionDecl::redecl_iterator R = Function->redecls_begin(),
+ REnd = Function->redecls_end();
+ R != REnd; ++R) {
+ if (*R != Function &&
+ ((*R)->getFriendObjectKind() != Decl::FOK_None)) {
+ if (const FunctionDecl *RPattern
+ = (*R)->getTemplateInstantiationPattern())
+ if (RPattern->getBody(RPattern)) {
+ SemaRef.Diag(Function->getLocation(), diag::err_redefinition)
+ << Function->getDeclName();
+ SemaRef.Diag((*R)->getLocation(), diag::note_previous_definition);
+ Function->setInvalidDecl();
+ break;
+ }
+ }
+ }
+ }
+
}
if (Function->isOverloadedOperator() && !DC->isRecord() &&
@@ -1761,7 +1824,9 @@ TemplateDeclInstantiator::InstantiateClassTemplatePartialSpecialization(
// Create the class template partial specialization declaration.
ClassTemplatePartialSpecializationDecl *InstPartialSpec
- = ClassTemplatePartialSpecializationDecl::Create(SemaRef.Context, Owner,
+ = ClassTemplatePartialSpecializationDecl::Create(SemaRef.Context,
+ PartialSpec->getTagKind(),
+ Owner,
PartialSpec->getLocation(),
InstParams,
ClassTemplate,
@@ -1946,15 +2011,13 @@ void Sema::InstantiateFunctionDefinition(SourceLocation PointOfInstantiation,
FunctionDecl *Function,
bool Recursive,
bool DefinitionRequired) {
- if (Function->isInvalidDecl())
+ if (Function->isInvalidDecl() || Function->getBody())
return;
- assert(!Function->getBody() && "Already instantiated!");
-
// Never instantiate an explicit specialization.
if (Function->getTemplateSpecializationKind() == TSK_ExplicitSpecialization)
return;
-
+
// Find the function body that we'll be substituting.
const FunctionDecl *PatternDecl = Function->getTemplateInstantiationPattern();
Stmt *Pattern = 0;
@@ -1975,6 +2038,7 @@ void Sema::InstantiateFunctionDefinition(SourceLocation PointOfInstantiation,
if (PatternDecl)
Diag(PatternDecl->getLocation(),
diag::note_explicit_instantiation_here);
+ Function->setInvalidDecl();
}
return;
@@ -2000,6 +2064,8 @@ void Sema::InstantiateFunctionDefinition(SourceLocation PointOfInstantiation,
if (Recursive)
PendingImplicitInstantiations.swap(SavedPendingImplicitInstantiations);
+ EnterExpressionEvaluationContext EvalContext(*this,
+ Action::PotentiallyEvaluated);
ActOnStartOfFunctionDef(0, DeclPtrTy::make(Function));
// Introduce a new scope where local variable instantiations will be
@@ -2644,8 +2710,7 @@ void Sema::PerformPendingImplicitInstantiations(bool LocalOnly) {
Context.getSourceManager(),
"instantiating function definition");
- if (!Function->getBody())
- InstantiateFunctionDefinition(/*FIXME:*/Inst.second, Function, true);
+ InstantiateFunctionDefinition(/*FIXME:*/Inst.second, Function, true);
continue;
}
diff --git a/lib/Sema/SemaType.cpp b/lib/Sema/SemaType.cpp
index d1a74beb538f..35efa6113b64 100644
--- a/lib/Sema/SemaType.cpp
+++ b/lib/Sema/SemaType.cpp
@@ -25,6 +25,8 @@
#include "llvm/Support/ErrorHandling.h"
using namespace clang;
+#include <iostream>
+
/// \brief Perform adjustment on the parameter type of a function.
///
/// This routine adjusts the given parameter type @p T to the actual
@@ -162,9 +164,10 @@ static QualType ConvertDeclSpecToType(Sema &TheSema,
case DeclSpec::TST_unspecified:
// "<proto1,proto2>" is an objc qualified ID with a missing id.
if (DeclSpec::ProtocolQualifierListTy PQ = DS.getProtocolQualifiers()) {
- Result = Context.getObjCObjectPointerType(Context.ObjCBuiltinIdTy,
- (ObjCProtocolDecl**)PQ,
- DS.getNumProtocolQualifiers());
+ Result = Context.getObjCObjectType(Context.ObjCBuiltinIdTy,
+ (ObjCProtocolDecl**)PQ,
+ DS.getNumProtocolQualifiers());
+ Result = Context.getObjCObjectPointerType(Result);
break;
}
@@ -283,12 +286,11 @@ static QualType ConvertDeclSpecToType(Sema &TheSema,
// In C++, make an ElaboratedType.
if (TheSema.getLangOptions().CPlusPlus) {
- TagDecl::TagKind Tag
- = TagDecl::getTagKindForTypeSpec(DS.getTypeSpecType());
- Result = TheSema.getQualifiedNameType(DS.getTypeSpecScope(), Result);
- Result = Context.getElaboratedType(Result, Tag);
+ ElaboratedTypeKeyword Keyword
+ = ElaboratedType::getKeywordForTypeSpec(DS.getTypeSpecType());
+ Result = TheSema.getElaboratedType(Keyword, DS.getTypeSpecScope(),
+ Result);
}
-
if (D->isInvalidDecl())
TheDeclarator.setInvalidType(true);
break;
@@ -300,28 +302,28 @@ static QualType ConvertDeclSpecToType(Sema &TheSema,
Result = TheSema.GetTypeFromParser(DS.getTypeRep());
if (DeclSpec::ProtocolQualifierListTy PQ = DS.getProtocolQualifiers()) {
- if (const ObjCInterfaceType *
- Interface = Result->getAs<ObjCInterfaceType>()) {
- // It would be nice if protocol qualifiers were only stored with the
- // ObjCObjectPointerType. Unfortunately, this isn't possible due
- // to the following typedef idiom (which is uncommon, but allowed):
- //
- // typedef Foo<P> T;
- // static void func() {
- // Foo<P> *yy;
- // T *zz;
- // }
- Result = Context.getObjCInterfaceType(Interface->getDecl(),
- (ObjCProtocolDecl**)PQ,
- DS.getNumProtocolQualifiers());
- } else if (Result->isObjCIdType())
+ if (const ObjCObjectType *ObjT = Result->getAs<ObjCObjectType>()) {
+ // Silently drop any existing protocol qualifiers.
+ // TODO: determine whether that's the right thing to do.
+ if (ObjT->getNumProtocols())
+ Result = ObjT->getBaseType();
+
+ if (DS.getNumProtocolQualifiers())
+ Result = Context.getObjCObjectType(Result,
+ (ObjCProtocolDecl**) PQ,
+ DS.getNumProtocolQualifiers());
+ } else if (Result->isObjCIdType()) {
// id<protocol-list>
- Result = Context.getObjCObjectPointerType(Context.ObjCBuiltinIdTy,
- (ObjCProtocolDecl**)PQ, DS.getNumProtocolQualifiers());
- else if (Result->isObjCClassType()) {
+ Result = Context.getObjCObjectType(Context.ObjCBuiltinIdTy,
+ (ObjCProtocolDecl**) PQ,
+ DS.getNumProtocolQualifiers());
+ Result = Context.getObjCObjectPointerType(Result);
+ } else if (Result->isObjCClassType()) {
// Class<protocol-list>
- Result = Context.getObjCObjectPointerType(Context.ObjCBuiltinClassTy,
- (ObjCProtocolDecl**)PQ, DS.getNumProtocolQualifiers());
+ Result = Context.getObjCObjectType(Context.ObjCBuiltinClassTy,
+ (ObjCProtocolDecl**) PQ,
+ DS.getNumProtocolQualifiers());
+ Result = Context.getObjCObjectPointerType(Result);
} else {
TheSema.Diag(DeclLoc, diag::err_invalid_protocol_qualifiers)
<< DS.getSourceRange();
@@ -504,7 +506,7 @@ QualType Sema::BuildPointerType(QualType T, unsigned Quals,
Qs.removeRestrict();
}
- assert(!T->isObjCInterfaceType() && "Should build ObjCObjectPointerType");
+ assert(!T->isObjCObjectType() && "Should build ObjCObjectPointerType");
// Build the pointer type.
return Context.getQualifiedType(Context.getPointerType(T), Qs);
@@ -659,7 +661,7 @@ QualType Sema::BuildArrayType(QualType T, ArrayType::ArraySizeModifier ASM,
// array, accept it as a GNU extension: C99 6.7.2.1p2.
if (EltTy->getDecl()->hasFlexibleArrayMember())
Diag(Loc, diag::ext_flexible_array_in_array) << T;
- } else if (T->isObjCInterfaceType()) {
+ } else if (T->isObjCObjectType()) {
Diag(Loc, diag::err_objc_array_of_interfaces) << T;
return QualType();
}
@@ -678,7 +680,7 @@ QualType Sema::BuildArrayType(QualType T, ArrayType::ArraySizeModifier ASM,
T = Context.getVariableArrayType(T, 0, ASM, Quals, Brackets);
else
T = Context.getIncompleteArrayType(T, ASM, Quals);
- } else if (ArraySize->isValueDependent()) {
+ } else if (ArraySize->isTypeDependent() || ArraySize->isValueDependent()) {
T = Context.getDependentSizedArrayType(T, ArraySize, ASM, Quals, Brackets);
} else if (!ArraySize->isIntegerConstantExpr(ConstVal, Context) ||
(!T->isDependentType() && !T->isIncompleteType() &&
@@ -707,11 +709,23 @@ QualType Sema::BuildArrayType(QualType T, ArrayType::ArraySizeModifier ASM,
}
// If this is not C99, extwarn about VLA's and C99 array size modifiers.
if (!getLangOptions().C99) {
- if (ArraySize && !ArraySize->isTypeDependent() &&
- !ArraySize->isValueDependent() &&
- !ArraySize->isIntegerConstantExpr(Context))
- Diag(Loc, getLangOptions().CPlusPlus? diag::err_vla_cxx : diag::ext_vla);
- else if (ASM != ArrayType::Normal || Quals != 0)
+ if (T->isVariableArrayType()) {
+ // Prohibit the use of non-POD types in VLAs.
+ if (!T->isDependentType() &&
+ !Context.getBaseElementType(T)->isPODType()) {
+ Diag(Loc, diag::err_vla_non_pod)
+ << Context.getBaseElementType(T);
+ return QualType();
+ }
+ // Prohibit the use of VLAs during template argument deduction.
+ else if (isSFINAEContext()) {
+ Diag(Loc, diag::err_vla_in_sfinae);
+ return QualType();
+ }
+ // Just extwarn about VLAs.
+ else
+ Diag(Loc, diag::ext_vla);
+ } else if (ASM != ArrayType::Normal || Quals != 0)
Diag(Loc,
getLangOptions().CPlusPlus? diag::err_c99_array_usage_cxx
: diag::ext_c99_array_usage);
@@ -995,10 +1009,10 @@ QualType Sema::GetTypeForDeclarator(Declarator &D, Scope *S,
break;
case Declarator::MemberContext:
switch (cast<TagDecl>(CurContext)->getTagKind()) {
- case TagDecl::TK_enum: assert(0 && "unhandled tag kind"); break;
- case TagDecl::TK_struct: Error = 1; /* Struct member */ break;
- case TagDecl::TK_union: Error = 2; /* Union member */ break;
- case TagDecl::TK_class: Error = 3; /* Class member */ break;
+ case TTK_Enum: assert(0 && "unhandled tag kind"); break;
+ case TTK_Struct: Error = 1; /* Struct member */ break;
+ case TTK_Union: Error = 2; /* Union member */ break;
+ case TTK_Class: Error = 3; /* Class member */ break;
}
break;
case Declarator::CXXCatchContext:
@@ -1056,13 +1070,9 @@ QualType Sema::GetTypeForDeclarator(Declarator &D, Scope *S,
D.setInvalidType(true);
// Build the type anyway.
}
- if (getLangOptions().ObjC1 && T->isObjCInterfaceType()) {
- const ObjCInterfaceType *OIT = T->getAs<ObjCInterfaceType>();
- T = Context.getObjCObjectPointerType(T,
- const_cast<ObjCProtocolDecl **>(
- OIT->qual_begin()),
- OIT->getNumProtocols(),
- DeclType.Ptr.TypeQuals);
+ if (getLangOptions().ObjC1 && T->getAs<ObjCObjectType>()) {
+ T = Context.getObjCObjectPointerType(T);
+ T = Context.getCVRQualifiedType(T, DeclType.Ptr.TypeQuals);
break;
}
T = BuildPointerType(T, DeclType.Ptr.TypeQuals, DeclType.Loc, Name);
@@ -1301,7 +1311,7 @@ QualType Sema::GetTypeForDeclarator(Declarator &D, Scope *S,
case NestedNameSpecifier::TypeSpecWithTemplate:
ClsType = QualType(NNS->getAsType(), 0);
if (NNSPrefix)
- ClsType = Context.getQualifiedNameType(NNSPrefix, ClsType);
+ ClsType = Context.getElaboratedType(ETK_None, NNSPrefix, ClsType);
break;
}
} else {
@@ -1401,7 +1411,18 @@ namespace {
}
void VisitObjCInterfaceTypeLoc(ObjCInterfaceTypeLoc TL) {
TL.setNameLoc(DS.getTypeSpecTypeLoc());
+ }
+ void VisitObjCObjectTypeLoc(ObjCObjectTypeLoc TL) {
+ // Handle the base type, which might not have been written explicitly.
+ if (DS.getTypeSpecType() == DeclSpec::TST_unspecified) {
+ TL.setHasBaseTypeAsWritten(false);
+ TL.getBaseLoc().initialize(SourceLocation());
+ } else {
+ TL.setHasBaseTypeAsWritten(true);
+ Visit(TL.getBaseLoc());
+ }
+ // Protocol qualifiers.
if (DS.getProtocolQualifiers()) {
assert(TL.getNumProtocols() > 0);
assert(TL.getNumProtocols() == DS.getNumProtocolQualifiers());
@@ -1416,34 +1437,8 @@ namespace {
}
}
void VisitObjCObjectPointerTypeLoc(ObjCObjectPointerTypeLoc TL) {
- assert(TL.getNumProtocols() == DS.getNumProtocolQualifiers());
-
TL.setStarLoc(SourceLocation());
-
- if (DS.getProtocolQualifiers()) {
- assert(TL.getNumProtocols() > 0);
- assert(TL.getNumProtocols() == DS.getNumProtocolQualifiers());
- TL.setHasProtocolsAsWritten(true);
- TL.setLAngleLoc(DS.getProtocolLAngleLoc());
- TL.setRAngleLoc(DS.getSourceRange().getEnd());
- for (unsigned i = 0, e = DS.getNumProtocolQualifiers(); i != e; ++i)
- TL.setProtocolLoc(i, DS.getProtocolLocs()[i]);
-
- } else {
- assert(TL.getNumProtocols() == 0);
- TL.setHasProtocolsAsWritten(false);
- TL.setLAngleLoc(SourceLocation());
- TL.setRAngleLoc(SourceLocation());
- }
-
- // This might not have been written with an inner type.
- if (DS.getTypeSpecType() == DeclSpec::TST_unspecified) {
- TL.setHasBaseTypeAsWritten(false);
- TL.getBaseTypeLoc().initialize(SourceLocation());
- } else {
- TL.setHasBaseTypeAsWritten(true);
- Visit(TL.getBaseTypeLoc());
- }
+ Visit(TL.getPointeeLoc());
}
void VisitTemplateSpecializationTypeLoc(TemplateSpecializationTypeLoc TL) {
TypeSourceInfo *TInfo = 0;
@@ -1456,9 +1451,15 @@ namespace {
return;
}
- TemplateSpecializationTypeLoc OldTL =
- cast<TemplateSpecializationTypeLoc>(TInfo->getTypeLoc());
- TL.copy(OldTL);
+ TypeLoc OldTL = TInfo->getTypeLoc();
+ if (TInfo->getType()->getAs<ElaboratedType>()) {
+ ElaboratedTypeLoc ElabTL = cast<ElaboratedTypeLoc>(OldTL);
+ TemplateSpecializationTypeLoc NamedTL =
+ cast<TemplateSpecializationTypeLoc>(ElabTL.getNamedTypeLoc());
+ TL.copy(NamedTL);
+ }
+ else
+ TL.copy(cast<TemplateSpecializationTypeLoc>(OldTL));
}
void VisitTypeOfExprTypeLoc(TypeOfExprTypeLoc TL) {
assert(DS.getTypeSpecType() == DeclSpec::TST_typeofExpr);
@@ -1489,6 +1490,44 @@ namespace {
TL.setBuiltinLoc(DS.getTypeSpecWidthLoc());
}
}
+ void VisitElaboratedTypeLoc(ElaboratedTypeLoc TL) {
+ ElaboratedTypeKeyword Keyword
+ = TypeWithKeyword::getKeywordForTypeSpec(DS.getTypeSpecType());
+ if (Keyword == ETK_Typename) {
+ TypeSourceInfo *TInfo = 0;
+ Sema::GetTypeFromParser(DS.getTypeRep(), &TInfo);
+ if (TInfo) {
+ TL.copy(cast<ElaboratedTypeLoc>(TInfo->getTypeLoc()));
+ return;
+ }
+ }
+ TL.setKeywordLoc(Keyword != ETK_None
+ ? DS.getTypeSpecTypeLoc()
+ : SourceLocation());
+ const CXXScopeSpec& SS = DS.getTypeSpecScope();
+ TL.setQualifierRange(SS.isEmpty() ? SourceRange(): SS.getRange());
+ Visit(TL.getNextTypeLoc().getUnqualifiedLoc());
+ }
+ void VisitDependentNameTypeLoc(DependentNameTypeLoc TL) {
+ ElaboratedTypeKeyword Keyword
+ = TypeWithKeyword::getKeywordForTypeSpec(DS.getTypeSpecType());
+ if (Keyword == ETK_Typename) {
+ TypeSourceInfo *TInfo = 0;
+ Sema::GetTypeFromParser(DS.getTypeRep(), &TInfo);
+ if (TInfo) {
+ TL.copy(cast<DependentNameTypeLoc>(TInfo->getTypeLoc()));
+ return;
+ }
+ }
+ TL.setKeywordLoc(Keyword != ETK_None
+ ? DS.getTypeSpecTypeLoc()
+ : SourceLocation());
+ const CXXScopeSpec& SS = DS.getTypeSpecScope();
+ TL.setQualifierRange(SS.isEmpty() ? SourceRange() : SS.getRange());
+ // FIXME: load appropriate source location.
+ TL.setNameLoc(DS.getTypeSpecTypeLoc());
+ }
+
void VisitTypeLoc(TypeLoc TL) {
// FIXME: add other typespec types and change this to an assert.
TL.initialize(DS.getTypeSpecTypeLoc());
@@ -1516,10 +1555,6 @@ namespace {
void VisitObjCObjectPointerTypeLoc(ObjCObjectPointerTypeLoc TL) {
assert(Chunk.Kind == DeclaratorChunk::Pointer);
TL.setStarLoc(Chunk.Loc);
- TL.setHasBaseTypeAsWritten(true);
- TL.setHasProtocolsAsWritten(false);
- TL.setLAngleLoc(SourceLocation());
- TL.setRAngleLoc(SourceLocation());
}
void VisitMemberPointerTypeLoc(MemberPointerTypeLoc TL) {
assert(Chunk.Kind == DeclaratorChunk::MemberPointer);
@@ -1642,6 +1677,16 @@ bool Sema::UnwrapSimilarPointerTypes(QualType& T1, QualType& T2) {
T2 = T2MPType->getPointeeType();
return true;
}
+
+ if (getLangOptions().ObjC1) {
+ const ObjCObjectPointerType *T1OPType = T1->getAs<ObjCObjectPointerType>(),
+ *T2OPType = T2->getAs<ObjCObjectPointerType>();
+ if (T1OPType && T2OPType) {
+ T1 = T1OPType->getPointeeType();
+ T2 = T2OPType->getPointeeType();
+ return true;
+ }
+ }
return false;
}
@@ -1704,7 +1749,8 @@ static void HandleAddressSpaceTypeAttribute(QualType &Type,
}
Expr *ASArgExpr = static_cast<Expr *>(Attr.getArg(0));
llvm::APSInt addrSpace(32);
- if (!ASArgExpr->isIntegerConstantExpr(addrSpace, S.Context)) {
+ if (ASArgExpr->isTypeDependent() || ASArgExpr->isValueDependent() ||
+ !ASArgExpr->isIntegerConstantExpr(addrSpace, S.Context)) {
S.Diag(Attr.getLoc(), diag::err_attribute_address_space_not_int)
<< ASArgExpr->getSourceRange();
Attr.setInvalid();
@@ -1810,7 +1856,8 @@ bool ProcessFnAttr(Sema &S, QualType &Type, const AttributeList &Attr) {
llvm::APSInt NumParams(32);
// The warning is emitted elsewhere
- if (!NumParamsExpr->isIntegerConstantExpr(NumParams, S.Context))
+ if (NumParamsExpr->isTypeDependent() || NumParamsExpr->isValueDependent() ||
+ !NumParamsExpr->isIntegerConstantExpr(NumParams, S.Context))
return false;
Type = S.Context.getRegParmType(Type, NumParams.getZExtValue());
@@ -1838,6 +1885,7 @@ bool ProcessFnAttr(Sema &S, QualType &Type, const AttributeList &Attr) {
case AttributeList::AT_cdecl: CC = CC_C; break;
case AttributeList::AT_fastcall: CC = CC_X86FastCall; break;
case AttributeList::AT_stdcall: CC = CC_X86StdCall; break;
+ case AttributeList::AT_thiscall: CC = CC_X86ThisCall; break;
default: llvm_unreachable("unexpected attribute kind"); return false;
}
@@ -1895,7 +1943,8 @@ static void HandleVectorSizeAttr(QualType& CurType, const AttributeList &Attr, S
}
Expr *sizeExpr = static_cast<Expr *>(Attr.getArg(0));
llvm::APSInt vecSize(32);
- if (!sizeExpr->isIntegerConstantExpr(vecSize, S.Context)) {
+ if (sizeExpr->isTypeDependent() || sizeExpr->isValueDependent() ||
+ !sizeExpr->isIntegerConstantExpr(vecSize, S.Context)) {
S.Diag(Attr.getLoc(), diag::err_attribute_argument_not_int)
<< "vector_size" << sizeExpr->getSourceRange();
Attr.setInvalid();
@@ -1962,6 +2011,7 @@ void ProcessTypeAttributeList(Sema &S, QualType &Result,
case AttributeList::AT_cdecl:
case AttributeList::AT_fastcall:
case AttributeList::AT_stdcall:
+ case AttributeList::AT_thiscall:
case AttributeList::AT_regparm:
// Don't process these on the DeclSpec.
if (IsDeclSpec ||
@@ -2082,15 +2132,21 @@ bool Sema::RequireCompleteType(SourceLocation Loc, QualType T,
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) {
- if (!SS.isSet() || SS.isInvalid() || T.isNull())
+/// \brief Retrieve a version of the type 'T' that is elaborated by Keyword
+/// and qualified by the nested-name-specifier contained in SS.
+QualType Sema::getElaboratedType(ElaboratedTypeKeyword Keyword,
+ const CXXScopeSpec &SS, QualType T) {
+ if (T.isNull())
return T;
-
- NestedNameSpecifier *NNS
- = static_cast<NestedNameSpecifier *>(SS.getScopeRep());
- return Context.getQualifiedNameType(NNS, T);
+ NestedNameSpecifier *NNS;
+ if (SS.isValid())
+ NNS = static_cast<NestedNameSpecifier *>(SS.getScopeRep());
+ else {
+ if (Keyword == ETK_None)
+ return T;
+ NNS = 0;
+ }
+ return Context.getElaboratedType(Keyword, NNS, T);
}
QualType Sema::BuildTypeofExprType(Expr *E) {
diff --git a/lib/Sema/TreeTransform.h b/lib/Sema/TreeTransform.h
index 5ce268bd9eb4..a18701e61d94 100644
--- a/lib/Sema/TreeTransform.h
+++ b/lib/Sema/TreeTransform.h
@@ -344,8 +344,8 @@ public:
OwningStmtResult Transform##Node(Node *S);
#define EXPR(Node, Parent) \
OwningExprResult Transform##Node(Node *E);
-#define ABSTRACT_EXPR(Node, Parent)
-#include "clang/AST/StmtNodes.def"
+#define ABSTRACT_STMT(Stmt)
+#include "clang/AST/StmtNodes.inc"
/// \brief Build a new pointer type given its pointee type.
///
@@ -492,11 +492,6 @@ public:
return SemaRef.Context.getTypeDeclType(Enum);
}
- /// \brief Build a new elaborated type.
- QualType RebuildElaboratedType(QualType T, ElaboratedType::TagKind Tag) {
- return SemaRef.Context.getElaboratedType(T, Tag);
- }
-
/// \brief Build a new typeof(expr) type.
///
/// By default, performs semantic analysis when building the typeof type.
@@ -525,19 +520,19 @@ public:
/// \brief Build a new qualified name type.
///
- /// By default, builds a new QualifiedNameType type from the
- /// nested-name-specifier and the named type. Subclasses may override
- /// this routine to provide different behavior.
- QualType RebuildQualifiedNameType(NestedNameSpecifier *NNS, QualType Named) {
- return SemaRef.Context.getQualifiedNameType(NNS, Named);
+ /// By default, builds a new ElaboratedType type from the keyword,
+ /// the nested-name-specifier and the named type.
+ /// Subclasses may override this routine to provide different behavior.
+ QualType RebuildElaboratedType(ElaboratedTypeKeyword Keyword,
+ NestedNameSpecifier *NNS, QualType Named) {
+ return SemaRef.Context.getElaboratedType(Keyword, NNS, Named);
}
/// \brief Build a new typename type that refers to a template-id.
///
- /// 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.
+ /// 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 RebuildDependentNameType(ElaboratedTypeKeyword Keyword,
NestedNameSpecifier *NNS, QualType T) {
if (NNS->isDependent()) {
@@ -548,50 +543,48 @@ public:
return SemaRef.Context.getDependentNameType(Keyword, NNS,
cast<TemplateSpecializationType>(T));
}
-
- // FIXME: Handle elaborated-type-specifiers separately.
- return SemaRef.Context.getQualifiedNameType(NNS, T);
+
+ return SemaRef.Context.getElaboratedType(Keyword, NNS, T);
}
/// \brief Build a new typename type that refers to an identifier.
///
/// By default, performs semantic analysis when building the typename type
- /// (or qualified name type). Subclasses may override this routine to provide
+ /// (or elaborated type). Subclasses may override this routine to provide
/// different behavior.
- QualType RebuildDependentNameType(ElaboratedTypeKeyword Keyword,
+ QualType RebuildDependentNameType(ElaboratedTypeKeyword Keyword,
NestedNameSpecifier *NNS,
const IdentifierInfo *Id,
- SourceRange SR) {
+ SourceLocation KeywordLoc,
+ SourceRange NNSRange,
+ SourceLocation IdLoc) {
CXXScopeSpec SS;
SS.setScopeRep(NNS);
-
+ SS.setRange(NNSRange);
+
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:
- // Fall through.
- case ETK_Typename:
- return SemaRef.CheckTypenameType(Keyword, 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
+ if (Keyword == ETK_None || Keyword == ETK_Typename)
+ return SemaRef.CheckTypenameType(Keyword, NNS, *Id,
+ KeywordLoc, NNSRange, IdLoc);
+
+ TagTypeKind Kind = TypeWithKeyword::getTagTypeKindForKeyword(Keyword);
+
+ // We had a dependent elaborated-type-specifier that has been transformed
// into a non-dependent elaborated-type-specifier. Find the tag we're
// referring to.
- LookupResult Result(SemaRef, Id, SR.getEnd(), Sema::LookupTagName);
+ LookupResult Result(SemaRef, Id, IdLoc, Sema::LookupTagName);
DeclContext *DC = SemaRef.computeDeclContext(SS, false);
if (!DC)
return QualType();
+ if (SemaRef.RequireCompleteDeclContext(SS, DC))
+ return QualType();
+
TagDecl *Tag = 0;
SemaRef.LookupQualifiedName(Result, DC);
switch (Result.getResultKind()) {
@@ -615,22 +608,20 @@ public:
if (!Tag) {
// FIXME: Would be nice to highlight just the source range.
- SemaRef.Diag(SR.getEnd(), diag::err_not_tag_in_scope)
+ SemaRef.Diag(IdLoc, 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;
+
+ if (!SemaRef.isAcceptableTagRedeclaration(Tag, Kind, IdLoc, *Id)) {
+ SemaRef.Diag(KeywordLoc, 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);
+ return SemaRef.Context.getElaboratedType(Keyword, NNS, T);
}
/// \brief Build a new nested-name-specifier given the prefix and an
@@ -769,9 +760,11 @@ public:
///
/// By default, performs semantic analysis to build the new statement.
/// Subclasses may override this routine to provide different behavior.
- OwningStmtResult RebuildSwitchStmtStart(Sema::FullExprArg Cond,
+ OwningStmtResult RebuildSwitchStmtStart(SourceLocation SwitchLoc,
+ Sema::ExprArg Cond,
VarDecl *CondVar) {
- return getSema().ActOnStartOfSwitchStmt(Cond, DeclPtrTy::make(CondVar));
+ return getSema().ActOnStartOfSwitchStmt(SwitchLoc, move(Cond),
+ DeclPtrTy::make(CondVar));
}
/// \brief Attach the body to the switch statement.
@@ -792,8 +785,8 @@ public:
Sema::FullExprArg Cond,
VarDecl *CondVar,
StmtArg Body) {
- return getSema().ActOnWhileStmt(WhileLoc, Cond, DeclPtrTy::make(CondVar),
- move(Body));
+ return getSema().ActOnWhileStmt(WhileLoc, Cond,
+ DeclPtrTy::make(CondVar), move(Body));
}
/// \brief Build a new do-while statement.
@@ -1966,13 +1959,13 @@ Sema::OwningStmtResult TreeTransform<Derived>::TransformStmt(Stmt *S) {
#define STMT(Node, Parent) \
case Stmt::Node##Class: return getDerived().Transform##Node(cast<Node>(S));
#define EXPR(Node, Parent)
-#include "clang/AST/StmtNodes.def"
+#include "clang/AST/StmtNodes.inc"
// Transform expressions by calling TransformExpr.
#define STMT(Node, Parent)
-#define ABSTRACT_EXPR(Node, Parent)
+#define ABSTRACT_STMT(Stmt)
#define EXPR(Node, Parent) case Stmt::Node##Class:
-#include "clang/AST/StmtNodes.def"
+#include "clang/AST/StmtNodes.inc"
{
Sema::OwningExprResult E = getDerived().TransformExpr(cast<Expr>(S));
if (E.isInvalid())
@@ -1994,10 +1987,10 @@ Sema::OwningExprResult TreeTransform<Derived>::TransformExpr(Expr *E) {
switch (E->getStmtClass()) {
case Stmt::NoStmtClass: break;
#define STMT(Node, Parent) case Stmt::Node##Class: break;
-#define ABSTRACT_EXPR(Node, Parent)
+#define ABSTRACT_STMT(Stmt)
#define EXPR(Node, Parent) \
case Stmt::Node##Class: return getDerived().Transform##Node(cast<Node>(E));
-#include "clang/AST/StmtNodes.def"
+#include "clang/AST/StmtNodes.inc"
}
return SemaRef.Owned(E->Retain());
@@ -2457,23 +2450,15 @@ QualType TreeTransform<Derived>::TransformPointerType(TypeLocBuilder &TLB,
return QualType();
QualType Result = TL.getType();
- if (PointeeType->isObjCInterfaceType()) {
+ if (PointeeType->getAs<ObjCObjectType>()) {
// A dependent pointer type 'T *' has is being transformed such
// that an Objective-C class type is being replaced for 'T'. The
// resulting pointer type is an ObjCObjectPointerType, not a
// PointerType.
- const ObjCInterfaceType *IFace = PointeeType->getAs<ObjCInterfaceType>();
- Result = SemaRef.Context.getObjCObjectPointerType(PointeeType,
- const_cast<ObjCProtocolDecl **>(
- IFace->qual_begin()),
- IFace->getNumProtocols());
+ Result = SemaRef.Context.getObjCObjectPointerType(PointeeType);
- ObjCObjectPointerTypeLoc NewT = TLB.push<ObjCObjectPointerTypeLoc>(Result);
- NewT.setStarLoc(TL.getSigilLoc());
- NewT.setHasProtocolsAsWritten(false);
- NewT.setLAngleLoc(SourceLocation());
- NewT.setRAngleLoc(SourceLocation());
- NewT.setHasBaseTypeAsWritten(true);
+ ObjCObjectPointerTypeLoc NewT = TLB.push<ObjCObjectPointerTypeLoc>(Result);
+ NewT.setStarLoc(TL.getStarLoc());
return Result;
}
@@ -3144,31 +3129,6 @@ QualType TreeTransform<Derived>::TransformEnumType(TypeLocBuilder &TLB,
return Result;
}
-template <typename Derived>
-QualType TreeTransform<Derived>::TransformElaboratedType(TypeLocBuilder &TLB,
- ElaboratedTypeLoc TL,
- QualType ObjectType) {
- ElaboratedType *T = TL.getTypePtr();
-
- // FIXME: this should be a nested type.
- QualType Underlying = getDerived().TransformType(T->getUnderlyingType());
- if (Underlying.isNull())
- return QualType();
-
- QualType Result = TL.getType();
- if (getDerived().AlwaysRebuild() ||
- Underlying != T->getUnderlyingType()) {
- Result = getDerived().RebuildElaboratedType(Underlying, T->getTagKind());
- if (Result.isNull())
- return QualType();
- }
-
- ElaboratedTypeLoc NewTL = TLB.push<ElaboratedTypeLoc>(Result);
- NewTL.setNameLoc(TL.getNameLoc());
-
- return Result;
-}
-
template<typename Derived>
QualType TreeTransform<Derived>::TransformInjectedClassNameType(
TypeLocBuilder &TLB,
@@ -3273,32 +3233,54 @@ QualType TreeTransform<Derived>::TransformTemplateSpecializationType(
template<typename Derived>
QualType
-TreeTransform<Derived>::TransformQualifiedNameType(TypeLocBuilder &TLB,
- QualifiedNameTypeLoc TL,
- QualType ObjectType) {
- QualifiedNameType *T = TL.getTypePtr();
- NestedNameSpecifier *NNS
- = getDerived().TransformNestedNameSpecifier(T->getQualifier(),
- SourceRange(),
- ObjectType);
- if (!NNS)
- return QualType();
+TreeTransform<Derived>::TransformElaboratedType(TypeLocBuilder &TLB,
+ ElaboratedTypeLoc TL,
+ QualType ObjectType) {
+ ElaboratedType *T = TL.getTypePtr();
- QualType Named = getDerived().TransformType(T->getNamedType());
- if (Named.isNull())
- return QualType();
+ NestedNameSpecifier *NNS = 0;
+ // NOTE: the qualifier in an ElaboratedType is optional.
+ if (T->getQualifier() != 0) {
+ NNS = getDerived().TransformNestedNameSpecifier(T->getQualifier(),
+ TL.getQualifierRange(),
+ ObjectType);
+ if (!NNS)
+ return QualType();
+ }
+
+ QualType NamedT;
+ // FIXME: this test is meant to workaround a problem (failing assertion)
+ // occurring if directly executing the code in the else branch.
+ if (isa<TemplateSpecializationTypeLoc>(TL.getNamedTypeLoc())) {
+ TemplateSpecializationTypeLoc OldNamedTL
+ = cast<TemplateSpecializationTypeLoc>(TL.getNamedTypeLoc());
+ const TemplateSpecializationType* OldTST
+ = OldNamedTL.getType()->template getAs<TemplateSpecializationType>();
+ NamedT = TransformTemplateSpecializationType(OldTST, ObjectType);
+ if (NamedT.isNull())
+ return QualType();
+ TemplateSpecializationTypeLoc NewNamedTL
+ = TLB.push<TemplateSpecializationTypeLoc>(NamedT);
+ NewNamedTL.copy(OldNamedTL);
+ }
+ else {
+ NamedT = getDerived().TransformType(TLB, TL.getNamedTypeLoc());
+ if (NamedT.isNull())
+ return QualType();
+ }
QualType Result = TL.getType();
if (getDerived().AlwaysRebuild() ||
NNS != T->getQualifier() ||
- Named != T->getNamedType()) {
- Result = getDerived().RebuildQualifiedNameType(NNS, Named);
+ NamedT != T->getNamedType()) {
+ Result = getDerived().RebuildElaboratedType(T->getKeyword(), NNS, NamedT);
if (Result.isNull())
return QualType();
}
- QualifiedNameTypeLoc NewTL = TLB.push<QualifiedNameTypeLoc>(Result);
- NewTL.setNameLoc(TL.getNameLoc());
+ ElaboratedTypeLoc NewTL = TLB.push<ElaboratedTypeLoc>(Result);
+ NewTL.setKeywordLoc(TL.getKeywordLoc());
+ NewTL.setQualifierRange(TL.getQualifierRange());
return Result;
}
@@ -3309,11 +3291,9 @@ QualType TreeTransform<Derived>::TransformDependentNameType(TypeLocBuilder &TLB,
QualType ObjectType) {
DependentNameType *T = TL.getTypePtr();
- /* FIXME: preserve source information better than this */
- SourceRange SR(TL.getNameLoc());
-
NestedNameSpecifier *NNS
- = getDerived().TransformNestedNameSpecifier(T->getQualifier(), SR,
+ = getDerived().TransformNestedNameSpecifier(T->getQualifier(),
+ TL.getQualifierRange(),
ObjectType);
if (!NNS)
return QualType();
@@ -3331,18 +3311,38 @@ QualType TreeTransform<Derived>::TransformDependentNameType(TypeLocBuilder &TLB,
NewTemplateId == QualType(TemplateId, 0))
return QualType(T, 0);
- Result = getDerived().RebuildDependentNameType(T->getKeyword(), NNS,
+ Result = getDerived().RebuildDependentNameType(T->getKeyword(), NNS,
NewTemplateId);
} else {
- Result = getDerived().RebuildDependentNameType(T->getKeyword(), NNS,
- T->getIdentifier(), SR);
+ Result = getDerived().RebuildDependentNameType(T->getKeyword(), NNS,
+ T->getIdentifier(),
+ TL.getKeywordLoc(),
+ TL.getQualifierRange(),
+ TL.getNameLoc());
}
if (Result.isNull())
return QualType();
- DependentNameTypeLoc NewTL = TLB.push<DependentNameTypeLoc>(Result);
- NewTL.setNameLoc(TL.getNameLoc());
-
+ if (const ElaboratedType* ElabT = Result->getAs<ElaboratedType>()) {
+ QualType NamedT = ElabT->getNamedType();
+ if (isa<TemplateSpecializationType>(NamedT)) {
+ TemplateSpecializationTypeLoc NamedTLoc
+ = TLB.push<TemplateSpecializationTypeLoc>(NamedT);
+ // FIXME: fill locations
+ NamedTLoc.initializeLocal(TL.getNameLoc());
+ } else {
+ TLB.pushTypeSpec(NamedT).setNameLoc(TL.getNameLoc());
+ }
+ ElaboratedTypeLoc NewTL = TLB.push<ElaboratedTypeLoc>(Result);
+ NewTL.setKeywordLoc(TL.getKeywordLoc());
+ NewTL.setQualifierRange(TL.getQualifierRange());
+ }
+ else {
+ DependentNameTypeLoc NewTL = TLB.push<DependentNameTypeLoc>(Result);
+ NewTL.setKeywordLoc(TL.getKeywordLoc());
+ NewTL.setQualifierRange(TL.getQualifierRange());
+ NewTL.setNameLoc(TL.getNameLoc());
+ }
return Result;
}
@@ -3352,6 +3352,17 @@ TreeTransform<Derived>::TransformObjCInterfaceType(TypeLocBuilder &TLB,
ObjCInterfaceTypeLoc TL,
QualType ObjectType) {
// ObjCInterfaceType is never dependent.
+ TLB.pushFullCopy(TL);
+ return TL.getType();
+}
+
+template<typename Derived>
+QualType
+TreeTransform<Derived>::TransformObjCObjectType(TypeLocBuilder &TLB,
+ ObjCObjectTypeLoc TL,
+ QualType ObjectType) {
+ // ObjCObjectType is never dependent.
+ TLB.pushFullCopy(TL);
return TL.getType();
}
@@ -3361,6 +3372,7 @@ TreeTransform<Derived>::TransformObjCObjectPointerType(TypeLocBuilder &TLB,
ObjCObjectPointerTypeLoc TL,
QualType ObjectType) {
// ObjCObjectPointerType is never dependent.
+ TLB.pushFullCopy(TL);
return TL.getType();
}
@@ -3489,10 +3501,23 @@ TreeTransform<Derived>::TransformIfStmt(IfStmt *S) {
if (Cond.isInvalid())
return SemaRef.StmtError();
+
+ // Convert the condition to a boolean value.
+ if (S->getCond()) {
+ OwningExprResult CondE = getSema().ActOnBooleanCondition(0,
+ S->getIfLoc(),
+ move(Cond));
+ if (CondE.isInvalid())
+ return getSema().StmtError();
+
+ Cond = move(CondE);
+ }
}
Sema::FullExprArg FullCond(getSema().MakeFullExpr(Cond));
-
+ if (!S->getConditionVariable() && S->getCond() && !FullCond->get())
+ return SemaRef.StmtError();
+
// Transform the "then" branch.
OwningStmtResult Then = getDerived().TransformStmt(S->getThen());
if (Then.isInvalid())
@@ -3536,11 +3561,10 @@ TreeTransform<Derived>::TransformSwitchStmt(SwitchStmt *S) {
return SemaRef.StmtError();
}
- Sema::FullExprArg FullCond(getSema().MakeFullExpr(Cond));
-
// Rebuild the switch statement.
- OwningStmtResult Switch = getDerived().RebuildSwitchStmtStart(FullCond,
- ConditionVar);
+ OwningStmtResult Switch
+ = getDerived().RebuildSwitchStmtStart(S->getSwitchLoc(), move(Cond),
+ ConditionVar);
if (Switch.isInvalid())
return SemaRef.StmtError();
@@ -3573,9 +3597,21 @@ TreeTransform<Derived>::TransformWhileStmt(WhileStmt *S) {
if (Cond.isInvalid())
return SemaRef.StmtError();
+
+ if (S->getCond()) {
+ // Convert the condition to a boolean value.
+ OwningExprResult CondE = getSema().ActOnBooleanCondition(0,
+ S->getWhileLoc(),
+ move(Cond));
+ if (CondE.isInvalid())
+ return getSema().StmtError();
+ Cond = move(CondE);
+ }
}
Sema::FullExprArg FullCond(getSema().MakeFullExpr(Cond));
+ if (!S->getConditionVariable() && S->getCond() && !FullCond->get())
+ return SemaRef.StmtError();
// Transform the body
OwningStmtResult Body = getDerived().TransformStmt(S->getBody());
@@ -3588,23 +3624,23 @@ TreeTransform<Derived>::TransformWhileStmt(WhileStmt *S) {
Body.get() == S->getBody())
return SemaRef.Owned(S->Retain());
- return getDerived().RebuildWhileStmt(S->getWhileLoc(), FullCond, ConditionVar,
- move(Body));
+ return getDerived().RebuildWhileStmt(S->getWhileLoc(), FullCond,
+ ConditionVar, move(Body));
}
template<typename Derived>
Sema::OwningStmtResult
TreeTransform<Derived>::TransformDoStmt(DoStmt *S) {
- // Transform the condition
- OwningExprResult Cond = getDerived().TransformExpr(S->getCond());
- if (Cond.isInvalid())
- return SemaRef.StmtError();
-
// Transform the body
OwningStmtResult Body = getDerived().TransformStmt(S->getBody());
if (Body.isInvalid())
return SemaRef.StmtError();
+ // Transform the condition
+ OwningExprResult Cond = getDerived().TransformExpr(S->getCond());
+ if (Cond.isInvalid())
+ return SemaRef.StmtError();
+
if (!getDerived().AlwaysRebuild() &&
Cond.get() == S->getCond() &&
Body.get() == S->getBody())
@@ -3639,13 +3675,32 @@ TreeTransform<Derived>::TransformForStmt(ForStmt *S) {
if (Cond.isInvalid())
return SemaRef.StmtError();
+
+ if (S->getCond()) {
+ // Convert the condition to a boolean value.
+ OwningExprResult CondE = getSema().ActOnBooleanCondition(0,
+ S->getForLoc(),
+ move(Cond));
+ if (CondE.isInvalid())
+ return getSema().StmtError();
+
+ Cond = move(CondE);
+ }
}
+ Sema::FullExprArg FullCond(getSema().MakeFullExpr(Cond));
+ if (!S->getConditionVariable() && S->getCond() && !FullCond->get())
+ return SemaRef.StmtError();
+
// Transform the increment
OwningExprResult Inc = getDerived().TransformExpr(S->getInc());
if (Inc.isInvalid())
return SemaRef.StmtError();
+ Sema::FullExprArg FullInc(getSema().MakeFullExpr(Inc));
+ if (S->getInc() && !FullInc->get())
+ return SemaRef.StmtError();
+
// Transform the body
OwningStmtResult Body = getDerived().TransformStmt(S->getBody());
if (Body.isInvalid())
@@ -3653,16 +3708,14 @@ TreeTransform<Derived>::TransformForStmt(ForStmt *S) {
if (!getDerived().AlwaysRebuild() &&
Init.get() == S->getInit() &&
- Cond.get() == S->getCond() &&
+ FullCond->get() == S->getCond() &&
Inc.get() == S->getInc() &&
Body.get() == S->getBody())
return SemaRef.Owned(S->Retain());
return getDerived().RebuildForStmt(S->getForLoc(), S->getLParenLoc(),
- move(Init), getSema().MakeFullExpr(Cond),
- ConditionVar,
- getSema().MakeFullExpr(Inc),
- S->getRParenLoc(), move(Body));
+ move(Init), FullCond, ConditionVar,
+ FullInc, S->getRParenLoc(), move(Body));
}
template<typename Derived>
@@ -5160,6 +5213,9 @@ TreeTransform<Derived>::TransformCXXNewExpr(CXXNewExpr *E) {
// transform the constructor arguments (if any).
ASTOwningVector<&ActionBase::DeleteExpr> ConstructorArgs(SemaRef);
for (unsigned I = 0, N = E->getNumConstructorArgs(); I != N; ++I) {
+ if (getDerived().DropCallArgument(E->getConstructorArg(I)))
+ break;
+
OwningExprResult Arg = getDerived().TransformExpr(E->getConstructorArg(I));
if (Arg.isInvalid())
return SemaRef.ExprError();
@@ -5855,7 +5911,7 @@ TreeTransform<Derived>::TransformUnresolvedMemberExpr(UnresolvedMemberExpr *Old)
R.resolveKind();
// Determine the naming class.
- if (!Old->getNamingClass()) {
+ if (Old->getNamingClass()) {
CXXRecordDecl *NamingClass
= cast_or_null<CXXRecordDecl>(getDerived().TransformDecl(
Old->getMemberLoc(),
diff --git a/test/Analysis/dead-stores.c b/test/Analysis/dead-stores.c
index 209ca6531cc2..1c600276ba43 100644
--- a/test/Analysis/dead-stores.c
+++ b/test/Analysis/dead-stores.c
@@ -450,3 +450,15 @@ int f26_nestedblocks() {
return y;
}
+// The FOREACH macro in QT uses 'break' statements within statement expressions
+// placed within the increment code of for loops.
+void rdar8014335() {
+ for (int i = 0 ; i != 10 ; ({ break; })) {
+ for ( ; ; ({ ++i; break; })) ;
+ // Note that the next value stored to 'i' is never executed
+ // because the next statement to be executed is the 'break'
+ // in the increment code of the first loop.
+ i = i * 3; // expected-warning{{Value stored to 'i' is never read}}
+ }
+}
+
diff --git a/test/Analysis/inline.c b/test/Analysis/inline.c
index acaf74ded996..50c1a54d1016 100644
--- a/test/Analysis/inline.c
+++ b/test/Analysis/inline.c
@@ -1,5 +1,5 @@
-// RUN: false
-// XFAIL: *
+// RUN: %clang_cc1 -analyze -analyzer-check-objc-mem -analyzer-inline-call -analyzer-store region -verify %s
+
int f1() {
int y = 1;
y++;
diff --git a/test/Analysis/inline2.c b/test/Analysis/inline2.c
index ec965a69c644..efdb75cc6535 100644
--- a/test/Analysis/inline2.c
+++ b/test/Analysis/inline2.c
@@ -1,5 +1,4 @@
-// RUN: false
-// XFAIL: *
+// RUN: %clang_cc1 -analyze -analyzer-check-objc-mem -analyzer-inline-call -analyzer-store region -verify %s
// Test parameter 'a' is registered to LiveVariables analysis data although it
// is not referenced in the function body.
diff --git a/test/Analysis/inline3.c b/test/Analysis/inline3.c
index 8f45858bb949..884b3ed9dc25 100644
--- a/test/Analysis/inline3.c
+++ b/test/Analysis/inline3.c
@@ -1,5 +1,4 @@
-// RUN: false
-// XFAIL: *
+// RUN: %clang_cc1 -analyze -analyzer-check-objc-mem -analyzer-inline-call -analyzer-store region -verify %s
// Test when entering f1(), we set the right AnalysisContext to Environment.
// Otherwise, block-level expr '1 && a' would not be block-level.
diff --git a/test/Analysis/inline4.c b/test/Analysis/inline4.c
index b2b3c346e374..5a1d193beb29 100644
--- a/test/Analysis/inline4.c
+++ b/test/Analysis/inline4.c
@@ -1,5 +1,5 @@
-// RUN: false
-// XFAIL: *
+// RUN: %clang_cc1 -analyze -analyzer-check-objc-mem -analyzer-inline-call -analyzer-store region -verify %s
+
int g(int a) {
return a;
}
diff --git a/test/Analysis/malloc.c b/test/Analysis/malloc.c
index 21b6d46a245e..fe24bc19e61c 100644
--- a/test/Analysis/malloc.c
+++ b/test/Analysis/malloc.c
@@ -6,16 +6,16 @@ void *realloc(void *ptr, size_t size);
void *calloc(size_t nmemb, size_t size);
void f1() {
- int *p = malloc(10);
+ int *p = malloc(12);
return; // expected-warning{{Allocated memory never released. Potential memory leak.}}
}
void f1_b() {
- int *p = malloc(10); // expected-warning{{Allocated memory never released. Potential memory leak.}}
+ int *p = malloc(12); // expected-warning{{Allocated memory never released. Potential memory leak.}}
}
void f2() {
- int *p = malloc(10);
+ int *p = malloc(12);
free(p);
free(p); // expected-warning{{Try to free a memory block that has been released}}
}
@@ -25,7 +25,7 @@ void f2() {
// or inter-procedural analysis, this is a conservative answer.
int *f3() {
static int *p = 0;
- p = malloc(10);
+ p = malloc(12);
return p; // no-warning
}
@@ -34,18 +34,18 @@ int *f3() {
// functions or inter-procedural analysis, this is a conservative answer.
static int *p_f4 = 0;
int *f4() {
- p_f4 = malloc(10);
+ p_f4 = malloc(12);
return p_f4; // no-warning
}
int *f5() {
- int *q = malloc(10);
+ int *q = malloc(12);
q = realloc(q, 20);
return q; // no-warning
}
void f6() {
- int *p = malloc(10);
+ int *p = malloc(12);
if (!p)
return; // no-warning
else
@@ -67,3 +67,13 @@ void f7() {
free(x);
x[0] = 'a'; // expected-warning{{Use dynamically allocated memory after it is freed.}}
}
+
+void PR6123() {
+ int *x = malloc(11); // expected-warning{{Cast a region whose size is not a multiple of the destination type size.}}
+}
+
+void PR7217() {
+ int *buf = malloc(2); // expected-warning{{Cast a region whose size is not a multiple of the destination type size.}}
+ buf[1] = 'c'; // not crash
+
+}
diff --git a/test/Analysis/method-call.cpp b/test/Analysis/method-call.cpp
index dd891596c5dc..47f14447d6bd 100644
--- a/test/Analysis/method-call.cpp
+++ b/test/Analysis/method-call.cpp
@@ -1,4 +1,4 @@
-// RUN: %clang_cc1 -analyze -analyzer-check-objc-mem -analyzer-store region -verify %s
+// RUN: %clang_cc1 -analyze -analyzer-check-objc-mem -analyzer-inline-call -analyzer-store region -verify %s
struct A {
int x;
A(int a) { x = a; }
diff --git a/test/Analysis/misc-ps-region-store.m b/test/Analysis/misc-ps-region-store.m
index 42551417a2a5..52516abc397b 100644
--- a/test/Analysis/misc-ps-region-store.m
+++ b/test/Analysis/misc-ps-region-store.m
@@ -1014,3 +1014,22 @@ void pr6854(void * arg) {
float f = *(float*) a;
}
+// <rdar://problem/8032791> False positive due to symbolic store not find
+// value because of 'const' qualifier
+double rdar_8032791_2();
+double rdar_8032791_1() {
+ struct R8032791 { double x[2]; double y; }
+ data[3] = {
+ {{1.0, 3.0}, 3.0}, // 1 2 3
+ {{1.0, 1.0}, 0.0}, // 1 1 2 2 3 3
+ {{1.0, 3.0}, 1.0} // 1 2 3
+ };
+
+ double x = 0.0;
+ for (unsigned i = 0 ; i < 3; i++) {
+ const struct R8032791 *p = &data[i];
+ x += p->y + rdar_8032791_2(); // no-warning
+ }
+ return x;
+}
+
diff --git a/test/Analysis/misc-ps.m b/test/Analysis/misc-ps.m
index 2b21eec18cd7..8323c62390e8 100644
--- a/test/Analysis/misc-ps.m
+++ b/test/Analysis/misc-ps.m
@@ -8,6 +8,10 @@
// RUN: %clang_cc1 -triple x86_64-apple-darwin10 -analyze -analyzer-experimental-internal-checks -analyzer-check-objc-mem -analyzer-store=region -analyzer-constraints=basic -verify -fblocks -Wno-unreachable-code %s
// RUN: %clang_cc1 -triple x86_64-apple-darwin10 -analyze -analyzer-experimental-internal-checks -analyzer-check-objc-mem -analyzer-store=region -analyzer-constraints=range -verify -fblocks -Wno-unreachable-code %s
+#ifndef __clang_analyzer__
+#error __clang__analyzer__ not defined
+#endif
+
typedef struct objc_ivar *Ivar;
typedef struct objc_selector *SEL;
typedef signed char BOOL;
@@ -957,3 +961,13 @@ void pr6938_b() {
}) == 0) {
}
}
+
+//===----------------------------------------------------------------------===//
+// <rdar://problem/7979430> - The CFG for code containing an empty
+// @synchronized block was previously broken (and would crash the analyzer).
+//===----------------------------------------------------------------------===//
+
+void r7979430(id x) {
+ @synchronized(x) {}
+}
+
diff --git a/test/Analysis/retain-release.m b/test/Analysis/retain-release.m
index 3f79c0c7f46d..9e5151d16704 100644
--- a/test/Analysis/retain-release.m
+++ b/test/Analysis/retain-release.m
@@ -1332,3 +1332,15 @@ void test_blocks_1_indirect_retain_via_call(void) {
^(NSObject *o){ [o retain]; }(number);
}
+//===--------------------------------------------------------------------===//
+// Test sending message to super that returns an object alias. Previously
+// this caused a crash in the analyzer.
+//===--------------------------------------------------------------------===//
+
+@interface Rdar8015556 : NSObject {} @end
+@implementation Rdar8015556
+- (id)retain {
+ return [super retain];
+}
+@end
+
diff --git a/test/CXX/class.access/class.friend/p1.cpp b/test/CXX/class.access/class.friend/p1.cpp
index 991698d5dcca..563ae4f63c4d 100644
--- a/test/CXX/class.access/class.friend/p1.cpp
+++ b/test/CXX/class.access/class.friend/p1.cpp
@@ -189,7 +189,7 @@ namespace test4 {
struct Inequal {};
bool test() {
Holder<Inequal> a, b;
- return a == b; // expected-note {{requested here}}
+ return a == b; // expected-note {{requested here}}
}
}
diff --git a/test/CXX/class.access/p4.cpp b/test/CXX/class.access/p4.cpp
index 1cd896613679..e8afbe7a3924 100644
--- a/test/CXX/class.access/p4.cpp
+++ b/test/CXX/class.access/p4.cpp
@@ -97,7 +97,7 @@ namespace test2 {
A A::foo; // okay
class B : A { }; // expected-error {{base class 'test2::A' has private constructor}}
- B b;
+ B b; // expected-note{{implicit default constructor}}
class C : virtual A {
public:
@@ -105,7 +105,7 @@ namespace test2 {
};
class D : C { }; // expected-error {{inherited virtual base class 'test2::A' has private constructor}}
- D d;
+ D d; // expected-note{{implicit default constructor}}
}
// Implicit destructor calls.
@@ -143,13 +143,15 @@ namespace test3 {
};
class Derived3 : // expected-error 2 {{inherited virtual base class 'Base<2>' has private destructor}} \
- // expected-error 2 {{inherited virtual base class 'Base<3>' has private destructor}}
+ // expected-error 2 {{inherited virtual base class 'Base<3>' has private destructor}} \
+ // expected-note 2{{implicit default constructor}}
Base<0>, // expected-error 2 {{base class 'Base<0>' has private destructor}}
virtual Base<1>, // expected-error 2 {{base class 'Base<1>' has private destructor}}
Base2, // expected-error 2 {{base class 'test3::Base2' has private destructor}}
virtual Base3
- {};
- Derived3 d3;
+ {};
+ Derived3 d3; // expected-note {{implicit default constructor}}\
+ // expected-note{{implicit default destructor}}}
}
// Conversion functions.
@@ -205,13 +207,13 @@ namespace test5 {
class Test1 { A a; }; // expected-error {{private member}}
void test1() {
Test1 a;
- a = Test1();
+ a = Test1(); // expected-note{{implicit default copy}}
}
class Test2 : A {}; // expected-error {{private member}}
void test2() {
Test2 a;
- a = Test2();
+ a = Test2(); // expected-note{{implicit default copy}}
}
}
@@ -224,12 +226,12 @@ namespace test6 {
class Test1 { A a; }; // expected-error {{field of type 'test6::A' has private copy constructor}}
void test1(const Test1 &t) {
- Test1 a = t;
+ Test1 a = t; // expected-note{{implicit default copy}}
}
class Test2 : A {}; // expected-error {{base class 'test6::A' has private copy constructor}}
void test2(const Test2 &t) {
- Test2 a = t;
+ Test2 a = t; // expected-note{{implicit default copy}}
}
}
diff --git a/test/CXX/dcl.dcl/basic.namespace/namespace.udecl/p8.cpp b/test/CXX/dcl.dcl/basic.namespace/namespace.udecl/p8.cpp
index fd2df010fc9b..466097171c8d 100644
--- a/test/CXX/dcl.dcl/basic.namespace/namespace.udecl/p8.cpp
+++ b/test/CXX/dcl.dcl/basic.namespace/namespace.udecl/p8.cpp
@@ -81,3 +81,18 @@ namespace test2 {
template struct Derived<int>; // expected-note {{in instantiation of template class}}
}
+
+// Redeclarations are okay in a function.
+namespace test3 {
+ namespace N {
+ int f(int);
+ typedef int type;
+ }
+
+ void g() {
+ using N::f;
+ using N::f;
+ using N::type;
+ using N::type;
+ }
+}
diff --git a/test/CXX/expr/expr.post/expr.ref/p3.cpp b/test/CXX/expr/expr.post/expr.ref/p3.cpp
new file mode 100644
index 000000000000..98771d34b63d
--- /dev/null
+++ b/test/CXX/expr/expr.post/expr.ref/p3.cpp
@@ -0,0 +1,15 @@
+// RUN: %clang_cc1 -verify -fsyntax-only %s
+
+template<typename T> struct Node {
+ int lhs;
+ void splay( )
+ {
+ Node<T> n[1];
+ (void)n->lhs;
+ }
+};
+
+void f() {
+ Node<int> n;
+ return n.splay();
+}
diff --git a/test/CXX/temp/temp.decls/temp.friend/p4.cpp b/test/CXX/temp/temp.decls/temp.friend/p4.cpp
new file mode 100644
index 000000000000..226ac0fc622f
--- /dev/null
+++ b/test/CXX/temp/temp.decls/temp.friend/p4.cpp
@@ -0,0 +1,10 @@
+// RUN: %clang_cc1 -fsyntax-only -verify %s
+
+template<typename T>
+struct X1 {
+ friend void f6(int) { } // expected-error{{redefinition of}} \
+ // expected-note{{previous definition}}
+};
+
+X1<int> x1a;
+X1<float> x1b; // expected-note {{in instantiation of}}
diff --git a/test/CXX/temp/temp.fct.spec/temp.deduct/temp.deduct.call/basic.cpp b/test/CXX/temp/temp.fct.spec/temp.deduct/temp.deduct.call/basic.cpp
index 1b7310f00055..90d29497f4b2 100644
--- a/test/CXX/temp/temp.fct.spec/temp.deduct/temp.deduct.call/basic.cpp
+++ b/test/CXX/temp/temp.fct.spec/temp.deduct/temp.deduct.call/basic.cpp
@@ -16,7 +16,8 @@ void test_f1(int *ip, float fv) {
}
// TODO: this diagnostic can and should improve
-template<typename T> void f2(T*, T*); // expected-note 2 {{candidate template ignored: failed template argument deduction}}
+template<typename T> void f2(T*, T*); // expected-note {{candidate template ignored: failed template argument deduction}} \
+// expected-note{{candidate template ignored: deduced conflicting types for parameter 'T' ('int' vs. 'float')}}
struct ConvToIntPtr {
operator int*() const;
diff --git a/test/CXX/temp/temp.fct.spec/temp.deduct/temp.deduct.call/p6.cpp b/test/CXX/temp/temp.fct.spec/temp.deduct/temp.deduct.call/p6.cpp
index 6edf079b3524..1b240cc98fc7 100644
--- a/test/CXX/temp/temp.fct.spec/temp.deduct/temp.deduct.call/p6.cpp
+++ b/test/CXX/temp/temp.fct.spec/temp.deduct/temp.deduct.call/p6.cpp
@@ -1,7 +1,7 @@
// RUN: %clang_cc1 -fsyntax-only -verify %s
namespace test0 {
- template<class T> void apply(T x, void (*f)(T)) { f(x); } // expected-note 2 {{failed template argument deduction}}\
+ template<class T> void apply(T x, void (*f)(T)) { f(x); } // expected-note 2 {{candidate template ignored: deduced conflicting types for parameter 'T'}}\
// expected-note {{no overload of 'temp2' matching 'void (*)(int)'}}
template<class A> void temp(A);
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
index 2a7f16dc6b69..bf5f96225dad 100644
--- 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
@@ -1,7 +1,7 @@
// 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}}
+template<short s> void f(A<s>); // expected-note{{candidate template ignored: substitution failure}}
void k1() {
A<1> a;
@@ -15,14 +15,14 @@ void k2() {
g(b); // OK: cv-qualifiers are ignored on template parameter types
}
-template<short s> void h(int (&)[s]); // expected-note{{failed template argument deduction}}
+template<short s> void h(int (&)[s]); // expected-note{{candidate function template not viable: requires 1 argument, but 2 were provided}}
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}}
+template<short s> void h(int (&)[s], A<s>); // expected-note{{candidate template ignored: substitution failure}}
void k4() {
A<5> a;
int array[5];
diff --git a/test/CXX/temp/temp.names/p2.cpp b/test/CXX/temp/temp.names/p2.cpp
new file mode 100644
index 000000000000..93e45dd7e3b0
--- /dev/null
+++ b/test/CXX/temp/temp.names/p2.cpp
@@ -0,0 +1,13 @@
+// RUN: %clang_cc1 -fsyntax-only -verify %s
+
+// Ensure that when enforcing access control an unqualified template name with
+// explicit template arguments, we don't lose the context of the name lookup
+// because of the required early lookup to determine if it names a template.
+namespace PR7163 {
+ template <typename R, typename P> void h(R (*func)(P)) {}
+ class C {
+ template <typename T> static void g(T*) {};
+ public:
+ void f() { h(g<int>); }
+ };
+}
diff --git a/test/CXX/temp/temp.spec/temp.explicit/p2.cpp b/test/CXX/temp/temp.spec/temp.explicit/p2.cpp
index 8538d27f09bc..0da316cc9cef 100644
--- a/test/CXX/temp/temp.spec/temp.explicit/p2.cpp
+++ b/test/CXX/temp/temp.spec/temp.explicit/p2.cpp
@@ -39,5 +39,5 @@ namespace N {
}
using namespace N;
-template struct X1<int>; // expected-error{{must occur in}}
-template void f1(int); // expected-error{{must occur in}}
+template struct X1<int>; // expected-warning{{must occur in}}
+template void f1(int); // expected-warning{{must occur in}}
diff --git a/test/CXX/temp/temp.spec/temp.explicit/p5.cpp b/test/CXX/temp/temp.spec/temp.explicit/p5.cpp
index 13fb0492f1a4..7522d02ffa19 100644
--- a/test/CXX/temp/temp.spec/temp.explicit/p5.cpp
+++ b/test/CXX/temp/temp.spec/temp.explicit/p5.cpp
@@ -11,7 +11,7 @@ template class Z<int>; // expected-error{{explicit instantiation of non-template
// FIXME: This example from the standard is wrong; note posted to CWG reflector
// on 10/27/2009
using N::Y;
-template class Y<int>; // expected-error{{must occur in}}
+template class Y<int>; // expected-warning{{must occur in}}
template class N::Y<char*>;
template void N::Y<double>::mf();
diff --git a/test/CodeCompletion/call.c b/test/CodeCompletion/call.c
index 8210389ffa56..8581414bf8c3 100644
--- a/test/CodeCompletion/call.c
+++ b/test/CodeCompletion/call.c
@@ -6,7 +6,7 @@ void test() {
f0(0, 0);
g0(0, 0);
f1(0, 0);
- // RUN: %clang_cc1 -std=c89 -fsyntax-only -code-completion-at=%s:6:6 %s -o - | FileCheck -check-prefix=CC1 %s
+ // RUN: %clang_cc1 -std=c89 -fsyntax-only -code-completion-at=%s:6:6 %s -o - | FileCheck -check-prefix=CC1 %s
// CHECK-CC1: f0(<#float x#>, float y)
// RUN: %clang_cc1 -std=c89 -fsyntax-only -code-completion-at=%s:6:9 %s -o - | FileCheck -check-prefix=CC2 %s
// CHECK-CC2: f0(float x, <#float y#>)
diff --git a/test/CodeCompletion/call.cpp b/test/CodeCompletion/call.cpp
index 1df958ed2cc0..46494e7619f5 100644
--- a/test/CodeCompletion/call.cpp
+++ b/test/CodeCompletion/call.cpp
@@ -17,7 +17,7 @@ void f();
void test() {
f(Y(), 0, 0);
- // RUN: %clang_cc1 -fsyntax-only -code-completion-at=%s:19:9 %s -o - | FileCheck -check-prefix=CC1 %s
+ // RUN: %clang_cc1 -fsyntax-only -code-completion-patterns -code-completion-at=%s:19:9 %s -o - | FileCheck -check-prefix=CC1 %s
// CHECK-CC1: COMPLETION: Pattern : dynamic_cast<<#type-id#>>(<#expression#>)
// CHECK-CC1: f(N::Y y, <#int ZZ#>)
// CHECK-CC1-NEXT: f(int i, <#int j#>, int k)
diff --git a/test/CodeCompletion/ordinary-name.cpp b/test/CodeCompletion/ordinary-name.cpp
index 699b01de74ff..20f661a28035 100644
--- a/test/CodeCompletion/ordinary-name.cpp
+++ b/test/CodeCompletion/ordinary-name.cpp
@@ -4,7 +4,7 @@ typedef struct t TYPEDEF;
void foo() {
int y = 17;
- // RUN: %clang_cc1 -fsyntax-only -code-completion-at=%s:6:14 %s -o - | FileCheck -check-prefix=CHECK-CC1 %s
+ // RUN: %clang_cc1 -fsyntax-only -code-completion-patterns -code-completion-at=%s:6:14 %s -o - | FileCheck -check-prefix=CHECK-CC1 %s
// CHECK-CC1: COMPLETION: bool
// CHECK-CC1-NEXT: COMPLETION: char
// CHECK-CC1-NEXT: COMPLETION: class
@@ -57,7 +57,7 @@ void foo() {
// CHECK-CC1-NEXT: COMPLETION: y : [#int#]y
// CHECK-CC1-NEXT: COMPLETION: z : [#void#]z(<#int#>)
- // RUN: %clang_cc1 -fsyntax-only -code-completion-at=%s:4:1 %s -o - | FileCheck -check-prefix=CHECK-CC2 %s
+ // RUN: %clang_cc1 -fsyntax-only -code-completion-patterns -code-completion-at=%s:4:1 %s -o - | FileCheck -check-prefix=CHECK-CC2 %s
// CHECK-CC2: COMPLETION: Pattern : asm(<#string-literal#>)
// CHECK-CC2-NEXT: COMPLETION: bool
// CHECK-CC2-NEXT: COMPLETION: char
@@ -93,7 +93,7 @@ void foo() {
// CHECK-CC2-NEXT: COMPLETION: wchar_t
// CHECK-CC2-NEXT: COMPLETION: X : X
- // RUN: %clang_cc1 -fsyntax-only -code-completion-at=%s:1:19 %s -o - | FileCheck -check-prefix=CHECK-CC3 %s
+ // RUN: %clang_cc1 -fsyntax-only -code-completion-patterns -code-completion-at=%s:1:19 %s -o - | FileCheck -check-prefix=CHECK-CC3 %s
// CHECK-CC3: COMPLETION: bool
// CHECK-CC3-NEXT: COMPLETION: char
// CHECK-CC3-NEXT: COMPLETION: class
@@ -129,7 +129,7 @@ void foo() {
// CHECK-CC3-NEXT: COMPLETION: wchar_t
// CHECK-CC3-NEXT: COMPLETION: X : X
- // RUN: %clang_cc1 -fsyntax-only -code-completion-at=%s:6:11 %s -o - | FileCheck -check-prefix=CHECK-CC4 %s
+ // RUN: %clang_cc1 -fsyntax-only -code-completion-patterns -code-completion-at=%s:6:11 %s -o - | FileCheck -check-prefix=CHECK-CC4 %s
// CHECK-CC4: COMPLETION: bool
// CHECK-CC4-NEXT: COMPLETION: char
// CHECK-CC4-NEXT: COMPLETION: class
diff --git a/test/CodeCompletion/truncation.c b/test/CodeCompletion/truncation.c
index 134139d78bdf..1b446b7d92ca 100644
--- a/test/CodeCompletion/truncation.c
+++ b/test/CodeCompletion/truncation.c
@@ -2,6 +2,8 @@
struct
+/* foo */
+
// RUN: %clang_cc1 -fsyntax-only -code-completion-at=%s.h:4:8 -o - %s | FileCheck -check-prefix=CC1 %s
// CHECK-CC1: X
// CHECK-CC1-NEXT: Y
@@ -9,3 +11,8 @@ struct
// CHECK-CC2: X
// CHECK-CC2: Xa
// CHECK-CC2: Y
+
+// RUN: %clang_cc1 -fsyntax-only -code-completion-at=%s:5:3 -o - %s | FileCheck -check-prefix=CC3 %s
+// CHECK-CC3: X
+// CHECK-CC3: Xa
+// CHECK-CC3: Y
diff --git a/test/CodeGen/blocks.c b/test/CodeGen/blocks.c
index e7625b19542c..a0f5dae6f44d 100644
--- a/test/CodeGen/blocks.c
+++ b/test/CodeGen/blocks.c
@@ -12,7 +12,7 @@ struct s0 {
int a[64];
};
-// RUN: grep 'internal void @__f2_block_invoke_(.struct.s0\* sret .*, .*, .* byval .*)' %t
+// RUN: grep 'internal void @__f2_block_invoke_0(.struct.s0\* sret .*, .*, .* byval .*)' %t
struct s0 f2(struct s0 a0) {
return ^(struct s0 a1){ return a1; }(a0);
}
diff --git a/test/CodeGen/builtins.c b/test/CodeGen/builtins.c
index a4424d77428f..8b6125806eff 100644
--- a/test/CodeGen/builtins.c
+++ b/test/CodeGen/builtins.c
@@ -163,3 +163,35 @@ void bar() {
}
// CHECK: }
+
+
+// CHECK: define void @test_float_builtins
+void test_float_builtins(float F, double D, long double LD) {
+ volatile int res;
+ res = __builtin_isinf(F);
+ // CHECK: call float @fabsf(float
+ // CHECK: fcmp oeq float {{.*}}, 0x7FF0000000000000
+
+ res = __builtin_isinf(D);
+ // CHECK: call double @fabs(double
+ // CHECK: fcmp oeq double {{.*}}, 0x7FF0000000000000
+
+ res = __builtin_isinf(LD);
+ // CHECK: call x86_fp80 @fabsl(x86_fp80
+ // CHECK: fcmp oeq x86_fp80 {{.*}}, 0xK7FFF8000000000000000
+
+ res = __builtin_isfinite(F);
+ // CHECK: fcmp oeq float
+ // CHECK: call float @fabsf
+ // CHECK: fcmp une float {{.*}}, 0x7FF0000000000000
+ // CHECK: and i1
+
+ res = __builtin_isnormal(F);
+ // CHECK: fcmp oeq float
+ // CHECK: call float @fabsf
+ // CHECK: fcmp ult float {{.*}}, 0x7FF0000000000000
+ // CHECK: fcmp uge float {{.*}}, 0x3810000000000000
+ // CHECK: and i1
+ // CHECK: and i1
+}
+
diff --git a/test/CodeGen/complex.c b/test/CodeGen/complex.c
index ca606109f8b2..055383ebbbe2 100644
--- a/test/CodeGen/complex.c
+++ b/test/CodeGen/complex.c
@@ -89,3 +89,7 @@ void t6() {
--ci1;
}
+// <rdar://problem/7958272>
+double t7(double _Complex c) {
+ return __builtin_fabs(__real__(c));
+}
diff --git a/test/CodeGen/microsoft-call-conv.c b/test/CodeGen/microsoft-call-conv.c
new file mode 100644
index 000000000000..95f5fa3f83b5
--- /dev/null
+++ b/test/CodeGen/microsoft-call-conv.c
@@ -0,0 +1,50 @@
+// RUN: %clang_cc1 -emit-llvm < %s | FileCheck %s
+
+void __fastcall f1(void);
+void __stdcall f2(void);
+void __thiscall f3(void);
+void __fastcall f4(void) {
+// CHECK: define x86_fastcallcc void @f4()
+ f1();
+// CHECK: call x86_fastcallcc void @f1()
+}
+void __stdcall f5(void) {
+// CHECK: define x86_stdcallcc void @f5()
+ f2();
+// CHECK: call x86_stdcallcc void @f2()
+}
+void __thiscall f6(void) {
+// CHECK: define x86_thiscallcc void @f6()
+ f3();
+// CHECK: call x86_thiscallcc void @f3()
+}
+
+// PR5280
+void (__fastcall *pf1)(void) = f1;
+void (__stdcall *pf2)(void) = f2;
+void (__thiscall *pf3)(void) = f3;
+void (__fastcall *pf4)(void) = f4;
+void (__stdcall *pf5)(void) = f5;
+void (__thiscall *pf6)(void) = f6;
+
+int main(void) {
+ f4(); f5(); f6();
+ // CHECK: call x86_fastcallcc void @f4()
+ // CHECK: call x86_stdcallcc void @f5()
+ // CHECK: call x86_thiscallcc void @f6()
+ pf1(); pf2(); pf3(); pf4(); pf5(); pf6();
+ // CHECK: call x86_fastcallcc void %{{.*}}()
+ // CHECK: call x86_stdcallcc void %{{.*}}()
+ // CHECK: call x86_thiscallcc void %{{.*}}()
+ // CHECK: call x86_fastcallcc void %{{.*}}()
+ // CHECK: call x86_stdcallcc void %{{.*}}()
+ // CHECK: call x86_thiscallcc void %{{.*}}()
+ return 0;
+}
+
+// PR7117
+void __stdcall f7(foo) int foo; {}
+void f8(void) {
+ f7(0);
+ // CHECK: call x86_stdcallcc void (...)* bitcast
+}
diff --git a/test/CodeGen/stdcall-fastcall.c b/test/CodeGen/stdcall-fastcall.c
index bea6df39f965..6f3b00328771 100644
--- a/test/CodeGen/stdcall-fastcall.c
+++ b/test/CodeGen/stdcall-fastcall.c
@@ -2,32 +2,49 @@
void __attribute__((fastcall)) f1(void);
void __attribute__((stdcall)) f2(void);
-void __attribute__((fastcall)) f3(void) {
-// CHECK: define x86_fastcallcc void @f3()
+void __attribute__((thiscall)) f3(void);
+void __attribute__((fastcall)) f4(void) {
+// CHECK: define x86_fastcallcc void @f4()
f1();
// CHECK: call x86_fastcallcc void @f1()
}
-void __attribute__((stdcall)) f4(void) {
-// CHECK: define x86_stdcallcc void @f4()
+void __attribute__((stdcall)) f5(void) {
+// CHECK: define x86_stdcallcc void @f5()
f2();
// CHECK: call x86_stdcallcc void @f2()
}
+void __attribute__((thiscall)) f6(void) {
+// CHECK: define x86_thiscallcc void @f6()
+ f3();
+// CHECK: call x86_thiscallcc void @f3()
+}
// PR5280
void (__attribute__((fastcall)) *pf1)(void) = f1;
void (__attribute__((stdcall)) *pf2)(void) = f2;
-void (__attribute__((fastcall)) *pf3)(void) = f3;
-void (__attribute__((stdcall)) *pf4)(void) = f4;
+void (__attribute__((thiscall)) *pf3)(void) = f3;
+void (__attribute__((fastcall)) *pf4)(void) = f4;
+void (__attribute__((stdcall)) *pf5)(void) = f5;
+void (__attribute__((thiscall)) *pf6)(void) = f6;
int main(void) {
- f3(); f4();
- // CHECK: call x86_fastcallcc void @f3()
- // CHECK: call x86_stdcallcc void @f4()
- pf1(); pf2(); pf3(); pf4();
+ f4(); f5(); f6();
+ // CHECK: call x86_fastcallcc void @f4()
+ // CHECK: call x86_stdcallcc void @f5()
+ // CHECK: call x86_thiscallcc void @f6()
+ pf1(); pf2(); pf3(); pf4(); pf5(); pf6();
// CHECK: call x86_fastcallcc void %{{.*}}()
// CHECK: call x86_stdcallcc void %{{.*}}()
+ // CHECK: call x86_thiscallcc void %{{.*}}()
// CHECK: call x86_fastcallcc void %{{.*}}()
// CHECK: call x86_stdcallcc void %{{.*}}()
+ // CHECK: call x86_thiscallcc void %{{.*}}()
return 0;
}
+// PR7117
+void __attribute((stdcall)) f7(foo) int foo; {}
+void f8(void) {
+ f7(0);
+ // CHECK: call x86_stdcallcc void (...)* bitcast
+}
diff --git a/test/CodeGenCXX/PR5863-unreachable-block.cpp b/test/CodeGenCXX/PR5863-unreachable-block.cpp
new file mode 100644
index 000000000000..77096153992b
--- /dev/null
+++ b/test/CodeGenCXX/PR5863-unreachable-block.cpp
@@ -0,0 +1,13 @@
+// RUN: %clang_cc1 -emit-llvm-only %s
+
+// PR5863
+class E { };
+
+void P1() {
+ try {
+ int a=0, b=0;
+ if (a > b) // simply filling in 0 or 1 doesn't trigger the assertion
+ throw E(); // commenting out 'if' or 'throw' 'fixes' the assertion failure
+ try { } catch (...) { } // empty try/catch block needed for failure
+ } catch (...) { } // this try/catch block needed for failure
+}
diff --git a/test/CodeGenCXX/PR6747.cpp b/test/CodeGenCXX/PR6747.cpp
deleted file mode 100644
index 5a07ce622013..000000000000
--- a/test/CodeGenCXX/PR6747.cpp
+++ /dev/null
@@ -1,11 +0,0 @@
-// RUN: %clang_cc1 %s -emit-llvm -o - | FileCheck %s
-
-struct foo {
- virtual void bar();
-// CHECK: define available_externally void @_ZN3foo3bazEv
- virtual void baz() {}
-};
-void zed() {
- foo b;
- b.baz();
-}
diff --git a/test/CodeGenCXX/anonymous-namespaces.cpp b/test/CodeGenCXX/anonymous-namespaces.cpp
index 695f8f59defc..fb3470ca9bee 100644
--- a/test/CodeGenCXX/anonymous-namespaces.cpp
+++ b/test/CodeGenCXX/anonymous-namespaces.cpp
@@ -1,6 +1,5 @@
// RUN: %clang_cc1 -emit-llvm %s -o - | FileCheck %s
-
int f();
namespace {
@@ -20,6 +19,13 @@ namespace {
int D::d = f();
+ // Check for generation of a VTT with internal linkage
+ // CHECK: @_ZTSN12_GLOBAL__N_11X1EE = internal constant
+ struct X {
+ struct EBase { };
+ struct E : public virtual EBase { virtual ~E() {} };
+ };
+
// CHECK: define internal i32 @_ZN12_GLOBAL__N_13fooEv()
int foo() {
return 32;
@@ -36,3 +42,5 @@ namespace {
int concrete() {
return a + foo() + A::foo();
}
+
+void test_XE() { throw X::E(); }
diff --git a/test/CodeGenCXX/anonymous-union-member-initializer.cpp b/test/CodeGenCXX/anonymous-union-member-initializer.cpp
index adb395021e73..a4da2c04fd7b 100644
--- a/test/CodeGenCXX/anonymous-union-member-initializer.cpp
+++ b/test/CodeGenCXX/anonymous-union-member-initializer.cpp
@@ -34,3 +34,47 @@ namespace PR7021 {
// CHECK: ret void
}
}
+
+namespace test2 {
+ struct A {
+ struct {
+ union {
+ int b;
+ };
+ };
+
+ A();
+ };
+
+ A::A() : b(10) { }
+ // CHECK: define void @_ZN5test21AC2Ev(
+ // CHECK-NOT: }
+ // CHECK: store i32 10
+ // CHECK: }
+}
+
+namespace test3 {
+ struct A {
+ union {
+ mutable char fibers[100];
+ struct {
+ void (*callback)(void*);
+ void *callback_value;
+ };
+ };
+
+ A();
+ };
+
+ A::A() : callback(0), callback_value(0) {}
+ // CHECK: define void @ZN5test31AC2Ev(
+ // CHECK: [[THIS:%.*]] = load
+ // CHECK-NEXT: [[UNION:%.*]] = getelementptr inbounds {{.*}} [[THIS]], i32 0, i32 0
+ // CHECK-NEXT: [[STRUCT:%.*]] = getelementptr inbounds {{.*}} [[UNION]], i32 0, i32 0
+ // CHECK-NEXT: [[CALLBACK:%.*]] = getelementptr inbounds {{.*}} [[STRUCT]], i32 0, i32 0
+ // CHECK-NEXT: store void (i8*)* null, void (i8*)** [[CALLBACK]]
+ // CHECK-NEXT: [[UNION:%.*]] = getelementptr inbounds {{.*}} [[THIS]], i32 0, i32 0
+ // CHECK-NEXT: [[STRUCT:%.*]] = getelementptr inbounds {{.*}} [[UNION]], i32 0, i32 0
+ // CHECK-NEXT: [[CVALUE:%.*]] = getelementptr inbounds {{.*}} [[STRUCT]], i32 0, i32 0
+ // CHECK-NEXT: store i8* null, void i8** [[CVALUE]]
+}
diff --git a/test/CodeGenCXX/array-value-initialize.cpp b/test/CodeGenCXX/array-value-initialize.cpp
index 5fe6c2022d8f..8a3d5ff8b6f5 100644
--- a/test/CodeGenCXX/array-value-initialize.cpp
+++ b/test/CodeGenCXX/array-value-initialize.cpp
@@ -1,4 +1,5 @@
-// RUN: %clang_cc1 -emit-llvm -o - %s
+// RUN: %clang_cc1 -triple x86_64-apple-darwin -emit-llvm -o - %s
+// RUN: %clang_cc1 -triple i386-apple-darwin -emit-llvm -o - %s
// PR5463
extern "C" int printf(...);
@@ -21,8 +22,31 @@ struct Foo {
S sbar_[5];
};
-int main(void)
-{
+int test1(void) {
Foo a;
}
+// PR7063
+
+
+struct Unit
+{
+ Unit() {}
+ Unit(const Unit& v) {}
+};
+
+
+struct Stuff
+{
+ Unit leafPos[1];
+};
+
+
+int main()
+{
+
+ Stuff a;
+ Stuff b = a;
+
+ return 0;
+} \ No newline at end of file
diff --git a/test/CodeGenCXX/c99-variable-length-array.cpp b/test/CodeGenCXX/c99-variable-length-array.cpp
new file mode 100644
index 000000000000..66c14ff579f2
--- /dev/null
+++ b/test/CodeGenCXX/c99-variable-length-array.cpp
@@ -0,0 +1,27 @@
+// RUN: %clang_cc1 -emit-llvm -o - %s | FileCheck %s
+struct X {
+ X();
+ ~X();
+};
+
+struct Y {
+ Y();
+ ~Y();
+};
+
+// CHECK: define void @_Z1fiPPKc(
+void f(int argc, const char* argv[]) {
+ // CHECK: call void @_ZN1XC1Ev
+ X x;
+ // CHECK: call i8* @llvm.stacksave(
+ const char *argv2[argc];
+ // CHECK: call void @_ZN1YC1Ev
+ Y y;
+ for (int i = 0; i != argc; ++i)
+ argv2[i] = argv[i];
+
+ // CHECK: call void @_ZN1YD1Ev
+ // CHECK: call void @llvm.stackrestore
+ // CHECK: call void @_ZN1XD1Ev
+ // CHECK: ret void
+}
diff --git a/test/CodeGenCXX/class-layout.cpp b/test/CodeGenCXX/class-layout.cpp
index 31091c5f4543..9303bdaba8bc 100644
--- a/test/CodeGenCXX/class-layout.cpp
+++ b/test/CodeGenCXX/class-layout.cpp
@@ -1,6 +1,6 @@
// RUN: %clang_cc1 %s -emit-llvm -o - | FileCheck %s
-// An extra byte shoudl be allocated for an empty class.
+// An extra byte should be allocated for an empty class.
// CHECK: %struct.A = type { i8 }
struct A { } a;
@@ -9,5 +9,5 @@ struct A { } a;
struct B { void *a; int b; } b;
// C should have a vtable pointer.
-// CHECK: %struct.C = type { i8**, i32 }
+// CHECK: %struct.C = type { i32 (...)**, i32 }
struct C { virtual void f(); int a; } *c;
diff --git a/test/CodeGenCXX/condition.cpp b/test/CodeGenCXX/condition.cpp
index e435408aa840..f5b43d2ef491 100644
--- a/test/CodeGenCXX/condition.cpp
+++ b/test/CodeGenCXX/condition.cpp
@@ -14,6 +14,7 @@ void h() {
struct X {
X();
+ X(const X&);
~X();
operator bool();
};
@@ -23,6 +24,8 @@ struct Y {
~Y();
};
+X getX();
+
void if_destruct(int z) {
// Verify that the condition variable is destroyed at the end of the
// "if" statement.
@@ -44,6 +47,14 @@ void if_destruct(int z) {
// CHECK: call void @_ZN1YD1Ev
// CHECK: br
// CHECK: call void @_ZN1XD1Ev
+
+ // CHECK: call void @_Z4getXv
+ // CHECK: call zeroext i1 @_ZN1XcvbEv
+ // CHECK: call void @_ZN1XD1Ev
+ // CHECK: br
+ if (getX()) { }
+
+ // CHECK: ret
}
struct ConvertibleToInt {
@@ -52,6 +63,8 @@ struct ConvertibleToInt {
operator int();
};
+ConvertibleToInt getConvToInt();
+
void switch_destruct(int z) {
// CHECK: call void @_ZN16ConvertibleToIntC1Ev
switch (ConvertibleToInt conv = ConvertibleToInt()) {
@@ -59,52 +72,181 @@ void switch_destruct(int z) {
break;
default:
- // CHECK: {{sw.default:|:3}}
+ // CHECK: {{sw.default:|:5}}
// CHECK: store i32 19
z = 19;
break;
}
- // CHECK: {{sw.epilog:|:5}}
+ // CHECK: {{sw.epilog:|:6}}
// CHECK: call void @_ZN16ConvertibleToIntD1Ev
// CHECK: store i32 20
z = 20;
+
+ // CHECK: call void @_Z12getConvToIntv
+ // CHECK: call i32 @_ZN16ConvertibleToIntcviEv
+ // CHECK: call void @_ZN16ConvertibleToIntD1Ev
+ switch(getConvToInt()) {
+ case 0:
+ break;
+ }
+ // CHECK: store i32 27
+ z = 27;
+ // CHECK: ret
}
int foo();
void while_destruct(int z) {
// CHECK: define void @_Z14while_destructi
- // CHECK: {{while.cond:|:2}}
+ // CHECK: {{while.cond:|:3}}
while (X x = X()) {
// CHECK: call void @_ZN1XC1Ev
- // CHECK: {{while.body:|:4}}
+ // CHECK: {{while.body:|:5}}
// CHECK: store i32 21
z = 21;
- // CHECK: {{while.cleanup:|:5}}
+ // CHECK: {{while.cleanup:|:6}}
// CHECK: call void @_ZN1XD1Ev
}
- // CHECK: {{while.end|:7}}
+ // CHECK: {{while.end|:8}}
// CHECK: store i32 22
z = 22;
+
+ // CHECK: call void @_Z4getXv
+ // CHECK: call zeroext i1 @_ZN1XcvbEv
+ // CHECK: call void @_ZN1XD1Ev
+ // CHECK: br
+ while(getX()) { }
+
+ // CHECK: store i32 25
+ z = 25;
+
+ // CHECK: ret
}
void for_destruct(int z) {
// CHECK: define void @_Z12for_destruct
// CHECK: call void @_ZN1YC1Ev
for(Y y = Y(); X x = X(); ++z)
- // CHECK: {{for.cond:|:2}}
+ // CHECK: {{for.cond:|:4}}
// CHECK: call void @_ZN1XC1Ev
- // CHECK: {{for.body:|:4}}
+ // CHECK: {{for.body:|:6}}
// CHECK: store i32 23
z = 23;
- // CHECK: {{for.inc:|:5}}
- // CHECK: br label %{{for.cond.cleanup|8}}
- // CHECK: {{for.cond.cleanup:|:8}}
+ // CHECK: {{for.inc:|:7}}
+ // CHECK: br label %{{for.cond.cleanup|10}}
+ // CHECK: {{for.cond.cleanup:|:10}}
// CHECK: call void @_ZN1XD1Ev
- // CHECK: {{for.end:|:10}}
+ // CHECK: {{for.end:|:12}}
// CHECK: call void @_ZN1YD1Ev
// CHECK: store i32 24
z = 24;
+
+ // CHECK: call void @_Z4getXv
+ // CHECK: call zeroext i1 @_ZN1XcvbEv
+ // CHECK: call void @_ZN1XD1Ev
+ // CHECK: br
+ // CHECK: call void @_Z4getXv
+ // CHECK: load
+ // CHECK: add
+ // CHECK: call void @_ZN1XD1Ev
+ int i = 0;
+ for(; getX(); getX(), ++i) { }
+ z = 26;
+ // CHECK: store i32 26
+ // CHECK: ret
}
+
+void do_destruct(int z) {
+ // CHECK: define void @_Z11do_destruct
+ do {
+ // CHECK: store i32 77
+ z = 77;
+ // CHECK: call void @_Z4getXv
+ // CHECK: call zeroext i1 @_ZN1XcvbEv
+ // CHECK: call void @_ZN1XD1Ev
+ // CHECK: br
+ } while (getX());
+ // CHECK: store i32 99
+ z = 99;
+ // CHECK: ret
+}
+
+int f(X);
+
+template<typename T>
+int instantiated(T x) {
+ int result;
+
+ // CHECK: call void @_ZN1XC1ERKS_
+ // CHECK: call i32 @_Z1f1X
+ // CHECK: call void @_ZN1XD1Ev
+ // CHECK: br
+ // CHECK: store i32 2
+ // CHECK: br
+ // CHECK: store i32 3
+ if (f(x)) { result = 2; } else { result = 3; }
+
+ // CHECK: call void @_ZN1XC1ERKS_
+ // CHECK: call i32 @_Z1f1X
+ // CHECK: call void @_ZN1XD1Ev
+ // CHECK: br
+ // CHECK: store i32 4
+ // CHECK: br
+ while (f(x)) { result = 4; }
+
+ // CHECK: call void @_ZN1XC1ERKS_
+ // CHECK: call i32 @_Z1f1X
+ // CHECK: call void @_ZN1XD1Ev
+ // CHECK: br
+ // CHECK: store i32 6
+ // CHECK: br
+ // CHECK: call void @_ZN1XC1ERKS_
+ // CHECK: call i32 @_Z1f1X
+ // CHECK: store i32 5
+ // CHECK: call void @_ZN1XD1Ev
+ // CHECK: br
+ for (; f(x); f(x), result = 5) {
+ result = 6;
+ }
+
+ // CHECK: call void @_ZN1XC1ERKS_
+ // CHECK: call i32 @_Z1f1X
+ // CHECK: call void @_ZN1XD1Ev
+ // CHECK: switch i32
+ // CHECK: store i32 7
+ // CHECK: store i32 8
+ switch (f(x)) {
+ case 0:
+ result = 7;
+ break;
+
+ case 1:
+ result = 8;
+ }
+
+ // CHECK: store i32 9
+ // CHECK: br
+ // CHECK: call void @_ZN1XC1ERKS_
+ // CHECK: call i32 @_Z1f1X
+ // CHECK: call void @_ZN1XD1Ev
+ // CHECK: br
+ do {
+ result = 9;
+ } while (f(x));
+
+ // CHECK: store i32 10
+ // CHECK: call void @_ZN1XC1ERKS_
+ // CHECK: call zeroext i1 @_ZN1XcvbEv
+ // CHECK: call void @_ZN1XD1Ev
+ // CHECK: br
+ do {
+ result = 10;
+ } while (X(x));
+
+ // CHECK: ret i32
+ return result;
+}
+
+template int instantiated(X);
diff --git a/test/CodeGenCXX/cxx-apple-kext.cpp b/test/CodeGenCXX/cxx-apple-kext.cpp
index 8d67b53657af..4ba69069bedd 100644
--- a/test/CodeGenCXX/cxx-apple-kext.cpp
+++ b/test/CodeGenCXX/cxx-apple-kext.cpp
@@ -3,9 +3,9 @@
// RUN: %clang -ccc-host-triple x86_64-apple-darwin10 %s -fapple-kext -flto -S -o - |\
// RUN: FileCheck --check-prefix=CHECK-KEXT %s
-// CHECK-NO-KEXT: @_ZTI3foo = {{.*}} @_ZTVN10__cxxabiv117
// CHECK-NO-KEXT-NOT: _GLOBAL__D_a
// CHECK-NO-KEXT: @is_hosted = global
+// CHECK-NO-KEXT: @_ZTI3foo = {{.*}} @_ZTVN10__cxxabiv117
// CHECK-NO-KEXT: call i32 @__cxa_atexit({{.*}} @_ZN3fooD1Ev
// CHECK-NO-KEXT: declare i32 @__cxa_atexit
diff --git a/test/CodeGenCXX/destructors.cpp b/test/CodeGenCXX/destructors.cpp
index d40b174012ff..1442e3740393 100644
--- a/test/CodeGenCXX/destructors.cpp
+++ b/test/CodeGenCXX/destructors.cpp
@@ -1,4 +1,4 @@
-// RUN: %clang_cc1 %s -emit-llvm -o - -mconstructor-aliases | FileCheck %s
+// RUN: %clang_cc1 %s -triple x86_64-apple-darwin10 -emit-llvm -o - -mconstructor-aliases -fexceptions | FileCheck %s
// CHECK: @_ZN5test01AD1Ev = alias {{.*}} @_ZN5test01AD2Ev
// CHECK: @_ZN5test11MD2Ev = alias {{.*}} @_ZN5test11AD2Ev
@@ -6,6 +6,10 @@
// CHECK: @_ZN5test11OD2Ev = alias {{.*}} @_ZN5test11AD2Ev
// CHECK: @_ZN5test11SD2Ev = alias bitcast {{.*}} @_ZN5test11AD2Ev
+// CHECK: @_ZN5test312_GLOBAL__N_11DD1Ev = alias internal {{.*}} @_ZN5test312_GLOBAL__N_11DD2Ev
+// CHECK: @_ZN5test312_GLOBAL__N_11DD2Ev = alias internal bitcast {{.*}} @_ZN5test312_GLOBAL__N_11CD2Ev
+// CHECK: @_ZN5test312_GLOBAL__N_11CD1Ev = alias internal {{.*}} @_ZN5test312_GLOBAL__N_11CD2Ev
+
struct A {
int a;
@@ -147,3 +151,62 @@ namespace test2 {
// CHECK: define void @_ZN5test21BD2Ev
// CHECK: call void @_ZN5test21AD2Ev
}
+
+// PR7142
+namespace test3 {
+ struct A { virtual ~A(); };
+ struct B { virtual ~B(); };
+ namespace { // internal linkage => deferred
+ struct C : A, B {}; // ~B() in D requires a this-adjustment thunk
+ struct D : C {}; // D::~D() is an alias to C::~C()
+ }
+
+ void test() {
+ new D; // Force emission of D's vtable
+ }
+
+ // Checked at top of file:
+ // @_ZN5test312_GLOBAL__N_11CD1Ev = alias internal {{.*}} @_ZN5test312_GLOBAL__N_11CD2Ev
+
+ // CHECK: define internal void @_ZN5test312_GLOBAL__N_11CD2Ev(
+ // CHECK: call void @_ZN5test31BD2Ev(
+ // CHECK: call void @_ZN5test31AD2Ev(
+ // CHECK: ret void
+
+ // CHECK: define internal void @_ZN5test312_GLOBAL__N_11DD0Ev(
+ // CHECK: call void @_ZN5test312_GLOBAL__N_11DD1Ev(
+ // CHECK: call void @_ZdlPv(
+ // CHECK: ret void
+
+ // Checked at top of file:
+ // @_ZN5test312_GLOBAL__N_11DD1Ev = alias internal {{.*}} @_ZN5test312_GLOBAL__N_11DD2Ev
+ // @_ZN5test312_GLOBAL__N_11DD2Ev = alias internal bitcast {{.*}} @_ZN5test312_GLOBAL__N_11CD2Ev
+
+ // CHECK: define internal void @_ZThn8_N5test312_GLOBAL__N_11DD1Ev(
+ // CHECK: getelementptr inbounds i8* {{.*}}, i64 -8
+ // CHECK: call void @_ZN5test312_GLOBAL__N_11DD1Ev(
+ // CHECK: ret void
+
+ // CHECK: define internal void @_ZThn8_N5test312_GLOBAL__N_11DD0Ev(
+ // CHECK: getelementptr inbounds i8* {{.*}}, i64 -8
+ // CHECK: call void @_ZN5test312_GLOBAL__N_11DD0Ev(
+ // CHECK: ret void
+
+ // CHECK: declare void @_ZN5test31BD2Ev(
+ // CHECK: declare void @_ZN5test31AD2Ev(
+
+ // CHECK: define internal void @_ZN5test312_GLOBAL__N_11CD0Ev(
+ // CHECK: call void @_ZN5test312_GLOBAL__N_11CD1Ev(
+ // CHECK: call void @_ZdlPv(
+ // CHECK: ret void
+
+ // CHECK: define internal void @_ZThn8_N5test312_GLOBAL__N_11CD1Ev(
+ // CHECK: getelementptr inbounds i8* {{.*}}, i64 -8
+ // CHECK: call void @_ZN5test312_GLOBAL__N_11CD1Ev(
+ // CHECK: ret void
+
+ // CHECK: define internal void @_ZThn8_N5test312_GLOBAL__N_11CD0Ev(
+ // CHECK: getelementptr inbounds i8* {{.*}}, i64 -8
+ // CHECK: call void @_ZN5test312_GLOBAL__N_11CD0Ev(
+ // CHECK: ret void
+}
diff --git a/test/CodeGenCXX/dynamic-cast.cpp b/test/CodeGenCXX/dynamic-cast.cpp
index aeb2a64157b4..9838e25b1d3f 100644
--- a/test/CodeGenCXX/dynamic-cast.cpp
+++ b/test/CodeGenCXX/dynamic-cast.cpp
@@ -1,8 +1,17 @@
-// RUN: %clang_cc1 %s -emit-llvm-only
-
+// RUN: %clang_cc1 -I%S %s -triple x86_64-apple-darwin10 -emit-llvm -fexceptions -o - | FileCheck %s
struct A { virtual void f(); };
struct B : A { };
+// CHECK: {{define.*@_Z1fP1A}}
+B fail;
const B& f(A *a) {
- return dynamic_cast<const B&>(*a);
+ try {
+ // CHECK: call i8* @__dynamic_cast
+ // CHECK: br i1
+ // CHECK: invoke void @__cxa_bad_cast() noreturn
+ dynamic_cast<const B&>(*a);
+ } catch (...) {
+ // CHECK: call i8* @llvm.eh.exception
+ }
+ return fail;
}
diff --git a/test/CodeGenCXX/dyncast.cpp b/test/CodeGenCXX/dyncast.cpp
index 127cdd89683d..906d44b3c5ec 100644
--- a/test/CodeGenCXX/dyncast.cpp
+++ b/test/CodeGenCXX/dyncast.cpp
@@ -20,8 +20,6 @@ extern "C" int printf(const char *str...);
void test1() {
test1_B* bp = (test1_B*)&test1_d;
test1_A* ap = &test1_d;
- // This throws
- // test1_D& dr = dynamic_cast<D&>(*bp);
test1_D* dp = dynamic_cast<test1_D*>(bp);
S(dp == 0, 1);
ap = dynamic_cast<test1_A*>(bp);
diff --git a/test/CodeGenCXX/implicit-copy-constructor.cpp b/test/CodeGenCXX/implicit-copy-constructor.cpp
new file mode 100644
index 000000000000..a343dd154cd9
--- /dev/null
+++ b/test/CodeGenCXX/implicit-copy-constructor.cpp
@@ -0,0 +1,72 @@
+// RUN: %clang_cc1 -triple x86_64-apple-darwin10 -emit-llvm -o - %s | FileCheck %s
+
+struct A {
+ A();
+ A(const A&);
+ A(A&);
+ ~A();
+};
+
+struct B {
+ B();
+ B(B&);
+};
+
+struct C {
+ C() {}
+ C(C& other, A a = A());
+ int i, j;
+};
+
+struct POD {
+ int array[3][4];
+};
+
+struct D : A, B, virtual C {
+ D();
+ int scalar;
+ int scalar_array[2][3];
+ B class_member;
+ C class_member_array[2][3];
+ POD pod_array[2][3];
+
+ union {
+ int x;
+ float f[3];
+ };
+};
+
+void f(D d) {
+ D d2(d);
+}
+
+// CHECK: define linkonce_odr void @_ZN1DC1ERS_
+// CHECK: call void @_ZN1AC1Ev
+// CHECK: call void @_ZN1CC2ERS_1A
+// CHECK: call void @_ZN1AD1Ev
+// CHECK: call void @_ZN1AC2ERS_
+// CHECK: call void @_ZN1BC2ERS_
+// CHECK: {{call void @llvm.memcpy.p0i8.p0i8.i64.*i64 24}}
+// CHECK: call void @_ZN1BC1ERS_
+// CHECK: br
+// CHECK: {{icmp ult.*, 2}}
+// CHECK: {{icmp ult.*, 3}}
+// CHECK: call void @_ZN1AC1Ev
+// CHECK: call void @_ZN1CC1ERS_1A
+// CHECK: call void @_ZN1AD1Ev
+// CHECK: {{call void @llvm.memcpy.p0i8.p0i8.i64.*i64 288}}
+// CHECK: {{call void @llvm.memcpy.p0i8.p0i8.i64.*i64 12}}
+// CHECK: ret void
+
+
+template<class T> struct X0 { void f0(T * ) { } };
+template <class > struct X1 { X1( X1& , int = 0 ) { } };
+struct X2 { X1<int> result; };
+void test_X2()
+{
+ typedef X2 impl;
+ typedef X0<impl> pimpl;
+ impl* i;
+ pimpl pdata;
+ pdata.f0( new impl(*i));
+}
diff --git a/test/CodeGenCXX/key-function-vtable.cpp b/test/CodeGenCXX/key-function-vtable.cpp
index 251a14e28f2a..1cfeb0c5022d 100644
--- a/test/CodeGenCXX/key-function-vtable.cpp
+++ b/test/CodeGenCXX/key-function-vtable.cpp
@@ -32,11 +32,20 @@ namespace {
}
testg *testgvar = new testg;
+struct X0 { virtual ~X0(); };
+struct X1 : X0 {
+ virtual void f();
+};
+
+inline void X1::f() { }
+
+void use_X1(X1 *x1) { x1->f(); }
+
// FIXME: The checks are extremely difficult to get right when the globals
// aren't alphabetized
+// CHECK: @_ZTV2X1 = weak_odr constant
// CHECK: @_ZTV5testa = constant [3 x i8*] [i8* null
// CHECK: @_ZTV5testc = weak_odr constant [3 x i8*] [i8* null
// CHECK: @_ZTVN12_GLOBAL__N_15testgE = internal constant [3 x i8*] [i8* null
// CHECK: @_ZTV5teste = weak_odr constant [3 x i8*] [i8* null
// CHECK: @_ZTV5testb = weak_odr constant [3 x i8*] [i8* null
-
diff --git a/test/CodeGenCXX/mangle-subst-std.cpp b/test/CodeGenCXX/mangle-subst-std.cpp
index 062610bd74a6..4c15eaac8835 100644
--- a/test/CodeGenCXX/mangle-subst-std.cpp
+++ b/test/CodeGenCXX/mangle-subst-std.cpp
@@ -1,5 +1,16 @@
// RUN: %clang_cc1 -emit-llvm %s -o - -triple=x86_64-apple-darwin9 | FileCheck %s
+// Check mangling of Vtables, VTTs, and construction vtables that
+// involve standard substitutions.
+
+// CHECK: @_ZTVSd = weak_odr constant
+// CHECK: @_ZTCSd0_Si = internal constant
+// CHECK: @_ZTCSd16_So = internal constant
+// CHECK: @_ZTTSd = weak_odr constant
+// CHECK: @_ZTVSo = weak_odr constant
+// CHECK: @_ZTTSo = weak_odr constant
+// CHECK: @_ZTVSi = weak_odr constant
+// CHECK: @_ZTTSi = weak_odr constant
namespace std {
struct A { A(); };
@@ -32,9 +43,30 @@ namespace std {
void f(std::string) { }
namespace std {
- template<typename, typename> struct basic_istream { };
- template<typename, typename> struct basic_ostream { };
- template<typename, typename> struct basic_iostream { };
+ template<typename, typename> struct basic_ios {
+ basic_ios(int);
+ virtual ~basic_ios();
+ };
+ template<typename charT, typename traits = char_traits<charT> >
+ struct basic_istream : virtual public basic_ios<charT, traits> {
+ basic_istream(int x) : basic_ios<charT, traits>(x), stored(x) { }
+
+ int stored;
+ };
+ template<typename charT, typename traits = char_traits<charT> >
+ struct basic_ostream : virtual public basic_ios<charT, traits> {
+ basic_ostream(int x) : basic_ios<charT, traits>(x), stored(x) { }
+
+ float stored;
+ };
+
+ template<typename charT, typename traits = char_traits<charT> >
+ struct basic_iostream : public basic_istream<charT, traits>,
+ public basic_ostream<charT, traits> {
+ basic_iostream(int x) : basic_istream<charT, traits>(x),
+ basic_ostream<charT, traits>(x),
+ basic_ios<charT, traits>(x) { }
+ };
}
// CHECK: _Z1fSi
@@ -61,3 +93,9 @@ namespace std
template<typename, typename, typename> struct basic_string { };
typedef basic_string<char, std::char_traits<char>, std::allocator<char> > not_string;
void f(not_string) { }
+
+// Manglings for instantiations caused by this function are at the
+// top of the test.
+void create_streams() {
+ std::basic_iostream<char> bio(17);
+}
diff --git a/test/CodeGenCXX/nrvo.cpp b/test/CodeGenCXX/nrvo.cpp
new file mode 100644
index 000000000000..9ee553673f18
--- /dev/null
+++ b/test/CodeGenCXX/nrvo.cpp
@@ -0,0 +1,84 @@
+// RUN: %clang_cc1 -emit-llvm -O1 -o - %s | FileCheck %s
+// RUN: %clang_cc1 -emit-llvm -fexceptions -o - %s | FileCheck --check-prefix=CHECK-EH %s
+
+// Test code generation for the named return value optimization.
+class X {
+public:
+ X();
+ X(const X&);
+ ~X();
+};
+
+// CHECK: define void @_Z5test0v
+// CHECK-EH: define void @_Z5test0v
+X test0() {
+ X x;
+ // CHECK-NOT: call void @_ZN1XD1Ev
+ // CHECK: ret void
+ // CHECK-EH: br label
+ // CHECK-EH: call void @_ZN1XD1Ev
+ // CHECK-EH: br label
+ // CHECK-EH: invoke void @_ZN1XD1Ev
+ // CHECK-EH: ret void
+ return x;
+}
+
+// CHECK: define void @_Z5test1b(
+X test1(bool B) {
+ // CHECK: call void @_ZN1XC1Ev
+ X x;
+ // CHECK-NOT: call void @_ZN1XD1Ev
+ // CHECK: ret void
+ if (B)
+ return (x);
+ return x;
+ // CHECK-EH: invoke void @_ZN1XD1Ev
+}
+
+// CHECK: define void @_Z5test2b
+// CHECK-EH: define void @_Z5test2b
+X test2(bool B) {
+ // No NRVO
+ // CHECK: call void @_ZN1XC1Ev
+ X x;
+ // CHECK: call void @_ZN1XC1Ev
+ X y;
+ // CHECK: call void @_ZN1XC1ERKS_
+ // CHECK-EH: invoke void @_ZN1XC1ERKS_
+ if (B)
+ return y;
+ // CHECK: call void @_ZN1XC1ERKS_
+ // CHECK-EH: invoke void @_ZN1XC1ERKS_
+ return x;
+ // CHECK: call void @_ZN1XD1Ev
+ // CHECK: call void @_ZN1XD1Ev
+ // CHECK: ret void
+ // CHECK-EH: invoke void @_ZN1XD1Ev
+ // CHECK-EH: invoke void @_ZN1XD1Ev
+}
+
+X test3(bool B) {
+ // FIXME: We don't manage to apply NRVO here, although we could.
+ {
+ X y;
+ return y;
+ }
+ X x;
+ return x;
+}
+
+extern "C" void exit(int) throw();
+
+// CHECK: define void @_Z5test4b
+X test4(bool B) {
+ {
+ // CHECK: tail call void @_ZN1XC1Ev
+ X x;
+ // CHECK: br i1
+ if (B)
+ return x;
+ }
+ // CHECK: tail call void @_ZN1XD1Ev
+ // CHECK: tail call void @exit(i32 1)
+ exit(1);
+}
diff --git a/test/CodeGenCXX/pointers-to-data-members.cpp b/test/CodeGenCXX/pointers-to-data-members.cpp
index d96eb03b8d82..affe1f7d18de 100644
--- a/test/CodeGenCXX/pointers-to-data-members.cpp
+++ b/test/CodeGenCXX/pointers-to-data-members.cpp
@@ -1,5 +1,5 @@
// RUN: %clang_cc1 %s -emit-llvm -o - -triple=x86_64-apple-darwin10 | FileCheck %s
-
+// RUN: %clang_cc1 %s -emit-llvm -o - -triple=x86_64-apple-darwin10 -O3 | FileCheck --check-prefix=CHECK-O3 %s
struct A { int a; int b; };
struct B { int b; };
struct C : B, A { };
@@ -35,6 +35,21 @@ namespace ZeroInit {
int A::*pa;
} s;
} ss;
+
+ struct A {
+ int A::*a;
+ int b;
+ };
+
+ struct B {
+ A a[10];
+ char c;
+ int B::*b;
+ };
+
+ struct C : A, B { int j; };
+ // CHECK: @_ZN8ZeroInit1cE = global %"struct.ZeroInit::C" { [16 x i8] c"\FF\FF\FF\FF\FF\FF\FF\FF\00\00\00\00\00\00\00\00", [176 x i8] c"\FF\FF\FF\FF\FF\FF\FF\FF\00\00\00\00\00\00\00\00\FF\FF\FF\FF\FF\FF\FF\FF\00\00\00\00\00\00\00\00\FF\FF\FF\FF\FF\FF\FF\FF\00\00\00\00\00\00\00\00\FF\FF\FF\FF\FF\FF\FF\FF\00\00\00\00\00\00\00\00\FF\FF\FF\FF\FF\FF\FF\FF\00\00\00\00\00\00\00\00\FF\FF\FF\FF\FF\FF\FF\FF\00\00\00\00\00\00\00\00\FF\FF\FF\FF\FF\FF\FF\FF\00\00\00\00\00\00\00\00\FF\FF\FF\FF\FF\FF\FF\FF\00\00\00\00\00\00\00\00\FF\FF\FF\FF\FF\FF\FF\FF\00\00\00\00\00\00\00\00\FF\FF\FF\FF\FF\FF\FF\FF\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\FF\FF\FF\FF\FF\FF\FF\FF", i32 0, [4 x i8] zeroinitializer }
+ C c;
}
// PR5674
@@ -85,3 +100,54 @@ namespace Comparisons {
if (0 == a) { }
}
}
+
+namespace ValueInit {
+
+struct A {
+ int A::*a;
+
+ char c;
+
+ A();
+};
+
+// CHECK: define void @_ZN9ValueInit1AC2Ev
+// CHECK: store i64 -1, i64*
+// CHECK: ret void
+A::A() : a() {}
+
+}
+
+namespace PR7139 {
+
+struct pair {
+ int first;
+ int second;
+};
+
+typedef int pair::*ptr_to_member_type;
+
+struct ptr_to_member_struct {
+ ptr_to_member_type data;
+ int i;
+};
+
+struct A {
+ ptr_to_member_struct a;
+
+ A() : a() {}
+};
+
+// CHECK-O3: define zeroext i1 @_ZN6PR71395checkEv() nounwind readnone
+bool check() {
+ // CHECK-O3: ret i1 true
+ return A().a.data == 0;
+}
+
+// CHECK-O3: define zeroext i1 @_ZN6PR71396check2Ev() nounwind readnone
+bool check2() {
+ // CHECK-O3: ret i1 true
+ return ptr_to_member_type() == 0;
+}
+
+}
diff --git a/test/CodeGenCXX/references.cpp b/test/CodeGenCXX/references.cpp
index 5a5947dd8162..6fc610298bd2 100644
--- a/test/CodeGenCXX/references.cpp
+++ b/test/CodeGenCXX/references.cpp
@@ -1,4 +1,4 @@
-// RUN: %clang_cc1 -verify -emit-llvm -o - %s | FileCheck %s
+// RUN: %clang_cc1 -triple x86_64-apple-darwin -verify -emit-llvm -o - %s | FileCheck %s
void t1() {
extern int& a;
int b = a;
@@ -155,3 +155,73 @@ void f0(s1 a) { s1 b = a; }
// CHECK: load
// CHECK: ret
const int &f2() { return 0; }
+
+// Don't constant fold const reference parameters with default arguments to
+// their default arguments.
+namespace N1 {
+ const int foo = 1;
+ // CHECK: @_ZN2N14test
+ int test(const int& arg = foo) {
+ // Ensure this array is on the stack where we can set values instead of
+ // being a global constant.
+ // CHECK: %args_array = alloca
+ const int* const args_array[] = { &arg };
+ }
+}
+
+// Bind to subobjects while extending the life of the complete object.
+namespace N2 {
+ class X {
+ public:
+ X(const X&);
+ X &operator=(const X&);
+ ~X();
+ };
+
+ struct P {
+ X first;
+ };
+
+ P getP();
+
+ // CHECK: define void @_ZN2N21fEi
+ // CHECK: call void @_ZN2N24getPEv
+ // CHECK: getelementptr inbounds
+ // CHECK: store i32 17
+ // CHECK: call void @_ZN2N21PD1Ev
+ void f(int i) {
+ const X& xr = getP().first;
+ i = 17;
+ }
+
+ struct SpaceWaster {
+ int i, j;
+ };
+
+ struct ReallyHasX {
+ X x;
+ };
+
+ struct HasX : ReallyHasX { };
+
+ struct HasXContainer {
+ HasX has;
+ };
+
+ struct Y : SpaceWaster, HasXContainer { };
+ struct Z : SpaceWaster, Y { };
+
+ Z getZ();
+
+ // CHECK: define void @_ZN2N21gEi
+ // CHECK: call void @_ZN2N24getZEv
+ // CHECK: {{getelementptr inbounds.*i32 0, i32 0}}
+ // CHECK: {{getelementptr inbounds.*i32 0, i32 0}}
+ // CHECK: store i32 19
+ // CHECK: call void @_ZN2N21ZD1Ev
+ // CHECK: ret void
+ void g(int i) {
+ const X &xr = getZ().has.x;
+ i = 19;
+ }
+}
diff --git a/test/CodeGenCXX/rtti-linkage.cpp b/test/CodeGenCXX/rtti-linkage.cpp
index b9eb5b4ad411..9d85a2c69ba0 100644
--- a/test/CodeGenCXX/rtti-linkage.cpp
+++ b/test/CodeGenCXX/rtti-linkage.cpp
@@ -1,47 +1,53 @@
-// RUN: %clang_cc1 %s -I%S -triple=x86_64-apple-darwin10 -emit-llvm -o - | FileCheck %s
+// RUN: %clang_cc1 %s -I%S -triple=x86_64-apple-darwin10 -emit-llvm -o - | sort | FileCheck %s
+
+// FIXME: Fails on Win32, dunno why.
+// XFAIL: win32
+
#include <typeinfo>
-// CHECK: _ZTS1B = constant
-// CHECK: _ZTS1A = weak_odr constant
+
+
+// CHECK: _ZTIN12_GLOBAL__N_11DE to
+
+
+
// CHECK: _ZTI1A = weak_odr constant
// CHECK: _ZTI1B = constant
-// CHECK: _ZTSP1C = internal constant
-// CHECK: _ZTS1C = internal constant
// CHECK: _ZTI1C = internal constant
-// CHECK: _ZTIP1C = internal constant
-// CHECK: _ZTSPP1C = internal constant
-// CHECK: _ZTIPP1C = internal constant
-// CHECK: _ZTSM1Ci = internal constant
-// CHECK: _ZTIM1Ci = internal constant
-// CHECK: _ZTSPM1Ci = internal constant
-// CHECK: _ZTIPM1Ci = internal constant
-// CHECK: _ZTSM1CS_ = internal constant
-// CHECK: _ZTIM1CS_ = internal constant
-// CHECK: _ZTSM1CPS_ = internal constant
-// CHECK: _ZTIM1CPS_ = internal constant
-// CHECK: _ZTSM1A1C = internal constant
+// CHECK: _ZTIFN12_GLOBAL__N_11DEvE = internal constant
+// CHECK: _ZTIFvN12_GLOBAL__N_11DEE = internal constant
+// CHECK: _ZTIFvvE = weak_odr
// CHECK: _ZTIM1A1C = internal constant
-// CHECK: _ZTSM1AP1C = internal constant
// CHECK: _ZTIM1AP1C = internal constant
-
-// CHECK: _ZTS1F = weak_odr constant
-
-// CHECK: _ZTSN12_GLOBAL__N_11DE = internal constant
+// CHECK: _ZTIM1CPS_ = internal constant
+// CHECK: _ZTIM1CS_ = internal constant
+// CHECK: _ZTIM1Ci = internal constant
// CHECK: _ZTIN12_GLOBAL__N_11DE = internal constant
-// CHECK: _ZTSPN12_GLOBAL__N_11DE = internal constant
+// CHECK: _ZTIN12_GLOBAL__N_11EE = internal constant
+// CHECK: _ZTIP1C = internal constant
+// CHECK: _ZTIPFvvE = weak_odr constant
+// CHECK: _ZTIPM1Ci = internal constant
// CHECK: _ZTIPN12_GLOBAL__N_11DE = internal constant
+// CHECK: _ZTIPP1C = internal constant
+// CHECK: _ZTS1A = weak_odr constant
+// CHECK: _ZTS1B = constant
+// CHECK: _ZTS1C = internal constant
+// CHECK: _ZTS1F = weak_odr constant
// CHECK: _ZTSFN12_GLOBAL__N_11DEvE = internal constant
-// CHECK: _ZTIFN12_GLOBAL__N_11DEvE = internal constant
// CHECK: _ZTSFvN12_GLOBAL__N_11DEE = internal constant
-// CHECK: _ZTIFvN12_GLOBAL__N_11DEE = internal constant
-
-// CHECK: _ZTSPFvvE = weak_odr constant
// CHECK: _ZTSFvvE = weak_odr constant
-// CHECK: _ZTIFvvE = weak_odr
-// CHECK: _ZTIPFvvE = weak_odr constant
-
+// CHECK: _ZTSM1A1C = internal constant
+// CHECK: _ZTSM1AP1C = internal constant
+// CHECK: _ZTSM1CPS_ = internal constant
+// CHECK: _ZTSM1CS_ = internal constant
+// CHECK: _ZTSM1Ci = internal constant
+// CHECK: _ZTSN12_GLOBAL__N_11DE = internal constant
// CHECK: _ZTSN12_GLOBAL__N_11EE = internal constant
-// CHECK: _ZTIN12_GLOBAL__N_11EE = internal constant
+// CHECK: _ZTSP1C = internal constant
+// CHECK: _ZTSPFvvE = weak_odr constant
+// CHECK: _ZTSPM1Ci = internal constant
+// CHECK: _ZTSPN12_GLOBAL__N_11DE = internal constant
+// CHECK: _ZTSPP1C = internal constant
// A has no key function, so its RTTI data should be weak_odr.
struct A { };
@@ -99,6 +105,5 @@ const std::type_info &t2() {
(void)typeid(E);
- // CHECK: _ZTIN12_GLOBAL__N_11DE to
return typeid(getD());
}
diff --git a/test/CodeGenCXX/static-init-3.cpp b/test/CodeGenCXX/static-init-3.cpp
new file mode 100644
index 000000000000..5bf76a61708e
--- /dev/null
+++ b/test/CodeGenCXX/static-init-3.cpp
@@ -0,0 +1,28 @@
+// RUN: %clang_cc1 -emit-llvm -triple x86_64-apple-darwin10.0.0 -o - %s | FileCheck %s
+
+// PR7050
+template<class T> struct X0 : public T { };
+
+template <class T>
+struct X1
+{
+ static T & instance;
+ // include this to provoke instantiation at pre-execution time
+ static void use(T const &) {}
+ static T & get() {
+ static X0<T> t;
+ use(instance);
+ return static_cast<T &>(t);
+ }
+};
+
+// CHECK: @_ZN2X1I2X2I1BEE8instanceE = weak global %struct.X0* null, align 8
+// CHECJ: @_ZN2X1I2X2I1AEE8instanceE = weak global %struct.X0* null, align 8
+template<class T> T & X1<T>::instance = X1<T>::get();
+
+class A { };
+class B : public A { };
+
+template<typename T> struct X2 {};
+X2< B > bg = X1< X2< B > >::get();
+X2< A > ag = X1< X2< A > >::get();
diff --git a/test/CodeGenCXX/static-init.cpp b/test/CodeGenCXX/static-init.cpp
index 750da02603b3..9ad87df8f0c3 100644
--- a/test/CodeGenCXX/static-init.cpp
+++ b/test/CodeGenCXX/static-init.cpp
@@ -2,8 +2,9 @@
// CHECK: @_ZZ1hvE1i = internal global i32 0, align 4
-// CHECK: @_ZZ2h2vE1i = weak global i32 0
-// CHECK: @_ZGVZ2h2vE1i = weak global i64 0
+// CHECK: @_ZZN5test16getvarEiE3var = internal constant [4 x i32] [i32 1, i32 0, i32 2, i32 4], align 4
+// CHECK: @_ZZ2h2vE1i = linkonce_odr global i32 0
+// CHECK: @_ZGVZ2h2vE1i = linkonce_odr global i64 0
struct A {
A();
@@ -11,7 +12,9 @@ struct A {
};
void f() {
- // CHECK: call void @_ZN1AC1Ev(
+ // CHECK: call i32 @__cxa_guard_acquire
+ // CHECK: call void @_ZN1AC1Ev
+ // CHECK: call void @__cxa_guard_release
// CHECK: call i32 @__cxa_atexit(void (i8*)* bitcast (void (%struct.A*)* @_ZN1AD1Ev to void (i8*)*), i8* getelementptr inbounds (%struct.A* @_ZZ1fvE1a, i32 0, i32 0), i8* bitcast (i8** @__dso_handle to i8*))
static A a;
}
@@ -45,3 +48,13 @@ namespace test0 {
static A r;
}
}
+
+namespace test1 {
+ // CHECK: define internal i32 @_ZN5test16getvarEi(
+ static inline int getvar(int index) {
+ static const int var[] = { 1, 0, 2, 4 };
+ return var[index];
+ }
+
+ void test() { (void) getvar(2); }
+}
diff --git a/test/CodeGenCXX/static-local-in-local-class.cpp b/test/CodeGenCXX/static-local-in-local-class.cpp
index d9e044ce9d97..ebf560ab9805 100644
--- a/test/CodeGenCXX/static-local-in-local-class.cpp
+++ b/test/CodeGenCXX/static-local-in-local-class.cpp
@@ -19,3 +19,15 @@ void X::f() {
}
(void)i;
}
+
+// pr7101
+void foo() {
+ static int n = 0;
+ struct Helper {
+ static void Execute() {
+ n++;
+ }
+ };
+ Helper::Execute();
+}
+
diff --git a/test/CodeGenCXX/template-linkage.cpp b/test/CodeGenCXX/template-linkage.cpp
index ccd61a7bbe30..63a5c09cd7d8 100644
--- a/test/CodeGenCXX/template-linkage.cpp
+++ b/test/CodeGenCXX/template-linkage.cpp
@@ -22,3 +22,23 @@ template void f<int>(int);
template <typename T> inline void g(T) { }
template void g<int>(int);
+template<typename T>
+struct X0 {
+ virtual ~X0() { }
+};
+
+template<typename T>
+struct X1 : X0<T> {
+ virtual void blarg();
+};
+
+template<typename T> void X1<T>::blarg() { }
+
+extern template struct X0<char>;
+extern template struct X1<char>;
+
+// CHECK: define linkonce_odr void @_ZN2X1IcED1Ev(
+void test_X1() {
+ X1<char> i1c;
+}
+
diff --git a/test/CodeGenCXX/threadsafe-statics-exceptions.cpp b/test/CodeGenCXX/threadsafe-statics-exceptions.cpp
new file mode 100644
index 000000000000..9347cc9616a1
--- /dev/null
+++ b/test/CodeGenCXX/threadsafe-statics-exceptions.cpp
@@ -0,0 +1,26 @@
+// RUN: %clang_cc1 -emit-llvm -o - -fexceptions -triple x86_64-apple-darwin10 %s | FileCheck %s
+
+struct X {
+ X();
+ ~X();
+};
+
+struct Y { };
+
+// CHECK: define void @_Z1fv
+void f() {
+ // CHECK: call i32 @__cxa_guard_acquire(i64* @_ZGVZ1fvE1x)
+ // CHECK: invoke void @_ZN1XC1Ev
+ // CHECK: call void @__cxa_guard_release(i64* @_ZGVZ1fvE1x)
+ // CHECK: call i32 @__cxa_atexit
+ // CHECK: br
+ static X x;
+ // CHECK: call i8* @llvm.eh.exception()
+ // CHECK: call i32 (i8*, i8*, ...)* @llvm.eh.selector
+ // CHECK: call void @__cxa_guard_abort(i64* @_ZGVZ1fvE1x)
+ // CHECK: call void @_Unwind_Resume_or_Rethrow
+ // CHECK: unreachable
+
+ // CHECK: call i8* @__cxa_allocate_exception
+ throw Y();
+}
diff --git a/test/CodeGenCXX/thunks.cpp b/test/CodeGenCXX/thunks.cpp
index b91ba3239b1e..79ca709f470d 100644
--- a/test/CodeGenCXX/thunks.cpp
+++ b/test/CodeGenCXX/thunks.cpp
@@ -86,9 +86,6 @@ void C::f() { }
}
-// This is from Test5:
-// CHECK: define linkonce_odr void @_ZTv0_n24_N5Test51B1fEv
-
// Check that the thunk gets internal linkage.
namespace {
@@ -106,7 +103,6 @@ struct C : A, B {
virtual void f();
};
-// CHECK: define internal void @_ZThn8_N12_GLOBAL__N_11C1fEv(
void C::f() { }
}
@@ -134,4 +130,112 @@ void f(B b) {
}
}
+namespace Test6 {
+ struct X {
+ X();
+ X(const X&);
+ X &operator=(const X&);
+ ~X();
+ };
+
+ struct P {
+ P();
+ P(const P&);
+ ~P();
+ X first;
+ X second;
+ };
+
+ P getP();
+
+ struct Base1 {
+ int i;
+
+ virtual X f() { return X(); }
+ };
+
+ struct Base2 {
+ float real;
+
+ virtual X f() { return X(); }
+ };
+
+ struct Thunks : Base1, Base2 {
+ long l;
+
+ virtual X f();
+ };
+
+ // CHECK: define void @_ZThn16_N5Test66Thunks1fEv
+ // CHECK-NOT: memcpy
+ // CHECK: {{call void @_ZN5Test66Thunks1fEv.*sret}}
+ // CHECK: ret void
+ X Thunks::f() { return X(); }
+}
+
+namespace Test7 {
+ // PR7188
+ struct X {
+ X();
+ X(const X&);
+ X &operator=(const X&);
+ ~X();
+ };
+
+ struct Small { short s; };
+ struct Large {
+ char array[1024];
+ };
+
+ class A {
+ protected:
+ virtual void foo() = 0;
+ };
+
+ class B : public A {
+ protected:
+ virtual void bar() = 0;
+ };
+
+ class C : public A {
+ protected:
+ virtual void baz(X, X&, _Complex float, Small, Small&, Large) = 0;
+ };
+
+ class D : public B,
+ public C {
+
+ void foo() {}
+ void bar() {}
+ void baz(X, X&, _Complex float, Small, Small&, Large);
+ };
+
+ void D::baz(X, X&, _Complex float, Small, Small&, Large) { }
+
+ // CHECK: define void @_ZThn8_N5Test71D3bazENS_1XERS1_CfNS_5SmallERS4_NS_5LargeE(
+ // CHECK-NOT: memcpy
+ // CHECK: ret void
+ void testD() { D d; }
+}
+
+namespace Test8 {
+ struct NonPOD { ~NonPOD(); int x, y, z; };
+ struct A { virtual void foo(); };
+ struct B { virtual void bar(NonPOD); };
+ struct C : A, B { virtual void bar(NonPOD); static void helper(NonPOD); };
+
+ // CHECK: define void @_ZN5Test81C6helperENS_6NonPODE([[NONPODTYPE:%.*]]*
+ void C::helper(NonPOD var) {}
+
+ // CHECK: define void @_ZThn8_N5Test81C3barENS_6NonPODE(
+ // CHECK-NOT: load [[NONPODTYPE]]*
+ // CHECK-NOT: memcpy
+ // CHECK: ret void
+ void C::bar(NonPOD var) {}
+}
+
+/**** The following has to go at the end of the file ****/
+// This is from Test5:
+// CHECK: define linkonce_odr void @_ZTv0_n24_N5Test51B1fEv
+// CHECK: define internal void @_ZThn8_N12_GLOBAL__N_11C1fEv(
diff --git a/test/CodeGenCXX/virtual-base-destructor-call.cpp b/test/CodeGenCXX/virtual-base-destructor-call.cpp
index 7de9dd2a6085..22c49a089d0d 100644
--- a/test/CodeGenCXX/virtual-base-destructor-call.cpp
+++ b/test/CodeGenCXX/virtual-base-destructor-call.cpp
@@ -49,3 +49,4 @@ int main() {
// CHECK: define linkonce_odr void @_ZN13basic_istreamIcED2Ev
// CHECK-NOT: call
// CHECK: }
+
diff --git a/test/CodeGenCXX/virtual-functions-incomplete-types.cpp b/test/CodeGenCXX/virtual-functions-incomplete-types.cpp
index 50e04357b390..991c2bc7220f 100644
--- a/test/CodeGenCXX/virtual-functions-incomplete-types.cpp
+++ b/test/CodeGenCXX/virtual-functions-incomplete-types.cpp
@@ -9,6 +9,7 @@ struct B {
void B::f() { }
+// CHECK: define i64 @_ZN1D1gEv(%struct.B* %this)
// CHECK: declare void @_ZN1B1gEv()
struct C;
@@ -24,7 +25,6 @@ struct C {
int a;
};
-// CHECK: define i64 @_ZN1D1gEv(%struct.B* %this)
C D::g() {
return C();
}
diff --git a/test/CodeGenCXX/vtable-layout.cpp b/test/CodeGenCXX/vtable-layout.cpp
index f2f5179d4a19..60b46fec39b3 100644
--- a/test/CodeGenCXX/vtable-layout.cpp
+++ b/test/CodeGenCXX/vtable-layout.cpp
@@ -1,4 +1,46 @@
-// RUN: %clang_cc1 %s -triple=x86_64-apple-darwin10 -emit-llvm-only -fdump-vtable-layouts 2>&1 | FileCheck %s
+// RUN: %clang_cc1 %s -triple=x86_64-apple-darwin10 -emit-llvm-only -fdump-vtable-layouts > %t 2>&1
+// RUN: FileCheck --check-prefix=CHECK-1 %s < %t
+// RUN: FileCheck --check-prefix=CHECK-2 %s < %t
+// RUN: FileCheck --check-prefix=CHECK-3 %s < %t
+// RUN: FileCheck --check-prefix=CHECK-4 %s < %t
+// RUN: FileCheck --check-prefix=CHECK-5 %s < %t
+// RUN: FileCheck --check-prefix=CHECK-6 %s < %t
+// RUN: FileCheck --check-prefix=CHECK-7 %s < %t
+// RUN: FileCheck --check-prefix=CHECK-8 %s < %t
+// RUN: FileCheck --check-prefix=CHECK-9 %s < %t
+// RUN: FileCheck --check-prefix=CHECK-10 %s < %t
+// RUN: FileCheck --check-prefix=CHECK-11 %s < %t
+// RUN: FileCheck --check-prefix=CHECK-12 %s < %t
+// RUN: FileCheck --check-prefix=CHECK-13 %s < %t
+// RUN: FileCheck --check-prefix=CHECK-14 %s < %t
+// RUN: FileCheck --check-prefix=CHECK-15 %s < %t
+// RUN: FileCheck --check-prefix=CHECK-16 %s < %t
+// RUN: FileCheck --check-prefix=CHECK-17 %s < %t
+// RUN: FileCheck --check-prefix=CHECK-18 %s < %t
+// RUN: FileCheck --check-prefix=CHECK-19 %s < %t
+// RUN: FileCheck --check-prefix=CHECK-20 %s < %t
+// RUN: FileCheck --check-prefix=CHECK-21 %s < %t
+// RUN: FileCheck --check-prefix=CHECK-22 %s < %t
+// RUN: FileCheck --check-prefix=CHECK-23 %s < %t
+// RUN: FileCheck --check-prefix=CHECK-24 %s < %t
+// RUN: FileCheck --check-prefix=CHECK-25 %s < %t
+// RUN: FileCheck --check-prefix=CHECK-26 %s < %t
+// RUN: FileCheck --check-prefix=CHECK-27 %s < %t
+// RUN: FileCheck --check-prefix=CHECK-28 %s < %t
+// RUN: FileCheck --check-prefix=CHECK-29 %s < %t
+// RUN: FileCheck --check-prefix=CHECK-30 %s < %t
+// RUN: FileCheck --check-prefix=CHECK-31 %s < %t
+// RUN: FileCheck --check-prefix=CHECK-32 %s < %t
+// RUN: FileCheck --check-prefix=CHECK-33 %s < %t
+// RUN: FileCheck --check-prefix=CHECK-34 %s < %t
+// RUN: FileCheck --check-prefix=CHECK-35 %s < %t
+// RUN: FileCheck --check-prefix=CHECK-36 %s < %t
+// RUN: FileCheck --check-prefix=CHECK-37 %s < %t
+// RUN: FileCheck --check-prefix=CHECK-38 %s < %t
+// RUN: FileCheck --check-prefix=CHECK-39 %s < %t
+// RUN: FileCheck --check-prefix=CHECK-40 %s < %t
+// RUN: FileCheck --check-prefix=CHECK-41 %s < %t
+// RUN: FileCheck --check-prefix=CHECK-42 %s < %t
// For now, just verify this doesn't crash.
namespace test0 {
@@ -11,11 +53,11 @@ namespace test0 {
}
namespace Test1 {
-// CHECK: Vtable for 'Test1::A' (3 entries).
-// CHECK-NEXT: 0 | offset_to_top (0)
-// CHECK-NEXT: 1 | Test1::A RTTI
-// CHECK-NEXT: -- (Test1::A, 0) vtable address --
-// CHECK-NEXT: 2 | void Test1::A::f()
+// CHECK-1: Vtable for 'Test1::A' (3 entries).
+// CHECK-1-NEXT: 0 | offset_to_top (0)
+// CHECK-1-NEXT: 1 | Test1::A RTTI
+// CHECK-1-NEXT: -- (Test1::A, 0) vtable address --
+// CHECK-1-NEXT: 2 | void Test1::A::f()
struct A {
virtual void f();
};
@@ -26,17 +68,17 @@ void A::f() { }
namespace Test2 {
// This is a smoke test of the vtable dumper.
-// CHECK: Vtable for 'Test2::A' (9 entries).
-// CHECK-NEXT: 0 | offset_to_top (0)
-// CHECK-NEXT: 1 | Test2::A RTTI
-// CHECK-NEXT: -- (Test2::A, 0) vtable address --
-// CHECK-NEXT: 2 | void Test2::A::f()
-// CHECK-NEXT: 3 | void Test2::A::f() const
-// CHECK-NEXT: 4 | Test2::A *Test2::A::g(int)
-// CHECK-NEXT: 5 | Test2::A::~A() [complete]
-// CHECK-NEXT: 6 | Test2::A::~A() [deleting]
-// CHECK-NEXT: 7 | void Test2::A::h()
-// CHECK-NEXT: 8 | Test2::A &Test2::A::operator=(Test2::A const &)
+// CHECK-2: Vtable for 'Test2::A' (9 entries).
+// CHECK-2-NEXT: 0 | offset_to_top (0)
+// CHECK-2-NEXT: 1 | Test2::A RTTI
+// CHECK-2-NEXT: -- (Test2::A, 0) vtable address --
+// CHECK-2-NEXT: 2 | void Test2::A::f()
+// CHECK-2-NEXT: 3 | void Test2::A::f() const
+// CHECK-2-NEXT: 4 | Test2::A *Test2::A::g(int)
+// CHECK-2-NEXT: 5 | Test2::A::~A() [complete]
+// CHECK-2-NEXT: 6 | Test2::A::~A() [deleting]
+// CHECK-2-NEXT: 7 | void Test2::A::h()
+// CHECK-2-NEXT: 8 | Test2::A &Test2::A::operator=(Test2::A const &)
struct A {
virtual void f();
virtual void f() const;
@@ -50,14 +92,14 @@ void A::f() { }
// Another simple vtable dumper test.
-// CHECK: Vtable for 'Test2::B' (6 entries).
-// CHECK-NEXT: 0 | offset_to_top (0)
-// CHECK-NEXT: 1 | Test2::B RTTI
-// CHECK-NEXT: -- (Test2::B, 0) vtable address --
-// CHECK-NEXT: 2 | void Test2::B::f()
-// CHECK-NEXT: 3 | void Test2::B::g() [pure]
-// CHECK-NEXT: 4 | Test2::B::~B() [complete] [pure]
-// CHECK-NEXT: 5 | Test2::B::~B() [deleting] [pure]
+// CHECK-3: Vtable for 'Test2::B' (6 entries).
+// CHECK-3-NEXT: 0 | offset_to_top (0)
+// CHECK-3-NEXT: 1 | Test2::B RTTI
+// CHECK-3-NEXT: -- (Test2::B, 0) vtable address --
+// CHECK-3-NEXT: 2 | void Test2::B::f()
+// CHECK-3-NEXT: 3 | void Test2::B::g() [pure]
+// CHECK-3-NEXT: 4 | Test2::B::~B() [complete] [pure]
+// CHECK-3-NEXT: 5 | Test2::B::~B() [deleting] [pure]
struct B {
virtual void f();
virtual void g() = 0;
@@ -73,52 +115,52 @@ namespace Test3 {
// then the function should not have an entry in the derived class (unless the return
// value requires adjusting).
-// CHECK: Vtable for 'Test3::A' (3 entries).
-// CHECK-NEXT: 0 | offset_to_top (0)
-// CHECK-NEXT: 1 | Test3::A RTTI
-// CHECK-NEXT: -- (Test3::A, 0) vtable address --
-// CHECK-NEXT: 2 | void Test3::A::f()
+// CHECK-4: Vtable for 'Test3::A' (3 entries).
+// CHECK-4-NEXT: 0 | offset_to_top (0)
+// CHECK-4-NEXT: 1 | Test3::A RTTI
+// CHECK-4-NEXT: -- (Test3::A, 0) vtable address --
+// CHECK-4-NEXT: 2 | void Test3::A::f()
struct A {
virtual void f();
};
void A::f() { }
-// CHECK: Vtable for 'Test3::B' (4 entries).
-// CHECK-NEXT: 0 | offset_to_top (0)
-// CHECK-NEXT: 1 | Test3::B RTTI
-// CHECK-NEXT: -- (Test3::A, 0) vtable address --
-// CHECK-NEXT: -- (Test3::B, 0) vtable address --
-// CHECK-NEXT: 2 | void Test3::B::f()
-// CHECK-NEXT: 3 | void Test3::B::g()
+// CHECK-5: Vtable for 'Test3::B' (4 entries).
+// CHECK-5-NEXT: 0 | offset_to_top (0)
+// CHECK-5-NEXT: 1 | Test3::B RTTI
+// CHECK-5-NEXT: -- (Test3::A, 0) vtable address --
+// CHECK-5-NEXT: -- (Test3::B, 0) vtable address --
+// CHECK-5-NEXT: 2 | void Test3::B::f()
+// CHECK-5-NEXT: 3 | void Test3::B::g()
struct B : A {
virtual void f();
virtual void g();
};
void B::f() { }
-// CHECK: Vtable for 'Test3::C' (5 entries).
-// CHECK-NEXT: 0 | offset_to_top (0)
-// CHECK-NEXT: 1 | Test3::C RTTI
-// CHECK-NEXT: -- (Test3::A, 0) vtable address --
-// CHECK-NEXT: -- (Test3::C, 0) vtable address --
-// CHECK-NEXT: 2 | void Test3::A::f()
-// CHECK-NEXT: 3 | void Test3::C::g()
-// CHECK-NEXT: 4 | void Test3::C::h()
+// CHECK-6: Vtable for 'Test3::C' (5 entries).
+// CHECK-6-NEXT: 0 | offset_to_top (0)
+// CHECK-6-NEXT: 1 | Test3::C RTTI
+// CHECK-6-NEXT: -- (Test3::A, 0) vtable address --
+// CHECK-6-NEXT: -- (Test3::C, 0) vtable address --
+// CHECK-6-NEXT: 2 | void Test3::A::f()
+// CHECK-6-NEXT: 3 | void Test3::C::g()
+// CHECK-6-NEXT: 4 | void Test3::C::h()
struct C : A {
virtual void g();
virtual void h();
};
void C::g() { }
-// CHECK: Vtable for 'Test3::D' (5 entries).
-// CHECK-NEXT: 0 | offset_to_top (0)
-// CHECK-NEXT: 1 | Test3::D RTTI
-// CHECK-NEXT: -- (Test3::A, 0) vtable address --
-// CHECK-NEXT: -- (Test3::B, 0) vtable address --
-// CHECK-NEXT: -- (Test3::D, 0) vtable address --
-// CHECK-NEXT: 2 | void Test3::D::f()
-// CHECK-NEXT: 3 | void Test3::D::g()
-// CHECK-NEXT: 4 | void Test3::D::h()
+// CHECK-7: Vtable for 'Test3::D' (5 entries).
+// CHECK-7-NEXT: 0 | offset_to_top (0)
+// CHECK-7-NEXT: 1 | Test3::D RTTI
+// CHECK-7-NEXT: -- (Test3::A, 0) vtable address --
+// CHECK-7-NEXT: -- (Test3::B, 0) vtable address --
+// CHECK-7-NEXT: -- (Test3::D, 0) vtable address --
+// CHECK-7-NEXT: 2 | void Test3::D::f()
+// CHECK-7-NEXT: 3 | void Test3::D::g()
+// CHECK-7-NEXT: 4 | void Test3::D::h()
struct D : B {
virtual void f();
virtual void g();
@@ -140,14 +182,14 @@ struct A {
virtual R2 *f();
};
-// CHECK: Vtable for 'Test4::B' (4 entries).
-// CHECK-NEXT: 0 | offset_to_top (0)
-// CHECK-NEXT: 1 | Test4::B RTTI
-// CHECK-NEXT: -- (Test4::A, 0) vtable address --
-// CHECK-NEXT: -- (Test4::B, 0) vtable address --
-// CHECK-NEXT: 2 | Test4::R3 *Test4::B::f()
-// CHECK-NEXT: [return adjustment: 4 non-virtual]
-// CHECK-NEXT: 3 | Test4::R3 *Test4::B::f()
+// CHECK-8: Vtable for 'Test4::B' (4 entries).
+// CHECK-8-NEXT: 0 | offset_to_top (0)
+// CHECK-8-NEXT: 1 | Test4::B RTTI
+// CHECK-8-NEXT: -- (Test4::A, 0) vtable address --
+// CHECK-8-NEXT: -- (Test4::B, 0) vtable address --
+// CHECK-8-NEXT: 2 | Test4::R3 *Test4::B::f()
+// CHECK-8-NEXT: [return adjustment: 4 non-virtual]
+// CHECK-8-NEXT: 3 | Test4::R3 *Test4::B::f()
struct B : A {
virtual R3 *f();
@@ -162,14 +204,14 @@ struct C {
virtual V1 *f();
};
-// CHECK: Vtable for 'Test4::D' (4 entries).
-// CHECK-NEXT: 0 | offset_to_top (0)
-// CHECK-NEXT: 1 | Test4::D RTTI
-// CHECK-NEXT: -- (Test4::C, 0) vtable address --
-// CHECK-NEXT: -- (Test4::D, 0) vtable address --
-// CHECK-NEXT: 2 | Test4::V2 *Test4::D::f()
-// CHECK-NEXT: [return adjustment: 0 non-virtual, -24 vbase offset offset]
-// CHECK-NEXT: 3 | Test4::V2 *Test4::D::f()
+// CHECK-9: Vtable for 'Test4::D' (4 entries).
+// CHECK-9-NEXT: 0 | offset_to_top (0)
+// CHECK-9-NEXT: 1 | Test4::D RTTI
+// CHECK-9-NEXT: -- (Test4::C, 0) vtable address --
+// CHECK-9-NEXT: -- (Test4::D, 0) vtable address --
+// CHECK-9-NEXT: 2 | Test4::V2 *Test4::D::f()
+// CHECK-9-NEXT: [return adjustment: 0 non-virtual, -24 vbase offset offset]
+// CHECK-9-NEXT: 3 | Test4::V2 *Test4::D::f()
struct D : C {
virtual V2 *f();
};
@@ -178,14 +220,14 @@ V2 *D::f() { return 0; };
// Virtual result adjustments with an additional non-virtual adjustment.
struct V3 : virtual R3 { int r3; };
-// CHECK: Vtable for 'Test4::E' (4 entries).
-// CHECK-NEXT: 0 | offset_to_top (0)
-// CHECK-NEXT: 1 | Test4::E RTTI
-// CHECK-NEXT: -- (Test4::A, 0) vtable address --
-// CHECK-NEXT: -- (Test4::E, 0) vtable address --
-// CHECK-NEXT: 2 | Test4::V3 *Test4::E::f()
-// CHECK-NEXT: [return adjustment: 4 non-virtual, -24 vbase offset offset]
-// CHECK-NEXT: 3 | Test4::V3 *Test4::E::f()
+// CHECK-10: Vtable for 'Test4::E' (4 entries).
+// CHECK-10-NEXT: 0 | offset_to_top (0)
+// CHECK-10-NEXT: 1 | Test4::E RTTI
+// CHECK-10-NEXT: -- (Test4::A, 0) vtable address --
+// CHECK-10-NEXT: -- (Test4::E, 0) vtable address --
+// CHECK-10-NEXT: 2 | Test4::V3 *Test4::E::f()
+// CHECK-10-NEXT: [return adjustment: 4 non-virtual, -24 vbase offset offset]
+// CHECK-10-NEXT: 3 | Test4::V3 *Test4::E::f()
struct E : A {
virtual V3 *f();
@@ -194,14 +236,14 @@ V3 *E::f() { return 0;}
// Test that a pure virtual member doesn't get a thunk.
-// CHECK: Vtable for 'Test4::F' (5 entries).
-// CHECK-NEXT: 0 | offset_to_top (0)
-// CHECK-NEXT: 1 | Test4::F RTTI
-// CHECK-NEXT: -- (Test4::A, 0) vtable address --
-// CHECK-NEXT: -- (Test4::F, 0) vtable address --
-// CHECK-NEXT: 2 | Test4::R3 *Test4::F::f() [pure]
-// CHECK-NEXT: 3 | void Test4::F::g()
-// CHECK-NEXT: 4 | Test4::R3 *Test4::F::f() [pure]
+// CHECK-11: Vtable for 'Test4::F' (5 entries).
+// CHECK-11-NEXT: 0 | offset_to_top (0)
+// CHECK-11-NEXT: 1 | Test4::F RTTI
+// CHECK-11-NEXT: -- (Test4::A, 0) vtable address --
+// CHECK-11-NEXT: -- (Test4::F, 0) vtable address --
+// CHECK-11-NEXT: 2 | Test4::R3 *Test4::F::f() [pure]
+// CHECK-11-NEXT: 3 | void Test4::F::g()
+// CHECK-11-NEXT: 4 | Test4::R3 *Test4::F::f() [pure]
struct F : A {
virtual void g();
virtual R3 *f() = 0;
@@ -229,21 +271,21 @@ struct B2 : A {
int b2;
};
-// CHECK: Vtable for 'Test5::C' (9 entries).
-// CHECK-NEXT: 0 | offset_to_top (0)
-// CHECK-NEXT: 1 | Test5::C RTTI
-// CHECK-NEXT: -- (Test5::A, 0) vtable address --
-// CHECK-NEXT: -- (Test5::B1, 0) vtable address --
-// CHECK-NEXT: -- (Test5::C, 0) vtable address --
-// CHECK-NEXT: 2 | void Test5::B1::f()
-// CHECK-NEXT: 3 | void Test5::A::g()
-// CHECK-NEXT: 4 | void Test5::C::h()
-// CHECK-NEXT: 5 | offset_to_top (-16)
-// CHECK-NEXT: 6 | Test5::C RTTI
-// CHECK-NEXT: -- (Test5::A, 16) vtable address --
-// CHECK-NEXT: -- (Test5::B2, 16) vtable address --
-// CHECK-NEXT: 7 | void Test5::A::f()
-// CHECK-NEXT: 8 | void Test5::B2::g()
+// CHECK-12: Vtable for 'Test5::C' (9 entries).
+// CHECK-12-NEXT: 0 | offset_to_top (0)
+// CHECK-12-NEXT: 1 | Test5::C RTTI
+// CHECK-12-NEXT: -- (Test5::A, 0) vtable address --
+// CHECK-12-NEXT: -- (Test5::B1, 0) vtable address --
+// CHECK-12-NEXT: -- (Test5::C, 0) vtable address --
+// CHECK-12-NEXT: 2 | void Test5::B1::f()
+// CHECK-12-NEXT: 3 | void Test5::A::g()
+// CHECK-12-NEXT: 4 | void Test5::C::h()
+// CHECK-12-NEXT: 5 | offset_to_top (-16)
+// CHECK-12-NEXT: 6 | Test5::C RTTI
+// CHECK-12-NEXT: -- (Test5::A, 16) vtable address --
+// CHECK-12-NEXT: -- (Test5::B2, 16) vtable address --
+// CHECK-12-NEXT: 7 | void Test5::A::f()
+// CHECK-12-NEXT: 8 | void Test5::B2::g()
struct C : B1, B2 {
virtual void h();
};
@@ -263,17 +305,17 @@ struct A2 {
int a;
};
-// CHECK: Vtable for 'Test6::C' (6 entries).
-// CHECK-NEXT: 0 | offset_to_top (0)
-// CHECK-NEXT: 1 | Test6::C RTTI
-// CHECK-NEXT: -- (Test6::A1, 0) vtable address --
-// CHECK-NEXT: -- (Test6::C, 0) vtable address --
-// CHECK-NEXT: 2 | void Test6::C::f()
-// CHECK-NEXT: 3 | offset_to_top (-16)
-// CHECK-NEXT: 4 | Test6::C RTTI
-// CHECK-NEXT: -- (Test6::A2, 16) vtable address --
-// CHECK-NEXT: 5 | void Test6::C::f()
-// CHECK-NEXT: [this adjustment: -16 non-virtual]
+// CHECK-13: Vtable for 'Test6::C' (6 entries).
+// CHECK-13-NEXT: 0 | offset_to_top (0)
+// CHECK-13-NEXT: 1 | Test6::C RTTI
+// CHECK-13-NEXT: -- (Test6::A1, 0) vtable address --
+// CHECK-13-NEXT: -- (Test6::C, 0) vtable address --
+// CHECK-13-NEXT: 2 | void Test6::C::f()
+// CHECK-13-NEXT: 3 | offset_to_top (-16)
+// CHECK-13-NEXT: 4 | Test6::C RTTI
+// CHECK-13-NEXT: -- (Test6::A2, 16) vtable address --
+// CHECK-13-NEXT: 5 | void Test6::C::f()
+// CHECK-13-NEXT: [this adjustment: -16 non-virtual]
struct C : A1, A2 {
virtual void f();
};
@@ -296,25 +338,25 @@ struct B2 : A { };
struct C { virtual void c(); };
-// CHECK: Vtable for 'Test7::D' (10 entries).
-// CHECK-NEXT: 0 | offset_to_top (0)
-// CHECK-NEXT: 1 | Test7::D RTTI
-// CHECK-NEXT: -- (Test7::C, 0) vtable address --
-// CHECK-NEXT: -- (Test7::D, 0) vtable address --
-// CHECK-NEXT: 2 | void Test7::C::c()
-// CHECK-NEXT: 3 | void Test7::D::f()
-// CHECK-NEXT: 4 | offset_to_top (-8)
-// CHECK-NEXT: 5 | Test7::D RTTI
-// CHECK-NEXT: -- (Test7::A, 8) vtable address --
-// CHECK-NEXT: -- (Test7::B1, 8) vtable address --
-// CHECK-NEXT: 6 | void Test7::D::f()
-// CHECK-NEXT: [this adjustment: -8 non-virtual]
-// CHECK-NEXT: 7 | offset_to_top (-24)
-// CHECK-NEXT: 8 | Test7::D RTTI
-// CHECK-NEXT: -- (Test7::A, 24) vtable address --
-// CHECK-NEXT: -- (Test7::B2, 24) vtable address --
-// CHECK-NEXT: 9 | void Test7::D::f()
-// CHECK-NEXT: [this adjustment: -24 non-virtual]
+// CHECK-14: Vtable for 'Test7::D' (10 entries).
+// CHECK-14-NEXT: 0 | offset_to_top (0)
+// CHECK-14-NEXT: 1 | Test7::D RTTI
+// CHECK-14-NEXT: -- (Test7::C, 0) vtable address --
+// CHECK-14-NEXT: -- (Test7::D, 0) vtable address --
+// CHECK-14-NEXT: 2 | void Test7::C::c()
+// CHECK-14-NEXT: 3 | void Test7::D::f()
+// CHECK-14-NEXT: 4 | offset_to_top (-8)
+// CHECK-14-NEXT: 5 | Test7::D RTTI
+// CHECK-14-NEXT: -- (Test7::A, 8) vtable address --
+// CHECK-14-NEXT: -- (Test7::B1, 8) vtable address --
+// CHECK-14-NEXT: 6 | void Test7::D::f()
+// CHECK-14-NEXT: [this adjustment: -8 non-virtual]
+// CHECK-14-NEXT: 7 | offset_to_top (-24)
+// CHECK-14-NEXT: 8 | Test7::D RTTI
+// CHECK-14-NEXT: -- (Test7::A, 24) vtable address --
+// CHECK-14-NEXT: -- (Test7::B2, 24) vtable address --
+// CHECK-14-NEXT: 9 | void Test7::D::f()
+// CHECK-14-NEXT: [this adjustment: -24 non-virtual]
struct D : C, B1, B2 {
virtual void f();
};
@@ -329,11 +371,11 @@ namespace Test8 {
struct A { };
-// CHECK: Vtable for 'Test8::B' (3 entries).
-// CHECK-NEXT: 0 | offset_to_top (0)
-// CHECK-NEXT: 1 | Test8::B RTTI
-// CHECK-NEXT: -- (Test8::B, 0) vtable address --
-// CHECK-NEXT: 2 | void Test8::B::f()
+// CHECK-15: Vtable for 'Test8::B' (3 entries).
+// CHECK-15-NEXT: 0 | offset_to_top (0)
+// CHECK-15-NEXT: 1 | Test8::B RTTI
+// CHECK-15-NEXT: -- (Test8::B, 0) vtable address --
+// CHECK-15-NEXT: 2 | void Test8::B::f()
struct B : A {
virtual void f();
};
@@ -348,13 +390,13 @@ namespace Test9 {
struct A1 { int a1; };
struct A2 { int a2; };
-// CHECK: Vtable for 'Test9::B' (5 entries).
-// CHECK-NEXT: 0 | vbase_offset (16)
-// CHECK-NEXT: 1 | vbase_offset (12)
-// CHECK-NEXT: 2 | offset_to_top (0)
-// CHECK-NEXT: 3 | Test9::B RTTI
-// CHECK-NEXT: -- (Test9::B, 0) vtable address --
-// CHECK-NEXT: 4 | void Test9::B::f()
+// CHECK-16: Vtable for 'Test9::B' (5 entries).
+// CHECK-16-NEXT: 0 | vbase_offset (16)
+// CHECK-16-NEXT: 1 | vbase_offset (12)
+// CHECK-16-NEXT: 2 | offset_to_top (0)
+// CHECK-16-NEXT: 3 | Test9::B RTTI
+// CHECK-16-NEXT: -- (Test9::B, 0) vtable address --
+// CHECK-16-NEXT: 4 | void Test9::B::f()
struct B : virtual A1, virtual A2 {
int b;
@@ -373,18 +415,18 @@ namespace Test10 {
struct A1 { virtual void a1(); };
struct A2 { virtual void a2(); };
-// CHECK: Vtable for 'Test10::C' (7 entries).
-// CHECK-NEXT: 0 | offset_to_top (0)
-// CHECK-NEXT: 1 | Test10::C RTTI
-// CHECK-NEXT: -- (Test10::A1, 0) vtable address --
-// CHECK-NEXT: -- (Test10::B, 0) vtable address --
-// CHECK-NEXT: -- (Test10::C, 0) vtable address --
-// CHECK-NEXT: 2 | void Test10::A1::a1()
-// CHECK-NEXT: 3 | void Test10::C::f()
-// CHECK-NEXT: 4 | offset_to_top (-8)
-// CHECK-NEXT: 5 | Test10::C RTTI
-// CHECK-NEXT: -- (Test10::A2, 8) vtable address --
-// CHECK-NEXT: 6 | void Test10::A2::a2()
+// CHECK-17: Vtable for 'Test10::C' (7 entries).
+// CHECK-17-NEXT: 0 | offset_to_top (0)
+// CHECK-17-NEXT: 1 | Test10::C RTTI
+// CHECK-17-NEXT: -- (Test10::A1, 0) vtable address --
+// CHECK-17-NEXT: -- (Test10::B, 0) vtable address --
+// CHECK-17-NEXT: -- (Test10::C, 0) vtable address --
+// CHECK-17-NEXT: 2 | void Test10::A1::a1()
+// CHECK-17-NEXT: 3 | void Test10::C::f()
+// CHECK-17-NEXT: 4 | offset_to_top (-8)
+// CHECK-17-NEXT: 5 | Test10::C RTTI
+// CHECK-17-NEXT: -- (Test10::A2, 8) vtable address --
+// CHECK-17-NEXT: 6 | void Test10::A2::a2()
struct B : A1, A2 {
int b;
};
@@ -406,16 +448,16 @@ struct B : A1, virtual A2 {
int b;
};
-// CHECK: Vtable for 'Test11::C' (8 entries).
-// CHECK-NEXT: 0 | vbase_offset (24)
-// CHECK-NEXT: 1 | vbase_offset (8)
-// CHECK-NEXT: 2 | offset_to_top (0)
-// CHECK-NEXT: 3 | Test11::C RTTI
-// CHECK-NEXT: -- (Test11::C, 0) vtable address --
-// CHECK-NEXT: 4 | void Test11::C::f()
-// CHECK-NEXT: 5 | vbase_offset (16)
-// CHECK-NEXT: 6 | offset_to_top (-8)
-// CHECK-NEXT: 7 | Test11::C RTTI
+// CHECK-18: Vtable for 'Test11::C' (8 entries).
+// CHECK-18-NEXT: 0 | vbase_offset (24)
+// CHECK-18-NEXT: 1 | vbase_offset (8)
+// CHECK-18-NEXT: 2 | offset_to_top (0)
+// CHECK-18-NEXT: 3 | Test11::C RTTI
+// CHECK-18-NEXT: -- (Test11::C, 0) vtable address --
+// CHECK-18-NEXT: 4 | void Test11::C::f()
+// CHECK-18-NEXT: 5 | vbase_offset (16)
+// CHECK-18-NEXT: 6 | offset_to_top (-8)
+// CHECK-18-NEXT: 7 | Test11::C RTTI
struct C : virtual B {
virtual void f();
};
@@ -427,32 +469,32 @@ namespace Test12 {
// Test that the right vcall offsets are generated in the right order.
-// CHECK: Vtable for 'Test12::B' (19 entries).
-// CHECK-NEXT: 0 | vbase_offset (8)
-// CHECK-NEXT: 1 | offset_to_top (0)
-// CHECK-NEXT: 2 | Test12::B RTTI
-// CHECK-NEXT: -- (Test12::B, 0) vtable address --
-// CHECK-NEXT: 3 | void Test12::B::f()
-// CHECK-NEXT: 4 | void Test12::B::a()
-// CHECK-NEXT: 5 | vcall_offset (32)
-// CHECK-NEXT: 6 | vcall_offset (16)
-// CHECK-NEXT: 7 | vcall_offset (-8)
-// CHECK-NEXT: 8 | vcall_offset (0)
-// CHECK-NEXT: 9 | offset_to_top (-8)
-// CHECK-NEXT: 10 | Test12::B RTTI
-// CHECK-NEXT: -- (Test12::A, 8) vtable address --
-// CHECK-NEXT: -- (Test12::A1, 8) vtable address --
-// CHECK-NEXT: 11 | void Test12::A1::a1()
-// CHECK-NEXT: 12 | void Test12::B::a()
-// CHECK-NEXT: [this adjustment: 0 non-virtual, -32 vcall offset offset]
-// CHECK-NEXT: 13 | offset_to_top (-24)
-// CHECK-NEXT: 14 | Test12::B RTTI
-// CHECK-NEXT: -- (Test12::A2, 24) vtable address --
-// CHECK-NEXT: 15 | void Test12::A2::a2()
-// CHECK-NEXT: 16 | offset_to_top (-40)
-// CHECK-NEXT: 17 | Test12::B RTTI
-// CHECK-NEXT: -- (Test12::A3, 40) vtable address --
-// CHECK-NEXT: 18 | void Test12::A3::a3()
+// CHECK-19: Vtable for 'Test12::B' (19 entries).
+// CHECK-19-NEXT: 0 | vbase_offset (8)
+// CHECK-19-NEXT: 1 | offset_to_top (0)
+// CHECK-19-NEXT: 2 | Test12::B RTTI
+// CHECK-19-NEXT: -- (Test12::B, 0) vtable address --
+// CHECK-19-NEXT: 3 | void Test12::B::f()
+// CHECK-19-NEXT: 4 | void Test12::B::a()
+// CHECK-19-NEXT: 5 | vcall_offset (32)
+// CHECK-19-NEXT: 6 | vcall_offset (16)
+// CHECK-19-NEXT: 7 | vcall_offset (-8)
+// CHECK-19-NEXT: 8 | vcall_offset (0)
+// CHECK-19-NEXT: 9 | offset_to_top (-8)
+// CHECK-19-NEXT: 10 | Test12::B RTTI
+// CHECK-19-NEXT: -- (Test12::A, 8) vtable address --
+// CHECK-19-NEXT: -- (Test12::A1, 8) vtable address --
+// CHECK-19-NEXT: 11 | void Test12::A1::a1()
+// CHECK-19-NEXT: 12 | void Test12::B::a()
+// CHECK-19-NEXT: [this adjustment: 0 non-virtual, -32 vcall offset offset]
+// CHECK-19-NEXT: 13 | offset_to_top (-24)
+// CHECK-19-NEXT: 14 | Test12::B RTTI
+// CHECK-19-NEXT: -- (Test12::A2, 24) vtable address --
+// CHECK-19-NEXT: 15 | void Test12::A2::a2()
+// CHECK-19-NEXT: 16 | offset_to_top (-40)
+// CHECK-19-NEXT: 17 | Test12::B RTTI
+// CHECK-19-NEXT: -- (Test12::A3, 40) vtable address --
+// CHECK-19-NEXT: 18 | void Test12::A3::a3()
struct A1 {
virtual void a1();
int a;
@@ -493,16 +535,16 @@ struct B : virtual A {
virtual void f();
};
-// CHECK: Vtable for 'Test13::C' (6 entries).
-// CHECK-NEXT: 0 | vbase_offset (0)
-// CHECK-NEXT: 1 | vbase_offset (0)
-// CHECK-NEXT: 2 | vcall_offset (0)
-// CHECK-NEXT: 3 | offset_to_top (0)
-// CHECK-NEXT: 4 | Test13::C RTTI
-// CHECK-NEXT: -- (Test13::A, 0) vtable address --
-// CHECK-NEXT: -- (Test13::B, 0) vtable address --
-// CHECK-NEXT: -- (Test13::C, 0) vtable address --
-// CHECK-NEXT: 5 | void Test13::C::f()
+// CHECK-20: Vtable for 'Test13::C' (6 entries).
+// CHECK-20-NEXT: 0 | vbase_offset (0)
+// CHECK-20-NEXT: 1 | vbase_offset (0)
+// CHECK-20-NEXT: 2 | vcall_offset (0)
+// CHECK-20-NEXT: 3 | offset_to_top (0)
+// CHECK-20-NEXT: 4 | Test13::C RTTI
+// CHECK-20-NEXT: -- (Test13::A, 0) vtable address --
+// CHECK-20-NEXT: -- (Test13::B, 0) vtable address --
+// CHECK-20-NEXT: -- (Test13::C, 0) vtable address --
+// CHECK-20-NEXT: 5 | void Test13::C::f()
struct C : virtual B, virtual A {
virtual void f();
};
@@ -522,16 +564,16 @@ struct B : A { };
struct C : virtual B { };
-// CHECK: Vtable for 'Test14::D' (5 entries).
-// CHECK-NEXT: 0 | vbase_offset (0)
-// CHECK-NEXT: 1 | vcall_offset (0)
-// CHECK-NEXT: 2 | offset_to_top (0)
-// CHECK-NEXT: 3 | Test14::D RTTI
-// CHECK-NEXT: -- (Test14::A, 0) vtable address --
-// CHECK-NEXT: -- (Test14::B, 0) vtable address --
-// CHECK-NEXT: -- (Test14::C, 0) vtable address --
-// CHECK-NEXT: -- (Test14::D, 0) vtable address --
-// CHECK-NEXT: 4 | void Test14::D::f()
+// CHECK-21: Vtable for 'Test14::D' (5 entries).
+// CHECK-21-NEXT: 0 | vbase_offset (0)
+// CHECK-21-NEXT: 1 | vcall_offset (0)
+// CHECK-21-NEXT: 2 | offset_to_top (0)
+// CHECK-21-NEXT: 3 | Test14::D RTTI
+// CHECK-21-NEXT: -- (Test14::A, 0) vtable address --
+// CHECK-21-NEXT: -- (Test14::B, 0) vtable address --
+// CHECK-21-NEXT: -- (Test14::C, 0) vtable address --
+// CHECK-21-NEXT: -- (Test14::D, 0) vtable address --
+// CHECK-21-NEXT: 4 | void Test14::D::f()
struct D : C, virtual B {
virtual void f();
};
@@ -547,22 +589,22 @@ struct B { virtual void b(); };
struct C : virtual B { };
-// CHECK: Vtable for 'Test15::D' (11 entries).
-// CHECK-NEXT: 0 | vbase_offset (8)
-// CHECK-NEXT: 1 | vbase_offset (8)
-// CHECK-NEXT: 2 | offset_to_top (0)
-// CHECK-NEXT: 3 | Test15::D RTTI
-// CHECK-NEXT: -- (Test15::A, 0) vtable address --
-// CHECK-NEXT: -- (Test15::D, 0) vtable address --
-// CHECK-NEXT: 4 | void Test15::A::a()
-// CHECK-NEXT: 5 | void Test15::D::f()
-// CHECK-NEXT: 6 | vbase_offset (0)
-// CHECK-NEXT: 7 | vcall_offset (0)
-// CHECK-NEXT: 8 | offset_to_top (-8)
-// CHECK-NEXT: 9 | Test15::D RTTI
-// CHECK-NEXT: -- (Test15::B, 8) vtable address --
-// CHECK-NEXT: -- (Test15::C, 8) vtable address --
-// CHECK-NEXT: 10 | void Test15::B::b()
+// CHECK-22: Vtable for 'Test15::D' (11 entries).
+// CHECK-22-NEXT: 0 | vbase_offset (8)
+// CHECK-22-NEXT: 1 | vbase_offset (8)
+// CHECK-22-NEXT: 2 | offset_to_top (0)
+// CHECK-22-NEXT: 3 | Test15::D RTTI
+// CHECK-22-NEXT: -- (Test15::A, 0) vtable address --
+// CHECK-22-NEXT: -- (Test15::D, 0) vtable address --
+// CHECK-22-NEXT: 4 | void Test15::A::a()
+// CHECK-22-NEXT: 5 | void Test15::D::f()
+// CHECK-22-NEXT: 6 | vbase_offset (0)
+// CHECK-22-NEXT: 7 | vcall_offset (0)
+// CHECK-22-NEXT: 8 | offset_to_top (-8)
+// CHECK-22-NEXT: 9 | Test15::D RTTI
+// CHECK-22-NEXT: -- (Test15::B, 8) vtable address --
+// CHECK-22-NEXT: -- (Test15::C, 8) vtable address --
+// CHECK-22-NEXT: 10 | void Test15::B::b()
struct D : A, virtual B, virtual C {
virtual void f();
};
@@ -579,30 +621,30 @@ struct B { virtual ~B(); };
struct C : A, B { virtual ~C(); };
-// CHECK: Vtable for 'Test16::D' (15 entries).
-// CHECK-NEXT: 0 | vbase_offset (8)
-// CHECK-NEXT: 1 | offset_to_top (0)
-// CHECK-NEXT: 2 | Test16::D RTTI
-// CHECK-NEXT: -- (Test16::D, 0) vtable address --
-// CHECK-NEXT: 3 | void Test16::D::f()
-// CHECK-NEXT: 4 | Test16::D::~D() [complete]
-// CHECK-NEXT: 5 | Test16::D::~D() [deleting]
-// CHECK-NEXT: 6 | vcall_offset (-8)
-// CHECK-NEXT: 7 | offset_to_top (-8)
-// CHECK-NEXT: 8 | Test16::D RTTI
-// CHECK-NEXT: -- (Test16::A, 8) vtable address --
-// CHECK-NEXT: -- (Test16::C, 8) vtable address --
-// CHECK-NEXT: 9 | Test16::D::~D() [complete]
-// CHECK-NEXT: [this adjustment: 0 non-virtual, -24 vcall offset offset]
-// CHECK-NEXT: 10 | Test16::D::~D() [deleting]
-// CHECK-NEXT: [this adjustment: 0 non-virtual, -24 vcall offset offset]
-// CHECK-NEXT: 11 | offset_to_top (-16)
-// CHECK-NEXT: 12 | Test16::D RTTI
-// CHECK-NEXT: -- (Test16::B, 16) vtable address --
-// CHECK-NEXT: 13 | Test16::D::~D() [complete]
-// CHECK-NEXT: [this adjustment: -8 non-virtual, -24 vcall offset offset]
-// CHECK-NEXT: 14 | Test16::D::~D() [deleting]
-// CHECK-NEXT: [this adjustment: -8 non-virtual, -24 vcall offset offset]
+// CHECK-23: Vtable for 'Test16::D' (15 entries).
+// CHECK-23-NEXT: 0 | vbase_offset (8)
+// CHECK-23-NEXT: 1 | offset_to_top (0)
+// CHECK-23-NEXT: 2 | Test16::D RTTI
+// CHECK-23-NEXT: -- (Test16::D, 0) vtable address --
+// CHECK-23-NEXT: 3 | void Test16::D::f()
+// CHECK-23-NEXT: 4 | Test16::D::~D() [complete]
+// CHECK-23-NEXT: 5 | Test16::D::~D() [deleting]
+// CHECK-23-NEXT: 6 | vcall_offset (-8)
+// CHECK-23-NEXT: 7 | offset_to_top (-8)
+// CHECK-23-NEXT: 8 | Test16::D RTTI
+// CHECK-23-NEXT: -- (Test16::A, 8) vtable address --
+// CHECK-23-NEXT: -- (Test16::C, 8) vtable address --
+// CHECK-23-NEXT: 9 | Test16::D::~D() [complete]
+// CHECK-23-NEXT: [this adjustment: 0 non-virtual, -24 vcall offset offset]
+// CHECK-23-NEXT: 10 | Test16::D::~D() [deleting]
+// CHECK-23-NEXT: [this adjustment: 0 non-virtual, -24 vcall offset offset]
+// CHECK-23-NEXT: 11 | offset_to_top (-16)
+// CHECK-23-NEXT: 12 | Test16::D RTTI
+// CHECK-23-NEXT: -- (Test16::B, 16) vtable address --
+// CHECK-23-NEXT: 13 | Test16::D::~D() [complete]
+// CHECK-23-NEXT: [this adjustment: -8 non-virtual, -24 vcall offset offset]
+// CHECK-23-NEXT: 14 | Test16::D::~D() [deleting]
+// CHECK-23-NEXT: [this adjustment: -8 non-virtual, -24 vcall offset offset]
struct D : virtual C {
virtual void f();
};
@@ -618,26 +660,26 @@ struct B : virtual A { virtual void f(); };
struct C : virtual A { virtual void f(); };
struct D : virtual B, virtual C { virtual void f(); };
-// CHECK: Vtable for 'Test17::E' (13 entries).
-// CHECK-NEXT: 0 | vbase_offset (0)
-// CHECK-NEXT: 1 | vbase_offset (8)
-// CHECK-NEXT: 2 | vbase_offset (0)
-// CHECK-NEXT: 3 | vbase_offset (0)
-// CHECK-NEXT: 4 | vcall_offset (0)
-// CHECK-NEXT: 5 | offset_to_top (0)
-// CHECK-NEXT: 6 | Test17::E RTTI
-// CHECK-NEXT: -- (Test17::A, 0) vtable address --
-// CHECK-NEXT: -- (Test17::B, 0) vtable address --
-// CHECK-NEXT: -- (Test17::D, 0) vtable address --
-// CHECK-NEXT: -- (Test17::E, 0) vtable address --
-// CHECK-NEXT: 7 | void Test17::E::f()
-// CHECK-NEXT: 8 | vbase_offset (-8)
-// CHECK-NEXT: 9 | vcall_offset (-8)
-// CHECK-NEXT: 10 | offset_to_top (-8)
-// CHECK-NEXT: 11 | Test17::E RTTI
-// 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]
+// CHECK-24: Vtable for 'Test17::E' (13 entries).
+// CHECK-24-NEXT: 0 | vbase_offset (0)
+// CHECK-24-NEXT: 1 | vbase_offset (8)
+// CHECK-24-NEXT: 2 | vbase_offset (0)
+// CHECK-24-NEXT: 3 | vbase_offset (0)
+// CHECK-24-NEXT: 4 | vcall_offset (0)
+// CHECK-24-NEXT: 5 | offset_to_top (0)
+// CHECK-24-NEXT: 6 | Test17::E RTTI
+// CHECK-24-NEXT: -- (Test17::A, 0) vtable address --
+// CHECK-24-NEXT: -- (Test17::B, 0) vtable address --
+// CHECK-24-NEXT: -- (Test17::D, 0) vtable address --
+// CHECK-24-NEXT: -- (Test17::E, 0) vtable address --
+// CHECK-24-NEXT: 7 | void Test17::E::f()
+// CHECK-24-NEXT: 8 | vbase_offset (-8)
+// CHECK-24-NEXT: 9 | vcall_offset (-8)
+// CHECK-24-NEXT: 10 | offset_to_top (-8)
+// CHECK-24-NEXT: 11 | Test17::E RTTI
+// CHECK-24-NEXT: -- (Test17::C, 8) vtable address --
+// CHECK-24-NEXT: 12 | void Test17::E::f()
+// CHECK-24-NEXT: [this adjustment: 0 non-virtual, -24 vcall offset offset]
class E : virtual D {
virtual void f();
};
@@ -662,97 +704,97 @@ struct C : A, B {
virtual void g();
};
-// CHECK: Vtable for 'Test18::D' (24 entries).
-// CHECK-NEXT: 0 | vbase_offset (8)
-// CHECK-NEXT: 1 | vbase_offset (0)
-// CHECK-NEXT: 2 | vbase_offset (0)
-// CHECK-NEXT: 3 | vcall_offset (8)
-// CHECK-NEXT: 4 | vcall_offset (0)
-// CHECK-NEXT: 5 | offset_to_top (0)
-// CHECK-NEXT: 6 | Test18::D RTTI
-// CHECK-NEXT: -- (Test18::A, 0) vtable address --
-// CHECK-NEXT: -- (Test18::B, 0) vtable address --
-// CHECK-NEXT: -- (Test18::D, 0) vtable address --
-// CHECK-NEXT: 7 | void Test18::D::f()
-// CHECK-NEXT: 8 | void Test18::C::g()
-// CHECK-NEXT: [this adjustment: 0 non-virtual, -32 vcall offset offset]
-// CHECK-NEXT: 9 | void Test18::D::h()
-// CHECK-NEXT: 10 | vcall_offset (0)
-// CHECK-NEXT: 11 | vcall_offset (-8)
-// CHECK-NEXT: 12 | vbase_offset (-8)
-// CHECK-NEXT: 13 | offset_to_top (-8)
-// CHECK-NEXT: 14 | Test18::D RTTI
-// CHECK-NEXT: -- (Test18::A, 8) vtable address --
-// CHECK-NEXT: -- (Test18::C, 8) vtable address --
-// CHECK-NEXT: 15 | void Test18::D::f()
-// CHECK-NEXT: [this adjustment: 0 non-virtual, -32 vcall offset offset]
-// CHECK-NEXT: 16 | void Test18::C::g()
-// CHECK-NEXT: 17 | vbase_offset (-16)
-// CHECK-NEXT: 18 | vcall_offset (-8)
-// CHECK-NEXT: 19 | vcall_offset (-16)
-// CHECK-NEXT: 20 | offset_to_top (-16)
-// CHECK-NEXT: 21 | Test18::D RTTI
-// 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]
-// CHECK-NEXT: 23 | [unused] void Test18::C::g()
-
-// CHECK: Construction vtable for ('Test18::B', 0) in 'Test18::D' (7 entries).
-// CHECK-NEXT: 0 | vbase_offset (0)
-// CHECK-NEXT: 1 | vcall_offset (0)
-// CHECK-NEXT: 2 | vcall_offset (0)
-// CHECK-NEXT: 3 | offset_to_top (0)
-// CHECK-NEXT: 4 | Test18::B RTTI
-// CHECK-NEXT: -- (Test18::A, 0) vtable address --
-// CHECK-NEXT: -- (Test18::B, 0) vtable address --
-// CHECK-NEXT: 5 | void Test18::B::f()
-// CHECK-NEXT: 6 | void Test18::A::g()
-
-// CHECK: Construction vtable for ('Test18::C', 8) in 'Test18::D' (20 entries).
-// CHECK-NEXT: 0 | vcall_offset (0)
-// CHECK-NEXT: 1 | vcall_offset (0)
-// CHECK-NEXT: 2 | vbase_offset (-8)
-// CHECK-NEXT: 3 | offset_to_top (0)
-// CHECK-NEXT: 4 | Test18::C RTTI
-// CHECK-NEXT: -- (Test18::A, 8) vtable address --
-// CHECK-NEXT: -- (Test18::C, 8) vtable address --
-// CHECK-NEXT: 5 | void Test18::A::f()
-// CHECK-NEXT: 6 | void Test18::C::g()
-// CHECK-NEXT: 7 | vbase_offset (-16)
-// CHECK-NEXT: 8 | vcall_offset (-8)
-// CHECK-NEXT: 9 | vcall_offset (0)
-// CHECK-NEXT: 10 | offset_to_top (-8)
-// CHECK-NEXT: 11 | Test18::C RTTI
-// CHECK-NEXT: -- (Test18::B, 16) vtable address --
-// CHECK-NEXT: 12 | void Test18::B::f()
-// CHECK-NEXT: 13 | [unused] void Test18::C::g()
-// CHECK-NEXT: 14 | vcall_offset (8)
-// CHECK-NEXT: 15 | vcall_offset (16)
-// CHECK-NEXT: 16 | offset_to_top (8)
-// CHECK-NEXT: 17 | Test18::C RTTI
-// CHECK-NEXT: -- (Test18::A, 0) vtable address --
-// CHECK-NEXT: 18 | void Test18::B::f()
-// CHECK-NEXT: [this adjustment: 0 non-virtual, -24 vcall offset offset]
-// CHECK-NEXT: 19 | void Test18::C::g()
-// CHECK-NEXT: [this adjustment: 0 non-virtual, -32 vcall offset offset]
-
-// CHECK: Construction vtable for ('Test18::B', 16) in 'Test18::D' (13 entries).
-// CHECK-NEXT: 0 | vbase_offset (-16)
-// CHECK-NEXT: 1 | vcall_offset (-16)
-// CHECK-NEXT: 2 | vcall_offset (0)
-// CHECK-NEXT: 3 | offset_to_top (0)
-// CHECK-NEXT: 4 | Test18::B RTTI
-// CHECK-NEXT: -- (Test18::B, 16) vtable address --
-// CHECK-NEXT: 5 | void Test18::B::f()
-// CHECK-NEXT: 6 | [unused] void Test18::A::g()
-// CHECK-NEXT: 7 | vcall_offset (0)
-// CHECK-NEXT: 8 | vcall_offset (16)
-// CHECK-NEXT: 9 | offset_to_top (16)
-// CHECK-NEXT: 10 | Test18::B RTTI
-// CHECK-NEXT: -- (Test18::A, 0) vtable address --
-// CHECK-NEXT: 11 | void Test18::B::f()
-// CHECK-NEXT: [this adjustment: 0 non-virtual, -24 vcall offset offset]
-// CHECK-NEXT: 12 | void Test18::A::g()
+// CHECK-25: Vtable for 'Test18::D' (24 entries).
+// CHECK-25-NEXT: 0 | vbase_offset (8)
+// CHECK-25-NEXT: 1 | vbase_offset (0)
+// CHECK-25-NEXT: 2 | vbase_offset (0)
+// CHECK-25-NEXT: 3 | vcall_offset (8)
+// CHECK-25-NEXT: 4 | vcall_offset (0)
+// CHECK-25-NEXT: 5 | offset_to_top (0)
+// CHECK-25-NEXT: 6 | Test18::D RTTI
+// CHECK-25-NEXT: -- (Test18::A, 0) vtable address --
+// CHECK-25-NEXT: -- (Test18::B, 0) vtable address --
+// CHECK-25-NEXT: -- (Test18::D, 0) vtable address --
+// CHECK-25-NEXT: 7 | void Test18::D::f()
+// CHECK-25-NEXT: 8 | void Test18::C::g()
+// CHECK-25-NEXT: [this adjustment: 0 non-virtual, -32 vcall offset offset]
+// CHECK-25-NEXT: 9 | void Test18::D::h()
+// CHECK-25-NEXT: 10 | vcall_offset (0)
+// CHECK-25-NEXT: 11 | vcall_offset (-8)
+// CHECK-25-NEXT: 12 | vbase_offset (-8)
+// CHECK-25-NEXT: 13 | offset_to_top (-8)
+// CHECK-25-NEXT: 14 | Test18::D RTTI
+// CHECK-25-NEXT: -- (Test18::A, 8) vtable address --
+// CHECK-25-NEXT: -- (Test18::C, 8) vtable address --
+// CHECK-25-NEXT: 15 | void Test18::D::f()
+// CHECK-25-NEXT: [this adjustment: 0 non-virtual, -32 vcall offset offset]
+// CHECK-25-NEXT: 16 | void Test18::C::g()
+// CHECK-25-NEXT: 17 | vbase_offset (-16)
+// CHECK-25-NEXT: 18 | vcall_offset (-8)
+// CHECK-25-NEXT: 19 | vcall_offset (-16)
+// CHECK-25-NEXT: 20 | offset_to_top (-16)
+// CHECK-25-NEXT: 21 | Test18::D RTTI
+// CHECK-25-NEXT: -- (Test18::B, 16) vtable address --
+// CHECK-25-NEXT: 22 | void Test18::D::f()
+// CHECK-25-NEXT: [this adjustment: -8 non-virtual, -32 vcall offset offset]
+// CHECK-25-NEXT: 23 | [unused] void Test18::C::g()
+
+// CHECK-25: Construction vtable for ('Test18::B', 0) in 'Test18::D' (7 entries).
+// CHECK-25-NEXT: 0 | vbase_offset (0)
+// CHECK-25-NEXT: 1 | vcall_offset (0)
+// CHECK-25-NEXT: 2 | vcall_offset (0)
+// CHECK-25-NEXT: 3 | offset_to_top (0)
+// CHECK-25-NEXT: 4 | Test18::B RTTI
+// CHECK-25-NEXT: -- (Test18::A, 0) vtable address --
+// CHECK-25-NEXT: -- (Test18::B, 0) vtable address --
+// CHECK-25-NEXT: 5 | void Test18::B::f()
+// CHECK-25-NEXT: 6 | void Test18::A::g()
+
+// CHECK-25: Construction vtable for ('Test18::C', 8) in 'Test18::D' (20 entries).
+// CHECK-25-NEXT: 0 | vcall_offset (0)
+// CHECK-25-NEXT: 1 | vcall_offset (0)
+// CHECK-25-NEXT: 2 | vbase_offset (-8)
+// CHECK-25-NEXT: 3 | offset_to_top (0)
+// CHECK-25-NEXT: 4 | Test18::C RTTI
+// CHECK-25-NEXT: -- (Test18::A, 8) vtable address --
+// CHECK-25-NEXT: -- (Test18::C, 8) vtable address --
+// CHECK-25-NEXT: 5 | void Test18::A::f()
+// CHECK-25-NEXT: 6 | void Test18::C::g()
+// CHECK-25-NEXT: 7 | vbase_offset (-16)
+// CHECK-25-NEXT: 8 | vcall_offset (-8)
+// CHECK-25-NEXT: 9 | vcall_offset (0)
+// CHECK-25-NEXT: 10 | offset_to_top (-8)
+// CHECK-25-NEXT: 11 | Test18::C RTTI
+// CHECK-25-NEXT: -- (Test18::B, 16) vtable address --
+// CHECK-25-NEXT: 12 | void Test18::B::f()
+// CHECK-25-NEXT: 13 | [unused] void Test18::C::g()
+// CHECK-25-NEXT: 14 | vcall_offset (8)
+// CHECK-25-NEXT: 15 | vcall_offset (16)
+// CHECK-25-NEXT: 16 | offset_to_top (8)
+// CHECK-25-NEXT: 17 | Test18::C RTTI
+// CHECK-25-NEXT: -- (Test18::A, 0) vtable address --
+// CHECK-25-NEXT: 18 | void Test18::B::f()
+// CHECK-25-NEXT: [this adjustment: 0 non-virtual, -24 vcall offset offset]
+// CHECK-25-NEXT: 19 | void Test18::C::g()
+// CHECK-25-NEXT: [this adjustment: 0 non-virtual, -32 vcall offset offset]
+
+// CHECK-25: Construction vtable for ('Test18::B', 16) in 'Test18::D' (13 entries).
+// CHECK-25-NEXT: 0 | vbase_offset (-16)
+// CHECK-25-NEXT: 1 | vcall_offset (-16)
+// CHECK-25-NEXT: 2 | vcall_offset (0)
+// CHECK-25-NEXT: 3 | offset_to_top (0)
+// CHECK-25-NEXT: 4 | Test18::B RTTI
+// CHECK-25-NEXT: -- (Test18::B, 16) vtable address --
+// CHECK-25-NEXT: 5 | void Test18::B::f()
+// CHECK-25-NEXT: 6 | [unused] void Test18::A::g()
+// CHECK-25-NEXT: 7 | vcall_offset (0)
+// CHECK-25-NEXT: 8 | vcall_offset (16)
+// CHECK-25-NEXT: 9 | offset_to_top (16)
+// CHECK-25-NEXT: 10 | Test18::B RTTI
+// CHECK-25-NEXT: -- (Test18::A, 0) vtable address --
+// CHECK-25-NEXT: 11 | void Test18::B::f()
+// CHECK-25-NEXT: [this adjustment: 0 non-virtual, -24 vcall offset offset]
+// CHECK-25-NEXT: 12 | void Test18::A::g()
struct D : virtual B, virtual C, virtual A
{
virtual void f();
@@ -782,27 +824,27 @@ struct C {
virtual void c();
};
-// CHECK: Vtable for 'Test19::D' (13 entries).
-// CHECK-NEXT: 0 | vbase_offset (24)
-// CHECK-NEXT: 1 | offset_to_top (0)
-// CHECK-NEXT: 2 | Test19::D RTTI
-// CHECK-NEXT: -- (Test19::C, 0) vtable address --
-// CHECK-NEXT: -- (Test19::D, 0) vtable address --
-// CHECK-NEXT: 3 | void Test19::C::c()
-// CHECK-NEXT: 4 | void Test19::D::f()
-// CHECK-NEXT: 5 | offset_to_top (-8)
-// CHECK-NEXT: 6 | Test19::D RTTI
-// CHECK-NEXT: -- (Test19::A, 8) vtable address --
-// CHECK-NEXT: -- (Test19::B, 8) vtable address --
-// CHECK-NEXT: 7 | void Test19::D::f()
-// CHECK-NEXT: [this adjustment: -8 non-virtual]
-// CHECK-NEXT: 8 | void Test19::B::g()
-// CHECK-NEXT: 9 | vcall_offset (-24)
-// CHECK-NEXT: 10 | offset_to_top (-24)
-// CHECK-NEXT: 11 | Test19::D RTTI
-// CHECK-NEXT: -- (Test19::A, 24) vtable address --
-// CHECK-NEXT: 12 | void Test19::D::f()
-// CHECK-NEXT: [this adjustment: 0 non-virtual, -24 vcall offset offset]
+// CHECK-26: Vtable for 'Test19::D' (13 entries).
+// CHECK-26-NEXT: 0 | vbase_offset (24)
+// CHECK-26-NEXT: 1 | offset_to_top (0)
+// CHECK-26-NEXT: 2 | Test19::D RTTI
+// CHECK-26-NEXT: -- (Test19::C, 0) vtable address --
+// CHECK-26-NEXT: -- (Test19::D, 0) vtable address --
+// CHECK-26-NEXT: 3 | void Test19::C::c()
+// CHECK-26-NEXT: 4 | void Test19::D::f()
+// CHECK-26-NEXT: 5 | offset_to_top (-8)
+// CHECK-26-NEXT: 6 | Test19::D RTTI
+// CHECK-26-NEXT: -- (Test19::A, 8) vtable address --
+// CHECK-26-NEXT: -- (Test19::B, 8) vtable address --
+// CHECK-26-NEXT: 7 | void Test19::D::f()
+// CHECK-26-NEXT: [this adjustment: -8 non-virtual]
+// CHECK-26-NEXT: 8 | void Test19::B::g()
+// CHECK-26-NEXT: 9 | vcall_offset (-24)
+// CHECK-26-NEXT: 10 | offset_to_top (-24)
+// CHECK-26-NEXT: 11 | Test19::D RTTI
+// CHECK-26-NEXT: -- (Test19::A, 24) vtable address --
+// CHECK-26-NEXT: 12 | void Test19::D::f()
+// CHECK-26-NEXT: [this adjustment: 0 non-virtual, -24 vcall offset offset]
struct D : C, B, virtual A {
virtual void f();
};
@@ -821,20 +863,20 @@ struct A {
struct B : A { };
-// CHECK: Vtable for 'Test20::C' (9 entries).
-// CHECK-NEXT: 0 | offset_to_top (0)
-// CHECK-NEXT: 1 | Test20::C RTTI
-// CHECK-NEXT: -- (Test20::A, 0) vtable address --
-// CHECK-NEXT: -- (Test20::C, 0) vtable address --
-// CHECK-NEXT: 2 | void Test20::C::f() [pure]
-// CHECK-NEXT: 3 | void Test20::A::g()
-// CHECK-NEXT: 4 | void Test20::C::h()
-// CHECK-NEXT: 5 | offset_to_top (-8)
-// CHECK-NEXT: 6 | Test20::C RTTI
-// CHECK-NEXT: -- (Test20::A, 8) vtable address --
-// CHECK-NEXT: -- (Test20::B, 8) vtable address --
-// CHECK-NEXT: 7 | void Test20::C::f() [pure]
-// CHECK-NEXT: 8 | void Test20::A::g()
+// CHECK-27: Vtable for 'Test20::C' (9 entries).
+// CHECK-27-NEXT: 0 | offset_to_top (0)
+// CHECK-27-NEXT: 1 | Test20::C RTTI
+// CHECK-27-NEXT: -- (Test20::A, 0) vtable address --
+// CHECK-27-NEXT: -- (Test20::C, 0) vtable address --
+// CHECK-27-NEXT: 2 | void Test20::C::f() [pure]
+// CHECK-27-NEXT: 3 | void Test20::A::g()
+// CHECK-27-NEXT: 4 | void Test20::C::h()
+// CHECK-27-NEXT: 5 | offset_to_top (-8)
+// CHECK-27-NEXT: 6 | Test20::C RTTI
+// CHECK-27-NEXT: -- (Test20::A, 8) vtable address --
+// CHECK-27-NEXT: -- (Test20::B, 8) vtable address --
+// CHECK-27-NEXT: 7 | void Test20::C::f() [pure]
+// CHECK-27-NEXT: 8 | void Test20::A::g()
struct C : A, B {
virtual void f() = 0;
virtual void h();
@@ -856,36 +898,36 @@ class D : virtual C { };
class E : virtual C { };
-// CHECK: Vtable for 'Test21::F' (16 entries).
-// CHECK-NEXT: 0 | vbase_offset (8)
-// CHECK-NEXT: 1 | vbase_offset (0)
-// CHECK-NEXT: 2 | vbase_offset (0)
-// CHECK-NEXT: 3 | vbase_offset (0)
-// CHECK-NEXT: 4 | vbase_offset (0)
-// CHECK-NEXT: 5 | vcall_offset (0)
-// CHECK-NEXT: 6 | offset_to_top (0)
-// CHECK-NEXT: 7 | Test21::F RTTI
-// CHECK-NEXT: -- (Test21::A, 0) vtable address --
-// CHECK-NEXT: -- (Test21::B, 0) vtable address --
-// CHECK-NEXT: -- (Test21::C, 0) vtable address --
-// CHECK-NEXT: -- (Test21::D, 0) vtable address --
-// CHECK-NEXT: -- (Test21::F, 0) vtable address --
-// CHECK-NEXT: 8 | void Test21::F::f()
-// CHECK-NEXT: 9 | vbase_offset (-8)
-// CHECK-NEXT: 10 | vbase_offset (-8)
-// CHECK-NEXT: 11 | vbase_offset (-8)
-// CHECK-NEXT: 12 | vcall_offset (-8)
-// CHECK-NEXT: 13 | offset_to_top (-8)
-// CHECK-NEXT: 14 | Test21::F RTTI
-// CHECK-NEXT: -- (Test21::E, 8) vtable address --
-// CHECK-NEXT: 15 | [unused] void Test21::F::f()
+// CHECK-28: Vtable for 'Test21::F' (16 entries).
+// CHECK-28-NEXT: 0 | vbase_offset (8)
+// CHECK-28-NEXT: 1 | vbase_offset (0)
+// CHECK-28-NEXT: 2 | vbase_offset (0)
+// CHECK-28-NEXT: 3 | vbase_offset (0)
+// CHECK-28-NEXT: 4 | vbase_offset (0)
+// CHECK-28-NEXT: 5 | vcall_offset (0)
+// CHECK-28-NEXT: 6 | offset_to_top (0)
+// CHECK-28-NEXT: 7 | Test21::F RTTI
+// CHECK-28-NEXT: -- (Test21::A, 0) vtable address --
+// CHECK-28-NEXT: -- (Test21::B, 0) vtable address --
+// CHECK-28-NEXT: -- (Test21::C, 0) vtable address --
+// CHECK-28-NEXT: -- (Test21::D, 0) vtable address --
+// CHECK-28-NEXT: -- (Test21::F, 0) vtable address --
+// CHECK-28-NEXT: 8 | void Test21::F::f()
+// CHECK-28-NEXT: 9 | vbase_offset (-8)
+// CHECK-28-NEXT: 10 | vbase_offset (-8)
+// CHECK-28-NEXT: 11 | vbase_offset (-8)
+// CHECK-28-NEXT: 12 | vcall_offset (-8)
+// CHECK-28-NEXT: 13 | offset_to_top (-8)
+// CHECK-28-NEXT: 14 | Test21::F RTTI
+// CHECK-28-NEXT: -- (Test21::E, 8) vtable address --
+// CHECK-28-NEXT: 15 | [unused] void Test21::F::f()
//
-// CHECK: Virtual base offset offsets for 'Test21::F' (5 entries).
-// CHECK-NEXT: Test21::A | -32
-// CHECK-NEXT: Test21::B | -40
-// CHECK-NEXT: Test21::C | -48
-// CHECK-NEXT: Test21::D | -56
-// CHECK-NEXT: Test21::E | -64
+// CHECK-28: Virtual base offset offsets for 'Test21::F' (5 entries).
+// CHECK-28-NEXT: Test21::A | -32
+// CHECK-28-NEXT: Test21::B | -40
+// CHECK-28-NEXT: Test21::C | -48
+// CHECK-28-NEXT: Test21::D | -56
+// CHECK-28-NEXT: Test21::E | -64
class F : virtual D, virtual E {
virtual void f();
};
@@ -904,22 +946,22 @@ struct V2 : virtual V1 {
int v2;
};
-// CHECK: Vtable for 'Test22::C' (8 entries).
-// CHECK-NEXT: 0 | vbase_offset (16)
-// CHECK-NEXT: 1 | vbase_offset (12)
-// CHECK-NEXT: 2 | offset_to_top (0)
-// CHECK-NEXT: 3 | Test22::C RTTI
-// CHECK-NEXT: -- (Test22::C, 0) vtable address --
-// CHECK-NEXT: 4 | void Test22::C::f()
-// CHECK-NEXT: 5 | vbase_offset (-4)
-// CHECK-NEXT: 6 | offset_to_top (-16)
-// CHECK-NEXT: 7 | Test22::C RTTI
-// CHECK-NEXT: -- (Test22::V2, 16) vtable address --
+// CHECK-29: Vtable for 'Test22::C' (8 entries).
+// CHECK-29-NEXT: 0 | vbase_offset (16)
+// CHECK-29-NEXT: 1 | vbase_offset (12)
+// CHECK-29-NEXT: 2 | offset_to_top (0)
+// CHECK-29-NEXT: 3 | Test22::C RTTI
+// CHECK-29-NEXT: -- (Test22::C, 0) vtable address --
+// CHECK-29-NEXT: 4 | void Test22::C::f()
+// CHECK-29-NEXT: 5 | vbase_offset (-4)
+// CHECK-29-NEXT: 6 | offset_to_top (-16)
+// CHECK-29-NEXT: 7 | Test22::C RTTI
+// CHECK-29-NEXT: -- (Test22::V2, 16) vtable address --
-// CHECK: Construction vtable for ('Test22::V2', 16) in 'Test22::C' (3 entries).
-// CHECK-NEXT: 0 | vbase_offset (-4)
-// CHECK-NEXT: 1 | offset_to_top (0)
-// CHECK-NEXT: 2 | Test22::V2 RTTI
+// CHECK-29: Construction vtable for ('Test22::V2', 16) in 'Test22::C' (3 entries).
+// CHECK-29-NEXT: 0 | vbase_offset (-4)
+// CHECK-29-NEXT: 1 | offset_to_top (0)
+// CHECK-29-NEXT: 2 | Test22::V2 RTTI
struct C : virtual V1, virtual V2 {
int c;
@@ -943,34 +985,34 @@ struct C : A, virtual B {
int c;
};
-// CHECK: Vtable for 'Test23::D' (7 entries).
-// CHECK-NEXT: 0 | vbase_offset (20)
-// CHECK-NEXT: 1 | vbase_offset (24)
-// CHECK-NEXT: 2 | offset_to_top (0)
-// CHECK-NEXT: 3 | Test23::D RTTI
-// CHECK-NEXT: -- (Test23::C, 0) vtable address --
-// CHECK-NEXT: -- (Test23::D, 0) vtable address --
-// CHECK-NEXT: 4 | vbase_offset (-4)
-// CHECK-NEXT: 5 | offset_to_top (-24)
-// CHECK-NEXT: 6 | Test23::D RTTI
-// CHECK-NEXT: -- (Test23::B, 24) vtable address --
-
-// CHECK: Construction vtable for ('Test23::C', 0) in 'Test23::D' (7 entries).
-// CHECK-NEXT: 0 | vbase_offset (20)
-// CHECK-NEXT: 1 | vbase_offset (24)
-// CHECK-NEXT: 2 | offset_to_top (0)
-// CHECK-NEXT: 3 | Test23::C RTTI
-// CHECK-NEXT: -- (Test23::C, 0) vtable address --
-// CHECK-NEXT: 4 | vbase_offset (-4)
-// CHECK-NEXT: 5 | offset_to_top (-24)
-// CHECK-NEXT: 6 | Test23::C RTTI
-// CHECK-NEXT: -- (Test23::B, 24) vtable address --
-
-// CHECK: Construction vtable for ('Test23::B', 24) in 'Test23::D' (3 entries).
-// CHECK-NEXT: 0 | vbase_offset (-4)
-// CHECK-NEXT: 1 | offset_to_top (0)
-// CHECK-NEXT: 2 | Test23::B RTTI
-// CHECK-NEXT: -- (Test23::B, 24) vtable address --
+// CHECK-30: Vtable for 'Test23::D' (7 entries).
+// CHECK-30-NEXT: 0 | vbase_offset (20)
+// CHECK-30-NEXT: 1 | vbase_offset (24)
+// CHECK-30-NEXT: 2 | offset_to_top (0)
+// CHECK-30-NEXT: 3 | Test23::D RTTI
+// CHECK-30-NEXT: -- (Test23::C, 0) vtable address --
+// CHECK-30-NEXT: -- (Test23::D, 0) vtable address --
+// CHECK-30-NEXT: 4 | vbase_offset (-4)
+// CHECK-30-NEXT: 5 | offset_to_top (-24)
+// CHECK-30-NEXT: 6 | Test23::D RTTI
+// CHECK-30-NEXT: -- (Test23::B, 24) vtable address --
+
+// CHECK-30: Construction vtable for ('Test23::C', 0) in 'Test23::D' (7 entries).
+// CHECK-30-NEXT: 0 | vbase_offset (20)
+// CHECK-30-NEXT: 1 | vbase_offset (24)
+// CHECK-30-NEXT: 2 | offset_to_top (0)
+// CHECK-30-NEXT: 3 | Test23::C RTTI
+// CHECK-30-NEXT: -- (Test23::C, 0) vtable address --
+// CHECK-30-NEXT: 4 | vbase_offset (-4)
+// CHECK-30-NEXT: 5 | offset_to_top (-24)
+// CHECK-30-NEXT: 6 | Test23::C RTTI
+// CHECK-30-NEXT: -- (Test23::B, 24) vtable address --
+
+// CHECK-30: Construction vtable for ('Test23::B', 24) in 'Test23::D' (3 entries).
+// CHECK-30-NEXT: 0 | vbase_offset (-4)
+// CHECK-30-NEXT: 1 | offset_to_top (0)
+// CHECK-30-NEXT: 2 | Test23::B RTTI
+// CHECK-30-NEXT: -- (Test23::B, 24) vtable address --
struct D : virtual A, virtual B, C {
int d;
@@ -978,7 +1020,7 @@ struct D : virtual A, virtual B, C {
void f();
};
void D::f() { }
-
+ D d;
}
namespace Test24 {
@@ -992,43 +1034,43 @@ struct A {
struct B : virtual A { };
struct C : virtual A { };
-// CHECK: Vtable for 'Test24::D' (10 entries).
-// CHECK-NEXT: 0 | vbase_offset (0)
-// CHECK-NEXT: 1 | vcall_offset (0)
-// CHECK-NEXT: 2 | offset_to_top (0)
-// CHECK-NEXT: 3 | Test24::D RTTI
-// CHECK-NEXT: -- (Test24::A, 0) vtable address --
-// CHECK-NEXT: -- (Test24::B, 0) vtable address --
-// CHECK-NEXT: -- (Test24::D, 0) vtable address --
-// CHECK-NEXT: 4 | void Test24::D::f()
-// CHECK-NEXT: 5 | vbase_offset (-8)
-// CHECK-NEXT: 6 | vcall_offset (-8)
-// CHECK-NEXT: 7 | offset_to_top (-8)
-// CHECK-NEXT: 8 | Test24::D RTTI
-// CHECK-NEXT: -- (Test24::C, 8) vtable address --
-// CHECK-NEXT: 9 | [unused] void Test24::D::f()
-
-// CHECK: Construction vtable for ('Test24::B', 0) in 'Test24::D' (5 entries).
-// CHECK-NEXT: 0 | vbase_offset (0)
-// CHECK-NEXT: 1 | vcall_offset (0)
-// CHECK-NEXT: 2 | offset_to_top (0)
-// CHECK-NEXT: 3 | Test24::B RTTI
-// CHECK-NEXT: -- (Test24::A, 0) vtable address --
-// CHECK-NEXT: -- (Test24::B, 0) vtable address --
-// CHECK-NEXT: 4 | void Test24::A::f()
-
-// CHECK: Construction vtable for ('Test24::C', 8) in 'Test24::D' (9 entries).
-// CHECK-NEXT: 0 | vbase_offset (-8)
-// CHECK-NEXT: 1 | vcall_offset (-8)
-// CHECK-NEXT: 2 | offset_to_top (0)
-// CHECK-NEXT: 3 | Test24::C RTTI
-// 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-31: Vtable for 'Test24::D' (10 entries).
+// CHECK-31-NEXT: 0 | vbase_offset (0)
+// CHECK-31-NEXT: 1 | vcall_offset (0)
+// CHECK-31-NEXT: 2 | offset_to_top (0)
+// CHECK-31-NEXT: 3 | Test24::D RTTI
+// CHECK-31-NEXT: -- (Test24::A, 0) vtable address --
+// CHECK-31-NEXT: -- (Test24::B, 0) vtable address --
+// CHECK-31-NEXT: -- (Test24::D, 0) vtable address --
+// CHECK-31-NEXT: 4 | void Test24::D::f()
+// CHECK-31-NEXT: 5 | vbase_offset (-8)
+// CHECK-31-NEXT: 6 | vcall_offset (-8)
+// CHECK-31-NEXT: 7 | offset_to_top (-8)
+// CHECK-31-NEXT: 8 | Test24::D RTTI
+// CHECK-31-NEXT: -- (Test24::C, 8) vtable address --
+// CHECK-31-NEXT: 9 | [unused] void Test24::D::f()
+
+// CHECK-31: Construction vtable for ('Test24::B', 0) in 'Test24::D' (5 entries).
+// CHECK-31-NEXT: 0 | vbase_offset (0)
+// CHECK-31-NEXT: 1 | vcall_offset (0)
+// CHECK-31-NEXT: 2 | offset_to_top (0)
+// CHECK-31-NEXT: 3 | Test24::B RTTI
+// CHECK-31-NEXT: -- (Test24::A, 0) vtable address --
+// CHECK-31-NEXT: -- (Test24::B, 0) vtable address --
+// CHECK-31-NEXT: 4 | void Test24::A::f()
+
+// CHECK-31: Construction vtable for ('Test24::C', 8) in 'Test24::D' (9 entries).
+// CHECK-31-NEXT: 0 | vbase_offset (-8)
+// CHECK-31-NEXT: 1 | vcall_offset (-8)
+// CHECK-31-NEXT: 2 | offset_to_top (0)
+// CHECK-31-NEXT: 3 | Test24::C RTTI
+// CHECK-31-NEXT: -- (Test24::C, 8) vtable address --
+// CHECK-31-NEXT: 4 | [unused] void Test24::A::f()
+// CHECK-31-NEXT: 5 | vcall_offset (0)
+// CHECK-31-NEXT: 6 | offset_to_top (8)
+// CHECK-31-NEXT: 7 | Test24::C RTTI
+// CHECK-31-NEXT: -- (Test24::A, 0) vtable address --
+// CHECK-31-NEXT: 8 | void Test24::A::f()
struct D : B, C {
virtual void f();
};
@@ -1047,44 +1089,44 @@ struct V {
struct A : virtual V { };
struct B : virtual V { };
-// CHECK: Vtable for 'Test25::C' (11 entries).
-// CHECK-NEXT: 0 | vbase_offset (0)
-// CHECK-NEXT: 1 | vcall_offset (0)
-// CHECK-NEXT: 2 | offset_to_top (0)
-// CHECK-NEXT: 3 | Test25::C RTTI
-// CHECK-NEXT: -- (Test25::A, 0) vtable address --
-// CHECK-NEXT: -- (Test25::C, 0) vtable address --
-// CHECK-NEXT: -- (Test25::V, 0) vtable address --
-// CHECK-NEXT: 4 | void Test25::V::f()
-// CHECK-NEXT: 5 | void Test25::C::g()
-// CHECK-NEXT: 6 | vbase_offset (-8)
-// CHECK-NEXT: 7 | vcall_offset (-8)
-// CHECK-NEXT: 8 | offset_to_top (-8)
-// CHECK-NEXT: 9 | Test25::C RTTI
-// CHECK-NEXT: -- (Test25::B, 8) vtable address --
-// CHECK-NEXT: 10 | [unused] void Test25::V::f()
-
-// CHECK: Construction vtable for ('Test25::A', 0) in 'Test25::C' (5 entries).
-// CHECK-NEXT: 0 | vbase_offset (0)
-// CHECK-NEXT: 1 | vcall_offset (0)
-// CHECK-NEXT: 2 | offset_to_top (0)
-// CHECK-NEXT: 3 | Test25::A RTTI
-// CHECK-NEXT: -- (Test25::A, 0) vtable address --
-// CHECK-NEXT: -- (Test25::V, 0) vtable address --
-// CHECK-NEXT: 4 | void Test25::V::f()
-
-// CHECK: Construction vtable for ('Test25::B', 8) in 'Test25::C' (9 entries).
-// CHECK-NEXT: 0 | vbase_offset (-8)
-// CHECK-NEXT: 1 | vcall_offset (-8)
-// CHECK-NEXT: 2 | offset_to_top (0)
-// CHECK-NEXT: 3 | Test25::B RTTI
-// CHECK-NEXT: -- (Test25::B, 8) vtable address --
-// CHECK-NEXT: 4 | [unused] void Test25::V::f()
-// CHECK-NEXT: 5 | vcall_offset (0)
-// CHECK-NEXT: 6 | offset_to_top (8)
-// CHECK-NEXT: 7 | Test25::B RTTI
-// CHECK-NEXT: -- (Test25::V, 0) vtable address --
-// CHECK-NEXT: 8 | void Test25::V::f()
+// CHECK-32: Vtable for 'Test25::C' (11 entries).
+// CHECK-32-NEXT: 0 | vbase_offset (0)
+// CHECK-32-NEXT: 1 | vcall_offset (0)
+// CHECK-32-NEXT: 2 | offset_to_top (0)
+// CHECK-32-NEXT: 3 | Test25::C RTTI
+// CHECK-32-NEXT: -- (Test25::A, 0) vtable address --
+// CHECK-32-NEXT: -- (Test25::C, 0) vtable address --
+// CHECK-32-NEXT: -- (Test25::V, 0) vtable address --
+// CHECK-32-NEXT: 4 | void Test25::V::f()
+// CHECK-32-NEXT: 5 | void Test25::C::g()
+// CHECK-32-NEXT: 6 | vbase_offset (-8)
+// CHECK-32-NEXT: 7 | vcall_offset (-8)
+// CHECK-32-NEXT: 8 | offset_to_top (-8)
+// CHECK-32-NEXT: 9 | Test25::C RTTI
+// CHECK-32-NEXT: -- (Test25::B, 8) vtable address --
+// CHECK-32-NEXT: 10 | [unused] void Test25::V::f()
+
+// CHECK-32: Construction vtable for ('Test25::A', 0) in 'Test25::C' (5 entries).
+// CHECK-32-NEXT: 0 | vbase_offset (0)
+// CHECK-32-NEXT: 1 | vcall_offset (0)
+// CHECK-32-NEXT: 2 | offset_to_top (0)
+// CHECK-32-NEXT: 3 | Test25::A RTTI
+// CHECK-32-NEXT: -- (Test25::A, 0) vtable address --
+// CHECK-32-NEXT: -- (Test25::V, 0) vtable address --
+// CHECK-32-NEXT: 4 | void Test25::V::f()
+
+// CHECK-32: Construction vtable for ('Test25::B', 8) in 'Test25::C' (9 entries).
+// CHECK-32-NEXT: 0 | vbase_offset (-8)
+// CHECK-32-NEXT: 1 | vcall_offset (-8)
+// CHECK-32-NEXT: 2 | offset_to_top (0)
+// CHECK-32-NEXT: 3 | Test25::B RTTI
+// CHECK-32-NEXT: -- (Test25::B, 8) vtable address --
+// CHECK-32-NEXT: 4 | [unused] void Test25::V::f()
+// CHECK-32-NEXT: 5 | vcall_offset (0)
+// CHECK-32-NEXT: 6 | offset_to_top (8)
+// CHECK-32-NEXT: 7 | Test25::B RTTI
+// CHECK-32-NEXT: -- (Test25::V, 0) vtable address --
+// CHECK-32-NEXT: 8 | void Test25::V::f()
struct C : A, virtual V, B {
virtual void g();
};
@@ -1109,37 +1151,37 @@ struct C : virtual A {
virtual void b();
};
-// CHECK: Vtable for 'Test26::D' (15 entries).
-// CHECK-NEXT: 0 | vbase_offset (8)
-// CHECK-NEXT: 1 | vbase_offset (8)
-// CHECK-NEXT: 2 | vbase_offset (0)
-// CHECK-NEXT: 3 | vcall_offset (0)
-// CHECK-NEXT: 4 | offset_to_top (0)
-// CHECK-NEXT: 5 | Test26::D RTTI
-// CHECK-NEXT: -- (Test26::B, 0) vtable address --
-// CHECK-NEXT: -- (Test26::D, 0) vtable address --
-// CHECK-NEXT: 6 | void Test26::B::c()
-// CHECK-NEXT: 7 | void Test26::D::d()
-// CHECK-NEXT: 8 | vcall_offset (0)
-// CHECK-NEXT: 9 | vbase_offset (0)
-// CHECK-NEXT: 10 | vcall_offset (0)
-// CHECK-NEXT: 11 | offset_to_top (-8)
-// CHECK-NEXT: 12 | Test26::D RTTI
-// CHECK-NEXT: -- (Test26::A, 8) vtable address --
-// CHECK-NEXT: -- (Test26::C, 8) vtable address --
-// CHECK-NEXT: 13 | void Test26::A::a()
-// CHECK-NEXT: 14 | void Test26::C::b()
-
-// CHECK: Construction vtable for ('Test26::C', 8) in 'Test26::D' (7 entries).
-// CHECK-NEXT: 0 | vcall_offset (0)
-// CHECK-NEXT: 1 | vbase_offset (0)
-// CHECK-NEXT: 2 | vcall_offset (0)
-// CHECK-NEXT: 3 | offset_to_top (0)
-// CHECK-NEXT: 4 | Test26::C RTTI
-// CHECK-NEXT: -- (Test26::A, 8) vtable address --
-// CHECK-NEXT: -- (Test26::C, 8) vtable address --
-// CHECK-NEXT: 5 | void Test26::A::a()
-// CHECK-NEXT: 6 | void Test26::C::b()
+// CHECK-33: Vtable for 'Test26::D' (15 entries).
+// CHECK-33-NEXT: 0 | vbase_offset (8)
+// CHECK-33-NEXT: 1 | vbase_offset (8)
+// CHECK-33-NEXT: 2 | vbase_offset (0)
+// CHECK-33-NEXT: 3 | vcall_offset (0)
+// CHECK-33-NEXT: 4 | offset_to_top (0)
+// CHECK-33-NEXT: 5 | Test26::D RTTI
+// CHECK-33-NEXT: -- (Test26::B, 0) vtable address --
+// CHECK-33-NEXT: -- (Test26::D, 0) vtable address --
+// CHECK-33-NEXT: 6 | void Test26::B::c()
+// CHECK-33-NEXT: 7 | void Test26::D::d()
+// CHECK-33-NEXT: 8 | vcall_offset (0)
+// CHECK-33-NEXT: 9 | vbase_offset (0)
+// CHECK-33-NEXT: 10 | vcall_offset (0)
+// CHECK-33-NEXT: 11 | offset_to_top (-8)
+// CHECK-33-NEXT: 12 | Test26::D RTTI
+// CHECK-33-NEXT: -- (Test26::A, 8) vtable address --
+// CHECK-33-NEXT: -- (Test26::C, 8) vtable address --
+// CHECK-33-NEXT: 13 | void Test26::A::a()
+// CHECK-33-NEXT: 14 | void Test26::C::b()
+
+// CHECK-33: Construction vtable for ('Test26::C', 8) in 'Test26::D' (7 entries).
+// CHECK-33-NEXT: 0 | vcall_offset (0)
+// CHECK-33-NEXT: 1 | vbase_offset (0)
+// CHECK-33-NEXT: 2 | vcall_offset (0)
+// CHECK-33-NEXT: 3 | offset_to_top (0)
+// CHECK-33-NEXT: 4 | Test26::C RTTI
+// CHECK-33-NEXT: -- (Test26::A, 8) vtable address --
+// CHECK-33-NEXT: -- (Test26::C, 8) vtable address --
+// CHECK-33-NEXT: 5 | void Test26::A::a()
+// CHECK-33-NEXT: 6 | void Test26::C::b()
class D : virtual B, virtual C {
virtual void d();
};
@@ -1168,39 +1210,39 @@ struct D : A, virtual B, C {
virtual void d();
};
-// CHECK: Vtable for 'Test27::E' (13 entries).
-// CHECK-NEXT: 0 | vbase_offset (16)
-// CHECK-NEXT: 1 | offset_to_top (0)
-// CHECK-NEXT: 2 | Test27::E RTTI
-// CHECK-NEXT: -- (Test27::A, 0) vtable address --
-// CHECK-NEXT: -- (Test27::D, 0) vtable address --
-// CHECK-NEXT: -- (Test27::E, 0) vtable address --
-// CHECK-NEXT: 3 | void Test27::A::a()
-// CHECK-NEXT: 4 | void Test27::D::d()
-// CHECK-NEXT: 5 | void Test27::E::e()
-// CHECK-NEXT: 6 | offset_to_top (-8)
-// CHECK-NEXT: 7 | Test27::E RTTI
-// CHECK-NEXT: -- (Test27::C, 8) vtable address --
-// CHECK-NEXT: 8 | void Test27::C::c()
-// CHECK-NEXT: 9 | vcall_offset (0)
-// CHECK-NEXT: 10 | offset_to_top (-16)
-// CHECK-NEXT: 11 | Test27::E RTTI
-// CHECK-NEXT: -- (Test27::B, 16) vtable address --
-// CHECK-NEXT: 12 | void Test27::B::b()
-
-// CHECK: Construction vtable for ('Test27::D', 0) in 'Test27::E' (9 entries).
-// CHECK-NEXT: 0 | vbase_offset (16)
-// CHECK-NEXT: 1 | offset_to_top (0)
-// CHECK-NEXT: 2 | Test27::D RTTI
-// CHECK-NEXT: -- (Test27::A, 0) vtable address --
-// CHECK-NEXT: -- (Test27::D, 0) vtable address --
-// CHECK-NEXT: 3 | void Test27::A::a()
-// CHECK-NEXT: 4 | void Test27::D::d()
-// CHECK-NEXT: 5 | vcall_offset (0)
-// CHECK-NEXT: 6 | offset_to_top (-16)
-// CHECK-NEXT: 7 | Test27::D RTTI
-// CHECK-NEXT: -- (Test27::B, 16) vtable address --
-// CHECK-NEXT: 8 | void Test27::B::b()
+// CHECK-34: Vtable for 'Test27::E' (13 entries).
+// CHECK-34-NEXT: 0 | vbase_offset (16)
+// CHECK-34-NEXT: 1 | offset_to_top (0)
+// CHECK-34-NEXT: 2 | Test27::E RTTI
+// CHECK-34-NEXT: -- (Test27::A, 0) vtable address --
+// CHECK-34-NEXT: -- (Test27::D, 0) vtable address --
+// CHECK-34-NEXT: -- (Test27::E, 0) vtable address --
+// CHECK-34-NEXT: 3 | void Test27::A::a()
+// CHECK-34-NEXT: 4 | void Test27::D::d()
+// CHECK-34-NEXT: 5 | void Test27::E::e()
+// CHECK-34-NEXT: 6 | offset_to_top (-8)
+// CHECK-34-NEXT: 7 | Test27::E RTTI
+// CHECK-34-NEXT: -- (Test27::C, 8) vtable address --
+// CHECK-34-NEXT: 8 | void Test27::C::c()
+// CHECK-34-NEXT: 9 | vcall_offset (0)
+// CHECK-34-NEXT: 10 | offset_to_top (-16)
+// CHECK-34-NEXT: 11 | Test27::E RTTI
+// CHECK-34-NEXT: -- (Test27::B, 16) vtable address --
+// CHECK-34-NEXT: 12 | void Test27::B::b()
+
+// CHECK-34: Construction vtable for ('Test27::D', 0) in 'Test27::E' (9 entries).
+// CHECK-34-NEXT: 0 | vbase_offset (16)
+// CHECK-34-NEXT: 1 | offset_to_top (0)
+// CHECK-34-NEXT: 2 | Test27::D RTTI
+// CHECK-34-NEXT: -- (Test27::A, 0) vtable address --
+// CHECK-34-NEXT: -- (Test27::D, 0) vtable address --
+// CHECK-34-NEXT: 3 | void Test27::A::a()
+// CHECK-34-NEXT: 4 | void Test27::D::d()
+// CHECK-34-NEXT: 5 | vcall_offset (0)
+// CHECK-34-NEXT: 6 | offset_to_top (-16)
+// CHECK-34-NEXT: 7 | Test27::D RTTI
+// CHECK-34-NEXT: -- (Test27::B, 16) vtable address --
+// CHECK-34-NEXT: 8 | void Test27::B::b()
struct E : D {
virtual void e();
};
@@ -1228,45 +1270,45 @@ struct C : A, B {
struct D : virtual C {
};
-// CHECK: Vtable for 'Test28::E' (14 entries).
-// CHECK-NEXT: 0 | vbase_offset (8)
-// CHECK-NEXT: 1 | offset_to_top (0)
-// CHECK-NEXT: 2 | Test28::E RTTI
-// CHECK-NEXT: -- (Test28::D, 0) vtable address --
-// CHECK-NEXT: -- (Test28::E, 0) vtable address --
-// CHECK-NEXT: 3 | void Test28::E::e()
-// CHECK-NEXT: 4 | vcall_offset (8)
-// CHECK-NEXT: 5 | vcall_offset (0)
-// CHECK-NEXT: 6 | vcall_offset (0)
-// CHECK-NEXT: 7 | offset_to_top (-8)
-// CHECK-NEXT: 8 | Test28::E RTTI
-// CHECK-NEXT: -- (Test28::A, 8) vtable address --
-// CHECK-NEXT: -- (Test28::C, 8) vtable address --
-// CHECK-NEXT: 9 | void Test28::A::a()
-// CHECK-NEXT: 10 | void Test28::C::c()
-// CHECK-NEXT: 11 | offset_to_top (-16)
-// CHECK-NEXT: 12 | Test28::E RTTI
-// CHECK-NEXT: -- (Test28::B, 16) vtable address --
-// CHECK-NEXT: 13 | void Test28::B::b()
-
-// CHECK: Construction vtable for ('Test28::D', 0) in 'Test28::E' (13 entries).
-// CHECK-NEXT: 0 | vbase_offset (8)
-// CHECK-NEXT: 1 | offset_to_top (0)
-// CHECK-NEXT: 2 | Test28::D RTTI
-// CHECK-NEXT: -- (Test28::D, 0) vtable address --
-// CHECK-NEXT: 3 | vcall_offset (8)
-// CHECK-NEXT: 4 | vcall_offset (0)
-// CHECK-NEXT: 5 | vcall_offset (0)
-// CHECK-NEXT: 6 | offset_to_top (-8)
-// CHECK-NEXT: 7 | Test28::D RTTI
-// CHECK-NEXT: -- (Test28::A, 8) vtable address --
-// CHECK-NEXT: -- (Test28::C, 8) vtable address --
-// CHECK-NEXT: 8 | void Test28::A::a()
-// CHECK-NEXT: 9 | void Test28::C::c()
-// CHECK-NEXT: 10 | offset_to_top (-16)
-// CHECK-NEXT: 11 | Test28::D RTTI
-// CHECK-NEXT: -- (Test28::B, 16) vtable address --
-// CHECK-NEXT: 12 | void Test28::B::b()
+// CHECK-35: Vtable for 'Test28::E' (14 entries).
+// CHECK-35-NEXT: 0 | vbase_offset (8)
+// CHECK-35-NEXT: 1 | offset_to_top (0)
+// CHECK-35-NEXT: 2 | Test28::E RTTI
+// CHECK-35-NEXT: -- (Test28::D, 0) vtable address --
+// CHECK-35-NEXT: -- (Test28::E, 0) vtable address --
+// CHECK-35-NEXT: 3 | void Test28::E::e()
+// CHECK-35-NEXT: 4 | vcall_offset (8)
+// CHECK-35-NEXT: 5 | vcall_offset (0)
+// CHECK-35-NEXT: 6 | vcall_offset (0)
+// CHECK-35-NEXT: 7 | offset_to_top (-8)
+// CHECK-35-NEXT: 8 | Test28::E RTTI
+// CHECK-35-NEXT: -- (Test28::A, 8) vtable address --
+// CHECK-35-NEXT: -- (Test28::C, 8) vtable address --
+// CHECK-35-NEXT: 9 | void Test28::A::a()
+// CHECK-35-NEXT: 10 | void Test28::C::c()
+// CHECK-35-NEXT: 11 | offset_to_top (-16)
+// CHECK-35-NEXT: 12 | Test28::E RTTI
+// CHECK-35-NEXT: -- (Test28::B, 16) vtable address --
+// CHECK-35-NEXT: 13 | void Test28::B::b()
+
+// CHECK-35: Construction vtable for ('Test28::D', 0) in 'Test28::E' (13 entries).
+// CHECK-35-NEXT: 0 | vbase_offset (8)
+// CHECK-35-NEXT: 1 | offset_to_top (0)
+// CHECK-35-NEXT: 2 | Test28::D RTTI
+// CHECK-35-NEXT: -- (Test28::D, 0) vtable address --
+// CHECK-35-NEXT: 3 | vcall_offset (8)
+// CHECK-35-NEXT: 4 | vcall_offset (0)
+// CHECK-35-NEXT: 5 | vcall_offset (0)
+// CHECK-35-NEXT: 6 | offset_to_top (-8)
+// CHECK-35-NEXT: 7 | Test28::D RTTI
+// CHECK-35-NEXT: -- (Test28::A, 8) vtable address --
+// CHECK-35-NEXT: -- (Test28::C, 8) vtable address --
+// CHECK-35-NEXT: 8 | void Test28::A::a()
+// CHECK-35-NEXT: 9 | void Test28::C::c()
+// CHECK-35-NEXT: 10 | offset_to_top (-16)
+// CHECK-35-NEXT: 11 | Test28::D RTTI
+// CHECK-35-NEXT: -- (Test28::B, 16) vtable address --
+// CHECK-35-NEXT: 12 | void Test28::B::b()
struct E : D {
virtual void e();
};
@@ -1286,17 +1328,17 @@ 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()
+// CHECK-36: Vtable for 'Test29::B' (6 entries).
+// CHECK-36-NEXT: 0 | vbase_offset (0)
+// CHECK-36-NEXT: 1 | vcall_offset (0)
+// CHECK-36-NEXT: 2 | offset_to_top (0)
+// CHECK-36-NEXT: 3 | Test29::B RTTI
+// CHECK-36-NEXT: -- (Test29::A, 0) vtable address --
+// CHECK-36-NEXT: -- (Test29::B, 0) vtable address --
+// CHECK-36-NEXT: 4 | Test29::V2 *Test29::B::f()
+// CHECK-36-NEXT: [return adjustment: 0 non-virtual, -24 vbase offset offset]
+// CHECK-36-NEXT: [this adjustment: 0 non-virtual, -24 vcall offset offset]
+// CHECK-36-NEXT: 5 | Test29::V2 *Test29::B::f()
struct B : virtual A {
virtual V2 *f();
};
@@ -1342,22 +1384,22 @@ struct C : A, virtual B {
virtual void f();
};
-// CHECK: Vtable for 'Test31::D' (11 entries).
-// CHECK-NEXT: 0 | vbase_offset (0)
-// CHECK-NEXT: 1 | vbase_offset (8)
-// CHECK-NEXT: 2 | vcall_offset (0)
-// CHECK-NEXT: 3 | offset_to_top (0)
-// CHECK-NEXT: 4 | Test31::D RTTI
-// CHECK-NEXT: -- (Test31::B, 0) vtable address --
-// CHECK-NEXT: -- (Test31::D, 0) vtable address --
-// CHECK-NEXT: 5 | void Test31::D::f()
-// CHECK-NEXT: 6 | vbase_offset (-8)
-// CHECK-NEXT: 7 | vcall_offset (-8)
-// CHECK-NEXT: 8 | offset_to_top (-8)
-// CHECK-NEXT: 9 | Test31::D RTTI
-// CHECK-NEXT: -- (Test31::C, 8) vtable address --
-// CHECK-NEXT: 10 | void Test31::D::f()
-// CHECK-NEXT: [this adjustment: 0 non-virtual, -24 vcall offset offset]
+// CHECK-37: Vtable for 'Test31::D' (11 entries).
+// CHECK-37-NEXT: 0 | vbase_offset (0)
+// CHECK-37-NEXT: 1 | vbase_offset (8)
+// CHECK-37-NEXT: 2 | vcall_offset (0)
+// CHECK-37-NEXT: 3 | offset_to_top (0)
+// CHECK-37-NEXT: 4 | Test31::D RTTI
+// CHECK-37-NEXT: -- (Test31::B, 0) vtable address --
+// CHECK-37-NEXT: -- (Test31::D, 0) vtable address --
+// CHECK-37-NEXT: 5 | void Test31::D::f()
+// CHECK-37-NEXT: 6 | vbase_offset (-8)
+// CHECK-37-NEXT: 7 | vcall_offset (-8)
+// CHECK-37-NEXT: 8 | offset_to_top (-8)
+// CHECK-37-NEXT: 9 | Test31::D RTTI
+// CHECK-37-NEXT: -- (Test31::C, 8) vtable address --
+// CHECK-37-NEXT: 10 | void Test31::D::f()
+// CHECK-37-NEXT: [this adjustment: 0 non-virtual, -24 vcall offset offset]
struct D : virtual C {
virtual void f();
};
@@ -1377,10 +1419,10 @@ struct B : virtual A { };
struct C : A, virtual B { };
struct D : virtual B { };
-// CHECK: Virtual base offset offsets for 'Test32::E' (3 entries).
-// CHECK-NEXT: Test32::A | -32
-// CHECK-NEXT: Test32::B | -24
-// CHECK-NEXT: Test32::D | -40
+// CHECK-38: Virtual base offset offsets for 'Test32::E' (3 entries).
+// CHECK-38-NEXT: Test32::A | -32
+// CHECK-38-NEXT: Test32::B | -24
+// CHECK-38-NEXT: Test32::D | -40
struct E : C, virtual D {
virtual void f();
};
@@ -1410,45 +1452,45 @@ struct E : A, D {
virtual void e();
};
-// CHECK: Vtable for 'Test33::F' (30 entries).
-// CHECK-NEXT: 0 | vbase_offset (24)
-// CHECK-NEXT: 1 | vbase_offset (16)
-// CHECK-NEXT: 2 | vbase_offset (16)
-// CHECK-NEXT: 3 | vbase_offset (8)
-// CHECK-NEXT: 4 | offset_to_top (0)
-// CHECK-NEXT: 5 | Test33::F RTTI
-// CHECK-NEXT: -- (Test33::A, 0) vtable address --
-// CHECK-NEXT: -- (Test33::F, 0) vtable address --
-// CHECK-NEXT: 6 | void Test33::A::a()
-// CHECK-NEXT: 7 | void Test33::F::f()
-// CHECK-NEXT: 8 | vcall_offset (0)
-// CHECK-NEXT: 9 | vcall_offset (0)
-// CHECK-NEXT: 10 | vbase_offset (16)
-// CHECK-NEXT: 11 | vbase_offset (8)
-// CHECK-NEXT: 12 | vbase_offset (8)
-// CHECK-NEXT: 13 | offset_to_top (-8)
-// CHECK-NEXT: 14 | Test33::F RTTI
-// CHECK-NEXT: -- (Test33::A, 8) vtable address --
-// CHECK-NEXT: -- (Test33::E, 8) vtable address --
-// CHECK-NEXT: 15 | void Test33::A::a()
-// CHECK-NEXT: 16 | void Test33::E::e()
-// CHECK-NEXT: 17 | vbase_offset (0)
-// CHECK-NEXT: 18 | vcall_offset (0)
-// CHECK-NEXT: 19 | vbase_offset (8)
-// CHECK-NEXT: 20 | vbase_offset (0)
-// CHECK-NEXT: 21 | vcall_offset (0)
-// CHECK-NEXT: 22 | offset_to_top (-16)
-// CHECK-NEXT: 23 | Test33::F RTTI
-// CHECK-NEXT: -- (Test33::A, 16) vtable address --
-// CHECK-NEXT: -- (Test33::C, 16) vtable address --
-// CHECK-NEXT: -- (Test33::D, 16) vtable address --
-// CHECK-NEXT: 24 | void Test33::A::a()
-// CHECK-NEXT: 25 | void Test33::C::c()
-// CHECK-NEXT: 26 | vcall_offset (0)
-// CHECK-NEXT: 27 | offset_to_top (-24)
-// CHECK-NEXT: 28 | Test33::F RTTI
-// CHECK-NEXT: -- (Test33::B, 24) vtable address --
-// CHECK-NEXT: 29 | void Test33::B::b()
+// CHECK-39: Vtable for 'Test33::F' (30 entries).
+// CHECK-39-NEXT: 0 | vbase_offset (24)
+// CHECK-39-NEXT: 1 | vbase_offset (16)
+// CHECK-39-NEXT: 2 | vbase_offset (16)
+// CHECK-39-NEXT: 3 | vbase_offset (8)
+// CHECK-39-NEXT: 4 | offset_to_top (0)
+// CHECK-39-NEXT: 5 | Test33::F RTTI
+// CHECK-39-NEXT: -- (Test33::A, 0) vtable address --
+// CHECK-39-NEXT: -- (Test33::F, 0) vtable address --
+// CHECK-39-NEXT: 6 | void Test33::A::a()
+// CHECK-39-NEXT: 7 | void Test33::F::f()
+// CHECK-39-NEXT: 8 | vcall_offset (0)
+// CHECK-39-NEXT: 9 | vcall_offset (0)
+// CHECK-39-NEXT: 10 | vbase_offset (16)
+// CHECK-39-NEXT: 11 | vbase_offset (8)
+// CHECK-39-NEXT: 12 | vbase_offset (8)
+// CHECK-39-NEXT: 13 | offset_to_top (-8)
+// CHECK-39-NEXT: 14 | Test33::F RTTI
+// CHECK-39-NEXT: -- (Test33::A, 8) vtable address --
+// CHECK-39-NEXT: -- (Test33::E, 8) vtable address --
+// CHECK-39-NEXT: 15 | void Test33::A::a()
+// CHECK-39-NEXT: 16 | void Test33::E::e()
+// CHECK-39-NEXT: 17 | vbase_offset (0)
+// CHECK-39-NEXT: 18 | vcall_offset (0)
+// CHECK-39-NEXT: 19 | vbase_offset (8)
+// CHECK-39-NEXT: 20 | vbase_offset (0)
+// CHECK-39-NEXT: 21 | vcall_offset (0)
+// CHECK-39-NEXT: 22 | offset_to_top (-16)
+// CHECK-39-NEXT: 23 | Test33::F RTTI
+// CHECK-39-NEXT: -- (Test33::A, 16) vtable address --
+// CHECK-39-NEXT: -- (Test33::C, 16) vtable address --
+// CHECK-39-NEXT: -- (Test33::D, 16) vtable address --
+// CHECK-39-NEXT: 24 | void Test33::A::a()
+// CHECK-39-NEXT: 25 | void Test33::C::c()
+// CHECK-39-NEXT: 26 | vcall_offset (0)
+// CHECK-39-NEXT: 27 | offset_to_top (-24)
+// CHECK-39-NEXT: 28 | Test33::F RTTI
+// CHECK-39-NEXT: -- (Test33::B, 24) vtable address --
+// CHECK-39-NEXT: 29 | void Test33::B::b()
struct F : virtual E, A {
virtual void f();
};
@@ -1475,36 +1517,36 @@ struct E : virtual D {
virtual void e();
};
-// CHECK: Construction vtable for ('Test34::E', 0) in 'Test34::F' (22 entries).
-// CHECK-NEXT: 0 | vbase_offset (0)
-// CHECK-NEXT: 1 | vbase_offset (8)
-// CHECK-NEXT: 2 | vcall_offset (0)
-// CHECK-NEXT: 3 | offset_to_top (0)
-// CHECK-NEXT: 4 | Test34::E RTTI
-// CHECK-NEXT: -- (Test34::A, 0) vtable address --
-// CHECK-NEXT: -- (Test34::E, 0) vtable address --
-// CHECK-NEXT: 5 | void Test34::A::a()
-// CHECK-NEXT: 6 | void Test34::E::e()
-// CHECK-NEXT: 7 | vcall_offset (8)
-// CHECK-NEXT: 8 | vcall_offset (0)
-// CHECK-NEXT: 9 | vbase_offset (-8)
-// CHECK-NEXT: 10 | offset_to_top (-8)
-// CHECK-NEXT: 11 | Test34::E RTTI
-// CHECK-NEXT: -- (Test34::A, 8) vtable address --
-// CHECK-NEXT: -- (Test34::D, 8) vtable address --
-// CHECK-NEXT: 12 | void Test34::A::a()
-// CHECK-NEXT: 13 | vbase_offset (-16)
-// CHECK-NEXT: 14 | vcall_offset (-16)
-// CHECK-NEXT: 15 | offset_to_top (-16)
-// CHECK-NEXT: 16 | Test34::E RTTI
-// CHECK-NEXT: -- (Test34::B, 16) vtable address --
-// CHECK-NEXT: -- (Test34::C, 16) vtable address --
-// CHECK-NEXT: 17 | [unused] void Test34::A::a()
-// CHECK-NEXT: 18 | void Test34::C::c()
-// CHECK-NEXT: 19 | offset_to_top (-24)
-// CHECK-NEXT: 20 | Test34::E RTTI
-// CHECK-NEXT: -- (Test34::A, 24) vtable address --
-// CHECK-NEXT: 21 | void Test34::A::a()
+// CHECK-40: Construction vtable for ('Test34::E', 0) in 'Test34::F' (22 entries).
+// CHECK-40-NEXT: 0 | vbase_offset (0)
+// CHECK-40-NEXT: 1 | vbase_offset (8)
+// CHECK-40-NEXT: 2 | vcall_offset (0)
+// CHECK-40-NEXT: 3 | offset_to_top (0)
+// CHECK-40-NEXT: 4 | Test34::E RTTI
+// CHECK-40-NEXT: -- (Test34::A, 0) vtable address --
+// CHECK-40-NEXT: -- (Test34::E, 0) vtable address --
+// CHECK-40-NEXT: 5 | void Test34::A::a()
+// CHECK-40-NEXT: 6 | void Test34::E::e()
+// CHECK-40-NEXT: 7 | vcall_offset (8)
+// CHECK-40-NEXT: 8 | vcall_offset (0)
+// CHECK-40-NEXT: 9 | vbase_offset (-8)
+// CHECK-40-NEXT: 10 | offset_to_top (-8)
+// CHECK-40-NEXT: 11 | Test34::E RTTI
+// CHECK-40-NEXT: -- (Test34::A, 8) vtable address --
+// CHECK-40-NEXT: -- (Test34::D, 8) vtable address --
+// CHECK-40-NEXT: 12 | void Test34::A::a()
+// CHECK-40-NEXT: 13 | vbase_offset (-16)
+// CHECK-40-NEXT: 14 | vcall_offset (-16)
+// CHECK-40-NEXT: 15 | offset_to_top (-16)
+// CHECK-40-NEXT: 16 | Test34::E RTTI
+// CHECK-40-NEXT: -- (Test34::B, 16) vtable address --
+// CHECK-40-NEXT: -- (Test34::C, 16) vtable address --
+// CHECK-40-NEXT: 17 | [unused] void Test34::A::a()
+// CHECK-40-NEXT: 18 | void Test34::C::c()
+// CHECK-40-NEXT: 19 | offset_to_top (-24)
+// CHECK-40-NEXT: 20 | Test34::E RTTI
+// CHECK-40-NEXT: -- (Test34::A, 24) vtable address --
+// CHECK-40-NEXT: 21 | void Test34::A::a()
struct F : E {
virtual void f();
};
@@ -1543,55 +1585,55 @@ struct E : D {
struct F : virtual D { };
struct G : virtual E { };
-// CHECK: Vtable for 'Test35::H' (32 entries).
-// CHECK-NEXT: 0 | vbase_offset (32)
-// CHECK-NEXT: 1 | vbase_offset (0)
-// CHECK-NEXT: 2 | vcall_offset (0)
-// CHECK-NEXT: 3 | vcall_offset (0)
-// CHECK-NEXT: 4 | vbase_offset (16)
-// CHECK-NEXT: 5 | vbase_offset (8)
-// CHECK-NEXT: 6 | offset_to_top (0)
-// CHECK-NEXT: 7 | Test35::H RTTI
-// CHECK-NEXT: -- (Test35::C, 0) vtable address --
-// CHECK-NEXT: -- (Test35::D, 0) vtable address --
-// CHECK-NEXT: -- (Test35::F, 0) vtable address --
-// CHECK-NEXT: -- (Test35::H, 0) vtable address --
-// CHECK-NEXT: 8 | void Test35::C::c()
-// CHECK-NEXT: 9 | void Test35::D::d()
-// CHECK-NEXT: 10 | void Test35::H::h()
-// CHECK-NEXT: 11 | vbase_offset (0)
-// CHECK-NEXT: 12 | vbase_offset (24)
-// CHECK-NEXT: 13 | vcall_offset (0)
-// CHECK-NEXT: 14 | vbase_offset (8)
-// CHECK-NEXT: 15 | offset_to_top (-8)
-// CHECK-NEXT: 16 | Test35::H RTTI
-// CHECK-NEXT: -- (Test35::B, 8) vtable address --
-// CHECK-NEXT: -- (Test35::G, 8) vtable address --
-// CHECK-NEXT: 17 | void Test35::B::b()
-// CHECK-NEXT: 18 | vcall_offset (0)
-// CHECK-NEXT: 19 | offset_to_top (-16)
-// CHECK-NEXT: 20 | Test35::H RTTI
-// CHECK-NEXT: -- (Test35::A, 16) vtable address --
-// CHECK-NEXT: 21 | void Test35::A::a()
-// CHECK-NEXT: 22 | vcall_offset (0)
-// CHECK-NEXT: 23 | vcall_offset (0)
-// CHECK-NEXT: 24 | vcall_offset (0)
-// CHECK-NEXT: 25 | vbase_offset (-16)
-// CHECK-NEXT: 26 | vbase_offset (-24)
-// CHECK-NEXT: 27 | offset_to_top (-32)
-// CHECK-NEXT: 28 | Test35::H RTTI
-// CHECK-NEXT: -- (Test35::C, 32) vtable address --
-// CHECK-NEXT: -- (Test35::D, 32) vtable address --
-// CHECK-NEXT: -- (Test35::E, 32) vtable address --
-// CHECK-NEXT: 29 | void Test35::C::c()
-// CHECK-NEXT: 30 | void Test35::D::d()
-// CHECK-NEXT: 31 | void Test35::E::e()
-
-// CHECK: Virtual base offset offsets for 'Test35::H' (4 entries).
-// CHECK-NEXT: Test35::A | -32
-// CHECK-NEXT: Test35::B | -24
-// CHECK-NEXT: Test35::D | -56
-// CHECK-NEXT: Test35::E | -64
+// CHECK-41: Vtable for 'Test35::H' (32 entries).
+// CHECK-41-NEXT: 0 | vbase_offset (32)
+// CHECK-41-NEXT: 1 | vbase_offset (0)
+// CHECK-41-NEXT: 2 | vcall_offset (0)
+// CHECK-41-NEXT: 3 | vcall_offset (0)
+// CHECK-41-NEXT: 4 | vbase_offset (16)
+// CHECK-41-NEXT: 5 | vbase_offset (8)
+// CHECK-41-NEXT: 6 | offset_to_top (0)
+// CHECK-41-NEXT: 7 | Test35::H RTTI
+// CHECK-41-NEXT: -- (Test35::C, 0) vtable address --
+// CHECK-41-NEXT: -- (Test35::D, 0) vtable address --
+// CHECK-41-NEXT: -- (Test35::F, 0) vtable address --
+// CHECK-41-NEXT: -- (Test35::H, 0) vtable address --
+// CHECK-41-NEXT: 8 | void Test35::C::c()
+// CHECK-41-NEXT: 9 | void Test35::D::d()
+// CHECK-41-NEXT: 10 | void Test35::H::h()
+// CHECK-41-NEXT: 11 | vbase_offset (0)
+// CHECK-41-NEXT: 12 | vbase_offset (24)
+// CHECK-41-NEXT: 13 | vcall_offset (0)
+// CHECK-41-NEXT: 14 | vbase_offset (8)
+// CHECK-41-NEXT: 15 | offset_to_top (-8)
+// CHECK-41-NEXT: 16 | Test35::H RTTI
+// CHECK-41-NEXT: -- (Test35::B, 8) vtable address --
+// CHECK-41-NEXT: -- (Test35::G, 8) vtable address --
+// CHECK-41-NEXT: 17 | void Test35::B::b()
+// CHECK-41-NEXT: 18 | vcall_offset (0)
+// CHECK-41-NEXT: 19 | offset_to_top (-16)
+// CHECK-41-NEXT: 20 | Test35::H RTTI
+// CHECK-41-NEXT: -- (Test35::A, 16) vtable address --
+// CHECK-41-NEXT: 21 | void Test35::A::a()
+// CHECK-41-NEXT: 22 | vcall_offset (0)
+// CHECK-41-NEXT: 23 | vcall_offset (0)
+// CHECK-41-NEXT: 24 | vcall_offset (0)
+// CHECK-41-NEXT: 25 | vbase_offset (-16)
+// CHECK-41-NEXT: 26 | vbase_offset (-24)
+// CHECK-41-NEXT: 27 | offset_to_top (-32)
+// CHECK-41-NEXT: 28 | Test35::H RTTI
+// CHECK-41-NEXT: -- (Test35::C, 32) vtable address --
+// CHECK-41-NEXT: -- (Test35::D, 32) vtable address --
+// CHECK-41-NEXT: -- (Test35::E, 32) vtable address --
+// CHECK-41-NEXT: 29 | void Test35::C::c()
+// CHECK-41-NEXT: 30 | void Test35::D::d()
+// CHECK-41-NEXT: 31 | void Test35::E::e()
+
+// CHECK-41: Virtual base offset offsets for 'Test35::H' (4 entries).
+// CHECK-41-NEXT: Test35::A | -32
+// CHECK-41-NEXT: Test35::B | -24
+// CHECK-41-NEXT: Test35::D | -56
+// CHECK-41-NEXT: Test35::E | -64
struct H : F, G {
virtual void h();
};
@@ -1613,24 +1655,24 @@ struct C : virtual A {
virtual void f();
};
-// CHECK: Vtable for 'Test36::D' (12 entries).
-// CHECK-NEXT: 0 | vbase_offset (8)
-// CHECK-NEXT: 1 | vbase_offset (8)
-// CHECK-NEXT: 2 | vcall_offset (0)
-// CHECK-NEXT: 3 | offset_to_top (0)
-// CHECK-NEXT: 4 | Test36::D RTTI
-// CHECK-NEXT: -- (Test36::C, 0) vtable address --
-// CHECK-NEXT: -- (Test36::D, 0) vtable address --
-// CHECK-NEXT: 5 | void Test36::C::f()
-// CHECK-NEXT: 6 | void Test36::D::g()
-// CHECK-NEXT: 7 | vbase_offset (0)
-// CHECK-NEXT: 8 | vcall_offset (-8)
-// CHECK-NEXT: 9 | offset_to_top (-8)
-// CHECK-NEXT: 10 | Test36::D RTTI
-// CHECK-NEXT: -- (Test36::A, 8) vtable address --
-// CHECK-NEXT: -- (Test36::B, 8) vtable address --
-// CHECK-NEXT: 11 | void Test36::C::f()
-// CHECK-NEXT: [this adjustment: 0 non-virtual, -24 vcall offset offset]
+// CHECK-42: Vtable for 'Test36::D' (12 entries).
+// CHECK-42-NEXT: 0 | vbase_offset (8)
+// CHECK-42-NEXT: 1 | vbase_offset (8)
+// CHECK-42-NEXT: 2 | vcall_offset (0)
+// CHECK-42-NEXT: 3 | offset_to_top (0)
+// CHECK-42-NEXT: 4 | Test36::D RTTI
+// CHECK-42-NEXT: -- (Test36::C, 0) vtable address --
+// CHECK-42-NEXT: -- (Test36::D, 0) vtable address --
+// CHECK-42-NEXT: 5 | void Test36::C::f()
+// CHECK-42-NEXT: 6 | void Test36::D::g()
+// CHECK-42-NEXT: 7 | vbase_offset (0)
+// CHECK-42-NEXT: 8 | vcall_offset (-8)
+// CHECK-42-NEXT: 9 | offset_to_top (-8)
+// CHECK-42-NEXT: 10 | Test36::D RTTI
+// CHECK-42-NEXT: -- (Test36::A, 8) vtable address --
+// CHECK-42-NEXT: -- (Test36::B, 8) vtable address --
+// CHECK-42-NEXT: 11 | void Test36::C::f()
+// CHECK-42-NEXT: [this adjustment: 0 non-virtual, -24 vcall offset offset]
struct D : virtual B, C {
virtual void g();
};
diff --git a/test/CodeGenCXX/vtable-linkage.cpp b/test/CodeGenCXX/vtable-linkage.cpp
index c75efe228dff..b3b68703c6d3 100644
--- a/test/CodeGenCXX/vtable-linkage.cpp
+++ b/test/CodeGenCXX/vtable-linkage.cpp
@@ -1,4 +1,16 @@
-// RUN: %clang_cc1 %s -triple=x86_64-apple-darwin10 -emit-llvm -o - | FileCheck %s
+// RUN: %clang_cc1 %s -triple=x86_64-apple-darwin10 -emit-llvm -o %t
+// RUN: FileCheck --check-prefix=CHECK-1 %s < %t
+// RUN: FileCheck --check-prefix=CHECK-2 %s < %t
+// RUN: FileCheck --check-prefix=CHECK-3 %s < %t
+// RUN: FileCheck --check-prefix=CHECK-4 %s < %t
+// RUN: FileCheck --check-prefix=CHECK-5 %s < %t
+// RUN: FileCheck --check-prefix=CHECK-6 %s < %t
+// RUN: FileCheck --check-prefix=CHECK-7 %s < %t
+// RUN: FileCheck --check-prefix=CHECK-8 %s < %t
+// RUN: FileCheck --check-prefix=CHECK-9 %s < %t
+// RUN: FileCheck --check-prefix=CHECK-10 %s < %t
+// RUN: FileCheck --check-prefix=CHECK-11 %s < %t
+// RUN: FileCheck --check-prefix=CHECK-12 %s < %t
namespace {
struct A {
@@ -73,7 +85,7 @@ extern template struct F<int>;
void use_F(F<char> &fc) {
F<int> fi;
- (void)fi;
+ fi.foo();
F<long> fl;
(void)fl;
fc.foo();
@@ -81,71 +93,85 @@ void use_F(F<char> &fc) {
// B has a key function that is not defined in this translation unit so its vtable
// has external linkage.
-// CHECK: @_ZTV1B = external constant
+// CHECK-1: @_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-2: @_ZTV1C = weak_odr constant
+// CHECK-2: @_ZTS1C = weak_odr constant
+// CHECK-2: @_ZTI1C = 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-3: @_ZTV1D = constant
+// CHECK-3: @_ZTS1D = constant
+// CHECK-3: @_ZTI1D = 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-4: @_ZTV1EIcE = constant
+// CHECK-4: @_ZTS1EIcE = constant
+// CHECK-4: @_ZTI1EIcE = 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-5: @_ZTV1EIsE = weak_odr constant
+// CHECK-5: @_ZTS1EIsE = weak_odr constant
+// CHECK-5: @_ZTI1EIsE = 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-6: @_ZTV1FIsE = weak_odr constant
+// CHECK-6: @_ZTS1FIsE = weak_odr constant
+// CHECK-6: @_ZTI1FIsE = 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-7: @_ZTV1EIlE = weak_odr constant
+// CHECK-7: @_ZTS1EIlE = weak_odr constant
+// CHECK-7: @_ZTI1EIlE = 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-8: @_ZTV1FIlE = weak_odr constant
+// CHECK-8: @_ZTS1FIlE = weak_odr constant
+// CHECK-8: @_ZTI1FIlE = weak_odr constant
// F<int> is an explicit template instantiation declaration without a
// key function, so its vtable should have external linkage.
-// CHECK: @_ZTV1FIiE = external constant
+// CHECK-9: @_ZTV1FIiE = external constant
// E<int> is an explicit template instantiation declaration. It has a
// key function that is not instantiated, so we should only reference
// its vtable, not define it.
-// CHECK: @_ZTV1EIiE = external constant
+// CHECK-10: @_ZTV1EIiE = external constant
// 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-11: @"_ZTV3$_0" = internal constant
+// CHECK-11: @"_ZTS3$_0" = internal constant
+// CHECK-11: @"_ZTI3$_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-12: @_ZTVN12_GLOBAL__N_11AE = internal constant
+// CHECK-12: @_ZTSN12_GLOBAL__N_11AE = internal constant
+// CHECK-12: @_ZTIN12_GLOBAL__N_11AE = internal constant
+
+// RUN: FileCheck --check-prefix=CHECK-G %s < %t
+//
+// CHECK-G: @_ZTV1GIiE = weak_odr constant
+template <typename T>
+class G {
+public:
+ G() {}
+ virtual void f0();
+ virtual void f1();
+};
+template <>
+void G<int>::f1() {}
+template <typename T>
+void G<T>::f0() {}
+void G_f0() { new G<int>(); }
diff --git a/test/CodeGenCXX/x86_32-arguments.cpp b/test/CodeGenCXX/x86_32-arguments.cpp
index f8d655145b8f..023b7297c7d7 100644
--- a/test/CodeGenCXX/x86_32-arguments.cpp
+++ b/test/CodeGenCXX/x86_32-arguments.cpp
@@ -1,9 +1,9 @@
-// RUN: %clang_cc1 -triple i386-unknown-unknown -emit-llvm -o - %s | FileCheck %s
+// RUN: %clang_cc1 -triple i386-apple-darwin9 -emit-llvm -o - %s | FileCheck %s
// Non-trivial dtors, should both be passed indirectly.
struct S {
~S();
- int s;
+ short s;
};
// CHECK: define void @_Z1fv(%struct.S* sret %
@@ -13,6 +13,7 @@ void f(S) { }
// Non-trivial dtors, should both be passed indirectly.
class C {
+public:
~C();
double c;
};
@@ -22,3 +23,94 @@ C g() { return C(); }
// CHECK: define void @_Z1f1C(%class.C*)
void f(C) { }
+
+
+
+
+// PR7058 - Missing byval on MI thunk definition.
+
+// CHECK: define void @_ZThn4_N18BasicAliasAnalysis13getModRefInfoE8CallSite
+// ...
+// CHECK: %struct.CallSite* byval %CS)
+struct CallSite {
+ unsigned Ptr;
+ CallSite(unsigned XX) : Ptr(XX) {}
+};
+
+struct AliasAnalysis {
+ virtual void xyz();
+ virtual void getModRefInfo(CallSite CS) = 0;
+};
+
+struct ModulePass {
+ virtual void xx();
+};
+
+struct BasicAliasAnalysis : public ModulePass, public AliasAnalysis {
+ void getModRefInfo(CallSite CS);
+};
+
+void BasicAliasAnalysis::getModRefInfo(CallSite CS) {
+}
+
+// Check various single element struct type conditions.
+//
+// PR7098.
+
+// CHECK: define i64 @_Z2f0v()
+struct s0_0 { int x; };
+struct s0_1 : s0_0 { int* y; };
+s0_1 f0() { return s0_1(); }
+
+// CHECK: define i32 @_Z2f1v()
+struct s1_0 { int x; };
+struct s1_1 : s1_0 { };
+s1_1 f1() { return s1_1(); }
+
+// CHECK: define double @_Z2f2v()
+struct s2_0 { double x; };
+struct s2_1 : s2_0 { };
+s2_1 f2() { return s2_1(); }
+
+// CHECK: define double @_Z2f3v()
+struct s3_0 { };
+struct s3_1 { double x; };
+struct s3_2 : s3_0, s3_1 { };
+s3_2 f3() { return s3_2(); }
+
+// CHECK: define i64 @_Z2f4v()
+struct s4_0 { float x; };
+struct s4_1 { float x; };
+struct s4_2 : s4_0, s4_1 { };
+s4_2 f4() { return s4_2(); }
+
+// CHECK: define i32 @_Z2f5v()
+struct s5 { s5(); int &x; };
+s5 f5() { return s5(); }
+
+// CHECK: define i32 @_Z4f6_0M2s6i(i32 %a)
+// CHECK: define i64 @_Z4f6_1M2s6FivE(%{{.*}} byval %a)
+// FIXME: It would be nice to avoid byval on the previous case.
+struct s6 {};
+typedef int s6::* s6_mdp;
+typedef int (s6::*s6_mfp)();
+s6_mdp f6_0(s6_mdp a) { return a; }
+s6_mfp f6_1(s6_mfp a) { return a; }
+
+// CHECK: define double @_Z2f7v()
+struct s7_0 { unsigned : 0; };
+struct s7_1 { double x; };
+struct s7 : s7_0, s7_1 { };
+s7 f7() { return s7(); }
+
+// CHECK: define void @_Z2f8v(%struct.s8* sret %agg.result)
+struct s8_0 { };
+struct s8_1 { double x; };
+struct s8 { s8_0 a; s8_1 b; };
+s8 f8() { return s8(); }
+
+// CHECK: define void @_Z2f9v(%struct.s9* sret %agg.result)
+struct s9_0 { unsigned : 0; };
+struct s9_1 { double x; };
+struct s9 { s9_0 a; s9_1 b; };
+s9 f9() { return s9(); }
diff --git a/test/CodeGenCXX/x86_64-arguments.cpp b/test/CodeGenCXX/x86_64-arguments.cpp
index 7ebbedc9989e..4bc83b85134e 100644
--- a/test/CodeGenCXX/x86_64-arguments.cpp
+++ b/test/CodeGenCXX/x86_64-arguments.cpp
@@ -25,3 +25,11 @@ void f2(f2_s1 a0) { }
struct s3_0 {};
struct s3_1 { struct s3_0 a; long b; };
void f3(struct s3_1 x) {}
+
+// CHECK: define i64 @_Z4f4_0M2s4i(i64)
+// CHECK: define [[i64_i64_ty]] @_Z4f4_1M2s4FivE([[i64_i64_ty]])
+struct s4 {};
+typedef int s4::* s4_mdp;
+typedef int (s4::*s4_mfp)();
+s4_mdp f4_0(s4_mdp a) { return a; }
+s4_mfp f4_1(s4_mfp a) { return a; }
diff --git a/test/CodeGenObjC/atomic-aggregate-property.m b/test/CodeGenObjC/atomic-aggregate-property.m
index 2896d379e75a..93eeca820117 100644
--- a/test/CodeGenObjC/atomic-aggregate-property.m
+++ b/test/CodeGenObjC/atomic-aggregate-property.m
@@ -1,4 +1,5 @@
// RUN: %clang_cc1 -triple x86_64-apple-darwin10 -fobjc-nonfragile-abi -fobjc-gc -emit-llvm -o - %s | FileCheck -check-prefix LP64 %s
+// RUN: %clang_cc1 -x objective-c++ -triple x86_64-apple-darwin10 -fobjc-nonfragile-abi -fobjc-gc -emit-llvm -o - %s | FileCheck -check-prefix LP64 %s
// rdar: // 7849824
struct s {
diff --git a/test/CodeGenObjC/blocks-1.m b/test/CodeGenObjC/blocks-1.m
index 76bfd59e41d1..1ac9c30c8a00 100644
--- a/test/CodeGenObjC/blocks-1.m
+++ b/test/CodeGenObjC/blocks-1.m
@@ -8,6 +8,16 @@
// RUN: grep "_Block_object_assign" %t | count 4
// RUN: grep "objc_read_weak" %t | count 2
// RUN: grep "objc_assign_weak" %t | count 3
+// RUN: %clang_cc1 -x objective-c++ %s -emit-llvm -o %t -fobjc-gc -fblocks -triple i386-apple-darwin10
+// RUN: grep "_Block_object_dispose" %t | count 6
+// RUN: grep "__copy_helper_block_" %t | count 4
+// RUN: grep "__destroy_helper_block_" %t | count 4
+// RUN: grep "__Block_byref_id_object_copy_" %t | count 2
+// RUN: grep "__Block_byref_id_object_dispose_" %t | count 2
+// RUN: grep "i32 135)" %t | count 0
+// RUN: grep "_Block_object_assign" %t | count 4
+// RUN: grep "objc_read_weak" %t | count 2
+// RUN: grep "objc_assign_weak" %t | count 3
@interface NSDictionary @end
diff --git a/test/CodeGenObjC/blocks-2.m b/test/CodeGenObjC/blocks-2.m
index 15160cc52b06..0062e842648b 100644
--- a/test/CodeGenObjC/blocks-2.m
+++ b/test/CodeGenObjC/blocks-2.m
@@ -1,5 +1,7 @@
// RUN: %clang_cc1 %s -emit-llvm -o %t -fobjc-gc -fblocks -triple i386-apple-darwin10
// RUN: grep "objc_assign_strongCast" %t | count 2
+// RUN: %clang_cc1 -x objective-c++ %s -emit-llvm -o %t -fobjc-gc -fblocks -triple i386-apple-darwin10
+// RUN: grep "objc_assign_strongCast" %t | count 2
// This should generate a strong cast.
diff --git a/test/CodeGenObjC/blocks-ivar-debug.m b/test/CodeGenObjC/blocks-ivar-debug.m
new file mode 100644
index 000000000000..d0cf1f10f729
--- /dev/null
+++ b/test/CodeGenObjC/blocks-ivar-debug.m
@@ -0,0 +1,20 @@
+// RUN: %clang_cc1 -g %s -fblocks -S -o %t
+// Radar 7959934
+
+@interface NSObject {
+ struct objc_object *isa;
+}
+@end
+@interface Foo : NSObject {
+ int _prop;
+}
+@end
+
+@implementation Foo
+- (int)doSomething {
+ int (^blk)(void) = ^{ return _prop; };
+ return blk();
+}
+
+@end
+
diff --git a/test/CodeGenObjC/blocks.m b/test/CodeGenObjC/blocks.m
index 8ba319eefee1..b96a8d942fac 100644
--- a/test/CodeGenObjC/blocks.m
+++ b/test/CodeGenObjC/blocks.m
@@ -19,7 +19,7 @@ void foo(T *P) {
-(void) im0;
@end
-// RUN: grep 'define internal i32 @"__-\[A im0\]_block_invoke_"' %t
+// RUN: grep 'define internal i32 @"__8-\[A im0\]_block_invoke_0"' %t
@implementation A
-(void) im0 {
(void) ^{ return 1; }();
@@ -31,5 +31,11 @@ void foo(T *P) {
-(void) im1 {
^(void) { [self im0]; }();
}
+-(void) im2 {
+ ^{ [super im0]; }();
+}
+-(void) im3 {
+ ^{ ^{[super im0];}(); }();
+}
@end
diff --git a/test/CodeGenObjC/default-property-synthesis.m b/test/CodeGenObjC/default-property-synthesis.m
new file mode 100644
index 000000000000..b3eeb22004ae
--- /dev/null
+++ b/test/CodeGenObjC/default-property-synthesis.m
@@ -0,0 +1,38 @@
+// RUN: %clang_cc1 -triple x86_64-apple-darwin10 -fobjc-nonfragile-abi2 -emit-llvm -o %t %s
+// rdar://7923851.
+
+// Superclass declares property. Subclass redeclares the same property.
+// Do not @synthesize-by-default in the subclass. P1
+// Superclass declares a property. Subclass declares a different property with the same name
+// (such as different type or attributes). Do not @synthesize-by-default in the subclass. P2
+// Superclass conforms to a protocol that declares a property. Subclass redeclares the
+// same property. Do not @synthesize-by-default in the subclass. P3
+// Superclass conforms to a protocol that declares a property. Subclass conforms to the
+// same protocol or a derived protocol. Do not @synthesize-by-default in the subclass. P4
+
+
+@protocol PROTO
+ @property int P3;
+ @property int P4;
+@end
+
+@protocol PROTO1 <PROTO>
+ @property int IMP1;
+@end
+
+@interface Super <PROTO>
+ @property int P1;
+ @property (copy) id P2;
+@end
+
+@interface Sub : Super <PROTO1>
+ @property int P1;
+ @property (nonatomic, retain) id P2; // expected-warning {{property 'P2' 'copy' attribute does not match the property inherited from 'Super'}} \
+ // expected-warning {{property 'P2' 'atomic' attribute does not match the property inherited from 'Super'}}
+ @property int P3;
+ @property int IMP2;
+@end
+
+@implementation Sub
+@end
+
diff --git a/test/CodeGenObjC/ivar-layout-64-bitfields.m b/test/CodeGenObjC/ivar-layout-64-bitfields.m
index 1b6a16b1b8be..9710e16172df 100644
--- a/test/CodeGenObjC/ivar-layout-64-bitfields.m
+++ b/test/CodeGenObjC/ivar-layout-64-bitfields.m
@@ -1,4 +1,5 @@
// RUN: %clang_cc1 -triple x86_64-apple-darwin9 -fobjc-gc -emit-llvm -o %t %s
+// RUN: %clang_cc1 -x objective-c++ -triple x86_64-apple-darwin9 -fobjc-gc -emit-llvm -o %t %s
@interface I
{
struct {
diff --git a/test/CodeGenObjC/ivar-layout-64.m b/test/CodeGenObjC/ivar-layout-64.m
index 60ce1dff57de..f227bfc30d36 100644
--- a/test/CodeGenObjC/ivar-layout-64.m
+++ b/test/CodeGenObjC/ivar-layout-64.m
@@ -4,6 +4,12 @@
// RUN: grep '@"\\01L_OBJC_CLASS_NAME_.*" = internal global .* c"\\11q\\10\\00"' %t
// RUN: grep '@"\\01L_OBJC_CLASS_NAME_.*" = internal global .* c"!q\\00"' %t
// RUN: grep '@"\\01L_OBJC_CLASS_NAME_.*" = internal global .* c"\\01\\14\\00"' %t
+// RUNX: llvm-gcc -ObjC++ -m64 -fobjc-gc -emit-llvm -S -o %t %s &&
+// RUN: %clang_cc1 -x objective-c++ -triple x86_64-apple-darwin10 -fobjc-nonfragile-abi -fobjc-gc -emit-llvm -o %t %s
+// RUN: grep '@"\\01L_OBJC_CLASS_NAME_.*" = internal global .* c"A\\00"' %t
+// RUN: grep '@"\\01L_OBJC_CLASS_NAME_.*" = internal global .* c"\\11q\\10\\00"' %t
+// RUN: grep '@"\\01L_OBJC_CLASS_NAME_.*" = internal global .* c"!q\\00"' %t
+// RUN: grep '@"\\01L_OBJC_CLASS_NAME_.*" = internal global .* c"\\01\\14\\00"' %t
/*
diff --git a/test/CodeGenObjC/ivar-layout-no-optimize.m b/test/CodeGenObjC/ivar-layout-no-optimize.m
index e7fd1301b810..7760f94a50ab 100644
--- a/test/CodeGenObjC/ivar-layout-no-optimize.m
+++ b/test/CodeGenObjC/ivar-layout-no-optimize.m
@@ -1,5 +1,7 @@
// RUN: %clang_cc1 -fobjc-gc -triple x86_64-apple-darwin -O0 -S %s -o %t-64.s
// RUN: FileCheck -check-prefix LP64 --input-file=%t-64.s %s
+// RUN: %clang_cc1 -x objective-c++ -fobjc-gc -triple x86_64-apple-darwin -O0 -S %s -o %t-64.s
+// RUN: FileCheck -check-prefix LP64 --input-file=%t-64.s %s
@interface NSObject {
id isa;
diff --git a/test/CodeGenObjC/objc-gc-aggr-assign.m b/test/CodeGenObjC/objc-gc-aggr-assign.m
new file mode 100644
index 000000000000..9fd64d5645c8
--- /dev/null
+++ b/test/CodeGenObjC/objc-gc-aggr-assign.m
@@ -0,0 +1,62 @@
+// RUN: %clang_cc1 -triple x86_64-apple-darwin10 -fobjc-gc -emit-llvm -o - %s | FileCheck -check-prefix C %s
+// RUN: %clang_cc1 -x objective-c++ -triple x86_64-apple-darwin10 -fobjc-gc -emit-llvm -o - %s | FileCheck -check-prefix CP %s
+
+static int count;
+
+typedef struct S {
+ int ii;
+} SS;
+
+struct type_s {
+ SS may_recurse;
+ id id_val;
+};
+
+@interface NamedObject
+{
+ struct type_s type_s_ivar;
+}
+- (void) setSome : (struct type_s) arg;
+- (struct type_s) getSome;
+@property(assign) struct type_s aggre_prop;
+@end
+
+@implementation NamedObject
+- (void) setSome : (struct type_s) arg
+ {
+ type_s_ivar = arg;
+ }
+- (struct type_s) getSome
+ {
+ return type_s_ivar;
+ }
+@synthesize aggre_prop = type_s_ivar;
+@end
+
+struct type_s some = {{1234}, (id)0};
+
+struct type_s get(void)
+{
+ return some;
+}
+
+void f(const struct type_s *in, struct type_s *out) {
+ *out = *in;
+}
+
+#ifdef __cplusplus
+struct Derived : type_s { };
+
+void foo(Derived* src, Derived* dest) {
+ *dest = *src;
+}
+#endif
+
+// CHECK-C: call i8* @objc_memmove_collectable
+// CHECK-C: call i8* @objc_memmove_collectable
+// CHECK-C: call i8* @objc_memmove_collectable
+
+// CHECK-CP: call i8* @objc_memmove_collectable
+// CHECK-CP: call i8* @objc_memmove_collectable
+// CHECK-CP: call i8* @objc_memmove_collectable
+// CHECK-CP: call i8* @objc_memmove_collectable
diff --git a/test/CodeGenObjC/objc2-new-gc-api-strongcast.m b/test/CodeGenObjC/objc2-new-gc-api-strongcast.m
index 1ff2dd3d8de2..0413910855e5 100644
--- a/test/CodeGenObjC/objc2-new-gc-api-strongcast.m
+++ b/test/CodeGenObjC/objc2-new-gc-api-strongcast.m
@@ -1,9 +1,11 @@
// RUN: %clang_cc1 -triple x86_64-apple-darwin10 -fblocks -fobjc-gc -emit-llvm -o %t %s
// RUN: grep -F '@objc_assign_strongCast' %t | count 4
+// RUN: %clang_cc1 -x objective-c++ -triple x86_64-apple-darwin10 -fblocks -fobjc-gc -emit-llvm -o %t %s
+// RUN: grep -F '@objc_assign_strongCast' %t | count 4
@interface DSATextSearch @end
-DSATextSearch **_uniqueIdToIdentifierArray = ((void *)0);
+DSATextSearch **_uniqueIdToIdentifierArray = (0);
void foo (int _nextId)
{
_uniqueIdToIdentifierArray[_nextId] = 0; // objc_assign_strongCast
diff --git a/test/CodeGenObjC/objc2-no-write-barrier.m b/test/CodeGenObjC/objc2-no-write-barrier.m
index 544c329c5e20..a0ebc100fb2f 100644
--- a/test/CodeGenObjC/objc2-no-write-barrier.m
+++ b/test/CodeGenObjC/objc2-no-write-barrier.m
@@ -1,5 +1,7 @@
// RUN: %clang_cc1 -triple x86_64-apple-darwin9 -fobjc-gc -emit-llvm -o %t %s
// RUN: grep 'objc_assign' %t | count 0
+// RUN: %clang_cc1 -x objective-c++ -triple x86_64-apple-darwin9 -fobjc-gc -emit-llvm -o %t %s
+// RUN: grep 'objc_assign' %t | count 0
typedef struct {
int ival;
diff --git a/test/CodeGenObjC/objc2-retain-codegen.m b/test/CodeGenObjC/objc2-retain-codegen.m
index 2c3317a4854d..9f6620619ecd 100644
--- a/test/CodeGenObjC/objc2-retain-codegen.m
+++ b/test/CodeGenObjC/objc2-retain-codegen.m
@@ -1,4 +1,5 @@
// RUN: %clang_cc1 -triple x86_64-unknown-unknown -fobjc-gc-only -emit-llvm -o %t %s
+// RUN: %clang_cc1 -x objective-c++ -triple x86_64-unknown-unknown -fobjc-gc-only -emit-llvm -o %t %s
@interface I0 {
I0 *_f0;
diff --git a/test/CodeGenObjC/objc2-strong-cast-1.m b/test/CodeGenObjC/objc2-strong-cast-1.m
index 509f21a342ae..b79f8a00f7a3 100644
--- a/test/CodeGenObjC/objc2-strong-cast-1.m
+++ b/test/CodeGenObjC/objc2-strong-cast-1.m
@@ -1,4 +1,5 @@
// RUN: %clang_cc1 -triple x86_64-unknown-unknown -fobjc-gc -emit-llvm -o %t %s
+// RUN: %clang_cc1 -x objective-c++ -triple x86_64-unknown-unknown -fobjc-gc -emit-llvm -o %t %s
@interface I {
__attribute__((objc_gc(strong))) int *i_IdocumentIDs;
diff --git a/test/CodeGenObjC/objc2-strong-cast.m b/test/CodeGenObjC/objc2-strong-cast.m
index 9ef463c0df10..7291c4e8d2d4 100644
--- a/test/CodeGenObjC/objc2-strong-cast.m
+++ b/test/CodeGenObjC/objc2-strong-cast.m
@@ -1,4 +1,5 @@
// RUN: %clang_cc1 -fobjc-gc -emit-llvm -o %t %s
+// RUN: %clang_cc1 -x objective-c++ -fobjc-gc -emit-llvm -o %t %s
@interface I {
__attribute__((objc_gc(strong))) signed long *_documentIDs;
diff --git a/test/CodeGenObjC/objc2-weak-assign.m b/test/CodeGenObjC/objc2-weak-assign.m
index 42fa7738f44e..74c0c00c7caa 100644
--- a/test/CodeGenObjC/objc2-weak-assign.m
+++ b/test/CodeGenObjC/objc2-weak-assign.m
@@ -1,5 +1,7 @@
// RUN: %clang_cc1 -triple x86_64-apple-darwin9 -fobjc-gc -emit-llvm -o %t %s
// RUN: grep -e "objc_assign_weak" %t | grep -e "call" | count 6
+// RUN: %clang_cc1 -x objective-c++ -triple x86_64-apple-darwin9 -fobjc-gc -emit-llvm -o %t %s
+// RUN: grep -e "objc_assign_weak" %t | grep -e "call" | count 6
__weak id* x;
id* __weak y;
diff --git a/test/CodeGenObjC/objc2-weak-compare.m b/test/CodeGenObjC/objc2-weak-compare.m
index cb8ca5ff4c07..8cba1a986094 100644
--- a/test/CodeGenObjC/objc2-weak-compare.m
+++ b/test/CodeGenObjC/objc2-weak-compare.m
@@ -1,4 +1,5 @@
// RUN: %clang_cc1 -triple i386-apple-darwin9 -fobjc-gc -emit-llvm -o %t %s
+// RUN: %clang_cc1 -x objective-c++ -triple i386-apple-darwin9 -fobjc-gc -emit-llvm -o %t %s
@interface PBXTarget
{
@@ -10,6 +11,7 @@ PBXTarget * result;
- Meth;
@end
+extern void foo();
@implementation PBXTarget
- Meth {
if (_lastKnownTarget != result)
diff --git a/test/CodeGenObjC/objc2-weak-ivar-debug.m b/test/CodeGenObjC/objc2-weak-ivar-debug.m
index a6fb7fa2751f..8f7acd7619ac 100644
--- a/test/CodeGenObjC/objc2-weak-ivar-debug.m
+++ b/test/CodeGenObjC/objc2-weak-ivar-debug.m
@@ -1,5 +1,7 @@
// RUN: %clang_cc1 -triple x86_64-apple-darwin9 -fobjc-gc -g -emit-llvm -o - %s
// RUN: %clang_cc1 -triple i386-apple-darwin9 -fobjc-gc -g -emit-llvm -o - %s
+// RUN: %clang_cc1 -x objective-c++ -triple x86_64-apple-darwin9 -fobjc-gc -g -emit-llvm -o - %s
+// RUN: %clang_cc1 -x objective-c++ -triple i386-apple-darwin9 -fobjc-gc -g -emit-llvm -o - %s
// rdar://7252252
@interface Loop {
diff --git a/test/CodeGenObjC/objc2-weak-ivar.m b/test/CodeGenObjC/objc2-weak-ivar.m
index cfe1e95952fe..8c91a80b6863 100644
--- a/test/CodeGenObjC/objc2-weak-ivar.m
+++ b/test/CodeGenObjC/objc2-weak-ivar.m
@@ -1,4 +1,5 @@
// RUN: %clang_cc1 -triple x86_64-apple-darwin9 -fobjc-gc -emit-llvm -o %t %s
+// RUN: %clang_cc1 -x objective-c++ -triple x86_64-apple-darwin9 -fobjc-gc -emit-llvm -o %t %s
@class NSObject;
@interface Foo {
diff --git a/test/CodeGenObjC/objc2-write-barrier-2.m b/test/CodeGenObjC/objc2-write-barrier-2.m
index 9a76c6eb8208..74cd7eafad4f 100644
--- a/test/CodeGenObjC/objc2-write-barrier-2.m
+++ b/test/CodeGenObjC/objc2-write-barrier-2.m
@@ -2,6 +2,10 @@
// RUN: grep -F '@objc_assign_global' %t | count 7
// RUN: grep -F '@objc_assign_ivar' %t | count 5
// RUN: grep -F '@objc_assign_strongCast' %t | count 8
+// RUN: %clang_cc1 -x objective-c++ -triple x86_64-apple-darwin10 -fobjc-gc -emit-llvm -o %t %s
+// RUN: grep -F '@objc_assign_global' %t | count 7
+// RUN: grep -F '@objc_assign_ivar' %t | count 5
+// RUN: grep -F '@objc_assign_strongCast' %t | count 8
extern id **somefunc(void);
extern id *somefunc2(void);
diff --git a/test/CodeGenObjC/objc2-write-barrier-3.m b/test/CodeGenObjC/objc2-write-barrier-3.m
index 626083b1c42d..cb72cc06e55c 100644
--- a/test/CodeGenObjC/objc2-write-barrier-3.m
+++ b/test/CodeGenObjC/objc2-write-barrier-3.m
@@ -1,6 +1,9 @@
// RUN: %clang_cc1 -triple x86_64-apple-darwin10 -fobjc-nonfragile-abi -fblocks -fobjc-gc -emit-llvm -o %t %s
// RUN: grep objc_assign_ivar %t | count 3
// RUN: grep objc_assign_strongCast %t | count 6
+// RUN: %clang_cc1 -x objective-c++ -triple x86_64-apple-darwin10 -fobjc-nonfragile-abi -fblocks -fobjc-gc -emit-llvm -o %t %s
+// RUN: grep objc_assign_ivar %t | count 3
+// RUN: grep objc_assign_strongCast %t | count 6
struct Slice {
void *__strong * items;
diff --git a/test/CodeGenObjC/objc2-write-barrier-4.m b/test/CodeGenObjC/objc2-write-barrier-4.m
index 11b4ab4e9604..ab30649bec2b 100644
--- a/test/CodeGenObjC/objc2-write-barrier-4.m
+++ b/test/CodeGenObjC/objc2-write-barrier-4.m
@@ -1,6 +1,9 @@
// RUN: %clang_cc1 -triple x86_64-apple-darwin10 -fobjc-gc -emit-llvm -o %t %s
// RUN: grep objc_assign_global %t | count 3
// RUN: grep objc_assign_strongCast %t | count 2
+// RUN: %clang_cc1 -x objective-c++ -triple x86_64-apple-darwin10 -fobjc-gc -emit-llvm -o %t %s
+// RUN: grep objc_assign_global %t | count 3
+// RUN: grep objc_assign_strongCast %t | count 2
@interface A
@end
diff --git a/test/CodeGenObjC/objc2-write-barrier-5.m b/test/CodeGenObjC/objc2-write-barrier-5.m
index babe26d55a53..373df0cc16b9 100644
--- a/test/CodeGenObjC/objc2-write-barrier-5.m
+++ b/test/CodeGenObjC/objc2-write-barrier-5.m
@@ -1,6 +1,9 @@
// RUN: %clang_cc1 -triple x86_64-apple-darwin10 -fobjc-gc -emit-llvm -o %t %s
// RUN: grep objc_assign_ivar %t | count 0
// RUN: grep objc_assign_strongCast %t | count 5
+// RUN: %clang_cc1 -x objective-c++ -triple x86_64-apple-darwin10 -fobjc-gc -emit-llvm -o %t %s
+// RUN: grep objc_assign_ivar %t | count 0
+// RUN: grep objc_assign_strongCast %t | count 5
@interface TestUnarchiver
{
diff --git a/test/CodeGenObjC/objc2-write-barrier.m b/test/CodeGenObjC/objc2-write-barrier.m
index 0934e0a46ac3..08b65deaa38d 100644
--- a/test/CodeGenObjC/objc2-write-barrier.m
+++ b/test/CodeGenObjC/objc2-write-barrier.m
@@ -1,6 +1,9 @@
// RUN: %clang_cc1 -triple x86_64-apple-darwin10 -fobjc-gc -emit-llvm -o %t %s
// RUN: grep -F '@objc_assign_global' %t | count 21
// RUN: grep -F '@objc_assign_ivar' %t | count 11
+// RUN: %clang_cc1 -x objective-c++ -triple x86_64-apple-darwin10 -fobjc-gc -emit-llvm -o %t %s
+// RUN: grep -F '@objc_assign_global' %t | count 21
+// RUN: grep -F '@objc_assign_ivar' %t | count 11
typedef const struct __CFDictionary * CFDictionaryRef;
@@ -49,9 +52,9 @@ struct_with_ids_t GlobalStructArray[10];
// The test cases
-void *rhs = 0;
+void* rhs = 0;
-#define ASSIGNTEST(expr, global) expr = rhs
+#define ASSIGNTEST(expr, global) expr = (typeof(expr))rhs
int testGlobals() {
// Everything in this function generates assign_global intercepts
diff --git a/test/CodeGenObjC/property-complex.m b/test/CodeGenObjC/property-complex.m
index 59200eba0905..071d0b1d24d2 100644
--- a/test/CodeGenObjC/property-complex.m
+++ b/test/CodeGenObjC/property-complex.m
@@ -1,5 +1,5 @@
-// RUN: %clang_cc1 -triple i386-apple-darwin9 -emit-llvm -S -o - %s
-// RUN: %clang_cc1 -triple x86_64-apple-darwin9 -emit-llvm -S -o - %s
+// RUN: %clang_cc1 -triple i386-apple-darwin9 -emit-llvm -o %t %s
+// RUN: %clang_cc1 -triple x86_64-apple-darwin9 -emit-llvm -o %t %s
@interface I0 {
@public
diff --git a/test/CodeGenObjC/protocols.m b/test/CodeGenObjC/protocols.m
index 0f24a1cd1fc1..6dadb11273dc 100644
--- a/test/CodeGenObjC/protocols.m
+++ b/test/CodeGenObjC/protocols.m
@@ -1,8 +1,9 @@
-// RUN: %clang_cc1 -emit-llvm %s -o %t
+// RUN: %clang_cc1 -emit-llvm-only %s
void p(const char*, ...);
@interface Root
++(int) maxValue;
-(int) conformsTo: (id) x;
@end
@@ -48,3 +49,9 @@ int main() {
return 0;
}
+
+// rdar://problem/7992749
+typedef Root<P1> P1Object;
+int test10() {
+ return [P1Object maxValue];
+}
diff --git a/test/CodeGenObjCXX/encode.mm b/test/CodeGenObjCXX/encode.mm
new file mode 100644
index 000000000000..83fb31e16d58
--- /dev/null
+++ b/test/CodeGenObjCXX/encode.mm
@@ -0,0 +1,52 @@
+// RUN: %clang_cc1 %s -triple=x86_64-apple-darwin10 -emit-llvm -o - | FileCheck %s
+
+// CHECK: v17@0:8{vector<float, float, float>=}16
+// CHECK: {vector<float, float, float>=}
+// CHECK: v24@0:816
+
+template <typename T1, typename T2, typename T3> struct vector {
+ vector();
+ vector(T1,T2,T3);
+};
+
+typedef vector< float, float, float > vector3f;
+
+@interface SceneNode
+{
+ vector3f position;
+}
+
+@property (assign, nonatomic) vector3f position;
+
+@end
+
+@interface MyOpenGLView
+{
+@public
+ vector3f position;
+}
+@property vector3f position;
+@end
+
+@implementation MyOpenGLView
+
+@synthesize position;
+
+-(void)awakeFromNib {
+ SceneNode *sn;
+ vector3f VF3(1.0, 1.0, 1.0);
+ [sn setPosition:VF3];
+}
+@end
+
+
+class Int3 { int x, y, z; };
+
+// Enforce @encoding for member pointers.
+@interface MemPtr {}
+- (void) foo: (int (Int3::*)) member;
+@end
+@implementation MemPtr
+- (void) foo: (int (Int3::*)) member {
+}
+@end
diff --git a/test/CodeGenObjCXX/mangle-blocks.mm b/test/CodeGenObjCXX/mangle-blocks.mm
new file mode 100644
index 000000000000..9f57557f8f67
--- /dev/null
+++ b/test/CodeGenObjCXX/mangle-blocks.mm
@@ -0,0 +1,50 @@
+// RUN: %clang_cc1 -emit-llvm -fblocks -o - -triple x86_64-apple-darwin10 %s | FileCheck %s
+
+// CHECK: @_ZGVN3foo20__foo_block_invoke_05valueE = internal global i64 0
+
+int f();
+
+void foo() {
+ // CHECK: define internal i32 @__foo_block_invoke_0
+ // CHECK: call i32 @__cxa_guard_acquire(i64* @_ZGVN3foo20__foo_block_invoke_05value
+ (void)^(int x) {
+ static int value = f();
+ return x + value;
+ };
+}
+
+// CHECK: define internal i32 @__block_global_0
+int i = ^(int x) { return x;}(i);
+
+@interface A
+- (void)method;
+@end
+
+@implementation A
+- (void)method {
+ // CHECK: define internal signext i8 @"__11-[A method]_block_invoke_0"
+ (void)^(int x) {
+ // CHECK: @"_ZN11-[A method]30__11-[A method]_block_invoke_04nameE"
+ static const char *name = "hello";
+ return name[x];
+ };
+}
+@end
+
+void foo(int) {
+ (void)^(int x) {
+ static const char *name = "hello";
+ return name[x];
+ };
+}
+
+namespace N {
+ // CHECK: define internal signext i8 @__bar_block_invoke_0
+ void bar() {
+ (void)^(int x) {
+ // CHECK: @_ZN1N3bar20__bar_block_invoke_04nameE
+ static const char *name = "hello";
+ return name[x];
+ };
+ }
+}
diff --git a/test/CodeGenObjCXX/property-objects.mm b/test/CodeGenObjCXX/property-objects.mm
new file mode 100644
index 000000000000..662dacc55d7d
--- /dev/null
+++ b/test/CodeGenObjCXX/property-objects.mm
@@ -0,0 +1,51 @@
+// RUN: %clang_cc1 %s -triple=x86_64-apple-darwin10 -fobjc-nonfragile-abi -emit-llvm -o - | FileCheck %s
+// CHECK-NOT: callq _objc_msgSend_stret
+// CHECK: call void @_ZN1SC1ERKS_
+// CHECK: call %class.S* @_ZN1SaSERKS_
+// CHECK: call %class.S* @_ZN6CGRectaSERKS_
+
+class S {
+public:
+ S& operator = (const S&);
+ S (const S&);
+ S ();
+};
+
+struct CGRect {
+ CGRect & operator = (const CGRect &);
+};
+
+@interface I {
+ S position;
+ CGRect bounds;
+}
+@property(assign, nonatomic) S position;
+@property CGRect bounds;
+@property CGRect frame;
+- (void)setFrame:(CGRect)frameRect;
+- (CGRect)frame;
+- (void) initWithOwner;
+@end
+
+@implementation I
+@synthesize position;
+@synthesize bounds;
+@synthesize frame;
+- (void)setFrame:(CGRect)frameRect {}
+- (CGRect)frame {return bounds;}
+
+- (void)initWithOwner {
+ I* _labelLayer;
+ CGRect labelLayerFrame = self.bounds;
+ labelLayerFrame = self.bounds;
+ _labelLayer.frame = labelLayerFrame;
+}
+@end
+
+int main() {
+ I *i;
+ S s1;
+ i.position = s1;
+ return 0;
+}
+
diff --git a/test/Coverage/ast-printing.cpp b/test/Coverage/ast-printing.cpp
index 1a75fb4c6322..0de56422895f 100644
--- a/test/Coverage/ast-printing.cpp
+++ b/test/Coverage/ast-printing.cpp
@@ -1,7 +1,7 @@
// RUN: %clang_cc1 -fsyntax-only %s
// RUN: %clang_cc1 -ast-print %s
// RUN: %clang_cc1 -ast-dump %s
-// FIXME: %clang_cc1 -ast-print-xml -o %t %s
+// RUN: %clang_cc1 -ast-print-xml -o %t %s
// RUN: %clang_cc1 -print-decl-contexts %s
// RUN: %clang_cc1 -fdump-record-layouts %s
diff --git a/test/Driver/bindings.c b/test/Driver/bindings.c
index 2271ab5c6459..e7ec0c597d4b 100644
--- a/test/Driver/bindings.c
+++ b/test/Driver/bindings.c
@@ -48,7 +48,7 @@
// RUN: grep '"gcc::Compile", inputs: \[".*bindings.c"\], output: "bindings.s"' %t
// Darwin bindings
-// RUN: %clang -ccc-host-triple i386-apple-darwin9 -ccc-print-bindings %s 2> %t
+// RUN: %clang -ccc-host-triple i386-apple-darwin9 -no-integrated-as -ccc-print-bindings %s 2> %t
// RUN: grep '"clang", inputs: \[".*bindings.c"\], output: ".*\.s"' %t
// RUN: grep '"darwin::Assemble", inputs: \[".*\.s"\], output: ".*\.o"' %t
// RUN: grep '"darwin::Link", inputs: \[".*\.o"\], output: "a.out"' %t
diff --git a/test/Driver/clang_f_opts.c b/test/Driver/clang_f_opts.c
index f1d67597777a..50bce3b274ca 100644
--- a/test/Driver/clang_f_opts.c
+++ b/test/Driver/clang_f_opts.c
@@ -1,10 +1,12 @@
-// RUN: %clang -### -S -fblocks -fbuiltin -fno-math-errno -fcommon -fpascal-strings -fno-blocks -fno-builtin -fmath-errno -fno-common -fno-pascal-strings -fblocks -fbuiltin -fmath-errno -fcommon -fpascal-strings %s 2>&1 | FileCheck -check-prefix=CHECK-OPTIONS1 %s
-// RUN: %clang -### -S -fblocks -fbuiltin -fno-math-errno -fcommon -fpascal-strings -fno-blocks -fno-builtin -fmath-errno -fno-common -fno-pascal-strings -fno-show-source-location -fshort-wchar %s 2>&1 | FileCheck -check-prefix=CHECK-OPTIONS2 %s
+// RUN: %clang -### -S -fasm -fblocks -fbuiltin -fno-math-errno -fcommon -fpascal-strings -fno-blocks -fno-builtin -fmath-errno -fno-common -fno-pascal-strings -fblocks -fbuiltin -fmath-errno -fcommon -fpascal-strings %s 2>&1 | FileCheck -check-prefix=CHECK-OPTIONS1 %s
+// RUN: %clang -### -S -fasm -fblocks -fbuiltin -fno-math-errno -fcommon -fpascal-strings -fno-asm -fno-blocks -fno-builtin -fmath-errno -fno-common -fno-pascal-strings -fno-show-source-location -fshort-wchar %s 2>&1 | FileCheck -check-prefix=CHECK-OPTIONS2 %s
// RUN: %clang -### -fshort-enums %s 2>&1 | FileCheck -check-prefix=CHECK-SHORT-ENUMS %s
+// CHECK-OPTIONS1: -fgnu-keywords
// CHECK-OPTIONS1: -fblocks
// CHECK-OPTIONS1: -fpascal-strings
+// CHECK_OPTIONS2: -fno-gnu-keywords
// CHECK-OPTIONS2: -fmath-errno
// CHECK-OPTIONS2: -fno-builtin
// CHECK-OPTIONS2: -fshort-wchar
diff --git a/test/FixIt/typo.m b/test/FixIt/typo.m
index f161bb8d9948..7197bc746d12 100644
--- a/test/FixIt/typo.m
+++ b/test/FixIt/typo.m
@@ -1,17 +1,18 @@
-// RUN: %clang_cc1 -fsyntax-only -verify %s
-// RUN: cp %s %t
-// RUN: %clang_cc1 -fsyntax-only -fixit %t || true
-// RUN: %clang_cc1 -fsyntax-only -pedantic -Werror -x objective-c %t
-// XFAIL: *
+// RUN: %clang_cc1 -fsyntax-only -triple x86_64-apple-darwin10 -fobjc-nonfragile-abi -DNON_FIXITS -verify %s
+// RUN: %clang -E -P %s -o %t
+// RUN: %clang_cc1 -x objective-c -fsyntax-only -triple x86_64-apple-darwin10 -fobjc-nonfragile-abi -fixit %t || true
+// RUN: %clang_cc1 -x objective-c -fsyntax-only -triple x86_64-apple-darwin10 -fobjc-nonfragile-abi -pedantic -Werror %t
@interface NSString // expected-note{{'NSString' declared here}}
+ (int)method:(int)x;
@end
+#ifdef NON_FIXITS
void test() {
// FIXME: not providing fix-its
NSstring *str = @"A string"; // expected-error{{use of undeclared identifier 'NSstring'; did you mean 'NSString'?}}
}
+#endif
@protocol P1
@optional
@@ -80,18 +81,23 @@ void test2(Collide *a) {
a->vale = 17; // expected-error{{'Collide' does not have a member named 'vale'; did you mean 'value'?}}
}
+#ifdef NON_FIXITS
@interface Derived : Collid // expected-error{{cannot find interface declaration for 'Collid', superclass of 'Derived'; did you mean 'Collide'?}}
@end
+#endif
+#ifdef NON_FIXITS
@protocol NetworkSocket // expected-note{{'NetworkSocket' declared here}}
- (int)send:(void*)buffer bytes:(int)bytes;
@end
@interface IPv6 <Network_Socket> // expected-error{{cannot find protocol declaration for 'Network_Socket'; did you mean 'NetworkSocket'?}}
@end
+#endif
@interface Super
-- (int)method;
+- (int)method; // expected-note{{using}}
+- (int)method2;
@end
@interface Sub : Super
@@ -105,6 +111,18 @@ void test2(Collide *a) {
@end
+double *isupper(int);
+
+@interface Sub2 : Super
+- (int)method2;
+@end
+
+@implementation Sub2
+- (int)method2 {
+ return [supper method2]; // expected-error{{unknown receiver 'supper'; did you mean 'super'?}}
+}
+@end
+
@interface Ivar
@end
@@ -112,29 +130,19 @@ void test2(Collide *a) {
@property (retain) id ivar;
@end
+#ifdef NON_FIXITS
@interface User <Proto>
-- (void)method;
+- (void)method; // expected-note{{also found}}
@end
@implementation User
@synthesize ivar;
- (void)method {
- [ivar method]; // Test that we don't correct 'ivar' to 'Ivar'
+ // Test that we don't correct 'ivar' to 'Ivar' e
+ [ivar method]; // expected-warning{{multiple methods named 'method' found}}
}
@end
+#endif
-@interface User2
-@end
-@interface User2 (Cat) < Proto>
-- (void)method;
-@end
-
-@implementation User2 (Cat)
-@synthesize ivar;
-
-- (void)method {
- [ivar method]; // Test that we don't correct 'ivar' to 'Ivar'
-}
-@end
diff --git a/test/Index/annotate-tokens-include.c b/test/Index/annotate-tokens-include.c
new file mode 100644
index 000000000000..3c3c43b746d6
--- /dev/null
+++ b/test/Index/annotate-tokens-include.c
@@ -0,0 +1,6 @@
+#include "annotate-tokens-include.h"
+
+// RUN: c-index-test -test-annotate-tokens=%s:1:1:2:1 %s | FileCheck %s
+// CHECK: Identifier: "include" [1:2 - 1:9] preprocessing directive=
+// CHECK: Literal: ""annotate-tokens-include.h"" [1:10 - 1:37] preprocessing directive=
+
diff --git a/test/Index/annotate-tokens-include.h b/test/Index/annotate-tokens-include.h
new file mode 100644
index 000000000000..5d5f8f0c9e78
--- /dev/null
+++ b/test/Index/annotate-tokens-include.h
@@ -0,0 +1 @@
+int foo();
diff --git a/test/Index/annotate-tokens.c b/test/Index/annotate-tokens.c
index 7fbf9cc4fb6e..41f182d27148 100644
--- a/test/Index/annotate-tokens.c
+++ b/test/Index/annotate-tokens.c
@@ -11,55 +11,55 @@ void f(void *ptr) {
// RUN: c-index-test -test-annotate-tokens=%s:4:1:9:32 %s | FileCheck %s
// CHECK: Identifier: "T" [4:3 - 4:4] TypeRef=T:1:13
-// CHECK: Punctuation: "*" [4:4 - 4:5]
+// CHECK: Punctuation: "*" [4:4 - 4:5] VarDecl=t_ptr:4:6 (Definition)
// CHECK: Identifier: "t_ptr" [4:6 - 4:11] VarDecl=t_ptr:4:6 (Definition)
-// CHECK: Punctuation: "=" [4:12 - 4:13]
-// CHECK: Punctuation: "(" [4:14 - 4:15]
+// CHECK: Punctuation: "=" [4:12 - 4:13] VarDecl=t_ptr:4:6 (Definition)
+// CHECK: Punctuation: "(" [4:14 - 4:15] UnexposedExpr=ptr:3:14
// CHECK: Identifier: "T" [4:15 - 4:16] TypeRef=T:1:13
-// CHECK: Punctuation: "*" [4:17 - 4:18]
-// CHECK: Punctuation: ")" [4:18 - 4:19]
+// CHECK: Punctuation: "*" [4:17 - 4:18] UnexposedExpr=ptr:3:14
+// CHECK: Punctuation: ")" [4:18 - 4:19] UnexposedExpr=ptr:3:14
// CHECK: Identifier: "ptr" [4:19 - 4:22] DeclRefExpr=ptr:3:14
-// CHECK: Punctuation: ";" [4:22 - 4:23]
-// CHECK: Punctuation: "(" [5:3 - 5:4]
-// CHECK: Keyword: "void" [5:4 - 5:8]
-// CHECK: Punctuation: ")" [5:8 - 5:9]
-// CHECK: Keyword: "sizeof" [5:9 - 5:15]
-// CHECK: Punctuation: "(" [5:15 - 5:16]
+// CHECK: Punctuation: ";" [4:22 - 4:23] UnexposedStmt=
+// CHECK: Punctuation: "(" [5:3 - 5:4] UnexposedExpr=
+// CHECK: Keyword: "void" [5:4 - 5:8] UnexposedExpr=
+// CHECK: Punctuation: ")" [5:8 - 5:9] UnexposedExpr=
+// CHECK: Keyword: "sizeof" [5:9 - 5:15] UnexposedExpr=
+// CHECK: Punctuation: "(" [5:15 - 5:16] UnexposedExpr=
// CHECK: Identifier: "T" [5:16 - 5:17] TypeRef=T:1:13
-// CHECK: Punctuation: ")" [5:17 - 5:18]
-// CHECK: Punctuation: ";" [5:18 - 5:19]
-// CHECK: Comment: "/* A comment */" [6:3 - 6:18]
-// CHECK: Keyword: "struct" [7:3 - 7:9]
+// CHECK: Punctuation: ")" [5:17 - 5:18] UnexposedExpr=
+// CHECK: Punctuation: ";" [5:18 - 5:19] UnexposedStmt=
+// CHECK: Comment: "/* A comment */" [6:3 - 6:18] UnexposedStmt=
+// CHECK: Keyword: "struct" [7:3 - 7:9] UnexposedStmt=
// CHECK: Identifier: "X" [7:10 - 7:11] TypeRef=struct X:2:8
// CHECK: Identifier: "x" [7:12 - 7:13] VarDecl=x:7:12 (Definition)
-// CHECK: Punctuation: "=" [7:14 - 7:15]
-// CHECK: Punctuation: "(" [7:16 - 7:17]
-// CHECK: Keyword: "struct" [7:17 - 7:23]
+// CHECK: Punctuation: "=" [7:14 - 7:15] VarDecl=x:7:12 (Definition)
+// CHECK: Punctuation: "(" [7:16 - 7:17] UnexposedExpr=
+// CHECK: Keyword: "struct" [7:17 - 7:23] UnexposedExpr=
// CHECK: Identifier: "X" [7:24 - 7:25] TypeRef=struct X:2:8
-// CHECK: Punctuation: ")" [7:25 - 7:26]
-// CHECK: Punctuation: "{" [7:26 - 7:27]
-// CHECK: Literal: "1" [7:27 - 7:28]
-// CHECK: Punctuation: "," [7:28 - 7:29]
-// CHECK: Literal: "2" [7:30 - 7:31]
-// CHECK: Punctuation: "}" [7:31 - 7:32]
-// CHECK: Punctuation: ";" [7:32 - 7:33]
-// CHECK: Keyword: "void" [8:3 - 8:7]
-// CHECK: Punctuation: "*" [8:8 - 8:9]
+// CHECK: Punctuation: ")" [7:25 - 7:26] UnexposedExpr=
+// CHECK: Punctuation: "{" [7:26 - 7:27] UnexposedExpr=
+// CHECK: Literal: "1" [7:27 - 7:28] UnexposedExpr=
+// CHECK: Punctuation: "," [7:28 - 7:29] UnexposedExpr=
+// CHECK: Literal: "2" [7:30 - 7:31] UnexposedExpr=
+// CHECK: Punctuation: "}" [7:31 - 7:32] UnexposedExpr=
+// CHECK: Punctuation: ";" [7:32 - 7:33] UnexposedStmt=
+// CHECK: Keyword: "void" [8:3 - 8:7] VarDecl=xx:8:9 (Definition)
+// CHECK: Punctuation: "*" [8:8 - 8:9] VarDecl=xx:8:9 (Definition)
// CHECK: Identifier: "xx" [8:9 - 8:11] VarDecl=xx:8:9 (Definition)
-// CHECK: Punctuation: "=" [8:12 - 8:13]
+// CHECK: Punctuation: "=" [8:12 - 8:13] VarDecl=xx:8:9 (Definition)
// CHECK: Identifier: "ptr" [8:14 - 8:17] DeclRefExpr=ptr:3:14
-// CHECK: Punctuation: "?" [8:18 - 8:19]
-// CHECK: Punctuation: ":" [8:20 - 8:21]
-// CHECK: Punctuation: "&" [8:22 - 8:23]
+// CHECK: Punctuation: "?" [8:18 - 8:19] UnexposedExpr=
+// CHECK: Punctuation: ":" [8:20 - 8:21] UnexposedExpr=
+// CHECK: Punctuation: "&" [8:22 - 8:23] UnexposedExpr=
// CHECK: Identifier: "x" [8:23 - 8:24] DeclRefExpr=x:7:12
-// CHECK: Punctuation: ";" [8:24 - 8:25]
-// CHECK: Keyword: "const" [9:3 - 9:8]
-// CHECK: Keyword: "char" [9:9 - 9:13]
-// CHECK: Punctuation: "*" [9:14 - 9:15]
+// CHECK: Punctuation: ";" [8:24 - 8:25] UnexposedStmt=
+// CHECK: Keyword: "const" [9:3 - 9:8] UnexposedStmt=
+// CHECK: Keyword: "char" [9:9 - 9:13] VarDecl=hello:9:16 (Definition)
+// CHECK: Punctuation: "*" [9:14 - 9:15] VarDecl=hello:9:16 (Definition)
// CHECK: Identifier: "hello" [9:16 - 9:21] VarDecl=hello:9:16 (Definition)
-// CHECK: Punctuation: "=" [9:22 - 9:23]
-// CHECK: Literal: ""Hello"" [9:24 - 9:31]
-// CHECK: Punctuation: ";" [9:31 - 9:32]
-// CHECK: Punctuation: "}" [10:1 - 10:2]
+// CHECK: Punctuation: "=" [9:22 - 9:23] VarDecl=hello:9:16 (Definition)
+// CHECK: Literal: ""Hello"" [9:24 - 9:31] UnexposedExpr=
+// CHECK: Punctuation: ";" [9:31 - 9:32] UnexposedStmt=
+// CHECK: Punctuation: "}" [10:1 - 10:2] UnexposedStmt=
// RUN: c-index-test -test-annotate-tokens=%s:4:1:165:32 %s | FileCheck %s
// RUN: c-index-test -test-annotate-tokens=%s:4:1:165:38 %s | FileCheck %s
diff --git a/test/Index/annotate-tokens.m b/test/Index/annotate-tokens.m
index ce399d34c6f2..c6e746bcb1b2 100644
--- a/test/Index/annotate-tokens.m
+++ b/test/Index/annotate-tokens.m
@@ -9,51 +9,245 @@
}
@end
-// RUN: c-index-test -test-annotate-tokens=%s:1:1:10:5 %s | FileCheck %s
-// CHECK: Punctuation: "@" [1:1 - 1:2]
-// CHECK: Identifier: "interface" [1:2 - 1:11]
+// From <rdar://problem/7971430>, the 'barType' referenced in the ivar
+// declarations should be annotated as TypeRefs.
+typedef int * barType;
+@interface Bar
+{
+ barType iVar;
+ barType iVar1, iVar2;
+}
+@end
+@implementation Bar
+- (void) method
+{
+ barType local = iVar;
+}
+@end
+
+// From <rdar://problem/7967123>. The ranges for attributes are not
+// currently stored, causing most of the tokens to be falsely annotated.
+// Since there are no source ranges for attributes, we currently don't
+// annotate them.
+@interface IBActionTests
+- (IBAction) actionMethod:(id)arg;
+- (void)foo:(int)x;
+@end
+extern int ibaction_test(void);
+@implementation IBActionTests
+- (IBAction) actionMethod:(id)arg
+{
+ ibaction_test();
+ [self foo:0];
+}
+- (void) foo:(int)x
+{
+ (void) x;
+}
+@end
+
+// From <rdar://problem/7961995>. Essentially the same issue as 7967123,
+// but impacting code marked as IBOutlets.
+@interface IBOutletTests
+{
+ IBOutlet char * anOutlet;
+}
+- (IBAction) actionMethod:(id)arg;
+@property IBOutlet int * aPropOutlet;
+@end
+
+// RUN: c-index-test -test-annotate-tokens=%s:1:1:58:1 %s -DIBOutlet='__attribute__((iboutlet))' -DIBAction='void)__attribute__((ibaction)' | FileCheck %s
+// CHECK: Punctuation: "@" [1:1 - 1:2] ObjCInterfaceDecl=Foo:1:12
+// CHECK: Keyword: "interface" [1:2 - 1:11] ObjCInterfaceDecl=Foo:1:12
// CHECK: Identifier: "Foo" [1:12 - 1:15] ObjCInterfaceDecl=Foo:1:12
// CHECK: Punctuation: "-" [2:1 - 2:2] ObjCInstanceMethodDecl=compare::2:1
-// CHECK: Punctuation: "(" [2:3 - 2:4]
-// CHECK: Keyword: "int" [2:4 - 2:7]
-// CHECK: Punctuation: ")" [2:7 - 2:8]
-// CHECK: Identifier: "compare" [2:8 - 2:15]
-// CHECK: Punctuation: ":" [2:15 - 2:16]
-// CHECK: Punctuation: "(" [2:16 - 2:17]
+// CHECK: Punctuation: "(" [2:3 - 2:4] ObjCInstanceMethodDecl=compare::2:1
+// CHECK: Keyword: "int" [2:4 - 2:7] ObjCInstanceMethodDecl=compare::2:1
+// CHECK: Punctuation: ")" [2:7 - 2:8] ObjCInstanceMethodDecl=compare::2:1
+// CHECK: Identifier: "compare" [2:8 - 2:15] ObjCInstanceMethodDecl=compare::2:1
+// CHECK: Punctuation: ":" [2:15 - 2:16] ObjCInstanceMethodDecl=compare::2:1
+// CHECK: Punctuation: "(" [2:16 - 2:17] ObjCInstanceMethodDecl=compare::2:1
// CHECK: Identifier: "Foo" [2:17 - 2:20] ObjCClassRef=Foo:1:12
-// CHECK: Punctuation: "*" [2:20 - 2:21]
-// CHECK: Punctuation: ")" [2:21 - 2:22]
+// CHECK: Punctuation: "*" [2:20 - 2:21] ParmDecl=other:2:22 (Definition)
+// CHECK: Punctuation: ")" [2:21 - 2:22] ParmDecl=other:2:22 (Definition)
// CHECK: Identifier: "other" [2:22 - 2:27] ParmDecl=other:2:22 (Definition)
-// CHECK: Punctuation: ";" [2:27 - 2:28]
-// CHECK: Punctuation: "@" [3:1 - 3:2]
-// CHECK: Identifier: "end" [3:2 - 3:5]
+// CHECK: Punctuation: ";" [2:27 - 2:28] ObjCInstanceMethodDecl=compare::2:1
+// CHECK: Punctuation: "@" [3:1 - 3:2] ObjCInterfaceDecl=Foo:1:12
+// CHECK: Keyword: "end" [3:2 - 3:5] ObjCInterfaceDecl=Foo:1:12
// CHECK: Punctuation: "@" [5:1 - 5:2] ObjCImplementationDecl=Foo:5:1 (Definition)
-// CHECK: Identifier: "implementation" [5:2 - 5:16]
-// CHECK: Identifier: "Foo" [5:17 - 5:20]
+// CHECK: Keyword: "implementation" [5:2 - 5:16] ObjCImplementationDecl=Foo:5:1 (Definition)
+// CHECK: Identifier: "Foo" [5:17 - 5:20] ObjCImplementationDecl=Foo:5:1 (Definition)
// CHECK: Punctuation: "-" [6:1 - 6:2] ObjCInstanceMethodDecl=compare::6:1 (Definition)
-// CHECK: Punctuation: "(" [6:3 - 6:4]
-// CHECK: Keyword: "int" [6:4 - 6:7]
-// CHECK: Punctuation: ")" [6:7 - 6:8]
-// CHECK: Identifier: "compare" [6:8 - 6:15]
-// CHECK: Punctuation: ":" [6:15 - 6:16]
-// CHECK: Punctuation: "(" [6:16 - 6:17]
+// CHECK: Punctuation: "(" [6:3 - 6:4] ObjCInstanceMethodDecl=compare::6:1 (Definition)
+// CHECK: Keyword: "int" [6:4 - 6:7] ObjCInstanceMethodDecl=compare::6:1 (Definition)
+// CHECK: Punctuation: ")" [6:7 - 6:8] ObjCInstanceMethodDecl=compare::6:1 (Definition)
+// CHECK: Identifier: "compare" [6:8 - 6:15] ObjCInstanceMethodDecl=compare::6:1 (Definition)
+// CHECK: Punctuation: ":" [6:15 - 6:16] ObjCInstanceMethodDecl=compare::6:1 (Definition)
+// CHECK: Punctuation: "(" [6:16 - 6:17] ObjCInstanceMethodDecl=compare::6:1 (Definition)
// CHECK: Identifier: "Foo" [6:17 - 6:20] ObjCClassRef=Foo:1:12
-// CHECK: Punctuation: "*" [6:20 - 6:21]
-// CHECK: Punctuation: ")" [6:21 - 6:22]
+// CHECK: Punctuation: "*" [6:20 - 6:21] ParmDecl=other:6:22 (Definition)
+// CHECK: Punctuation: ")" [6:21 - 6:22] ParmDecl=other:6:22 (Definition)
// CHECK: Identifier: "other" [6:22 - 6:27] ParmDecl=other:6:22 (Definition)
-// CHECK: Punctuation: "{" [6:28 - 6:29]
-// CHECK: Keyword: "return" [7:3 - 7:9]
-// CHECK: Literal: "0" [7:10 - 7:11]
-// CHECK: Punctuation: ";" [7:11 - 7:12]
-// CHECK: Punctuation: "(" [8:3 - 8:4]
-// CHECK: Keyword: "void" [8:4 - 8:8]
-// CHECK: Punctuation: ")" [8:8 - 8:9]
-// CHECK: Punctuation: "@" [8:9 - 8:10]
-// CHECK: Identifier: "encode" [8:10 - 8:16]
-// CHECK: Punctuation: "(" [8:16 - 8:17]
+// CHECK: Punctuation: "{" [6:28 - 6:29] UnexposedStmt=
+// CHECK: Keyword: "return" [7:3 - 7:9] UnexposedStmt=
+// CHECK: Literal: "0" [7:10 - 7:11] UnexposedExpr=
+// CHECK: Punctuation: ";" [7:11 - 7:12] UnexposedStmt=
+// CHECK: Punctuation: "(" [8:3 - 8:4] UnexposedExpr=
+// CHECK: Keyword: "void" [8:4 - 8:8] UnexposedExpr=
+// CHECK: Punctuation: ")" [8:8 - 8:9] UnexposedExpr=
+// CHECK: Punctuation: "@" [8:9 - 8:10] UnexposedExpr=
+// CHECK: Keyword: "encode" [8:10 - 8:16] UnexposedExpr=
+// CHECK: Punctuation: "(" [8:16 - 8:17] UnexposedExpr=
// CHECK: Identifier: "Foo" [8:17 - 8:20] ObjCClassRef=Foo:1:12
-// CHECK: Punctuation: ")" [8:20 - 8:21]
-// CHECK: Punctuation: ";" [8:21 - 8:22]
-// CHECK: Punctuation: "}" [9:1 - 9:2]
-// CHECK: Punctuation: "@" [10:1 - 10:2]
-// CHECK: Identifier: "end" [10:2 - 10:5]
+// CHECK: Punctuation: ")" [8:20 - 8:21] UnexposedExpr=
+// CHECK: Punctuation: ";" [8:21 - 8:22] UnexposedStmt=
+// CHECK: Punctuation: "}" [9:1 - 9:2] UnexposedStmt=
+// CHECK: Punctuation: "@" [10:1 - 10:2] ObjCImplementationDecl=Foo:5:1 (Definition)
+// CHECK: Keyword: "end" [10:2 - 10:5]
+// CHECK: Keyword: "typedef" [14:1 - 14:8]
+// CHECK: Keyword: "int" [14:9 - 14:12]
+// CHECK: Punctuation: "*" [14:13 - 14:14]
+// CHECK: Identifier: "barType" [14:15 - 14:22] TypedefDecl=barType:14:15 (Definition)
+// CHECK: Punctuation: ";" [14:22 - 14:23]
+// CHECK: Punctuation: "@" [15:1 - 15:2] ObjCInterfaceDecl=Bar:15:12
+// CHECK: Keyword: "interface" [15:2 - 15:11] ObjCInterfaceDecl=Bar:15:12
+// CHECK: Identifier: "Bar" [15:12 - 15:15] ObjCInterfaceDecl=Bar:15:12
+// CHECK: Punctuation: "{" [16:1 - 16:2] ObjCInterfaceDecl=Bar:15:12
+// CHECK: Identifier: "barType" [17:5 - 17:12] TypeRef=barType:14:15
+// CHECK: Identifier: "iVar" [17:13 - 17:17] ObjCIvarDecl=iVar:17:13 (Definition)
+// CHECK: Punctuation: ";" [17:17 - 17:18] ObjCInterfaceDecl=Bar:15:12
+// CHECK: Identifier: "barType" [18:5 - 18:12] TypeRef=barType:14:15
+// CHECK: Identifier: "iVar1" [18:13 - 18:18] ObjCIvarDecl=iVar1:18:13 (Definition)
+// CHECK: Punctuation: "," [18:18 - 18:19] ObjCIvarDecl=iVar2:18:20 (Definition)
+// CHECK: Identifier: "iVar2" [18:20 - 18:25] ObjCIvarDecl=iVar2:18:20 (Definition)
+// CHECK: Punctuation: ";" [18:25 - 18:26] ObjCInterfaceDecl=Bar:15:12
+// CHECK: Punctuation: "}" [19:1 - 19:2] ObjCInterfaceDecl=Bar:15:12
+// CHECK: Punctuation: "@" [20:1 - 20:2] ObjCInterfaceDecl=Bar:15:12
+// CHECK: Keyword: "end" [20:2 - 20:5] ObjCInterfaceDecl=Bar:15:12
+// CHECK: Punctuation: "@" [21:1 - 21:2] ObjCImplementationDecl=Bar:21:1 (Definition)
+// CHECK: Keyword: "implementation" [21:2 - 21:16] ObjCImplementationDecl=Bar:21:1 (Definition)
+// CHECK: Identifier: "Bar" [21:17 - 21:20] ObjCImplementationDecl=Bar:21:1 (Definition)
+// CHECK: Punctuation: "-" [22:1 - 22:2] ObjCInstanceMethodDecl=method:22:1 (Definition)
+// CHECK: Punctuation: "(" [22:3 - 22:4] ObjCInstanceMethodDecl=method:22:1 (Definition)
+// CHECK: Keyword: "void" [22:4 - 22:8] ObjCInstanceMethodDecl=method:22:1 (Definition)
+// CHECK: Punctuation: ")" [22:8 - 22:9] ObjCInstanceMethodDecl=method:22:1 (Definition)
+// CHECK: Identifier: "method" [22:10 - 22:16] ObjCInstanceMethodDecl=method:22:1 (Definition)
+// CHECK: Punctuation: "{" [23:1 - 23:2] UnexposedStmt=
+// CHECK: Identifier: "barType" [24:5 - 24:12] TypeRef=barType:14:15
+// CHECK: Identifier: "local" [24:13 - 24:18] VarDecl=local:24:13 (Definition)
+// CHECK: Punctuation: "=" [24:19 - 24:20] VarDecl=local:24:13 (Definition)
+// CHECK: Identifier: "iVar" [24:21 - 24:25] MemberRefExpr=iVar:17:13
+// CHECK: Punctuation: ";" [24:25 - 24:26] UnexposedStmt=
+// CHECK: Punctuation: "}" [25:1 - 25:2] UnexposedStmt=
+// CHECK: Punctuation: "@" [26:1 - 26:2] ObjCImplementationDecl=Bar:21:1 (Definition)
+// CHECK: Keyword: "end" [26:2 - 26:5]
+// CHECK: Punctuation: "@" [32:1 - 32:2] ObjCInterfaceDecl=IBActionTests:32:12
+// CHECK: Keyword: "interface" [32:2 - 32:11] ObjCInterfaceDecl=IBActionTests:32:12
+// CHECK: Identifier: "IBActionTests" [32:12 - 32:25] ObjCInterfaceDecl=IBActionTests:32:12
+// CHECK: Punctuation: "-" [33:1 - 33:2] ObjCInstanceMethodDecl=actionMethod::33:1
+// CHECK: Punctuation: "(" [33:3 - 33:4] ObjCInstanceMethodDecl=actionMethod::33:1
+// CHECK: Identifier: "IBAction" [33:4 - 33:12] macro instantiation=IBAction
+// CHECK: Punctuation: ")" [33:12 - 33:13] ObjCInstanceMethodDecl=actionMethod::33:1
+// CHECK: Identifier: "actionMethod" [33:14 - 33:26] ObjCInstanceMethodDecl=actionMethod::33:1
+// CHECK: Punctuation: ":" [33:26 - 33:27] ObjCInstanceMethodDecl=actionMethod::33:1
+// CHECK: Punctuation: "(" [33:27 - 33:28] ObjCInstanceMethodDecl=actionMethod::33:1
+// CHECK: Identifier: "id" [33:28 - 33:30] TypeRef=id:0:0
+// CHECK: Punctuation: ")" [33:30 - 33:31] ParmDecl=arg:33:31 (Definition)
+// CHECK: Identifier: "arg" [33:31 - 33:34] ParmDecl=arg:33:31 (Definition)
+// CHECK: Punctuation: ";" [33:34 - 33:35] ObjCInstanceMethodDecl=actionMethod::33:1
+// CHECK: Punctuation: "-" [34:1 - 34:2] ObjCInstanceMethodDecl=foo::34:1
+// CHECK: Punctuation: "(" [34:3 - 34:4] ObjCInstanceMethodDecl=foo::34:1
+// CHECK: Keyword: "void" [34:4 - 34:8] ObjCInstanceMethodDecl=foo::34:1
+// CHECK: Punctuation: ")" [34:8 - 34:9] ObjCInstanceMethodDecl=foo::34:1
+// CHECK: Identifier: "foo" [34:9 - 34:12] ObjCInstanceMethodDecl=foo::34:1
+// CHECK: Punctuation: ":" [34:12 - 34:13] ObjCInstanceMethodDecl=foo::34:1
+// CHECK: Punctuation: "(" [34:13 - 34:14] ObjCInstanceMethodDecl=foo::34:1
+// CHECK: Keyword: "int" [34:14 - 34:17] ParmDecl=x:34:18 (Definition)
+// CHECK: Punctuation: ")" [34:17 - 34:18] ParmDecl=x:34:18 (Definition)
+// CHECK: Identifier: "x" [34:18 - 34:19] ParmDecl=x:34:18 (Definition)
+// CHECK: Punctuation: ";" [34:19 - 34:20] ObjCInstanceMethodDecl=foo::34:1
+// CHECK: Punctuation: "@" [35:1 - 35:2] ObjCInterfaceDecl=IBActionTests:32:12
+// CHECK: Keyword: "end" [35:2 - 35:5] ObjCInterfaceDecl=IBActionTests:32:12
+// CHECK: Keyword: "extern" [36:1 - 36:7]
+// CHECK: Keyword: "int" [36:8 - 36:11] FunctionDecl=ibaction_test:36:12
+// CHECK: Identifier: "ibaction_test" [36:12 - 36:25] FunctionDecl=ibaction_test:36:12
+// CHECK: Punctuation: "(" [36:25 - 36:26] FunctionDecl=ibaction_test:36:12
+// CHECK: Keyword: "void" [36:26 - 36:30] FunctionDecl=ibaction_test:36:12
+// CHECK: Punctuation: ")" [36:30 - 36:31] FunctionDecl=ibaction_test:36:12
+// CHECK: Punctuation: ";" [36:31 - 36:32]
+// CHECK: Punctuation: "@" [37:1 - 37:2] ObjCImplementationDecl=IBActionTests:37:1 (Definition)
+// CHECK: Keyword: "implementation" [37:2 - 37:16] ObjCImplementationDecl=IBActionTests:37:1 (Definition)
+// CHECK: Identifier: "IBActionTests" [37:17 - 37:30] ObjCImplementationDecl=IBActionTests:37:1 (Definition)
+// CHECK: Punctuation: "-" [38:1 - 38:2] ObjCInstanceMethodDecl=actionMethod::38:1 (Definition)
+// CHECK: Punctuation: "(" [38:3 - 38:4] ObjCInstanceMethodDecl=actionMethod::38:1 (Definition)
+// CHECK: Identifier: "IBAction" [38:4 - 38:12] macro instantiation=IBAction
+// CHECK: Punctuation: ")" [38:12 - 38:13] ObjCInstanceMethodDecl=actionMethod::38:1 (Definition)
+// CHECK: Identifier: "actionMethod" [38:14 - 38:26] ObjCInstanceMethodDecl=actionMethod::38:1 (Definition)
+// CHECK: Punctuation: ":" [38:26 - 38:27] ObjCInstanceMethodDecl=actionMethod::38:1 (Definition)
+// CHECK: Punctuation: "(" [38:27 - 38:28] ObjCInstanceMethodDecl=actionMethod::38:1 (Definition)
+// CHECK: Identifier: "id" [38:28 - 38:30] TypeRef=id:0:0
+// CHECK: Punctuation: ")" [38:30 - 38:31] ParmDecl=arg:38:31 (Definition)
+// CHECK: Identifier: "arg" [38:31 - 38:34] ParmDecl=arg:38:31 (Definition)
+// CHECK: Punctuation: "{" [39:1 - 39:2] UnexposedStmt=
+// CHECK: Identifier: "ibaction_test" [40:5 - 40:18] DeclRefExpr=ibaction_test:36:12
+// CHECK: Punctuation: "(" [40:18 - 40:19] CallExpr=ibaction_test:36:12
+// CHECK: Punctuation: ")" [40:19 - 40:20] CallExpr=ibaction_test:36:12
+// CHECK: Punctuation: ";" [40:20 - 40:21] UnexposedStmt=
+// CHECK: Punctuation: "[" [41:5 - 41:6] ObjCMessageExpr=foo::34:1
+// CHECK: Identifier: "self" [41:6 - 41:10] DeclRefExpr=self:0:0
+// CHECK: Identifier: "foo" [41:11 - 41:14] ObjCMessageExpr=foo::34:1
+// CHECK: Punctuation: ":" [41:14 - 41:15] ObjCMessageExpr=foo::34:1
+// CHECK: Literal: "0" [41:15 - 41:16] UnexposedExpr=
+// CHECK: Punctuation: "]" [41:16 - 41:17] ObjCMessageExpr=foo::34:1
+// CHECK: Punctuation: ";" [41:17 - 41:18] UnexposedStmt=
+// CHECK: Punctuation: "}" [42:1 - 42:2] UnexposedStmt=
+// CHECK: Punctuation: "-" [43:1 - 43:2] ObjCInstanceMethodDecl=foo::43:1 (Definition)
+// CHECK: Punctuation: "(" [43:3 - 43:4] ObjCInstanceMethodDecl=foo::43:1 (Definition)
+// CHECK: Keyword: "void" [43:4 - 43:8] ObjCInstanceMethodDecl=foo::43:1 (Definition)
+// CHECK: Punctuation: ")" [43:8 - 43:9] ObjCInstanceMethodDecl=foo::43:1 (Definition)
+// CHECK: Identifier: "foo" [43:10 - 43:13] ObjCInstanceMethodDecl=foo::43:1 (Definition)
+// CHECK: Punctuation: ":" [43:13 - 43:14] ObjCInstanceMethodDecl=foo::43:1 (Definition)
+// CHECK: Punctuation: "(" [43:14 - 43:15] ObjCInstanceMethodDecl=foo::43:1 (Definition)
+// CHECK: Keyword: "int" [43:15 - 43:18] ParmDecl=x:43:19 (Definition)
+// CHECK: Punctuation: ")" [43:18 - 43:19] ParmDecl=x:43:19 (Definition)
+// CHECK: Identifier: "x" [43:19 - 43:20] ParmDecl=x:43:19 (Definition)
+// CHECK: Punctuation: "{" [44:1 - 44:2] UnexposedStmt=
+// CHECK: Punctuation: "(" [45:3 - 45:4] UnexposedExpr=x:43:19
+// CHECK: Keyword: "void" [45:4 - 45:8] UnexposedExpr=x:43:19
+// CHECK: Punctuation: ")" [45:8 - 45:9] UnexposedExpr=x:43:19
+// CHECK: Identifier: "x" [45:10 - 45:11] DeclRefExpr=x:43:19
+// CHECK: Punctuation: ";" [45:11 - 45:12] UnexposedStmt=
+// CHECK: Punctuation: "}" [46:1 - 46:2] UnexposedStmt=
+// CHECK: Punctuation: "@" [47:1 - 47:2] ObjCImplementationDecl=IBActionTests:37:1 (Definition)
+// CHECK: Keyword: "end" [47:2 - 47:5]
+// CHECK: Punctuation: "@" [51:1 - 51:2] ObjCInterfaceDecl=IBOutletTests:51:12
+// CHECK: Keyword: "interface" [51:2 - 51:11] ObjCInterfaceDecl=IBOutletTests:51:12
+// CHECK: Identifier: "IBOutletTests" [51:12 - 51:25] ObjCInterfaceDecl=IBOutletTests:51:12
+// CHECK: Punctuation: "{" [52:1 - 52:2] ObjCInterfaceDecl=IBOutletTests:51:12
+// CHECK: Identifier: "IBOutlet" [53:5 - 53:13] macro instantiation=IBOutlet:{{[0-9]+}}:{{[0-9]+}}
+// CHECK: Keyword: "char" [53:14 - 53:18] ObjCIvarDecl=anOutlet:53:21 (Definition)
+// CHECK: Punctuation: "*" [53:19 - 53:20] ObjCIvarDecl=anOutlet:53:21 (Definition)
+// CHECK: Identifier: "anOutlet" [53:21 - 53:29] ObjCIvarDecl=anOutlet:53:21 (Definition)
+// CHECK: Punctuation: ";" [53:29 - 53:30] ObjCInterfaceDecl=IBOutletTests:51:12
+// CHECK: Punctuation: "}" [54:1 - 54:2] ObjCInterfaceDecl=IBOutletTests:51:12
+// CHECK: Punctuation: "-" [55:1 - 55:2] ObjCInterfaceDecl=IBOutletTests:51:12
+// CHECK: Punctuation: "(" [55:3 - 55:4] ObjCInterfaceDecl=IBOutletTests:51:12
+// CHECK: Identifier: "IBAction" [55:4 - 55:12] macro instantiation=IBAction
+// CHECK: Punctuation: ")" [55:12 - 55:13] ObjCInterfaceDecl=IBOutletTests:51:12
+// CHECK: Identifier: "actionMethod" [55:14 - 55:26] ObjCInterfaceDecl=IBOutletTests:51:12
+// CHECK: Punctuation: ":" [55:26 - 55:27] ObjCInterfaceDecl=IBOutletTests:51:12
+// CHECK: Punctuation: "(" [55:27 - 55:28] ObjCInterfaceDecl=IBOutletTests:51:12
+// CHECK: Identifier: "id" [55:28 - 55:30] ObjCInterfaceDecl=IBOutletTests:51:12
+// CHECK: Punctuation: ")" [55:30 - 55:31] ObjCInterfaceDecl=IBOutletTests:51:12
+// CHECK: Identifier: "arg" [55:31 - 55:34] ObjCInterfaceDecl=IBOutletTests:51:12
+// CHECK: Punctuation: ";" [55:34 - 55:35] ObjCInterfaceDecl=IBOutletTests:51:12
+// CHECK: Punctuation: "@" [56:1 - 56:2] ObjCInterfaceDecl=IBOutletTests:51:12
+// CHECK: Keyword: "property" [56:2 - 56:10] ObjCInterfaceDecl=IBOutletTests:51:12
+// CHECK: Identifier: "IBOutlet" [56:11 - 56:19] macro instantiation=IBOutlet:{{[0-9]+}}:{{[0-9]+}}
+// CHECK: Keyword: "int" [56:20 - 56:23] ObjCInterfaceDecl=IBOutletTests:51:12
+// CHECK: Punctuation: "*" [56:24 - 56:25] ObjCInterfaceDecl=IBOutletTests:51:12
+// CHECK: Identifier: "aPropOutlet" [56:26 - 56:37] ObjCPropertyDecl=aPropOutlet:56:26
+// CHECK: Punctuation: ";" [56:37 - 56:38] ObjCInterfaceDecl=IBOutletTests:51:12
+// CHECK: Punctuation: "@" [57:1 - 57:2] ObjCInterfaceDecl=IBOutletTests:51:12
+// CHECK: Keyword: "end" [57:2 - 57:5] ObjCInterfaceDecl=IBOutletTests:51:12
+
diff --git a/test/Index/c-index-api-loadTU-test.m b/test/Index/c-index-api-loadTU-test.m
index 5b2f86e543b2..22875dbfe851 100644
--- a/test/Index/c-index-api-loadTU-test.m
+++ b/test/Index/c-index-api-loadTU-test.m
@@ -54,12 +54,24 @@ int main (int argc, const char * argv[]) {
main(someEnum, (const char **)bee);
}
+// Test attribute traversal.
+#define IBOutlet __attribute__((iboutlet))
+#define IBOutletCollection(ClassName) __attribute__((iboutletcollection))
+#define IBAction void)__attribute__((ibaction)
+
+@interface TestAttributes {
+ IBOutlet char * anOutlet;
+ IBOutletCollection(id) id anOutletCollection;
+}
+- (IBAction) actionMethod:(id)arg;
+@end
+
// CHECK: c-index-api-loadTU-test.m:4:12: ObjCInterfaceDecl=Foo:4:12 Extent=[4:1 - 12:5]
// CHECK: c-index-api-loadTU-test.m:6:32: ObjCIvarDecl=myoutlet:6:32 (Definition) Extent=[6:32 - 6:40]
-// CHECK: c-index-api-loadTU-test.m:6:32: attribute(iboutlet)= Extent=[6:32 - 6:40]
+// CHECK: <invalid loc>:0:0: attribute(iboutlet)=
// CHECK: c-index-api-loadTU-test.m:6:29: TypeRef=id:0:0 Extent=[6:29 - 6:31]
// CHECK: c-index-api-loadTU-test.m:8:1: ObjCInstanceMethodDecl=myMessage::8:1 Extent=[8:1 - 8:54]
-// CHECK: c-index-api-loadTU-test.m:8:1: attribute(ibaction)= Extent=[8:1 - 8:54]
+// CHECK: <invalid loc>:0:0: attribute(ibaction)=
// CHECK: c-index-api-loadTU-test.m:8:50: ParmDecl=msg:8:50 (Definition) Extent=[8:47 - 8:53]
// CHECK: c-index-api-loadTU-test.m:8:47: TypeRef=id:0:0 Extent=[8:47 - 8:49]
// CHECK: c-index-api-loadTU-test.m:9:1: ObjCInstanceMethodDecl=foo:9:1 Extent=[9:1 - 9:7]
@@ -81,27 +93,29 @@ int main (int argc, const char * argv[]) {
// CHECK: c-index-api-loadTU-test.m:33:23: ObjCProtocolRef=SubP:29:1 Extent=[33:23 - 33:27]
// CHECK: c-index-api-loadTU-test.m:35:9: ObjCIvarDecl=_anIVar:35:9 (Definition) Extent=[35:9 - 35:16]
// CHECK: c-index-api-loadTU-test.m:38:1: ObjCInstanceMethodDecl=bazMethod:38:1 Extent=[38:1 - 38:21]
+// CHECK: c-index-api-loadTU-test.m:38:4: ObjCClassRef=Foo:4:12 Extent=[38:4 - 38:7]
// CHECK: c-index-api-loadTU-test.m:42:1: EnumDecl=:42:1 (Definition) Extent=[42:1 - 44:2]
// CHECK: c-index-api-loadTU-test.m:43:3: EnumConstantDecl=someEnum:43:3 (Definition) Extent=[43:3 - 43:11]
// CHECK: c-index-api-loadTU-test.m:46:5: FunctionDecl=main:46:5 (Definition) Extent=[46:5 - 55:2]
// CHECK: c-index-api-loadTU-test.m:46:15: ParmDecl=argc:46:15 (Definition) Extent=[46:11 - 46:19]
// CHECK: c-index-api-loadTU-test.m:46:34: ParmDecl=argv:46:34 (Definition) Extent=[46:27 - 46:38]
-// CHECK: c-index-api-loadTU-test.m:46:5: UnexposedStmt= Extent=[46:42 - 55:2]
-// CHECK: c-index-api-loadTU-test.m:46:5: UnexposedStmt= Extent=[47:2 - 47:12]
+// CHECK: <invalid loc>:0:0: UnexposedStmt= Extent=[46:42 - 55:2]
+// CHECK: <invalid loc>:0:0: UnexposedStmt= Extent=[47:2 - 47:12]
// CHECK: c-index-api-loadTU-test.m:47:8: VarDecl=bee:47:8 (Definition) Extent=[47:2 - 47:11]
// CHECK: c-index-api-loadTU-test.m:47:2: ObjCClassRef=Baz:33:12 Extent=[47:2 - 47:5]
-// CHECK: c-index-api-loadTU-test.m:47:8: UnexposedStmt= Extent=[48:2 - 48:19]
+// CHECK: <invalid loc>:0:0: UnexposedStmt= Extent=[48:2 - 48:19]
// CHECK: c-index-api-loadTU-test.m:48:5: VarDecl=a:48:5 (Definition) Extent=[48:2 - 48:18]
// CHECK: c-index-api-loadTU-test.m:48:2: TypeRef=id:0:0 Extent=[48:2 - 48:4]
// CHECK: c-index-api-loadTU-test.m:48:9: ObjCMessageExpr=foo:9:1 Extent=[48:9 - 48:18]
// CHECK: c-index-api-loadTU-test.m:48:10: DeclRefExpr=bee:47:8 Extent=[48:10 - 48:13]
-// CHECK: c-index-api-loadTU-test.m:48:5: UnexposedStmt= Extent=[49:2 - 49:27]
+// CHECK: <invalid loc>:0:0: UnexposedStmt= Extent=[49:2 - 49:27]
// CHECK: c-index-api-loadTU-test.m:49:12: VarDecl=c:49:12 (Definition) Extent=[49:2 - 49:26]
// CHECK: c-index-api-loadTU-test.m:49:2: TypeRef=id:0:0 Extent=[49:2 - 49:4]
// CHECK: c-index-api-loadTU-test.m:49:6: ObjCProtocolRef=SubP:29:1 Extent=[49:6 - 49:10]
// CHECK: c-index-api-loadTU-test.m:49:16: UnexposedExpr=fooC:10:1 Extent=[49:16 - 49:26]
// CHECK: c-index-api-loadTU-test.m:49:16: ObjCMessageExpr=fooC:10:1 Extent=[49:16 - 49:26]
-// CHECK: c-index-api-loadTU-test.m:49:12: UnexposedStmt= Extent=[50:2 - 50:15]
+// CHECK: c-index-api-loadTU-test.m:49:17: ObjCClassRef=Foo:4:12 Extent=[49:17 - 49:20]
+// CHECK: <invalid loc>:0:0: UnexposedStmt= Extent=[50:2 - 50:15]
// CHECK: c-index-api-loadTU-test.m:50:13: VarDecl=d:50:13 (Definition) Extent=[50:2 - 50:14]
// CHECK: c-index-api-loadTU-test.m:50:2: TypeRef=id:0:0 Extent=[50:2 - 50:4]
// CHECK: c-index-api-loadTU-test.m:50:6: ObjCProtocolRef=Proto:25:1 Extent=[50:6 - 50:11]
@@ -121,4 +135,14 @@ int main (int argc, const char * argv[]) {
// CHECK: c-index-api-loadTU-test.m:54:8: DeclRefExpr=someEnum:43:3 Extent=[54:8 - 54:16]
// CHECK: c-index-api-loadTU-test.m:54:18: UnexposedExpr=bee:47:8 Extent=[54:18 - 54:36]
// CHECK: c-index-api-loadTU-test.m:54:33: DeclRefExpr=bee:47:8 Extent=[54:33 - 54:36]
+// CHECK: c-index-api-loadTU-test.m:62:12: ObjCInterfaceDecl=TestAttributes:62:12 Extent=[62:1 - 67:5]
+// CHECK: c-index-api-loadTU-test.m:63:19: ObjCIvarDecl=anOutlet:63:19 (Definition) Extent=[63:19 - 63:27]
+// CHECK: <invalid loc>:0:0: attribute(iboutlet)=
+// CHECK: c-index-api-loadTU-test.m:64:29: ObjCIvarDecl=anOutletCollection:64:29 (Definition) Extent=[64:29 - 64:47]
+// CHECK: <invalid loc>:0:0: attribute(iboutletcollection)=
+// CHECK: c-index-api-loadTU-test.m:64:26: TypeRef=id:0:0 Extent=[64:26 - 64:28]
+// CHECK: c-index-api-loadTU-test.m:66:1: ObjCInstanceMethodDecl=actionMethod::66:1 Extent=[66:1 - 66:35]
+// CHECK: <invalid loc>:0:0: attribute(ibaction)=
+// CHECK: c-index-api-loadTU-test.m:66:31: ParmDecl=arg:66:31 (Definition) Extent=[66:28 - 66:34]
+// CHECK: c-index-api-loadTU-test.m:66:28: TypeRef=id:0:0 Extent=[66:28 - 66:30]
diff --git a/test/Index/complete-at-directives.m b/test/Index/complete-at-directives.m
index 811bca00efb0..a278ce883666 100644
--- a/test/Index/complete-at-directives.m
+++ b/test/Index/complete-at-directives.m
@@ -5,25 +5,25 @@
@implementation MyClass
@end
-// RUN: c-index-test -code-completion-at=%s:2:2 %s | FileCheck -check-prefix=CHECK-CC1 %s
+// RUN: c-index-test -code-completion-at=%s:2:2 -Xclang -code-completion-patterns %s | FileCheck -check-prefix=CHECK-CC1 %s
// CHECK-CC1: {TypedText class}{HorizontalSpace }{Placeholder identifier}
// CHECK-CC1: {TypedText compatibility_alias}{HorizontalSpace }{Placeholder alias}{HorizontalSpace }{Placeholder class}
// CHECK-CC1: {TypedText implementation}{HorizontalSpace }{Placeholder class}
// CHECK-CC1: {TypedText interface}{HorizontalSpace }{Placeholder class}
// CHECK-CC1: {TypedText protocol}{HorizontalSpace }{Placeholder protocol}
-// RUN: c-index-test -code-completion-at=%s:3:2 %s | FileCheck -check-prefix=CHECK-CC2 %s
+// RUN: c-index-test -code-completion-at=%s:3:2 -Xclang -code-completion-patterns %s | FileCheck -check-prefix=CHECK-CC2 %s
// CHECK-CC2: {TypedText end}
// CHECK-CC2: {TypedText optional}
// CHECK-CC2: {TypedText property}
// CHECK-CC2: {TypedText required}
-// RUN: c-index-test -code-completion-at=%s:6:2 %s | FileCheck -check-prefix=CHECK-CC3 %s
+// RUN: c-index-test -code-completion-at=%s:6:2 -Xclang -code-completion-patterns %s | FileCheck -check-prefix=CHECK-CC3 %s
// CHECK-CC3: {TypedText dynamic}{HorizontalSpace }{Placeholder property}
// CHECK-CC3: {TypedText end}
// CHECK-CC3: {TypedText synthesize}{HorizontalSpace }{Placeholder property}
-// RUN: c-index-test -code-completion-at=%s:2:1 %s | FileCheck -check-prefix=CHECK-CC4 %s
+// RUN: c-index-test -code-completion-at=%s:2:1 -Xclang -code-completion-patterns %s | FileCheck -check-prefix=CHECK-CC4 %s
// CHECK-CC4: NotImplemented:{TypedText @class}{HorizontalSpace }{Placeholder identifier}
// CHECK-CC4: NotImplemented:{TypedText @compatibility_alias}{HorizontalSpace }{Placeholder alias}{HorizontalSpace }{Placeholder class}
// CHECK-CC4: NotImplemented:{TypedText @implementation}{HorizontalSpace }{Placeholder class}
@@ -34,7 +34,7 @@
// CHECK-CC4: TypedefDecl:{TypedText id}
// CHECK-CC4: TypedefDecl:{TypedText SEL}
-// RUN: c-index-test -code-completion-at=%s:3:1 %s | FileCheck -check-prefix=CHECK-CC5 %s
+// RUN: c-index-test -code-completion-at=%s:3:1 -Xclang -code-completion-patterns %s | FileCheck -check-prefix=CHECK-CC5 %s
// CHECK-CC5: {TypedText @end}
// CHECK-CC5: {TypedText @optional}
// CHECK-CC5: {TypedText @property}
@@ -45,13 +45,13 @@
// CHECK-CC5: ObjCInterfaceDecl:{TypedText MyClass}
// CHECK-CC5: TypedefDecl:{TypedText SEL}
-// RUN: c-index-test -code-completion-at=%s:2:23 %s | FileCheck -check-prefix=CHECK-CC6 %s
+// RUN: c-index-test -code-completion-at=%s:2:23 -Xclang -code-completion-patterns %s | FileCheck -check-prefix=CHECK-CC6 %s
// CHECK-CC6: NotImplemented:{TypedText package}
// CHECK-CC6: NotImplemented:{TypedText private}
// CHECK-CC6: NotImplemented:{TypedText protected}
// CHECK-CC6: NotImplemented:{TypedText public}
-// RUN: c-index-test -code-completion-at=%s:2:22 %s | FileCheck -check-prefix=CHECK-CC7 %s
+// RUN: c-index-test -code-completion-at=%s:2:22 -Xclang -code-completion-patterns %s | FileCheck -check-prefix=CHECK-CC7 %s
// CHECK-CC7: NotImplemented:{TypedText @package}
// CHECK-CC7: NotImplemented:{TypedText @private}
// CHECK-CC7: NotImplemented:{TypedText @protected}
diff --git a/test/Index/complete-at-exprstmt.m b/test/Index/complete-at-exprstmt.m
index 87e554ff22ae..85370989fd83 100644
--- a/test/Index/complete-at-exprstmt.m
+++ b/test/Index/complete-at-exprstmt.m
@@ -9,18 +9,18 @@
@synchronized (@encode(MyClass)) { }
}
@end
-// RUN: c-index-test -code-completion-at=%s:9:4 %s | FileCheck -check-prefix=CHECK-CC1 %s
+// RUN: c-index-test -code-completion-at=%s:9:4 -Xclang -code-completion-patterns %s | FileCheck -check-prefix=CHECK-CC1 %s
// CHECK-CC1: {TypedText encode}{LeftParen (}{Placeholder type-name}{RightParen )}
// CHECK-CC1: {TypedText protocol}{LeftParen (}{Placeholder protocol-name}{RightParen )}
// CHECK-CC1: {TypedText selector}{LeftParen (}{Placeholder selector}{RightParen )}
// CHECK-CC1: {TypedText synchronized}{HorizontalSpace }{LeftParen (}{Placeholder expression}{RightParen )}{LeftBrace {}{Placeholder statements}{RightBrace }}
// CHECK-CC1: {TypedText throw}{HorizontalSpace }{Placeholder expression}
// CHECK-CC1: {TypedText try}{LeftBrace {}{Placeholder statements}{RightBrace }}{Text @catch}{LeftParen (}{Placeholder parameter}{RightParen )}{LeftBrace {}{Placeholder statements}{RightBrace }}{Text @finally}{LeftBrace {}{Placeholder statements}{RightBrace }}
-// RUN: c-index-test -code-completion-at=%s:9:19 %s | FileCheck -check-prefix=CHECK-CC2 %s
+// RUN: c-index-test -code-completion-at=%s:9:19 -Xclang -code-completion-patterns %s | FileCheck -check-prefix=CHECK-CC2 %s
// CHECK-CC2: {TypedText encode}{LeftParen (}{Placeholder type-name}{RightParen )}
// CHECK-CC2: {TypedText protocol}{LeftParen (}{Placeholder protocol-name}{RightParen )}
// CHECK-CC2: {TypedText selector}{LeftParen (}{Placeholder selector}{RightParen )}
-// RUN: c-index-test -code-completion-at=%s:9:3 %s | FileCheck -check-prefix=CHECK-CC3 %s
+// RUN: c-index-test -code-completion-at=%s:9:3 -Xclang -code-completion-patterns %s | FileCheck -check-prefix=CHECK-CC3 %s
// CHECK-CC3: NotImplemented:{TypedText @encode}{LeftParen (}{Placeholder type-name}{RightParen )}
// CHECK-CC3: NotImplemented:{TypedText @protocol}{LeftParen (}{Placeholder protocol-name}{RightParen )}
// CHECK-CC3: NotImplemented:{TypedText @selector}{LeftParen (}{Placeholder selector}{RightParen )}
diff --git a/test/Index/complete-exprs.c b/test/Index/complete-exprs.c
index efc82f90a9e6..65af2419213a 100644
--- a/test/Index/complete-exprs.c
+++ b/test/Index/complete-exprs.c
@@ -7,9 +7,12 @@ int test(int i, int j, int k, int l) {
return i | j | k & l;
}
-// RUN: c-index-test -code-completion-at=%s:7:9 %s | FileCheck -check-prefix=CHECK-CC1 %s
-// CHECK-CC1: FunctionDecl:{ResultType int}{TypedText f}{LeftParen (}{Placeholder int}{RightParen )}
-// CHECK-CC1: NotImplemented:{TypedText sizeof}{LeftParen (}{Placeholder expression-or-type}{RightParen )}
-// RUN: c-index-test -code-completion-at=%s:7:14 %s | FileCheck -check-prefix=CHECK-CC1 %s
-// RUN: c-index-test -code-completion-at=%s:7:18 %s | FileCheck -check-prefix=CHECK-CC1 %s
-// RUN: c-index-test -code-completion-at=%s:7:22 %s | FileCheck -check-prefix=CHECK-CC1 %s
+// RUN: c-index-test -code-completion-at=%s:7:9 -Xclang -code-completion-patterns %s | FileCheck -check-prefix=CHECK-CC1 %s
+// CHECK-CC1: macro definition:{TypedText __VERSION__} (70)
+// CHECK-CC1: FunctionDecl:{ResultType int}{TypedText f}{LeftParen (}{Placeholder int}{RightParen )} (50)
+// CHECK-CC1: NotImplemented:{TypedText float} (40)
+// CHECK-CC1: ParmDecl:{ResultType int}{TypedText j} (8)
+// CHECK-CC1: NotImplemented:{TypedText sizeof}{LeftParen (}{Placeholder expression-or-type}{RightParen )} (30)
+// RUN: c-index-test -code-completion-at=%s:7:14 -Xclang -code-completion-patterns %s | FileCheck -check-prefix=CHECK-CC1 %s
+// RUN: c-index-test -code-completion-at=%s:7:18 -Xclang -code-completion-patterns %s | FileCheck -check-prefix=CHECK-CC1 %s
+// RUN: c-index-test -code-completion-at=%s:7:22 -Xclang -code-completion-patterns %s | FileCheck -check-prefix=CHECK-CC1 %s
diff --git a/test/Index/complete-member-access.m b/test/Index/complete-member-access.m
index 2502d7705b9c..82efb9511586 100644
--- a/test/Index/complete-member-access.m
+++ b/test/Index/complete-member-access.m
@@ -26,5 +26,5 @@ void test_props(Int* ptr) {
// CHECK-CC1: ObjCPropertyDecl:{ResultType int}{TypedText prop1}
// CHECK-CC1: ObjCPropertyDecl:{ResultType float}{TypedText ProtoProp}
// RUN: c-index-test -code-completion-at=%s:22:8 %s | FileCheck -check-prefix=CHECK-CC2 %s
-// CHECK-CC2: ObjCIvarDecl:{ResultType int}{TypedText IVar}
-// CHECK-CC2: ObjCIvarDecl:{ResultType int}{TypedText SuperIVar}
+// CHECK-CC2: ObjCIvarDecl:{ResultType int}{TypedText IVar} (20)
+// CHECK-CC2: ObjCIvarDecl:{ResultType int}{TypedText SuperIVar} (22)
diff --git a/test/Index/complete-recovery.m b/test/Index/complete-recovery.m
new file mode 100644
index 000000000000..c28438da66f8
--- /dev/null
+++ b/test/Index/complete-recovery.m
@@ -0,0 +1,21 @@
+/* Run lines are at the end, since line/column matter in this test. */
+
+@interface A
+- (void)method:(int)x;
+@end
+
+@implementation A
+- (void)method:(int)x {
+ A *a = [A method:1];
+ blarg * blah = wibble
+}
+@end
+
+// RUN: c-index-test -code-completion-at=%s:9:20 -Xclang -code-completion-patterns %s 2>%t | FileCheck -check-prefix=CHECK-CC1 %s
+// RUN: not grep error %t
+// CHECK-CC1: NotImplemented:{TypedText @encode}{LeftParen (}{Placeholder type-name}{RightParen )}
+// CHECK-CC1: NotImplemented:{TypedText _Bool}
+// CHECK-CC1: VarDecl:{ResultType A *}{TypedText a}
+// CHECK-CC1: NotImplemented:{TypedText sizeof}{LeftParen (}{Placeholder expression-or-type}{RightParen )}
+
+// RUN: c-index-test -code-completion-at=%s:10:24 -Xclang -code-completion-patterns %s 2>%t | FileCheck -check-prefix=CHECK-CC1 %s
diff --git a/test/Index/load-stmts.cpp b/test/Index/load-stmts.cpp
index fdfedfb16efb..cb99aee3ad6d 100644
--- a/test/Index/load-stmts.cpp
+++ b/test/Index/load-stmts.cpp
@@ -11,8 +11,15 @@ void f(int x) {
}
// RUN: c-index-test -test-load-source all %s | FileCheck %s
-// CHECK: load-stmts.cpp:3:6: UnexposedStmt= Extent=[4:3 - 5:4]
-// CHECK: load-stmts.cpp:3:6: UnexposedStmt= Extent=[4:8 - 4:16]
+// CHECK: load-stmts.cpp:1:13: TypedefDecl=T:1:13 (Definition) Extent=[1:13 - 1:14]
+// CHECK: load-stmts.cpp:2:8: StructDecl=X:2:8 (Definition) Extent=[2:1 - 2:23]
+// CHECK: load-stmts.cpp:2:16: FieldDecl=a:2:16 (Definition) Extent=[2:16 - 2:17]
+// CHECK: load-stmts.cpp:2:19: FieldDecl=b:2:19 (Definition) Extent=[2:19 - 2:20]
+// CHECK: load-stmts.cpp:3:6: FunctionDecl=f:3:6 (Definition) Extent=[3:6 - 11:2]
+// CHECK: load-stmts.cpp:3:12: ParmDecl=x:3:12 (Definition) Extent=[3:8 - 3:13]
+// CHECK: <invalid loc>:0:0: UnexposedStmt= Extent=[3:15 - 11:2]
+// CHECK: <invalid loc>:0:0: UnexposedStmt= Extent=[4:3 - 5:4]
+// CHECK: <invalid loc>:0:0: UnexposedStmt= Extent=[4:8 - 4:16]
// CHECK: load-stmts.cpp:4:10: VarDecl=y:4:10 (Definition) Extent=[4:8 - 4:15]
// CHECK: load-stmts.cpp:4:8: TypeRef=T:1:13 Extent=[4:8 - 4:9]
// CHECK: load-stmts.cpp:4:14: DeclRefExpr=x:3:12 Extent=[4:14 - 4:15]
@@ -23,29 +30,30 @@ void f(int x) {
// CHECK: load-stmts.cpp:4:19: DeclRefExpr=z:4:19 Extent=[4:19 - 4:20]
// CHECK: load-stmts.cpp:4:26: UnexposedExpr= Extent=[4:26 - 4:29]
// CHECK: load-stmts.cpp:4:28: DeclRefExpr=x:3:12 Extent=[4:28 - 4:29]
-// CHECK: load-stmts.cpp:4:19: UnexposedStmt= Extent=[4:31 - 5:4]
-// CHECK: load-stmts.cpp:4:19: UnexposedStmt= Extent=[6:3 - 6:22]
+// CHECK: <invalid loc>:0:0: UnexposedStmt= Extent=[4:31 - 5:4]
+// CHECK: <invalid loc>:0:0: UnexposedStmt= Extent=[6:3 - 6:22]
// CHECK: load-stmts.cpp:6:10: VarDecl=z2:6:10 (Definition) Extent=[6:7 - 6:17]
// CHECK: load-stmts.cpp:6:7: TypeRef=T:1:13 Extent=[6:7 - 6:8]
// CHECK: load-stmts.cpp:6:15: UnexposedExpr= Extent=[6:15 - 6:17]
// CHECK: load-stmts.cpp:6:16: DeclRefExpr=x:3:12 Extent=[6:16 - 6:17]
// CHECK: load-stmts.cpp:6:10: UnexposedExpr=z2:6:10 Extent=[6:10 - 6:12]
// CHECK: load-stmts.cpp:6:10: DeclRefExpr=z2:6:10 Extent=[6:10 - 6:12]
-// CHECK: load-stmts.cpp:6:10: UnexposedStmt= Extent=[6:19 - 6:22]
-// CHECK: load-stmts.cpp:6:10: UnexposedStmt= Extent=[7:3 - 7:25]
+// CHECK: <invalid loc>:0:0: UnexposedStmt= Extent=[6:19 - 6:22]
+// CHECK: <invalid loc>:0:0: UnexposedStmt= Extent=[7:3 - 7:25]
// CHECK: load-stmts.cpp:7:13: VarDecl=z3:7:13 (Definition) Extent=[7:10 - 7:20]
// CHECK: load-stmts.cpp:7:10: TypeRef=T:1:13 Extent=[7:10 - 7:11]
// CHECK: load-stmts.cpp:7:18: UnexposedExpr= Extent=[7:18 - 7:20]
// CHECK: load-stmts.cpp:7:19: DeclRefExpr=x:3:12 Extent=[7:19 - 7:20]
// CHECK: load-stmts.cpp:7:13: UnexposedExpr=z3:7:13 Extent=[7:13 - 7:15]
// CHECK: load-stmts.cpp:7:13: DeclRefExpr=z3:7:13 Extent=[7:13 - 7:15]
-// CHECK: load-stmts.cpp:7:13: UnexposedStmt= Extent=[7:22 - 7:25]
-// CHECK: load-stmts.cpp:7:13: UnexposedStmt= Extent=[8:3 - 10:4]
+// CHECK: <invalid loc>:0:0: UnexposedStmt= Extent=[7:22 - 7:25]
+// CHECK: <invalid loc>:0:0: UnexposedStmt= Extent=[8:3 - 10:4]
// CHECK: load-stmts.cpp:8:13: VarDecl=z4:8:13 (Definition) Extent=[8:11 - 8:19]
// CHECK: load-stmts.cpp:8:11: TypeRef=T:1:13 Extent=[8:11 - 8:12]
// CHECK: load-stmts.cpp:8:18: DeclRefExpr=x:3:12 Extent=[8:18 - 8:19]
// CHECK: load-stmts.cpp:8:13: DeclRefExpr=z4:8:13 Extent=[8:13 - 8:15]
-// CHECK: load-stmts.cpp:8:13: UnexposedStmt= Extent=[8:21 - 10:4]
-// CHECK: load-stmts.cpp:8:13: UnexposedStmt= Extent=[9:3 - 9:17]
-// CHECK: load-stmts.cpp:8:13: UnexposedStmt= Extent=[9:12 - 9:17]
+// CHECK: <invalid loc>:0:0: UnexposedStmt= Extent=[8:21 - 10:4]
+// CHECK: <invalid loc>:0:0: UnexposedStmt= Extent=[9:3 - 9:17]
// CHECK: load-stmts.cpp:9:8: UnexposedExpr= Extent=[9:8 - 9:10]
+// CHECK: <invalid loc>:0:0: UnexposedStmt= Extent=[9:12 - 9:17]
+
diff --git a/test/Index/print-typekind.c b/test/Index/print-typekind.c
new file mode 100644
index 000000000000..79a9965d4d85
--- /dev/null
+++ b/test/Index/print-typekind.c
@@ -0,0 +1,20 @@
+typedef int FooType;
+int *p;
+int *f(int *p, char *x, FooType z) {
+ FooType w = z;
+ return p + z;
+}
+
+// RUN: c-index-test -test-print-typekind %s | FileCheck %s
+// CHECK: TypedefDecl=FooType:1:13 (Definition) typekind=Typedef [canonical=Int]
+// CHECK: VarDecl=p:2:6 typekind=Pointer
+// CHECK: FunctionDecl=f:3:6 (Definition) typekind=Unexposed [canonical=Unexposed]
+// CHECK: ParmDecl=p:3:13 (Definition) typekind=Pointer
+// CHECK: ParmDecl=x:3:22 (Definition) typekind=Pointer
+// CHECK: ParmDecl=z:3:33 (Definition) typekind=Typedef [canonical=Int]
+// CHECK: VarDecl=w:4:11 (Definition) typekind=Typedef [canonical=Int]
+// CHECK: DeclRefExpr=z:3:33 typekind=Typedef [canonical=Int]
+// CHECK: UnexposedExpr= typekind=Pointer
+// CHECK: DeclRefExpr=p:3:13 typekind=Pointer
+// CHECK: DeclRefExpr=z:3:33 typekind=Typedef [canonical=Int]
+
diff --git a/test/Index/properties-class-extensions.m b/test/Index/properties-class-extensions.m
new file mode 100644
index 000000000000..8bca37e7c9de
--- /dev/null
+++ b/test/Index/properties-class-extensions.m
@@ -0,0 +1,28 @@
+// Test that @properties within class extensions are visited by
+// clang_visitChildren only in the class extension, not the original
+// @interface (where we have a duplicate declaration - to be removed).
+@interface Foo {} @end
+@interface Foo (Cat)
+ @property int a;
+@end
+@interface Foo ()
+ @property int b;
+ - (void) bar;
+@end
+
+// RUN: c-index-test -test-load-source local %s | FileCheck %s
+// CHECK: properties-class-extensions.m:4:12: ObjCInterfaceDecl=Foo:4:12 Extent=[4:1 - 4:23]
+// CHECK: properties-class-extensions.m:5:12: ObjCCategoryDecl=Cat:5:12 Extent=[5:1 - 7:5]
+// CHECK: properties-class-extensions.m:5:12: ObjCClassRef=Foo:4:12 Extent=[5:12 - 5:15]
+// CHECK: properties-class-extensions.m:6:17: ObjCPropertyDecl=a:6:17 Extent=[6:17 - 6:18]
+// CHECK: properties-class-extensions.m:6:17: ObjCInstanceMethodDecl=a:6:17 Extent=[6:17 - 6:18]
+// CHECK: properties-class-extensions.m:6:17: ObjCInstanceMethodDecl=setA::6:17 Extent=[6:17 - 6:18]
+// CHECK: properties-class-extensions.m:6:17: ParmDecl=a:6:17 (Definition) Extent=[6:17 - 6:18]
+// CHECK: properties-class-extensions.m:8:12: ObjCCategoryDecl=:8:12 Extent=[8:1 - 11:5]
+// CHECK: properties-class-extensions.m:8:12: ObjCClassRef=Foo:4:12 Extent=[8:12 - 8:15]
+// CHECK: properties-class-extensions.m:9:17: ObjCPropertyDecl=b:9:17 Extent=[9:17 - 9:18]
+// CHECK: properties-class-extensions.m:9:17: ObjCInstanceMethodDecl=b:9:17 Extent=[9:17 - 9:18]
+// CHECK: properties-class-extensions.m:9:17: ObjCInstanceMethodDecl=setB::9:17 Extent=[9:17 - 9:18]
+// CHECK: properties-class-extensions.m:9:17: ParmDecl=b:9:17 (Definition) Extent=[9:17 - 9:18]
+// CHECK: properties-class-extensions.m:10:3: ObjCInstanceMethodDecl=bar:10:3 Extent=[10:3 - 10:16]
+
diff --git a/test/Index/remap-load.c b/test/Index/remap-load.c
index b8415e6a17d4..d9634a4af676 100644
--- a/test/Index/remap-load.c
+++ b/test/Index/remap-load.c
@@ -5,8 +5,8 @@
// CHECK: remap-load.c:1:5: FunctionDecl=foo:1:5 (Definition) Extent=[1:5 - 3:2]
// CHECK: remap-load.c:1:13: ParmDecl=parm1:1:13 (Definition) Extent=[1:9 - 1:18]
// CHECK: remap-load.c:1:26: ParmDecl=parm2:1:26 (Definition) Extent=[1:20 - 1:31]
-// CHECK: remap-load.c:1:5: UnexposedStmt= Extent=[1:33 - 3:2]
-// CHECK: remap-load.c:1:5: UnexposedStmt= Extent=[2:3 - 2:23]
+// CHECK: <invalid loc>:0:0: UnexposedStmt= Extent=[1:33 - 3:2]
+// CHECK: <invalid loc>:0:0: UnexposedStmt= Extent=[2:3 - 2:23]
// CHECK: remap-load.c:2:10: UnexposedExpr= Extent=[2:10 - 2:23]
// CHECK: remap-load.c:2:10: UnexposedExpr= Extent=[2:10 - 2:23]
// CHECK: remap-load.c:2:10: UnexposedExpr=parm1:1:13 Extent=[2:10 - 2:15]
diff --git a/test/Index/usrs.cpp b/test/Index/usrs.cpp
new file mode 100644
index 000000000000..b6a6d3dadab6
--- /dev/null
+++ b/test/Index/usrs.cpp
@@ -0,0 +1,107 @@
+namespace foo {
+ int x;
+ void bar(int z);
+}
+namespace bar {
+ typedef int QType;
+ void bar(QType z);
+}
+
+class ClsA {
+public:
+ int a, b;
+ ClsA(int A, int B) : a(A), b(B) {}
+};
+
+namespace foo {
+ class ClsB : public ClsA {
+ public:
+ ClsB() : ClsA(1, 2) {}
+ int result() const;
+ };
+}
+
+int foo::ClsB::result() const {
+ return a + b;
+}
+
+namespace {
+ class ClsC : public foo::ClsB {};
+ int w;
+}
+
+int z;
+
+namespace foo { namespace taz {
+ int x;
+ static inline int add(int a, int b) { return a + b; }
+ void sub(int a, int b);
+}
+}
+
+namespace foo { namespace taz {
+ class ClsD : public foo::ClsB {
+ public:
+ ClsD& operator=(int x) { a = x; return *this; }
+ ClsD& operator=(double x) { a = (int) x; return *this; }
+ ClsD& operator=(const ClsD &x) { a = x.a; return *this; }
+ static int qux();
+ static int uz(int z, ...);
+ bool operator==(const ClsD &x) const { return a == x.a; }
+ };
+}}
+
+extern "C" {
+ void rez(int a, int b);
+}
+
+// RUN: c-index-test -test-load-source-usrs all %s | FileCheck %s
+// CHECK: usrs.cpp c:@N@foo Extent=[1:11 - 4:2]
+// CHECK: usrs.cpp c:@N@foo@x Extent=[2:3 - 2:8]
+// CHECK: usrs.cpp c:@N@foo@F@bar#I# Extent=[3:8 - 3:18]
+// CHECK: usrs.cpp c:usrs.cpp@3:12@N@foo@F@bar#I#@z Extent=[3:12 - 3:17]
+// CHECK: usrs.cpp c:@N@bar Extent=[5:11 - 8:2]
+// CHECK: usrs.cpp c:usrs.cpp@6:15@N@bar@T@QType Extent=[6:15 - 6:20]
+// CHECK: usrs.cpp c:@N@bar@F@bar#I# Extent=[7:8 - 7:20]
+// CHECK: usrs.cpp c:usrs.cpp@7:12@N@bar@F@bar#I#@z Extent=[7:12 - 7:19]
+// CHECK: usrs.cpp c:@C@ClsA Extent=[10:1 - 14:2]
+// CHECK: usrs.cpp c:@C@ClsA@FI@a Extent=[12:7 - 12:8]
+// CHECK: usrs.cpp c:@C@ClsA@FI@b Extent=[12:10 - 12:11]
+// CHECK: usrs.cpp c:@C@ClsA@F@ClsA#I#I# Extent=[13:3 - 13:37]
+// CHECK: usrs.cpp c:usrs.cpp@13:8@C@ClsA@F@ClsA#I#I#@A Extent=[13:8 - 13:13]
+// CHECK: usrs.cpp c:usrs.cpp@13:15@C@ClsA@F@ClsA#I#I#@B Extent=[13:15 - 13:20]
+// CHECK: usrs.cpp c:@N@foo Extent=[16:11 - 22:2]
+// CHECK: usrs.cpp c:@N@foo@C@ClsB Extent=[17:3 - 21:4]
+// CHECK: usrs.cpp c:@N@foo@C@ClsB@F@ClsB# Extent=[19:5 - 19:27]
+// CHECK: usrs.cpp c:@N@foo@C@ClsB@F@result#1 Extent=[20:9 - 20:17]
+// CHECK: usrs.cpp c:@N@foo@C@ClsB@F@result#1 Extent=[24:16 - 26:2]
+// CHECK: usrs.cpp c:@aN@C@ClsC Extent=[29:3 - 29:35]
+// CHECK: usrs.cpp c:@aN@w Extent=[30:3 - 30:8]
+// CHECK: usrs.cpp c:@z Extent=[33:1 - 33:6]
+// CHECK: usrs.cpp c:@N@foo Extent=[35:11 - 40:2]
+// CHECK: usrs.cpp c:@N@foo@N@taz Extent=[35:27 - 39:2]
+// CHECK: usrs.cpp c:@N@foo@N@taz@x Extent=[36:3 - 36:8]
+// CHECK: usrs.cpp c:usrs.cpp@37:21@N@foo@N@taz@F@add#I#I# Extent=[37:21 - 37:56]
+// CHECK: usrs.cpp c:usrs.cpp@37:25@N@foo@N@taz@F@add#I#I#@a Extent=[37:25 - 37:30]
+// CHECK: usrs.cpp c:usrs.cpp@37:32@N@foo@N@taz@F@add#I#I#@b Extent=[37:32 - 37:37]
+// CHECK: usrs.cpp c:@N@foo@N@taz@F@sub#I#I# Extent=[38:8 - 38:25]
+// CHECK: usrs.cpp c:usrs.cpp@38:12@N@foo@N@taz@F@sub#I#I#@a Extent=[38:12 - 38:17]
+// CHECK: usrs.cpp c:usrs.cpp@38:19@N@foo@N@taz@F@sub#I#I#@b Extent=[38:19 - 38:24]
+// CHECK: usrs.cpp c:@N@foo Extent=[42:11 - 52:3]
+// CHECK: usrs.cpp c:@N@foo@N@taz Extent=[42:27 - 52:2]
+// CHECK: usrs.cpp c:@N@foo@N@taz@C@ClsD Extent=[43:3 - 51:4]
+// CHECK: usrs.cpp c:@N@foo@N@taz@C@ClsD@F@operator=#I# Extent=[45:11 - 45:52]
+// CHECK: usrs.cpp c:usrs.cpp@45:21@N@foo@N@taz@C@ClsD@F@operator=#I#@x Extent=[45:21 - 45:26]
+// CHECK: usrs.cpp c:@N@foo@N@taz@C@ClsD@F@operator=#d# Extent=[46:11 - 46:61]
+// CHECK: usrs.cpp c:usrs.cpp@46:21@N@foo@N@taz@C@ClsD@F@operator=#d#@x Extent=[46:21 - 46:29]
+// CHECK: usrs.cpp c:@N@foo@N@taz@C@ClsD@F@operator=#&1$@N@foo@N@taz@C@ClsD# Extent=[47:11 - 47:62]
+// CHECK: usrs.cpp c:usrs.cpp@47:27@N@foo@N@taz@C@ClsD@F@operator=#&1$@N@foo@N@taz@C@ClsD#@x Extent=[47:27 - 47:34]
+// CHECK: usrs.cpp c:@N@foo@N@taz@C@ClsD@F@qux#S Extent=[48:16 - 48:21]
+// CHECK: usrs.cpp c:@N@foo@N@taz@C@ClsD@F@uz#I.#S Extent=[49:16 - 49:30]
+// CHECK: usrs.cpp c:usrs.cpp@49:19@N@foo@N@taz@C@ClsD@F@uz#I.#S@z Extent=[49:19 - 49:24]
+// CHECK: usrs.cpp c:@N@foo@N@taz@C@ClsD@F@operator==#&1$@N@foo@N@taz@C@ClsD#1 Extent=[50:10 - 50:62]
+// CHECK: usrs.cpp c:usrs.cpp@50:27@N@foo@N@taz@C@ClsD@F@operator==#&1$@N@foo@N@taz@C@ClsD#1@x Extent=[50:27 - 50:34]
+// CHECK: usrs.cpp c:@F@rez Extent=[55:8 - 55:25]
+// CHECK: usrs.cpp c:usrs.cpp@55:12@F@rez@a Extent=[55:12 - 55:17]
+// CHECK: usrs.cpp c:usrs.cpp@55:19@F@rez@b Extent=[55:19 - 55:24]
+
diff --git a/test/Index/usrs.m b/test/Index/usrs.m
index eb0817c27c81..bffd0ee4bbc7 100644
--- a/test/Index/usrs.m
+++ b/test/Index/usrs.m
@@ -49,18 +49,18 @@ int z;
static int local_func(int x) { return x; }
// CHECK: usrs.m c:usrs.m@3:19@F@my_helper Extent=[3:19 - 3:60]
-// CHECK: usrs.m c:usrs.m@3:29@x Extent=[3:29 - 3:34]
-// CHECK: usrs.m c:usrs.m@3:36@y Extent=[3:36 - 3:41]
-// CHECK: usrs.m c:@Ea@usrs.m@5:1 Extent=[5:1 - 8:2]
-// CHECK: usrs.m c:@Ea@usrs.m@5:1@ABA Extent=[6:3 - 6:6]
-// CHECK: usrs.m c:@Ea@usrs.m@5:1@CADABA Extent=[7:3 - 7:9]
-// CHECK: usrs.m c:@Ea@usrs.m@10:1 Extent=[10:1 - 13:2]
-// CHECK: usrs.m c:@Ea@usrs.m@10:1@FOO Extent=[11:3 - 11:6]
-// CHECK: usrs.m c:@Ea@usrs.m@10:1@BAR Extent=[12:3 - 12:6]
+// CHECK: usrs.m c:usrs.m@3:29@F@my_helper@x Extent=[3:29 - 3:34]
+// CHECK: usrs.m c:usrs.m@3:36@F@my_helper@y Extent=[3:36 - 3:41]
+// CHECK: usrs.m c:usrs.m@5:1@Ea Extent=[5:1 - 8:2]
+// CHECK: usrs.m c:usrs.m@5:1@Ea@ABA Extent=[6:3 - 6:6]
+// CHECK: usrs.m c:usrs.m@5:1@Ea@CADABA Extent=[7:3 - 7:9]
+// CHECK: usrs.m c:usrs.m@10:1@Ea Extent=[10:1 - 13:2]
+// CHECK: usrs.m c:usrs.m@10:1@Ea@FOO Extent=[11:3 - 11:6]
+// CHECK: usrs.m c:usrs.m@10:1@Ea@BAR Extent=[12:3 - 12:6]
// CHECK: usrs.m c:@SA@MyStruct Extent=[15:9 - 18:2]
// CHECK: usrs.m c:@SA@MyStruct@FI@wa Extent=[16:7 - 16:9]
// CHECK: usrs.m c:@SA@MyStruct@FI@moo Extent=[17:7 - 17:10]
-// CHECK: usrs.m c:@T@usrs.m@18:3@MyStruct Extent=[18:3 - 18:11]
+// CHECK: usrs.m c:usrs.m@18:3@T@MyStruct Extent=[18:3 - 18:11]
// CHECK: usrs.m c:@E@Pizza Extent=[20:1 - 23:2]
// CHECK: usrs.m c:@E@Pizza@CHEESE Extent=[21:3 - 21:9]
// CHECK: usrs.m c:@E@Pizza@MUSHROOMS Extent=[22:3 - 22:12]
@@ -72,16 +72,16 @@ static int local_func(int x) { return x; }
// CHECK: usrs.m c:objc(cs)Foo(cm)kingkong Extent=[30:1 - 30:17]
// CHECK: usrs.m c:objc(cs)Foo(im)d1 Extent=[31:15 - 31:17]
// CHECK: usrs.m c:objc(cs)Foo(im)setD1: Extent=[31:15 - 31:17]
-// CHECK: usrs.m c:usrs.m@31:15@d1 Extent=[31:15 - 31:17]
+// CHECK: usrs.m c:usrs.m@31:15objc(cs)Foo(im)setD1:@d1 Extent=[31:15 - 31:17]
// CHECK: usrs.m c:objc(cs)Foo Extent=[34:1 - 45:2]
// CHECK: usrs.m c:objc(cs)Foo(im)godzilla Extent=[35:1 - 39:2]
-// CHECK: usrs.m c:usrs.m@36:10@a Extent=[36:10 - 36:19]
-// CHECK: usrs.m c:@z Extent=[37:10 - 37:15]
+// CHECK: usrs.m c:usrs.m@36:10objc(cs)Foo(im)godzilla@a Extent=[36:10 - 36:19]
+// CHECK: usrs.m c:objc(cs)Foo(im)godzilla@z Extent=[37:10 - 37:15]
// CHECK: usrs.m c:objc(cs)Foo(cm)kingkong Extent=[40:1 - 43:2]
-// CHECK: usrs.m c:usrs.m@41:3@local_var Extent=[41:3 - 41:16]
+// CHECK: usrs.m c:usrs.m@41:3objc(cs)Foo(cm)kingkong@local_var Extent=[41:3 - 41:16]
// CHECK: usrs.m c:objc(cs)Foo@d1 Extent=[44:13 - 44:15]
// CHECK: usrs.m c:objc(cs)Foo(py)d1 Extent=[44:1 - 44:15]
// CHECK: usrs.m c:@z Extent=[47:1 - 47:6]
// CHECK: usrs.m c:usrs.m@49:12@F@local_func Extent=[49:12 - 49:43]
-// CHECK: usrs.m c:usrs.m@49:23@x Extent=[49:23 - 49:28]
+// CHECK: usrs.m c:usrs.m@49:23@F@local_func@x Extent=[49:23 - 49:28]
diff --git a/test/Lexer/gnu_keywords.c b/test/Lexer/gnu_keywords.c
index 3234f58114a6..c4bd9b3e59d6 100644
--- a/test/Lexer/gnu_keywords.c
+++ b/test/Lexer/gnu_keywords.c
@@ -1,7 +1,7 @@
-// RUN: %clang -DGNU_KEYWORDS -std=gnu89 -fsyntax-only -verify %s
-// RUN: %clang -DGNU_KEYWORDS -std=c99 -fgnu-keywords -fsyntax-only -verify %s
-// RUN: %clang -std=c99 -fsyntax-only -verify %s
-// RUN: %clang -std=gnu89 -fno-gnu-keywords -fsyntax-only -verify %s
+// RUN: %clang_cc1 -DGNU_KEYWORDS -std=gnu89 -fsyntax-only -verify %s
+// RUN: %clang_cc1 -DGNU_KEYWORDS -std=c99 -fgnu-keywords -fsyntax-only -verify %s
+// RUN: %clang_cc1 -std=c99 -fsyntax-only -verify %s
+// RUN: %clang_cc1 -std=gnu89 -fno-gnu-keywords -fsyntax-only -verify %s
void f() {
#ifdef GNU_KEYWORDS
diff --git a/test/Lexer/hexfloat.cpp b/test/Lexer/hexfloat.cpp
index 5a62556ff616..a3b230e78f16 100644
--- a/test/Lexer/hexfloat.cpp
+++ b/test/Lexer/hexfloat.cpp
@@ -1,5 +1,5 @@
-//RUN: %clang_cc1 -fsyntax-only -verify
-//RUN: %clang_cc1 -std=c++0x -fsyntax-only -verify
+// RUN: %clang_cc1 -fsyntax-only -verify -pedantic
+// RUN: %clang_cc1 -std=c++0x -fsyntax-only -verify
#ifndef __GXX_EXPERIMENTAL_CXX0X__
float f = 0x1p+1; // expected-warning {{incompatible with C++0x}}
diff --git a/test/Makefile b/test/Makefile
index e9d89454b898..c3b3eab58945 100644
--- a/test/Makefile
+++ b/test/Makefile
@@ -18,7 +18,7 @@ ifndef TESTARGS
ifdef VERBOSE
TESTARGS = -v
else
-TESTARGS = -s -v
+TESTARGS = -s -v
endif
endif
diff --git a/test/Misc/diag-aka-types.cpp b/test/Misc/diag-aka-types.cpp
new file mode 100644
index 000000000000..7233c4e85b49
--- /dev/null
+++ b/test/Misc/diag-aka-types.cpp
@@ -0,0 +1,10 @@
+// RUN: %clang_cc1 %s -fsyntax-only -verify
+
+struct X {};
+typedef X foo_t;
+
+foo_t *ptr;
+char c1 = ptr; // expected-error{{'foo_t *' (aka 'X *')}}
+
+const foo_t &ref = foo_t();
+char c2 = ref; // expected-error{{'foo_t const' (aka 'X const')}}
diff --git a/test/PCH/Inputs/namespaces.h b/test/PCH/Inputs/namespaces.h
index 1bab7463fbbb..553aadd1f9ed 100644
--- a/test/PCH/Inputs/namespaces.h
+++ b/test/PCH/Inputs/namespaces.h
@@ -6,8 +6,35 @@ namespace N1 {
namespace N1 {
typedef int t2;
+
+ void used_func();
+
+ struct used_cls { };
}
namespace N2 {
typedef float t1;
+
+ namespace Inner {
+ typedef int t3;
+ };
+}
+
+namespace {
+ void anon() { }
+ class C;
+}
+
+namespace N3 {
+ namespace {
+ class C;
+ }
+}
+
+namespace Alias1 = N2::Inner;
+
+using namespace N2::Inner;
+
+extern "C" {
+ void ext();
}
diff --git a/test/PCH/cxx_exprs.cpp b/test/PCH/cxx_exprs.cpp
index 0f0fe88dc54a..ec7041b9843a 100644
--- a/test/PCH/cxx_exprs.cpp
+++ b/test/PCH/cxx_exprs.cpp
@@ -33,3 +33,7 @@ static_assert(!false_value, "false_value is false");
// CXXNullPtrLiteralExpr
cxx_null_ptr_result null_ptr = nullptr;
+
+// CXXTypeidExpr
+typeid_result1 typeid_1 = 0;
+typeid_result2 typeid_2 = 0; \ No newline at end of file
diff --git a/test/PCH/cxx_exprs.h b/test/PCH/cxx_exprs.h
index a871aa201f12..f64792238991 100644
--- a/test/PCH/cxx_exprs.h
+++ b/test/PCH/cxx_exprs.h
@@ -1,11 +1,12 @@
// Header for PCH test cxx_exprs.cpp
+
// CXXStaticCastExpr
typedef __typeof__(static_cast<void *>(0)) static_cast_result;
// CXXDynamicCastExpr
-struct Base { virtual void f(); };
-struct Derived : Base { };
+struct Base { Base(int); virtual void f(int x = 492); ~Base(); };
+struct Derived : Base { Derived(); void g(); };
Base *base_ptr;
typedef __typeof__(dynamic_cast<Derived *>(base_ptr)) dynamic_cast_result;
@@ -27,3 +28,56 @@ const bool false_value = false;
// CXXNullPtrLiteralExpr
typedef __typeof__(nullptr) cxx_null_ptr_result;
+
+void foo(Derived *P) {
+ // CXXMemberCallExpr
+ P->f(12);
+}
+
+
+// FIXME: This is a hack until <typeinfo> works completely.
+namespace std {
+ class type_info {};
+}
+
+// CXXTypeidExpr - Both expr and type forms.
+typedef __typeof__(typeid(int))* typeid_result1;
+typedef __typeof__(typeid(2))* typeid_result2;
+
+Derived foo();
+
+Derived::Derived() : Base(4) {
+}
+
+void Derived::g() {
+ // CXXThisExpr
+ f(2); // Implicit
+ this->f(1); // Explicit
+
+ // CXXThrowExpr
+ throw;
+ throw 42;
+
+ // CXXDefaultArgExpr
+ f();
+
+ const Derived &X = foo();
+
+ // FIXME: How do I make a CXXBindReferenceExpr, CXXConstructExpr?
+
+ int A = int(0.5); // CXXFunctionalCastExpr
+ A = int(); // CXXZeroInitValueExpr
+
+ new Base(4); // CXXNewExpr
+
+}
+
+
+// FIXME: The comment on CXXTemporaryObjectExpr is broken, this doesn't make
+// one.
+struct CtorStruct { CtorStruct(int, float); };
+
+CtorStruct create_CtorStruct() {
+ return CtorStruct(1, 3.14f); // CXXTemporaryObjectExpr
+};
+
diff --git a/test/PCH/namespaces.cpp b/test/PCH/namespaces.cpp
index eef9e06e5462..532d627fadcf 100644
--- a/test/PCH/namespaces.cpp
+++ b/test/PCH/namespaces.cpp
@@ -8,7 +8,36 @@
int int_val;
N1::t1 *ip1 = &int_val;
N1::t2 *ip2 = &int_val;
+N2::Inner::t3 *ip3 = &int_val;
float float_val;
namespace N2 { }
N2::t1 *fp1 = &float_val;
+
+Alias1::t3 *ip4 = &int_val;
+t3 *ip5 = &int_val;
+
+void(*funp1)() = anon;
+
+namespace {
+ class C;
+}
+C* cp1;
+
+namespace N3 {
+ namespace {
+ class C;
+ }
+}
+
+N3::C *cp2;
+
+void(*funp2)() = ext;
+
+using N1::used_func;
+void (*pused)() = used_func;
+
+// FIXME: Disabled until CXXRecord serialization is re-added.
+// using N1::used_cls;
+// used_cls s1;
+// used_cls* ps1 = &s1;
diff --git a/test/Parser/cxx-undeclared-identifier.cpp b/test/Parser/cxx-undeclared-identifier.cpp
new file mode 100644
index 000000000000..36d8f7a65381
--- /dev/null
+++ b/test/Parser/cxx-undeclared-identifier.cpp
@@ -0,0 +1,6 @@
+// RUN: %clang_cc1 -fsyntax-only -pedantic -verify %s
+
+class Foo::Bar { // expected-error {{use of undeclared identifier 'Foo'}} \
+ // expected-note {{to match this '{'}} \
+ // expected-error {{expected ';' after class}}
+ // expected-error {{expected '}'}}
diff --git a/test/Parser/namespaces.cpp b/test/Parser/namespaces.cpp
new file mode 100644
index 000000000000..b8c7819a019f
--- /dev/null
+++ b/test/Parser/namespaces.cpp
@@ -0,0 +1,8 @@
+// RUN: %clang_cc1 -fsyntax-only -verify %s
+
+// PR6596
+namespace g { enum { o = 0 }; }
+
+void foo() {
+ namespace a { typedef g::o o; } // expected-error{{namespaces can only be defined in global or namespace scope}}
+}
diff --git a/test/Parser/pragma-options.c b/test/Parser/pragma-options.c
new file mode 100644
index 000000000000..332249fdcfe3
--- /dev/null
+++ b/test/Parser/pragma-options.c
@@ -0,0 +1,12 @@
+// RUN: %clang_cc1 -triple i386-apple-darwin9 -fsyntax-only -verify %s
+
+/* expected-warning {{expected 'align' following '#pragma options'}} */ #pragma options
+/* expected-warning {{expected '=' following '#pragma options align'}} */ #pragma options align
+/* expected-warning {{expected identifier in '#pragma options'}} */ #pragma options align =
+/* expected-warning {{invalid alignment option in '#pragma options align'}} */ #pragma options align = foo
+/* expected-warning {{extra tokens at end of '#pragma options'}} */ #pragma options align = reset foo
+
+#pragma options align=natural
+#pragma options align=reset
+#pragma options align=mac68k
+/* expected-warning {{unsupported alignment option}} */ #pragma options align=power
diff --git a/test/Parser/recovery.c b/test/Parser/recovery.c
index 8e7181e0ba05..6cd95da878d2 100644
--- a/test/Parser/recovery.c
+++ b/test/Parser/recovery.c
@@ -73,3 +73,8 @@ void foo() {
int X;
X = 4 // expected-error{{expected ';' after expression}}
}
+
+
+// rdar://7980651
+typedef int intptr_t; // expected-note {{'intptr_t' declared here}}
+void bar(intptr y); // expected-error {{unknown type name 'intptr'; did you mean 'intptr_t'?}}
diff --git a/test/Parser/switch-recovery.cpp b/test/Parser/switch-recovery.cpp
new file mode 100644
index 000000000000..8eb4cff4fbe1
--- /dev/null
+++ b/test/Parser/switch-recovery.cpp
@@ -0,0 +1,12 @@
+// RUN: %clang_cc1 -fsyntax-only -verify %s
+
+// <rdar://problem/7971948>
+struct A {};
+struct B {
+ void foo() {
+ switch (a) { // expected-error{{use of undeclared identifier 'a'}}
+ default:
+ return;
+ }
+ }
+};
diff --git a/test/Rewriter/rewrite-block-argument.m b/test/Rewriter/rewrite-block-argument.m
new file mode 100644
index 000000000000..4ebbef9abcbd
--- /dev/null
+++ b/test/Rewriter/rewrite-block-argument.m
@@ -0,0 +1,33 @@
+// RUN: %clang_cc1 -x objective-c -Wno-return-type -fblocks -fms-extensions -rewrite-objc %s -o %t-rw.cpp
+// RUN: %clang_cc1 -Wno-address-of-temporary -Did="void *" -D"SEL=void*" -D"__declspec(X)=" -emit-llvm -o %t %t-rw.cpp
+// radar 7987817
+
+void *sel_registerName(const char *);
+
+@interface Test {
+}
+@end
+
+@implementation Test
+
+- (void)enumerateProvidersWithBlock:(void (^)(void))block {
+ block();
+}
+
+- (void)providerEnumerator {
+ ^(void (^providerBlock)(void)) {
+ [self enumerateProvidersWithBlock:providerBlock];
+ };
+}
+
+- (void)testNilBlock {
+ [self enumerateProvidersWithBlock:0];
+}
+
+@end
+
+
+
+int main(int argc, char *argv[]) {
+ return 0;
+}
diff --git a/test/Rewriter/rewrite-local-static-id.mm b/test/Rewriter/rewrite-local-static-id.mm
new file mode 100644
index 000000000000..a0b85f4f4dfd
--- /dev/null
+++ b/test/Rewriter/rewrite-local-static-id.mm
@@ -0,0 +1,24 @@
+// RUN: %clang_cc1 -x objective-c++ -Wno-return-type -fblocks -fms-extensions -rewrite-objc %s -o %t-rw.cpp
+// RUN: %clang_cc1 -Wno-address-of-temporary -Did="void *" -D"SEL=void*" -D"__declspec(X)=" -emit-llvm -o %t %t-rw.cpp
+// radar 7946975
+
+void *sel_registerName(const char *);
+
+@interface foo
+@end
+
+@interface foo2 : foo
++ (id)x;
+@end
+
+typedef void (^b_t)(void);
+
+void bar(b_t block);
+
+void f() {
+ static id foo = 0;
+ bar(^{
+ foo = [foo2 x];
+ });
+}
+
diff --git a/test/Rewriter/rewrite-no-nextline.mm b/test/Rewriter/rewrite-no-nextline.mm
new file mode 100644
index 000000000000..0c3657c90678
--- /dev/null
+++ b/test/Rewriter/rewrite-no-nextline.mm
@@ -0,0 +1,10 @@
+// RUN: %clang_cc1 -x objective-c++ -Wno-return-type -fblocks -fms-extensions -rewrite-objc %s -o %t-rw.cpp
+// RUN: %clang_cc1 -fsyntax-only -Wno-address-of-temporary -D"SEL=void*" -D"__declspec(X)=" %t-rw.cpp
+// radar 7946975
+
+@interface RootObject {
+}
+@end void doStuff();
+int main(int argc, char *argv[]) {
+ return 0;
+}
diff --git a/test/Sema/attr-sentinel.c b/test/Sema/attr-sentinel.c
index db90d078b3f7..5ca6a8d00113 100644
--- a/test/Sema/attr-sentinel.c
+++ b/test/Sema/attr-sentinel.c
@@ -4,7 +4,7 @@
#define ATTR __attribute__ ((__sentinel__))
-void foo1 (int x, ...) ATTR; // expected-note {{function has been explicitly marked sentinel here}}
+void foo1 (int x, ...) ATTR; // expected-note 2 {{function has been explicitly marked sentinel here}}
void foo5 (int x, ...) __attribute__ ((__sentinel__(1))); // expected-note {{function has been explicitly marked sentinel here}}
void foo6 (int x, ...) __attribute__ ((__sentinel__(5))); // expected-note {{function has been explicitly marked sentinel here}}
void foo7 (int x, ...) __attribute__ ((__sentinel__(0))); // expected-note {{function has been explicitly marked sentinel here}}
@@ -24,6 +24,12 @@ void test1() {
foo7(1, NULL); // OK
foo12(1); // expected-warning {{not enough variable arguments in 'foo12' declaration to fit a sentinel}}
+
+ // PR 5685
+ struct A {};
+ struct A a, b, c;
+ foo1(3, &a, &b, &c); // expected-warning {{missing sentinel in function call}}
+ foo1(3, &a, &b, &c, (struct A*) 0);
}
diff --git a/test/Sema/c89.c b/test/Sema/c89.c
index 8a9e622d8749..038f7e537d76 100644
--- a/test/Sema/c89.c
+++ b/test/Sema/c89.c
@@ -61,7 +61,7 @@ void foo(T); /* typedef for void is allowed */
void foo(void) {}
/* PR2759 */
-void test10 (int x[*]); /* expected-warning {{use of C99-specific array features}} */
+void test10 (int x[*]); /* expected-warning {{variable length arrays are a C99 feature, accepted as an extension}} */
void test11 (int x[static 4]); /* expected-warning {{use of C99-specific array features}} */
void test12 (int x[const 4]) { /* expected-warning {{use of C99-specific array features}} */
diff --git a/test/Sema/compare.c b/test/Sema/compare.c
index 631b69420293..f997dc1a73bf 100644
--- a/test/Sema/compare.c
+++ b/test/Sema/compare.c
@@ -23,8 +23,8 @@ int ints(long a, unsigned long b) {
((signed char) a == b) + // expected-warning {{comparison of integers of different signs}}
((long) a == (unsigned long) b) + // expected-warning {{comparison of integers of different signs}}
((int) a == (unsigned int) b) + // expected-warning {{comparison of integers of different signs}}
- ((short) a == (unsigned short) b) + // expected-warning {{comparison of integers of different signs}}
- ((signed char) a == (unsigned char) b) + // expected-warning {{comparison of integers of different signs}}
+ ((short) a == (unsigned short) b) +
+ ((signed char) a == (unsigned char) b) +
(a < (unsigned long) b) + // expected-warning {{comparison of integers of different signs}}
(a < (unsigned int) b) +
(a < (unsigned short) b) +
@@ -35,8 +35,8 @@ int ints(long a, unsigned long b) {
((signed char) a < b) + // expected-warning {{comparison of integers of different signs}}
((long) a < (unsigned long) b) + // expected-warning {{comparison of integers of different signs}}
((int) a < (unsigned int) b) + // expected-warning {{comparison of integers of different signs}}
- ((short) a < (unsigned short) b) + // expected-warning {{comparison of integers of different signs}}
- ((signed char) a < (unsigned char) b) + // expected-warning {{comparison of integers of different signs}}
+ ((short) a < (unsigned short) b) +
+ ((signed char) a < (unsigned char) b) +
// (A,b)
(A == (unsigned long) b) +
@@ -87,8 +87,8 @@ int ints(long a, unsigned long b) {
((signed char) a < B) +
((long) a < (unsigned long) B) + // expected-warning {{comparison of integers of different signs}}
((int) a < (unsigned int) B) + // expected-warning {{comparison of integers of different signs}}
- ((short) a < (unsigned short) B) + // expected-warning {{comparison of integers of different signs}}
- ((signed char) a < (unsigned char) B) + // expected-warning {{comparison of integers of different signs}}
+ ((short) a < (unsigned short) B) +
+ ((signed char) a < (unsigned char) B) +
// (C,b)
(C == (unsigned long) b) +
@@ -139,8 +139,8 @@ int ints(long a, unsigned long b) {
((signed char) a < C) +
((long) a < (unsigned long) C) + // expected-warning {{comparison of integers of different signs}}
((int) a < (unsigned int) C) + // expected-warning {{comparison of integers of different signs}}
- ((short) a < (unsigned short) C) + // expected-warning {{comparison of integers of different signs}}
- ((signed char) a < (unsigned char) C) + // expected-warning {{comparison of integers of different signs}}
+ ((short) a < (unsigned short) C) +
+ ((signed char) a < (unsigned char) C) +
// (0x80000,b)
(0x80000 == (unsigned long) b) +
@@ -191,8 +191,8 @@ int ints(long a, unsigned long b) {
((signed char) a < 0x80000) +
((long) a < (unsigned long) 0x80000) + // expected-warning {{comparison of integers of different signs}}
((int) a < (unsigned int) 0x80000) + // expected-warning {{comparison of integers of different signs}}
- ((short) a < (unsigned short) 0x80000) + // expected-warning {{comparison of integers of different signs}}
- ((signed char) a < (unsigned char) 0x80000) + // expected-warning {{comparison of integers of different signs}}
+ ((short) a < (unsigned short) 0x80000) +
+ ((signed char) a < (unsigned char) 0x80000) +
// We should be able to avoid warning about this.
(b != (a < 4 ? 1 : 2)) +
diff --git a/test/Sema/conditional-expr.c b/test/Sema/conditional-expr.c
index 5e2c1a46248a..6e248bc3cfec 100644
--- a/test/Sema/conditional-expr.c
+++ b/test/Sema/conditional-expr.c
@@ -52,7 +52,9 @@ void foo() {
enum Enum { EVal };
test0 = test0 ? EVal : test0;
test0 = test0 ? EVal : (int) test0; // okay: EVal is an int
- test0 = test0 ? (unsigned) EVal : (int) test0; // expected-warning {{operands of ? are integers of different signs}}
+ test0 = test0 ? // expected-warning {{operands of ? are integers of different signs}}
+ (unsigned) EVal
+ : (int) test0;
}
int Postgresql() {
@@ -68,3 +70,8 @@ int f0(int a) {
// GCC considers this a warning.
return a ? f1() : nil; // expected-warning {{pointer/integer type mismatch in conditional expression ('int' and 'void *')}} expected-warning {{incompatible pointer to integer conversion returning 'void *' from a function with result type 'int'}}
}
+
+int f2(int x) {
+ // We can suppress this because the immediate context wants an int.
+ return (x != 0) ? 0U : x;
+}
diff --git a/test/Sema/conversion.c b/test/Sema/conversion.c
index addedd91f7e8..5b09ec6d9708 100644
--- a/test/Sema/conversion.c
+++ b/test/Sema/conversion.c
@@ -287,3 +287,13 @@ void test_7676608(void) {
char c = 5;
f7676608(c *= q);
}
+
+// <rdar://problem/7904686>
+void test_7904686(void) {
+ const int i = -1;
+ unsigned u1 = i; // expected-warning {{implicit cast changes signedness}}
+ u1 = i; // expected-warning {{implicit cast changes signedness}}
+
+ unsigned u2 = -1; // expected-warning {{implicit cast changes signedness}}
+ u2 = -1; // expected-warning {{implicit cast changes signedness}}
+}
diff --git a/test/Sema/format-strings.c b/test/Sema/format-strings.c
index bdc2bb0c9abe..d6d37961d922 100644
--- a/test/Sema/format-strings.c
+++ b/test/Sema/format-strings.c
@@ -251,3 +251,6 @@ void test_pr_6697() {
myprintf_PR_6697("%1$s\n", 1, (int) 0); // expected-warning{{conversion specifies type 'char *' but the argument has type 'int'}}
}
+void rdar8026030(FILE *fp) {
+ fprintf(fp, "\%"); // expected-warning{{incomplete format specifier}}
+}
diff --git a/test/Sema/init.c b/test/Sema/init.c
index b9867cf5027b..c2c29ad9b04b 100644
--- a/test/Sema/init.c
+++ b/test/Sema/init.c
@@ -131,3 +131,17 @@ const wchar_t widestr[] = L"asdf";
// PR5447
const double pr5447 = (0.05 < -1.0) ? -1.0 : 0.0499878;
+// PR4386
+
+// None of these are constant initializers, but we implement GCC's old
+// behaviour of accepting bar and zed but not foo. GCC's behaviour was
+// changed in 2007 (rev 122551), so we should be able to change too one
+// day.
+int PR4386_bar();
+int PR4386_foo() __attribute((weak));
+int PR4386_zed();
+
+int PR4386_a = ((void *) PR4386_bar) != 0;
+int PR4386_b = ((void *) PR4386_foo) != 0; // expected-error{{initializer element is not a compile-time constant}}
+int PR4386_c = ((void *) PR4386_zed) != 0;
+int PR4386_zed() __attribute((weak));
diff --git a/test/Sema/pragma-align-mac68k-unsupported.c b/test/Sema/pragma-align-mac68k-unsupported.c
new file mode 100644
index 000000000000..6588aa17a15e
--- /dev/null
+++ b/test/Sema/pragma-align-mac68k-unsupported.c
@@ -0,0 +1,4 @@
+// RUN: %clang-cc1 -triple x86_64-apple-darwin10 -fsyntax-only -verify %s
+// RUN: %clang-cc1 -triple i386-pc-linux-gnu -fsyntax-only -verify %s
+
+/* expected-error {{mac68k alignment pragma is not supported}} */ #pragma options align=mac68k
diff --git a/test/Sema/pragma-align-mac68k.c b/test/Sema/pragma-align-mac68k.c
new file mode 100644
index 000000000000..d13a0bebb767
--- /dev/null
+++ b/test/Sema/pragma-align-mac68k.c
@@ -0,0 +1,98 @@
+// RUN: %clang-cc1 -triple i386-apple-darwin9 -fsyntax-only -verify %s
+
+#include <stddef.h>
+
+#pragma options align=mac68k
+
+typedef float __attribute__((vector_size (8))) v2f_t;
+typedef float __attribute__((vector_size (16))) v4f_t;
+
+extern int a0_0[__alignof(v2f_t) == 8 ? 1 : -1];
+extern int a0_1[__alignof(v4f_t) == 16 ? 1 : -1];
+
+struct s1 {
+ char f0;
+ int f1;
+};
+extern int a1_0[offsetof(struct s1, f0) == 0 ? 1 : -1];
+extern int a1_1[offsetof(struct s1, f1) == 2 ? 1 : -1];
+extern int a1_2[sizeof(struct s1) == 6 ? 1 : -1];
+extern int a1_3[__alignof(struct s1) == 2 ? 1 : -1];
+
+struct s2 {
+ char f0;
+ double f1;
+};
+extern int a2_0[offsetof(struct s2, f0) == 0 ? 1 : -1];
+extern int a2_1[offsetof(struct s2, f1) == 2 ? 1 : -1];
+extern int a2_2[sizeof(struct s2) == 10 ? 1 : -1];
+extern int a2_3[__alignof(struct s2) == 2 ? 1 : -1];
+
+struct s3 {
+ char f0;
+ v4f_t f1;
+};
+extern int a3_0[offsetof(struct s3, f0) == 0 ? 1 : -1];
+extern int a3_1[offsetof(struct s3, f1) == 2 ? 1 : -1];
+extern int a3_2[sizeof(struct s3) == 18 ? 1 : -1];
+extern int a3_3[__alignof(struct s3) == 2 ? 1 : -1];
+
+struct s4 {
+ char f0;
+ char f1;
+};
+extern int a4_0[offsetof(struct s4, f0) == 0 ? 1 : -1];
+extern int a4_1[offsetof(struct s4, f1) == 1 ? 1 : -1];
+extern int a4_2[sizeof(struct s4) == 2 ? 1 : -1];
+extern int a4_3[__alignof(struct s4) == 2 ? 1 : -1];
+
+struct s5 {
+ unsigned f0 : 9;
+ unsigned f1 : 9;
+};
+extern int a5_0[sizeof(struct s5) == 4 ? 1 : -1];
+extern int a5_1[__alignof(struct s5) == 2 ? 1 : -1];
+
+struct s6 {
+ unsigned : 0;
+ unsigned : 0;
+};
+extern int a6_0[sizeof(struct s6) == 0 ? 1 : -1];
+extern int a6_1[__alignof(struct s6) == 2 ? 1 : -1];
+
+struct s7 {
+ char : 1;
+ unsigned : 1;
+};
+extern int a7_0[sizeof(struct s7) == 2 ? 1 : -1];
+extern int a7_1[__alignof(struct s7) == 2 ? 1 : -1];
+
+struct s8 {
+ char f0;
+ unsigned : 1;
+};
+extern int a8_0[sizeof(struct s8) == 2 ? 1 : -1];
+extern int a8_1[__alignof(struct s8) == 2 ? 1 : -1];
+
+struct s9 {
+ char f0[3];
+ unsigned : 0;
+ char f1;
+};
+extern int a9_0[sizeof(struct s9) == 6 ? 1 : -1];
+extern int a9_1[__alignof(struct s9) == 2 ? 1 : -1];
+
+struct s10 {
+ char f0;
+};
+extern int a10_0[sizeof(struct s10) == 2 ? 1 : -1];
+extern int a10_1[__alignof(struct s10) == 2 ? 1 : -1];
+
+struct s11 {
+ char f0;
+ v2f_t f1;
+};
+extern int a11_0[offsetof(struct s11, f0) == 0 ? 1 : -1];
+extern int a11_1[offsetof(struct s11, f1) == 2 ? 1 : -1];
+extern int a11_2[sizeof(struct s11) == 10 ? 1 : -1];
+extern int a11_3[__alignof(struct s11) == 2 ? 1 : -1];
diff --git a/test/Sema/pragma-pack-and-options-align.c b/test/Sema/pragma-pack-and-options-align.c
new file mode 100644
index 000000000000..c880ed6305b4
--- /dev/null
+++ b/test/Sema/pragma-pack-and-options-align.c
@@ -0,0 +1,34 @@
+// RUN: %clang_cc1 -triple i686-apple-darwin9 %s -fsyntax-only -verify
+
+// Check that #pragma pack and #pragma options share the same stack.
+
+#pragma pack(push, 1)
+struct s0 {
+ char c;
+ int x;
+};
+extern int a[sizeof(struct s0) == 5 ? 1 : -1];
+
+#pragma options align=natural
+struct s1 {
+ char c;
+ int x;
+};
+extern int a[sizeof(struct s1) == 8 ? 1 : -1];
+
+#pragma pack(pop)
+struct s2 {
+ char c;
+ int x;
+};
+extern int a[sizeof(struct s2) == 5 ? 1 : -1];
+#pragma pack(pop)
+
+struct s3 {
+ char c;
+ int x;
+};
+extern int a[sizeof(struct s3) == 8 ? 1 : -1];
+
+/* expected-warning {{#pragma options align=reset failed: stack empty}} */ #pragma options align=reset
+/* expected-warning {{#pragma pack(pop, ...) failed: stack empty}} */ #pragma pack(pop)
diff --git a/test/Sema/scope-check.c b/test/Sema/scope-check.c
index 6f8640255a9e..f3881ed086ac 100644
--- a/test/Sema/scope-check.c
+++ b/test/Sema/scope-check.c
@@ -19,7 +19,7 @@ void test3clean(int*);
int test3() {
goto L; // expected-error{{illegal goto into protected scope}}
-int a __attribute((cleanup(test3clean))); // expected-note {{jump bypasses initialization of declaration with __attribute__((cleanup))}}
+int a __attribute((cleanup(test3clean))); // expected-note {{jump bypasses initialization of variable with __attribute__((cleanup))}}
L:
return a;
}
@@ -133,20 +133,20 @@ int test8(int x) {
void test9(int n, void *P) {
int Y;
int Z = 4;
- goto *P; // ok.
+ goto *P; // expected-warning {{indirect goto might cross protected scopes}}
L2: ;
- int a[n]; // expected-note 2 {{jump bypasses initialization of variable length array}}
+ int a[n]; // expected-note {{jump bypasses initialization of variable length array}}
-L3:
+L3: // expected-note {{possible target of indirect goto}}
L4:
- goto *P; // expected-warning {{illegal indirect goto in protected scope, unknown effect on scopes}}
+ goto *P;
goto L3; // ok
goto L4; // ok
void *Ptrs[] = {
- &&L2, // Ok.
- &&L3 // expected-warning {{address taken of label in protected scope, jump to it would have unknown effect on scope}}
+ &&L2,
+ &&L3
};
}
@@ -193,3 +193,9 @@ void test12(int n) {
};
}
+void test13(int n, void *p) {
+ int vla[n];
+ goto *p;
+ a0: ;
+ static void *ps[] = { &&a0 };
+}
diff --git a/test/Sema/switch.c b/test/Sema/switch.c
index e63a1942bba5..27ad06657e26 100644
--- a/test/Sema/switch.c
+++ b/test/Sema/switch.c
@@ -24,36 +24,37 @@ void foo(int X) {
void test3(void) {
// empty switch;
- switch (0);
+ switch (0); // expected-warning {{no case matching constant switch condition '0'}}
}
extern int g();
void test4()
{
- switch (1) {
+ int cond;
+ switch (cond) {
case 0 && g():
case 1 || g():
break;
}
- switch(1) {
+ switch(cond) {
case g(): // expected-error {{expression is not an integer constant expression}}
case 0 ... g(): // expected-error {{expression is not an integer constant expression}}
break;
}
- switch (1) {
+ switch (cond) {
case 0 && g() ... 1 || g():
break;
}
- switch (1) {
+ switch (cond) {
case g() && 0: // expected-error {{expression is not an integer constant expression}} // expected-note {{subexpression not valid in an integer constant expression}}
break;
}
- switch (1) {
+ switch (cond) {
case 0 ... g() || 1: // expected-error {{expression is not an integer constant expression}} // expected-note {{subexpression not valid in an integer constant expression}}
break;
}
@@ -68,7 +69,7 @@ void test5(int z) {
}
void test6() {
- const char ch = 'a';
+ char ch = 'a';
switch(ch) {
case 1234: // expected-warning {{overflow converting case value}}
break;
@@ -261,3 +262,18 @@ void f1(unsigned x) {
default: break;
}
}
+
+void test15() {
+ int i = 0;
+ switch (1) { // expected-warning {{no case matching constant switch condition '1'}}
+ case 0: i = 0; break;
+ case 2: i++; break;
+ }
+}
+
+void test16() {
+ const char c = '5';
+ switch (c) { // expected-warning {{no case matching constant switch condition '53'}}
+ case '6': return;
+ }
+}
diff --git a/test/Sema/unused-expr.c b/test/Sema/unused-expr.c
index 4ae0d4b46504..15608ec8a4be 100644
--- a/test/Sema/unused-expr.c
+++ b/test/Sema/unused-expr.c
@@ -110,3 +110,11 @@ void *some_function(void);
void t10() {
(void*) some_function(); //expected-warning {{expression result unused; should this cast be to 'void'?}}
}
+
+void f(int i, ...) {
+ __builtin_va_list ap;
+
+ __builtin_va_start(ap, i);
+ __builtin_va_arg(ap, int);
+ __builtin_va_end(ap);
+}
diff --git a/test/SemaCXX/alignof-sizeof-reference.cpp b/test/SemaCXX/alignof-sizeof-reference.cpp
index f02282d72d30..dd64d6a23ae3 100644
--- a/test/SemaCXX/alignof-sizeof-reference.cpp
+++ b/test/SemaCXX/alignof-sizeof-reference.cpp
@@ -7,3 +7,9 @@ void test() {
static_assert(alignof(r) == 1, "bad alignment");
static_assert(sizeof(r) == 1, "bad size");
}
+
+void f();
+void f(int);
+void g() {
+ sizeof(&f); // expected-error{{invalid application of 'sizeof' to an overloaded function}}
+}
diff --git a/test/SemaCXX/anonymous-union.cpp b/test/SemaCXX/anonymous-union.cpp
index 5c34e016e57d..5f84bcca28db 100644
--- a/test/SemaCXX/anonymous-union.cpp
+++ b/test/SemaCXX/anonymous-union.cpp
@@ -121,3 +121,37 @@ typedef struct _s {
int Foo;
};
} s, *ps;
+
+// <rdar://problem/7987650>
+namespace test4 {
+ class A {
+ struct {
+ int s0; // expected-note {{declared private here}}
+ double s1; // expected-note {{declared private here}}
+ union {
+ int su0; // expected-note {{declared private here}}
+ double su1; // expected-note {{declared private here}}
+ };
+ };
+ union {
+ int u0; // expected-note {{declared private here}}
+ double u1; // expected-note {{declared private here}}
+ struct {
+ int us0; // expected-note {{declared private here}}
+ double us1; // expected-note {{declared private here}}
+ };
+ };
+ };
+
+ void test() {
+ A a;
+ (void) a.s0; // expected-error {{private member}}
+ (void) a.s1; // expected-error {{private member}}
+ (void) a.su0; // expected-error {{private member}}
+ (void) a.su1; // expected-error {{private member}}
+ (void) a.u0; // expected-error {{private member}}
+ (void) a.u1; // expected-error {{private member}}
+ (void) a.us0; // expected-error {{private member}}
+ (void) a.us1; // expected-error {{private member}}
+ }
+}
diff --git a/test/SemaCXX/attr-deprecated.cpp b/test/SemaCXX/attr-deprecated.cpp
index d5662d3f6313..2164f9dd17f2 100644
--- a/test/SemaCXX/attr-deprecated.cpp
+++ b/test/SemaCXX/attr-deprecated.cpp
@@ -64,3 +64,129 @@ void D::f() { }
void f(D* d) {
d->f();
}
+
+
+// Overloaded namespace members.
+namespace test1 {
+ void foo(int) __attribute__((deprecated));
+ void test1() { foo(10); } // expected-warning {{deprecated}}
+ void foo(short) __attribute__((deprecated));
+ void test2(short s) { foo(s); } // expected-warning {{deprecated}}
+ void foo(long);
+ void test3(long l) { foo(l); }
+ struct A {
+ friend void foo(A*) __attribute__((deprecated));
+ };
+ void test4(A *a) { foo(a); } // expected-warning {{deprecated}}
+
+ namespace ns {
+ struct Foo {};
+ void foo(const Foo &f) __attribute__((deprecated));
+ }
+ void test5() {
+ foo(ns::Foo()); // expected-warning {{deprecated}}
+ }
+}
+
+// Overloaded class members.
+namespace test2 {
+ struct A {
+ void foo(int) __attribute__((deprecated));
+ void foo(long);
+ static void bar(int) __attribute__((deprecated));
+ static void bar(long);
+
+ void test2(int i, long l);
+ };
+ void test1(int i, long l) {
+ A a;
+ a.foo(i); // expected-warning {{deprecated}}
+ a.foo(l);
+ a.bar(i); // expected-warning {{deprecated}}
+ a.bar(l);
+ A::bar(i); // expected-warning {{deprecated}}
+ A::bar(l);
+ }
+
+ void A::test2(int i, long l) {
+ foo(i); // expected-warning {{deprecated}}
+ foo(l);
+ bar(i); // expected-warning {{deprecated}}
+ bar(l);
+ }
+}
+
+// Overloaded operators.
+namespace test3 {
+ struct A {
+ void operator*(const A &);
+ void operator*(int) __attribute__((deprecated));
+ void operator-(const A &) const;
+ };
+ void operator+(const A &, const A &);
+ void operator+(const A &, int) __attribute__((deprecated));
+ void operator-(const A &, int) __attribute__((deprecated));
+
+ void test() {
+ A a, b;
+ a + b;
+ a + 1; // expected-warning {{deprecated}}
+ a - b;
+ a - 1; // expected-warning {{deprecated}}
+ a * b;
+ a * 1; // expected-warning {{deprecated}}
+ }
+}
+
+// Overloaded operator call.
+namespace test4 {
+ struct A {
+ typedef void (*intfn)(int);
+ typedef void (*unintfn)(unsigned);
+ operator intfn() __attribute__((deprecated));
+ operator unintfn();
+ void operator ()(A &) __attribute__((deprecated));
+ void operator ()(const A &);
+ };
+
+ void test() {
+ A a;
+ a(1); // expected-warning {{deprecated}}
+ a(1U);
+
+ A &b = a;
+ const A &c = a;
+ a(b); // expected-warning {{deprecated}}
+ a(c);
+ }
+}
+
+namespace test5 {
+ struct A {
+ operator int() __attribute__((deprecated));
+ operator long();
+ };
+ void test1(A a) {
+ int i = a; // expected-warning {{deprecated}}
+ long l = a;
+ }
+
+ void foo(int);
+ void foo(void*);
+ void bar(long);
+ void bar(void*);
+ void test2(A a) {
+ foo(a); // expected-warning {{deprecated}}
+ bar(a);
+ }
+
+ struct B {
+ int myInt;
+ long myLong;
+
+ B(A &a) :
+ myInt(a), // expected-warning {{deprecated}}
+ myLong(a)
+ {}
+ };
+}
diff --git a/test/SemaCXX/blocks.cpp b/test/SemaCXX/blocks.cpp
index 94295437e161..baa79e7d8971 100644
--- a/test/SemaCXX/blocks.cpp
+++ b/test/SemaCXX/blocks.cpp
@@ -9,3 +9,35 @@ void tovoid_test(int (^f)(int, int)) {
void reference_lvalue_test(int& (^f)()) {
f() = 10;
}
+
+// PR 7165
+namespace test1 {
+ void g(void (^)());
+ struct Foo {
+ void foo();
+ void test() {
+ (void) ^{ foo(); };
+ }
+ };
+}
+
+namespace test2 {
+ int repeat(int value, int (^block)(int), unsigned n) {
+ while (n--) value = block(value);
+ return value;
+ }
+
+ class Power {
+ int base;
+
+ public:
+ Power(int base) : base(base) {}
+ int calculate(unsigned n) {
+ return repeat(1, ^(int v) { return v * base; }, n);
+ }
+ };
+
+ int test() {
+ return Power(2).calculate(10);
+ }
+}
diff --git a/test/SemaCXX/c99-variable-length-array.cpp b/test/SemaCXX/c99-variable-length-array.cpp
new file mode 100644
index 000000000000..7dc912a0d5f6
--- /dev/null
+++ b/test/SemaCXX/c99-variable-length-array.cpp
@@ -0,0 +1,116 @@
+// RUN: %clang_cc1 -fsyntax-only -verify -Wvla %s
+struct NonPOD {
+ NonPOD();
+};
+
+struct NonPOD2 {
+ NonPOD np;
+};
+
+struct POD {
+ int x;
+ int y;
+};
+
+// We allow VLAs of POD types, only.
+void vla(int N) {
+ int array1[N]; // expected-warning{{variable length arrays are a C99 feature, accepted as an extension}}
+ POD array2[N]; // expected-warning{{variable length arrays are a C99 feature, accepted as an extension}}
+ NonPOD array3[N]; // expected-error{{variable length array of non-POD element type 'NonPOD'}}
+ NonPOD2 array4[N][3]; // expected-error{{variable length array of non-POD element type 'NonPOD2'}}
+}
+
+/// Warn about VLAs in templates.
+template<typename T>
+void vla_in_template(int N, T t) {
+ int array1[N]; // expected-warning{{variable length arrays are a C99 feature, accepted as an extension}}
+}
+
+struct HasConstantValue {
+ static const unsigned int value = 2;
+};
+
+struct HasNonConstantValue {
+ static unsigned int value;
+};
+
+template<typename T>
+void vla_in_template(T t) {
+ int array2[T::value]; // expected-warning{{variable length arrays are a C99 feature, accepted as an extension}}
+}
+
+template void vla_in_template<HasConstantValue>(HasConstantValue);
+template void vla_in_template<HasNonConstantValue>(HasNonConstantValue); // expected-note{{instantiation of}}
+
+template<typename T> struct X0 { };
+
+// Cannot use any variably-modified type with a template parameter or
+// argument.
+void inst_with_vla(int N) {
+ int array[N]; // expected-warning{{variable length arrays are a C99 feature, accepted as an extension}}
+ X0<__typeof__(array)> x0a; // expected-error{{variably modified type 'typeof (array)' (aka 'int [N]') cannot be used as a template argument}}
+}
+
+template<typename T>
+struct X1 {
+ template<int (&Array)[T::value]> // expected-error{{non-type template parameter of variably modified type 'int (&)[HasNonConstantValue::value]'}} \
+ // expected-warning{{variable length arrays are a C99 feature, accepted as an extension}}
+ struct Inner {
+
+ };
+};
+
+X1<HasConstantValue> x1a;
+X1<HasNonConstantValue> x1b; // expected-note{{in instantiation of}}
+
+// Template argument deduction does not allow deducing a size from a VLA.
+template<typename T, unsigned N>
+void accept_array(T (&array)[N]); // expected-note{{candidate template ignored: failed template argument deduction}}
+
+void test_accept_array(int N) {
+ int array[N]; // expected-warning{{variable length arrays are a C99 feature, accepted as an extension}}
+ accept_array(array); // expected-error{{no matching function for call to 'accept_array'}}
+}
+
+// Variably-modified types cannot be used in local classes.
+void local_classes(int N) {
+ struct X {
+ int size;
+ int array[N]; // expected-error{{fields must have a constant size: 'variable length array in structure' extension will never be supported}} \
+ // expected-warning{{variable length arrays are a C99 feature, accepted as an extension}}
+ };
+}
+
+namespace PR7206 {
+ void f(int x) {
+ struct edge_info {
+ float left;
+ float right;
+ };
+ struct edge_info edgeInfo[x]; // expected-warning{{variable length arrays are a C99 feature, accepted as an extension}}
+ }
+}
+
+namespace rdar8020206 {
+ template<typename T>
+ void f(int i) {
+ const unsigned value = i;
+ int array[value * i]; // expected-warning 2{{variable length arrays are a C99 feature, accepted as an extension}}
+ }
+
+ template void f<int>(int); // expected-note{{instantiation of}}
+}
+
+namespace rdar8021385 {
+ typedef int my_int;
+ struct A { typedef int my_int; };
+ template<typename T>
+ struct B {
+ typedef typename T::my_int my_int;
+ void f0() {
+ int M = 4;
+ my_int a[M]; // expected-warning{{variable length arrays are a C99 feature, accepted as an extension}}
+ }
+ };
+ B<A> a;
+}
diff --git a/test/SemaCXX/c99.cpp b/test/SemaCXX/c99.cpp
index f4c3639e16a9..b0bd45dea3d1 100644
--- a/test/SemaCXX/c99.cpp
+++ b/test/SemaCXX/c99.cpp
@@ -1,8 +1,3 @@
// RUN: %clang_cc1 -fsyntax-only -verify %s
-
-void f0(int i) {
- char array[i]; // expected-error{{variable length arrays}}
-}
-
void f1(int i[static 5]) { // expected-error{{C99}}
}
diff --git a/test/SemaCXX/class.cpp b/test/SemaCXX/class.cpp
index 7eea67ad4455..b5cecbcf937b 100644
--- a/test/SemaCXX/class.cpp
+++ b/test/SemaCXX/class.cpp
@@ -136,3 +136,26 @@ namespace pr6629 {
};
};
}
+
+namespace PR7153 {
+ class EnclosingClass {
+ public:
+ struct A { } mutable *member;
+ };
+
+ void f(const EnclosingClass &ec) {
+ ec.member = 0;
+ }
+}
+
+namespace PR7196 {
+ struct A {
+ int a;
+
+ void f() {
+ char i[sizeof(a)];
+ enum { x = sizeof(i) };
+ enum { y = sizeof(a) };
+ }
+ };
+}
diff --git a/test/SemaCXX/compare.cpp b/test/SemaCXX/compare.cpp
index cd243e3d6b23..4790347220d6 100644
--- a/test/SemaCXX/compare.cpp
+++ b/test/SemaCXX/compare.cpp
@@ -19,8 +19,8 @@ int test0(long a, unsigned long b) {
((signed char) a == b) + // expected-warning {{comparison of integers of different signs}}
((long) a == (unsigned long) b) + // expected-warning {{comparison of integers of different signs}}
((int) a == (unsigned int) b) + // expected-warning {{comparison of integers of different signs}}
- ((short) a == (unsigned short) b) + // expected-warning {{comparison of integers of different signs}}
- ((signed char) a == (unsigned char) b) + // expected-warning {{comparison of integers of different signs}}
+ ((short) a == (unsigned short) b) +
+ ((signed char) a == (unsigned char) b) +
(a < (unsigned long) b) + // expected-warning {{comparison of integers of different signs}}
(a < (unsigned int) b) +
(a < (unsigned short) b) +
@@ -31,8 +31,8 @@ int test0(long a, unsigned long b) {
((signed char) a < b) + // expected-warning {{comparison of integers of different signs}}
((long) a < (unsigned long) b) + // expected-warning {{comparison of integers of different signs}}
((int) a < (unsigned int) b) + // expected-warning {{comparison of integers of different signs}}
- ((short) a < (unsigned short) b) + // expected-warning {{comparison of integers of different signs}}
- ((signed char) a < (unsigned char) b) + // expected-warning {{comparison of integers of different signs}}
+ ((short) a < (unsigned short) b) +
+ ((signed char) a < (unsigned char) b) +
// (A,b)
(A == (unsigned long) b) +
@@ -83,8 +83,8 @@ int test0(long a, unsigned long b) {
((signed char) a < B) +
((long) a < (unsigned long) B) + // expected-warning {{comparison of integers of different signs}}
((int) a < (unsigned int) B) + // expected-warning {{comparison of integers of different signs}}
- ((short) a < (unsigned short) B) + // expected-warning {{comparison of integers of different signs}}
- ((signed char) a < (unsigned char) B) + // expected-warning {{comparison of integers of different signs}}
+ ((short) a < (unsigned short) B) +
+ ((signed char) a < (unsigned char) B) +
// (C,b)
(C == (unsigned long) b) +
@@ -135,8 +135,8 @@ int test0(long a, unsigned long b) {
((signed char) a < C) +
((long) a < (unsigned long) C) + // expected-warning {{comparison of integers of different signs}}
((int) a < (unsigned int) C) + // expected-warning {{comparison of integers of different signs}}
- ((short) a < (unsigned short) C) + // expected-warning {{comparison of integers of different signs}}
- ((signed char) a < (unsigned char) C) + // expected-warning {{comparison of integers of different signs}}
+ ((short) a < (unsigned short) C) +
+ ((signed char) a < (unsigned char) C) +
// (0x80000,b)
(0x80000 == (unsigned long) b) +
@@ -187,8 +187,8 @@ int test0(long a, unsigned long b) {
((signed char) a < 0x80000) +
((long) a < (unsigned long) 0x80000) + // expected-warning {{comparison of integers of different signs}}
((int) a < (unsigned int) 0x80000) + // expected-warning {{comparison of integers of different signs}}
- ((short) a < (unsigned short) 0x80000) + // expected-warning {{comparison of integers of different signs}}
- ((signed char) a < (unsigned char) 0x80000) + // expected-warning {{comparison of integers of different signs}}
+ ((short) a < (unsigned short) 0x80000) +
+ ((signed char) a < (unsigned char) 0x80000) +
10
;
diff --git a/test/SemaCXX/conditional-expr.cpp b/test/SemaCXX/conditional-expr.cpp
index a812a5920d65..a09ff2bd417d 100644
--- a/test/SemaCXX/conditional-expr.cpp
+++ b/test/SemaCXX/conditional-expr.cpp
@@ -238,3 +238,40 @@ namespace PR6757 {
(void)(true ? Bar() : Foo3()); // expected-error{{no viable constructor copying temporary}}
}
}
+
+// Reduced from selfhost.
+namespace test1 {
+ struct A {
+ enum Foo {
+ fa, fb, fc, fd, fe, ff
+ };
+
+ Foo x();
+ };
+
+ void foo(int);
+
+ void test(A *a) {
+ foo(a ? a->x() : 0);
+ }
+}
+
+namespace rdar7998817 {
+ class X {
+ X(X&); // expected-note{{declared private here}}
+
+ struct ref { };
+
+ public:
+ X();
+ X(ref);
+
+ operator ref();
+ };
+
+ void f(bool B) {
+ X x;
+ (void)(B? x // expected-error{{calling a private constructor of class 'rdar7998817::X'}}
+ : X());
+ }
+}
diff --git a/test/SemaCXX/constant-expression.cpp b/test/SemaCXX/constant-expression.cpp
index a17dd58dab03..1341036d83da 100644
--- a/test/SemaCXX/constant-expression.cpp
+++ b/test/SemaCXX/constant-expression.cpp
@@ -57,8 +57,8 @@ template <int itval, Enum etval> struct C {
i10 = sizeof(Struct),
i11 = true? 1 + cval * Struct::sval ^ itval / (int)1.5 - sizeof(Struct) : 0
;
- void f() {
- switch(0) {
+ void f(int cond) {
+ switch(cond) {
case 0 + 1:
case 100 + eval:
case 200 + cval:
diff --git a/test/SemaCXX/default-assignment-operator.cpp b/test/SemaCXX/default-assignment-operator.cpp
index dee6d131e4ad..668c60036662 100644
--- a/test/SemaCXX/default-assignment-operator.cpp
+++ b/test/SemaCXX/default-assignment-operator.cpp
@@ -1,15 +1,14 @@
// RUN: %clang_cc1 -fsyntax-only -verify %s
class Base { // expected-error {{cannot define the implicit default assignment operator for 'Base', because non-static reference member 'ref' can't use default assignment operator}} \
- // expected-warning{{class 'Base' does not declare any constructor to initialize its non-modifiable members}} \
- // expected-note {{synthesized method is first required here}}
+ // expected-warning{{class 'Base' does not declare any constructor to initialize its non-modifiable members}}
int &ref; // expected-note {{declared here}} \
// expected-note{{reference member 'ref' will never be initialized}}
};
class X : Base { // // expected-error {{cannot define the implicit default assignment operator for 'X', because non-static const member 'cint' can't use default assignment operator}} \
- // expected-note {{synthesized method is first required here}}
-public:
+// expected-note{{assignment operator for 'Base' first required here}}
+public:
X();
const int cint; // expected-note {{declared here}}
};
@@ -29,7 +28,7 @@ Z z2;
// Test1
void f(X x, const X cx) {
- x = cx;
+ x = cx; // expected-note{{assignment operator for 'X' first required here}}
x = cx;
z1 = z2;
}
@@ -74,8 +73,7 @@ void i() {
// Test5
-class E1 { // expected-error{{cannot define the implicit default assignment operator for 'E1', because non-static const member 'a' can't use default assignment operator}} \
- // expected-note {{synthesized method is first required here}}
+class E1 { // expected-error{{cannot define the implicit default assignment operator for 'E1', because non-static const member 'a' can't use default assignment operator}}
public:
const int a; // expected-note{{declared here}}
@@ -86,7 +84,7 @@ public:
E1 e1, e2;
void j() {
- e1 = e2;
+ e1 = e2; // expected-note{{assignment operator for 'E1' first required here}}
}
namespace ProtectedCheck {
@@ -103,7 +101,8 @@ namespace ProtectedCheck {
X x;
};
- void f(Z z) { z = z; } //
+ void f(Z z) { z = z; } // expected-note{{implicit default copy assignment operator}}
+
}
namespace MultiplePaths {
diff --git a/test/SemaCXX/empty-class-layout.cpp b/test/SemaCXX/empty-class-layout.cpp
index c3dc7330fe76..27f5040e1877 100644
--- a/test/SemaCXX/empty-class-layout.cpp
+++ b/test/SemaCXX/empty-class-layout.cpp
@@ -2,6 +2,8 @@
#define SA(n, p) int a##n[(p) ? 1 : -1]
+namespace Test0 {
+
struct A { int a; };
SA(0, sizeof(A) == 4);
@@ -66,3 +68,19 @@ SA(11, sizeof(S7) == 8);
struct S8 : Empty, A {
};
SA(12, sizeof(S8) == 4);
+
+}
+
+namespace Test1 {
+
+// Test that we don't try to place both A subobjects at offset 0.
+struct A { };
+class B { virtual void f(); };
+class C : A, virtual B { };
+struct D : virtual C { };
+struct E : virtual A { };
+class F : D, E { };
+
+SA(0, sizeof(F) == 24);
+
+}
diff --git a/test/SemaCXX/enum.cpp b/test/SemaCXX/enum.cpp
index dc4a506dda21..bfb5784dd161 100644
--- a/test/SemaCXX/enum.cpp
+++ b/test/SemaCXX/enum.cpp
@@ -1,5 +1,4 @@
// RUN: %clang_cc1 -fsyntax-only -pedantic -std=c++98 -verify -triple x86_64-apple-darwin %s
-
enum E {
Val1,
Val2
@@ -71,3 +70,12 @@ namespace PR6061 {
namespace Conditional {
enum a { A }; a x(const enum a x) { return 1?x:A; }
}
+
+namespace PR7051 {
+ enum E { e0 };
+ void f() {
+ E e;
+ e = 1; // expected-error{{assigning to 'PR7051::E' from incompatible type 'int'}}
+ e |= 1; // expected-error{{assigning to 'PR7051::E' from incompatible type 'int'}}
+ }
+}
diff --git a/test/SemaCXX/flexible-array-test.cpp b/test/SemaCXX/flexible-array-test.cpp
new file mode 100644
index 000000000000..02e3f83974e2
--- /dev/null
+++ b/test/SemaCXX/flexible-array-test.cpp
@@ -0,0 +1,45 @@
+// RUN: %clang_cc1 -fsyntax-only -verify %s
+// pr7029
+
+template <class Key, class T> struct QMap
+{
+ void insert(const Key &, const T &);
+ T v;
+};
+
+
+template <class Key, class T>
+void QMap<Key, T>::insert(const Key &, const T &avalue)
+{
+ v = avalue;
+}
+
+
+struct inotify_event
+{
+ int wd;
+
+ // clang doesn't like '[]':
+ // cannot initialize a parameter of type 'void *' with an rvalue of type 'char (*)[]'
+ char name [];
+};
+
+
+void foo()
+{
+ inotify_event event;
+ inotify_event* ptr = &event;
+ inotify_event event1 = *ptr;
+ *ptr = event;
+ QMap<int, inotify_event> eventForId;
+ eventForId.insert(ptr->wd, *ptr);
+}
+
+struct S {
+ virtual void foo();
+};
+
+struct X {
+ int blah;
+ S strings[]; // expected-error {{flexible array member 'strings' of non-POD element type 'S []'}}
+};
diff --git a/test/SemaCXX/i-c-e-cxx.cpp b/test/SemaCXX/i-c-e-cxx.cpp
index e8275d463de5..9672a420dcae 100644
--- a/test/SemaCXX/i-c-e-cxx.cpp
+++ b/test/SemaCXX/i-c-e-cxx.cpp
@@ -17,7 +17,7 @@ void f() {
int a() {
const int t=t; // expected-note {{subexpression not valid}}
- switch(1) {
+ switch(1) { // expected-warning {{no case matching constant switch condition '1'}}
case t:; // expected-error {{not an integer constant expression}}
}
}
diff --git a/test/SemaCXX/implicit-virtual-member-functions.cpp b/test/SemaCXX/implicit-virtual-member-functions.cpp
index cb245011a873..f6082e5699cc 100644
--- a/test/SemaCXX/implicit-virtual-member-functions.cpp
+++ b/test/SemaCXX/implicit-virtual-member-functions.cpp
@@ -21,9 +21,9 @@ C::C() { } // expected-note {{implicit default destructor for 'C' first require
struct D : A { // expected-error {{no suitable member 'operator delete' in 'D'}}
void operator delete(void *, int); // expected-note {{'operator delete' declared here}}
-}; // expected-note {{implicit default destructor for 'D' first required here}}
+};
void f() {
- new D;
+ new D; // expected-note {{implicit default destructor for 'D' first required here}}
}
diff --git a/test/SemaCXX/invalid-instantiated-field-decl.cpp b/test/SemaCXX/invalid-instantiated-field-decl.cpp
new file mode 100644
index 000000000000..8b26489d94d1
--- /dev/null
+++ b/test/SemaCXX/invalid-instantiated-field-decl.cpp
@@ -0,0 +1,35 @@
+// RUN: %clang_cc1 -fsyntax-only -verify %s
+
+template <typename T>
+class SmallVectorImpl {
+public:
+ explicit SmallVectorImpl(unsigned N) {
+ }
+
+ ~SmallVectorImpl() { }
+
+};
+
+template <typename T, unsigned N>
+class SmallVector : public SmallVectorImpl<T> {
+ typedef typename SmallVectorImpl<T>::U U; // expected-error {{no type named 'U' in 'SmallVectorImpl<CallSite>'}}
+ enum {
+
+ MinUs = (static_cast<unsigned int>(sizeof(T))*N + // expected-error {{invalid application of 'sizeof' to an incomplete type 'CallSite'}}
+ static_cast<unsigned int>(sizeof(U)) - 1) /
+ static_cast<unsigned int>(sizeof(U)),
+ NumInlineEltsElts = MinUs
+ };
+ U InlineElts[NumInlineEltsElts];
+public:
+ SmallVector() : SmallVectorImpl<T>(NumInlineEltsElts) {
+ }
+
+};
+
+class CallSite; // expected-note {{forward declaration of 'CallSite'}}
+class InlineFunctionInfo {
+public:
+ explicit InlineFunctionInfo() {}
+ SmallVector<CallSite, 2> DevirtualizedCalls; // expected-note {{in instantiation of template class 'SmallVector<CallSite, 2>' requested}}
+};
diff --git a/test/SemaCXX/member-pointer.cpp b/test/SemaCXX/member-pointer.cpp
index be25cbdb7ed0..9d5cd2fc9273 100644
--- a/test/SemaCXX/member-pointer.cpp
+++ b/test/SemaCXX/member-pointer.cpp
@@ -157,3 +157,20 @@ namespace pr6783 {
return object->*p2m; // expected-error {{left hand operand to ->*}}
}
}
+
+namespace PR7176 {
+ namespace base
+ {
+ struct Process
+ { };
+ struct Continuous : Process
+ {
+ bool cond();
+ };
+ }
+
+ typedef bool( base::Process::*Condition )();
+
+ void m()
+ { (void)(Condition) &base::Continuous::cond; }
+}
diff --git a/test/SemaCXX/namespace-alias.cpp b/test/SemaCXX/namespace-alias.cpp
index 1c3da3c656a6..52cae2e92f5a 100644
--- a/test/SemaCXX/namespace-alias.cpp
+++ b/test/SemaCXX/namespace-alias.cpp
@@ -84,6 +84,26 @@ namespace K {
}
}
+namespace {
+ class C1;
+}
+namespace {
+ class C1;
+}
+C1 *pc1 = 0;
+
+namespace N {
+ namespace {
+ class C2;
+ }
+}
+namespace N {
+ namespace {
+ class C2;
+ }
+}
+N::C2 *pc2 = 0;
+
// PR6341
namespace A = N;
namespace N { }
diff --git a/test/SemaCXX/nested-name-spec.cpp b/test/SemaCXX/nested-name-spec.cpp
index 59a8e8c45dc7..0dc1097e3867 100644
--- a/test/SemaCXX/nested-name-spec.cpp
+++ b/test/SemaCXX/nested-name-spec.cpp
@@ -228,3 +228,19 @@ namespace test3 {
A::execute(path); // expected-error {{incomplete type 'test3::A' named in nested name specifier}}
}
}
+
+namespace PR7133 {
+ namespace A {
+ class Foo;
+ }
+
+ namespace A {
+ namespace B {
+ bool foo(Foo &);
+ }
+ }
+
+ bool A::B::foo(Foo &) {
+ return false;
+ }
+}
diff --git a/test/SemaCXX/new-delete.cpp b/test/SemaCXX/new-delete.cpp
index 763ed2c7b4d6..3f1da0292b4a 100644
--- a/test/SemaCXX/new-delete.cpp
+++ b/test/SemaCXX/new-delete.cpp
@@ -24,6 +24,8 @@ void* operator new(size_t, int*); // expected-note 3 {{candidate}}
void* operator new(size_t, float*); // expected-note 3 {{candidate}}
void* operator new(size_t, S); // expected-note 2 {{candidate}}
+struct foo { };
+
void good_news()
{
int *pi = new int;
@@ -43,6 +45,14 @@ void good_news()
pi = new (S(1.0f, 2)) int;
(void)new int[true];
+
+ // PR7147
+ typedef int a[2];
+ foo* f1 = new foo;
+ foo* f2 = new foo[2];
+ typedef foo x[2];
+ typedef foo y[2][2];
+ x* f3 = new y;
}
struct abstract {
@@ -93,7 +103,7 @@ void bad_deletes()
delete 0; // expected-error {{cannot delete expression of type 'int'}}
delete [0] (int*)0; // expected-error {{expected ']'}} \
// expected-note {{to match this '['}}
- delete (void*)0; // expected-error {{cannot delete expression}}
+ delete (void*)0; // expected-warning {{cannot delete expression with pointer-to-'void' type 'void *'}}
delete (T*)0; // expected-warning {{deleting pointer to incomplete type}}
::S::delete (int*)0; // expected-error {{expected unqualified-id}}
}
@@ -235,6 +245,9 @@ namespace Test1 {
void f() {
(void)new int[10](1, 2); // expected-error {{array 'new' cannot have initialization arguments}}
+
+ typedef int T[10];
+ (void)new T(1, 2); // expected-error {{array 'new' cannot have initialization arguments}}
}
template<typename T>
diff --git a/test/SemaCXX/offsetof.cpp b/test/SemaCXX/offsetof.cpp
index 47c3f22a0ed3..639d7faa8e96 100644
--- a/test/SemaCXX/offsetof.cpp
+++ b/test/SemaCXX/offsetof.cpp
@@ -26,7 +26,7 @@ struct HasArray {
// Constant and non-constant offsetof expressions
void test_ice(int i) {
int array0[__builtin_offsetof(HasArray, array[5])];
- int array1[__builtin_offsetof(HasArray, array[i])]; // expected-error{{variable length arrays are not permitted in C++}}
+ int array1[__builtin_offsetof(HasArray, array[i])];
}
// Bitfields
diff --git a/test/SemaCXX/overload-call.cpp b/test/SemaCXX/overload-call.cpp
index 79c74cec4947..29133c7c7ff1 100644
--- a/test/SemaCXX/overload-call.cpp
+++ b/test/SemaCXX/overload-call.cpp
@@ -430,3 +430,33 @@ namespace PR6177 {
void g() { f(""); } // expected-error{{volatile lvalue reference to type 'bool const volatile' cannot bind to a value of unrelated type 'char const [1]'}}
}
+
+namespace PR7095 {
+ struct X { };
+
+ struct Y {
+ operator const X*();
+
+ private:
+ operator X*();
+ };
+
+ void f(const X *);
+ void g(Y y) { f(y); }
+}
+
+namespace PR7224 {
+ class A {};
+ class B : public A {};
+
+ int &foo(A *const d);
+ float &foo(const A *const d);
+
+ void bar()
+ {
+ B *const d = 0;
+ B const *const d2 = 0;
+ int &ir = foo(d);
+ float &fr = foo(d2);
+ }
+}
diff --git a/test/SemaCXX/references.cpp b/test/SemaCXX/references.cpp
index e40ea01a9b99..a7aafe41c392 100644
--- a/test/SemaCXX/references.cpp
+++ b/test/SemaCXX/references.cpp
@@ -115,3 +115,18 @@ void test10() {
int &c = ev.x; // expected-error{{non-const reference cannot bind to vector element}}
const int &d = ev.x;
}
+
+namespace PR7149 {
+ template<typename T> struct X0
+ {
+ T& first;
+ X0(T& p1) : first(p1) { }
+ };
+
+
+ void f()
+ {
+ int p1[1];
+ X0< const int[1]> c(p1);
+ }
+}
diff --git a/test/SemaCXX/return-noreturn.cpp b/test/SemaCXX/return-noreturn.cpp
new file mode 100644
index 000000000000..9242d1240ab6
--- /dev/null
+++ b/test/SemaCXX/return-noreturn.cpp
@@ -0,0 +1,17 @@
+// RUN: %clang_cc1 %s -fsyntax-only -verify -Wmissing-noreturn -Wno-unreachable-code
+
+// A destructor may be marked noreturn and should still influence the CFG.
+namespace PR6884 {
+ struct abort_struct {
+ abort_struct() {} // Make this non-POD so the destructor is invoked.
+ ~abort_struct() __attribute__((noreturn));
+ };
+
+ int f() {
+ abort_struct();
+ }
+
+ int f2() {
+ abort_struct s;
+ } // expected-warning{{control reaches end of non-void function}}
+}
diff --git a/test/SemaCXX/scope-check.cpp b/test/SemaCXX/scope-check.cpp
new file mode 100644
index 000000000000..cef64f6322c5
--- /dev/null
+++ b/test/SemaCXX/scope-check.cpp
@@ -0,0 +1,123 @@
+// RUN: %clang_cc1 -fsyntax-only -verify -fblocks %s -Wno-unreachable-code
+
+namespace test0 {
+ struct D { ~D(); };
+
+ int f(bool b) {
+ if (b) {
+ D d;
+ goto end;
+ }
+
+ end:
+ return 1;
+ }
+}
+
+namespace test1 {
+ struct C { C(); };
+
+ int f(bool b) {
+ if (b)
+ goto foo; // expected-error {{illegal goto into protected scope}}
+ C c; // expected-note {{jump bypasses variable initialization}}
+ foo:
+ return 1;
+ }
+}
+
+namespace test2 {
+ struct C { C(); };
+
+ int f(void **ip) {
+ static void *ips[] = { &&lbl1, &&lbl2 };
+
+ C c;
+ goto *ip;
+ lbl1:
+ return 0;
+ lbl2:
+ return 1;
+ }
+}
+
+namespace test3 {
+ struct C { C(); };
+
+ int f(void **ip) {
+ static void *ips[] = { &&lbl1, &&lbl2 };
+
+ goto *ip;
+ lbl1: {
+ C c;
+ return 0;
+ }
+ lbl2:
+ return 1;
+ }
+}
+
+namespace test4 {
+ struct C { C(); };
+ struct D { ~D(); };
+
+ int f(void **ip) {
+ static void *ips[] = { &&lbl1, &&lbl2 };
+
+ C c0;
+
+ goto *ip; // expected-warning {{indirect goto might cross protected scopes}}
+ C c1; // expected-note {{jump bypasses variable initialization}}
+ lbl1: // expected-note {{possible target of indirect goto}}
+ return 0;
+ lbl2:
+ return 1;
+ }
+}
+
+namespace test5 {
+ struct C { C(); };
+ struct D { ~D(); };
+
+ int f(void **ip) {
+ static void *ips[] = { &&lbl1, &&lbl2 };
+ C c0;
+
+ goto *ip;
+ lbl1: // expected-note {{possible target of indirect goto}}
+ return 0;
+ lbl2:
+ if (ip[1]) {
+ D d; // expected-note {{jump exits scope of variable with non-trivial destructor}}
+ ip += 2;
+ goto *ip; // expected-warning {{indirect goto might cross protected scopes}}
+ }
+ return 1;
+ }
+}
+
+namespace test6 {
+ struct C { C(); };
+
+ unsigned f(unsigned s0, unsigned s1, void **ip) {
+ static void *ips[] = { &&lbl1, &&lbl2, &&lbl3, &&lbl4 };
+ C c0;
+
+ goto *ip;
+ lbl1:
+ s0++;
+ goto *++ip;
+ lbl2:
+ s0 -= s1;
+ goto *++ip;
+ lbl3: {
+ unsigned tmp = s0;
+ s0 = s1;
+ s1 = tmp;
+ goto *++ip;
+ }
+ lbl4:
+ return s0;
+ }
+}
+
diff --git a/test/SemaCXX/switch.cpp b/test/SemaCXX/switch.cpp
index c256960af1da..fc13630bbf12 100644
--- a/test/SemaCXX/switch.cpp
+++ b/test/SemaCXX/switch.cpp
@@ -1,4 +1,4 @@
-// RUN: %clang_cc1 -fsyntax-only -verify %s
+// RUN: %clang_cc1 -fsyntax-only -verify -Wswitch-enum %s
void test() {
bool x = true;
@@ -40,3 +40,20 @@ void x3(C &c) {
switch (c) { // expected-error{{incomplete class type}}
}
}
+
+namespace test3 {
+ enum En { A, B, C };
+ template <En how> void foo() {
+ int x = 0, y = 5;
+
+ switch (how) { //expected-warning {{no case matching constant switch condition '2'}}
+ case A: x *= y; break;
+ case B: x += y; break;
+ // No case for C, but it's okay because we have a constant condition.
+ }
+ }
+
+ template void foo<A>();
+ template void foo<B>();
+ template void foo<C>(); //expected-note {{in instantiation}}
+}
diff --git a/test/SemaCXX/vararg-non-pod.cpp b/test/SemaCXX/vararg-non-pod.cpp
index d31f1f7196aa..55ec9418cd47 100644
--- a/test/SemaCXX/vararg-non-pod.cpp
+++ b/test/SemaCXX/vararg-non-pod.cpp
@@ -88,3 +88,13 @@ void test_typeid(Base &base) {
(void)typeid(get_base(base)); // expected-warning{{cannot pass object of non-POD type 'Base' through variadic function; call will abort at runtime}}
(void)typeid(eat_base(base)); // okay
}
+
+
+// rdar://7985267 - Shouldn't warn, doesn't actually use __builtin_va_start is
+// magic.
+
+void t6(Foo somearg, ... ) {
+ __builtin_va_list list;
+ __builtin_va_start(list, somearg);
+}
+
diff --git a/test/SemaCXX/vector.cpp b/test/SemaCXX/vector.cpp
new file mode 100644
index 000000000000..b548865553c2
--- /dev/null
+++ b/test/SemaCXX/vector.cpp
@@ -0,0 +1,188 @@
+// RUN: %clang_cc1 -triple x86_64-apple-darwin10 -fsyntax-only -verify %s
+typedef char char16 __attribute__ ((__vector_size__ (16)));
+typedef long long longlong16 __attribute__ ((__vector_size__ (16)));
+typedef char char16_e __attribute__ ((__ext_vector_type__ (16)));
+typedef long long longlong16_e __attribute__ ((__ext_vector_type__ (2)));
+
+// Test overloading and function calls with vector types.
+void f0(char16);
+
+void f0_test(char16 c16, longlong16 ll16, char16_e c16e, longlong16_e ll16e) {
+ f0(c16);
+ f0(ll16);
+ f0(c16e);
+ f0(ll16e);
+}
+
+int &f1(char16); // expected-note 2{{candidate function}}
+float &f1(longlong16); // expected-note 2{{candidate function}}
+
+void f1_test(char16 c16, longlong16 ll16, char16_e c16e, longlong16_e ll16e) {
+ int &ir1 = f1(c16);
+ float &fr1 = f1(ll16);
+ f1(c16e); // expected-error{{call to 'f1' is ambiguous}}
+ f1(ll16e); // expected-error{{call to 'f1' is ambiguous}}
+}
+
+void f2(char16_e); // expected-note{{no known conversion from 'longlong16_e' to 'char16_e' for 1st argument}} \
+ // expected-note{{candidate function not viable: no known conversion from 'convertible_to<longlong16_e>' to 'char16_e' for 1st argument}}
+
+void f2_test(char16 c16, longlong16 ll16, char16_e c16e, longlong16_e ll16e) {
+ f2(c16);
+ f2(ll16);
+ f2(c16e);
+ f2(ll16e); // expected-error{{no matching function}}
+ f2('a');
+ f2(17);
+}
+
+// Test the conditional operator with vector types.
+void conditional(bool Cond, char16 c16, longlong16 ll16, char16_e c16e,
+ longlong16_e ll16e) {
+ // Conditional operators with the same type.
+ __typeof__(Cond? c16 : c16) *c16p1 = &c16;
+ __typeof__(Cond? ll16 : ll16) *ll16p1 = &ll16;
+ __typeof__(Cond? c16e : c16e) *c16ep1 = &c16e;
+ __typeof__(Cond? ll16e : ll16e) *ll16ep1 = &ll16e;
+
+ // Conditional operators with similar types.
+ __typeof__(Cond? c16 : c16e) *c16ep2 = &c16e;
+ __typeof__(Cond? c16e : c16) *c16ep3 = &c16e;
+ __typeof__(Cond? ll16 : ll16e) *ll16ep2 = &ll16e;
+ __typeof__(Cond? ll16e : ll16) *ll16ep3 = &ll16e;
+
+ // Conditional operators with incompatible types.
+ (void)(Cond? c16 : ll16); // expected-error{{can't convert between vector values}}
+ (void)(Cond? ll16e : c16e); // expected-error{{can't convert between vector values}}
+ (void)(Cond? ll16e : c16); // expected-error{{can't convert between vector values}}
+}
+
+// Test C++ cast'ing of vector types.
+void casts(longlong16 ll16, longlong16_e ll16e) {
+ // C-style casts.
+ (void)(char16)ll16;
+ (void)(char16_e)ll16;
+ (void)(longlong16)ll16;
+ (void)(longlong16_e)ll16;
+ (void)(char16)ll16e;
+ (void)(char16_e)ll16e;
+ (void)(longlong16)ll16e;
+ (void)(longlong16_e)ll16e;
+
+ // Function-style casts.
+ (void)char16(ll16);
+ (void)char16_e(ll16);
+ (void)longlong16(ll16);
+ (void)longlong16_e(ll16);
+ (void)char16(ll16e);
+ (void)char16_e(ll16e);
+ (void)longlong16(ll16e);
+ (void)longlong16_e(ll16e);
+
+ // static_cast
+ (void)static_cast<char16>(ll16);
+ (void)static_cast<char16_e>(ll16);
+ (void)static_cast<longlong16>(ll16);
+ (void)static_cast<longlong16_e>(ll16);
+ (void)static_cast<char16>(ll16e);
+ (void)static_cast<char16_e>(ll16e); // expected-error{{static_cast from 'longlong16_e' to 'char16_e' is not allowed}}
+ (void)static_cast<longlong16>(ll16e);
+ (void)static_cast<longlong16_e>(ll16e);
+
+ // reinterpret_cast
+ (void)reinterpret_cast<char16>(ll16);
+ (void)reinterpret_cast<char16_e>(ll16);
+ (void)reinterpret_cast<longlong16>(ll16);
+ (void)reinterpret_cast<longlong16_e>(ll16);
+ (void)reinterpret_cast<char16>(ll16e);
+ (void)reinterpret_cast<char16_e>(ll16e);
+ (void)reinterpret_cast<longlong16>(ll16e);
+ (void)reinterpret_cast<longlong16_e>(ll16e);
+}
+
+template<typename T>
+struct convertible_to { // expected-note 3 {{candidate function (the implicit copy assignment operator)}}
+ operator T() const;
+};
+
+void test_implicit_conversions(bool Cond, char16 c16, longlong16 ll16,
+ char16_e c16e, longlong16_e ll16e,
+ convertible_to<char16> to_c16,
+ convertible_to<longlong16> to_ll16,
+ convertible_to<char16_e> to_c16e,
+ convertible_to<longlong16_e> to_ll16e,
+ convertible_to<char16&> rto_c16,
+ convertible_to<char16_e&> rto_c16e) {
+ f0(to_c16);
+ f0(to_ll16);
+ f0(to_c16e);
+ f0(to_ll16e);
+ f2(to_c16);
+ f2(to_ll16);
+ f2(to_c16e);
+ f2(to_ll16e); // expected-error{{no matching function}}
+
+ (void)(c16 == c16e);
+ (void)(c16 == to_c16);
+ (void)+to_c16;
+ (void)-to_c16;
+ (void)~to_c16;
+ (void)(to_c16 == to_c16e);
+ (void)(to_c16 != to_c16e);
+ (void)(to_c16 < to_c16e);
+ (void)(to_c16 <= to_c16e);
+ (void)(to_c16 > to_c16e);
+ (void)(to_c16 >= to_c16e);
+ (void)(to_c16 + to_c16);
+ (void)(to_c16 - to_c16);
+ (void)(to_c16 * to_c16);
+ (void)(to_c16 / to_c16);
+ (void)(rto_c16 = to_c16); // expected-error{{no viable overloaded '='}}
+ (void)(rto_c16 += to_c16);
+ (void)(rto_c16 -= to_c16);
+ (void)(rto_c16 *= to_c16);
+ (void)(rto_c16 /= to_c16);
+
+ (void)+to_c16e;
+ (void)-to_c16e;
+ (void)~to_c16e;
+ (void)(to_c16e == to_c16e);
+ (void)(to_c16e != to_c16e);
+ (void)(to_c16e < to_c16e);
+ (void)(to_c16e <= to_c16e);
+ (void)(to_c16e > to_c16e);
+ (void)(to_c16e >= to_c16e);
+ (void)(to_c16e + to_c16);
+ (void)(to_c16e - to_c16);
+ (void)(to_c16e * to_c16);
+ (void)(to_c16e / to_c16);
+ (void)(rto_c16e = to_c16); // expected-error{{no viable overloaded '='}}
+ (void)(rto_c16e += to_c16);
+ (void)(rto_c16e -= to_c16);
+ (void)(rto_c16e *= to_c16);
+ (void)(rto_c16e /= to_c16);
+
+ (void)+to_c16;
+ (void)-to_c16;
+ (void)~to_c16;
+ (void)(to_c16 == to_c16e);
+ (void)(to_c16 != to_c16e);
+ (void)(to_c16 < to_c16e);
+ (void)(to_c16 <= to_c16e);
+ (void)(to_c16 > to_c16e);
+ (void)(to_c16 >= to_c16e);
+ (void)(to_c16 + to_c16e);
+ (void)(to_c16 - to_c16e);
+ (void)(to_c16 * to_c16e);
+ (void)(to_c16 / to_c16e);
+ (void)(rto_c16 = c16e); // expected-error{{no viable overloaded '='}}
+ (void)(rto_c16 += to_c16e); // expected-error{{expression is not assignable}}
+ (void)(rto_c16 -= to_c16e); // expected-error{{expression is not assignable}}
+ (void)(rto_c16 *= to_c16e); // expected-error{{expression is not assignable}}
+ (void)(rto_c16 /= to_c16e); // expected-error{{expression is not assignable}}
+
+ (void)(Cond? to_c16 : to_c16e);
+ (void)(Cond? to_ll16e : to_ll16);
+ (void)(Cond? to_c16 : to_ll16); // expected-error{{can't convert between vector values of different size}}
+ (void)(Cond? to_c16e : to_ll16e); // expected-error{{can't convert between vector values of different size}}
+}
diff --git a/test/SemaCXX/virtual-member-functions-key-function.cpp b/test/SemaCXX/virtual-member-functions-key-function.cpp
index 97164d93affc..09a30b93605e 100644
--- a/test/SemaCXX/virtual-member-functions-key-function.cpp
+++ b/test/SemaCXX/virtual-member-functions-key-function.cpp
@@ -4,17 +4,17 @@ struct A {
};
struct B : A { // expected-error {{no suitable member 'operator delete' in 'B'}}
- B() { }
+ B() { } // expected-note {{implicit default destructor for 'B' first required here}}
void operator delete(void *, int); // expected-note {{'operator delete' declared here}}
-}; // expected-note {{implicit default destructor for 'B' first required here}}
+};
struct C : A { // expected-error {{no suitable member 'operator delete' in 'C'}}
void operator delete(void *, int); // expected-note {{'operator delete' declared here}}
-}; // expected-note {{implicit default destructor for 'C' first required here}}
+};
void f() {
- (void)new B;
- (void)new C;
+ (void)new B;
+ (void)new C; // expected-note {{implicit default destructor for 'C' first required here}}
}
// Make sure that the key-function computation is consistent when the
diff --git a/test/SemaCXX/warn-missing-noreturn.cpp b/test/SemaCXX/warn-missing-noreturn.cpp
index 8016c3da5cc5..f2f9b2e2b751 100644
--- a/test/SemaCXX/warn-missing-noreturn.cpp
+++ b/test/SemaCXX/warn-missing-noreturn.cpp
@@ -36,3 +36,17 @@ namespace test1 {
while (condition()) {}
}
}
+
+
+// <rdar://problem/7880658> - This test case previously had a false "missing return"
+// warning.
+struct R7880658 {
+ R7880658 &operator++();
+ bool operator==(const R7880658 &) const;
+ bool operator!=(const R7880658 &) const;
+};
+
+void f_R7880658(R7880658 f, R7880658 l) { // no-warning
+ for (; f != l; ++f) {
+ }
+}
diff --git a/test/SemaCXX/warn-reorder-ctor-initialization.cpp b/test/SemaCXX/warn-reorder-ctor-initialization.cpp
index 3ff01af3627c..8c254e5515bf 100644
--- a/test/SemaCXX/warn-reorder-ctor-initialization.cpp
+++ b/test/SemaCXX/warn-reorder-ctor-initialization.cpp
@@ -120,3 +120,13 @@ namespace test3 {
};
};
}
+
+namespace PR7179 {
+ struct X
+ {
+ struct Y
+ {
+ template <class T> Y(T x) : X(x) { }
+ };
+ };
+}
diff --git a/test/SemaCXX/warn-weak-vtables.cpp b/test/SemaCXX/warn-weak-vtables.cpp
index 39333c108ae8..c0cfd74a3e52 100644
--- a/test/SemaCXX/warn-weak-vtables.cpp
+++ b/test/SemaCXX/warn-weak-vtables.cpp
@@ -18,4 +18,14 @@ void f() {
struct A {
virtual void f() { }
};
+
+ A *a;
+ a->f();
+}
+
+// Use the vtables
+void uses(A &a, B<int> &b, C &c) {
+ a.f();
+ b.f();
+ c.f();
}
diff --git a/test/SemaObjC/block-attr.m b/test/SemaObjC/block-attr.m
index c89aed4bb60d..de203e711ede 100644
--- a/test/SemaObjC/block-attr.m
+++ b/test/SemaObjC/block-attr.m
@@ -1,4 +1,5 @@
// RUN: %clang_cc1 -triple x86_64-apple-darwin10 -fsyntax-only -verify -fblocks -fobjc-gc-only %s
+// RUN: %clang_cc1 -x objective-c++ -triple x86_64-apple-darwin10 -fsyntax-only -verify -fblocks -fobjc-gc-only %s
@interface Thing {}
diff --git a/test/SemaObjC/error-property-gc-attr.m b/test/SemaObjC/error-property-gc-attr.m
index a36170475bc2..661638c52e06 100644
--- a/test/SemaObjC/error-property-gc-attr.m
+++ b/test/SemaObjC/error-property-gc-attr.m
@@ -1,4 +1,5 @@
// RUN: %clang_cc1 -triple i386-apple-darwin9 -fobjc-gc -fsyntax-only -verify %s
+// RUN: %clang_cc1 -x objective-c++ -triple i386-apple-darwin9 -fobjc-gc -fsyntax-only -verify %s
@interface INTF
{
@@ -11,7 +12,7 @@
}
@property (assign) __weak id pweak;
@property (assign) __weak id WID;
-@property (assign) __strong id not;
+@property (assign) __strong id NOT;
@property (assign) id ID;
@property (assign) INTF* AWEAK;
@property (assign) __weak INTF* WI;
@@ -19,7 +20,7 @@
@implementation INTF
@synthesize pweak=IVAR; // expected-error {{existing ivar 'IVAR' for __weak property 'pweak' must be __weak}}
-@synthesize not=II; // expected-error {{existing ivar 'II' for a __strong property 'not' must be garbage collectable}}
+@synthesize NOT=II; // expected-error {{existing ivar 'II' for a __strong property 'NOT' must be garbage collectable}}
@synthesize WID;
@synthesize ID;
@synthesize AWEAK; // expected-error {{existing ivar 'AWEAK' for a __strong property 'AWEAK' must be garbage collectable}}
diff --git a/test/SemaObjC/method-conflict.m b/test/SemaObjC/method-conflict.m
index 08fdfc017ccc..5dc886fb7fd2 100644
--- a/test/SemaObjC/method-conflict.m
+++ b/test/SemaObjC/method-conflict.m
@@ -53,3 +53,14 @@ typedef NSUInteger XDSourceLanguage;
return 0;
}
@end
+
+// rdar: // 8006060
+@interface Bar
+- (void)foo:(id)format, ...; // expected-note {{previous declaration is here}}
+- (void)foo1:(id)format; // expected-note {{previous declaration is here}}
+@end
+@implementation Bar
+- (void)foo:(id)format {}; // expected-warning {{conflicting variadic declaration of method and its implementation}}
+- (void)foo1:(id)format, ... {}; // expected-warning {{conflicting variadic declaration of method and its implementation}}
+@end
+
diff --git a/test/SemaObjC/objc2-warn-weak-decl.m b/test/SemaObjC/objc2-warn-weak-decl.m
index 76b542de94a6..22a3fca91ba5 100644
--- a/test/SemaObjC/objc2-warn-weak-decl.m
+++ b/test/SemaObjC/objc2-warn-weak-decl.m
@@ -1,4 +1,5 @@
// RUN: %clang_cc1 -triple i386-apple-darwin9 -fsyntax-only -fobjc-gc -verify %s
+// RUN: %clang_cc1 -x objective-c++ -triple i386-apple-darwin9 -fsyntax-only -fobjc-gc -verify %s
struct S {
__weak id p; // expected-warning {{__weak attribute cannot be specified on a field declaration}}
};
diff --git a/test/SemaObjC/warn-assign-property-nscopying.m b/test/SemaObjC/warn-assign-property-nscopying.m
index 953814cdce1b..1bdb4f0de93e 100644
--- a/test/SemaObjC/warn-assign-property-nscopying.m
+++ b/test/SemaObjC/warn-assign-property-nscopying.m
@@ -1,4 +1,5 @@
// RUN: %clang_cc1 -fobjc-gc -fsyntax-only -verify %s
+// RUN: %clang_cc1 -x objective-c++ -fobjc-gc -fsyntax-only -verify %s
@protocol NSCopying @end
diff --git a/test/SemaObjC/warn-weak-field.m b/test/SemaObjC/warn-weak-field.m
index f20691c18696..ead454a04a37 100644
--- a/test/SemaObjC/warn-weak-field.m
+++ b/test/SemaObjC/warn-weak-field.m
@@ -1,4 +1,5 @@
// RUN: %clang_cc1 -triple i386-apple-darwin9 -fsyntax-only -fobjc-gc -verify %s
+// RUN: %clang_cc1 -x objective-c++ -triple i386-apple-darwin9 -fsyntax-only -fobjc-gc -verify %s
struct S {
__weak id w; // expected-warning {{__weak attribute cannot be specified on a field declaration}}
diff --git a/test/SemaObjCXX/const-cast.mm b/test/SemaObjCXX/const-cast.mm
new file mode 100644
index 000000000000..933fd47de7ca
--- /dev/null
+++ b/test/SemaObjCXX/const-cast.mm
@@ -0,0 +1,13 @@
+// RUN: %clang_cc1 -fsyntax-only -verify %s
+
+@class Foo;
+
+void test() {
+ const Foo *foo1 = 0;
+ Foo *foo2 = foo1; // expected-error {{cannot initialize}}
+}
+
+void test1() {
+ const Foo *foo1 = 0;
+ Foo *foo2 = const_cast<Foo*>(foo1);
+}
diff --git a/test/SemaObjCXX/conversion-to-objc-pointer-2.mm b/test/SemaObjCXX/conversion-to-objc-pointer-2.mm
new file mode 100644
index 000000000000..5277d101f588
--- /dev/null
+++ b/test/SemaObjCXX/conversion-to-objc-pointer-2.mm
@@ -0,0 +1,87 @@
+// RUN: %clang_cc1 -fsyntax-only -verify %s
+// rdar: // 7963410
+
+@protocol NSObject @end
+@interface NSObject
+- (id)init;
+- (id) alloc;
+- (id) autorelease;
+@end
+
+template<class T>
+class TNSAutoRef
+{
+public:
+ TNSAutoRef(T t)
+ : fRef(t)
+ { }
+
+ ~TNSAutoRef()
+ { }
+
+ operator T() const
+ { return fRef; }
+
+private:
+ T fRef;
+};
+
+
+#pragma mark -
+
+
+@protocol TFooProtocol <NSObject>
+
+- (void) foo;
+@end
+
+
+#pragma mark -
+
+
+@interface TFoo : NSObject
+
+- (void) setBlah: (id<TFooProtocol>)blah;
+@end
+
+
+#pragma mark -
+
+
+@implementation TFoo
+
+- (void) setBlah: (id<TFooProtocol>)blah
+ { }
+@end
+
+
+#pragma mark -
+
+
+@interface TBar : NSObject
+
+- (void) setBlah: (id)blah;
+@end
+
+#pragma mark -
+
+
+@implementation TBar
+
+- (void) setBlah: (id)blah
+ { }
+@end
+
+
+#pragma mark -
+
+
+int main (int argc, const char * argv[]) {
+
+ NSObject* object1 = [[[NSObject alloc] init] autorelease];
+ TNSAutoRef<NSObject*> object2([[NSObject alloc] init]);
+ TNSAutoRef<TBar*> bar([[TBar alloc] init]);
+ [bar setBlah: object1]; // <== Does not compile. It should.
+ [bar setBlah: object2]; // <== Does not compile. It should.
+ return 0;
+}
diff --git a/test/SemaObjCXX/conversion-to-objc-pointer.mm b/test/SemaObjCXX/conversion-to-objc-pointer.mm
new file mode 100644
index 000000000000..235aaac8d09c
--- /dev/null
+++ b/test/SemaObjCXX/conversion-to-objc-pointer.mm
@@ -0,0 +1,50 @@
+// RUN: %clang_cc1 -fsyntax-only -verify %s
+// rdar: // 7963410
+
+template<class T>
+class TNSAutoRef
+{
+public:
+ TNSAutoRef(T t)
+ : fRef(t)
+ { }
+
+ ~TNSAutoRef()
+ { }
+
+ operator T() const
+ { return fRef; }
+
+ T Get() const
+ { return fRef; }
+
+private:
+ T fRef;
+};
+
+@interface NSObject
+- (id) alloc;
+- (id)init;
+@end
+
+@interface TFoo : NSObject
+- (void) foo;
+@end
+
+@implementation TFoo
+- (void) foo {}
+@end
+
+@interface TBar : NSObject
+- (void) foo;
+@end
+
+@implementation TBar
+- (void) foo {}
+@end
+
+int main () {
+ TNSAutoRef<TBar*> bar([[TBar alloc] init]);
+ [bar foo];
+ return 0;
+}
diff --git a/test/SemaObjCXX/deduction.mm b/test/SemaObjCXX/deduction.mm
new file mode 100644
index 000000000000..6dd449d6ea75
--- /dev/null
+++ b/test/SemaObjCXX/deduction.mm
@@ -0,0 +1,58 @@
+// RUN: %clang_cc1 -fsyntax-only -verify %s
+
+@class NSString;
+
+// Reduced from WebKit.
+namespace test0 {
+ template <typename T> struct RemovePointer {
+ typedef T Type;
+ };
+
+ template <typename T> struct RemovePointer<T*> {
+ typedef T Type;
+ };
+
+ template <typename T> struct RetainPtr {
+ typedef typename RemovePointer<T>::Type ValueType;
+ typedef ValueType* PtrType;
+ RetainPtr(PtrType ptr);
+ };
+
+ void test(NSString *S) {
+ RetainPtr<NSString*> ptr(S);
+ }
+
+ void test(id S) {
+ RetainPtr<id> ptr(S);
+ }
+}
+
+@class Test1Class;
+@protocol Test1Protocol;
+namespace test1 {
+ template <typename T> struct RemovePointer {
+ typedef T type;
+ };
+ template <typename T> struct RemovePointer<T*> {
+ typedef T type;
+ };
+ template <typename A, typename B> struct is_same {};
+ template <typename A> struct is_same<A,A> {
+ static void foo();
+ };
+ template <typename T> struct tester {
+ void test() {
+ is_same<T, typename RemovePointer<T>::type*>::foo(); // expected-error 2 {{no member named 'foo'}}
+ }
+ };
+
+ template struct tester<id>;
+ template struct tester<id<Test1Protocol> >;
+ template struct tester<Class>;
+ template struct tester<Class<Test1Protocol> >;
+ template struct tester<Test1Class*>;
+ template struct tester<Test1Class<Test1Protocol>*>;
+
+ template struct tester<Test1Class>; // expected-note {{in instantiation}}
+ template struct tester<Test1Class<Test1Protocol> >; // expected-note {{in instantiation}}
+}
diff --git a/test/SemaObjCXX/ivar-construct.mm b/test/SemaObjCXX/ivar-construct.mm
new file mode 100644
index 000000000000..da066e965971
--- /dev/null
+++ b/test/SemaObjCXX/ivar-construct.mm
@@ -0,0 +1,29 @@
+// RUN: %clang_cc1 -fsyntax-only -verify %s
+struct Y {
+ Y();
+
+private:
+ ~Y(); // expected-note 3{{declared private here}}
+};
+
+template<typename T>
+struct X : T { }; // expected-error 2{{private destructor}}
+
+struct Z; // expected-note{{forward declaration}}
+
+@interface A {
+ X<Y> x; // expected-note{{implicit default destructor}}
+ Y y; // expected-error{{private destructor}}
+}
+@end
+
+@implementation A // expected-note{{implicit default constructor}}
+@end
+
+@interface B {
+ Z z; // expected-error{{incomplete type}}
+}
+@end
+
+@implementation B
+@end
diff --git a/test/SemaObjCXX/ivar-struct.mm b/test/SemaObjCXX/ivar-struct.mm
new file mode 100644
index 000000000000..3f9c7eb1a503
--- /dev/null
+++ b/test/SemaObjCXX/ivar-struct.mm
@@ -0,0 +1,7 @@
+// RUN: %clang_cc1 -fsyntax-only -verify %s
+@interface A {
+ struct X {
+ int x, y;
+ } X;
+}
+@end
diff --git a/test/SemaObjCXX/objc2-merge-gc-attribue-decl.mm b/test/SemaObjCXX/objc2-merge-gc-attribue-decl.mm
new file mode 100644
index 000000000000..7be5f17daa80
--- /dev/null
+++ b/test/SemaObjCXX/objc2-merge-gc-attribue-decl.mm
@@ -0,0 +1,51 @@
+// RUN: %clang_cc1 -triple i386-apple-darwin9 -fobjc-gc -fsyntax-only -verify %s
+@interface INTF @end
+
+extern INTF* p2;
+extern __strong INTF* p2;
+
+extern __strong id p1;
+extern id p1;
+
+extern id CFRunLoopGetMain();
+extern __strong id CFRunLoopGetMain();
+
+extern __strong id CFRunLoopGetMain2();
+extern id CFRunLoopGetMain2();
+
+extern INTF* CFRunLoopGetMain3();
+extern __strong INTF* CFRunLoopGetMain3();
+
+extern __strong INTF* CFRunLoopGetMain4();
+extern INTF* CFRunLoopGetMain4();
+
+typedef id ID;
+extern ID CFRunLoopGetMain5();
+extern __strong id CFRunLoopGetMain5();
+
+extern __strong id CFRunLoopGetMain6();
+extern ID CFRunLoopGetMain6();
+
+extern ID CFRunLoopGetMain7();
+extern __strong ID CFRunLoopGetMain7();
+
+extern __strong ID CFRunLoopGetMain8();
+extern ID CFRunLoopGetMain8();
+
+extern __weak id WLoopGetMain(); // expected-note {{previous declaration is here}}
+extern id WLoopGetMain(); // expected-error {{functions that differ only in their return type cannot be overloaded}}
+
+extern id p3; // expected-note {{previous definition is here}}
+extern __weak id p3; // expected-error {{redefinition of 'p3' with a different type}}
+
+extern void *p4; // expected-note {{previous definition is here}}
+extern void * __strong p4; // expected-error {{redefinition of 'p4' with a different type}}
+
+extern id p5;
+extern __strong id p5;
+
+extern char* __strong p6; // expected-note {{previous definition is here}}
+extern char* p6; // expected-error {{redefinition of 'p6' with a different type}}
+
+extern __strong char* p7; // expected-note {{previous definition is here}}
+extern char* p7; // expected-error {{redefinition of 'p7' with a different type}}
diff --git a/test/SemaObjCXX/static-cast.mm b/test/SemaObjCXX/static-cast.mm
new file mode 100644
index 000000000000..e2827028de59
--- /dev/null
+++ b/test/SemaObjCXX/static-cast.mm
@@ -0,0 +1,29 @@
+// RUN: %clang_cc1 -fsyntax-only -verify %s
+
+@protocol NSTextViewDelegate;
+
+@interface NSResponder @end
+
+class AutoreleaseObject
+{
+public:
+ AutoreleaseObject();
+ ~AutoreleaseObject();
+
+
+ AutoreleaseObject& operator=(NSResponder* inValue);
+ AutoreleaseObject& operator=(const AutoreleaseObject& inValue);
+
+ AutoreleaseObject(const AutoreleaseObject& inValue);
+
+ operator NSResponder*() const;
+};
+
+
+void InvokeSaveFocus()
+{
+ AutoreleaseObject mResolvedFirstResponder;
+ id<NSTextViewDelegate> Mydelegate;
+ mResolvedFirstResponder = static_cast<NSResponder*>(Mydelegate);
+}
+
diff --git a/test/SemaObjCXX/vla.mm b/test/SemaObjCXX/vla.mm
index 9c6fc54f817a..d6da1c0cf40e 100644
--- a/test/SemaObjCXX/vla.mm
+++ b/test/SemaObjCXX/vla.mm
@@ -6,7 +6,7 @@
@end
void test(Data *d) {
- char buffer[[d length]]; // expected-error{{variable length arrays are not permitted in C++}}
+ char buffer[[d length]];
[d getData:buffer];
}
diff --git a/test/SemaObjCXX/void_to_obj.mm b/test/SemaObjCXX/void_to_obj.mm
index 52510c84f139..7dca9faa8544 100644
--- a/test/SemaObjCXX/void_to_obj.mm
+++ b/test/SemaObjCXX/void_to_obj.mm
@@ -9,3 +9,18 @@ void func() {
obj = vv; // expected-error{{assigning to 'XX *' from incompatible type 'void *'}}
}
+
+// <rdar://problem/7952457>
+@interface I
+{
+ void* delegate;
+}
+- (I*) Meth;
+- (I*) Meth1;
+@end
+
+@implementation I
+- (I*) Meth { return static_cast<I*>(delegate); }
+- (I*) Meth1 { return reinterpret_cast<I*>(delegate); }
+@end
+
diff --git a/test/SemaTemplate/attributes.cpp b/test/SemaTemplate/attributes.cpp
new file mode 100644
index 000000000000..b696c5cd9840
--- /dev/null
+++ b/test/SemaTemplate/attributes.cpp
@@ -0,0 +1,8 @@
+// RUN: %clang_cc1 -fsyntax-only -verify %s
+
+template<int N>
+struct X {
+ struct __attribute__((__aligned__((N)))) Aligned { }; // expected-error{{'aligned' attribute requires integer constant}}
+
+ int __attribute__((__address_space__(N))) *ptr; // expected-error{{attribute requires 1 argument(s)}}
+};
diff --git a/test/SemaTemplate/current-instantiation.cpp b/test/SemaTemplate/current-instantiation.cpp
index 45637484f0fd..c631dd71d174 100644
--- a/test/SemaTemplate/current-instantiation.cpp
+++ b/test/SemaTemplate/current-instantiation.cpp
@@ -151,3 +151,16 @@ struct X1 {
X1<T*>::a = b;
}
};
+
+namespace ConstantInCurrentInstantiation {
+ template<typename T>
+ struct X {
+ static const int value = 2;
+ static int array[value];
+ };
+
+ template<typename T> const int X<T>::value;
+
+ template<typename T>
+ int X<T>::array[X<T>::value] = { 1, 2 };
+}
diff --git a/test/SemaTemplate/dependent-base-classes.cpp b/test/SemaTemplate/dependent-base-classes.cpp
index d0dd9c98fa71..e64d62301ea2 100644
--- a/test/SemaTemplate/dependent-base-classes.cpp
+++ b/test/SemaTemplate/dependent-base-classes.cpp
@@ -6,7 +6,7 @@ struct X0 : T::template apply<U> {
};
template<typename T, typename U>
-struct X1 : T::apply<U> { }; // expected-error{{missing 'template' keyword prior to dependent template name 'T::apply'}}
+struct X1 : T::apply<U> { }; // expected-error{{use 'template' keyword to treat 'apply' as a dependent template name}}
template<typename T>
struct X2 : vector<T> { }; // expected-error{{unknown template name 'vector'}}
diff --git a/test/SemaTemplate/dependent-expr.cpp b/test/SemaTemplate/dependent-expr.cpp
index 3f481b513691..9fa757107bdb 100644
--- a/test/SemaTemplate/dependent-expr.cpp
+++ b/test/SemaTemplate/dependent-expr.cpp
@@ -24,3 +24,19 @@ namespace PR6045 {
(void)(k % member);
}
}
+
+namespace PR7198 {
+ struct A
+ {
+ ~A() { }
+ };
+
+ template<typename T>
+ struct B {
+ struct C : A {};
+ void f()
+ {
+ C c = C();
+ }
+ };
+}
diff --git a/test/SemaTemplate/dependent-template-recover.cpp b/test/SemaTemplate/dependent-template-recover.cpp
new file mode 100644
index 000000000000..e91ffb52539c
--- /dev/null
+++ b/test/SemaTemplate/dependent-template-recover.cpp
@@ -0,0 +1,18 @@
+// RUN: %clang_cc1 -fsyntax-only -verify %s
+template<typename T, typename U, int N>
+struct X {
+ void f(T* t) {
+ t->f0<U>(); // expected-error{{use 'template' keyword to treat 'f0' as a dependent template name}}
+ t->f0<int>(); // expected-error{{use 'template' keyword to treat 'f0' as a dependent template name}}
+
+ t->operator+<U const, 1>(); // expected-error{{use 'template' keyword to treat 'operator +' as a dependent template name}}
+ t->f1<int const, 2>(); // expected-error{{use 'template' keyword to treat 'f1' as a dependent template name}}
+
+ T::getAs<U>(); // expected-error{{use 'template' keyword to treat 'getAs' as a dependent template name}}
+ t->T::getAs<U>(); // expected-error{{use 'template' keyword to treat 'getAs' as a dependent template name}}
+
+ // FIXME: We can't recover from these yet
+ (*t).f2<N>(); // expected-error{{expected expression}}
+ (*t).f2<0>(); // expected-error{{expected expression}}
+ }
+};
diff --git a/test/SemaTemplate/dependent-type-identity.cpp b/test/SemaTemplate/dependent-type-identity.cpp
index e09581223af6..feffdcf36959 100644
--- a/test/SemaTemplate/dependent-type-identity.cpp
+++ b/test/SemaTemplate/dependent-type-identity.cpp
@@ -70,3 +70,19 @@ struct X1 {
void f8(typename N::X2<U>::template apply<T> *);
void f8(typename ::Nalias::X2<type>::template apply<U_type> *); // expected-error{{redeclar}}
};
+
+namespace PR6851 {
+ template <bool v>
+ struct S;
+
+ struct N {
+ template <bool w>
+ S< S<w>::cond && 1 > foo();
+ };
+
+ struct Alien;
+ bool operator&&(const Alien&, const Alien&);
+
+ template <bool w>
+ S< S<w>::cond && 1 > N::foo() { }
+}
diff --git a/test/SemaTemplate/enum-argument.cpp b/test/SemaTemplate/enum-argument.cpp
index de89487bd581..7d237570678f 100644
--- a/test/SemaTemplate/enum-argument.cpp
+++ b/test/SemaTemplate/enum-argument.cpp
@@ -21,3 +21,16 @@ struct X0 {
};
X0<int> x0i;
+
+namespace rdar8020920 {
+ template<typename T>
+ struct X {
+ enum { e0 = 32 };
+
+ unsigned long long bitfield : e0;
+
+ void f(int j) {
+ bitfield + j;
+ }
+ };
+}
diff --git a/test/SemaTemplate/instantiate-anonymous-union.cpp b/test/SemaTemplate/instantiate-anonymous-union.cpp
index 7c75885788de..255454b2ebf2 100644
--- a/test/SemaTemplate/instantiate-anonymous-union.cpp
+++ b/test/SemaTemplate/instantiate-anonymous-union.cpp
@@ -29,3 +29,21 @@ template <typename T> struct C {
};
C<int> c0(0);
+
+namespace PR7088 {
+ template<typename T>
+ void f() {
+ union {
+ int a;
+ union {
+ float real;
+ T d;
+ };
+ };
+
+ a = 17;
+ d = 3.14;
+ }
+
+ template void f<double>();
+}
diff --git a/test/SemaTemplate/instantiate-attr.cpp b/test/SemaTemplate/instantiate-attr.cpp
index 7fb173645932..e8291ed00d20 100644
--- a/test/SemaTemplate/instantiate-attr.cpp
+++ b/test/SemaTemplate/instantiate-attr.cpp
@@ -2,6 +2,12 @@
template <typename T>
struct A {
char a __attribute__((aligned(16)));
+
+ struct B {
+ typedef T __attribute__((aligned(16))) i16;
+ i16 x;
+ };
};
int a[sizeof(A<int>) == 16 ? 1 : -1];
+int a2[sizeof(A<int>::B) == 16 ? 1 : -1];
diff --git a/test/SemaTemplate/instantiate-complete.cpp b/test/SemaTemplate/instantiate-complete.cpp
index d854c9e6aacc..c13930d108c4 100644
--- a/test/SemaTemplate/instantiate-complete.cpp
+++ b/test/SemaTemplate/instantiate-complete.cpp
@@ -99,3 +99,32 @@ namespace TemporaryObjectCopy {
template void f(int);
}
+
+namespace PR7080 {
+ template <class T, class U>
+ class X
+ {
+ typedef char true_t;
+ class false_t { char dummy[2]; };
+ static true_t dispatch(U);
+ static false_t dispatch(...);
+ static T trigger();
+ public:
+ enum { value = sizeof(dispatch(trigger())) == sizeof(true_t) };
+ };
+
+ template <class T>
+ class rv : public T
+ { };
+
+ bool x = X<int, rv<int>&>::value;
+}
+
+namespace pr7199 {
+ template <class T> class A; // expected-note {{template is declared here}}
+ template <class T> class B {
+ class A<T>::C field; // expected-error {{implicit instantiation of undefined template 'pr7199::A<int>'}}
+ };
+
+ template class B<int>; // expected-note {{in instantiation}}
+}
diff --git a/test/SemaTemplate/instantiate-declref-ice.cpp b/test/SemaTemplate/instantiate-declref-ice.cpp
index e88b49447cb9..0f3c08b05620 100644
--- a/test/SemaTemplate/instantiate-declref-ice.cpp
+++ b/test/SemaTemplate/instantiate-declref-ice.cpp
@@ -31,5 +31,4 @@ struct X1 {
template<typename T>
const unsigned X1<T>::value = sizeof(T);
-int array3[X1<int>::value == sizeof(int)? 1 : -1]; // expected-error{{variable length arrays are not permitted in C++}} \
-// expected-error{{variable length array declaration not allowed at file scope}}
+int array3[X1<int>::value == sizeof(int)? 1 : -1]; // expected-error{{variable length array declaration not allowed at file scope}}
diff --git a/test/SemaTemplate/instantiate-expr-2.cpp b/test/SemaTemplate/instantiate-expr-2.cpp
index b91b398a80e3..eaa68ddea901 100644
--- a/test/SemaTemplate/instantiate-expr-2.cpp
+++ b/test/SemaTemplate/instantiate-expr-2.cpp
@@ -194,6 +194,37 @@ namespace N12 {
void f0(int **a) { C::f0(a); }
}
+namespace PR7202 {
+ template<typename U, typename T>
+ struct meta {
+ typedef T type;
+ };
+
+ struct X {
+ struct dummy;
+
+ template<typename T>
+ X(T, typename meta<T, dummy*>::type = 0);
+
+ template<typename T, typename A>
+ X(T, A);
+ };
+
+ template<typename T>
+ struct Z { };
+
+ template<typename T> Z<T> g(T);
+
+ struct Y {
+ template<typename T>
+ void f(T t) {
+ new X(g(*this));
+ }
+ };
+
+ template void Y::f(int);
+}
+
namespace N13 {
class A{
A(const A&);
diff --git a/test/SemaTemplate/instantiate-expr-3.cpp b/test/SemaTemplate/instantiate-expr-3.cpp
index 41a96a32e0bf..d506b19a7a97 100644
--- a/test/SemaTemplate/instantiate-expr-3.cpp
+++ b/test/SemaTemplate/instantiate-expr-3.cpp
@@ -63,7 +63,7 @@ template struct Conditional0<int, int, int>;
template<typename T>
struct StatementExpr0 {
void f(T t) {
- (void)({ if (t) t = t + 17; t + 12;}); // expected-error{{invalid}}
+ (void)({ if (t) t = t + 17; t + 12;}); // expected-error{{contextually convertible}}
}
};
diff --git a/test/SemaTemplate/instantiate-field.cpp b/test/SemaTemplate/instantiate-field.cpp
index 60d4b21cac9e..a260635778ca 100644
--- a/test/SemaTemplate/instantiate-field.cpp
+++ b/test/SemaTemplate/instantiate-field.cpp
@@ -26,3 +26,58 @@ void test2(const X<float> *xf) {
void test3(const X<int(int)> *xf) {
(void)xf->x; // expected-note{{in instantiation of template class 'X<int (int)>' requested here}}
}
+
+namespace PR7123 {
+ template <class > struct requirement_;
+
+ template <void(*)()> struct instantiate
+ { };
+
+ template <class > struct requirement ;
+ struct failed ;
+
+ template <class Model> struct requirement<failed *Model::*>
+ {
+ static void failed()
+ {
+ ((Model*)0)->~Model(); // expected-note{{in instantiation of}}
+ }
+ };
+
+ template <class Model> struct requirement_<void(*)(Model)> : requirement<failed *Model::*>
+ { };
+
+ template <int> struct Requires_
+ { typedef void type; };
+
+ template <class Model> struct usage_requirements
+ {
+ ~usage_requirements()
+ {((Model*)0)->~Model(); } // expected-note{{in instantiation of}}
+ };
+
+ template < typename TT > struct BidirectionalIterator
+ {
+ enum
+ { value = 0 };
+
+ instantiate< requirement_<void(*)(usage_requirements<BidirectionalIterator>)>::failed> int534; // expected-note{{in instantiation of}}
+
+ ~BidirectionalIterator()
+ { i--; } // expected-error{{cannot decrement value of type 'PR7123::X'}}
+
+ TT i;
+ };
+
+ struct X
+ { };
+
+ template<typename RanIter>
+ typename Requires_< BidirectionalIterator<RanIter>::value >::type sort(RanIter,RanIter){}
+
+ void f()
+ {
+ X x;
+ sort(x,x);
+ }
+}
diff --git a/test/SemaTemplate/instantiate-function-2.cpp b/test/SemaTemplate/instantiate-function-2.cpp
index 6318facfc0ea..afca35878444 100644
--- a/test/SemaTemplate/instantiate-function-2.cpp
+++ b/test/SemaTemplate/instantiate-function-2.cpp
@@ -10,3 +10,13 @@ void f() {
S<int> s1;
S<int> s2(10);
}
+
+namespace PR7184 {
+ template<typename T>
+ void f() {
+ typedef T type;
+ void g(int array[sizeof(type)]);
+ }
+
+ template void f<int>();
+}
diff --git a/test/SemaTemplate/instantiate-member-pointers.cpp b/test/SemaTemplate/instantiate-member-pointers.cpp
index 2308ac541b2e..dca0f6217054 100644
--- a/test/SemaTemplate/instantiate-member-pointers.cpp
+++ b/test/SemaTemplate/instantiate-member-pointers.cpp
@@ -53,3 +53,15 @@ void accept_X4(X4<Member>);
void test_accept_X4(X4<&Y::x> x4) {
accept_X4(x4);
}
+
+namespace ValueDepMemberPointer {
+ template <void (*)()> struct instantiate_function {};
+ template <typename T> struct S {
+ static void instantiate();
+ typedef instantiate_function<&S::instantiate> x; // expected-note{{instantiation}}
+ };
+ template <typename T> void S<T>::instantiate() {
+ int a[(int)sizeof(T)-42]; // expected-error{{array size is negative}}
+ }
+ S<int> s;
+}
diff --git a/test/SemaTemplate/instantiate-non-dependent-types.cpp b/test/SemaTemplate/instantiate-non-dependent-types.cpp
new file mode 100644
index 000000000000..a0005c56675a
--- /dev/null
+++ b/test/SemaTemplate/instantiate-non-dependent-types.cpp
@@ -0,0 +1,14 @@
+// RUN: %clang_cc1 -fsyntax-only -verify %s
+template<typename T>
+struct X1 {
+ static void member() { T* x = 1; } // expected-error{{cannot initialize a variable of type 'int *' with an rvalue of type 'int'}}
+};
+
+template<void(*)()> struct instantiate { };
+
+template<typename T>
+struct X2 {
+ typedef instantiate<&X1<int>::member> i; // expected-note{{in instantiation of}}
+};
+
+X2<int> x;
diff --git a/test/SemaTemplate/instantiate-overload-candidates.cpp b/test/SemaTemplate/instantiate-overload-candidates.cpp
new file mode 100644
index 000000000000..5b7e60dccfdd
--- /dev/null
+++ b/test/SemaTemplate/instantiate-overload-candidates.cpp
@@ -0,0 +1,21 @@
+// RUN: %clang_cc1 -fsyntax-only -verify %s
+
+// This is the function actually selected during overload resolution, and the
+// only one defined.
+template <typename T> void f(T*, int) {}
+
+template <typename T> struct S;
+template <typename T> struct S_ : S<T> { typedef int type; }; // expected-note{{in instantiation}}
+template <typename T> struct S {
+ // Force T to have a complete type here so we can observe instantiations with
+ // incomplete types.
+ T t; // expected-error{{field has incomplete type}}
+};
+
+// Provide a bad class and an overload that instantiates templates with it.
+class NoDefinition; // expected-note{{forward declaration}}
+template <typename T> S_<NoDefinition>::type f(T*, NoDefinition*); // expected-note{{in instantiation}}
+
+void test(int x) {
+ f(&x, 0);
+}
diff --git a/test/SemaTemplate/nested-name-spec-template.cpp b/test/SemaTemplate/nested-name-spec-template.cpp
index 9d25a051e8a8..54e615b4ab69 100644
--- a/test/SemaTemplate/nested-name-spec-template.cpp
+++ b/test/SemaTemplate/nested-name-spec-template.cpp
@@ -64,3 +64,10 @@ namespace test1 {
template <class T>
T pair<T>::* const pair<T>::mem_array[2] = { &pair<T>::x, &pair<T>::y };
}
+
+typedef int T;
+namespace N1 {
+ template<typename T> T f0();
+}
+
+template<typename T> T N1::f0() { }
diff --git a/test/SemaTemplate/overload-candidates.cpp b/test/SemaTemplate/overload-candidates.cpp
new file mode 100644
index 000000000000..8762cc80630a
--- /dev/null
+++ b/test/SemaTemplate/overload-candidates.cpp
@@ -0,0 +1,40 @@
+// RUN: %clang_cc1 -fsyntax-only -verify %s
+
+template<typename T>
+const T& min(const T&, const T&); // expected-note{{candidate template ignored: deduced conflicting types for parameter 'T' ('int' vs. 'long')}}
+
+void test_min() {
+ (void)min(1, 2l); // expected-error{{no matching function for call to 'min'}}
+}
+
+template<typename R, typename T>
+R *dyn_cast(const T&); // expected-note{{candidate template ignored: couldn't infer template argument 'R'}}
+
+void test_dyn_cast(int* ptr) {
+ (void)dyn_cast(ptr); // expected-error{{no matching function for call to 'dyn_cast'}}
+}
+
+template<int I, typename T>
+ void get(const T&); // expected-note{{candidate template ignored: invalid explicitly-specified argument for template parameter 'I'}}
+template<template<class T> class, typename T>
+ void get(const T&); // expected-note{{candidate template ignored: invalid explicitly-specified argument for 1st template parameter}}
+
+void test_get(void *ptr) {
+ get<int>(ptr); // expected-error{{no matching function for call to 'get'}}
+}
+
+template<typename T>
+ typename T::type get_type(const T&); // expected-note{{candidate template ignored: substitution failure [with T = int *]}}
+
+void test_get_type(int *ptr) {
+ (void)get_type(ptr); // expected-error{{no matching function for call to 'get_type'}}
+}
+
+struct X {
+ template<typename T>
+ const T& min(const T&, const T&); // expected-note{{candidate template ignored: deduced conflicting types for parameter 'T' ('int' vs. 'long')}}
+};
+
+void test_X_min(X x) {
+ (void)x.min(1, 2l); // expected-error{{no matching member function for call to 'min'}}
+}
diff --git a/test/SemaTemplate/partial-spec-instantiate.cpp b/test/SemaTemplate/partial-spec-instantiate.cpp
index 3156892a7234..68b4964816e4 100644
--- a/test/SemaTemplate/partial-spec-instantiate.cpp
+++ b/test/SemaTemplate/partial-spec-instantiate.cpp
@@ -18,3 +18,23 @@ struct X2<U*> {
};
void a(char *a, char *b) {X2<char*>::f();}
+
+namespace WonkyAccess {
+ template<typename T>
+ struct X {
+ int m;
+ };
+
+ template<typename U>
+ class Y;
+
+ template<typename U>
+ struct Y<U*> : X<U> { };
+
+ template<>
+ struct Y<float*> : X<float> { };
+
+ int f(Y<int*> y, Y<float*> y2) {
+ return y.m + y2.m;
+ }
+}
diff --git a/test/SemaTemplate/temp_explicit.cpp b/test/SemaTemplate/temp_explicit.cpp
index fbb41ff601a3..76244c25e824 100644
--- a/test/SemaTemplate/temp_explicit.cpp
+++ b/test/SemaTemplate/temp_explicit.cpp
@@ -1,4 +1,4 @@
-// RUN: %clang_cc1 -fsyntax-only -pedantic -verify %s
+// RUN: %clang_cc1 -fsyntax-only -verify -pedantic -Wc++0x-compat %s
//
// Tests explicit instantiation of templates.
template<typename T, typename U = T> class X0 { };
@@ -125,3 +125,27 @@ template <> // expected-warning{{extraneous template parameter list}}
template <>
struct Foo<int>::Bar<void>
{};
+
+namespace N1 {
+
+ template<typename T> struct X7 { }; // expected-note{{here}}
+
+ namespace Inner {
+ template<typename T> struct X8 { };
+ }
+
+ template struct X7<int>;
+ template struct Inner::X8<int>;
+}
+
+template<typename T> struct X9 { }; // expected-note{{here}}
+
+template struct ::N1::Inner::X8<float>;
+
+namespace N2 {
+ using namespace N1;
+
+ template struct X7<double>; // expected-warning{{must occur in namespace}}
+
+ template struct X9<float>; // expected-warning{{must occur in the global}}
+}
diff --git a/test/SemaTemplate/template-id-expr.cpp b/test/SemaTemplate/template-id-expr.cpp
index b3f41be7bfad..de8d7f6c91a4 100644
--- a/test/SemaTemplate/template-id-expr.cpp
+++ b/test/SemaTemplate/template-id-expr.cpp
@@ -44,3 +44,41 @@ struct X {
};
template struct X<3>;
+
+// 'template' as a disambiguator.
+// PR7030
+struct Y0 {
+ template<typename U>
+ void f1(U);
+
+ template<typename U>
+ static void f2(U);
+
+ void f3(int);
+
+ static int f4(int);
+ template<typename U>
+ static void f4(U);
+
+ template<typename U>
+ void f() {
+ Y0::template f1<U>(0);
+ Y0::template f1(0);
+ this->template f1(0);
+
+ Y0::template f2<U>(0);
+ Y0::template f2(0);
+
+ Y0::template f3(0); // expected-error {{'f3' following the 'template' keyword does not refer to a template}}
+ Y0::template f3(); // expected-error {{'f3' following the 'template' keyword does not refer to a template}}
+
+ int x;
+ x = Y0::f4(0);
+ x = Y0::f4<int>(0); // expected-error {{assigning to 'int' from incompatible type 'void'}}
+ x = Y0::template f4(0); // expected-error {{assigning to 'int' from incompatible type 'void'}}
+
+ x = this->f4(0);
+ x = this->f4<int>(0); // expected-error {{assigning to 'int' from incompatible type 'void'}}
+ x = this->template f4(0); // expected-error {{assigning to 'int' from incompatible type 'void'}}
+ }
+};
diff --git a/test/SemaTemplate/unused-variables.cpp b/test/SemaTemplate/unused-variables.cpp
new file mode 100644
index 000000000000..1b9350b865dc
--- /dev/null
+++ b/test/SemaTemplate/unused-variables.cpp
@@ -0,0 +1,21 @@
+// RUN: %clang_cc1 -fsyntax-only -Wunused -verify %s
+
+struct X0 {
+ ~X0();
+};
+
+struct X1 { };
+
+template<typename T>
+void f() {
+ X0 x0;
+ X1 x1; // expected-warning{{unused variable 'x1'}}
+}
+
+template<typename T, typename U>
+void g() {
+ T t;
+ U u; // expected-warning{{unused variable 'u'}}
+}
+
+template void g<X0, X1>(); // expected-note{{in instantiation of}}
diff --git a/test/SemaTemplate/virtual-member-functions.cpp b/test/SemaTemplate/virtual-member-functions.cpp
index 59df3c22aa1c..974f66484ba1 100644
--- a/test/SemaTemplate/virtual-member-functions.cpp
+++ b/test/SemaTemplate/virtual-member-functions.cpp
@@ -3,7 +3,7 @@
namespace PR5557 {
template <class T> struct A {
A();
- virtual void anchor(); // expected-note{{instantiation}}
+ virtual void anchor();
virtual int a(T x);
};
template<class T> A<T>::A() {}
@@ -14,7 +14,7 @@ template<class T> int A<T>::a(T x) {
}
void f(A<int> x) {
- x.anchor();
+ x.anchor(); // expected-note{{instantiation}}
}
template<typename T>
@@ -43,7 +43,7 @@ template struct Derived<int>; // expected-note {{in instantiation of member func
template<typename T>
struct HasOutOfLineKey {
- HasOutOfLineKey() { } // expected-note{{in instantiation of member function 'HasOutOfLineKey<int>::f' requested here}}
+ HasOutOfLineKey() { }
virtual T *f(float *fp);
};
@@ -52,4 +52,35 @@ T *HasOutOfLineKey<T>::f(float *fp) {
return fp; // expected-error{{cannot initialize return object of type 'int *' with an lvalue of type 'float *'}}
}
-HasOutOfLineKey<int> out_of_line;
+HasOutOfLineKey<int> out_of_line; // expected-note{{in instantiation of member function 'HasOutOfLineKey<int>::f' requested here}}
+
+namespace std {
+ class type_info;
+}
+
+namespace PR7114 {
+ class A { virtual ~A(); }; // expected-note{{declared private here}}
+
+ template<typename T>
+ class B {
+ public:
+ class Inner : public A { }; // expected-error{{base class 'PR7114::A' has private destructor}}
+ static Inner i;
+ static const unsigned value = sizeof(i) == 4;
+ };
+
+ int f() { return B<int>::value; }
+
+ void test_typeid(B<float>::Inner bfi) {
+ (void)typeid(bfi); // expected-note{{implicit default destructor}}
+ }
+
+ template<typename T>
+ struct X : A {
+ void f() { }
+ };
+
+ void test_X(X<int> xi, X<float> xf) {
+ xi.f();
+ }
+}
diff --git a/tools/c-index-test/c-index-test.c b/tools/c-index-test/c-index-test.c
index 494181675c5a..4268cec1b231 100644
--- a/tools/c-index-test/c-index-test.c
+++ b/tools/c-index-test/c-index-test.c
@@ -447,6 +447,31 @@ static enum CXChildVisitResult PrintLinkage(CXCursor cursor, CXCursor p,
}
/******************************************************************************/
+/* Typekind testing. */
+/******************************************************************************/
+
+static enum CXChildVisitResult PrintTypeKind(CXCursor cursor, CXCursor p,
+ CXClientData d) {
+
+ if (!clang_isInvalid(clang_getCursorKind(cursor))) {
+ CXType T = clang_getCursorType(cursor);
+ CXType CT = clang_getCanonicalType(T);
+ CXString S = clang_getTypeKindSpelling(T.kind);
+ PrintCursor(cursor);
+ printf(" typekind=%s", clang_getCString(S));
+ if (!clang_equalTypes(T, CT)) {
+ CXString CS = clang_getTypeKindSpelling(CT.kind);
+ printf(" [canonical=%s]", clang_getCString(CS));
+ clang_disposeString(CS);
+ }
+ clang_disposeString(S);
+ printf("\n");
+ }
+ return CXChildVisit_Recurse;
+}
+
+
+/******************************************************************************/
/* Loading ASTs/source. */
/******************************************************************************/
@@ -757,7 +782,8 @@ void print_completion_result(CXCompletionResult *completion_result,
clang_disposeString(ks);
print_completion_string(completion_result->CompletionString, file);
- fprintf(file, "\n");
+ fprintf(file, " (%u)\n",
+ clang_getCompletionPriority(completion_result->CompletionString));
}
int perform_code_completion(int argc, const char **argv) {
@@ -1179,6 +1205,7 @@ static void print_usage(void) {
" 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"
+ " c-index-test -test-print-typekind {<args>}*\n"
" c-index-test -print-usr [<CursorKind> {<args>}]*\n"
" c-index-test -print-usr-file <file>\n\n"
" <symbol filter> values:\n%s",
@@ -1223,6 +1250,9 @@ 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 > 2 && strcmp(argv[1], "-test-print-typekind") == 0)
+ return perform_test_load_source(argc - 2, argv + 2, "all",
+ PrintTypeKind, 0);
else if (argc > 1 && strcmp(argv[1], "-print-usr") == 0) {
if (argc > 2)
return print_usrs(argv + 2, argv + argc);
diff --git a/tools/driver/CMakeLists.txt b/tools/driver/CMakeLists.txt
index ca2f4081aa9f..706f05051c52 100644
--- a/tools/driver/CMakeLists.txt
+++ b/tools/driver/CMakeLists.txt
@@ -26,6 +26,7 @@ set( LLVM_LINK_COMPONENTS
add_clang_executable(clang
driver.cpp
cc1_main.cpp
+ cc1as_main.cpp
)
if(UNIX)
diff --git a/tools/driver/cc1_main.cpp b/tools/driver/cc1_main.cpp
index 144a734b151d..ac19e9393c5b 100644
--- a/tools/driver/cc1_main.cpp
+++ b/tools/driver/cc1_main.cpp
@@ -1,4 +1,4 @@
-//===-- cc1_main.cpp - Clang CC1 Driver -----------------------------------===//
+//===-- cc1_main.cpp - Clang CC1 Compiler Frontend ------------------------===//
//
// The LLVM Compiler Infrastructure
//
@@ -43,7 +43,7 @@ using namespace clang;
// Main driver
//===----------------------------------------------------------------------===//
-void LLVMErrorHandler(void *UserData, const std::string &Message) {
+static void LLVMErrorHandler(void *UserData, const std::string &Message) {
Diagnostic &Diags = *static_cast<Diagnostic*>(UserData);
Diags.Report(diag::err_fe_error_backend) << Message;
@@ -63,6 +63,7 @@ static FrontendAction *CreateFrontendBaseAction(CompilerInstance &CI) {
case ASTPrint: return new ASTPrintAction();
case ASTPrintXML: return new ASTPrintXMLAction();
case ASTView: return new ASTViewAction();
+ case BoostCon: return new BoostConAction();
case DumpRawTokens: return new DumpRawTokensAction();
case DumpTokens: return new DumpTokensAction();
case EmitAssembly: return new EmitAssemblyAction();
@@ -70,6 +71,7 @@ static FrontendAction *CreateFrontendBaseAction(CompilerInstance &CI) {
case EmitHTML: return new HTMLPrintAction();
case EmitLLVM: return new EmitLLVMAction();
case EmitLLVMOnly: return new EmitLLVMOnlyAction();
+ case EmitCodeGenOnly: return new EmitCodeGenOnlyAction();
case EmitObj: return new EmitObjAction();
case FixIt: return new FixItAction();
case GeneratePCH: return new GeneratePCHAction();
diff --git a/tools/driver/cc1as_main.cpp b/tools/driver/cc1as_main.cpp
new file mode 100644
index 000000000000..5f1ee092ba4f
--- /dev/null
+++ b/tools/driver/cc1as_main.cpp
@@ -0,0 +1,373 @@
+//===-- cc1as_main.cpp - Clang Assembler ---------------------------------===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+//
+// This is the entry point to the clang -cc1as functionality, which implements
+// the direct interface to the LLVM MC based assembler.
+//
+//===----------------------------------------------------------------------===//
+
+#include "clang/Basic/Diagnostic.h"
+#include "clang/Driver/Arg.h"
+#include "clang/Driver/ArgList.h"
+#include "clang/Driver/DriverDiagnostic.h"
+#include "clang/Driver/CC1AsOptions.h"
+#include "clang/Driver/OptTable.h"
+#include "clang/Driver/Options.h"
+#include "clang/Frontend/DiagnosticOptions.h"
+#include "clang/Frontend/FrontendDiagnostic.h"
+#include "clang/Frontend/TextDiagnosticPrinter.h"
+#include "llvm/ADT/OwningPtr.h"
+#include "llvm/ADT/StringSwitch.h"
+#include "llvm/MC/MCParser/AsmParser.h"
+#include "llvm/MC/MCCodeEmitter.h"
+#include "llvm/MC/MCContext.h"
+#include "llvm/MC/MCStreamer.h"
+#include "llvm/Support/CommandLine.h"
+#include "llvm/Support/FormattedStream.h"
+#include "llvm/Support/ErrorHandling.h"
+#include "llvm/Support/ManagedStatic.h"
+#include "llvm/Support/MemoryBuffer.h"
+#include "llvm/Support/PrettyStackTrace.h"
+#include "llvm/Support/SourceMgr.h"
+#include "llvm/Support/Timer.h"
+#include "llvm/Support/raw_ostream.h"
+#include "llvm/System/Host.h"
+#include "llvm/System/Path.h"
+#include "llvm/System/Signals.h"
+#include "llvm/Target/TargetAsmBackend.h"
+#include "llvm/Target/TargetAsmParser.h"
+#include "llvm/Target/TargetData.h"
+#include "llvm/Target/TargetMachine.h"
+#include "llvm/Target/TargetRegistry.h"
+#include "llvm/Target/TargetSelect.h"
+using namespace clang;
+using namespace clang::driver;
+using namespace llvm;
+
+namespace {
+
+/// \brief Helper class for representing a single invocation of the assembler.
+struct AssemblerInvocation {
+ /// @name Target Options
+ /// @{
+
+ std::string Triple;
+
+ /// @}
+ /// @name Language Options
+ /// @{
+
+ std::vector<std::string> IncludePaths;
+ unsigned NoInitialTextSection : 1;
+
+ /// @}
+ /// @name Frontend Options
+ /// @{
+
+ std::string InputFile;
+ std::vector<std::string> LLVMArgs;
+ std::string OutputPath;
+ enum FileType {
+ FT_Asm, ///< Assembly (.s) output, transliterate mode.
+ FT_Null, ///< No output, for timing purposes.
+ FT_Obj ///< Object file output.
+ };
+ FileType OutputType;
+ unsigned ShowHelp : 1;
+ unsigned ShowVersion : 1;
+
+ /// @}
+ /// @name Transliterate Options
+ /// @{
+
+ unsigned OutputAsmVariant;
+ unsigned ShowEncoding : 1;
+ unsigned ShowInst : 1;
+
+ /// @}
+ /// @name Assembler Options
+ /// @{
+
+ unsigned RelaxAll : 1;
+
+ /// @}
+
+public:
+ AssemblerInvocation() {
+ Triple = "";
+ NoInitialTextSection = 0;
+ InputFile = "-";
+ OutputPath = "-";
+ OutputType = FT_Asm;
+ OutputAsmVariant = 0;
+ ShowInst = 0;
+ ShowEncoding = 0;
+ RelaxAll = 0;
+ }
+
+ static void CreateFromArgs(AssemblerInvocation &Res, const char **ArgBegin,
+ const char **ArgEnd, Diagnostic &Diags);
+};
+
+}
+
+void AssemblerInvocation::CreateFromArgs(AssemblerInvocation &Opts,
+ const char **ArgBegin,
+ const char **ArgEnd,
+ Diagnostic &Diags) {
+ using namespace clang::driver::cc1asoptions;
+ // Parse the arguments.
+ OwningPtr<OptTable> OptTbl(createCC1AsOptTable());
+ unsigned MissingArgIndex, MissingArgCount;
+ OwningPtr<InputArgList> Args(
+ OptTbl->ParseArgs(ArgBegin, ArgEnd,MissingArgIndex, MissingArgCount));
+
+ // Check for missing argument error.
+ if (MissingArgCount)
+ Diags.Report(diag::err_drv_missing_argument)
+ << Args->getArgString(MissingArgIndex) << MissingArgCount;
+
+ // Issue errors on unknown arguments.
+ for (arg_iterator it = Args->filtered_begin(cc1asoptions::OPT_UNKNOWN),
+ ie = Args->filtered_end(); it != ie; ++it)
+ Diags.Report(diag::err_drv_unknown_argument) << it->getAsString(*Args);
+
+ // Construct the invocation.
+
+ // Target Options
+ Opts.Triple = Args->getLastArgValue(OPT_triple);
+ if (Opts.Triple.empty()) // Use the host triple if unspecified.
+ Opts.Triple = sys::getHostTriple();
+
+ // Language Options
+ Opts.IncludePaths = Args->getAllArgValues(OPT_I);
+ Opts.NoInitialTextSection = Args->hasArg(OPT_n);
+
+ // Frontend Options
+ if (Args->hasArg(OPT_INPUT)) {
+ bool First = true;
+ for (arg_iterator it = Args->filtered_begin(OPT_INPUT),
+ ie = Args->filtered_end(); it != ie; ++it, First=false) {
+ if (First)
+ Opts.InputFile = it->getValue(*Args);
+ else
+ Diags.Report(diag::err_drv_unknown_argument) << it->getAsString(*Args);
+ }
+ }
+ Opts.LLVMArgs = Args->getAllArgValues(OPT_mllvm);
+ Opts.OutputPath = Args->getLastArgValue(OPT_o);
+ if (Arg *A = Args->getLastArg(OPT_filetype)) {
+ StringRef Name = A->getValue(*Args);
+ unsigned OutputType = StringSwitch<unsigned>(Name)
+ .Case("asm", FT_Asm)
+ .Case("null", FT_Null)
+ .Case("obj", FT_Obj)
+ .Default(~0U);
+ if (OutputType == ~0U)
+ Diags.Report(diag::err_drv_invalid_value)
+ << A->getAsString(*Args) << Name;
+ else
+ Opts.OutputType = FileType(OutputType);
+ }
+ Opts.ShowHelp = Args->hasArg(OPT_help);
+ Opts.ShowVersion = Args->hasArg(OPT_version);
+
+ // Transliterate Options
+ Opts.OutputAsmVariant = Args->getLastArgIntValue(OPT_output_asm_variant,
+ 0, Diags);
+ Opts.ShowEncoding = Args->hasArg(OPT_show_encoding);
+ Opts.ShowInst = Args->hasArg(OPT_show_inst);
+
+ // Assemble Options
+ Opts.RelaxAll = Args->hasArg(OPT_relax_all);
+}
+
+static formatted_raw_ostream *GetOutputStream(AssemblerInvocation &Opts,
+ Diagnostic &Diags,
+ bool Binary) {
+ if (Opts.OutputPath.empty())
+ Opts.OutputPath = "-";
+
+ // Make sure that the Out file gets unlinked from the disk if we get a
+ // SIGINT.
+ if (Opts.OutputPath != "-")
+ sys::RemoveFileOnSignal(sys::Path(Opts.OutputPath));
+
+ std::string Error;
+ raw_fd_ostream *Out =
+ new raw_fd_ostream(Opts.OutputPath.c_str(), Error,
+ (Binary ? raw_fd_ostream::F_Binary : 0));
+ if (!Error.empty()) {
+ Diags.Report(diag::err_fe_unable_to_open_output)
+ << Opts.OutputPath << Error;
+ return 0;
+ }
+
+ return new formatted_raw_ostream(*Out, formatted_raw_ostream::DELETE_STREAM);
+}
+
+static bool ExecuteAssembler(AssemblerInvocation &Opts, Diagnostic &Diags) {
+ // Get the target specific parser.
+ std::string Error;
+ const Target *TheTarget(TargetRegistry::lookupTarget(Opts.Triple, Error));
+ if (!TheTarget) {
+ Diags.Report(diag::err_target_unknown_triple) << Opts.Triple;
+ return false;
+ }
+
+ MemoryBuffer *Buffer = MemoryBuffer::getFileOrSTDIN(Opts.InputFile, &Error);
+ if (Buffer == 0) {
+ Diags.Report(diag::err_fe_error_reading) << Opts.InputFile;
+ return false;
+ }
+
+ SourceMgr SrcMgr;
+
+ // Tell SrcMgr about this buffer, which is what the parser will pick up.
+ SrcMgr.AddNewSourceBuffer(Buffer, SMLoc());
+
+ // Record the location of the include directories so that the lexer can find
+ // it later.
+ SrcMgr.setIncludeDirs(Opts.IncludePaths);
+
+ OwningPtr<MCAsmInfo> MAI(TheTarget->createAsmInfo(Opts.Triple));
+ assert(MAI && "Unable to create target asm info!");
+
+ MCContext Ctx(*MAI);
+ bool IsBinary = Opts.OutputType == AssemblerInvocation::FT_Obj;
+ formatted_raw_ostream *Out = GetOutputStream(Opts, Diags, IsBinary);
+ if (!Out)
+ return false;
+
+ // FIXME: We shouldn't need to do this (and link in codegen).
+ OwningPtr<TargetMachine> TM(TheTarget->createTargetMachine(Opts.Triple, ""));
+ if (!TM) {
+ Diags.Report(diag::err_target_unknown_triple) << Opts.Triple;
+ return false;
+ }
+
+ OwningPtr<MCCodeEmitter> CE;
+ OwningPtr<MCStreamer> Str;
+ OwningPtr<TargetAsmBackend> TAB;
+
+ if (Opts.OutputType == AssemblerInvocation::FT_Asm) {
+ MCInstPrinter *IP =
+ TheTarget->createMCInstPrinter(Opts.OutputAsmVariant, *MAI);
+ if (Opts.ShowEncoding)
+ CE.reset(TheTarget->createCodeEmitter(*TM, Ctx));
+ Str.reset(createAsmStreamer(Ctx, *Out,TM->getTargetData()->isLittleEndian(),
+ /*asmverbose*/true, IP, CE.get(),
+ Opts.ShowInst));
+ } else if (Opts.OutputType == AssemblerInvocation::FT_Null) {
+ Str.reset(createNullStreamer(Ctx));
+ } else {
+ assert(Opts.OutputType == AssemblerInvocation::FT_Obj &&
+ "Invalid file type!");
+ CE.reset(TheTarget->createCodeEmitter(*TM, Ctx));
+ TAB.reset(TheTarget->createAsmBackend(Opts.Triple));
+ Str.reset(createMachOStreamer(Ctx, *TAB, *Out, CE.get(), Opts.RelaxAll));
+ }
+
+ AsmParser Parser(SrcMgr, Ctx, *Str.get(), *MAI);
+ OwningPtr<TargetAsmParser> TAP(TheTarget->createAsmParser(Parser));
+ if (!TAP) {
+ Diags.Report(diag::err_target_unknown_triple) << Opts.Triple;
+ return false;
+ }
+
+ Parser.setTargetParser(*TAP.get());
+
+ bool Success = !Parser.Run(Opts.NoInitialTextSection);
+
+ // Close the output.
+ delete Out;
+
+ // Delete output on errors.
+ if (!Success && Opts.OutputPath != "-")
+ sys::Path(Opts.OutputPath).eraseFromDisk();
+
+ return Success;
+}
+
+static void LLVMErrorHandler(void *UserData, const std::string &Message) {
+ Diagnostic &Diags = *static_cast<Diagnostic*>(UserData);
+
+ Diags.Report(diag::err_fe_error_backend) << Message;
+
+ // We cannot recover from llvm errors.
+ exit(1);
+}
+
+int cc1as_main(const char **ArgBegin, const char **ArgEnd,
+ const char *Argv0, void *MainAddr) {
+ // Print a stack trace if we signal out.
+ sys::PrintStackTraceOnErrorSignal();
+ PrettyStackTraceProgram X(ArgEnd - ArgBegin, ArgBegin);
+ llvm_shutdown_obj Y; // Call llvm_shutdown() on exit.
+
+ // Initialize targets and assembly printers/parsers.
+ InitializeAllTargetInfos();
+ // FIXME: We shouldn't need to initialize the Target(Machine)s.
+ InitializeAllTargets();
+ InitializeAllAsmPrinters();
+ InitializeAllAsmParsers();
+
+ // Construct our diagnostic client.
+ TextDiagnosticPrinter DiagClient(errs(), DiagnosticOptions());
+ DiagClient.setPrefix("clang -cc1as");
+ Diagnostic Diags(&DiagClient);
+
+ // Set an error handler, so that any LLVM backend diagnostics go through our
+ // error handler.
+ install_fatal_error_handler(LLVMErrorHandler,
+ static_cast<void*>(&Diags));
+
+ // Parse the arguments.
+ AssemblerInvocation Asm;
+ AssemblerInvocation::CreateFromArgs(Asm, ArgBegin, ArgEnd, Diags);
+
+ // Honor -help.
+ if (Asm.ShowHelp) {
+ llvm::OwningPtr<driver::OptTable> Opts(driver::createCC1AsOptTable());
+ Opts->PrintHelp(llvm::outs(), "clang -cc1as", "Clang Integrated Assembler");
+ return 0;
+ }
+
+ // Honor -version.
+ //
+ // FIXME: Use a better -version message?
+ if (Asm.ShowVersion) {
+ llvm::cl::PrintVersionMessage();
+ return 0;
+ }
+
+ // Honor -mllvm.
+ //
+ // FIXME: Remove this, one day.
+ if (!Asm.LLVMArgs.empty()) {
+ unsigned NumArgs = Asm.LLVMArgs.size();
+ const char **Args = new const char*[NumArgs + 2];
+ Args[0] = "clang (LLVM option parsing)";
+ for (unsigned i = 0; i != NumArgs; ++i)
+ Args[i + 1] = Asm.LLVMArgs[i].c_str();
+ Args[NumArgs + 1] = 0;
+ llvm::cl::ParseCommandLineOptions(NumArgs + 1, const_cast<char **>(Args));
+ }
+
+ // Execute the invocation, unless there were parsing errors.
+ bool Success = false;
+ if (!Diags.getNumErrors())
+ Success = ExecuteAssembler(Asm, Diags);
+
+ // If any timers were active but haven't been destroyed yet, print their
+ // results now.
+ TimerGroup::printAll(errs());
+
+ return !Success;
+}
diff --git a/tools/driver/driver.cpp b/tools/driver/driver.cpp
index 3f1cca1f887a..c4b12cba0f7a 100644
--- a/tools/driver/driver.cpp
+++ b/tools/driver/driver.cpp
@@ -170,15 +170,28 @@ static void ApplyQAOverride(std::vector<const char*> &Args,
extern int cc1_main(const char **ArgBegin, const char **ArgEnd,
const char *Argv0, void *MainAddr);
+extern int cc1as_main(const char **ArgBegin, const char **ArgEnd,
+ const char *Argv0, void *MainAddr);
int main(int argc, const char **argv) {
llvm::sys::PrintStackTraceOnErrorSignal();
llvm::PrettyStackTraceProgram X(argc, argv);
- // Dispatch to cc1_main if appropriate.
- if (argc > 1 && llvm::StringRef(argv[1]) == "-cc1")
- return cc1_main(argv+2, argv+argc, argv[0],
- (void*) (intptr_t) GetExecutablePath);
+ // Handle -cc1 integrated tools.
+ if (argc > 1 && llvm::StringRef(argv[1]).startswith("-cc1")) {
+ llvm::StringRef Tool = argv[1] + 4;
+
+ if (Tool == "")
+ return cc1_main(argv+2, argv+argc, argv[0],
+ (void*) (intptr_t) GetExecutablePath);
+ if (Tool == "as")
+ return cc1as_main(argv+2, argv+argc, argv[0],
+ (void*) (intptr_t) GetExecutablePath);
+
+ // Reject unknown tools.
+ llvm::errs() << "error: unknown integrated tool '" << Tool << "'\n";
+ return 1;
+ }
bool CanonicalPrefixes = true;
for (int i = 1; i < argc; ++i) {
diff --git a/tools/libclang/CIndex.cpp b/tools/libclang/CIndex.cpp
index f9f735113f7a..a077589c8f79 100644
--- a/tools/libclang/CIndex.cpp
+++ b/tools/libclang/CIndex.cpp
@@ -44,11 +44,11 @@ using namespace clang::cxstring;
// Crash Reporting.
//===----------------------------------------------------------------------===//
-#ifdef __APPLE__
-#define USE_CRASHTRACER
+#ifdef USE_CRASHTRACER
#include "clang/Analysis/Support/SaveAndRestore.h"
// Integrate with crash reporter.
-extern "C" const char *__crashreporter_info__;
+static const char *__crashreporter_info__ = 0;
+asm(".desc ___crashreporter_info__, 0x10");
#define NUM_CRASH_STRINGS 32
static unsigned crashtracer_counter = 0;
static unsigned crashtracer_counter_id[NUM_CRASH_STRINGS] = { 0 };
@@ -152,6 +152,23 @@ static RangeComparisonResult RangeCompare(SourceManager &SM,
return RangeOverlap;
}
+/// \brief Determine if a source location falls within, before, or after a
+/// a given source range.
+static RangeComparisonResult LocationCompare(SourceManager &SM,
+ SourceLocation L, SourceRange R) {
+ assert(R.isValid() && "First range is invalid?");
+ assert(L.isValid() && "Second range is invalid?");
+ if (L == R.getBegin())
+ return RangeOverlap;
+ if (L == R.getEnd())
+ return RangeAfter;
+ if (SM.isBeforeInTranslationUnit(L, R.getBegin()))
+ return RangeBefore;
+ if (SM.isBeforeInTranslationUnit(R.getEnd(), L))
+ return RangeAfter;
+ return RangeOverlap;
+}
+
/// \brief Translate a Clang source range into a CIndex source range.
///
/// Clang internally represents ranges where the end location points to the
@@ -222,6 +239,27 @@ class CursorVisitor : public DeclVisitor<CursorVisitor, bool>,
/// \param R a half-open source range retrieved from the abstract syntax tree.
RangeComparisonResult CompareRegionOfInterest(SourceRange R);
+ class SetParentRAII {
+ CXCursor &Parent;
+ Decl *&StmtParent;
+ CXCursor OldParent;
+
+ public:
+ SetParentRAII(CXCursor &Parent, Decl *&StmtParent, CXCursor NewParent)
+ : Parent(Parent), StmtParent(StmtParent), OldParent(Parent)
+ {
+ Parent = NewParent;
+ if (clang_isDeclaration(Parent.kind))
+ StmtParent = getCursorDecl(Parent);
+ }
+
+ ~SetParentRAII() {
+ Parent = OldParent;
+ if (clang_isDeclaration(Parent.kind))
+ StmtParent = getCursorDecl(Parent);
+ }
+ };
+
public:
CursorVisitor(ASTUnit *TU, CXCursorVisitor Visitor, CXClientData ClientData,
unsigned MaxPCHLevel,
@@ -259,6 +297,7 @@ public:
bool VisitObjCContainerDecl(ObjCContainerDecl *D);
bool VisitObjCCategoryDecl(ObjCCategoryDecl *ND);
bool VisitObjCProtocolDecl(ObjCProtocolDecl *PID);
+ bool VisitObjCPropertyDecl(ObjCPropertyDecl *PD);
bool VisitObjCInterfaceDecl(ObjCInterfaceDecl *D);
bool VisitObjCImplDecl(ObjCImplDecl *D);
bool VisitObjCCategoryImplDecl(ObjCCategoryImplDecl *D);
@@ -268,6 +307,8 @@ public:
// FIXME: ObjCCompatibleAliasDecl requires aliased-class locations.
bool VisitObjCForwardProtocolDecl(ObjCForwardProtocolDecl *D);
bool VisitObjCClassDecl(ObjCClassDecl *D);
+ bool VisitLinkageSpecDecl(LinkageSpecDecl *D);
+ bool VisitNamespaceDecl(NamespaceDecl *D);
// Type visitors
// FIXME: QualifiedTypeLoc doesn't provide any location information
@@ -277,6 +318,7 @@ public:
bool VisitTagTypeLoc(TagTypeLoc TL);
// FIXME: TemplateTypeParmTypeLoc doesn't provide any location information
bool VisitObjCInterfaceTypeLoc(ObjCInterfaceTypeLoc TL);
+ bool VisitObjCObjectTypeLoc(ObjCObjectTypeLoc TL);
bool VisitObjCObjectPointerTypeLoc(ObjCObjectPointerTypeLoc TL);
bool VisitPointerTypeLoc(PointerTypeLoc TL);
bool VisitBlockPointerTypeLoc(BlockPointerTypeLoc TL);
@@ -297,8 +339,10 @@ public:
// FIXME: LabelStmt label?
bool VisitIfStmt(IfStmt *S);
bool VisitSwitchStmt(SwitchStmt *S);
+ bool VisitCaseStmt(CaseStmt *S);
bool VisitWhileStmt(WhileStmt *S);
bool VisitForStmt(ForStmt *S);
+// bool VisitSwitchCase(SwitchCase *S);
// Expression visitors
bool VisitBlockExpr(BlockExpr *B);
@@ -417,26 +461,7 @@ bool CursorVisitor::VisitChildren(CXCursor Cursor) {
// Set the Parent field to Cursor, then back to its old value once we're
// done.
- class SetParentRAII {
- CXCursor &Parent;
- Decl *&StmtParent;
- CXCursor OldParent;
-
- public:
- SetParentRAII(CXCursor &Parent, Decl *&StmtParent, CXCursor NewParent)
- : Parent(Parent), StmtParent(StmtParent), OldParent(Parent)
- {
- Parent = NewParent;
- if (clang_isDeclaration(Parent.kind))
- StmtParent = getCursorDecl(Parent);
- }
-
- ~SetParentRAII() {
- Parent = OldParent;
- if (clang_isDeclaration(Parent.kind))
- StmtParent = getCursorDecl(Parent);
- }
- } SetParent(Parent, StmtParent, Cursor);
+ SetParentRAII SetParent(Parent, StmtParent, Cursor);
if (clang_isDeclaration(Cursor.kind)) {
Decl *D = getCursorDecl(Cursor);
@@ -504,7 +529,11 @@ bool CursorVisitor::VisitDeclContext(DeclContext *DC) {
for (DeclContext::decl_iterator
I = DC->decls_begin(), E = DC->decls_end(); I != E; ++I) {
- CXCursor Cursor = MakeCXCursor(*I, TU);
+ Decl *D = *I;
+ if (D->getLexicalDeclContext() != DC)
+ continue;
+
+ CXCursor Cursor = MakeCXCursor(D, TU);
if (RegionOfInterest.isValid()) {
SourceRange Range =
@@ -642,6 +671,40 @@ bool CursorVisitor::VisitObjCProtocolDecl(ObjCProtocolDecl *PID) {
return VisitObjCContainerDecl(PID);
}
+bool CursorVisitor::VisitObjCPropertyDecl(ObjCPropertyDecl *PD) {
+ // FIXME: This implements a workaround with @property declarations also being
+ // installed in the DeclContext for the @interface. Eventually this code
+ // should be removed.
+ ObjCCategoryDecl *CDecl = dyn_cast<ObjCCategoryDecl>(PD->getDeclContext());
+ if (!CDecl || !CDecl->IsClassExtension())
+ return false;
+
+ ObjCInterfaceDecl *ID = CDecl->getClassInterface();
+ if (!ID)
+ return false;
+
+ IdentifierInfo *PropertyId = PD->getIdentifier();
+ ObjCPropertyDecl *prevDecl =
+ ObjCPropertyDecl::findPropertyDecl(cast<DeclContext>(ID), PropertyId);
+
+ if (!prevDecl)
+ return false;
+
+ // Visit synthesized methods since they will be skipped when visiting
+ // the @interface.
+ if (ObjCMethodDecl *MD = prevDecl->getGetterMethodDecl())
+ if (MD->isSynthesized())
+ if (Visit(MakeCXCursor(MD, TU)))
+ return true;
+
+ if (ObjCMethodDecl *MD = prevDecl->getSetterMethodDecl())
+ if (MD->isSynthesized())
+ if (Visit(MakeCXCursor(MD, TU)))
+ return true;
+
+ return false;
+}
+
bool CursorVisitor::VisitObjCInterfaceDecl(ObjCInterfaceDecl *D) {
// Issue callbacks for super class.
if (D->getSuperClass() &&
@@ -705,6 +768,14 @@ bool CursorVisitor::VisitObjCClassDecl(ObjCClassDecl *D) {
return false;
}
+bool CursorVisitor::VisitNamespaceDecl(NamespaceDecl *D) {
+ return VisitDeclContext(D);
+}
+
+bool CursorVisitor::VisitLinkageSpecDecl(LinkageSpecDecl *D) {
+ return VisitDeclContext(D);
+}
+
bool CursorVisitor::VisitBuiltinTypeLoc(BuiltinTypeLoc TL) {
ASTContext &Context = TU->getASTContext();
@@ -780,6 +851,13 @@ bool CursorVisitor::VisitObjCInterfaceTypeLoc(ObjCInterfaceTypeLoc TL) {
if (Visit(MakeCursorObjCClassRef(TL.getIFaceDecl(), TL.getNameLoc(), TU)))
return true;
+ return false;
+}
+
+bool CursorVisitor::VisitObjCObjectTypeLoc(ObjCObjectTypeLoc TL) {
+ if (TL.hasBaseTypeAsWritten() && Visit(TL.getBaseLoc()))
+ return true;
+
for (unsigned I = 0, N = TL.getNumProtocols(); I != N; ++I) {
if (Visit(MakeCursorObjCProtocolRef(TL.getProtocol(I), TL.getProtocolLoc(I),
TU)))
@@ -790,19 +868,7 @@ bool CursorVisitor::VisitObjCInterfaceTypeLoc(ObjCInterfaceTypeLoc TL) {
}
bool CursorVisitor::VisitObjCObjectPointerTypeLoc(ObjCObjectPointerTypeLoc TL) {
- if (TL.hasBaseTypeAsWritten() && Visit(TL.getBaseTypeLoc()))
- return true;
-
- if (TL.hasProtocolsAsWritten()) {
- for (unsigned I = 0, N = TL.getNumProtocols(); I != N; ++I) {
- if (Visit(MakeCursorObjCProtocolRef(TL.getProtocol(I),
- TL.getProtocolLoc(I),
- TU)))
- return true;
- }
- }
-
- return false;
+ return Visit(TL.getPointeeLoc());
}
bool CursorVisitor::VisitPointerTypeLoc(PointerTypeLoc TL) {
@@ -861,13 +927,60 @@ bool CursorVisitor::VisitTypeOfTypeLoc(TypeOfTypeLoc TL) {
bool CursorVisitor::VisitStmt(Stmt *S) {
for (Stmt::child_iterator Child = S->child_begin(), ChildEnd = S->child_end();
Child != ChildEnd; ++Child) {
- if (*Child && Visit(MakeCXCursor(*Child, StmtParent, TU)))
- return true;
+ if (Stmt *C = *Child)
+ if (Visit(MakeCXCursor(C, StmtParent, TU)))
+ return true;
}
return false;
}
+bool CursorVisitor::VisitCaseStmt(CaseStmt *S) {
+ // Specially handle CaseStmts because they can be nested, e.g.:
+ //
+ // case 1:
+ // case 2:
+ //
+ // In this case the second CaseStmt is the child of the first. Walking
+ // these recursively can blow out the stack.
+ CXCursor Cursor = MakeCXCursor(S, StmtParent, TU);
+ while (true) {
+ // Set the Parent field to Cursor, then back to its old value once we're
+ // done.
+ SetParentRAII SetParent(Parent, StmtParent, Cursor);
+
+ if (Stmt *LHS = S->getLHS())
+ if (Visit(MakeCXCursor(LHS, StmtParent, TU)))
+ return true;
+ if (Stmt *RHS = S->getRHS())
+ if (Visit(MakeCXCursor(RHS, StmtParent, TU)))
+ return true;
+ if (Stmt *SubStmt = S->getSubStmt()) {
+ if (!isa<CaseStmt>(SubStmt))
+ return Visit(MakeCXCursor(SubStmt, StmtParent, TU));
+
+ // Specially handle 'CaseStmt' so that we don't blow out the stack.
+ CaseStmt *CS = cast<CaseStmt>(SubStmt);
+ Cursor = MakeCXCursor(CS, StmtParent, TU);
+ if (RegionOfInterest.isValid()) {
+ SourceRange Range = CS->getSourceRange();
+ if (Range.isInvalid() || CompareRegionOfInterest(Range))
+ return false;
+ }
+
+ switch (Visitor(Cursor, Parent, ClientData)) {
+ case CXChildVisit_Break: return true;
+ case CXChildVisit_Continue: return false;
+ case CXChildVisit_Recurse:
+ // Perform tail-recursion manually.
+ S = CS;
+ continue;
+ }
+ }
+ return false;
+ }
+}
+
bool CursorVisitor::VisitDeclStmt(DeclStmt *S) {
for (DeclStmt::decl_iterator D = S->decl_begin(), DEnd = S->decl_end();
D != DEnd; ++D) {
@@ -1089,8 +1202,6 @@ clang_createTranslationUnitFromSourceFile(CXIndex CIdx,
RemappedFiles.size(),
/*CaptureDiagnostics=*/true));
- // FIXME: Until we have broader testing, just drop the entire AST if we
- // encountered an error.
if (NumErrors != Diags->getNumErrors()) {
// Make sure to check that 'Unit' is non-NULL.
if (CXXIdx->getDisplayDiagnostics() && Unit.get()) {
@@ -1368,6 +1479,16 @@ CXSourceLocation clang_getRangeEnd(CXSourceRange range) {
return Result;
}
+unsigned clang_isFromMainFile(CXSourceLocation loc) {
+ SourceLocation Loc = SourceLocation::getFromRawEncoding(loc.int_data);
+ if (!loc.ptr_data[0] || Loc.isInvalid())
+ return 0;
+
+ const SourceManager &SM =
+ *static_cast<const SourceManager*>(loc.ptr_data[0]);
+ return SM.isFromMainFile(Loc) ? 1 : 0;
+}
+
} // end: extern "C"
//===----------------------------------------------------------------------===//
@@ -1474,10 +1595,11 @@ static CXString getDeclSpelling(Decl *D) {
// ObjCCategoryImplDecl returns the category name.
return createCXString(CIMP->getIdentifier()->getNameStart());
- if (ND->getIdentifier())
- return createCXString(ND->getIdentifier()->getNameStart());
-
- return createCXString("");
+ llvm::SmallString<1024> S;
+ llvm::raw_svector_ostream os(S);
+ ND->printName(os);
+
+ return createCXString(os.str());
}
CXString clang_getCursorSpelling(CXCursor C) {
@@ -1615,12 +1737,18 @@ CXString clang_getCursorKindSpelling(enum CXCursorKind Kind) {
return createCXString("attribute(ibaction)");
case CXCursor_IBOutletAttr:
return createCXString("attribute(iboutlet)");
+ case CXCursor_IBOutletCollectionAttr:
+ return createCXString("attribute(iboutletcollection)");
case CXCursor_PreprocessingDirective:
return createCXString("preprocessing directive");
case CXCursor_MacroDefinition:
return createCXString("macro definition");
case CXCursor_MacroInstantiation:
return createCXString("macro instantiation");
+ case CXCursor_Namespace:
+ return createCXString("Namespace");
+ case CXCursor_LinkageSpec:
+ return createCXString("LinkageSpec");
}
llvm_unreachable("Unhandled CXCursorKind");
@@ -1763,7 +1891,7 @@ CXSourceLocation clang_getCursorLocation(CXCursor C) {
return cxloc::translateSourceLocation(getCursorContext(C), L);
}
- if (!getCursorDecl(C))
+ if (C.kind < CXCursor_FirstDecl || C.kind > CXCursor_LastDecl)
return clang_getNullLocation();
Decl *D = getCursorDecl(C);
@@ -1829,7 +1957,7 @@ CXSourceRange clang_getCursorExtent(CXCursor C) {
return cxloc::translateSourceRange(getCursorContext(C), R);
}
- if (!getCursorDecl(C))
+ if (C.kind < CXCursor_FirstDecl || C.kind > CXCursor_LastDecl)
return clang_getNullRange();
Decl *D = getCursorDecl(C);
@@ -2286,9 +2414,15 @@ void clang_tokenize(CXTranslationUnit TU, CXSourceRange Range,
const char *StartPos = Buf.data() + LocInfo.second;
IdentifierInfo *II
= CXXUnit->getPreprocessor().LookUpIdentifierInfo(Tok, StartPos);
- CXTok.int_data[0] = II->getTokenID() == tok::identifier?
- CXToken_Identifier
- : CXToken_Keyword;
+
+ if (II->getObjCKeywordID() != tok::objc_not_keyword) {
+ CXTok.int_data[0] = CXToken_Keyword;
+ }
+ else {
+ CXTok.int_data[0] = II->getTokenID() == tok::identifier?
+ CXToken_Identifier
+ : CXToken_Keyword;
+ }
CXTok.ptr_data = II;
} else if (Tok.is(tok::comment)) {
CXTok.int_data[0] = CXToken_Comment;
@@ -2308,62 +2442,214 @@ void clang_tokenize(CXTranslationUnit TU, CXSourceRange Range,
*NumTokens = CXTokens.size();
}
+void clang_disposeTokens(CXTranslationUnit TU,
+ CXToken *Tokens, unsigned NumTokens) {
+ free(Tokens);
+}
+
+} // end: extern "C"
+
+//===----------------------------------------------------------------------===//
+// Token annotation APIs.
+//===----------------------------------------------------------------------===//
+
typedef llvm::DenseMap<unsigned, CXCursor> AnnotateTokensData;
+static enum CXChildVisitResult AnnotateTokensVisitor(CXCursor cursor,
+ CXCursor parent,
+ CXClientData client_data);
+namespace {
+class AnnotateTokensWorker {
+ AnnotateTokensData &Annotated;
+ CXToken *Tokens;
+ CXCursor *Cursors;
+ unsigned NumTokens;
+ unsigned TokIdx;
+ CursorVisitor AnnotateVis;
+ SourceManager &SrcMgr;
+
+ bool MoreTokens() const { return TokIdx < NumTokens; }
+ unsigned NextToken() const { return TokIdx; }
+ void AdvanceToken() { ++TokIdx; }
+ SourceLocation GetTokenLoc(unsigned tokI) {
+ return SourceLocation::getFromRawEncoding(Tokens[tokI].int_data[1]);
+ }
-enum CXChildVisitResult AnnotateTokensVisitor(CXCursor cursor,
- CXCursor parent,
- CXClientData client_data) {
- AnnotateTokensData *Data = static_cast<AnnotateTokensData *>(client_data);
-
- // We only annotate the locations of declarations, simple
- // references, and expressions which directly reference something.
- CXCursorKind Kind = clang_getCursorKind(cursor);
- if (clang_isDeclaration(Kind) || clang_isReference(Kind)) {
- // Okay: We can annotate the location of this declaration with the
- // declaration or reference
- } else if (clang_isExpression(cursor.kind)) {
- if (Kind != CXCursor_DeclRefExpr &&
- Kind != CXCursor_MemberRefExpr &&
- Kind != CXCursor_ObjCMessageExpr)
- return CXChildVisit_Recurse;
-
- CXCursor Referenced = clang_getCursorReferenced(cursor);
- if (Referenced == cursor || Referenced == clang_getNullCursor())
- return CXChildVisit_Recurse;
-
- // Okay: we can annotate the location of this expression
- } else if (clang_isPreprocessing(cursor.kind)) {
- // We can always annotate a preprocessing directive/macro instantiation.
- } else {
- // Nothing to annotate
- return CXChildVisit_Recurse;
+public:
+ AnnotateTokensWorker(AnnotateTokensData &annotated,
+ CXToken *tokens, CXCursor *cursors, unsigned numTokens,
+ ASTUnit *CXXUnit, SourceRange RegionOfInterest)
+ : Annotated(annotated), Tokens(tokens), Cursors(cursors),
+ NumTokens(numTokens), TokIdx(0),
+ AnnotateVis(CXXUnit, AnnotateTokensVisitor, this,
+ Decl::MaxPCHLevel, RegionOfInterest),
+ SrcMgr(CXXUnit->getSourceManager()) {}
+
+ void VisitChildren(CXCursor C) { AnnotateVis.VisitChildren(C); }
+ enum CXChildVisitResult Visit(CXCursor cursor, CXCursor parent);
+ void AnnotateTokens(CXCursor parent);
+};
+}
+
+void AnnotateTokensWorker::AnnotateTokens(CXCursor parent) {
+ // Walk the AST within the region of interest, annotating tokens
+ // along the way.
+ VisitChildren(parent);
+
+ for (unsigned I = 0 ; I < TokIdx ; ++I) {
+ AnnotateTokensData::iterator Pos = Annotated.find(Tokens[I].int_data[1]);
+ if (Pos != Annotated.end())
+ Cursors[I] = Pos->second;
}
+ // Finish up annotating any tokens left.
+ if (!MoreTokens())
+ return;
+
+ const CXCursor &C = clang_getNullCursor();
+ for (unsigned I = TokIdx ; I < NumTokens ; ++I) {
+ AnnotateTokensData::iterator Pos = Annotated.find(Tokens[I].int_data[1]);
+ Cursors[I] = (Pos == Annotated.end()) ? C : Pos->second;
+ }
+}
+
+enum CXChildVisitResult
+AnnotateTokensWorker::Visit(CXCursor cursor, CXCursor parent) {
CXSourceLocation Loc = clang_getCursorLocation(cursor);
- (*Data)[Loc.int_data] = cursor;
- return CXChildVisit_Recurse;
+ // We can always annotate a preprocessing directive/macro instantiation.
+ if (clang_isPreprocessing(cursor.kind)) {
+ Annotated[Loc.int_data] = cursor;
+ return CXChildVisit_Recurse;
+ }
+
+ CXSourceRange cursorExtent = clang_getCursorExtent(cursor);
+ SourceRange cursorRange = cxloc::translateCXSourceRange(cursorExtent);
+
+ if (cursorRange.isInvalid())
+ return CXChildVisit_Continue;
+
+ SourceLocation L = SourceLocation::getFromRawEncoding(Loc.int_data);
+
+ // Adjust the annotated range based specific declarations.
+ const enum CXCursorKind cursorK = clang_getCursorKind(cursor);
+ if (cursorK >= CXCursor_FirstDecl && cursorK <= CXCursor_LastDecl) {
+ Decl *D = cxcursor::getCursorDecl(cursor);
+ // Don't visit synthesized ObjC methods, since they have no syntatic
+ // representation in the source.
+ if (const ObjCMethodDecl *MD = dyn_cast<ObjCMethodDecl>(D)) {
+ if (MD->isSynthesized())
+ return CXChildVisit_Continue;
+ }
+ if (const DeclaratorDecl *DD = dyn_cast<DeclaratorDecl>(D)) {
+ if (TypeSourceInfo *TI = DD->getTypeSourceInfo()) {
+ TypeLoc TL = TI->getTypeLoc();
+ SourceLocation TLoc = TL.getSourceRange().getBegin();
+ if (TLoc.isValid() &&
+ SrcMgr.isBeforeInTranslationUnit(TLoc, L))
+ cursorRange.setBegin(TLoc);
+ }
+ }
+ }
+
+ const enum CXCursorKind K = clang_getCursorKind(parent);
+ const CXCursor updateC =
+ (clang_isInvalid(K) || K == CXCursor_TranslationUnit ||
+ L.isMacroID())
+ ? clang_getNullCursor() : parent;
+
+ while (MoreTokens()) {
+ const unsigned I = NextToken();
+ SourceLocation TokLoc = GetTokenLoc(I);
+ switch (LocationCompare(SrcMgr, TokLoc, cursorRange)) {
+ case RangeBefore:
+ Cursors[I] = updateC;
+ AdvanceToken();
+ continue;
+ case RangeAfter:
+ return CXChildVisit_Continue;
+ case RangeOverlap:
+ break;
+ }
+ break;
+ }
+
+ // Visit children to get their cursor information.
+ const unsigned BeforeChildren = NextToken();
+ VisitChildren(cursor);
+ const unsigned AfterChildren = NextToken();
+
+ // Adjust 'Last' to the last token within the extent of the cursor.
+ while (MoreTokens()) {
+ const unsigned I = NextToken();
+ SourceLocation TokLoc = GetTokenLoc(I);
+ switch (LocationCompare(SrcMgr, TokLoc, cursorRange)) {
+ case RangeBefore:
+ assert(0 && "Infeasible");
+ case RangeAfter:
+ break;
+ case RangeOverlap:
+ Cursors[I] = updateC;
+ AdvanceToken();
+ continue;
+ }
+ break;
+ }
+ const unsigned Last = NextToken();
+
+ // Scan the tokens that are at the beginning of the cursor, but are not
+ // capture by the child cursors.
+
+ // For AST elements within macros, rely on a post-annotate pass to
+ // to correctly annotate the tokens with cursors. Otherwise we can
+ // get confusing results of having tokens that map to cursors that really
+ // are expanded by an instantiation.
+ if (L.isMacroID())
+ cursor = clang_getNullCursor();
+
+ for (unsigned I = BeforeChildren; I != AfterChildren; ++I) {
+ if (!clang_isInvalid(clang_getCursorKind(Cursors[I])))
+ break;
+ Cursors[I] = cursor;
+ }
+ // Scan the tokens that are at the end of the cursor, but are not captured
+ // but the child cursors.
+ for (unsigned I = AfterChildren; I != Last; ++I)
+ Cursors[I] = cursor;
+
+ TokIdx = Last;
+ return CXChildVisit_Continue;
}
+static enum CXChildVisitResult AnnotateTokensVisitor(CXCursor cursor,
+ CXCursor parent,
+ CXClientData client_data) {
+ return static_cast<AnnotateTokensWorker*>(client_data)->Visit(cursor, parent);
+}
+
+extern "C" {
+
void clang_annotateTokens(CXTranslationUnit TU,
CXToken *Tokens, unsigned NumTokens,
CXCursor *Cursors) {
- if (NumTokens == 0)
- return;
- // Any token we don't specifically annotate will have a NULL cursor.
- for (unsigned I = 0; I != NumTokens; ++I)
- Cursors[I] = clang_getNullCursor();
+ if (NumTokens == 0 || !Tokens || !Cursors)
+ return;
ASTUnit *CXXUnit = static_cast<ASTUnit *>(TU);
- if (!CXXUnit || !Tokens)
+ if (!CXXUnit) {
+ // Any token we don't specifically annotate will have a NULL cursor.
+ const CXCursor &C = clang_getNullCursor();
+ for (unsigned I = 0; I != NumTokens; ++I)
+ Cursors[I] = C;
return;
+ }
ASTUnit::ConcurrencyCheck Check(*CXXUnit);
// Determine the region of interest, which contains all of the tokens.
SourceRange RegionOfInterest;
- RegionOfInterest.setBegin(
- cxloc::translateSourceLocation(clang_getTokenLocation(TU, Tokens[0])));
+ RegionOfInterest.setBegin(cxloc::translateSourceLocation(
+ clang_getTokenLocation(TU, Tokens[0])));
+
SourceLocation End
= cxloc::translateSourceLocation(clang_getTokenLocation(TU,
Tokens[NumTokens - 1]));
@@ -2373,14 +2659,14 @@ void clang_annotateTokens(CXTranslationUnit TU,
// region of interest to the corresponding cursors.
AnnotateTokensData Annotated;
- // Relex the tokens within the source range to look for preprocessing
+ // Relex the tokens within the source range to look for preprocessing
// directives.
SourceManager &SourceMgr = CXXUnit->getSourceManager();
std::pair<FileID, unsigned> BeginLocInfo
= SourceMgr.getDecomposedLoc(RegionOfInterest.getBegin());
std::pair<FileID, unsigned> EndLocInfo
= SourceMgr.getDecomposedLoc(RegionOfInterest.getEnd());
-
+
llvm::StringRef Buffer;
bool Invalid = false;
if (BeginLocInfo.first == EndLocInfo.first &&
@@ -2388,16 +2674,16 @@ void clang_annotateTokens(CXTranslationUnit TU,
!Invalid) {
Lexer Lex(SourceMgr.getLocForStartOfFile(BeginLocInfo.first),
CXXUnit->getASTContext().getLangOptions(),
- Buffer.begin(), Buffer.data() + BeginLocInfo.second,
+ Buffer.begin(), Buffer.data() + BeginLocInfo.second,
Buffer.end());
Lex.SetCommentRetentionState(true);
-
- // Lex tokens in raw mode until we hit the end of the range, to avoid
+
+ // Lex tokens in raw mode until we hit the end of the range, to avoid
// entering #includes or expanding macros.
while (true) {
Token Tok;
Lex.LexFromRawLexer(Tok);
-
+
reprocess:
if (Tok.is(tok::hash) && Tok.isAtStartOfLine()) {
// We have found a preprocessing directive. Gobble it up so that we
@@ -2410,51 +2696,35 @@ void clang_annotateTokens(CXTranslationUnit TU,
std::vector<SourceLocation> Locations;
do {
Locations.push_back(Tok.getLocation());
- Lex.LexFromRawLexer(Tok);
+ Lex.LexFromRawLexer(Tok);
} while (!Tok.isAtStartOfLine() && !Tok.is(tok::eof));
-
+
using namespace cxcursor;
CXCursor Cursor
= MakePreprocessingDirectiveCursor(SourceRange(Locations.front(),
Locations.back()),
- CXXUnit);
+ CXXUnit);
for (unsigned I = 0, N = Locations.size(); I != N; ++I) {
Annotated[Locations[I].getRawEncoding()] = Cursor;
}
-
+
if (Tok.isAtStartOfLine())
goto reprocess;
-
+
continue;
}
-
+
if (Tok.is(tok::eof))
break;
}
}
-
- // Annotate all of the source locations in the region of interest that map to
- // a specific cursor.
- CXCursor Parent = clang_getTranslationUnitCursor(CXXUnit);
- CursorVisitor AnnotateVis(CXXUnit, AnnotateTokensVisitor, &Annotated,
- Decl::MaxPCHLevel, RegionOfInterest);
- AnnotateVis.VisitChildren(Parent);
-
- for (unsigned I = 0; I != NumTokens; ++I) {
- // Determine whether we saw a cursor at this token's location.
- AnnotateTokensData::iterator Pos = Annotated.find(Tokens[I].int_data[1]);
- if (Pos == Annotated.end())
- continue;
-
- Cursors[I] = Pos->second;
- }
-}
-void clang_disposeTokens(CXTranslationUnit TU,
- CXToken *Tokens, unsigned NumTokens) {
- free(Tokens);
+ // Annotate all of the source locations in the region of interest that map to
+ // a specific cursor.
+ AnnotateTokensWorker W(Annotated, Tokens, Cursors, NumTokens,
+ CXXUnit, RegionOfInterest);
+ W.AnnotateTokens(clang_getTranslationUnitCursor(CXXUnit));
}
-
} // end: extern "C"
//===----------------------------------------------------------------------===//
@@ -2540,6 +2810,21 @@ CXLanguageKind clang_getCursorLanguage(CXCursor cursor) {
}
} // end: extern "C"
+
+//===----------------------------------------------------------------------===//
+// C++ AST instrospection.
+//===----------------------------------------------------------------------===//
+
+extern "C" {
+unsigned clang_CXXMethod_isStatic(CXCursor C) {
+ if (!clang_isDeclaration(C.kind))
+ return 0;
+ CXXMethodDecl *D = dyn_cast<CXXMethodDecl>(cxcursor::getCursorDecl(C));
+ return (D && D->isStatic()) ? 1 : 0;
+}
+
+} // end: extern "C"
+
//===----------------------------------------------------------------------===//
// CXString Operations.
//===----------------------------------------------------------------------===//
diff --git a/tools/libclang/CIndexCodeCompletion.cpp b/tools/libclang/CIndexCodeCompletion.cpp
index a21614c74735..481a375fb839 100644
--- a/tools/libclang/CIndexCodeCompletion.cpp
+++ b/tools/libclang/CIndexCodeCompletion.cpp
@@ -37,12 +37,27 @@
using namespace clang;
using namespace clang::cxstring;
+namespace {
+ /// \brief Stored representation of a completion string.
+ ///
+ /// This is the representation behind a CXCompletionString.
+ class CXStoredCodeCompletionString : public CodeCompletionString {
+ unsigned Priority;
+
+ public:
+ CXStoredCodeCompletionString(unsigned Priority) : Priority(Priority) { }
+
+ unsigned getPriority() const { return Priority; }
+ };
+}
+
extern "C" {
enum CXCompletionChunkKind
clang_getCompletionChunkKind(CXCompletionString completion_string,
unsigned chunk_number) {
- CodeCompletionString *CCStr = (CodeCompletionString *)completion_string;
+ CXStoredCodeCompletionString *CCStr
+ = (CXStoredCodeCompletionString *)completion_string;
if (!CCStr || chunk_number >= CCStr->size())
return CXCompletionChunk_Text;
@@ -97,7 +112,8 @@ clang_getCompletionChunkKind(CXCompletionString completion_string,
CXString clang_getCompletionChunkText(CXCompletionString completion_string,
unsigned chunk_number) {
- CodeCompletionString *CCStr = (CodeCompletionString *)completion_string;
+ CXStoredCodeCompletionString *CCStr
+ = (CXStoredCodeCompletionString *)completion_string;
if (!CCStr || chunk_number >= CCStr->size())
return createCXString(0);
@@ -121,9 +137,12 @@ CXString clang_getCompletionChunkText(CXCompletionString completion_string,
case CodeCompletionString::CK_SemiColon:
case CodeCompletionString::CK_Equal:
case CodeCompletionString::CK_HorizontalSpace:
- case CodeCompletionString::CK_VerticalSpace:
return createCXString((*CCStr)[chunk_number].Text, false);
+ case CodeCompletionString::CK_VerticalSpace:
+ // FIXME: Temporary hack until we figure out how to handle vertical space.
+ return createCXString(" ");
+
case CodeCompletionString::CK_Optional:
// Note: treated as an empty text block.
return createCXString("");
@@ -137,7 +156,8 @@ CXString clang_getCompletionChunkText(CXCompletionString completion_string,
CXCompletionString
clang_getCompletionChunkCompletionString(CXCompletionString completion_string,
unsigned chunk_number) {
- CodeCompletionString *CCStr = (CodeCompletionString *)completion_string;
+ CXStoredCodeCompletionString *CCStr
+ = (CXStoredCodeCompletionString *)completion_string;
if (!CCStr || chunk_number >= CCStr->size())
return 0;
@@ -174,10 +194,17 @@ clang_getCompletionChunkCompletionString(CXCompletionString completion_string,
}
unsigned clang_getNumCompletionChunks(CXCompletionString completion_string) {
- CodeCompletionString *CCStr = (CodeCompletionString *)completion_string;
+ CXStoredCodeCompletionString *CCStr
+ = (CXStoredCodeCompletionString *)completion_string;
return CCStr? CCStr->size() : 0;
}
+unsigned clang_getCompletionPriority(CXCompletionString completion_string) {
+ CXStoredCodeCompletionString *CCStr
+ = (CXStoredCodeCompletionString *)completion_string;
+ return CCStr? CCStr->getPriority() : CCP_Unlikely;
+}
+
static bool ReadUnsigned(const char *&Memory, const char *MemoryEnd,
unsigned &Value) {
if (Memory + sizeof(unsigned) > MemoryEnd)
@@ -223,7 +250,7 @@ AllocatedCXCodeCompleteResults::AllocatedCXCodeCompleteResults()
AllocatedCXCodeCompleteResults::~AllocatedCXCodeCompleteResults() {
for (unsigned I = 0, N = NumResults; I != N; ++I)
- delete (CodeCompletionString *)Results[I].CompletionString;
+ delete (CXStoredCodeCompletionString *)Results[I].CompletionString;
delete [] Results;
delete Buffer;
@@ -373,10 +400,16 @@ CXCodeCompleteResults *clang_codeComplete(CXIndex CIdx,
if (ReadUnsigned(Str, StrEnd, KindValue))
break;
- CodeCompletionString *CCStr
- = CodeCompletionString::Deserialize(Str, StrEnd);
- if (!CCStr)
+ unsigned Priority;
+ if (ReadUnsigned(Str, StrEnd, Priority))
+ break;
+
+ CXStoredCodeCompletionString *CCStr
+ = new CXStoredCodeCompletionString(Priority);
+ if (!CCStr->Deserialize(Str, StrEnd)) {
+ delete CCStr;
continue;
+ }
if (!CCStr->empty()) {
// Vend the code-completion result to the caller.
diff --git a/tools/libclang/CIndexUSRs.cpp b/tools/libclang/CIndexUSRs.cpp
index f3c74e85316f..e98fd262a712 100644
--- a/tools/libclang/CIndexUSRs.cpp
+++ b/tools/libclang/CIndexUSRs.cpp
@@ -28,12 +28,33 @@ using namespace clang::cxstring;
namespace {
class USRGenerator : public DeclVisitor<USRGenerator> {
- llvm::raw_ostream &Out;
+ llvm::SmallString<1024> Buf;
+ llvm::raw_svector_ostream Out;
bool IgnoreResults;
ASTUnit *AU;
+ bool generatedLoc;
public:
- USRGenerator(ASTUnit *au, llvm::raw_ostream &out)
- : Out(out), IgnoreResults(false), AU(au) {}
+ USRGenerator(const CXCursor *C = 0)
+ : Out(Buf),
+ IgnoreResults(false),
+ AU(C ? cxcursor::getCursorASTUnit(*C) : 0),
+ generatedLoc(false)
+ {
+ // Add the USR space prefix.
+ Out << "c:";
+ }
+
+ llvm::StringRef str() {
+ return Out.str();
+ }
+
+ USRGenerator* operator->() { return this; }
+
+ template <typename T>
+ llvm::raw_svector_ostream &operator<<(const T &x) {
+ Out << x;
+ return Out;
+ }
bool ignoreResults() const { return IgnoreResults; }
@@ -52,10 +73,14 @@ public:
void VisitTagDecl(TagDecl *D);
void VisitTypedefDecl(TypedefDecl *D);
void VisitVarDecl(VarDecl *D);
+ void VisitLinkageSpecDecl(LinkageSpecDecl *D) {
+ IgnoreResults = true;
+ return;
+ }
/// Generate the string component containing the location of the
/// declaration.
- void GenLoc(const Decl *D);
+ bool GenLoc(const Decl *D);
/// String generation methods used both by the visitation methods
/// and from other clients that want to directly generate USRs. These
@@ -63,10 +88,6 @@ public:
/// of an AST element), but only the fragments concerning the AST element
/// itself.
- /// Generate a USR fragment for a named declaration. This does
- /// not include the USR component for the parent.
- void GenNamedDecl(llvm::StringRef name);
-
/// Generate a USR for an Objective-C class.
void GenObjCClass(llvm::StringRef cls);
/// Generate a USR for an Objective-C class category.
@@ -81,31 +102,12 @@ public:
void GenObjCProperty(llvm::StringRef prop);
/// Generate a USR for an Objective-C protocol.
void GenObjCProtocol(llvm::StringRef prot);
-};
-class StringUSRGenerator {
-private:
- llvm::SmallString<1024> StrBuf;
- llvm::raw_svector_ostream Out;
- USRGenerator UG;
-public:
- StringUSRGenerator(const CXCursor *C = 0)
- : Out(StrBuf), UG(C ? cxcursor::getCursorASTUnit(*C) : 0, Out) {
- // Add the USR space prefix.
- Out << "c:";
- }
-
- llvm::StringRef str() {
- return Out.str();
- }
+ void VisitType(QualType T);
- USRGenerator* operator->() { return &UG; }
-
- template <typename T>
- llvm::raw_svector_ostream &operator<<(const T &x) {
- Out << x;
- return Out;
- }
+ /// Emit a Decl's name using NamedDecl::printName() and return true if
+ /// the decl had no name.
+ bool EmitDeclName(const NamedDecl *D);
};
} // end anonymous namespace
@@ -114,56 +116,91 @@ public:
// Generating USRs from ASTS.
//===----------------------------------------------------------------------===//
+bool USRGenerator::EmitDeclName(const NamedDecl *D) {
+ Out.flush();
+ const unsigned startSize = Buf.size();
+ D->printName(Out);
+ Out.flush();
+ const unsigned endSize = Buf.size();
+ return startSize == endSize;
+}
+
+static bool InAnonymousNamespace(const Decl *D) {
+ if (const NamespaceDecl *ND = dyn_cast<NamespaceDecl>(D->getDeclContext()))
+ return ND->isAnonymousNamespace();
+ return false;
+}
+
+static inline bool ShouldGenerateLocation(const NamedDecl *D) {
+ return D->getLinkage() != ExternalLinkage && !InAnonymousNamespace(D);
+}
+
void USRGenerator::VisitDeclContext(DeclContext *DC) {
if (NamedDecl *D = dyn_cast<NamedDecl>(DC))
Visit(D);
}
void USRGenerator::VisitFieldDecl(FieldDecl *D) {
- const std::string &s = D->getNameAsString();
- if (s.empty()) {
+ VisitDeclContext(D->getDeclContext());
+ Out << (isa<ObjCIvarDecl>(D) ? "@" : "@FI@");
+ if (EmitDeclName(D)) {
// Bit fields can be anonymous.
IgnoreResults = true;
return;
}
- VisitDeclContext(D->getDeclContext());
- Out << (isa<ObjCIvarDecl>(D) ? "@" : "@FI@") << s;
}
void USRGenerator::VisitFunctionDecl(FunctionDecl *D) {
- if (D->getLinkage() != ExternalLinkage) {
- GenLoc(D);
- if (IgnoreResults)
- return;
- }
- else
- VisitDeclContext(D->getDeclContext());
+ if (ShouldGenerateLocation(D) && GenLoc(D))
+ return;
+
+ VisitDeclContext(D->getDeclContext());
+ Out << "@F@";
+ D->printName(Out);
+
+ ASTContext &Ctx = AU->getASTContext();
+ if (!Ctx.getLangOptions().CPlusPlus || D->isExternC())
+ return;
- Out << "@F@" << D;
+ // Mangle in type information for the arguments.
+ for (FunctionDecl::param_iterator I = D->param_begin(), E = D->param_end();
+ I != E; ++I) {
+ Out << '#';
+ if (ParmVarDecl *PD = *I)
+ VisitType(PD->getType());
+ }
+ if (D->isVariadic())
+ Out << '.';
+ Out << '#';
+ if (CXXMethodDecl *MD = dyn_cast<CXXMethodDecl>(D)) {
+ if (MD->isStatic())
+ Out << 'S';
+ if (unsigned quals = MD->getTypeQualifiers())
+ Out << (char)('0' + quals);
+ }
}
void USRGenerator::VisitNamedDecl(NamedDecl *D) {
VisitDeclContext(D->getDeclContext());
- const std::string &s = D->getNameAsString();
- // The string can be empty if the declaration has no name; e.g., it is
- // the ParmDecl with no name for declaration of a function pointer type, e.g.:
- // void (*f)(void *);
- // In this case, don't generate a USR.
- if (s.empty())
+ Out << "@";
+
+ if (EmitDeclName(D)) {
+ // The string can be empty if the declaration has no name; e.g., it is
+ // the ParmDecl with no name for declaration of a function pointer type,
+ // e.g.: void (*f)(void *);
+ // In this case, don't generate a USR.
IgnoreResults = true;
- else
- GenNamedDecl(s);
+ }
}
void USRGenerator::VisitVarDecl(VarDecl *D) {
// VarDecls can be declared 'extern' within a function or method body,
// but their enclosing DeclContext is the function, not the TU. We need
// to check the storage class to correctly generate the USR.
- if (D->getLinkage() != ExternalLinkage) {
- GenLoc(D);
- if (IgnoreResults)
- return;
- }
+ if (ShouldGenerateLocation(D) && GenLoc(D))
+ return;
+
+ VisitDeclContext(D->getDeclContext());
// Variables always have simple names.
llvm::StringRef s = D->getName();
@@ -175,18 +212,28 @@ void USRGenerator::VisitVarDecl(VarDecl *D) {
if (s.empty())
IgnoreResults = true;
else
- GenNamedDecl(s);
+ Out << '@' << s;
}
void USRGenerator::VisitNamespaceDecl(NamespaceDecl *D) {
+ if (D->isAnonymousNamespace()) {
+ Out << "@aN";
+ return;
+ }
+
VisitDeclContext(D->getDeclContext());
- Out << "@N@" << D;
+ if (!IgnoreResults)
+ Out << "@N@" << D->getName();
}
void USRGenerator::VisitObjCMethodDecl(ObjCMethodDecl *D) {
Visit(cast<Decl>(D->getDeclContext()));
- GenObjCMethod(DeclarationName(D->getSelector()).getAsString(),
- D->isInstanceMethod());
+ // Ideally we would use 'GenObjCMethod', but this is such a hot path
+ // for Objective-C code that we don't want to use
+ // DeclarationName::getAsString().
+ Out << (D->isInstanceMethod() ? "(im)" : "(cm)");
+ DeclarationName N(D->getSelector());
+ N.printName(Out);
}
void USRGenerator::VisitObjCClassDecl(ObjCClassDecl *D) {
@@ -258,59 +305,56 @@ void USRGenerator::VisitObjCPropertyImplDecl(ObjCPropertyImplDecl *D) {
}
void USRGenerator::VisitTagDecl(TagDecl *D) {
+ // Add the location of the tag decl to handle resolution across
+ // translation units.
+ if (ShouldGenerateLocation(D) && GenLoc(D))
+ return;
+
D = D->getCanonicalDecl();
VisitDeclContext(D->getDeclContext());
- switch (D->getTagKind()) {
- case TagDecl::TK_struct: Out << "@S"; break;
- case TagDecl::TK_class: Out << "@C"; break;
- case TagDecl::TK_union: Out << "@U"; break;
- case TagDecl::TK_enum: Out << "@E"; break;
- }
- const std::string &s = D->getNameAsString();
- const TypedefDecl *TD = 0;
- if (s.empty()) {
- TD = D->getTypedefForAnonDecl();
- Out << (TD ? 'A' : 'a');
+ switch (D->getTagKind()) {
+ case TTK_Struct: Out << "@S"; break;
+ case TTK_Class: Out << "@C"; break;
+ case TTK_Union: Out << "@U"; break;
+ case TTK_Enum: Out << "@E"; break;
}
- // Add the location of the tag decl to handle resolution across
- // translation units.
- if (D->getLinkage() == NoLinkage) {
- Out << '@';
- GenLoc(D);
- if (IgnoreResults)
- return;
- }
+ Out << '@';
+ Out.flush();
+ assert(Buf.size() > 0);
+ const unsigned off = Buf.size() - 1;
- if (s.empty()) {
- if (TD)
+ if (EmitDeclName(D)) {
+ if (const TypedefDecl *TD = D->getTypedefForAnonDecl()) {
+ Buf[off] = 'A';
Out << '@' << TD;
+ }
+ else
+ Buf[off] = 'a';
}
- else
- Out << '@' << s;
}
void USRGenerator::VisitTypedefDecl(TypedefDecl *D) {
+ if (ShouldGenerateLocation(D) && GenLoc(D))
+ return;
DeclContext *DC = D->getDeclContext();
if (NamedDecl *DCN = dyn_cast<NamedDecl>(DC))
Visit(DCN);
Out << "@T@";
- if (D->getLinkage() == NoLinkage) {
- GenLoc(D);
- if (IgnoreResults)
- return;
- Out << '@';
- }
Out << D->getName();
}
-void USRGenerator::GenLoc(const Decl *D) {
+bool USRGenerator::GenLoc(const Decl *D) {
+ if (generatedLoc)
+ return IgnoreResults;
+ generatedLoc = true;
+
const SourceManager &SM = AU->getSourceManager();
SourceLocation L = D->getLocStart();
if (L.isInvalid()) {
IgnoreResults = true;
- return;
+ return true;
}
L = SM.getInstantiationLoc(L);
const std::pair<FileID, unsigned> &Decomposed = SM.getDecomposedLoc(L);
@@ -322,21 +366,145 @@ void USRGenerator::GenLoc(const Decl *D) {
else {
// This case really isn't interesting.
IgnoreResults = true;
- return;
+ return true;
}
Out << '@'
<< SM.getLineNumber(Decomposed.first, Decomposed.second) << ':'
<< SM.getColumnNumber(Decomposed.first, Decomposed.second);
+
+ return IgnoreResults;
+}
+
+void USRGenerator::VisitType(QualType T) {
+ // This method mangles in USR information for types. It can possibly
+ // just reuse the naming-mangling logic used by codegen, although the
+ // requirements for USRs might not be the same.
+ ASTContext &Ctx = AU->getASTContext();
+
+ do {
+ T = Ctx.getCanonicalType(T);
+ Qualifiers Q = T.getQualifiers();
+ unsigned qVal = 0;
+ if (Q.hasConst())
+ qVal |= 0x1;
+ if (Q.hasVolatile())
+ qVal |= 0x2;
+ if (Q.hasRestrict())
+ qVal |= 0x4;
+ if(qVal)
+ Out << ((char) ('0' + qVal));
+
+ // Mangle in ObjC GC qualifiers?
+
+ if (const PointerType *PT = T->getAs<PointerType>()) {
+ Out << '*';
+ T = PT->getPointeeType();
+ continue;
+ }
+ if (const ReferenceType *RT = T->getAs<ReferenceType>()) {
+ Out << '&';
+ T = RT->getPointeeType();
+ continue;
+ }
+ if (const FunctionProtoType *FT = T->getAs<FunctionProtoType>()) {
+ Out << 'F';
+ VisitType(FT->getResultType());
+ for (FunctionProtoType::arg_type_iterator
+ I = FT->arg_type_begin(), E = FT->arg_type_end(); I!=E; ++I) {
+ VisitType(*I);
+ }
+ if (FT->isVariadic())
+ Out << '.';
+ return;
+ }
+ if (const BlockPointerType *BT = T->getAs<BlockPointerType>()) {
+ Out << 'B';
+ T = BT->getPointeeType();
+ continue;
+ }
+ if (const BuiltinType *BT = T->getAs<BuiltinType>()) {
+ unsigned char c = '\0';
+ switch (BT->getKind()) {
+ case BuiltinType::Void:
+ c = 'v'; break;
+ case BuiltinType::Bool:
+ c = 'b'; break;
+ case BuiltinType::Char_U:
+ case BuiltinType::UChar:
+ c = 'c'; break;
+ case BuiltinType::Char16:
+ c = 'q'; break;
+ case BuiltinType::Char32:
+ c = 'w'; break;
+ case BuiltinType::UShort:
+ c = 's'; break;
+ case BuiltinType::UInt:
+ c = 'i'; break;
+ case BuiltinType::ULong:
+ c = 'l'; break;
+ case BuiltinType::ULongLong:
+ c = 'k'; break;
+ case BuiltinType::UInt128:
+ c = 'j'; break;
+ case BuiltinType::Char_S:
+ case BuiltinType::SChar:
+ c = 'C'; break;
+ case BuiltinType::WChar:
+ c = 'W'; break;
+ case BuiltinType::Short:
+ c = 'S'; break;
+ case BuiltinType::Int:
+ c = 'I'; break;
+ case BuiltinType::Long:
+ c = 'L'; break;
+ case BuiltinType::LongLong:
+ c = 'K'; break;
+ case BuiltinType::Int128:
+ c = 'J'; break;
+ case BuiltinType::Float:
+ c = 'f'; break;
+ case BuiltinType::Double:
+ c = 'd'; break;
+ case BuiltinType::LongDouble:
+ c = 'D'; break;
+ case BuiltinType::NullPtr:
+ c = 'n'; break;
+ case BuiltinType::Overload:
+ case BuiltinType::Dependent:
+ case BuiltinType::UndeducedAuto:
+ IgnoreResults = true;
+ return;
+ case BuiltinType::ObjCId:
+ c = 'o'; break;
+ case BuiltinType::ObjCClass:
+ c = 'O'; break;
+ case BuiltinType::ObjCSel:
+ c = 'e'; break;
+ }
+ Out << c;
+ return;
+ }
+ if (const ComplexType *CT = T->getAs<ComplexType>()) {
+ Out << '<';
+ T = CT->getElementType();
+ continue;
+ }
+ if (const TagType *TT = T->getAs<TagType>()) {
+ Out << '$';
+ VisitTagDecl(TT->getDecl());
+ return;
+ }
+
+ // Unhandled type.
+ Out << ' ';
+ break;
+ } while (true);
}
//===----------------------------------------------------------------------===//
// General purpose USR generation methods.
//===----------------------------------------------------------------------===//
-void USRGenerator::GenNamedDecl(llvm::StringRef name) {
- Out << "@" << name;
-}
-
void USRGenerator::GenObjCClass(llvm::StringRef cls) {
Out << "objc(cs)" << cls;
}
@@ -346,7 +514,7 @@ void USRGenerator::GenObjCCategory(llvm::StringRef cls, llvm::StringRef cat) {
}
void USRGenerator::GenObjCIvar(llvm::StringRef ivar) {
- GenNamedDecl(ivar);
+ Out << '@' << ivar;
}
void USRGenerator::GenObjCMethod(llvm::StringRef meth, bool isInstanceMethod) {
@@ -383,6 +551,7 @@ static CXString getDeclCursorUSR(const CXCursor &C) {
// Generate USRs for all entities with external linkage.
break;
case NoLinkage:
+ case UniqueExternalLinkage:
// We allow enums, typedefs, and structs that have no linkage to
// have USRs that are anchored to the file they were defined in
// (e.g., the header). This is a little gross, but in principal
@@ -390,27 +559,27 @@ static CXString getDeclCursorUSR(const CXCursor &C) {
// are referred to across multiple translation units.
if (isa<TagDecl>(ND) || isa<TypedefDecl>(ND) ||
isa<EnumConstantDecl>(ND) || isa<FieldDecl>(ND) ||
- isa<VarDecl>(ND))
+ isa<VarDecl>(ND) || isa<NamespaceDecl>(ND))
break;
// Fall-through.
case InternalLinkage:
if (isa<FunctionDecl>(ND))
break;
- case UniqueExternalLinkage:
- return createCXString("");
}
- StringUSRGenerator SUG(&C);
- SUG->Visit(D);
+ USRGenerator UG(&C);
+ UG->Visit(D);
- if (SUG->ignoreResults())
+ if (UG->ignoreResults())
return createCXString("");
+#if 0
// For development testing.
- // assert(SUG.str().size() > 2);
+ assert(UG.str().size() > 2);
+#endif
// Return a copy of the string that must be disposed by the caller.
- return createCXString(SUG.str(), true);
+ return createCXString(UG.str(), true);
}
extern "C" {
@@ -422,56 +591,56 @@ CXString clang_getCursorUSR(CXCursor C) {
return getDeclCursorUSR(C);
if (K == CXCursor_MacroDefinition) {
- StringUSRGenerator SUG(&C);
- SUG << "macro@"
- << cxcursor::getCursorMacroDefinition(C)->getName()->getNameStart();
- return createCXString(SUG.str(), true);
+ USRGenerator UG(&C);
+ UG << "macro@"
+ << cxcursor::getCursorMacroDefinition(C)->getName()->getNameStart();
+ return createCXString(UG.str(), true);
}
return createCXString("");
}
CXString clang_constructUSR_ObjCIvar(const char *name, CXString classUSR) {
- StringUSRGenerator SUG;
- SUG << extractUSRSuffix(clang_getCString(classUSR));
- SUG->GenObjCIvar(name);
- return createCXString(SUG.str(), true);
+ USRGenerator UG;
+ UG << extractUSRSuffix(clang_getCString(classUSR));
+ UG->GenObjCIvar(name);
+ return createCXString(UG.str(), true);
}
CXString clang_constructUSR_ObjCMethod(const char *name,
unsigned isInstanceMethod,
CXString classUSR) {
- StringUSRGenerator SUG;
- SUG << extractUSRSuffix(clang_getCString(classUSR));
- SUG->GenObjCMethod(name, isInstanceMethod);
- return createCXString(SUG.str(), true);
+ USRGenerator UG;
+ UG << extractUSRSuffix(clang_getCString(classUSR));
+ UG->GenObjCMethod(name, isInstanceMethod);
+ return createCXString(UG.str(), true);
}
CXString clang_constructUSR_ObjCClass(const char *name) {
- StringUSRGenerator SUG;
- SUG->GenObjCClass(name);
- return createCXString(SUG.str(), true);
+ USRGenerator UG;
+ UG->GenObjCClass(name);
+ return createCXString(UG.str(), true);
}
CXString clang_constructUSR_ObjCProtocol(const char *name) {
- StringUSRGenerator SUG;
- SUG->GenObjCProtocol(name);
- return createCXString(SUG.str(), true);
+ USRGenerator UG;
+ UG->GenObjCProtocol(name);
+ return createCXString(UG.str(), true);
}
CXString clang_constructUSR_ObjCCategory(const char *class_name,
const char *category_name) {
- StringUSRGenerator SUG;
- SUG->GenObjCCategory(class_name, category_name);
- return createCXString(SUG.str(), true);
+ USRGenerator UG;
+ UG->GenObjCCategory(class_name, category_name);
+ return createCXString(UG.str(), true);
}
CXString clang_constructUSR_ObjCProperty(const char *property,
CXString classUSR) {
- StringUSRGenerator SUG;
- SUG << extractUSRSuffix(clang_getCString(classUSR));
- SUG->GenObjCProperty(property);
- return createCXString(SUG.str(), true);
+ USRGenerator UG;
+ UG << extractUSRSuffix(clang_getCString(classUSR));
+ UG->GenObjCProperty(property);
+ return createCXString(UG.str(), true);
}
} // end extern "C"
diff --git a/tools/libclang/CMakeLists.txt b/tools/libclang/CMakeLists.txt
index d3de94a7a561..62c973852dc1 100644
--- a/tools/libclang/CMakeLists.txt
+++ b/tools/libclang/CMakeLists.txt
@@ -26,6 +26,7 @@ add_clang_library(libclang
CIndexUSRs.cpp
CIndexer.cpp
CXCursor.cpp
+ CXTypes.cpp
../../include/clang-c/Index.h
)
set_target_properties(libclang PROPERTIES OUTPUT_NAME clang)
diff --git a/tools/libclang/CXCursor.cpp b/tools/libclang/CXCursor.cpp
index c8eb4823779b..f7192dd7e2c8 100644
--- a/tools/libclang/CXCursor.cpp
+++ b/tools/libclang/CXCursor.cpp
@@ -56,13 +56,14 @@ static CXCursorKind GetCursorKind(Decl *D) {
case Decl::ParmVar: return CXCursor_ParmDecl;
case Decl::Typedef: return CXCursor_TypedefDecl;
case Decl::Var: return CXCursor_VarDecl;
+ case Decl::Namespace: return CXCursor_Namespace;
default:
if (TagDecl *TD = dyn_cast<TagDecl>(D)) {
switch (TD->getTagKind()) {
- case TagDecl::TK_struct: return CXCursor_StructDecl;
- case TagDecl::TK_class: return CXCursor_ClassDecl;
- case TagDecl::TK_union: return CXCursor_UnionDecl;
- case TagDecl::TK_enum: return CXCursor_EnumDecl;
+ case TTK_Struct: return CXCursor_StructDecl;
+ case TTK_Class: return CXCursor_ClassDecl;
+ case TTK_Union: return CXCursor_UnionDecl;
+ case TTK_Enum: return CXCursor_EnumDecl;
}
}
@@ -79,6 +80,7 @@ static CXCursorKind GetCursorKind(const Attr *A) {
default: break;
case Attr::IBActionKind: return CXCursor_IBActionAttr;
case Attr::IBOutletKind: return CXCursor_IBOutletAttr;
+ case Attr::IBOutletCollectionKind: return CXCursor_IBOutletCollectionAttr;
}
return CXCursor_UnexposedAttr;
diff --git a/tools/libclang/CXTypes.cpp b/tools/libclang/CXTypes.cpp
new file mode 100644
index 000000000000..137370adb200
--- /dev/null
+++ b/tools/libclang/CXTypes.cpp
@@ -0,0 +1,249 @@
+//===- CXTypes.cpp - Implements 'CXTypes' aspect of libclang ------------===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===--------------------------------------------------------------------===//
+//
+// This file implements the 'CXTypes' API hooks in the Clang-C library.
+//
+//===--------------------------------------------------------------------===//
+
+#include "CIndexer.h"
+#include "CXCursor.h"
+#include "clang/AST/Expr.h"
+#include "clang/AST/Type.h"
+#include "clang/AST/Decl.h"
+#include "clang/AST/DeclObjC.h"
+#include "clang/Frontend/ASTUnit.h"
+
+using namespace clang;
+
+static CXTypeKind GetBuiltinTypeKind(const BuiltinType *BT) {
+#define BTCASE(K) case BuiltinType::K: return CXType_##K
+ switch (BT->getKind()) {
+ BTCASE(Void);
+ BTCASE(Bool);
+ BTCASE(Char_U);
+ BTCASE(UChar);
+ BTCASE(Char16);
+ BTCASE(Char32);
+ BTCASE(UShort);
+ BTCASE(UInt);
+ BTCASE(ULong);
+ BTCASE(ULongLong);
+ BTCASE(UInt128);
+ BTCASE(Char_S);
+ BTCASE(SChar);
+ BTCASE(WChar);
+ BTCASE(Short);
+ BTCASE(Int);
+ BTCASE(Long);
+ BTCASE(LongLong);
+ BTCASE(Int128);
+ BTCASE(Float);
+ BTCASE(Double);
+ BTCASE(LongDouble);
+ BTCASE(NullPtr);
+ BTCASE(Overload);
+ BTCASE(Dependent);
+ BTCASE(ObjCId);
+ BTCASE(ObjCClass);
+ BTCASE(ObjCSel);
+ default:
+ return CXType_Unexposed;
+ }
+#undef BTCASE
+}
+
+static CXTypeKind GetTypeKind(QualType T) {
+ Type *TP = T.getTypePtr();
+ if (!TP)
+ return CXType_Invalid;
+
+#define TKCASE(K) case Type::K: return CXType_##K
+ switch (TP->getTypeClass()) {
+ case Type::Builtin:
+ return GetBuiltinTypeKind(cast<BuiltinType>(TP));
+ TKCASE(Complex);
+ TKCASE(Pointer);
+ TKCASE(BlockPointer);
+ TKCASE(LValueReference);
+ TKCASE(RValueReference);
+ TKCASE(Record);
+ TKCASE(Enum);
+ TKCASE(Typedef);
+ TKCASE(ObjCInterface);
+ TKCASE(ObjCObjectPointer);
+ default:
+ return CXType_Unexposed;
+ }
+#undef TKCASE
+}
+
+static CXType MakeCXType(QualType T, ASTUnit *TU) {
+ CXTypeKind TK = GetTypeKind(T);
+ CXType CT = { TK, { TK == CXType_Invalid ? 0 : T.getAsOpaquePtr(), TU }};
+ return CT;
+}
+
+static inline QualType GetQualType(CXType CT) {
+ return QualType::getFromOpaquePtr(CT.data[0]);
+}
+
+static inline ASTUnit* GetASTU(CXType CT) {
+ return static_cast<ASTUnit*>(CT.data[1]);
+}
+
+extern "C" {
+
+CXType clang_getCursorType(CXCursor C) {
+ ASTUnit *AU = cxcursor::getCursorASTUnit(C);
+
+ if (clang_isExpression(C.kind)) {
+ QualType T = cxcursor::getCursorExpr(C)->getType();
+ return MakeCXType(T, AU);
+ }
+
+ if (clang_isDeclaration(C.kind)) {
+ Decl *D = cxcursor::getCursorDecl(C);
+
+ if (TypeDecl *TD = dyn_cast<TypeDecl>(D))
+ return MakeCXType(QualType(TD->getTypeForDecl(), 0), AU);
+ if (ObjCInterfaceDecl *ID = dyn_cast<ObjCInterfaceDecl>(D))
+ return MakeCXType(QualType(ID->getTypeForDecl(), 0), AU);
+ if (ValueDecl *VD = dyn_cast<ValueDecl>(D))
+ return MakeCXType(VD->getType(), AU);
+
+ return MakeCXType(QualType(), AU);
+ }
+
+ return MakeCXType(QualType(), AU);
+}
+
+CXType clang_getCanonicalType(CXType CT) {
+ if (CT.kind == CXType_Invalid)
+ return CT;
+
+ QualType T = GetQualType(CT);
+
+ if (T.isNull())
+ return MakeCXType(QualType(), GetASTU(CT));
+
+ ASTUnit *AU = GetASTU(CT);
+ return MakeCXType(AU->getASTContext().getCanonicalType(T), AU);
+}
+
+CXType clang_getPointeeType(CXType CT) {
+ QualType T = GetQualType(CT);
+ Type *TP = T.getTypePtr();
+
+ if (!TP)
+ return MakeCXType(QualType(), GetASTU(CT));
+
+ switch (TP->getTypeClass()) {
+ case Type::Pointer:
+ T = cast<PointerType>(TP)->getPointeeType();
+ break;
+ case Type::BlockPointer:
+ T = cast<BlockPointerType>(TP)->getPointeeType();
+ break;
+ case Type::LValueReference:
+ case Type::RValueReference:
+ T = cast<ReferenceType>(TP)->getPointeeType();
+ break;
+ case Type::ObjCObjectPointer:
+ T = cast<ObjCObjectPointerType>(TP)->getPointeeType();
+ break;
+ default:
+ T = QualType();
+ break;
+ }
+ return MakeCXType(T, GetASTU(CT));
+}
+
+CXCursor clang_getTypeDeclaration(CXType CT) {
+ QualType T = GetQualType(CT);
+ Type *TP = T.getTypePtr();
+ Decl *D = 0;
+
+ switch (TP->getTypeClass()) {
+ case Type::Typedef:
+ D = cast<TypedefType>(TP)->getDecl();
+ break;
+ case Type::ObjCObject:
+ D = cast<ObjCObjectType>(TP)->getInterface();
+ break;
+ case Type::ObjCInterface:
+ D = cast<ObjCInterfaceType>(TP)->getDecl();
+ break;
+ case Type::Record:
+ case Type::Enum:
+ D = cast<TagType>(TP)->getDecl();
+ break;
+ default:
+ break;
+ }
+
+ if (!D)
+ return cxcursor::MakeCXCursorInvalid(CXCursor_NoDeclFound);
+
+ return cxcursor::MakeCXCursor(D, GetASTU(CT));
+}
+
+CXString clang_getTypeKindSpelling(enum CXTypeKind K) {
+ const char *s = 0;
+#define TKIND(X) case CXType_##X: s = "" #X ""; break
+ switch (K) {
+ TKIND(Invalid);
+ TKIND(Unexposed);
+ TKIND(Void);
+ TKIND(Bool);
+ TKIND(Char_U);
+ TKIND(UChar);
+ TKIND(Char16);
+ TKIND(Char32);
+ TKIND(UShort);
+ TKIND(UInt);
+ TKIND(ULong);
+ TKIND(ULongLong);
+ TKIND(UInt128);
+ TKIND(Char_S);
+ TKIND(SChar);
+ TKIND(WChar);
+ TKIND(Short);
+ TKIND(Int);
+ TKIND(Long);
+ TKIND(LongLong);
+ TKIND(Int128);
+ TKIND(Float);
+ TKIND(Double);
+ TKIND(LongDouble);
+ TKIND(NullPtr);
+ TKIND(Overload);
+ TKIND(Dependent);
+ TKIND(ObjCId);
+ TKIND(ObjCClass);
+ TKIND(ObjCSel);
+ TKIND(Complex);
+ TKIND(Pointer);
+ TKIND(BlockPointer);
+ TKIND(LValueReference);
+ TKIND(RValueReference);
+ TKIND(Record);
+ TKIND(Enum);
+ TKIND(Typedef);
+ TKIND(ObjCInterface);
+ TKIND(ObjCObjectPointer);
+ }
+#undef TKIND
+ return cxstring::createCXString(s);
+}
+
+unsigned clang_equalTypes(CXType A, CXType B) {
+ return A.data[0] == B.data[0] && A.data[1] == B.data[1];;
+}
+
+} // end: extern "C"
diff --git a/tools/libclang/Makefile b/tools/libclang/Makefile
index a7877bf8e16b..ff0fa33e41eb 100644
--- a/tools/libclang/Makefile
+++ b/tools/libclang/Makefile
@@ -50,6 +50,6 @@ ifeq ($(HOST_OS),Darwin)
ifneq ($(DARWIN_VERS),8)
LLVMLibsOptions := $(LLVMLibsOptions) \
-no-undefined -Wl,-install_name \
- -Wl,"@executable_path/../lib/lib$(LIBRARYNAME)$(SHLIBEXT)"
+ -Wl,"@rpath/lib$(LIBRARYNAME)$(SHLIBEXT)"
endif
endif
diff --git a/tools/libclang/libclang.darwin.exports b/tools/libclang/libclang.darwin.exports
index b36116805311..a9f4f0777cdc 100644
--- a/tools/libclang/libclang.darwin.exports
+++ b/tools/libclang/libclang.darwin.exports
@@ -1,3 +1,4 @@
+_clang_CXXMethod_isStatic
_clang_annotateTokens
_clang_codeComplete
_clang_codeCompleteGetDiagnostic
@@ -21,12 +22,15 @@ _clang_disposeTranslationUnit
_clang_enableStackTraces
_clang_equalCursors
_clang_equalLocations
+_clang_equalTypes
_clang_formatDiagnostic
_clang_getCString
+_clang_getCanonicalType
_clang_getClangVersion
_clang_getCompletionChunkCompletionString
_clang_getCompletionChunkKind
_clang_getCompletionChunkText
+_clang_getCompletionPriority
_clang_getCursor
_clang_getCursorDefinition
_clang_getCursorExtent
@@ -37,6 +41,7 @@ _clang_getCursorLinkage
_clang_getCursorLocation
_clang_getCursorReferenced
_clang_getCursorSpelling
+_clang_getCursorType
_clang_getCursorUSR
_clang_getDefinitionSpellingAndExtent
_clang_getDiagnostic
@@ -58,6 +63,7 @@ _clang_getNullLocation
_clang_getNullRange
_clang_getNumCompletionChunks
_clang_getNumDiagnostics
+_clang_getPointeeType
_clang_getRange
_clang_getRangeEnd
_clang_getRangeStart
@@ -67,9 +73,12 @@ _clang_getTokenLocation
_clang_getTokenSpelling
_clang_getTranslationUnitCursor
_clang_getTranslationUnitSpelling
+_clang_getTypeDeclaration
+_clang_getTypeKindSpelling
_clang_isCursorDefinition
_clang_isDeclaration
_clang_isExpression
+_clang_isFromMainFile
_clang_isInvalid
_clang_isPreprocessing
_clang_isReference
diff --git a/tools/libclang/libclang.exports b/tools/libclang/libclang.exports
index 991bb067f7d0..b09e6ac56c85 100644
--- a/tools/libclang/libclang.exports
+++ b/tools/libclang/libclang.exports
@@ -1,3 +1,4 @@
+clang_CXXMethod_isStatic
clang_annotateTokens
clang_codeComplete
clang_codeCompleteGetDiagnostic
@@ -21,12 +22,15 @@ clang_disposeTranslationUnit
clang_enableStackTraces
clang_equalCursors
clang_equalLocations
+clang_equalTypes
clang_formatDiagnostic
clang_getCString
+clang_getCanonicalType
clang_getClangVersion
clang_getCompletionChunkCompletionString
clang_getCompletionChunkKind
clang_getCompletionChunkText
+clang_getCompletionPriority
clang_getCursor
clang_getCursorDefinition
clang_getCursorExtent
@@ -37,6 +41,7 @@ clang_getCursorLinkage
clang_getCursorLocation
clang_getCursorReferenced
clang_getCursorSpelling
+clang_getCursorType
clang_getCursorUSR
clang_getDefinitionSpellingAndExtent
clang_getDiagnostic
@@ -58,6 +63,7 @@ clang_getNullLocation
clang_getNullRange
clang_getNumCompletionChunks
clang_getNumDiagnostics
+clang_getPointeeType
clang_getRange
clang_getRangeEnd
clang_getRangeStart
@@ -67,9 +73,12 @@ clang_getTokenLocation
clang_getTokenSpelling
clang_getTranslationUnitCursor
clang_getTranslationUnitSpelling
+clang_getTypeDeclaration
+clang_getTypeKindSpelling
clang_isCursorDefinition
clang_isDeclaration
clang_isExpression
+clang_isFromMainFile
clang_isInvalid
clang_isPreprocessing
clang_isReference
@@ -79,3 +88,4 @@ clang_isUnexposed
clang_setUseExternalASTGeneration
clang_tokenize
clang_visitChildren
+
diff --git a/www/analyzer/annotations.html b/www/analyzer/annotations.html
index 620471346365..5184aeddfef4 100644
--- a/www/analyzer/annotations.html
+++ b/www/analyzer/annotations.html
@@ -53,7 +53,9 @@ recognized by GCC. Their use can be conditioned using preprocessor macros
<li><a href="#cocoa_mem">Cocoa &amp; Core Foundation Memory Management Annotations</a>
<ul>
<li><a href="#attr_ns_returns_retained">Attribute 'ns_returns_retained'</a></li>
+ <li><a href="#attr_ns_returns_not_retained">Attribute 'ns_returns_not_retained'</a></li>
<li><a href="#attr_cf_returns_retained">Attribute 'cf_returns_retained'</a></li>
+ <li><a href="#attr_cf_returns_not_retained">Attribute 'cf_returns_not_retained'</a></li>
</ul>
</li>
</ul>
@@ -190,6 +192,36 @@ use 'cf_returns_retained'.</p>
<img src="images/example_ns_returns_retained.png">
+<h4 id="attr_ns_returns_not_retained">Attribute 'ns_returns_not_retained'
+(Clang-specific)</h4>
+
+<p>The 'ns_returns_not_retained' attribute is the complement of '<a
+href="#attr_ns_returns_retained">ns_returns_retained</a>'. Where a function or
+method may appear to obey the Cocoa conventions and return a retained Cocoa
+object, this attribute can be used to indicate that the object reference
+returned should not be considered as an &quot;owning&quot; reference being
+returned to the caller.</p>
+
+<p>Usage is identical to <a
+href="#attr_ns_returns_retained">ns_returns_retained</a>. When using the
+attribute, be sure to declare it within the proper macro that checks for
+its availability, as it is not available in earlier versions of the analyzer:</p>
+
+<pre class="code_example">
+<span class="command">$ cat test.m</span>
+#ifndef __has_feature // Optional.
+#define __has_feature(x) 0 // Compatibility with non-clang compilers.
+#endif
+
+#ifndef NS_RETURNS_NOT_RETAINED
+#if __has_feature(attribute_ns_returns_not_retained)
+<span class="code_highlight">#define NS_RETURNS_NOT_RETAINED __attribute__((ns_returns_not_retained))</span>
+#else
+#define NS_RETURNS_NOT_RETAINED
+#endif
+#endif
+</pre>
+
<h4 id="attr_cf_returns_retained">Attribute 'cf_returns_retained'
(Clang-specific)</h4>
@@ -288,6 +320,36 @@ collection:</p>
<img src="images/example_cf_returns_retained_gc.png">
+<h4 id="attr_cf_returns_not_retained">Attribute 'cf_returns_not_retained'
+(Clang-specific)</h4>
+
+<p>The 'cf_returns_not_retained' attribute is the complement of '<a
+href="#attr_cf_returns_retained">cf_returns_retained</a>'. Where a function or
+method may appear to obey the Core Foundation or Cocoa conventions and return
+a retained Core Foundation object, this attribute can be used to indicate that
+the object reference returned should not be considered as an
+&quot;owning&quot; reference being returned to the caller.</p>
+
+<p>Usage is identical to <a
+href="#attr_cf_returns_retained">cf_returns_retained</a>. When using the
+attribute, be sure to declare it within the proper macro that checks for
+its availability, as it is not available in earlier versions of the analyzer:</p>
+
+<pre class="code_example">
+<span class="command">$ cat test.m</span>
+#ifndef __has_feature // Optional.
+#define __has_feature(x) 0 // Compatibility with non-clang compilers.
+#endif
+
+#ifndef CF_RETURNS_NOT_RETAINED
+#if __has_feature(attribute_cf_returns_not_retained)
+<span class="code_highlight">#define CF_RETURNS_NOT_RETAINED __attribute__((cf_returns_not_retained))</span>
+#else
+#define CF_RETURNS_NOT_RETAINED
+#endif
+#endif
+</pre>
+
<!-- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -->
<h2 id="custom_assertions">Custom Assertion Handlers</h2>
<!-- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -->
diff --git a/www/analyzer/latest_checker.html.incl b/www/analyzer/latest_checker.html.incl
index 413130609217..ecc516a641f4 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-240.tar.bz2">checker-240.tar.bz2</a></b> (built April 11, 2010)
+<b><a href="http://files.me.com/tkremenek/mt0ve6">checker-241.tar.bz2</a></b> (built May 26, 2010)
diff --git a/www/clang-tutorial.html b/www/clang-tutorial.html
new file mode 100644
index 000000000000..0e17046996e9
--- /dev/null
+++ b/www/clang-tutorial.html
@@ -0,0 +1,56 @@
+<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01//EN"
+ "http://www.w3.org/TR/html4/strict.dtd">
+<html>
+<head>
+ <META http-equiv="Content-Type" content="text/html; charset=ISO-8859-1" />
+ <title>Clang - Quick Tutorial</title>
+ <link type="text/css" rel="stylesheet" href="menu.css" />
+ <link type="text/css" rel="stylesheet" href="content.css" />
+</head>
+<body>
+
+<!--#include virtual="menu.html.incl"-->
+
+<div id="content">
+
+<h1>Tutorial</h1>
+
+ <p>Invoking the BoostCon tool:</p>
+ <pre>
+$ clang -cc1 -boostcon t.cpp
+</pre>
+
+ <p>Teach the BoostCon action to identify and print C++ classes:</p>
+ <pre>
+bool VisitCXXRecordDecl(CXXRecordDecl *D) {
+ std::cout &lt;&lt; D-&gt;getNameAsString()
+ &lt;&lt; '\n';
+ return false;
+}
+</pre>
+
+ <p>Walk and print base classes of a class:</p>
+ <pre>
+for(CXXRecordDecl::base_class_iterator
+ B = D-&gt;bases_begin(), BEnd = D-&gt;bases_end();
+ B != BEnd; ++B) {
+ QualType BaseType = B-&gt;getType();
+ std::cout &lt;&lt; " " &lt;&lt; BaseType.getAsString()
+ &lt;&lt; '\n';
+}
+</pre>
+
+ <p>Retrieve the C++ class declaration from a base type:</p>
+ <pre>
+if (const RecordType *RTy
+ = BaseType-&gt;getAs&lt;RecordType&gt;()) {
+ RecordDecl *Base = RTy-&gt;getDecl();
+ if (CXXRecordDecl *BaseCXX
+ = dyn_cast&lt;CXXRecordDecl&gt;(Base)) {
+
+ }
+}
+</pre>
+</div>
+</body>
+</html>
diff --git a/www/comparison.html b/www/comparison.html
index 0a6a7c8e00fa..dcf6220eb95f 100644
--- a/www/comparison.html
+++ b/www/comparison.html
@@ -50,8 +50,10 @@
<ul>
<li>GCC supports languages that clang does not aim to, such as Java, Ada,
FORTRAN, etc.</li>
- <li>GCC front-ends are very mature and already support C++.
- <a href="cxx_status.html">clang's support for C++</a> is further behind.</li>
+ <li><a href="cxx_status.html">Clang support for C++</a> is more compliant
+ than GCC's in many ways, but is not as mature as GCC's. GCC has several
+ C++'0x features that Clang does not yet support (e.g. variadic
+ templates).</li>
<li>GCC supports more targets than LLVM.</li>
<li>GCC is popular and widely adopted.</li>
<li>GCC does not require a C++ compiler to build it.</li>
diff --git a/www/cxx_compatibility.html b/www/cxx_compatibility.html
index bd48c6c09d38..fe032403d7c7 100644
--- a/www/cxx_compatibility.html
+++ b/www/cxx_compatibility.html
@@ -42,14 +42,25 @@ C++-conformance bug in your code and how you can fix it.</p>
<h2 id="vla">Variable-length arrays</h2>
<!-- ======================================================================= -->
-<p>GCC allows an array's size to be determined at run time. This,
-however, is not standard C++. Furthermore, it is a potential security
-hole as an incorrect array size may overflow the stack. If Clang tells
-you <tt>"variable length arrays are not permitted in C++"</tt>, here
-are some ways in which you can fix it:</p>
+<p>GCC and C99 allow an array's size to be determined at run
+time. This extension is not permitted in standard C++. However, Clang
+supports such variable length arrays in very limited circumstances for
+compatibility with GNU C and C99 programs:</p>
+
+<ul>
+ <li>The element type of a variable length array must be a POD
+ ("plain old data") type, which means that it cannot have any
+ user-declared constructors or destructors, base classes, or any
+ members if non-POD type. All C types are POD types.</li>
+
+ <li>Variable length arrays cannot be used as the type of a non-type
+template parameter.</li> </ul>
+
+<p>If your code uses variable length arrays in a manner that Clang doesn't support, there are several ways to fix your code:
<ol>
-<li>replace it with a fixed-size array if you can determine a
+<li>replace the variable length array with a fixed-size array if you can
+ determine a
reasonable upper bound at compile time; sometimes this is as
simple as changing <tt>int size = ...;</tt> to <tt>const int size
= ...;</tt> (if the definition of <tt>size</tt> is a compile-time
diff --git a/www/cxx_status.html b/www/cxx_status.html
index 9ba3200faba8..8fccc2a34137 100644
--- a/www/cxx_status.html
+++ b/www/cxx_status.html
@@ -3,7 +3,7 @@
<html>
<head>
<META http-equiv="Content-Type" content="text/html; charset=ISO-8859-1">
- <title>Clang - C++ Support</title>
+ <title>Clang - C++ and C++'0x Status</title>
<link type="text/css" rel="stylesheet" href="menu.css">
<link type="text/css" rel="stylesheet" href="content.css">
<style type="text/css">
@@ -22,11 +22,9 @@
<div id="content">
<!--*************************************************************************-->
-<h1>C++ Support in Clang</h1>
+<h1>C++ and C++'0x Support in Clang</h1>
<!--*************************************************************************-->
-<p>Last updated: $Date: 2010-04-12 18:01:38 +0200 (Mon, 12 Apr 2010) $</p>
-
-<h1>Clang C++ Status</h1>
+<p>Last updated: $Date: 2010-05-21 23:16:21 +0200 (Fri, 21 May 2010) $</p>
<ul>
<li><a href="#projects">Projects Building with Clang</a></li>
@@ -34,19 +32,19 @@
<li><a href="#cxx0x">C++0x Status</a></li>
</ul>
-<p>Clang currently implements nearly all of the ISO C++ 1998 standard (including the defects addressed in the ISO C++ 2003 standard). However, the implementation of Clang C++ is still quite immature, with many remaining bugs that are likely to cause compiler crashes, erroneous errors and warnings, and miscompiled code. The <a href="http://llvm.org/bugs/">LLVM bug tracker</a> contains a Clang C++ component that tracks known Clang C++ bugs.</p>
+<p>Clang currently implements all of the ISO C++ 1998 standard (including
+ the defects addressed in the ISO C++ 2003 standard) except for 'export'
+ (which has been removed from the C++'0x draft).
+ However, the implementation of Clang C++ is still somewhat immature, with
+ remaining bugs that may cause compiler crashes, erroneous errors and warnings,
+ or miscompiled code. The <a href="http://llvm.org/bugs/">LLVM bug tracker</a>
+ contains a Clang C++ component that tracks known Clang C++ bugs.</p>
<h2 id="projects">Projects Building with Clang</h2>
- <p>Clang is now capable of compiling some language C++ projects, or
-large pieces of such projects. The following table describes various
-projects that we have attempted to compile with Clang along with the results of that attempt.</p>
-
- <p> At this point in time, each new C++ project typically uncovers
-new bugs. We keep track of these in the <a
- href="http://llvm.org/bugs/">LLVM bug tracker</a> via tracking bugs,
-which are used to relate all of the bugs known to affect that
-particular project. Introducing a new project in this list typically requires a liason familiar with LLVM or Clang development, who is able to provide detailed bug reports and track progress for the particular project.</p>
+ <p>Clang is now capable of compiling large C++ projects, and the following
+ table describes various projects that we have attempted to compile with
+ Clang++.</p>
<table width="689" border="1" cellspacing="0">
<tr>
@@ -68,20 +66,28 @@ particular project. Introducing a new project in this list typically requires a
<td></td>
</tr>
<tr>
+ <td><a href="http://www.boost.org">Boost</a></td>
+ <td><a href="http://blog.llvm.org/2010/05/clang-builds-boost.html">Compiles
+ and passes regression tests</a> on Darwin/X86-64.</td>
+ <td>May 20, 2010</td>
+ <td><a href="http://llvm.org/bugs/show_bug.cgi?id=6023">PR6023</a></td>
+ </tr>
+ <tr>
<td><a href="http://qt.nokia.com">Qt</a></td>
<td>Partially compiles; miscompilation of uic prevents complete compilation, qmake works, some small examples also.</td>
<td>February 9, 2010</td>
<td><a href="http://llvm.org/bugs/show_bug.cgi?id=5881">PR5881</a></td>
</tr>
- <tr>
- <td><a href="http://www.boost.org">Boost</a></td>
- <td>Some libraries (e.g., Boost.MPL) successfully build and pass regression tests, the majority still fail.</td>
- <td>February 5, 2010</td>
- <td><a href="http://llvm.org/bugs/show_bug.cgi?id=6023">PR6023</a></td>
- </tr>
</table>
- <h2 id="specification">Implementation Status by Section</h2>
+<h2 id="cxx0x">C++0x Implementation status</h2>
+
+<p>Clang's development effort is focused primarily on fixing bugs in the current
+ISO C++ standard (1998/2003). This section tracks the status of various C++0x
+features.</p>
+
+
+<h2 id="specification">Implementation Status by Feature</h2>
<!-- Within this table: The colors we're using to color-code our level
@@ -96,9 +102,9 @@ of support for a given section:
-->
<p>The following table is used to help track our implementation
- progress toward implementing the complete C++03 standard. We use a
+ progress toward implementing the complete C++'0x standard. We use a
simple, somewhat arbitrary color-coding scheme to describe the
- relative completeness of features by section:</p>
+ relative completeness of features:</p>
<table width="689" border="1" cellspacing="0">
<tr>
@@ -125,2239 +131,46 @@ of support for a given section:
<p>A feature is "complete" when the appropriate Clang component (Parse, AST,
Sema, CodeGen) implements the behavior described in all of the
-paragraphs in the relevant C++ standard. Note that many C++ features are
-actually described in several different sections within the standard. The major components are:</p>
+paragraphs in the relevant C++'0x draft standard. The major
+components are:</p>
<dl>
<dt>Parse</dt>
- <dd>Clang is able to parse the grammar of this feature (or the grammar described by this section), but does not necessarily do anything with the parsed result. Use Clang's <code>-fsyntax-only</code> option to parse C++ programs.</dd>
+ <dd>Clang is able to parse the grammar of this feature (or the grammar
+ described by this section), but does not necessarily do anything with the
+ parsed result. Use Clang's <code>-fsyntax-only</code> option to parse C++
+ programs.</dd>
<dt>AST</dt>
- <dd>Clang builds an abstract syntax tree (AST) for the feature, but does not necessarily perform any type-checking. Use Clang's <code>-ast-print</code> option to print the resulting ASTs.</dd>
+ <dd>Clang builds an abstract syntax tree (AST) for the feature, but does not
+ necessarily perform any type-checking. Use Clang's <code>-ast-print</code>
+ option to print the resulting ASTs.</dd>
<dt>Sema</dt>
- <dd>Clang parses and type-checks this feature and provides a well-formed AST annotated with types. Use Clang's <code>-fsyntax-only</code> to type-check code.</dd>
+ <dd>Clang parses and type-checks this feature and provides a well-formed AST
+ annotated with types. Use Clang's <code>-fsyntax-only</code> to type-check
+ code.</dd>
<dt>CodeGen</dt>
- <dd>Clang parses, type-checks, and generates code for this feature, allowing one to compile and execute programs.</dd>
+ <dd>Clang parses, type-checks, and generates code for this feature, allowing
+ one to compile and execute programs.</dd>
</dl>
-<p>Updates to this table are welcome! Since Clang already supports
-much of C, and therefore much C++, many of the currently-white cells
-could be filled in. If you wish to do so, please compare Clang's
-implementation against the C++ standard and provide a patch that
-updates the table accordingly. Tests for the various features are also
+<p>Updates to this table are welcome! Tests for the various features are also
welcome!</p>
<table width="689" border="1" cellspacing="0">
+<tr><td colspan="6" align="center" bgcolor="#ffffcc">C++0x Features</td>
+</tr>
<tr>
- <th>Section</th>
+ <th>Feature</th>
<th>Parse</th>
<th>AST</th>
<th>Sema</th>
<th>CodeGen</th>
<th>Notes</th>
</tr>
-<tr>
- <td>2 [lex]</td>
- <td class="complete" align="center"></td>
- <td class="na">N/A</td>
- <td class="na">N/A</td>
- <td class="na">N/A</td>
- <td></td>
-</tr>
-<tr>
- <td>&nbsp;&nbsp;2.1 [lex.phases]</td>
- <td class="advanced" align="center"></td>
- <td class="na">N/A</td>
- <td class="na">N/A</td>
- <td class="na">N/A</td>
- <td>Extended characters aren't handled.</td>
-</tr>
-<tr>
- <td>&nbsp;&nbsp;2.2 [lex.charset]</td>
- <td class="basic"></td>
- <td class="na">N/A</td>
- <td class="na">N/A</td>
- <td class="na">N/A</td>
- <td>No support for extended characters.</td>
-</tr>
-<tr>
- <td>&nbsp;&nbsp;2.3 [lex.trigraph]</td>
- <td class="complete" align="center"></td>
- <td class="na">N/A</td>
- <td class="na">N/A</td>
- <td class="na">N/A</td>
- <td></td>
-</tr>
-<tr>
- <td>&nbsp;&nbsp;2.4 [lex.pptoken]</td>
- <td class="complete" align="center"></td>
- <td class="na">N/A</td>
- <td class="na">N/A</td>
- <td class="na">N/A</td>
- <td></td>
-</tr>
-<tr>
- <td>&nbsp;&nbsp;2.5 [lex.digraph]</td>
- <td class="complete" align="center"></td>
- <td class="na">N/A</td>
- <td class="na">N/A</td>
- <td class="na">N/A</td>
- <td></td>
-</tr>
-<tr>
- <td>&nbsp;&nbsp;2.6 [lex.token]</td>
- <td class="complete" align="center"></td>
- <td class="na">N/A</td>
- <td class="na">N/A</td>
- <td class="na">N/A</td>
- <td></td>
-</tr>
-<tr>
- <td>&nbsp;&nbsp;2.7 [lex.comment]</td>
- <td class="advanced" align="center"></td>
- <td></td>
- <td class="na">N/A</td>
- <td class="na">N/A</td>
- <td>NDR "form feed or vtab in comment" is not diagnosed.</td>
-</tr>
-<tr>
- <td>&nbsp;&nbsp;2.8 [lex.header]</td>
- <td class="complete" align="center"></td>
- <td class="na">N/A</td>
- <td class="na">N/A</td>
- <td class="na">N/A</td>
- <td></td>
-</tr>
-<tr>
- <td>&nbsp;&nbsp;2.9 [lex.ppnumber]</td>
- <td class="complete" align="center"></td>
- <td class="na">N/A</td>
- <td class="na">N/A</td>
- <td class="na">N/A</td>
- <td></td>
-</tr>
-<tr>
- <td>&nbsp;&nbsp;2.10 [lex.name]</td>
- <td class="advanced" align="center"></td>
- <td class="na">N/A</td>
- <td class="na">N/A</td>
- <td class="na">N/A</td>
- <td>No support for extended characters</td>
-</tr>
-<tr>
- <td>&nbsp;&nbsp;2.11 [lex.key]</td>
- <td class="complete" align="center"></td>
- <td class="na">N/A</td>
- <td class="na">N/A</td>
- <td class="na">N/A</td>
- <td></td>
-</tr>
-<tr>
- <td>&nbsp;&nbsp;2.12 [lex.operators]</td>
- <td class="complete" align="center"></td>
- <td class="na">N/A</td>
- <td class="na">N/A</td>
- <td class="na">N/A</td>
- <td></td>
-</tr>
-<tr>
- <td>&nbsp;&nbsp;2.13 [lex.literal]</td>
- <td class="complete" align="center"></td>
- <td class="na">N/A</td>
- <td class="na">N/A</td>
- <td class="na">N/A</td>
- <td></td>
-</tr>
-<tr>
- <td>&nbsp;&nbsp;&nbsp;&nbsp;2.13.1 [lex.icon]</td>
- <td class="complete" align="center"></td>
- <td class="na">N/A</td>
- <td class="na">N/A</td>
- <td class="na">N/A</td>
- <td></td>
-</tr>
-<tr>
- <td>&nbsp;&nbsp;&nbsp;&nbsp;2.13.2 [lex.ccon]</td>
- <td class="advanced" align="center"></td>
- <td class="na">N/A</td>
- <td class="na">N/A</td>
- <td class="na">N/A</td>
- <td>Poor support for extended characters</td>
-</tr>
-<tr>
- <td>&nbsp;&nbsp;&nbsp;&nbsp;2.13.3 [lex.fcon]</td>
- <td class="complete" align="center"></td>
- <td class="na">N/A</td>
- <td class="na">N/A</td>
- <td class="na">N/A</td>
- <td></td>
-</tr>
-<tr>
- <td>&nbsp;&nbsp;&nbsp;&nbsp;2.13.4 [lex.string]</td>
- <td class="advanced" align="center"></td>
- <td class="na">N/A</td>
- <td class="na">N/A</td>
- <td class="na">N/A</td>
- <td>Poor support for extended characters</td>
-</tr>
-<tr>
- <td>&nbsp;&nbsp;&nbsp;&nbsp;2.13.5 [lex.bool]</td>
- <td class="complete" align="center"></td>
- <td class="na">N/A</td>
- <td class="na">N/A</td>
- <td class="na">N/A</td>
- <td></td>
-</tr>
-<tr>
-<td>3 [basic]</td>
- <td class="na">N/A</td>
- <td class="na">N/A</td>
- <td class="na">N/A</td>
- <td class="na">N/A</td>
- <td></td>
-</tr>
-<tr>
- <td>&nbsp;&nbsp;3.1 [basic.def]</td>
- <td></td>
- <td></td>
- <td></td>
- <td class="na">N/A</td>
- <td></td>
-</tr>
-<tr>
- <td>&nbsp;&nbsp;3.2 [basic.def.odr]</td>
- <td></td>
- <td></td>
- <td></td>
- <td></td>
- <td></td>
-</tr>
-<tr>
- <td>&nbsp;&nbsp;3.3 [basic.scope]</td>
- <td class="na">N/A</td>
- <td class="na">N/A</td>
- <td class="complete" align="center"></td>
- <td class="na">N/A</td>
- <td></td>
-</tr>
-<tr>
- <td>&nbsp;&nbsp;&nbsp;&nbsp;3.3.1 [basic.scope.pdecl]</td>
- <td class="na">N/A</td>
- <td class="na">N/A</td>
- <td class="complete" align="center"></td>
- <td class="na">N/A</td>
- <td></td>
-</tr>
-<tr>
- <td>&nbsp;&nbsp;&nbsp;&nbsp;3.3.2 [basic.scope.local]</td>
- <td class="na">N/A</td>
- <td class="na">N/A</td>
- <td class="complete" align="center"></td>
- <td class="na">N/A</td>
- <td></td>
-</tr>
-<tr>
- <td>&nbsp;&nbsp;&nbsp;&nbsp;3.3.3 [basic.scope.proto]</td>
- <td class="na">N/A</td>
- <td class="na">N/A</td>
- <td class="complete" align="center"></td>
- <td class="na">N/A</td>
- <td></td>
-</tr>
-<tr>
- <td>&nbsp;&nbsp;&nbsp;&nbsp;3.3.4 [basic.funscope]</td>
- <td class="na">N/A</td>
- <td class="na">N/A</td>
- <td class="complete" align="center"></td>
- <td class="na">N/A</td>
- <td></td>
-</tr>
-<tr>
- <td>&nbsp;&nbsp;&nbsp;&nbsp;3.3.5 [basic.scope.namespace]</td>
- <td class="na">N/A</td>
- <td class="na">N/A</td>
- <td class="complete"></td>
- <td class="na">N/A</td>
- <td></td>
-</tr>
-<tr>
- <td>&nbsp;&nbsp;&nbsp;&nbsp;3.3.6 [basic.scope.class]</td>
- <td class="na">N/A</td>
- <td class="na">N/A</td>
- <td class="advanced"></td>
- <td class="na">N/A</td>
- <td>Does not check that reordering the members of a class maintains semantics.</td>
-</tr>
-<tr>
- <td>&nbsp;&nbsp;&nbsp;&nbsp;3.3.7 [basic.scope.hiding]</td>
- <td class="na">N/A</td>
- <td class="na">N/A</td>
- <td class="complete" align="center"></td>
- <td class="na">N/A</td>
- <td></td>
-</tr>
-<tr>
- <td>&nbsp;&nbsp;3.4 [basic.lookup]</td>
- <td class="na">N/A</td>
- <td class="na">N/A</td>
- <td class="complete" align="center"></td>
- <td class="na">N/A</td>
- <td></td>
-</tr>
-<tr>
- <td>&nbsp;&nbsp;&nbsp;&nbsp;3.4.1 [basic.lookup.unqual]</td>
- <td class="na">N/A</td>
- <td class="na">N/A</td>
- <td class="advanced"></td>
- <td class="na">N/A</td>
- <td></td>
-</tr>
-<tr>
- <td>&nbsp;&nbsp;&nbsp;&nbsp;3.4.2 [basic.lookup.argdep]</td>
- <td class="na">N/A</td>
- <td class="na">N/A</td>
- <td class="complete"></td>
- <td class="na">N/A</td>
- <td></td>
-</tr>
-<tr>
- <td>&nbsp;&nbsp;&nbsp;&nbsp;3.4.3 [basic.lookup.qual]</td>
- <td class="na">N/A</td>
- <td class="na">N/A</td>
- <td class="advanced"></td>
- <td class="na">N/A</td>
- <td></td>
-</tr>
-<tr>
- <td>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;3.4.3.1 [class.qual]</td>
- <td class="na">N/A</td>
- <td class="na">N/A</td>
- <td class="advanced"></td>
- <td class="na">N/A</td>
- <td></td>
-</tr>
-<tr>
- <td>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;3.4.3.2 [namespace.qual]</td>
- <td class="na">N/A</td>
- <td class="na">N/A</td>
- <td class="advanced"></td>
- <td class="na">N/A</td>
- <td></td>
-</tr>
-<tr><td>&nbsp;&nbsp;&nbsp;&nbsp;3.4.4 [basic.lookup.elab]</td><td></td><td></td><td></td><td></td><td></td></tr>
-<tr>
- <td>&nbsp;&nbsp;&nbsp;&nbsp;3.4.5 [basic.lookup.classref]</td>
- <td class="na">N/A</td>
- <td class="na">N/A</td>
- <td class="advanced"></td>
- <td class="na">N/A</td>
- <td>Missing ambiguity/consistency checks for paragraphs 3 (~type-name) and 7 (conversion-type-id)</td>
-</tr>
-<tr>
- <td>&nbsp;&nbsp;&nbsp;&nbsp;3.4.6 [basic.lookup.udir]</td>
- <td class="na">N/A</td>
- <td class="na">N/A</td>
- <td class="medium"></td>
- <td class="na">N/A</td>
- <td></td>
-</tr>
-<tr><td>&nbsp;&nbsp;3.5 [basic.link]</td><td></td><td></td><td></td><td></td><td></td></tr>
-<tr><td>&nbsp;&nbsp;3.6 [basic.start]</td><td></td><td></td><td></td><td></td><td></td></tr>
-<tr><td>&nbsp;&nbsp;&nbsp;&nbsp;3.6.1 [basic.start.main]</td><td></td><td></td><td></td><td></td><td></td></tr>
-<tr><td>&nbsp;&nbsp;&nbsp;&nbsp;3.6.2 [basic.start.init]</td><td></td><td></td><td></td><td></td><td></td></tr>
-<tr><td>&nbsp;&nbsp;&nbsp;&nbsp;3.6.3 [basic.start.term]</td><td></td><td></td><td></td><td></td><td></td></tr>
-<tr><td>&nbsp;&nbsp;3.7 [basic.stc]</td><td></td><td></td><td></td><td></td><td></td></tr>
-<tr><td>&nbsp;&nbsp;&nbsp;&nbsp;3.7.1 [basic.stc.static]</td><td></td><td></td><td></td><td></td><td></td></tr>
-<tr><td>&nbsp;&nbsp;&nbsp;&nbsp;3.7.2 [basic.stc.auto]</td><td></td><td></td><td></td><td></td><td></td></tr>
-<tr><td>&nbsp;&nbsp;&nbsp;&nbsp;3.7.3 [basic.stc.dynamic]</td><td></td><td></td><td></td><td></td><td></td></tr>
-<tr><td>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;3.7.3.1 [basic.stc.dynamic.allocation]</td><td></td><td></td><td></td><td></td><td></td></tr>
-<tr><td>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;3.7.3.2 [basic.stc.dynamic.deallocation]</td><td></td><td></td><td></td><td></td><td></td></tr>
-<tr><td>&nbsp;&nbsp;&nbsp;&nbsp;3.7.4 [basic.stc.inherit]</td><td></td><td></td><td></td><td></td><td></td></tr>
-<tr><td>&nbsp;&nbsp;3.8 [basic.life]</td><td></td><td></td><td></td><td></td><td></td></tr>
-<tr><td>&nbsp;&nbsp;3.9 [basic.types]</td><td></td><td></td><td></td><td></td><td></td></tr>
-<tr><td>&nbsp;&nbsp;&nbsp;&nbsp;3.9.1 [basic.fundamental]</td><td></td><td></td><td></td><td></td><td></td></tr>
-<tr><td>&nbsp;&nbsp;&nbsp;&nbsp;3.9.2 [basic.compound]</td><td></td><td></td><td></td><td></td><td></td></tr>
-<tr><td>&nbsp;&nbsp;&nbsp;&nbsp;3.9.3 [basic.type.qualifier]</td><td></td><td></td><td></td><td></td><td></td></tr>
-<tr><td>&nbsp;&nbsp;3.10 [basic.lval]</td><td></td><td></td><td></td><td></td><td></td></tr>
-<tr>
- <td>4 [conv]</td>
- <td class="complete" align="center"></td>
- <td class="complete" align="center"></td>
- <td class="complete" align="center"></td>
- <td></td>
- <td></td>
-</tr>
-<tr>
- <td>&nbsp;&nbsp;4.1 [conv.lval]</td>
- <td class="complete" align="center"></td>
- <td class="complete" align="center"></td>
- <td class="advanced" align="center"></td> <!-- p2: sizeof -->
- <td></td>
- <td></td>
-</tr>
-<tr>
- <td>&nbsp;&nbsp;4.2 [conv.array]</td>
- <td class="complete" align="center"></td>
- <td class="complete" align="center"></td>
- <td class="complete" align="center"></td>
- <td></td>
- <td></td>
-</tr>
-<tr>
- <td>&nbsp;&nbsp;4.3 [conv.func]</td>
- <td class="complete" align="center"></td>
- <td class="complete" align="center"></td>
- <td class="advanced" align="center"></td>
- <td></td>
- <td></td>
-</tr>
-<tr>
- <td>&nbsp;&nbsp;4.4 [conv.qual]</td>
- <td class="complete" align="center"></td>
- <td class="complete" align="center"></td>
- <td class="complete" align="center"></td>
- <td></td>
- <td></td>
-</tr>
-<tr>
- <td>&nbsp;&nbsp;4.5 [conv.prom]</td>
- <td class="complete" align="center"></td>
- <td class="complete" align="center"></td>
- <td class="complete" align="center"></td>
- <td></td>
- <td></td>
-</tr>
-<tr>
- <td>&nbsp;&nbsp;4.6 [conv.fpprom]</td>
- <td class="complete" align="center"></td>
- <td class="complete" align="center"></td>
- <td class="complete" align="center"></td>
- <td></td>
- <td></td>
-</tr>
-<tr>
- <td>&nbsp;&nbsp;4.7 [conv.integral]</td>
- <td class="complete" align="center"></td>
- <td class="complete" align="center"></td>
- <td class="complete" align="center"></td>
- <td></td>
- <td></td>
-</tr>
-<tr>
- <td>&nbsp;&nbsp;4.8 [conv.double]</td>
- <td class="complete" align="center"></td>
- <td class="complete" align="center"></td>
- <td class="complete" align="center"></td>
- <td></td>
- <td></td>
-</tr>
-<tr>
- <td>&nbsp;&nbsp;4.9 [conv.fpint]</td>
- <td class="complete" align="center"></td>
- <td class="complete" align="center"></td>
- <td class="complete" align="center"></td>
- <td></td>
- <td></td>
-</tr>
-<tr>
- <td>&nbsp;&nbsp;4.10 [conv.ptr]</td>
- <td class="complete" align="center"></td>
- <td class="complete" align="center"></td>
- <td class="complete" align="center"></td>
- <td></td>
- <td></td>
-</tr>
-<tr>
- <td>&nbsp;&nbsp;4.11 [conv.mem]</td>
- <td class="complete" align="center"></td>
- <td class="complete" align="center"></td>
- <td class="complete" align="center"></td>
- <td></td>
- <td></td>
-</tr>
-<tr>
- <td>&nbsp;&nbsp;4.12 [conv.bool]</td>
- <td class="complete" align="center"></td>
- <td class="complete" align="center"></td>
- <td class="complete" align="center"></td>
- <td></td>
- <td></td>
-</tr>
-<tr>
- <td>5 [expr]</td>
- <td class="na">N/A</td>
- <td class="na">N/A</td>
- <td class="complete" align="center">&#x2713;</td>
- <td class="na">N/A</td>
- <td></td>
-</tr>
-<tr>
- <td>&nbsp;&nbsp;5.1 [expr.prim]</td>
- <td class="advanced" align="center"></td>
- <td class="advanced" align="center"></td>
- <td class="advanced" align="center"></td>
- <td></td>
- <td></td>
-</tr>
-<tr><td>&nbsp;&nbsp;5.2 [expr.post]</td><td></td><td></td><td></td><td></td><td></td></tr>
-<tr>
- <td>&nbsp;&nbsp;&nbsp;&nbsp;5.2.1 [expr.sub]</td>
- <td class="complete" align="center"></td>
- <td class="complete" align="center"></td>
- <td class="complete" align="center"></td>
- <td></td>
- <td></td>
-</tr>
-<tr>
- <td>&nbsp;&nbsp;&nbsp;&nbsp;5.2.2 [expr.call]</td>
- <td class="complete" align="center"></td>
- <td class="complete" align="center"></td>
- <td class="advanced" align="center"></td>
- <td></td>
- <td></td>
-</tr>
-<tr>
- <td>&nbsp;&nbsp;&nbsp;&nbsp;5.2.3 [expr.type.conv]</td>
- <td class="complete" align="center"></td>
- <td class="advanced" align="center"></td>
- <td class="advanced"></td>
- <td></td>
- <td></td>
-</tr>
-<tr>
- <td>&nbsp;&nbsp;&nbsp;&nbsp;5.2.4 [expr.pseudo]</td>
- <td class="complete"></td>
- <td class="complete"></td>
- <td class="complete"></td>
- <td class="complete"></td>
- <td></td>
-</tr>
-<tr>
- <td>&nbsp;&nbsp;&nbsp;&nbsp;5.2.5 [expr.ref]</td>
- <td class="complete" align="center"></td>
- <td class="complete"></td>
- <td class="complete"></td>
- <td></td>
- <td></td>
-</tr>
-<tr>
- <td>&nbsp;&nbsp;&nbsp;&nbsp;5.2.6 [expr.post.incr]</td>
- <td class="complete" align="center"></td>
- <td class="complete" align="center"></td>
- <td class="complete" align="center"></td>
- <td></td>
- <td></td>
-</tr>
-<tr>
- <td>&nbsp;&nbsp;&nbsp;&nbsp;5.2.7 [expr.dynamic.cast]</td>
- <td class="complete" align="center"></td>
- <td class="complete" align="center"></td>
- <td class="complete" align="center"></td>
- <td></td>
- <td></td>
-</tr>
-<tr>
- <td>&nbsp;&nbsp;&nbsp;&nbsp;5.2.8 [expr.typeid]</td>
- <td class="complete" align="center"></td>
- <td class="complete" align="center"></td>
- <td class="complete" align="center"></td>
- <td></td>
- <td></td>
-</tr>
-<tr>
- <td>&nbsp;&nbsp;&nbsp;&nbsp;5.2.9 [expr.static.cast]</td>
- <td class="complete" align="center"></td>
- <td class="advanced" align="center"></td>
- <td class="advanced" align="center"></td>
- <td></td>
- <td></td>
-</tr>
-<tr>
- <td>&nbsp;&nbsp;&nbsp;&nbsp;5.2.10 [expr.reinterpret.cast]</td>
- <td class="complete" align="center"></td>
- <td class="complete" align="center"></td>
- <td class="complete" align="center"></td>
- <td></td>
- <td></td>
-</tr>
-<tr>
- <td>&nbsp;&nbsp;&nbsp;&nbsp;5.2.11 [expr.const.cast]</td>
- <td class="complete" align="center"></td>
- <td class="complete" align="center"></td>
- <td class="complete" align="center"></td>
- <td></td>
- <td></td>
-</tr>
-<tr><td>&nbsp;&nbsp;5.3 [expr.unary]</td><td></td><td></td><td></td><td></td><td></td></tr>
-<tr><td>&nbsp;&nbsp;&nbsp;&nbsp;5.3.1 [expr.unary.op]</td><td></td><td></td><td></td><td></td><td></td></tr>
-<tr>
- <td>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;5.3.1p1 Unary *</td>
- <td class="complete" align="center"></td>
- <td class="complete" align="center"></td>
- <td class="complete" align="center"></td>
- <td></td>
- <td></td>
-</tr>
-<tr>
- <td>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;5.3.1p2-5 Unary &amp;</td>
- <td class="complete" align="center"></td>
- <td class="complete" align="center"></td>
- <td class="complete" align="center"></td>
- <td></td>
- <td></td>
-</tr>
-<tr>
- <td>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;5.3.1p6 Unary +</td>
- <td class="complete" align="center"></td>
- <td class="complete" align="center"></td>
- <td class="complete" align="center"></td>
- <td></td>
- <td></td>
-</tr>
-<tr>
- <td>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;5.3.1p7 Unary -</td>
- <td class="complete" align="center"></td>
- <td class="complete" align="center"></td>
- <td class="complete" align="center"></td>
- <td></td>
- <td></td>
-</tr>
-<tr>
- <td>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;5.3.1p8 Unary !</td>
- <td class="complete" align="center"></td>
- <td class="complete" align="center"></td>
- <td class="complete" align="center"></td>
- <td></td>
- <td></td>
-</tr>
-<tr>
- <td>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;5.3.1p9 Unary ~</td>
- <td class="complete" align="center"></td>
- <td class="complete" align="center"></td>
- <td class="complete" align="center"></td>
- <td></td>
- <td></td>
-</tr>
-<tr>
- <td>&nbsp;&nbsp;&nbsp;&nbsp;5.3.2 [expr.pre.incr]</td>
- <td class="complete" align="center"></td>
- <td class="complete" align="center"></td>
- <td class="complete" align="center"></td>
- <td></td>
- <td></td>
-</tr>
-<tr>
- <td>&nbsp;&nbsp;&nbsp;&nbsp;5.3.3 [expr.sizeof]</td>
- <td class="complete" align="center"></td>
- <td class="complete" align="center"></td>
- <td class="complete" align="center"></td>
- <td></td>
- <td></td>
-</tr>
-<tr>
- <td>&nbsp;&nbsp;&nbsp;&nbsp;5.3.4 [expr.new]</td>
- <td class="complete" align="center"></td>
- <td class="complete" align="center"></td>
- <td class="advanced" align="center"></td>
- <td></td>
- <td>operator delete is not looked up, initialization not quite correct</td>
-</tr>
-<tr>
- <td>&nbsp;&nbsp;&nbsp;&nbsp;5.3.5 [expr.delete]</td>
- <td class="complete" align="center"></td>
- <td class="complete" align="center"></td>
- <td class="complete" align="center"></td>
- <td></td>
- <td></td>
-</tr>
-<tr>
- <td>&nbsp;&nbsp;5.4 [expr.cast]</td>
- <td class="complete" align="center"></td>
- <td class="advanced" align="center"></td>
- <td class="advanced"></td>
- <td></td>
- <td></td>
-</tr>
-<tr>
- <td>&nbsp;&nbsp;5.5 [expr.mptr.oper]</td>
- <td class="complete" align="center"></td>
- <td class="advanced"></td>
- <td class="advanced"></td>
- <td></td>
- <td>Dereferenced member function pointers have the wrong type(see FIXME in CheckPointerToMemberOperands).</td>
-</tr>
-<tr>
- <td>&nbsp;&nbsp;5.6 [expr.mul]</td>
- <td class="complete" align="center"></td>
- <td class="complete" align="center"></td>
- <td class="complete" align="center"></td>
- <td></td>
- <td></td>
-</tr>
-<tr>
- <td>&nbsp;&nbsp;5.7 [expr.add]</td>
- <td class="complete" align="center"></td>
- <td class="complete" align="center"></td>
- <td class="complete" align="center"></td>
- <td></td>
- <td></td>
-</tr>
-<tr>
- <td>&nbsp;&nbsp;5.8 [expr.shift]</td>
- <td class="complete" align="center"></td>
- <td class="complete" align="center"></td>
- <td class="complete" align="center"></td>
- <td></td>
- <td></td>
-</tr>
-<tr>
- <td>&nbsp;&nbsp;5.9 [expr.rel]</td>
- <td class="complete" align="center"></td>
- <td class="complete" align="center"></td>
- <td class="complete" align="center"></td>
- <td></td>
- <td></td>
-</tr>
-<tr>
- <td>&nbsp;&nbsp;5.10 [expr.eq]</td>
- <td class="complete" align="center"></td>
- <td class="complete" align="center"></td>
- <td class="complete" align="center"></td>
- <td></td>
- <td></td>
-</tr>
-<tr>
- <td>&nbsp;&nbsp;5.11 [expr.bit.and]</td>
- <td class="complete" align="center"></td>
- <td class="complete" align="center"></td>
- <td class="complete" align="center"></td>
- <td></td>
- <td></td>
-</tr>
-<tr>
- <td>&nbsp;&nbsp;5.12 [expr.xor]</td>
- <td class="complete" align="center"></td>
- <td class="complete" align="center"></td>
- <td class="complete" align="center"></td>
- <td></td>
- <td></td>
-</tr>
-<tr>
- <td>&nbsp;&nbsp;5.13 [expr.or]</td>
- <td class="complete" align="center"></td>
- <td class="complete" align="center"></td>
- <td class="complete" align="center"></td>
- <td></td>
- <td></td>
-</tr>
-<tr>
- <td>&nbsp;&nbsp;5.14 [expr.log.and]</td>
- <td class="complete" align="center"></td>
- <td class="complete" align="center"></td>
- <td class="complete" align="center"></td>
- <td></td>
- <td></td>
-</tr>
-<tr>
- <td>&nbsp;&nbsp;5.15 [expr.log.or]</td>
- <td class="complete" align="center"></td>
- <td class="complete" align="center"></td>
- <td class="complete" align="center"></td>
- <td></td>
- <td></td>
-</tr>
-<tr>
- <td>&nbsp;&nbsp;5.16 [expr.cond]</td>
- <td class="complete" align="center"></td>
- <td class="complete" align="center"></td>
- <td class="complete" align="center"></td>
- <td></td>
- <td>some invalid hierarchy casts still accepted, but that's a general problem</td>
-</tr>
-<tr>
- <td>&nbsp;&nbsp;5.17 [expr.ass]</td>
- <td class="complete" align="center"></td>
- <td class="complete" align="center"></td>
- <td class="complete" align="center"></td>
- <td></td>
- <td></td>
-</tr>
-<tr>
- <td>&nbsp;&nbsp;5.18 [expr.comma]</td>
- <td class="complete" align="center"></td>
- <td class="complete" align="center"></td>
- <td class="complete" align="center"></td>
- <td></td>
- <td></td>
-</tr>
-<tr>
- <td>&nbsp;&nbsp;5.19 [expr.const]</td>
- <td class="complete" align="center"></td>
- <td class="complete" align="center"></td>
- <td class="basic"></td>
- <td></td>
- <td>Uses C semantics</td>
-</tr>
-<tr>
- <td>6 [stmt.stmt]</td>
- <td class="complete" align="center"></td>
- <td class="complete" align="center"></td>
- <td class="complete" align="center"></td>
- <td></td>
- <td></td>
-</tr>
-<tr>
- <td>&nbsp;&nbsp;6.1 [stmt.label]</td>
- <td class="complete" align="center"></td>
- <td class="complete" align="center"></td>
- <td class="complete" align="center"></td>
- <td></td>
- <td></td>
-</tr>
-<tr>
- <td>&nbsp;&nbsp;6.2 [stmt.expr]</td>
- <td class="complete" align="center"></td>
- <td class="complete" align="center"></td>
- <td class="complete" align="center"></td>
- <td></td>
- <td></td>
-</tr>
-<tr>
- <td>&nbsp;&nbsp;6.3 [stmt.block]</td>
- <td class="complete" align="center"></td>
- <td class="complete" align="center"></td>
- <td class="complete" align="center"></td>
- <td></td>
- <td></td>
-</tr>
-<tr>
- <td>&nbsp;&nbsp;6.4 [stmt.select]</td>
- <td class="complete" align="center"></td>
- <td class="complete" align="center"></td>
- <td class="advanced" align="center"></td>
- <td></td>
- <td>Conversion of declarations to required types not really supported.</td>
-</tr>
-<tr>
- <td>&nbsp;&nbsp;&nbsp;&nbsp;6.4.1 [stmt.if]</td>
- <td class="complete" align="center"></td>
- <td class="complete" align="center"></td>
- <td class="complete" align="center"></td>
- <td></td>
- <td></td>
-</tr>
-<tr>
- <td>&nbsp;&nbsp;&nbsp;&nbsp;6.4.2 [stmt.switch]</td>
- <td class="complete" align="center"></td>
- <td class="complete" align="center"></td>
- <td class="complete" align="center"></td>
- <td></td>
- <td></td>
-</tr>
-<tr>
- <td>&nbsp;&nbsp;6.5 [stmt.iter]</td>
- <td class="complete" align="center"></td>
- <td class="complete" align="center"></td>
- <td class="advanced" align="center"></td>
- <td></td>
- <td>Conversion of declarations to required types not really supported.</td>
-</tr>
-<tr>
- <td>&nbsp;&nbsp;&nbsp;&nbsp;6.5.1 [stmt.while]</td>
- <td class="complete" align="center"></td>
- <td class="complete" align="center"></td>
- <td class="complete" align="center"></td>
- <td></td>
- <td></td>
-</tr>
-<tr>
- <td>&nbsp;&nbsp;&nbsp;&nbsp;6.5.2 [stmt.do]</td>
- <td class="complete" align="center"></td>
- <td class="complete" align="center"></td>
- <td class="complete" align="center"></td>
- <td></td>
- <td></td>
-</tr>
-<tr>
- <td>&nbsp;&nbsp;&nbsp;&nbsp;6.5.3 [stmt.for]</td>
- <td class="complete" align="center"></td>
- <td class="complete" align="center"></td>
- <td class="complete" align="center"></td>
- <td></td>
- <td></td>
-</tr>
-<tr>
- <td>&nbsp;&nbsp;6.6 [stmt.jump]</td>
- <td class="complete" align="center"></td>
- <td class="complete" align="center"></td>
- <td class="complete" align="center"></td>
- <td></td>
- <td></td>
-</tr>
-<tr>
- <td>&nbsp;&nbsp;&nbsp;&nbsp;6.6.1 [stmt.break]</td>
- <td class="complete" align="center"></td>
- <td class="complete" align="center"></td>
- <td class="complete" align="center"></td>
- <td></td>
- <td></td>
-</tr>
-<tr>
- <td>&nbsp;&nbsp;&nbsp;&nbsp;6.6.2 [stmt.cont]</td>
- <td class="complete" align="center"></td>
- <td class="complete" align="center"></td>
- <td class="complete" align="center"></td>
- <td></td>
- <td></td>
-</tr>
-<tr>
- <td>&nbsp;&nbsp;&nbsp;&nbsp;6.6.3 [stmt.return]</td>
- <td class="complete" align="center"></td>
- <td class="complete" align="center"></td>
- <td class="complete" align="center"></td>
- <td></td>
- <td></td>
-</tr>
-<tr>
- <td>&nbsp;&nbsp;&nbsp;&nbsp;6.6.4 [stmt.goto]</td>
- <td class="complete" align="center"></td>
- <td class="complete" align="center"></td>
- <td class="complete" align="center"></td>
- <td></td>
- <td></td>
-</tr>
-<tr>
- <td>&nbsp;&nbsp;6.7 [stmt.dcl]</td>
- <td class="complete" align="center"></td>
- <td class="complete" align="center"></td>
- <td class="advanced" align="center"></td>
- <td></td>
- <td>Existence and accessibility of destructors is not tested for.</td>
-</tr>
-<tr>
- <td>&nbsp;&nbsp;6.8 [stmt.ambig]</td>
- <td class="complete" align="center"></td>
- <td class="complete" align="center"></td>
- <td class="complete" align="center"></td>
- <td></td>
- <td></td>
-</tr>
-<tr><td>7 [dcl.dcl]</td><td></td><td></td><td></td><td></td><td></td></tr>
-<tr><td>
- &nbsp;&nbsp;7.1 [dcl.spec]</td>
- <td class="advanced" align="center"></td>
- <td class="advanced" align="center"></td>
- <td class="advanced" align="center"></td>
- <td></td>
- <td></td>
-</tr>
-<tr>
- <td>&nbsp;&nbsp;&nbsp;&nbsp;7.1.1 [dcl.stc]</td>
- <td class="complete" align="center"></td>
- <td class="advanced" align="center"></td>
- <td class="advanced" align="center"></td>
- <td></td>
- <td>Linkage merging has some errors.</td>
-</tr>
-<tr>
- <td>&nbsp;&nbsp;&nbsp;&nbsp;7.1.2 [dcl.fct.spec]</td>
- <td class="complete" align="center"></td>
- <td class="complete" align="center"></td>
- <td class="complete" align="center"></td>
- <td></td>
- <td></td>
-</tr>
-<tr>
- <td>&nbsp;&nbsp;&nbsp;&nbsp;7.1.3 [dcl.typedef]</td>
- <td class="complete" align="center"></td>
- <td class="complete" align="center"></td>
- <td class="complete" align="center"></td>
- <td class="complete" align="center"></td>
- <td></td>
-</tr>
-<tr>
- <td>&nbsp;&nbsp;&nbsp;&nbsp;7.1.4 [dcl.friend]</td>
- <td class="medium"></td>
- <td class="medium"></td>
- <td class="medium"></td>
- <td></td>
- <td></td>
-</tr>
-<tr>
- <td>&nbsp;&nbsp;&nbsp;&nbsp;7.1.5 [dcl.type]</td>
- <td class="complete" align="center"></td>
- <td class="complete" align="center"></td>
- <td class="complete" align="center"></td>
- <td></td>
- <td></td>
-</tr>
-<tr>
- <td>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;7.1.5.1 [dcl.type.cv]</td>
- <td class="complete" align="center"></td>
- <td class="complete" align="center"></td>
- <td class="complete" align="center"></td>
- <td></td>
- <td></td>
-</tr>
-<tr>
- <td>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;7.1.5.2 [dcl.type.simple]</td>
- <td class="advanced"></td>
- <td class="advanced"></td>
- <td class="advanced"></td>
- <td></td>
- <td></td>
-</tr>
-<tr>
- <td>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;7.1.5.3 [dcl.type.elab]</td>
- <td class="advanced"></td>
- <td class="advanced"></td>
- <td class="advanced"></td>
- <td></td>
- <td></td>
-</tr>
-<tr>
- <td>&nbsp;&nbsp;7.2 [dcl.enum]</td>
- <td class="complete" align="center"></td>
- <td class="complete" align="center"></td>
- <td class="complete" align="center"></td>
- <td></td>
- <td></td>
-</tr>
-<tr>
- <td>&nbsp;&nbsp;7.3 [basic.namespace]</td>
- <td class="complete" align="center"></td>
- <td class="complete" align="center"></td>
- <td class="complete" align="center"></td>
- <td></td>
- <td></td>
-</tr>
-<tr>
- <td>&nbsp;&nbsp;&nbsp;&nbsp;7.3.1 [namespace.def]</td>
- <td class="advanced"></td>
- <td class="advanced"></td>
- <td class="advanced"></td>
- <td></td>
- <td></td>
-</tr>
-<tr>
- <td>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;7.3.1.1 [namespace.unnamed]</td>
- <td class="complete" align="center"></td>
- <td class="complete" align="center"></td>
- <td class="complete"></td>
- <td></td>
- <td></td>
-</tr>
-<tr>
- <td>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;7.3.1.2 [namespace.memdef]</td>
- <td class="complete" align="center"></td>
- <td class="complete" align="center"></td>
- <td class="advanced"></td>
- <td></td>
- <td></td>
-</tr>
-<tr>
- <td>&nbsp;&nbsp;&nbsp;&nbsp;7.3.2 [namespace.alias]</td>
- <td class="complete" align="center"></td>
- <td class="complete" align="center"></td>
- <td class="complete" align="center"></td>
- <td class="na">N/A</td>
- <td></td>
-</tr>
-<tr>
- <td>&nbsp;&nbsp;&nbsp;&nbsp;7.3.3 [namespace.udecl]</td>
- <td class="complete" align="center"></td>
- <td class="complete" align="center"></td>
- <td class="complete" align="center"></td>
- <td class="na">N/A</td>
- <td></td>
-</tr>
-<tr>
- <td>&nbsp;&nbsp;&nbsp;&nbsp;7.3.4[namespace.udir]</td>
- <td class="complete" align="center"></td>
- <td class="complete" align="center"></td>
- <td class="advanced"></td>
- <td class="broken" align="center"></td>
- <td>Example in p4 fails.</td>
-</tr>
-<tr><td>
- &nbsp;&nbsp;7.4 [dcl.asm]</td>
- <td class="complete" align="center"></td>
- <td class="complete" align="center"></td>
- <td class="complete" align="center"></td>
- <td></td>
- <td></td>
-</tr>
-<tr>
- <td>&nbsp;&nbsp;7.5 [dcl.link]</td>
- <td class="complete" align="center"></td>
- <td class="medium"></td>
- <td class="medium"></td>
- <td></td>
- <td></td>
-</tr>
-<tr>
- <td>8 [dcl.decl]</td><td></td><td></td><td></td><td></td><td></td>
-</tr>
-<tr>
- <td>&nbsp;&nbsp;8.1 [dcl.name]</td>
- <td class="complete" align="center"></td>
- <td class="complete" align="center"></td>
- <td class="complete" align="center"></td>
- <td class="na">N/A</td>
- <td></td>
-</tr>
-<tr>
- <td>&nbsp;&nbsp;8.2 [dcl.ambig.res]</td>
- <td class="complete" align="center">&#x2713;</td>
- <td class="na" align="center">N/A</td>
- <td class="complete" align="center">&#x2713;</td>
- <td class="na">N/A</td>
- <td></td>
-</tr>
-<tr>
- <td>&nbsp;&nbsp;8.3 [dcl.meaning]</td>
- <td class="complete" align="center"></td>
- <td class="complete" align="center"></td>
- <td class="advanced" align="center"></td>
- <td class="na">N/A</td>
- <td></td>
-</tr>
- <tr>
- <td>&nbsp;&nbsp;&nbsp;&nbsp;8.3.1 [dcl.ptr]</td>
- <td class="complete" align="center"></td>
- <td class="complete" align="center"></td>
- <td class="complete" align="center"></td>
- <td class="na">N/A</td>
- <td></td>
- </tr>
- <tr>
- <td>&nbsp;&nbsp;&nbsp;&nbsp;8.3.2 [dcl.ref]</td>
- <td class="complete" align="center"></td>
- <td class="complete" align="center"></td>
- <td class="complete" align="center"></td>
- <td class="na">N/A</td>
- <td></td>
- </tr>
- <tr>
- <td>&nbsp;&nbsp;&nbsp;&nbsp;8.3.3 [dcl.mptr]</td>
- <td class="complete" align="center"></td>
- <td class="complete" align="center"></td>
- <td class="complete" align="center"></td>
- <td class="na">N/A</td>
- <td></td>
- </tr>
- <tr>
- <td>&nbsp;&nbsp;&nbsp;&nbsp;8.3.4 [dcl.array]</td>
- <td class="complete" align="center"></td>
- <td class="complete" align="center"></td>
- <td class="complete" align="center"></td>
- <td class="na">N/A</td>
- <td></td>
- </tr>
- <tr>
- <td>&nbsp;&nbsp;&nbsp;&nbsp;8.3.5 [dcl.fct]</td>
- <td class="complete" align="center"></td>
- <td class="complete" align="center"></td>
- <td class="complete" align="center"></td>
- <td class="na">N/A</td>
- <td></td>
- </tr>
- <tr>
- <td>&nbsp;&nbsp;&nbsp;&nbsp;8.3.6 [dcl.fct.default]</td>
- <td class="advanced" align="center"></td>
- <td class="advanced" align="center"></td>
- <td class="advanced" align="center"></td>
- <td class="na">N/A</td>
- <td>Partial support for default arguments of templates.</td>
-</tr>
-<tr>
- <td>&nbsp;&nbsp;8.4 [dcl.fct.def]</td>
- <td class="complete" align="center"></td>
- <td class="complete" align="center"></td>
- <td class="complete" align="center"></td>
- <td class="medium" align="center"></td>
- <td></td>
-</tr>
-<tr>
- <td>&nbsp;&nbsp;8.5 [dcl.init]</td>
- <td class="advanced" align="center"></td>
- <td class="advanced" align="center"></td>
- <td class="advanced" align="center"></td>
- <td class="medium" align="center"></td>
- <td></td>
-</tr>
-<tr>
- <td>&nbsp;&nbsp;&nbsp;&nbsp;8.5.1[dcl.init.aggr]</td>
- <td class="advanced" align="center"></td>
- <td class="advanced" align="center"></td>
- <td class="medium" align="center"></td>
- <td class="basic" align="center"></td>
- <td>No CodeGen for dynamic initialization.</td>
-</tr>
-<tr>
- <td>&nbsp;&nbsp;&nbsp;&nbsp;8.5.2[dcl.init.string]</td>
- <td class="advanced" align="center"></td>
- <td class="advanced" align="center"></td>
- <td class="medium" align="center"></td>
- <td class="basic" align="center"></td>
- <td></td>
-</tr>
-<tr>
- <td>&nbsp;&nbsp;&nbsp;&nbsp;8.5.3 [dcl.init.ref]</td>
- <td class="advanced" align="center"></td>
- <td class="advanced" align="center"></td>
- <td class="medium" align="center"></td>
- <td class="basic" align="center"></td>
- <td></td>
-</tr>
-<tr>
- <td>9 [class]</td>
- <td class="advanced" align="center"></td>
- <td></td>
- <td></td>
- <td></td>
- <td></td>
-</tr>
-<tr>
- <td>&nbsp;&nbsp;9.1 [class.name]</td>
- <td class="complete" align="center"></td>
- <td class="complete" align="center"></td>
- <td class="complete" align="center"></td>
- <td class="na" align="center">N/A</td>
- <td></td>
-</tr>
-<tr>
- <td>&nbsp;&nbsp;9.2 [class.mem]</td>
- <td class="advanced" align="center"></td>
- <td class="advanced" align="center"></td>
- <td class="advanced" align="center"></td>
- <td class="medium" align="center"></td>
- <td></td>
-</tr>
-<tr>
- <td>&nbsp;&nbsp;9.3 [class.mfct]</td>
- <td class="complete" align="center"></td>
- <td class="advanced" align="center"></td>
- <td class="advanced" align="center"></td>
- <td class="basic" align="center"></td>
- <td></td>
-</tr>
-<tr>
- <td>&nbsp;&nbsp;&nbsp;&nbsp;9.3.1 [class.mfct.non-static]</td>
- <td class="complete" align="center"></td>
- <td class="advanced" align="center"></td>
- <td class="advanced" align="center"></td>
- <td class="basic" align="center"></td>
- <td></td>
-</tr>
-<tr>
- <td>&nbsp;&nbsp;&nbsp;&nbsp;9.3.2 [class.this]</td>
- <td class="complete" align="center"></td>
- <td class="advanced" align="center"></td>
- <td class="advanced" align="center"></td>
- <td class="basic"></td>
- <td></td>
-</tr>
-<tr>
- <td>&nbsp;&nbsp;9.4 [class.static]</td>
- <td class="complete" align="center"></td>
- <td class="complete" align="center"></td>
- <td class="advanced" align="center"></td>
- <td class="basic"></td>
- <td></td>
-</tr>
-<tr>
- <td>&nbsp;&nbsp;&nbsp;&nbsp;9.4.1 [class.static.mfct]</td>
- <td class="complete" align="center"></td>
- <td class="complete" align="center"></td>
- <td class="advanced" align="center"></td>
- <td class="basic"></td>
- <td></td>
-</tr>
-<tr>
- <td>&nbsp;&nbsp;&nbsp;&nbsp;9.4.2 [class.static.data]</td>
- <td class="complete" align="center"></td>
- <td class="complete" align="center"></td>
- <td class="advanced" align="center"></td>
- <td class="basic"></td>
- <td></td>
-</tr>
-<tr>
- <td>&nbsp;&nbsp;9.5 [class.union]</td>
- <td class="complete" align="center"></td>
- <td class="complete" align="center"></td>
- <td class="complete"></td>
- <td class="complete"></td>
- <td></td>
-</tr>
-<tr>
- <td>&nbsp;&nbsp;9.6 [class.bit]</td>
- <td class="complete" align="center"></td>
- <td class="complete" align="center"></td>
- <td class="complete" align="center"></td>
- <td class="complete" align="center"></td>
- <td></td>
-</tr>
-<tr>
- <td>&nbsp;&nbsp;9.7 [class.nest]</td>
- <td class="complete" align="center"></td>
- <td class="advanced"></td>
- <td class="advanced"></td>
- <td class="na" align="center">N/A</td>
- <td></td>
-</tr>
-<tr>
- <td>&nbsp;&nbsp;9.8 [class.local]</td>
- <td class="complete" align="center">&#x2713;</td>
- <td class="complete" align="center">&#x2713;</td>
- <td class="complete" align="center">&#x2713;</td>
- <td class="na" align="center">N/A</td>
- <td></td>
-</tr>
-<tr>
- <td>&nbsp;&nbsp;9.9 [class.nested.type]</td>
- <td class="complete" align="center">&#x2713;</td>
- <td class="complete" align="center">&#x2713;</td>
- <td class="complete" align="center">&#x2713;</td>
- <td class="na" align="center">N/A</td>
- <td></td>
-</tr>
-<tr>
- <td>10 [class.derived]</td>
- <td class="advanced" align="center"></td>
- <td class="advanced" align="center"></td>
- <td class="advanced" align="center"></td>
- <td class="medium" align="center"></td>
- <td></td>
-</tr>
-<tr>
- <td>&nbsp;&nbsp;10.1 [class.mi]</td>
- <td class="advanced" align="center"></td>
- <td class="advanced" align="center"></td>
- <td class="advanced" align="center"></td>
- <td class="medium" align="center"></td>
- <td></td>
-</tr>
-<tr>
- <td>&nbsp;&nbsp;10.2 [class.member.lookup]</td>
- <td class="complete" align="center"></td>
- <td class="complete" align="center"></td>
- <td class="complete" align="center"></td>
- <td class="na" align="center">N/A</td>
- <td></td>
-</tr>
-<tr>
- <td>&nbsp;&nbsp;10.3 [class.virtual]</td>
- <td class="advanced" align="center"></td>
- <td class="advanced" align="center"></td>
- <td class="advanced" align="center"></td>
- <td class="medium" align="center"></td>
- <td></td>
-</tr>
-<tr>
- <td>&nbsp;&nbsp;10.4 [class.abstract]</td>
- <td class="complete" align="center"></td>
- <td class="complete" align="center"></td>
- <td class="complete" align="center"></td>
- <td class="na" align="center">N/A</td>
- <td></td>
- </tr>
-<tr>
- <td>11 [class.access]</td>
- <td class="medium" align="center"></td>
- <td class="medium" align="center"></td>
- <td class="broken" align="center"></td>
- <td class="na" align="center">N/A</td>
- <td></td>
-</tr>
-<tr>
- <td>&nbsp;&nbsp;11.1 [class.access.spec]</td>
- <td class="complete" align="center"></td>
- <td class="advanced" align="center"></td>
- <td class="complete" align="center"></td>
- <td class="na" align="center">N/A</td>
- <td></td>
-</tr>
-<tr>
- <td>&nbsp;&nbsp;11.2 [class.access.base]</td>
- <td class="complete" align="center"></td>
- <td class="complete" align="center"></td>
- <td class="broken" align="center"></td>
- <td class="na" align="center">N/A</td>
- <td></td>
-</tr>
-<tr>
- <td>&nbsp;&nbsp;11.3 [class.access.dcl]</td>
- <td class="broken" align="center"></td>
- <td class="broken" align="center"></td>
- <td class="broken" align="center"></td>
- <td class="na" align="center">N/A</td>
- <td></td>
-</tr>
-<tr>
- <td>&nbsp;&nbsp;11.4 [class.friend]</td>
- <td class="medium" align="center"></td>
- <td class="medium" align="center"></td>
- <td class="medium" align="center"></td>
- <td class="na" align="center">N/A</td>
- <td></td>
-</tr>
-<tr>
- <td>&nbsp;&nbsp;11.5 [class.protected]</td>
- <td class="na" align="center"></td>
- <td class="complete" align="center"></td>
- <td class="broken" align="center"></td>
- <td class="na" align="center">N/A</td>
- <td></td>
-</tr>
-<tr>
- <td>&nbsp;&nbsp;11.6 [class.access.virt]</td>
- <td class="na" align="center"></td>
- <td class="na" align="center"></td>
- <td class="broken" align="center"></td>
- <td class="na" align="center">N/A</td>
- <td></td>
-</tr>
-<tr>
- <td>&nbsp;&nbsp;11.7 [class.paths]</td>
- <td class="na" align="center"></td>
- <td class="na" align="center"></td>
- <td class="broken" align="center"></td>
- <td class="na" align="center">N/A</td>
- <td></td>
-</tr>
-<tr>
- <td>&nbsp;&nbsp;11.8 [class.access.nest]</td>
- <td class="na" align="center"></td>
- <td class="na" align="center"></td>
- <td class="broken" align="center"></td>
- <td class="na" align="center">N/A</td>
- <td></td>
-</tr>
-<tr><td>12 [special]</td><td></td><td></td><td></td><td></td><td></td></tr>
-<tr>
- <td>&nbsp;&nbsp;12.1 [class.ctor]</td>
- <td class="advanced" align="center"></td>
- <td class="advanced" align="center"></td>
- <td class="advanced" align="center"></td>
- <td class="advanced" align="center"></td>
- <td></td>
-</tr>
-<tr>
- <td>&nbsp;&nbsp;12.2 [class.temporary]</td>
- <td class="na" align="center">N/A</td>
- <td class="medium" align="center"></td>
- <td class="medium" align="center"></td>
- <td class="medium" align="center"></td>
- <td></td>
-</tr>
-<tr>
- <td>&nbsp;&nbsp;12.3 [class.conv]</td>
- <td class="advanced" align="center"></td>
- <td class="advanced" align="center"></td>
- <td class="advanced" align="center"></td>
- <td class="advanced" align="center"></td>
- <td></td>
-</tr>
-<tr>
- <td>&nbsp;&nbsp;&nbsp;&nbsp;12.3.1 [class.conv.ctor]</td>
- <td class="complete" align="center"></td>
- <td class="advanced" align="center"></td>
- <td class="advanced" align="center"></td>
- <td class="advanced" align="center"></td>
- <td></td>
-</tr>
-<tr>
- <td>&nbsp;&nbsp;&nbsp;&nbsp;12.3.2 [class.conv.fct]</td>
- <td class="complete" align="center"></td>
- <td class="advanced" align="center"></td>
- <td class="advanced" align="center"></td>
- <td class="advanced" align="center"></td>
- <td></td>
-</tr>
-<tr>
- <td>&nbsp;&nbsp;12.4 [class.dtor]</td>
- <td class="advanced" align="center"></td>
- <td class="medium" align="center"></td>
- <td class="medium" align="center"></td>
- <td class="medium" align="center"></td>
- <td></td>
-</tr>
-<tr><td>&nbsp;&nbsp;12.5 [class.free]</td><td></td><td></td><td></td><td></td><td></td></tr>
-<tr><td>&nbsp;&nbsp;12.6 [class.init]</td><td></td><td></td><td></td><td></td><td></td></tr>
-<tr><td>&nbsp;&nbsp;&nbsp;&nbsp;12.6.1 [class.expl.init]</td><td></td><td></td><td></td><td></td><td></td></tr>
-<tr>
- <td>&nbsp;&nbsp;&nbsp;&nbsp;12.6.2 [class.base.init]</td>
- <td class="advanced" align="center"></td>
- <td class="medium" align="center"></td>
- <td class="advanced" align="center"></td>
- <td class="advanced" align="center"></td>
- <td>Most of the semantics of base initializations are implemented.</td>
-</tr>
-<tr><td>&nbsp;&nbsp;12.7 [class.cdtor]</td><td></td><td></td><td></td><td></td><td></td></tr>
-<tr>
- <td>&nbsp;&nbsp;12.8 [class.copy]</td>
- <td class="advanced" align="center"></td>
- <td class="advanced" align="center"></td>
- <td class="advanced" align="center"></td>
- <td class="advanced" align="center"></td>
- <td>Most of the semantics of copy constructors are implemented.</td>
-</tr>
-
-<tr><td>13 [over]</td><td></td><td></td><td></td><td></td><td></td></tr>
-<tr>
- <td>&nbsp;&nbsp;13.1 [over.load]</td>
- <td class="na" align="center">N/A</td>
- <td class="advanced" align="center"></td>
- <td class="advanced" align="center"></td>
- <td class="medium" align="center"></td>
- <td></td>
-</tr>
-<tr>
- <td>&nbsp;&nbsp;13.2 [over.dcl]</td>
- <td class="na" align="center">N/A</td>
- <td class="advanced" align="center"></td>
- <td class="advanced" align="center"></td>
- <td class="na" align="center">N/A</td>
- <td></td>
-</tr>
-<tr>
- <td>&nbsp;&nbsp;13.3 [over.match]</td>
- <td class="na" align="center">N/A</td>
- <td class="advanced" align="center"></td>
- <td class="advanced" align="center"></td>
- <td class="na" align="center">N/A</td>
- <td></td>
-</tr>
-<tr>
- <td>&nbsp;&nbsp;&nbsp;&nbsp;13.3.1 [over.match.funcs]</td>
- <td class="na" align="center">N/A</td>
- <td class="advanced" align="center"></td>
- <td class="advanced" align="center"></td>
- <td class="na" align="center">N/A</td>
- <td></td>
-</tr>
-<tr>
- <td>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;13.3.1.1 [over.match.call]</td>
- <td class="na" align="center">N/A</td>
- <td class="advanced" align="center"></td>
- <td class="advanced" align="center"></td>
- <td class="na" align="center">N/A</td>
- <td></td>
-</tr>
-<tr>
- <td>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;13.3.1.1.1 [over.call.func]</td>
- <td class="na" align="center">N/A</td>
- <td class="advanced" align="center"></td>
- <td class="advanced" align="center"></td>
- <td class="na" align="center">N/A</td>
- <td></td>
-</tr>
-<tr>
- <td>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;13.3.1.1.2 [over.call.object]</td>
- <td class="na" align="center">N/A</td>
- <td class="advanced" align="center"></td>
- <td class="advanced" align="center"></td>
- <td class="na" align="center">N/A</td>
- <td></td>
-</tr>
-<tr>
- <td>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;13.3.1.2 [over.match.oper]</td>
- <td class="na" align="center">N/A</td>
- <td class="advanced" align="center"></td>
- <td class="advanced" align="center"></td>
- <td class="na" align="center">N/A</td>
- <td></td>
-</tr>
-<tr>
- <td>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;13.3.1.3 [over.match.ctor]</td>
- <td class="na" align="center">N/A</td>
- <td class="advanced" align="center"></td>
- <td class="advanced" align="center"></td>
- <td class="na" align="center">N/A</td>
- <td></td>
-</tr>
-<tr>
- <td>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;13.3.1.4 [over.match.copy]</td>
- <td class="na" align="center">N/A</td>
- <td class="advanced" align="center"></td>
- <td class="advanced" align="center"></td>
- <td class="na" align="center">N/A</td>
- <td></td>
-</tr>
-<tr>
- <td>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;13.3.1.5 [over.match.conv]</td>
- <td class="na" align="center">N/A</td>
- <td class="advanced" align="center"></td>
- <td class="advanced" align="center"></td>
- <td class="na" align="center">N/A</td>
- <td></td>
-</tr>
-<tr>
- <td>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;13.3.1.6 [over.match.ref]</td>
- <td class="na" align="center">N/A</td>
- <td class="advanced" align="center"></td>
- <td class="advanced" align="center"></td>
- <td class="na" align="center">N/A</td>
- <td></td>
-</tr>
-<tr>
- <td>&nbsp;&nbsp;&nbsp;&nbsp;13.3.2 [over.match.viable]</td>
- <td class="na" align="center">N/A</td>
- <td class="advanced" align="center"></td>
- <td class="advanced" align="center"></td>
- <td class="na" align="center">N/A</td>
- <td></td>
-</tr>
-<tr>
- <td>&nbsp;&nbsp;&nbsp;&nbsp;13.3.3 [over.match.best]</td>
- <td class="na" align="center">N/A</td>
- <td class="advanced" align="center"></td>
- <td class="advanced" align="center"></td>
- <td class="na" align="center">N/A</td>
- <td></td>
-</tr>
-<tr>
- <td>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;13.3.3.1 [over.best.ics]</td>
- <td class="na" align="center">N/A</td>
- <td class="advanced" align="center"></td>
- <td class="advanced" align="center"></td>
- <td class="na" align="center">N/A</td>
- <td></td>
-</tr>
-<tr>
- <td>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;13.3.3.1.1 [over.ics.scs]</td>
- <td class="na" align="center">N/A</td>
- <td class="advanced" align="center"></td>
- <td class="advanced" align="center"></td>
- <td class="na" align="center">N/A</td>
- <td></td>
-</tr>
-<tr>
- <td>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;13.3.3.1.2 [over.ics.user]</td>
- <td class="na" align="center">N/A</td>
- <td class="advanced" align="center"></td>
- <td class="advanced" align="center"></td>
- <td class="na" align="center">N/A</td>
- <td></td>
-</tr>
-<tr>
- <td>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;13.3.3.1.3 [over.ics.ellipsis]</td>
- <td class="na" align="center">N/A</td>
- <td class="advanced" align="center"></td>
- <td class="advanced" align="center"></td>
- <td class="na" align="center">N/A</td>
- <td></td>
-</tr>
-<tr>
- <td>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;13.3.3.1.4 [over.ics.ref]</td>
- <td class="na" align="center">N/A</td>
- <td class="advanced" align="center"></td>
- <td class="advanced" align="center"></td>
- <td class="na" align="center">N/A</td>
- <td></td>
-</tr>
-<tr>
- <td>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;13.3.3.2 [over.ics.rank]</td>
- <td class="na" align="center">N/A</td>
- <td class="advanced" align="center"></td>
- <td class="advanced" align="center"></td>
- <td class="na" align="center">N/A</td>
- <td></td>
-</tr>
-<tr>
- <td>&nbsp;&nbsp;13.4 [over.over]</td>
- <td class="na" align="center">N/A</td>
- <td class="advanced" align="center"></td>
- <td class="advanced" align="center"></td>
- <td class="na" align="center">N/A</td>
- <td></td>
-</tr>
-<tr>
- <td>&nbsp;&nbsp;13.5 [over.oper]</td>
- <td class="advanced" align="center"></td>
- <td class="advanced" align="center"></td>
- <td class="advanced" align="center"></td>
- <td class="na" align="center">N/A</td>
- <td></td>
-</tr>
-<tr>
- <td>&nbsp;&nbsp;&nbsp;&nbsp;13.5.1 [over.unary]</td>
- <td class="na" align="center">N/A</td>
- <td class="advanced" align="center"></td>
- <td class="advanced" align="center"></td>
- <td class="na" align="center">N/A</td>
- <td></td>
-</tr>
-<tr>
- <td>&nbsp;&nbsp;&nbsp;&nbsp;13.5.2 [over.binary]</td>
- <td class="na" align="center">N/A</td>
- <td class="advanced" align="center"></td>
- <td class="advanced" align="center"></td>
- <td class="na" align="center">N/A</td>
- <td></td>
-</tr>
-<tr>
- <td>&nbsp;&nbsp;&nbsp;&nbsp;13.5.3 [over.ass]</td>
- <td class="na" align="center">N/A</td>
- <td class="advanced" align="center"></td>
- <td class="advanced" align="center"></td>
- <td class="na" align="center">N/A</td>
- <td></td>
-</tr>
-<tr>
- <td>&nbsp;&nbsp;&nbsp;&nbsp;13.5.4 [over.call]</td>
- <td class="na" align="center">N/A</td>
- <td class="advanced" align="center"></td>
- <td class="advanced" align="center"></td>
- <td class="na" align="center">N/A</td>
- <td></td>
-</tr>
-<tr>
- <td>&nbsp;&nbsp;&nbsp;&nbsp;13.5.5 [over.sub]</td>
- <td class="na" align="center">N/A</td>
- <td class="advanced" align="center"></td>
- <td class="advanced" align="center"></td>
- <td class="na" align="center">N/A</td>
- <td></td>
-</tr>
-<tr>
- <td>&nbsp;&nbsp;&nbsp;&nbsp;13.5.6 [over.ref]</td>
- <td class="na" align="center">N/A</td>
- <td class="advanced" align="center"></td>
- <td class="advanced" align="center"></td>
- <td class="na" align="center">N/A</td>
- <td></td>
-</tr>
-<tr>
- <td>&nbsp;&nbsp;&nbsp;&nbsp;13.5.7 [over.inc]</td>
- <td class="na" align="center">N/A</td>
- <td class="advanced" align="center"></td>
- <td class="advanced" align="center"></td>
- <td class="na" align="center">N/A</td>
- <td></td>
-</tr>
-<tr>
- <td>&nbsp;&nbsp;13.6 [over.built]</td>
- <td class="na" align="center">N/A</td>
- <td class="advanced" align="center"></td>
- <td class="medium" align="center"></td>
- <td class="na" align="center">N/A</td>
- <td>Missing support for the ternary operator (p24, p25).</td>
-</tr>
-<tr>
- <td>14 [temp]</td>
- <td class="medium" align="center"></td>
- <td class="basic" align="center"></td>
- <td class="basic" align="center"></td>
- <td class="broken" align="center"></td>
- <td></td>
-</tr>
-<tr>
- <td>&nbsp;&nbsp;14.1 [temp.param]</td>
- <td class="complete" align="center">&#x2713;</td>
- <td class="complete" align="center">&#x2713;</td>
- <td class="medium" align="center"></td>
- <td class="na" align="center">N/A</td>
- <td></td>
-</tr>
-<tr>
- <td>&nbsp;&nbsp;14.2 [temp.names]</td>
- <td class="complete" align="center"></td>
- <td class="complete" align="center"></td>
- <td class="complete" align="center"></td>
- <td class="na" align="center">N/A</td>
- <td></td>
-</tr>
-<tr>
- <td>&nbsp;&nbsp;14.3 [temp.arg]</td>
- <td class="complete" align="center"></td>
- <td class="complete" align="center"></td>
- <td class="advanced" align="center"></td>
- <td class="na" align="center">N/A</td>
- <td></td>
-</tr>
-<tr>
- <td>&nbsp;&nbsp;&nbsp;&nbsp;14.3.1 [temp.arg.type]</td>
- <td class="complete" align="center">&#x2713;</td>
- <td class="complete" align="center">&#x2713;</td>
- <td class="complete" align="center"></td>
- <td class="na" align="center">N/A</td>
- <td>Paragraph 3 will be tested elsewhere</td>
-</tr>
-<tr>
- <td>&nbsp;&nbsp;&nbsp;&nbsp;14.3.2 [temp.arg.nontype]</td>
- <td class="complete" align="center"></td>
- <td class="complete" align="center"></td>
- <td class="complete" align="center"></td>
- <td class="na" align="center">N/A</td>
- <td></td>
-</tr>
-<tr>
- <td>&nbsp;&nbsp;&nbsp;&nbsp;14.3.3 [temp.arg.template]</td>
- <td class="complete" align="center"></td>
- <td class="medium" align="center"></td>
- <td class="basic" align="center"></td>
- <td class="na" align="center">N/A</td>
- <td></td>
-</tr>
-<tr>
- <td>&nbsp;&nbsp;14.4 [temp.type]</td>
- <td class="na" align="center">N/A</td>
- <td class="complete" align="center">&#x2713;</td>
- <td class="complete" align="center">&#x2713;</td>
- <td class="na" align="center">N/A</td>
- <td></td>
-</tr>
-<tr>
- <td>&nbsp;&nbsp;14.5 [temp.decls]</td><td></td><td></td><td></td><td></td><td></td>
-</tr>
-<tr>
- <td>&nbsp;&nbsp;&nbsp;&nbsp;14.5.1 [temp.class]</td>
- <td class="advanced" align="center"></td>
- <td class="advanced" align="center"></td>
- <td class="advanced" align="center"></td>
- <td class="medium" align="center"></td>
- <td></td>
-</tr>
-<tr>
- <td>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;14.5.1.1 [temp.mem.func]</td>
- <td class="advanced" align="center"></td>
- <td class="advanced" align="center"></td>
- <td class="advanced" align="center"></td>
- <td class="medium" align="center"></td>
- <td></td>
-</tr>
-<tr>
- <td>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;14.5.1.2 [temp.mem.class]</td>
- <td class="advanced" align="center"></td>
- <td class="advanced" align="center"></td>
- <td class="advanced" align="center"></td>
- <td class="medium" align="center"></td>
- <td></td>
-</tr>
-<tr>
- <td>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;14.5.1.3 [temp.static]</td>
- <td class="advanced" align="center"></td>
- <td class="advanced" align="center"></td>
- <td class="advanced" align="center"></td>
- <td class="medium" align="center"></td>
- <td></td>
-</tr>
-<tr>
- <td>&nbsp;&nbsp;&nbsp;&nbsp;14.5.2 [temp.mem]</td>
- <td class="advanced" align="center"></td>
- <td class="medium" align="center"></td>
- <td class="medium" align="center"></td>
- <td class="na" align="center"></td>
- <td></td>
-</tr>
-<tr>
- <td>&nbsp;&nbsp;&nbsp;&nbsp;14.5.3 [temp.friend]</td>
- <td class="medium" align="center"></td>
- <td class="medium" align="center"></td>
- <td class="broken" align="center"></td>
- <td class="na" align="center">N/A</td>
- <td></td>
-</tr>
-<tr>
- <td>&nbsp;&nbsp;&nbsp;&nbsp;14.5.4 [temp.class.spec]</td>
- <td class="complete" align="center"></td>
- <td class="complete" align="center"></td>
- <td class="complete" align="center"></td>
- <td class="na" align="center">N/A</td>
- <td></td>
-</tr>
-<tr>
- <td>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;14.5.4.1 [temp.class.spec.match]</td>
- <td class="na" align="center">N/A</td>
- <td class="na" align="center">N/A</td>
- <td class="complete" align="center"></td>
- <td class="na" align="center">N/A</td>
- <td></td>
-</tr>
-<tr>
- <td>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;14.5.4.2 [temp.class.order]</td>
- <td class="na" align="center"></td>
- <td class="advanced" align="center"></td>
- <td class="advanced" align="center"></td>
- <td class="na" align="center">N/A</td>
- <td></td>
-</tr>
-<tr>
- <td>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;14.5.5.3 [temp.class.spec.mfunc]</td>
- <td class="advanced" align="center"></td>
- <td class="advanced" align="center"></td>
- <td class="advanced" align="center"></td>
- <td class="na" align="center">N/A</td>
- <td></td>
-</tr>
-<tr>
- <td>&nbsp;&nbsp;&nbsp;&nbsp;14.5.5 [temp.fct]</td>
- <td class="advanced" align="center"></td>
- <td class="advanced" align="center"></td>
- <td class="advanced" align="center"></td>
- <td class="medium" align="center"></td>
- <td></td>
-</tr>
-<tr>
- <td>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;14.5.5.1 [temp.over.link]</td>
- <td class="na" align="center"></td>
- <td class="complete" align="center"></td>
- <td class="advanced" align="center"></td>
- <td class="na" align="center">N/A</td>
- <td></td>
-</tr>
-<tr>
- <td>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;14.5.5.2 [temp.func.order]</td>
- <td class="na" align="center"></td>
- <td class="advanced" align="center"></td>
- <td class="advanced" align="center"></td>
- <td class="na" align="center">N/A</td>
- <td></td>
-</tr>
-<tr>
- <td>&nbsp;&nbsp;14.6 [temp.res]</td>
- <td class="advanced" align="center"></td>
- <td class="advanced" align="center"></td>
- <td class="advanced" align="center"></td>
- <td class="na" align="center"></td>
- <td></td>
-</tr>
-<tr>
- <td>&nbsp;&nbsp;&nbsp;&nbsp;14.6.1 [temp.local]</td>
- <td class="advanced" align="center"></td>
- <td class="advanced" align="center"></td>
- <td class="advanced" align="center"></td>
- <td class="na" align="center"></td>
- <td></td>
-</tr>
-<tr>
- <td>&nbsp;&nbsp;&nbsp;&nbsp;14.6.2 [temp.dep]</td>
- <td class="na" align="center">N/A</td>
- <td class="advanced" align="center"></td>
- <td class="advanced" align="center"></td>
- <td class="na" align="center"></td>
- <td></td>
-</tr>
-<tr>
- <td>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;14.6.2.1 [temp.dep.type]</td>
- <td class="na" align="center">N/A</td>
- <td class="advanced" align="center"></td>
- <td class="advanced" align="center"></td>
- <td class="na" align="center"></td>
- <td></td>
-</tr>
-<tr>
- <td>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;14.6.2.2 [temp.dep.expr]</td>
- <td class="na" align="center">N/A</td>
- <td class="advanced" align="center"></td>
- <td class="advanced" align="center"></td>
- <td class="na" align="center"></td>
- <td></td>
-</tr>
-<tr>
- <td>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;14.6.2.3 [temp.dep.constexpr]</td>
- <td class="na" align="center">N/A</td>
- <td class="advanced" align="center"></td>
- <td class="advanced" align="center"></td>
- <td class="na" align="center"></td>
- <td></td>
-</tr>
-<tr>
- <td>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;14.6.2.4 [temp.dep.temp]</td>
- <td class="na" align="center">N/A</td>
- <td class="advanced" align="center"></td>
- <td class="advanced" align="center"></td>
- <td class="na" align="center"></td>
- <td></td>
-</tr>
-<tr>
- <td>&nbsp;&nbsp;&nbsp;&nbsp;14.6.3 [temp.nondep]</td>
- <td class="na" align="center">N/A</td>
- <td class="complete" align="center"></td>
- <td class="complete" align="center"></td>
- <td class="na" align="center"></td>
- <td></td>
-</tr>
-<tr>
- <td>&nbsp;&nbsp;&nbsp;&nbsp;14.6.4 [temp.dep.res]</td>
- <td class="na" align="center">N/A</td>
- <td class="advanced" align="center"></td>
- <td class="advanced" align="center"></td>
- <td class="na" align="center"></td>
- <td></td>
-</tr>
-<tr>
- <td>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;14.6.4.1 [temp.point]</td>
- <td class="na" align="center">N/A</td>
- <td class="medium" align="center"></td>
- <td class="medium" align="center"></td>
- <td class="medium" align="center"></td>
- <td></td>
-</tr>
-<tr>
- <td>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;14.6.4.2 [temp.dep.candidate]</td>
- <td class="na" align="center">N/A</td>
- <td class="advanced" align="center"></td>
- <td class="advanced" align="center"></td>
- <td class="na" align="center"></td>
- <td>Not restricted to functions with external linkage</td>
-</tr>
-<tr>
- <td>&nbsp;&nbsp;&nbsp;&nbsp;14.6.5 [temp.inject]</td>
- <td class="na" align="center">N/A</td>
- <td class="basic" align="center"></td>
- <td class="basic" align="center"></td>
- <td class="na" align="center"></td>
- <td></td>
-</tr>
-<tr>
- <td>&nbsp;&nbsp;14.7 [temp.spec]</td>
- <td class="advanced" align="center"></td>
- <td class="advanced" align="center"></td>
- <td class="advanced" align="center"></td>
- <td class="advanced" align="center"></td>
- <td></td>
-</tr>
-<tr>
- <td>&nbsp;&nbsp;&nbsp;&nbsp;14.7.1 [temp.inst]</td>
- <td class="na" align="center">N/A</td>
- <td class="na" align="center"></td>
- <td class="advanced" align="center"></td>
- <td class="advanced" align="center"></td>
- <td></td>
-</tr>
-<tr>
- <td>&nbsp;&nbsp;&nbsp;&nbsp;14.7.2 [temp.explicit]</td>
- <td class="complete" align="center"></td>
- <td class="advanced" align="center"></td>
- <td class="advanced" align="center"></td>
- <td class="complete" align="center"></td>
- <td>Cannot test paragraph 11 until access control is implemented.<br/>
- ASTs do not carry enough information to reproduce source code accurately.</td>
-</tr>
-<tr>
- <td>&nbsp;&nbsp;&nbsp;&nbsp;14.7.3 [temp.expl.spec]</td>
- <td class="complete" align="center">&#x2713;</td>
- <td class="advanced" align="center"></td>
- <td class="complete" align="center">&#x2713;</td>
- <td class="complete" align="center"></td>
- <td>ASTs do not carry enough information to reproduce source code accurately</td>
-</tr>
-<tr>
- <td>&nbsp;&nbsp;14.8 [temp.fct.spec]</td>
- <td class="advanced" align="center"></td>
- <td class="advanced" align="center"></td>
- <td class="advanced" align="center"></td>
- <td class="advanced" align="center"></td>
- <td></td>
-</tr>
-<tr>
- <td>&nbsp;&nbsp;&nbsp;&nbsp;14.8.1 [temp.arg.explicit]</td>
- <td class="advanced" align="center"></td>
- <td class="advanced" align="center"></td>
- <td class="advanced" align="center"></td>
- <td class="na" align="center"></td>
- <td></td>
-</tr>
-<tr>
- <td>&nbsp;&nbsp;&nbsp;&nbsp;14.8.2 [temp.deduct]</td>
- <td class="na" align="center">N/A</td>
- <td class="na" align="center">N/A</td>
- <td class="advanced" align="center"></td>
- <td class="na" align="center">N/A</td>
- <td></td>
-</tr>
-<tr>
- <td>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;14.8.2.1 [temp.deduct.call]</td>
- <td class="na" align="center"></td>
- <td class="complete" align="center"></td>
- <td class="advanced" align="center"></td>
- <td class="na" align="center"></td>
- <td></td>
-</tr>
-<tr>
- <td>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;14.8.2.2 [temp.deduct.funcaddr]</td>
- <td class="na" align="center">N/A</td>
- <td class="advanced" align="center"></td>
- <td class="advanced" align="center"></td>
- <td class="na" align="center">N/A</td>
- <td></td>
-</tr>
-<tr>
- <td>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;14.8.2.3 [temp.deduct.conv]</td>
- <td class="na" align="center"></td>
- <td class="advanced" align="center"></td>
- <td class="advanced" align="center"></td>
- <td class="na" align="center"></td>
- <td></td>
-</tr>
-<tr>
- <td>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;14.8.2.4 [temp.deduct.type]</td>
- <td class="na" align="center">N/A</td>
- <td class="complete" align="center"></td>
- <td class="advanced" align="center"></td>
- <td class="na" align="center">N/A</td>
- <td></td>
-</tr>
-<tr>
- <td>&nbsp;&nbsp;&nbsp;&nbsp;14.8.3 [temp.over]</td>
- <td class="na" align="center"></td>
- <td class="advanced" align="center"></td>
- <td class="advanced" align="center"></td>
- <td class="na" align="center"></td>
- <td></td>
-</tr>
-<tr>
- <td>15 [except]</td>
- <td class="complete" align="center"></td>
- <td class="complete" align="center"></td>
- <td class="complete" align="center"></td>
- <td></td>
- <td></td>
-</tr>
-<tr>
- <td>&nbsp;&nbsp;15.1 [except.throw]</td>
- <td class="na" align="center">N/A</td>
- <td class="na" align="center">N/A</td>
- <td class="advanced" align="center"></td>
- <td></td>
- <td></td>
-</tr>
-<tr>
- <td>&nbsp;&nbsp;15.2 [except.ctor]</td>
- <td class="na" align="center">N/A</td>
- <td class="na" align="center">N/A</td>
- <td class="na" align="center">N/A</td>
- <td></td>
- <td></td>
-</tr>
-<tr>
- <td>&nbsp;&nbsp;15.3 [except.handle]</td>
- <td class="na" align="center">N/A</td>
- <td class="na" align="center">N/A</td>
- <td class="advanced" align="center"></td>
- <td></td>
- <td>Not all constraints are checked</td>
-</tr>
-<tr>
- <td>&nbsp;&nbsp;15.4 [except.spec]</td>
- <td class="complete" align="center"></td>
- <td class="complete" align="center"></td>
- <td class="complete" align="center"></td>
- <td class="broken"></td>
- <td></td>
-</tr>
-<tr>
- <td>&nbsp;&nbsp;15.5 [except.special]</td>
- <td class="na" align="center">N/A</td>
- <td class="na" align="center">N/A</td>
- <td class="na" align="center">N/A</td>
- <td class="na" align="center">N/A</td>
- <td></td>
-</tr>
-<tr>
- <td>&nbsp;&nbsp;&nbsp;&nbsp;15.5.1 [except.terminate]</td>
- <td class="na" align="center">N/A</td>
- <td class="na" align="center">N/A</td>
- <td class="na" align="center">N/A</td>
- <td class="na" align="center">N/A</td>
- <td></td>
-</tr>
-<tr>
- <td>&nbsp;&nbsp;&nbsp;&nbsp;15.5.2 [except.unexpected]</td>
- <td class="na" align="center">N/A</td>
- <td class="na" align="center">N/A</td>
- <td class="na" align="center">N/A</td>
- <td class="na" align="center">N/A</td>
- <td></td>
-</tr>
-<tr>
- <td>&nbsp;&nbsp;&nbsp;&nbsp;15.5.3 [except.uncaught]</td>
- <td class="na" align="center">N/A</td>
- <td class="na" align="center">N/A</td>
- <td class="na" align="center">N/A</td>
- <td class="na" align="center">N/A</td>
- <td></td>
-</tr>
-<tr>
- <td>&nbsp;&nbsp;15.6 [except.access]</td>
- <td class="na" align="center">N/A</td>
- <td class="na" align="center">N/A</td>
- <td class="na" align="center">N/A</td>
- <td class="na" align="center">N/A</td>
- <td>Redundant - struck from C++0x</td>
-</tr>
-<tr><td>16 [cpp]</td><td></td><td></td><td></td><td></td><td></td></tr>
-<tr><td>&nbsp;&nbsp;16.1 [cpp.cond]</td><td></td><td></td><td></td><td></td><td></td></tr>
-<tr><td>&nbsp;&nbsp;16.2 [cpp.include]</td><td></td><td></td><td></td><td></td><td></td></tr>
-<tr><td>&nbsp;&nbsp;16.3 [cpp.replace]</td><td></td><td></td><td></td><td></td><td></td></tr>
-<tr><td>&nbsp;&nbsp;&nbsp;&nbsp;16.3.1 [cpp.subst]</td><td></td><td></td><td></td><td></td><td></td></tr>
-<tr><td>&nbsp;&nbsp;&nbsp;&nbsp;16.3.2 [cpp.stringize]</td><td></td><td></td><td></td><td></td><td></td></tr>
-<tr><td>&nbsp;&nbsp;&nbsp;&nbsp;16.3.3 [cpp.concat]</td><td></td><td></td><td></td><td></td><td></td></tr>
-<tr><td>&nbsp;&nbsp;&nbsp;&nbsp;16.3.4 [cpp.rescan]</td><td></td><td></td><td></td><td></td><td></td></tr>
-<tr><td>&nbsp;&nbsp;&nbsp;&nbsp;16.3.5 [cpp.scope]</td><td></td><td></td><td></td><td></td><td></td></tr>
-<tr><td>&nbsp;&nbsp;16.4 [cpp.line]</td><td></td><td></td><td></td><td></td><td></td></tr>
-<tr><td>&nbsp;&nbsp;16.5 [cpp.error]</td><td></td><td></td><td></td><td></td><td></td></tr>
-<tr><td>&nbsp;&nbsp;16.6 [cpp.pragma]</td><td></td><td></td><td></td><td></td><td></td></tr>
-<tr><td>&nbsp;&nbsp;16.7 [cpp.null]</td><td></td><td></td><td></td><td></td><td></td></tr>
-<tr><td>&nbsp;&nbsp;16.8 [cpp.predefined]</td><td></td><td></td><td></td><td></td><td></td></tr>
-<tr><td>A [gram]</td><td></td><td></td><td></td><td></td><td></td></tr>
-<tr><td>&nbsp;&nbsp;A.1 [gram.key]</td><td></td><td></td><td></td><td></td><td></td></tr>
-<tr><td>&nbsp;&nbsp;A.2 [gram.lex]</td><td></td><td></td><td></td><td></td><td></td></tr>
-<tr><td>&nbsp;&nbsp;A.3 [gram.basic]</td><td></td><td></td><td></td><td></td><td></td></tr>
-<tr><td>&nbsp;&nbsp;A.4 [gram.expr]</td><td></td><td></td><td></td><td></td><td></td></tr>
-<tr><td>&nbsp;&nbsp;A.5 [gram.stmt]</td><td></td><td></td><td></td><td></td><td></td></tr>
-<tr><td>&nbsp;&nbsp;A.6 [gram.dcl]</td><td></td><td></td><td></td><td></td><td></td></tr>
-<tr><td>&nbsp;&nbsp;A.7 [gram.decl]</td><td></td><td></td><td></td><td></td><td></td></tr>
-<tr><td>&nbsp;&nbsp;A.8 [gram.class]</td><td></td><td></td><td></td><td></td><td></td></tr>
-<tr><td>&nbsp;&nbsp;A.9 [gram.derived]</td><td></td><td></td><td></td><td></td><td></td></tr>
-<tr><td>&nbsp;&nbsp;A.10 [gram.special]</td><td></td><td></td><td></td><td></td><td></td></tr>
-<tr><td>&nbsp;&nbsp;A.11 [gram.over]</td><td></td><td></td><td></td><td></td><td></td></tr>
-<tr><td>&nbsp;&nbsp;A.12 [gram.temp]</td><td></td><td></td><td></td><td></td><td></td></tr>
-<tr><td>&nbsp;&nbsp;A.13 [gram.except]</td><td></td><td></td><td></td><td></td><td></td></tr>
-<tr><td>&nbsp;&nbsp;A.14 [gram.cpp]</td><td></td><td></td><td></td><td></td><td></td></tr>
-<tr><td>B [implimits]</td><td></td><td></td><td></td><td></td><td></td></tr>
-<tr><td>C [diff]</td><td></td><td></td><td></td><td></td><td></td></tr>
-<tr><td>&nbsp;&nbsp;C.1 [diff.iso]</td><td></td><td></td><td></td><td></td><td></td></tr>
-<tr><td>&nbsp;&nbsp;&nbsp;&nbsp;C.1.1 [diff.lex]</td><td></td><td></td><td></td><td></td><td></td></tr>
-<tr><td>&nbsp;&nbsp;&nbsp;&nbsp;C.1.2 [diff.basic]</td><td></td><td></td><td></td><td></td><td></td></tr>
-<tr><td>&nbsp;&nbsp;&nbsp;&nbsp;C.1.3 [diff.expr]</td><td></td><td></td><td></td><td></td><td></td></tr>
-<tr><td>&nbsp;&nbsp;&nbsp;&nbsp;C.1.4 [diff.stat]</td><td></td><td></td><td></td><td></td><td></td></tr>
-<tr><td>&nbsp;&nbsp;&nbsp;&nbsp;C.1.5 [diff.dcl]</td><td></td><td></td><td></td><td></td><td></td></tr>
-<tr><td>&nbsp;&nbsp;&nbsp;&nbsp;C.1.6 [diff.decl]</td><td></td><td></td><td></td><td></td><td></td></tr>
-<tr><td>&nbsp;&nbsp;&nbsp;&nbsp;C.1.7 [diff.class]</td><td></td><td></td><td></td><td></td><td></td></tr>
-<tr><td>&nbsp;&nbsp;&nbsp;&nbsp;C.1.8 [diff.special]</td><td></td><td></td><td></td><td></td><td></td></tr>
-<tr><td>&nbsp;&nbsp;&nbsp;&nbsp;C.1.9 [diff.cpp]</td><td></td><td></td><td></td><td></td><td></td></tr>
-<tr><td>&nbsp;&nbsp;C.2 [diff.library]</td><td></td><td></td><td></td><td></td><td></td></tr>
-<tr><td>&nbsp;&nbsp;&nbsp;&nbsp;C.2.1 [diff.mods.to.headers]</td><td></td><td></td><td></td><td></td><td></td></tr>
-<tr><td>&nbsp;&nbsp;&nbsp;&nbsp;C.2.2 [diff.mods.to.definitions]</td><td></td><td></td><td></td><td></td><td></td></tr>
-<tr><td>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;C.2.2.2 [diff.wchar.t]</td><td></td><td></td><td></td><td></td><td></td></tr>
-<tr><td>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;C.2.2.3 [diff.header.iso646.h]</td><td></td><td></td><td></td><td></td><td></td></tr>
-<tr><td>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;C.2.2.4 [diff.null]</td><td></td><td></td><td></td><td></td><td></td></tr>
-<tr><td>&nbsp;&nbsp;&nbsp;&nbsp;C.2.3 [diff.mods.to.declarations]</td><td></td><td></td><td></td><td></td><td></td></tr>
-<tr><td>&nbsp;&nbsp;&nbsp;&nbsp;C.2.4 [diff.mods.to.behavior]</td><td></td><td></td><td></td><td></td><td></td></tr>
-<tr><td>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;C.2.4.1 [diff.offsetof]</td><td></td><td></td><td></td><td></td><td></td></tr>
-<tr><td>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;C.2.4.2 [diff.malloc]</td><td></td><td></td><td></td><td></td><td></td></tr>
-<tr><td>D [depr]</td><td></td><td></td><td></td><td></td><td></td></tr>
-<tr><td>&nbsp;&nbsp;D.1 [depr.incr.bool]</td><td></td><td></td><td></td><td></td><td></td></tr>
-<tr><td>&nbsp;&nbsp;D.2 [depr.static]</td><td></td><td></td><td></td><td></td><td></td></tr>
-<tr><td>&nbsp;&nbsp;D.3 [depr.access.dcl]</td><td></td><td></td><td></td><td></td><td></td></tr>
-<tr><td>&nbsp;&nbsp;D.4 [depr.string]</td><td></td><td></td><td></td><td></td><td></td></tr>
-<tr><td>&nbsp;&nbsp;D.5 [depr.c.headers]</td><td></td><td></td><td></td><td></td><td></td></tr>
-<tr><td>E [extendid]</td><td></td><td></td><td></td><td></td><td></td></tr>
-<tr>
-</table>
- <h2 id="cxx0x">C++0x Implementation status</h2>
-<p>Clang's development effort is focused primarily on supporting the current ISO C++ standard (1998/2003). This section tracks the status of various C++0x features. In general, the implementations of these features are far less developed than C++98/03 features.</p>
-
-<table width="689" border="1" cellspacing="0">
- <td colspan="6" align="center" bgcolor="#ffffcc">C++0x Features</td>
-</tr>
<tr>
<td>Explicit conversion operators (<a href="http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2007/n2437.pdf">N2437</a>)</td>
<td class="complete" align="center"></td>
diff --git a/www/get_started.html b/www/get_started.html
index 141698f6e812..96979af32d06 100644
--- a/www/get_started.html
+++ b/www/get_started.html
@@ -61,6 +61,11 @@ follows:</p>
<li>Note: For subsequent Clang development, you can just do make at the
clang directory level.</li>
</ul>
+
+ <p>It is also possible to use CMake instead of the makefiles. With CMake it
+ is also possible to generate project files for several IDEs: Eclipse CDT4,
+ CodeBlocks, Qt-Creator (use the CodeBlocks generator), KDevelop3.</p>
+
<li>If you intend to work on Clang C++ support, you may need to tell it how
to find your C++ standard library headers. If Clang cannot find your
system libstdc++ headers, please follow these instructions:</li>