aboutsummaryrefslogtreecommitdiffstats
path: root/lib
diff options
context:
space:
mode:
authorDimitry Andric <dim@FreeBSD.org>2013-12-22 00:07:40 +0000
committerDimitry Andric <dim@FreeBSD.org>2013-12-22 00:07:40 +0000
commitbfef399519ca9b8a4b4c6b563253bad7e0eeffe0 (patch)
treedf8df0b0067b381eab470a3b8f28d14a552a6340 /lib
parent6a0372513edbc473b538d2f724efac50405d6fef (diff)
downloadsrc-bfef399519ca9b8a4b4c6b563253bad7e0eeffe0.tar.gz
src-bfef399519ca9b8a4b4c6b563253bad7e0eeffe0.zip
Vendor import of clang release_34 branch r197841 (effectively, 3.4 RC3):vendor/clang/clang-release_34-r197841
Notes
Notes: svn path=/vendor/clang/dist/; revision=259701 svn path=/vendor/clang/clang-release_34-r197841/; revision=259703; tag=vendor/clang/clang-release_34-r197841
Diffstat (limited to 'lib')
-rw-r--r--lib/ARCMigrate/ARCMT.cpp13
-rw-r--r--lib/ARCMigrate/CMakeLists.txt1
-rw-r--r--lib/ARCMigrate/FileRemapper.cpp57
-rw-r--r--lib/ARCMigrate/ObjCMT.cpp1572
-rw-r--r--lib/ARCMigrate/TransUnbridgedCasts.cpp11
-rw-r--r--lib/ARCMigrate/Transforms.cpp22
-rw-r--r--lib/ARCMigrate/Transforms.h6
-rw-r--r--lib/AST/APValue.cpp34
-rw-r--r--lib/AST/ASTContext.cpp816
-rw-r--r--lib/AST/ASTDiagnostic.cpp83
-rw-r--r--lib/AST/ASTDumper.cpp219
-rw-r--r--lib/AST/ASTImporter.cpp291
-rw-r--r--lib/AST/ASTTypeTraits.cpp105
-rw-r--r--lib/AST/AttrImpl.cpp1
-rw-r--r--lib/AST/CMakeLists.txt4
-rw-r--r--lib/AST/CXXABI.h8
-rw-r--r--lib/AST/CXXInheritance.cpp14
-rw-r--r--lib/AST/Comment.cpp15
-rw-r--r--lib/AST/CommentCommandTraits.cpp43
-rw-r--r--lib/AST/CommentLexer.cpp21
-rw-r--r--lib/AST/CommentParser.cpp21
-rw-r--r--lib/AST/CommentSema.cpp145
-rw-r--r--lib/AST/Decl.cpp800
-rw-r--r--lib/AST/DeclBase.cpp195
-rw-r--r--lib/AST/DeclCXX.cpp198
-rw-r--r--lib/AST/DeclFriend.cpp5
-rw-r--r--lib/AST/DeclObjC.cpp86
-rw-r--r--lib/AST/DeclOpenMP.cpp11
-rw-r--r--lib/AST/DeclPrinter.cpp29
-rw-r--r--lib/AST/DeclTemplate.cpp357
-rw-r--r--lib/AST/DeclarationName.cpp142
-rw-r--r--lib/AST/DumpXML.cpp1053
-rw-r--r--lib/AST/Expr.cpp462
-rw-r--r--lib/AST/ExprCXX.cpp268
-rw-r--r--lib/AST/ExprClassification.cpp13
-rw-r--r--lib/AST/ExprConstant.cpp1981
-rw-r--r--lib/AST/InheritViz.cpp38
-rw-r--r--lib/AST/ItaniumCXXABI.cpp18
-rw-r--r--lib/AST/ItaniumMangle.cpp577
-rw-r--r--lib/AST/Mangle.cpp153
-rw-r--r--lib/AST/MangleNumberingContext.cpp (renamed from lib/AST/LambdaMangleContext.cpp)28
-rw-r--r--lib/AST/MicrosoftCXXABI.cpp21
-rw-r--r--lib/AST/MicrosoftMangle.cpp992
-rw-r--r--lib/AST/NestedNameSpecifier.cpp3
-rw-r--r--lib/AST/ParentMap.cpp30
-rw-r--r--lib/AST/RawCommentList.cpp106
-rw-r--r--lib/AST/RecordLayout.cpp9
-rw-r--r--lib/AST/RecordLayoutBuilder.cpp1484
-rw-r--r--lib/AST/Stmt.cpp266
-rw-r--r--lib/AST/StmtIterator.cpp63
-rw-r--r--lib/AST/StmtPrinter.cpp112
-rw-r--r--lib/AST/StmtProfile.cpp75
-rw-r--r--lib/AST/TemplateBase.cpp81
-rw-r--r--lib/AST/Type.cpp128
-rw-r--r--lib/AST/TypeLoc.cpp53
-rw-r--r--lib/AST/TypePrinter.cpp130
-rw-r--r--lib/AST/VTableBuilder.cpp1662
-rw-r--r--lib/ASTMatchers/ASTMatchFinder.cpp425
-rw-r--r--lib/ASTMatchers/ASTMatchersInternal.cpp95
-rw-r--r--lib/ASTMatchers/CMakeLists.txt2
-rw-r--r--lib/ASTMatchers/Dynamic/CMakeLists.txt16
-rw-r--r--lib/ASTMatchers/Dynamic/Diagnostics.cpp220
-rw-r--r--lib/ASTMatchers/Dynamic/Makefile13
-rw-r--r--lib/ASTMatchers/Dynamic/Marshallers.h453
-rw-r--r--lib/ASTMatchers/Dynamic/Parser.cpp420
-rw-r--r--lib/ASTMatchers/Dynamic/Registry.cpp345
-rw-r--r--lib/ASTMatchers/Dynamic/VariantValue.cpp256
-rw-r--r--lib/ASTMatchers/Makefile2
-rw-r--r--lib/Analysis/AnalysisDeclContext.cpp39
-rw-r--r--lib/Analysis/CFG.cpp330
-rw-r--r--lib/Analysis/CFGReachabilityAnalysis.cpp9
-rw-r--r--lib/Analysis/CMakeLists.txt1
-rw-r--r--lib/Analysis/Consumed.cpp1521
-rw-r--r--lib/Analysis/FormatString.cpp50
-rw-r--r--lib/Analysis/LiveVariables.cpp3
-rw-r--r--lib/Analysis/PrintfFormatString.cpp31
-rw-r--r--lib/Analysis/ReachableCode.cpp13
-rw-r--r--lib/Analysis/ScanfFormatString.cpp18
-rw-r--r--lib/Analysis/ThreadSafety.cpp160
-rw-r--r--lib/Analysis/UninitializedValues.cpp30
-rw-r--r--lib/Basic/Builtins.cpp32
-rw-r--r--lib/Basic/DiagnosticIDs.cpp104
-rw-r--r--lib/Basic/FileManager.cpp149
-rw-r--r--lib/Basic/FileSystemStatCache.cpp60
-rw-r--r--lib/Basic/IdentifierTable.cpp52
-rw-r--r--lib/Basic/Module.cpp84
-rw-r--r--lib/Basic/ObjCRuntime.cpp8
-rw-r--r--lib/Basic/OpenMPKinds.cpp94
-rw-r--r--lib/Basic/OperatorPrecedence.cpp2
-rw-r--r--lib/Basic/SourceManager.cpp216
-rw-r--r--lib/Basic/TargetInfo.cpp79
-rw-r--r--lib/Basic/Targets.cpp2183
-rw-r--r--lib/Basic/Version.cpp2
-rw-r--r--lib/CMakeLists.txt13
-rw-r--r--lib/CodeGen/ABIInfo.h147
-rw-r--r--lib/CodeGen/BackendUtil.cpp40
-rw-r--r--lib/CodeGen/CGAtomic.cpp231
-rw-r--r--lib/CodeGen/CGBlocks.cpp40
-rw-r--r--lib/CodeGen/CGBuiltin.cpp2556
-rw-r--r--lib/CodeGen/CGCUDARuntime.cpp4
-rw-r--r--lib/CodeGen/CGCXX.cpp249
-rw-r--r--lib/CodeGen/CGCXXABI.cpp42
-rw-r--r--lib/CodeGen/CGCXXABI.h157
-rw-r--r--lib/CodeGen/CGCall.cpp237
-rw-r--r--lib/CodeGen/CGCall.h200
-rw-r--r--lib/CodeGen/CGClass.cpp393
-rw-r--r--lib/CodeGen/CGCleanup.cpp39
-rw-r--r--lib/CodeGen/CGCleanup.h12
-rw-r--r--lib/CodeGen/CGDebugInfo.cpp1355
-rw-r--r--lib/CodeGen/CGDebugInfo.h176
-rw-r--r--lib/CodeGen/CGDecl.cpp119
-rw-r--r--lib/CodeGen/CGDeclCXX.cpp80
-rw-r--r--lib/CodeGen/CGException.cpp33
-rw-r--r--lib/CodeGen/CGExpr.cpp939
-rw-r--r--lib/CodeGen/CGExprAgg.cpp285
-rw-r--r--lib/CodeGen/CGExprCXX.cpp235
-rw-r--r--lib/CodeGen/CGExprComplex.cpp167
-rw-r--r--lib/CodeGen/CGExprConstant.cpp95
-rw-r--r--lib/CodeGen/CGExprScalar.cpp402
-rw-r--r--lib/CodeGen/CGObjC.cpp30
-rw-r--r--lib/CodeGen/CGObjCGNU.cpp59
-rw-r--r--lib/CodeGen/CGObjCMac.cpp29
-rw-r--r--lib/CodeGen/CGObjCRuntime.cpp1
-rw-r--r--lib/CodeGen/CGRTTI.cpp62
-rw-r--r--lib/CodeGen/CGRecordLayoutBuilder.cpp54
-rw-r--r--lib/CodeGen/CGStmt.cpp184
-rw-r--r--lib/CodeGen/CGVTT.cpp34
-rw-r--r--lib/CodeGen/CGVTables.cpp363
-rw-r--r--lib/CodeGen/CGVTables.h40
-rw-r--r--lib/CodeGen/CGValue.h30
-rw-r--r--lib/CodeGen/CMakeLists.txt2
-rw-r--r--lib/CodeGen/CodeGenABITypes.cpp69
-rw-r--r--lib/CodeGen/CodeGenAction.cpp17
-rw-r--r--lib/CodeGen/CodeGenFunction.cpp152
-rw-r--r--lib/CodeGen/CodeGenFunction.h714
-rw-r--r--lib/CodeGen/CodeGenModule.cpp723
-rw-r--r--lib/CodeGen/CodeGenModule.h120
-rw-r--r--lib/CodeGen/CodeGenTBAA.cpp73
-rw-r--r--lib/CodeGen/CodeGenTBAA.h2
-rw-r--r--lib/CodeGen/CodeGenTypes.cpp7
-rw-r--r--lib/CodeGen/CodeGenTypes.h7
-rw-r--r--lib/CodeGen/EHScopeStack.h489
-rw-r--r--lib/CodeGen/ItaniumCXXABI.cpp514
-rw-r--r--lib/CodeGen/MicrosoftCXXABI.cpp1289
-rw-r--r--lib/CodeGen/MicrosoftVBTables.cpp233
-rw-r--r--lib/CodeGen/MicrosoftVBTables.h129
-rw-r--r--lib/CodeGen/ModuleBuilder.cpp36
-rw-r--r--lib/CodeGen/TargetInfo.cpp842
-rw-r--r--lib/CodeGen/TargetInfo.h34
-rw-r--r--lib/Driver/Action.cpp1
-rw-r--r--lib/Driver/Arg.cpp123
-rw-r--r--lib/Driver/ArgList.cpp423
-rw-r--r--lib/Driver/CC1AsOptions.cpp21
-rw-r--r--lib/Driver/CMakeLists.txt7
-rw-r--r--lib/Driver/Compilation.cpp199
-rw-r--r--lib/Driver/Driver.cpp512
-rw-r--r--lib/Driver/DriverOptions.cpp19
-rw-r--r--lib/Driver/InputInfo.h11
-rw-r--r--lib/Driver/Job.cpp163
-rw-r--r--lib/Driver/OptTable.cpp388
-rw-r--r--lib/Driver/Option.cpp200
-rw-r--r--lib/Driver/SanitizerArgs.cpp389
-rw-r--r--lib/Driver/SanitizerArgs.h220
-rw-r--r--lib/Driver/ToolChain.cpp64
-rw-r--r--lib/Driver/ToolChains.cpp1199
-rw-r--r--lib/Driver/ToolChains.h292
-rw-r--r--lib/Driver/Tools.cpp2230
-rw-r--r--lib/Driver/Tools.h188
-rw-r--r--lib/Driver/Types.cpp17
-rw-r--r--lib/Driver/WindowsToolChain.cpp55
-rw-r--r--lib/Edit/Commit.cpp14
-rw-r--r--lib/Format/BreakableToken.cpp504
-rw-r--r--lib/Format/BreakableToken.h349
-rw-r--r--lib/Format/CMakeLists.txt2
-rw-r--r--lib/Format/ContinuationIndenter.cpp884
-rw-r--r--lib/Format/ContinuationIndenter.h327
-rw-r--r--lib/Format/Encoding.h144
-rw-r--r--lib/Format/Format.cpp2231
-rw-r--r--lib/Format/FormatToken.cpp204
-rw-r--r--lib/Format/FormatToken.h452
-rw-r--r--lib/Format/TokenAnnotator.cpp1096
-rw-r--r--lib/Format/TokenAnnotator.h257
-rw-r--r--lib/Format/UnwrappedLineParser.cpp862
-rw-r--r--lib/Format/UnwrappedLineParser.h163
-rw-r--r--lib/Format/WhitespaceManager.cpp413
-rw-r--r--lib/Format/WhitespaceManager.h182
-rw-r--r--lib/Frontend/ASTConsumers.cpp54
-rw-r--r--lib/Frontend/ASTUnit.cpp294
-rw-r--r--lib/Frontend/CacheTokens.cpp45
-rw-r--r--lib/Frontend/ChainedIncludesSource.cpp6
-rw-r--r--lib/Frontend/CompilerInstance.cpp219
-rw-r--r--lib/Frontend/CompilerInvocation.cpp281
-rw-r--r--lib/Frontend/CreateInvocationFromCommandLine.cpp9
-rw-r--r--lib/Frontend/DependencyFile.cpp4
-rw-r--r--lib/Frontend/FrontendAction.cpp12
-rw-r--r--lib/Frontend/FrontendActions.cpp27
-rw-r--r--lib/Frontend/FrontendOptions.cpp1
-rw-r--r--lib/Frontend/HeaderIncludeGen.cpp24
-rw-r--r--lib/Frontend/InitHeaderSearch.cpp47
-rw-r--r--lib/Frontend/InitPreprocessor.cpp76
-rw-r--r--lib/Frontend/MultiplexConsumer.cpp20
-rw-r--r--lib/Frontend/PrintPreprocessedOutput.cpp97
-rw-r--r--lib/Frontend/TextDiagnostic.cpp64
-rw-r--r--lib/Frontend/TextDiagnosticPrinter.cpp3
-rw-r--r--lib/Frontend/VerifyDiagnosticConsumer.cpp8
-rw-r--r--lib/FrontendTool/CMakeLists.txt18
-rw-r--r--lib/FrontendTool/ExecuteCompilerInvocation.cpp60
-rw-r--r--lib/Headers/CMakeLists.txt17
-rw-r--r--lib/Headers/Intrin.h784
-rw-r--r--lib/Headers/avx2intrin.h25
-rw-r--r--lib/Headers/avxintrin.h22
-rw-r--r--lib/Headers/cpuid.h126
-rw-r--r--lib/Headers/emmintrin.h36
-rw-r--r--lib/Headers/f16cintrin.h4
-rw-r--r--lib/Headers/immintrin.h4
-rw-r--r--lib/Headers/limits.h6
-rw-r--r--lib/Headers/module.map11
-rw-r--r--lib/Headers/prfchwintrin.h5
-rw-r--r--lib/Headers/rdseedintrin.h4
-rw-r--r--lib/Headers/rtmintrin.h5
-rw-r--r--lib/Headers/shaintrin.h74
-rw-r--r--lib/Headers/smmintrin.h15
-rw-r--r--lib/Headers/tbmintrin.h158
-rw-r--r--lib/Headers/tgmath.h6
-rw-r--r--lib/Headers/unwind.h159
-rw-r--r--lib/Headers/x86intrin.h4
-rw-r--r--lib/Headers/xmmintrin.h18
-rw-r--r--lib/Headers/xopintrin.h393
-rw-r--r--lib/Index/CMakeLists.txt11
-rw-r--r--lib/Index/CommentToXML.cpp1136
-rw-r--r--lib/Index/Makefile13
-rw-r--r--lib/Index/SimpleFormatContext.h77
-rw-r--r--lib/Index/USRGeneration.cpp803
-rw-r--r--lib/Lex/HeaderMap.cpp2
-rw-r--r--lib/Lex/HeaderSearch.cpp125
-rw-r--r--lib/Lex/Lexer.cpp470
-rw-r--r--lib/Lex/LiteralSupport.cpp156
-rw-r--r--lib/Lex/ModuleMap.cpp392
-rw-r--r--lib/Lex/PPConditionalDirectiveRecord.cpp4
-rw-r--r--lib/Lex/PPDirectives.cpp219
-rw-r--r--lib/Lex/PPExpressions.cpp29
-rw-r--r--lib/Lex/PPLexerChange.cpp86
-rw-r--r--lib/Lex/PPMacroExpansion.cpp280
-rw-r--r--lib/Lex/PTHLexer.cpp89
-rw-r--r--lib/Lex/Pragma.cpp206
-rw-r--r--lib/Lex/PreprocessingRecord.cpp3
-rw-r--r--lib/Lex/Preprocessor.cpp48
-rw-r--r--lib/Lex/PreprocessorLexer.cpp5
-rw-r--r--lib/Lex/TokenLexer.cpp61
-rw-r--r--lib/Lex/UnicodeCharSets.h102
-rwxr-xr-xlib/Makefile8
-rw-r--r--lib/Parse/CMakeLists.txt3
-rw-r--r--lib/Parse/ParseAST.cpp2
-rw-r--r--lib/Parse/ParseCXXInlineMethods.cpp548
-rw-r--r--lib/Parse/ParseDecl.cpp723
-rw-r--r--lib/Parse/ParseDeclCXX.cpp421
-rw-r--r--lib/Parse/ParseExpr.cpp172
-rw-r--r--lib/Parse/ParseExprCXX.cpp252
-rw-r--r--lib/Parse/ParseInit.cpp10
-rw-r--r--lib/Parse/ParseObjc.cpp109
-rw-r--r--lib/Parse/ParseOpenMP.cpp347
-rw-r--r--lib/Parse/ParsePragma.cpp85
-rw-r--r--lib/Parse/ParsePragma.h15
-rw-r--r--lib/Parse/ParseStmt.cpp209
-rw-r--r--lib/Parse/ParseTemplate.cpp115
-rw-r--r--lib/Parse/ParseTentative.cpp418
-rw-r--r--lib/Parse/Parser.cpp184
-rw-r--r--lib/Parse/RAIIObjectsForParser.h7
-rw-r--r--lib/Rewrite/Core/HTMLRewrite.cpp5
-rw-r--r--lib/Rewrite/Core/Rewriter.cpp5
-rw-r--r--lib/Rewrite/Frontend/FixItRewriter.cpp2
-rw-r--r--lib/Rewrite/Frontend/FrontendActions.cpp10
-rw-r--r--lib/Rewrite/Frontend/InclusionRewriter.cpp71
-rw-r--r--lib/Rewrite/Frontend/RewriteMacros.cpp2
-rw-r--r--lib/Rewrite/Frontend/RewriteModernObjC.cpp208
-rw-r--r--lib/Rewrite/Frontend/RewriteObjC.cpp66
-rw-r--r--lib/Sema/AnalysisBasedWarnings.cpp213
-rw-r--r--lib/Sema/AttributeList.cpp40
-rw-r--r--lib/Sema/CMakeLists.txt2
-rw-r--r--lib/Sema/DeclSpec.cpp100
-rw-r--r--lib/Sema/IdentifierResolver.cpp40
-rw-r--r--lib/Sema/JumpDiagnostics.cpp9
-rw-r--r--lib/Sema/MultiplexExternalSemaSource.cpp31
-rw-r--r--lib/Sema/ScopeInfo.cpp15
-rw-r--r--lib/Sema/Sema.cpp188
-rw-r--r--lib/Sema/SemaAccess.cpp30
-rw-r--r--lib/Sema/SemaAttr.cpp42
-rw-r--r--lib/Sema/SemaCXXScopeSpec.cpp50
-rw-r--r--lib/Sema/SemaCast.cpp142
-rw-r--r--lib/Sema/SemaChecking.cpp844
-rw-r--r--lib/Sema/SemaCodeComplete.cpp218
-rw-r--r--lib/Sema/SemaDecl.cpp2406
-rw-r--r--lib/Sema/SemaDeclAttr.cpp1965
-rw-r--r--lib/Sema/SemaDeclCXX.cpp2108
-rw-r--r--lib/Sema/SemaDeclObjC.cpp408
-rw-r--r--lib/Sema/SemaExceptionSpec.cpp204
-rw-r--r--lib/Sema/SemaExpr.cpp2496
-rw-r--r--lib/Sema/SemaExprCXX.cpp972
-rw-r--r--lib/Sema/SemaExprMember.cpp175
-rw-r--r--lib/Sema/SemaExprObjC.cpp296
-rw-r--r--lib/Sema/SemaFixItUtils.cpp28
-rw-r--r--lib/Sema/SemaInit.cpp1181
-rw-r--r--lib/Sema/SemaLambda.cpp948
-rw-r--r--lib/Sema/SemaLookup.cpp924
-rw-r--r--lib/Sema/SemaObjCProperty.cpp444
-rw-r--r--lib/Sema/SemaOpenMP.cpp1207
-rw-r--r--lib/Sema/SemaOverload.cpp1531
-rw-r--r--lib/Sema/SemaPseudoObject.cpp39
-rw-r--r--lib/Sema/SemaStmt.cpp573
-rw-r--r--lib/Sema/SemaStmtAsm.cpp11
-rw-r--r--lib/Sema/SemaTemplate.cpp1386
-rw-r--r--lib/Sema/SemaTemplateDeduction.cpp699
-rw-r--r--lib/Sema/SemaTemplateInstantiate.cpp295
-rw-r--r--lib/Sema/SemaTemplateInstantiateDecl.cpp1403
-rw-r--r--lib/Sema/SemaTemplateVariadic.cpp97
-rw-r--r--lib/Sema/SemaType.cpp810
-rw-r--r--lib/Sema/TargetAttributesSema.cpp136
-rw-r--r--lib/Sema/TreeTransform.h691
-rw-r--r--lib/Sema/TypeLocBuilder.cpp136
-rw-r--r--lib/Sema/TypeLocBuilder.h86
-rw-r--r--lib/Serialization/ASTCommon.cpp5
-rw-r--r--lib/Serialization/ASTCommon.h4
-rw-r--r--lib/Serialization/ASTReader.cpp293
-rw-r--r--lib/Serialization/ASTReaderDecl.cpp772
-rw-r--r--lib/Serialization/ASTReaderStmt.cpp145
-rw-r--r--lib/Serialization/ASTWriter.cpp229
-rw-r--r--lib/Serialization/ASTWriterDecl.cpp170
-rw-r--r--lib/Serialization/ASTWriterStmt.cpp110
-rw-r--r--lib/Serialization/GeneratePCH.cpp17
-rw-r--r--lib/Serialization/GlobalModuleIndex.cpp8
-rw-r--r--lib/Serialization/ModuleManager.cpp13
-rw-r--r--lib/StaticAnalyzer/Checkers/BasicObjCFoundationChecks.cpp365
-rw-r--r--lib/StaticAnalyzer/Checkers/BuiltinFunctionChecker.cpp30
-rw-r--r--lib/StaticAnalyzer/Checkers/CMakeLists.txt2
-rw-r--r--lib/StaticAnalyzer/Checkers/CStringChecker.cpp84
-rw-r--r--lib/StaticAnalyzer/Checkers/CStringSyntaxChecker.cpp3
-rw-r--r--lib/StaticAnalyzer/Checkers/CallAndMessageChecker.cpp59
-rw-r--r--lib/StaticAnalyzer/Checkers/CheckSecuritySyntaxOnly.cpp63
-rw-r--r--lib/StaticAnalyzer/Checkers/CheckSizeofPointer.cpp5
-rw-r--r--lib/StaticAnalyzer/Checkers/CheckerDocumentation.cpp2
-rw-r--r--lib/StaticAnalyzer/Checkers/Checkers.td8
-rw-r--r--lib/StaticAnalyzer/Checkers/ClangSACheckers.h2
-rw-r--r--lib/StaticAnalyzer/Checkers/DeadStoresChecker.cpp42
-rw-r--r--lib/StaticAnalyzer/Checkers/DebugCheckers.cpp49
-rw-r--r--lib/StaticAnalyzer/Checkers/DirectIvarAssignment.cpp50
-rw-r--r--lib/StaticAnalyzer/Checkers/DynamicTypePropagation.cpp4
-rw-r--r--lib/StaticAnalyzer/Checkers/ExprInspectionChecker.cpp20
-rw-r--r--lib/StaticAnalyzer/Checkers/GenericTaintChecker.cpp3
-rw-r--r--lib/StaticAnalyzer/Checkers/IdempotentOperationChecker.cpp19
-rw-r--r--lib/StaticAnalyzer/Checkers/IdenticalExprChecker.cpp226
-rw-r--r--lib/StaticAnalyzer/Checkers/MallocChecker.cpp120
-rw-r--r--lib/StaticAnalyzer/Checkers/MallocOverflowSecurityChecker.cpp4
-rw-r--r--lib/StaticAnalyzer/Checkers/MallocSizeofChecker.cpp2
-rw-r--r--lib/StaticAnalyzer/Checkers/NoReturnFunctionChecker.cpp27
-rw-r--r--lib/StaticAnalyzer/Checkers/ObjCContainersASTChecker.cpp3
-rw-r--r--lib/StaticAnalyzer/Checkers/RetainCountChecker.cpp220
-rw-r--r--lib/StaticAnalyzer/Checkers/SimpleStreamChecker.cpp8
-rw-r--r--lib/StaticAnalyzer/Checkers/UndefResultChecker.cpp9
-rw-r--r--lib/StaticAnalyzer/Checkers/UndefinedArraySubscriptChecker.cpp3
-rw-r--r--lib/StaticAnalyzer/Checkers/UndefinedAssignmentChecker.cpp8
-rw-r--r--lib/StaticAnalyzer/Checkers/UnreachableCodeChecker.cpp3
-rw-r--r--lib/StaticAnalyzer/Checkers/VirtualCallChecker.cpp4
-rw-r--r--lib/StaticAnalyzer/Core/AnalyzerOptions.cpp12
-rw-r--r--lib/StaticAnalyzer/Core/BugReporter.cpp1194
-rw-r--r--lib/StaticAnalyzer/Core/BugReporterVisitors.cpp90
-rw-r--r--lib/StaticAnalyzer/Core/CMakeLists.txt2
-rw-r--r--lib/StaticAnalyzer/Core/CallEvent.cpp61
-rw-r--r--lib/StaticAnalyzer/Core/CheckerContext.cpp2
-rw-r--r--lib/StaticAnalyzer/Core/CheckerManager.cpp42
-rw-r--r--lib/StaticAnalyzer/Core/CommonBugCategories.cpp (renamed from lib/StaticAnalyzer/Checkers/CommonBugCategories.cpp)10
-rw-r--r--lib/StaticAnalyzer/Core/ExplodedGraph.cpp6
-rw-r--r--lib/StaticAnalyzer/Core/ExprEngine.cpp143
-rw-r--r--lib/StaticAnalyzer/Core/ExprEngineC.cpp79
-rw-r--r--lib/StaticAnalyzer/Core/ExprEngineCXX.cpp92
-rw-r--r--lib/StaticAnalyzer/Core/ExprEngineCallAndReturn.cpp45
-rw-r--r--lib/StaticAnalyzer/Core/HTMLDiagnostics.cpp59
-rw-r--r--lib/StaticAnalyzer/Core/MemRegion.cpp85
-rw-r--r--lib/StaticAnalyzer/Core/PathDiagnostic.cpp83
-rw-r--r--lib/StaticAnalyzer/Core/PlistDiagnostics.cpp28
-rw-r--r--lib/StaticAnalyzer/Core/PrettyStackTraceLocationContext.h45
-rw-r--r--lib/StaticAnalyzer/Core/ProgramState.cpp126
-rw-r--r--lib/StaticAnalyzer/Core/RegionStore.cpp139
-rw-r--r--lib/StaticAnalyzer/Core/SValBuilder.cpp36
-rw-r--r--lib/StaticAnalyzer/Core/SimpleConstraintManager.cpp59
-rw-r--r--lib/StaticAnalyzer/Core/SimpleConstraintManager.h6
-rw-r--r--lib/StaticAnalyzer/Core/SimpleSValBuilder.cpp212
-rw-r--r--lib/StaticAnalyzer/Core/Store.cpp5
-rw-r--r--lib/StaticAnalyzer/Core/SymbolManager.cpp6
-rw-r--r--lib/StaticAnalyzer/Core/TextPathDiagnostics.cpp72
-rw-r--r--lib/StaticAnalyzer/Frontend/AnalysisConsumer.cpp120
-rw-r--r--lib/Tooling/ArgumentsAdjusters.cpp29
-rw-r--r--lib/Tooling/CommonOptionsParser.cpp5
-rw-r--r--lib/Tooling/CompilationDatabase.cpp185
-rw-r--r--lib/Tooling/FileMatchTrie.cpp2
-rw-r--r--lib/Tooling/JSONCompilationDatabase.cpp4
-rw-r--r--lib/Tooling/Refactoring.cpp190
-rw-r--r--lib/Tooling/Tooling.cpp232
397 files changed, 67004 insertions, 28930 deletions
diff --git a/lib/ARCMigrate/ARCMT.cpp b/lib/ARCMigrate/ARCMT.cpp
index a6d48762fe55..3e429beded5d 100644
--- a/lib/ARCMigrate/ARCMT.cpp
+++ b/lib/ARCMigrate/ARCMT.cpp
@@ -150,7 +150,7 @@ static bool HasARCRuntime(CompilerInvocation &origCI) {
// and avoid unrelated complications.
llvm::Triple triple(origCI.getTargetOpts().Triple);
- if (triple.getOS() == llvm::Triple::IOS)
+ if (triple.isiOS())
return triple.getOSMajorVersion() >= 5;
if (triple.getOS() == llvm::Triple::Darwin)
@@ -321,10 +321,6 @@ bool arcmt::checkForManualIssues(CompilerInvocation &origCI,
DiagClient->EndSourceFile();
errRec.FinishCapture();
- // If we are migrating code that gets the '-fobjc-arc' flag, make sure
- // to remove it so that we don't get errors from normal compilation.
- origCI.getLangOpts()->ObjCAutoRefCount = false;
-
return capturedDiags.hasErrors() || testAct.hasReportedErrors();
}
@@ -374,9 +370,6 @@ static bool applyTransforms(CompilerInvocation &origCI,
origCI.getLangOpts()->ObjCAutoRefCount = true;
return migration.getRemapper().overwriteOriginal(*Diags);
} else {
- // If we are migrating code that gets the '-fobjc-arc' flag, make sure
- // to remove it so that we don't get errors from normal compilation.
- origCI.getLangOpts()->ObjCAutoRefCount = false;
return migration.getRemapper().flushToDisk(outputDir, *Diags);
}
}
@@ -545,7 +538,7 @@ MigrationProcess::RewriteListener::~RewriteListener() { }
MigrationProcess::MigrationProcess(const CompilerInvocation &CI,
DiagnosticConsumer *diagClient,
StringRef outputDir)
- : OrigCI(CI), DiagClient(diagClient) {
+ : OrigCI(CI), DiagClient(diagClient), HadARCErrors(false) {
if (!outputDir.empty()) {
IntrusiveRefCntPtr<DiagnosticIDs> DiagID(new DiagnosticIDs());
IntrusiveRefCntPtr<DiagnosticsEngine> Diags(
@@ -588,6 +581,8 @@ bool MigrationProcess::applyTransform(TransformFn trans,
}
Unit->setOwnsRemappedFileBuffers(false); // FileRemapper manages that.
+ HadARCErrors = HadARCErrors || capturedDiags.hasErrors();
+
// Don't filter diagnostics anymore.
Diags->setClient(DiagClient, /*ShouldOwnClient=*/false);
diff --git a/lib/ARCMigrate/CMakeLists.txt b/lib/ARCMigrate/CMakeLists.txt
index da51d6db83b8..c55261277dd1 100644
--- a/lib/ARCMigrate/CMakeLists.txt
+++ b/lib/ARCMigrate/CMakeLists.txt
@@ -40,4 +40,5 @@ target_link_libraries(clangARCMigrate
clangFrontend
clangRewriteCore
clangRewriteFrontend
+ clangStaticAnalyzerCheckers
)
diff --git a/lib/ARCMigrate/FileRemapper.cpp b/lib/ARCMigrate/FileRemapper.cpp
index 6a8686c4ff0f..a14226e43fe0 100644
--- a/lib/ARCMigrate/FileRemapper.cpp
+++ b/lib/ARCMigrate/FileRemapper.cpp
@@ -43,10 +43,9 @@ void FileRemapper::clear(StringRef outputDir) {
std::string FileRemapper::getRemapInfoFile(StringRef outputDir) {
assert(!outputDir.empty());
- llvm::sys::Path dir(outputDir);
- llvm::sys::Path infoFile = dir;
- infoFile.appendComponent("remap");
- return infoFile.str();
+ SmallString<128> InfoFile = outputDir;
+ llvm::sys::path::append(InfoFile, "remap");
+ return InfoFile.str();
}
bool FileRemapper::initFromDisk(StringRef outputDir, DiagnosticsEngine &Diag,
@@ -127,7 +126,7 @@ bool FileRemapper::flushToFile(StringRef outputPath, DiagnosticsEngine &Diag) {
std::string errMsg;
std::string infoFile = outputPath;
llvm::raw_fd_ostream infoOut(infoFile.c_str(), errMsg,
- llvm::raw_fd_ostream::F_Binary);
+ llvm::sys::fs::F_Binary);
if (!errMsg.empty())
return report(errMsg, Diag);
@@ -147,11 +146,10 @@ bool FileRemapper::flushToFile(StringRef outputPath, DiagnosticsEngine &Diag) {
} else {
SmallString<64> tempPath;
- tempPath = path::filename(origFE->getName());
- tempPath += "-%%%%%%%%";
- tempPath += path::extension(origFE->getName());
int fd;
- if (fs::unique_file(tempPath.str(), fd, tempPath) != llvm::errc::success)
+ if (fs::createTemporaryFile(path::filename(origFE->getName()),
+ path::extension(origFE->getName()), fd,
+ tempPath))
return report("Could not create file: " + tempPath.str(), Diag);
llvm::raw_fd_ostream newOut(fd, /*shouldClose=*/true);
@@ -176,29 +174,22 @@ bool FileRemapper::overwriteOriginal(DiagnosticsEngine &Diag,
for (MappingsTy::iterator
I = FromToMappings.begin(), E = FromToMappings.end(); I != E; ++I) {
const FileEntry *origFE = I->first;
- if (const FileEntry *newFE = I->second.dyn_cast<const FileEntry *>()) {
- if (fs::copy_file(newFE->getName(), origFE->getName(),
- fs::copy_option::overwrite_if_exists) != llvm::errc::success)
- return report(StringRef("Could not copy file '") + newFE->getName() +
- "' to file '" + origFE->getName() + "'", Diag);
- } else {
-
- bool fileExists = false;
- fs::exists(origFE->getName(), fileExists);
- if (!fileExists)
- return report(StringRef("File does not exist: ") + origFE->getName(),
- Diag);
+ assert(I->second.is<llvm::MemoryBuffer *>());
+ bool fileExists = false;
+ fs::exists(origFE->getName(), fileExists);
+ if (!fileExists)
+ return report(StringRef("File does not exist: ") + origFE->getName(),
+ Diag);
- std::string errMsg;
- llvm::raw_fd_ostream Out(origFE->getName(), errMsg,
- llvm::raw_fd_ostream::F_Binary);
- if (!errMsg.empty())
- return report(errMsg, Diag);
+ std::string errMsg;
+ llvm::raw_fd_ostream Out(origFE->getName(), errMsg,
+ llvm::sys::fs::F_Binary);
+ if (!errMsg.empty())
+ return report(errMsg, Diag);
- llvm::MemoryBuffer *mem = I->second.get<llvm::MemoryBuffer *>();
- Out.write(mem->getBufferStart(), mem->getBufferSize());
- Out.close();
- }
+ llvm::MemoryBuffer *mem = I->second.get<llvm::MemoryBuffer *>();
+ Out.write(mem->getBufferStart(), mem->getBufferSize());
+ Out.close();
}
clear(outputDir);
@@ -239,12 +230,6 @@ void FileRemapper::remap(StringRef filePath, llvm::MemoryBuffer *memBuf) {
remap(getOriginalFile(filePath), memBuf);
}
-void FileRemapper::remap(StringRef filePath, StringRef newPath) {
- const FileEntry *file = getOriginalFile(filePath);
- const FileEntry *newfile = FileMgr->getFile(newPath);
- remap(file, newfile);
-}
-
void FileRemapper::remap(const FileEntry *file, llvm::MemoryBuffer *memBuf) {
assert(file);
Target &targ = FromToMappings[file];
diff --git a/lib/ARCMigrate/ObjCMT.cpp b/lib/ARCMigrate/ObjCMT.cpp
index 57fac0389fc3..cac0fb0aed1b 100644
--- a/lib/ARCMigrate/ObjCMT.cpp
+++ b/lib/ARCMigrate/ObjCMT.cpp
@@ -7,6 +7,7 @@
//
//===----------------------------------------------------------------------===//
+#include "Transforms.h"
#include "clang/ARCMigrate/ARCMTActions.h"
#include "clang/AST/ASTConsumer.h"
#include "clang/AST/ASTContext.h"
@@ -23,46 +24,101 @@
#include "clang/Lex/PPConditionalDirectiveRecord.h"
#include "clang/Lex/Preprocessor.h"
#include "clang/Rewrite/Core/Rewriter.h"
+#include "clang/Analysis/DomainSpecific/CocoaConventions.h"
+#include "clang/StaticAnalyzer/Checkers/ObjCRetainCount.h"
+#include "clang/AST/Attr.h"
#include "llvm/ADT/SmallString.h"
+#include "llvm/Support/Path.h"
using namespace clang;
using namespace arcmt;
+using namespace ento::objc_retain;
namespace {
class ObjCMigrateASTConsumer : public ASTConsumer {
+ enum CF_BRIDGING_KIND {
+ CF_BRIDGING_NONE,
+ CF_BRIDGING_ENABLE,
+ CF_BRIDGING_MAY_INCLUDE
+ };
+
void migrateDecl(Decl *D);
-
+ void migrateObjCInterfaceDecl(ASTContext &Ctx, ObjCContainerDecl *D);
+ void migrateDeprecatedAnnotation(ASTContext &Ctx, ObjCCategoryDecl *CatDecl);
+ void migrateProtocolConformance(ASTContext &Ctx,
+ const ObjCImplementationDecl *ImpDecl);
+ void CacheObjCNSIntegerTypedefed(const TypedefDecl *TypedefDcl);
+ bool migrateNSEnumDecl(ASTContext &Ctx, const EnumDecl *EnumDcl,
+ const TypedefDecl *TypedefDcl);
+ void migrateAllMethodInstaceType(ASTContext &Ctx, ObjCContainerDecl *CDecl);
+ void migrateMethodInstanceType(ASTContext &Ctx, ObjCContainerDecl *CDecl,
+ ObjCMethodDecl *OM);
+ bool migrateProperty(ASTContext &Ctx, ObjCContainerDecl *D, ObjCMethodDecl *OM);
+ void migrateNsReturnsInnerPointer(ASTContext &Ctx, ObjCMethodDecl *OM);
+ void migratePropertyNsReturnsInnerPointer(ASTContext &Ctx, ObjCPropertyDecl *P);
+ void migrateFactoryMethod(ASTContext &Ctx, ObjCContainerDecl *CDecl,
+ ObjCMethodDecl *OM,
+ ObjCInstanceTypeFamily OIT_Family = OIT_None);
+
+ void migrateCFAnnotation(ASTContext &Ctx, const Decl *Decl);
+ void AddCFAnnotations(ASTContext &Ctx, const CallEffects &CE,
+ const FunctionDecl *FuncDecl, bool ResultAnnotated);
+ void AddCFAnnotations(ASTContext &Ctx, const CallEffects &CE,
+ const ObjCMethodDecl *MethodDecl, bool ResultAnnotated);
+
+ void AnnotateImplicitBridging(ASTContext &Ctx);
+
+ CF_BRIDGING_KIND migrateAddFunctionAnnotation(ASTContext &Ctx,
+ const FunctionDecl *FuncDecl);
+
+ void migrateARCSafeAnnotation(ASTContext &Ctx, ObjCContainerDecl *CDecl);
+
+ void migrateAddMethodAnnotation(ASTContext &Ctx,
+ const ObjCMethodDecl *MethodDecl);
public:
std::string MigrateDir;
- bool MigrateLiterals;
- bool MigrateSubscripting;
+ unsigned ASTMigrateActions;
+ FileID FileId;
+ const TypedefDecl *NSIntegerTypedefed;
+ const TypedefDecl *NSUIntegerTypedefed;
OwningPtr<NSAPI> NSAPIObj;
OwningPtr<edit::EditedSource> Editor;
FileRemapper &Remapper;
FileManager &FileMgr;
const PPConditionalDirectiveRecord *PPRec;
+ Preprocessor &PP;
bool IsOutputFile;
-
+ llvm::SmallPtrSet<ObjCProtocolDecl *, 32> ObjCProtocolDecls;
+ llvm::SmallVector<const Decl *, 8> CFFunctionIBCandidates;
+ llvm::StringMap<char> WhiteListFilenames;
+
ObjCMigrateASTConsumer(StringRef migrateDir,
- bool migrateLiterals,
- bool migrateSubscripting,
+ unsigned astMigrateActions,
FileRemapper &remapper,
FileManager &fileMgr,
const PPConditionalDirectiveRecord *PPRec,
- bool isOutputFile = false)
+ Preprocessor &PP,
+ bool isOutputFile,
+ ArrayRef<std::string> WhiteList)
: MigrateDir(migrateDir),
- MigrateLiterals(migrateLiterals),
- MigrateSubscripting(migrateSubscripting),
- Remapper(remapper), FileMgr(fileMgr), PPRec(PPRec),
- IsOutputFile(isOutputFile) { }
+ ASTMigrateActions(astMigrateActions),
+ NSIntegerTypedefed(0), NSUIntegerTypedefed(0),
+ Remapper(remapper), FileMgr(fileMgr), PPRec(PPRec), PP(PP),
+ IsOutputFile(isOutputFile) {
+
+ for (ArrayRef<std::string>::iterator
+ I = WhiteList.begin(), E = WhiteList.end(); I != E; ++I) {
+ WhiteListFilenames.GetOrCreateValue(*I);
+ }
+ }
protected:
virtual void Initialize(ASTContext &Context) {
NSAPIObj.reset(new NSAPI(Context));
Editor.reset(new edit::EditedSource(Context.getSourceManager(),
Context.getLangOpts(),
- PPRec));
+ PPRec, false));
}
virtual bool HandleTopLevelDecl(DeclGroupRef DG) {
@@ -78,16 +134,22 @@ protected:
}
virtual void HandleTranslationUnit(ASTContext &Ctx);
+
+ bool canModifyFile(StringRef Path) {
+ if (WhiteListFilenames.empty())
+ return true;
+ return WhiteListFilenames.find(llvm::sys::path::filename(Path))
+ != WhiteListFilenames.end();
+ }
};
}
ObjCMigrateAction::ObjCMigrateAction(FrontendAction *WrappedAction,
- StringRef migrateDir,
- bool migrateLiterals,
- bool migrateSubscripting)
+ StringRef migrateDir,
+ unsigned migrateAction)
: WrapperFrontendAction(WrappedAction), MigrateDir(migrateDir),
- MigrateLiterals(migrateLiterals), MigrateSubscripting(migrateSubscripting),
+ ObjCMigAction(migrateAction),
CompInst(0) {
if (MigrateDir.empty())
MigrateDir = "."; // user current directory if none is given.
@@ -101,11 +163,13 @@ ASTConsumer *ObjCMigrateAction::CreateASTConsumer(CompilerInstance &CI,
ASTConsumer *
WrappedConsumer = WrapperFrontendAction::CreateASTConsumer(CI, InFile);
ASTConsumer *MTConsumer = new ObjCMigrateASTConsumer(MigrateDir,
- MigrateLiterals,
- MigrateSubscripting,
+ ObjCMigAction,
Remapper,
CompInst->getFileManager(),
- PPRec);
+ PPRec,
+ CompInst->getPreprocessor(),
+ false,
+ ArrayRef<std::string>());
ASTConsumer *Consumers[] = { MTConsumer, WrappedConsumer };
return new MultiplexConsumer(Consumers);
}
@@ -131,13 +195,13 @@ public:
bool shouldWalkTypesOfTypeLocs() const { return false; }
bool VisitObjCMessageExpr(ObjCMessageExpr *E) {
- if (Consumer.MigrateLiterals) {
+ if (Consumer.ASTMigrateActions & FrontendOptions::ObjCMT_Literals) {
edit::Commit commit(*Consumer.Editor);
edit::rewriteToObjCLiteralSyntax(E, *Consumer.NSAPIObj, commit, &PMap);
Consumer.Editor->commit(commit);
}
- if (Consumer.MigrateSubscripting) {
+ if (Consumer.ASTMigrateActions & FrontendOptions::ObjCMT_Subscripting) {
edit::Commit commit(*Consumer.Editor);
edit::rewriteToObjCSubscriptSyntax(E, *Consumer.NSAPIObj, commit);
Consumer.Editor->commit(commit);
@@ -184,6 +248,1322 @@ void ObjCMigrateASTConsumer::migrateDecl(Decl *D) {
BodyMigrator(*this).TraverseDecl(D);
}
+static void append_attr(std::string &PropertyString, const char *attr,
+ bool &LParenAdded) {
+ if (!LParenAdded) {
+ PropertyString += "(";
+ LParenAdded = true;
+ }
+ else
+ PropertyString += ", ";
+ PropertyString += attr;
+}
+
+static
+void MigrateBlockOrFunctionPointerTypeVariable(std::string & PropertyString,
+ const std::string& TypeString,
+ const char *name) {
+ const char *argPtr = TypeString.c_str();
+ int paren = 0;
+ while (*argPtr) {
+ switch (*argPtr) {
+ case '(':
+ PropertyString += *argPtr;
+ paren++;
+ break;
+ case ')':
+ PropertyString += *argPtr;
+ paren--;
+ break;
+ case '^':
+ case '*':
+ PropertyString += (*argPtr);
+ if (paren == 1) {
+ PropertyString += name;
+ name = "";
+ }
+ break;
+ default:
+ PropertyString += *argPtr;
+ break;
+ }
+ argPtr++;
+ }
+}
+
+static const char *PropertyMemoryAttribute(ASTContext &Context, QualType ArgType) {
+ Qualifiers::ObjCLifetime propertyLifetime = ArgType.getObjCLifetime();
+ bool RetainableObject = ArgType->isObjCRetainableType();
+ if (RetainableObject && propertyLifetime == Qualifiers::OCL_Strong) {
+ if (const ObjCObjectPointerType *ObjPtrTy =
+ ArgType->getAs<ObjCObjectPointerType>()) {
+ ObjCInterfaceDecl *IDecl = ObjPtrTy->getObjectType()->getInterface();
+ if (IDecl &&
+ IDecl->lookupNestedProtocol(&Context.Idents.get("NSCopying")))
+ return "copy";
+ else
+ return "retain";
+ }
+ else if (ArgType->isBlockPointerType())
+ return "copy";
+ } else if (propertyLifetime == Qualifiers::OCL_Weak)
+ // TODO. More precise determination of 'weak' attribute requires
+ // looking into setter's implementation for backing weak ivar.
+ return "weak";
+ else if (RetainableObject)
+ return ArgType->isBlockPointerType() ? "copy" : "retain";
+ return 0;
+}
+
+static void rewriteToObjCProperty(const ObjCMethodDecl *Getter,
+ const ObjCMethodDecl *Setter,
+ const NSAPI &NS, edit::Commit &commit,
+ unsigned LengthOfPrefix,
+ bool Atomic, bool UseNsIosOnlyMacro,
+ bool AvailabilityArgsMatch) {
+ ASTContext &Context = NS.getASTContext();
+ bool LParenAdded = false;
+ std::string PropertyString = "@property ";
+ if (UseNsIosOnlyMacro && Context.Idents.get("NS_NONATOMIC_IOSONLY").hasMacroDefinition()) {
+ PropertyString += "(NS_NONATOMIC_IOSONLY";
+ LParenAdded = true;
+ } else if (!Atomic) {
+ PropertyString += "(nonatomic";
+ LParenAdded = true;
+ }
+
+ std::string PropertyNameString = Getter->getNameAsString();
+ StringRef PropertyName(PropertyNameString);
+ if (LengthOfPrefix > 0) {
+ if (!LParenAdded) {
+ PropertyString += "(getter=";
+ LParenAdded = true;
+ }
+ else
+ PropertyString += ", getter=";
+ PropertyString += PropertyNameString;
+ }
+ // Property with no setter may be suggested as a 'readonly' property.
+ if (!Setter) {
+ append_attr(PropertyString, "readonly", LParenAdded);
+ QualType ResType = Context.getCanonicalType(Getter->getResultType());
+ if (const char *MemoryManagementAttr = PropertyMemoryAttribute(Context, ResType))
+ append_attr(PropertyString, MemoryManagementAttr, LParenAdded);
+ }
+
+ // Short circuit 'delegate' properties that contain the name "delegate" or
+ // "dataSource", or have exact name "target" to have 'assign' attribute.
+ if (PropertyName.equals("target") ||
+ (PropertyName.find("delegate") != StringRef::npos) ||
+ (PropertyName.find("dataSource") != StringRef::npos)) {
+ QualType QT = Getter->getResultType();
+ if (!QT->isRealType())
+ append_attr(PropertyString, "assign", LParenAdded);
+ }
+ else if (Setter) {
+ const ParmVarDecl *argDecl = *Setter->param_begin();
+ QualType ArgType = Context.getCanonicalType(argDecl->getType());
+ if (const char *MemoryManagementAttr = PropertyMemoryAttribute(Context, ArgType))
+ append_attr(PropertyString, MemoryManagementAttr, LParenAdded);
+ }
+ if (LParenAdded)
+ PropertyString += ')';
+ QualType RT = Getter->getResultType();
+ if (!isa<TypedefType>(RT)) {
+ // strip off any ARC lifetime qualifier.
+ QualType CanResultTy = Context.getCanonicalType(RT);
+ if (CanResultTy.getQualifiers().hasObjCLifetime()) {
+ Qualifiers Qs = CanResultTy.getQualifiers();
+ Qs.removeObjCLifetime();
+ RT = Context.getQualifiedType(CanResultTy.getUnqualifiedType(), Qs);
+ }
+ }
+ PropertyString += " ";
+ PrintingPolicy SubPolicy(Context.getPrintingPolicy());
+ SubPolicy.SuppressStrongLifetime = true;
+ SubPolicy.SuppressLifetimeQualifiers = true;
+ std::string TypeString = RT.getAsString(SubPolicy);
+ if (LengthOfPrefix > 0) {
+ // property name must strip off "is" and lower case the first character
+ // after that; e.g. isContinuous will become continuous.
+ StringRef PropertyNameStringRef(PropertyNameString);
+ PropertyNameStringRef = PropertyNameStringRef.drop_front(LengthOfPrefix);
+ PropertyNameString = PropertyNameStringRef;
+ bool NoLowering = (isUppercase(PropertyNameString[0]) &&
+ PropertyNameString.size() > 1 &&
+ isUppercase(PropertyNameString[1]));
+ if (!NoLowering)
+ PropertyNameString[0] = toLowercase(PropertyNameString[0]);
+ }
+ if (RT->isBlockPointerType() || RT->isFunctionPointerType())
+ MigrateBlockOrFunctionPointerTypeVariable(PropertyString,
+ TypeString,
+ PropertyNameString.c_str());
+ else {
+ char LastChar = TypeString[TypeString.size()-1];
+ PropertyString += TypeString;
+ if (LastChar != '*')
+ PropertyString += ' ';
+ PropertyString += PropertyNameString;
+ }
+ SourceLocation StartGetterSelectorLoc = Getter->getSelectorStartLoc();
+ Selector GetterSelector = Getter->getSelector();
+
+ SourceLocation EndGetterSelectorLoc =
+ StartGetterSelectorLoc.getLocWithOffset(GetterSelector.getNameForSlot(0).size());
+ commit.replace(CharSourceRange::getCharRange(Getter->getLocStart(),
+ EndGetterSelectorLoc),
+ PropertyString);
+ if (Setter && AvailabilityArgsMatch) {
+ SourceLocation EndLoc = Setter->getDeclaratorEndLoc();
+ // Get location past ';'
+ EndLoc = EndLoc.getLocWithOffset(1);
+ SourceLocation BeginOfSetterDclLoc = Setter->getLocStart();
+ // FIXME. This assumes that setter decl; is immediately preceeded by eoln.
+ // It is trying to remove the setter method decl. line entirely.
+ BeginOfSetterDclLoc = BeginOfSetterDclLoc.getLocWithOffset(-1);
+ commit.remove(SourceRange(BeginOfSetterDclLoc, EndLoc));
+ }
+}
+
+void ObjCMigrateASTConsumer::migrateObjCInterfaceDecl(ASTContext &Ctx,
+ ObjCContainerDecl *D) {
+ if (D->isDeprecated())
+ return;
+
+ for (ObjCContainerDecl::method_iterator M = D->meth_begin(), MEnd = D->meth_end();
+ M != MEnd; ++M) {
+ ObjCMethodDecl *Method = (*M);
+ if (Method->isDeprecated())
+ continue;
+ bool PropertyInferred = migrateProperty(Ctx, D, Method);
+ // If a property is inferred, do not attempt to attach NS_RETURNS_INNER_POINTER to
+ // the getter method as it ends up on the property itself which we don't want
+ // to do unless -objcmt-returns-innerpointer-property option is on.
+ if (!PropertyInferred ||
+ (ASTMigrateActions & FrontendOptions::ObjCMT_ReturnsInnerPointerProperty))
+ if (ASTMigrateActions & FrontendOptions::ObjCMT_Annotation)
+ migrateNsReturnsInnerPointer(Ctx, Method);
+ }
+ if (!(ASTMigrateActions & FrontendOptions::ObjCMT_ReturnsInnerPointerProperty))
+ return;
+
+ for (ObjCContainerDecl::prop_iterator P = D->prop_begin(),
+ E = D->prop_end(); P != E; ++P) {
+ ObjCPropertyDecl *Prop = *P;
+ if ((ASTMigrateActions & FrontendOptions::ObjCMT_Annotation) &&
+ !Prop->isDeprecated())
+ migratePropertyNsReturnsInnerPointer(Ctx, Prop);
+ }
+}
+
+void ObjCMigrateASTConsumer::migrateDeprecatedAnnotation(ASTContext &Ctx,
+ ObjCCategoryDecl *CatDecl) {
+ StringRef Name = CatDecl->getName();
+ if (!Name.endswith("Deprecated"))
+ return;
+
+ if (!Ctx.Idents.get("DEPRECATED").hasMacroDefinition())
+ return;
+
+ ObjCContainerDecl *D = cast<ObjCContainerDecl>(CatDecl);
+
+ for (ObjCContainerDecl::method_iterator M = D->meth_begin(), MEnd = D->meth_end();
+ M != MEnd; ++M) {
+ ObjCMethodDecl *Method = (*M);
+ if (Method->isDeprecated() || Method->isImplicit())
+ continue;
+ // Annotate with DEPRECATED
+ edit::Commit commit(*Editor);
+ commit.insertBefore(Method->getLocEnd(), " DEPRECATED");
+ Editor->commit(commit);
+ }
+ for (ObjCContainerDecl::prop_iterator P = D->prop_begin(),
+ E = D->prop_end(); P != E; ++P) {
+ ObjCPropertyDecl *Prop = *P;
+ if (Prop->isDeprecated())
+ continue;
+ // Annotate with DEPRECATED
+ edit::Commit commit(*Editor);
+ commit.insertAfterToken(Prop->getLocEnd(), " DEPRECATED");
+ Editor->commit(commit);
+ }
+}
+
+static bool
+ClassImplementsAllMethodsAndProperties(ASTContext &Ctx,
+ const ObjCImplementationDecl *ImpDecl,
+ const ObjCInterfaceDecl *IDecl,
+ ObjCProtocolDecl *Protocol) {
+ // In auto-synthesis, protocol properties are not synthesized. So,
+ // a conforming protocol must have its required properties declared
+ // in class interface.
+ bool HasAtleastOneRequiredProperty = false;
+ if (const ObjCProtocolDecl *PDecl = Protocol->getDefinition())
+ for (ObjCProtocolDecl::prop_iterator P = PDecl->prop_begin(),
+ E = PDecl->prop_end(); P != E; ++P) {
+ ObjCPropertyDecl *Property = *P;
+ if (Property->getPropertyImplementation() == ObjCPropertyDecl::Optional)
+ continue;
+ HasAtleastOneRequiredProperty = true;
+ DeclContext::lookup_const_result R = IDecl->lookup(Property->getDeclName());
+ if (R.size() == 0) {
+ // Relax the rule and look into class's implementation for a synthesize
+ // or dynamic declaration. Class is implementing a property coming from
+ // another protocol. This still makes the target protocol as conforming.
+ if (!ImpDecl->FindPropertyImplDecl(
+ Property->getDeclName().getAsIdentifierInfo()))
+ return false;
+ }
+ else if (ObjCPropertyDecl *ClassProperty = dyn_cast<ObjCPropertyDecl>(R[0])) {
+ if ((ClassProperty->getPropertyAttributes()
+ != Property->getPropertyAttributes()) ||
+ !Ctx.hasSameType(ClassProperty->getType(), Property->getType()))
+ return false;
+ }
+ else
+ return false;
+ }
+
+ // At this point, all required properties in this protocol conform to those
+ // declared in the class.
+ // Check that class implements the required methods of the protocol too.
+ bool HasAtleastOneRequiredMethod = false;
+ if (const ObjCProtocolDecl *PDecl = Protocol->getDefinition()) {
+ if (PDecl->meth_begin() == PDecl->meth_end())
+ return HasAtleastOneRequiredProperty;
+ for (ObjCContainerDecl::method_iterator M = PDecl->meth_begin(),
+ MEnd = PDecl->meth_end(); M != MEnd; ++M) {
+ ObjCMethodDecl *MD = (*M);
+ if (MD->isImplicit())
+ continue;
+ if (MD->getImplementationControl() == ObjCMethodDecl::Optional)
+ continue;
+ DeclContext::lookup_const_result R = ImpDecl->lookup(MD->getDeclName());
+ if (R.size() == 0)
+ return false;
+ bool match = false;
+ HasAtleastOneRequiredMethod = true;
+ for (unsigned I = 0, N = R.size(); I != N; ++I)
+ if (ObjCMethodDecl *ImpMD = dyn_cast<ObjCMethodDecl>(R[0]))
+ if (Ctx.ObjCMethodsAreEqual(MD, ImpMD)) {
+ match = true;
+ break;
+ }
+ if (!match)
+ return false;
+ }
+ }
+ if (HasAtleastOneRequiredProperty || HasAtleastOneRequiredMethod)
+ return true;
+ return false;
+}
+
+static bool rewriteToObjCInterfaceDecl(const ObjCInterfaceDecl *IDecl,
+ llvm::SmallVectorImpl<ObjCProtocolDecl*> &ConformingProtocols,
+ const NSAPI &NS, edit::Commit &commit) {
+ const ObjCList<ObjCProtocolDecl> &Protocols = IDecl->getReferencedProtocols();
+ std::string ClassString;
+ SourceLocation EndLoc =
+ IDecl->getSuperClass() ? IDecl->getSuperClassLoc() : IDecl->getLocation();
+
+ if (Protocols.empty()) {
+ ClassString = '<';
+ for (unsigned i = 0, e = ConformingProtocols.size(); i != e; i++) {
+ ClassString += ConformingProtocols[i]->getNameAsString();
+ if (i != (e-1))
+ ClassString += ", ";
+ }
+ ClassString += "> ";
+ }
+ else {
+ ClassString = ", ";
+ for (unsigned i = 0, e = ConformingProtocols.size(); i != e; i++) {
+ ClassString += ConformingProtocols[i]->getNameAsString();
+ if (i != (e-1))
+ ClassString += ", ";
+ }
+ ObjCInterfaceDecl::protocol_loc_iterator PL = IDecl->protocol_loc_end() - 1;
+ EndLoc = *PL;
+ }
+
+ commit.insertAfterToken(EndLoc, ClassString);
+ return true;
+}
+
+static bool rewriteToNSEnumDecl(const EnumDecl *EnumDcl,
+ const TypedefDecl *TypedefDcl,
+ const NSAPI &NS, edit::Commit &commit,
+ bool IsNSIntegerType,
+ bool NSOptions) {
+ std::string ClassString;
+ if (NSOptions)
+ ClassString = "typedef NS_OPTIONS(NSUInteger, ";
+ else
+ ClassString =
+ IsNSIntegerType ? "typedef NS_ENUM(NSInteger, "
+ : "typedef NS_ENUM(NSUInteger, ";
+
+ ClassString += TypedefDcl->getIdentifier()->getName();
+ ClassString += ')';
+ SourceRange R(EnumDcl->getLocStart(), EnumDcl->getLocStart());
+ commit.replace(R, ClassString);
+ SourceLocation EndOfEnumDclLoc = EnumDcl->getLocEnd();
+ EndOfEnumDclLoc = trans::findSemiAfterLocation(EndOfEnumDclLoc,
+ NS.getASTContext(), /*IsDecl*/true);
+ if (!EndOfEnumDclLoc.isInvalid()) {
+ SourceRange EnumDclRange(EnumDcl->getLocStart(), EndOfEnumDclLoc);
+ commit.insertFromRange(TypedefDcl->getLocStart(), EnumDclRange);
+ }
+ else
+ return false;
+
+ SourceLocation EndTypedefDclLoc = TypedefDcl->getLocEnd();
+ EndTypedefDclLoc = trans::findSemiAfterLocation(EndTypedefDclLoc,
+ NS.getASTContext(), /*IsDecl*/true);
+ if (!EndTypedefDclLoc.isInvalid()) {
+ SourceRange TDRange(TypedefDcl->getLocStart(), EndTypedefDclLoc);
+ commit.remove(TDRange);
+ }
+ else
+ return false;
+
+ EndOfEnumDclLoc = trans::findLocationAfterSemi(EnumDcl->getLocEnd(), NS.getASTContext(),
+ /*IsDecl*/true);
+ if (!EndOfEnumDclLoc.isInvalid()) {
+ SourceLocation BeginOfEnumDclLoc = EnumDcl->getLocStart();
+ // FIXME. This assumes that enum decl; is immediately preceeded by eoln.
+ // It is trying to remove the enum decl. lines entirely.
+ BeginOfEnumDclLoc = BeginOfEnumDclLoc.getLocWithOffset(-1);
+ commit.remove(SourceRange(BeginOfEnumDclLoc, EndOfEnumDclLoc));
+ return true;
+ }
+ return false;
+}
+
+static void rewriteToNSMacroDecl(const EnumDecl *EnumDcl,
+ const TypedefDecl *TypedefDcl,
+ const NSAPI &NS, edit::Commit &commit,
+ bool IsNSIntegerType) {
+ std::string ClassString =
+ IsNSIntegerType ? "NS_ENUM(NSInteger, " : "NS_OPTIONS(NSUInteger, ";
+ ClassString += TypedefDcl->getIdentifier()->getName();
+ ClassString += ')';
+ SourceRange R(EnumDcl->getLocStart(), EnumDcl->getLocStart());
+ commit.replace(R, ClassString);
+ SourceLocation TypedefLoc = TypedefDcl->getLocEnd();
+ commit.remove(SourceRange(TypedefLoc, TypedefLoc));
+}
+
+static bool UseNSOptionsMacro(Preprocessor &PP, ASTContext &Ctx,
+ const EnumDecl *EnumDcl) {
+ bool PowerOfTwo = true;
+ bool AllHexdecimalEnumerator = true;
+ uint64_t MaxPowerOfTwoVal = 0;
+ for (EnumDecl::enumerator_iterator EI = EnumDcl->enumerator_begin(),
+ EE = EnumDcl->enumerator_end(); EI != EE; ++EI) {
+ EnumConstantDecl *Enumerator = (*EI);
+ const Expr *InitExpr = Enumerator->getInitExpr();
+ if (!InitExpr) {
+ PowerOfTwo = false;
+ AllHexdecimalEnumerator = false;
+ continue;
+ }
+ InitExpr = InitExpr->IgnoreParenCasts();
+ if (const BinaryOperator *BO = dyn_cast<BinaryOperator>(InitExpr))
+ if (BO->isShiftOp() || BO->isBitwiseOp())
+ return true;
+
+ uint64_t EnumVal = Enumerator->getInitVal().getZExtValue();
+ if (PowerOfTwo && EnumVal) {
+ if (!llvm::isPowerOf2_64(EnumVal))
+ PowerOfTwo = false;
+ else if (EnumVal > MaxPowerOfTwoVal)
+ MaxPowerOfTwoVal = EnumVal;
+ }
+ if (AllHexdecimalEnumerator && EnumVal) {
+ bool FoundHexdecimalEnumerator = false;
+ SourceLocation EndLoc = Enumerator->getLocEnd();
+ Token Tok;
+ if (!PP.getRawToken(EndLoc, Tok, /*IgnoreWhiteSpace=*/true))
+ if (Tok.isLiteral() && Tok.getLength() > 2) {
+ if (const char *StringLit = Tok.getLiteralData())
+ FoundHexdecimalEnumerator =
+ (StringLit[0] == '0' && (toLowercase(StringLit[1]) == 'x'));
+ }
+ if (!FoundHexdecimalEnumerator)
+ AllHexdecimalEnumerator = false;
+ }
+ }
+ return AllHexdecimalEnumerator || (PowerOfTwo && (MaxPowerOfTwoVal > 2));
+}
+
+void ObjCMigrateASTConsumer::migrateProtocolConformance(ASTContext &Ctx,
+ const ObjCImplementationDecl *ImpDecl) {
+ const ObjCInterfaceDecl *IDecl = ImpDecl->getClassInterface();
+ if (!IDecl || ObjCProtocolDecls.empty() || IDecl->isDeprecated())
+ return;
+ // Find all implicit conforming protocols for this class
+ // and make them explicit.
+ llvm::SmallPtrSet<ObjCProtocolDecl *, 8> ExplicitProtocols;
+ Ctx.CollectInheritedProtocols(IDecl, ExplicitProtocols);
+ llvm::SmallVector<ObjCProtocolDecl *, 8> PotentialImplicitProtocols;
+
+ for (llvm::SmallPtrSet<ObjCProtocolDecl*, 32>::iterator I =
+ ObjCProtocolDecls.begin(),
+ E = ObjCProtocolDecls.end(); I != E; ++I)
+ if (!ExplicitProtocols.count(*I))
+ PotentialImplicitProtocols.push_back(*I);
+
+ if (PotentialImplicitProtocols.empty())
+ return;
+
+ // go through list of non-optional methods and properties in each protocol
+ // in the PotentialImplicitProtocols list. If class implements every one of the
+ // methods and properties, then this class conforms to this protocol.
+ llvm::SmallVector<ObjCProtocolDecl*, 8> ConformingProtocols;
+ for (unsigned i = 0, e = PotentialImplicitProtocols.size(); i != e; i++)
+ if (ClassImplementsAllMethodsAndProperties(Ctx, ImpDecl, IDecl,
+ PotentialImplicitProtocols[i]))
+ ConformingProtocols.push_back(PotentialImplicitProtocols[i]);
+
+ if (ConformingProtocols.empty())
+ return;
+
+ // Further reduce number of conforming protocols. If protocol P1 is in the list
+ // protocol P2 (P2<P1>), No need to include P1.
+ llvm::SmallVector<ObjCProtocolDecl*, 8> MinimalConformingProtocols;
+ for (unsigned i = 0, e = ConformingProtocols.size(); i != e; i++) {
+ bool DropIt = false;
+ ObjCProtocolDecl *TargetPDecl = ConformingProtocols[i];
+ for (unsigned i1 = 0, e1 = ConformingProtocols.size(); i1 != e1; i1++) {
+ ObjCProtocolDecl *PDecl = ConformingProtocols[i1];
+ if (PDecl == TargetPDecl)
+ continue;
+ if (PDecl->lookupProtocolNamed(
+ TargetPDecl->getDeclName().getAsIdentifierInfo())) {
+ DropIt = true;
+ break;
+ }
+ }
+ if (!DropIt)
+ MinimalConformingProtocols.push_back(TargetPDecl);
+ }
+ edit::Commit commit(*Editor);
+ rewriteToObjCInterfaceDecl(IDecl, MinimalConformingProtocols,
+ *NSAPIObj, commit);
+ Editor->commit(commit);
+}
+
+void ObjCMigrateASTConsumer::CacheObjCNSIntegerTypedefed(
+ const TypedefDecl *TypedefDcl) {
+
+ QualType qt = TypedefDcl->getTypeSourceInfo()->getType();
+ if (NSAPIObj->isObjCNSIntegerType(qt))
+ NSIntegerTypedefed = TypedefDcl;
+ else if (NSAPIObj->isObjCNSUIntegerType(qt))
+ NSUIntegerTypedefed = TypedefDcl;
+}
+
+bool ObjCMigrateASTConsumer::migrateNSEnumDecl(ASTContext &Ctx,
+ const EnumDecl *EnumDcl,
+ const TypedefDecl *TypedefDcl) {
+ if (!EnumDcl->isCompleteDefinition() || EnumDcl->getIdentifier() ||
+ EnumDcl->isDeprecated())
+ return false;
+ if (!TypedefDcl) {
+ if (NSIntegerTypedefed) {
+ TypedefDcl = NSIntegerTypedefed;
+ NSIntegerTypedefed = 0;
+ }
+ else if (NSUIntegerTypedefed) {
+ TypedefDcl = NSUIntegerTypedefed;
+ NSUIntegerTypedefed = 0;
+ }
+ else
+ return false;
+ FileID FileIdOfTypedefDcl =
+ PP.getSourceManager().getFileID(TypedefDcl->getLocation());
+ FileID FileIdOfEnumDcl =
+ PP.getSourceManager().getFileID(EnumDcl->getLocation());
+ if (FileIdOfTypedefDcl != FileIdOfEnumDcl)
+ return false;
+ }
+ if (TypedefDcl->isDeprecated())
+ return false;
+
+ QualType qt = TypedefDcl->getTypeSourceInfo()->getType();
+ bool IsNSIntegerType = NSAPIObj->isObjCNSIntegerType(qt);
+ bool IsNSUIntegerType = !IsNSIntegerType && NSAPIObj->isObjCNSUIntegerType(qt);
+
+ if (!IsNSIntegerType && !IsNSUIntegerType) {
+ // Also check for typedef enum {...} TD;
+ if (const EnumType *EnumTy = qt->getAs<EnumType>()) {
+ if (EnumTy->getDecl() == EnumDcl) {
+ bool NSOptions = UseNSOptionsMacro(PP, Ctx, EnumDcl);
+ if (NSOptions) {
+ if (!Ctx.Idents.get("NS_OPTIONS").hasMacroDefinition())
+ return false;
+ }
+ else if (!Ctx.Idents.get("NS_ENUM").hasMacroDefinition())
+ return false;
+ edit::Commit commit(*Editor);
+ rewriteToNSMacroDecl(EnumDcl, TypedefDcl, *NSAPIObj, commit, !NSOptions);
+ Editor->commit(commit);
+ return true;
+ }
+ }
+ return false;
+ }
+
+ // We may still use NS_OPTIONS based on what we find in the enumertor list.
+ bool NSOptions = UseNSOptionsMacro(PP, Ctx, EnumDcl);
+ // NS_ENUM must be available.
+ if (IsNSIntegerType && !Ctx.Idents.get("NS_ENUM").hasMacroDefinition())
+ return false;
+ // NS_OPTIONS must be available.
+ if (IsNSUIntegerType && !Ctx.Idents.get("NS_OPTIONS").hasMacroDefinition())
+ return false;
+ edit::Commit commit(*Editor);
+ bool Res = rewriteToNSEnumDecl(EnumDcl, TypedefDcl, *NSAPIObj,
+ commit, IsNSIntegerType, NSOptions);
+ Editor->commit(commit);
+ return Res;
+}
+
+static void ReplaceWithInstancetype(const ObjCMigrateASTConsumer &ASTC,
+ ObjCMethodDecl *OM) {
+ SourceRange R;
+ std::string ClassString;
+ if (TypeSourceInfo *TSInfo = OM->getResultTypeSourceInfo()) {
+ TypeLoc TL = TSInfo->getTypeLoc();
+ R = SourceRange(TL.getBeginLoc(), TL.getEndLoc());
+ ClassString = "instancetype";
+ }
+ else {
+ R = SourceRange(OM->getLocStart(), OM->getLocStart());
+ ClassString = OM->isInstanceMethod() ? '-' : '+';
+ ClassString += " (instancetype)";
+ }
+ edit::Commit commit(*ASTC.Editor);
+ commit.replace(R, ClassString);
+ ASTC.Editor->commit(commit);
+}
+
+static void ReplaceWithClasstype(const ObjCMigrateASTConsumer &ASTC,
+ ObjCMethodDecl *OM) {
+ ObjCInterfaceDecl *IDecl = OM->getClassInterface();
+ SourceRange R;
+ std::string ClassString;
+ if (TypeSourceInfo *TSInfo = OM->getResultTypeSourceInfo()) {
+ TypeLoc TL = TSInfo->getTypeLoc();
+ R = SourceRange(TL.getBeginLoc(), TL.getEndLoc()); {
+ ClassString = IDecl->getName();
+ ClassString += "*";
+ }
+ }
+ else {
+ R = SourceRange(OM->getLocStart(), OM->getLocStart());
+ ClassString = "+ (";
+ ClassString += IDecl->getName(); ClassString += "*)";
+ }
+ edit::Commit commit(*ASTC.Editor);
+ commit.replace(R, ClassString);
+ ASTC.Editor->commit(commit);
+}
+
+void ObjCMigrateASTConsumer::migrateMethodInstanceType(ASTContext &Ctx,
+ ObjCContainerDecl *CDecl,
+ ObjCMethodDecl *OM) {
+ ObjCInstanceTypeFamily OIT_Family =
+ Selector::getInstTypeMethodFamily(OM->getSelector());
+
+ std::string ClassName;
+ switch (OIT_Family) {
+ case OIT_None:
+ migrateFactoryMethod(Ctx, CDecl, OM);
+ return;
+ case OIT_Array:
+ ClassName = "NSArray";
+ break;
+ case OIT_Dictionary:
+ ClassName = "NSDictionary";
+ break;
+ case OIT_Singleton:
+ migrateFactoryMethod(Ctx, CDecl, OM, OIT_Singleton);
+ return;
+ case OIT_Init:
+ if (OM->getResultType()->isObjCIdType())
+ ReplaceWithInstancetype(*this, OM);
+ return;
+ case OIT_ReturnsSelf:
+ migrateFactoryMethod(Ctx, CDecl, OM, OIT_ReturnsSelf);
+ return;
+ }
+ if (!OM->getResultType()->isObjCIdType())
+ return;
+
+ ObjCInterfaceDecl *IDecl = dyn_cast<ObjCInterfaceDecl>(CDecl);
+ if (!IDecl) {
+ if (ObjCCategoryDecl *CatDecl = dyn_cast<ObjCCategoryDecl>(CDecl))
+ IDecl = CatDecl->getClassInterface();
+ else if (ObjCImplDecl *ImpDecl = dyn_cast<ObjCImplDecl>(CDecl))
+ IDecl = ImpDecl->getClassInterface();
+ }
+ if (!IDecl ||
+ !IDecl->lookupInheritedClass(&Ctx.Idents.get(ClassName))) {
+ migrateFactoryMethod(Ctx, CDecl, OM);
+ return;
+ }
+ ReplaceWithInstancetype(*this, OM);
+}
+
+static bool TypeIsInnerPointer(QualType T) {
+ if (!T->isAnyPointerType())
+ return false;
+ if (T->isObjCObjectPointerType() || T->isObjCBuiltinType() ||
+ T->isBlockPointerType() || T->isFunctionPointerType() ||
+ ento::coreFoundation::isCFObjectRef(T))
+ return false;
+ // Also, typedef-of-pointer-to-incomplete-struct is something that we assume
+ // is not an innter pointer type.
+ QualType OrigT = T;
+ while (const TypedefType *TD = dyn_cast<TypedefType>(T.getTypePtr()))
+ T = TD->getDecl()->getUnderlyingType();
+ if (OrigT == T || !T->isPointerType())
+ return true;
+ const PointerType* PT = T->getAs<PointerType>();
+ QualType UPointeeT = PT->getPointeeType().getUnqualifiedType();
+ if (UPointeeT->isRecordType()) {
+ const RecordType *RecordTy = UPointeeT->getAs<RecordType>();
+ if (!RecordTy->getDecl()->isCompleteDefinition())
+ return false;
+ }
+ return true;
+}
+
+/// \brief Check whether the two versions match.
+static bool versionsMatch(const VersionTuple &X, const VersionTuple &Y) {
+ return (X == Y);
+}
+
+/// AvailabilityAttrsMatch - This routine checks that if comparing two
+/// availability attributes, all their components match. It returns
+/// true, if not dealing with availability or when all components of
+/// availability attributes match. This routine is only called when
+/// the attributes are of the same kind.
+static bool AvailabilityAttrsMatch(Attr *At1, Attr *At2) {
+ const AvailabilityAttr *AA1 = dyn_cast<AvailabilityAttr>(At1);
+ if (!AA1)
+ return true;
+ const AvailabilityAttr *AA2 = dyn_cast<AvailabilityAttr>(At2);
+
+ VersionTuple Introduced1 = AA1->getIntroduced();
+ VersionTuple Deprecated1 = AA1->getDeprecated();
+ VersionTuple Obsoleted1 = AA1->getObsoleted();
+ bool IsUnavailable1 = AA1->getUnavailable();
+ VersionTuple Introduced2 = AA2->getIntroduced();
+ VersionTuple Deprecated2 = AA2->getDeprecated();
+ VersionTuple Obsoleted2 = AA2->getObsoleted();
+ bool IsUnavailable2 = AA2->getUnavailable();
+ return (versionsMatch(Introduced1, Introduced2) &&
+ versionsMatch(Deprecated1, Deprecated2) &&
+ versionsMatch(Obsoleted1, Obsoleted2) &&
+ IsUnavailable1 == IsUnavailable2);
+
+}
+
+static bool MatchTwoAttributeLists(const AttrVec &Attrs1, const AttrVec &Attrs2,
+ bool &AvailabilityArgsMatch) {
+ // This list is very small, so this need not be optimized.
+ for (unsigned i = 0, e = Attrs1.size(); i != e; i++) {
+ bool match = false;
+ for (unsigned j = 0, f = Attrs2.size(); j != f; j++) {
+ // Matching attribute kind only. Except for Availabilty attributes,
+ // we are not getting into details of the attributes. For all practical purposes
+ // this is sufficient.
+ if (Attrs1[i]->getKind() == Attrs2[j]->getKind()) {
+ if (AvailabilityArgsMatch)
+ AvailabilityArgsMatch = AvailabilityAttrsMatch(Attrs1[i], Attrs2[j]);
+ match = true;
+ break;
+ }
+ }
+ if (!match)
+ return false;
+ }
+ return true;
+}
+
+/// AttributesMatch - This routine checks list of attributes for two
+/// decls. It returns false, if there is a mismatch in kind of
+/// attributes seen in the decls. It returns true if the two decls
+/// have list of same kind of attributes. Furthermore, when there
+/// are availability attributes in the two decls, it sets the
+/// AvailabilityArgsMatch to false if availability attributes have
+/// different versions, etc.
+static bool AttributesMatch(const Decl *Decl1, const Decl *Decl2,
+ bool &AvailabilityArgsMatch) {
+ if (!Decl1->hasAttrs() || !Decl2->hasAttrs()) {
+ AvailabilityArgsMatch = (Decl1->hasAttrs() == Decl2->hasAttrs());
+ return true;
+ }
+ AvailabilityArgsMatch = true;
+ const AttrVec &Attrs1 = Decl1->getAttrs();
+ const AttrVec &Attrs2 = Decl2->getAttrs();
+ bool match = MatchTwoAttributeLists(Attrs1, Attrs2, AvailabilityArgsMatch);
+ if (match && (Attrs2.size() > Attrs1.size()))
+ return MatchTwoAttributeLists(Attrs2, Attrs1, AvailabilityArgsMatch);
+ return match;
+}
+
+static bool IsValidIdentifier(ASTContext &Ctx,
+ const char *Name) {
+ if (!isIdentifierHead(Name[0]))
+ return false;
+ std::string NameString = Name;
+ NameString[0] = toLowercase(NameString[0]);
+ IdentifierInfo *II = &Ctx.Idents.get(NameString);
+ return II->getTokenID() == tok::identifier;
+}
+
+bool ObjCMigrateASTConsumer::migrateProperty(ASTContext &Ctx,
+ ObjCContainerDecl *D,
+ ObjCMethodDecl *Method) {
+ if (Method->isPropertyAccessor() || !Method->isInstanceMethod() ||
+ Method->param_size() != 0)
+ return false;
+ // Is this method candidate to be a getter?
+ QualType GRT = Method->getResultType();
+ if (GRT->isVoidType())
+ return false;
+
+ Selector GetterSelector = Method->getSelector();
+ ObjCInstanceTypeFamily OIT_Family =
+ Selector::getInstTypeMethodFamily(GetterSelector);
+
+ if (OIT_Family != OIT_None)
+ return false;
+
+ IdentifierInfo *getterName = GetterSelector.getIdentifierInfoForSlot(0);
+ Selector SetterSelector =
+ SelectorTable::constructSetterSelector(PP.getIdentifierTable(),
+ PP.getSelectorTable(),
+ getterName);
+ ObjCMethodDecl *SetterMethod = D->getInstanceMethod(SetterSelector);
+ unsigned LengthOfPrefix = 0;
+ if (!SetterMethod) {
+ // try a different naming convention for getter: isXxxxx
+ StringRef getterNameString = getterName->getName();
+ bool IsPrefix = getterNameString.startswith("is");
+ // Note that we don't want to change an isXXX method of retainable object
+ // type to property (readonly or otherwise).
+ if (IsPrefix && GRT->isObjCRetainableType())
+ return false;
+ if (IsPrefix || getterNameString.startswith("get")) {
+ LengthOfPrefix = (IsPrefix ? 2 : 3);
+ const char *CGetterName = getterNameString.data() + LengthOfPrefix;
+ // Make sure that first character after "is" or "get" prefix can
+ // start an identifier.
+ if (!IsValidIdentifier(Ctx, CGetterName))
+ return false;
+ if (CGetterName[0] && isUppercase(CGetterName[0])) {
+ getterName = &Ctx.Idents.get(CGetterName);
+ SetterSelector =
+ SelectorTable::constructSetterSelector(PP.getIdentifierTable(),
+ PP.getSelectorTable(),
+ getterName);
+ SetterMethod = D->getInstanceMethod(SetterSelector);
+ }
+ }
+ }
+
+ if (SetterMethod) {
+ if ((ASTMigrateActions & FrontendOptions::ObjCMT_ReadwriteProperty) == 0)
+ return false;
+ bool AvailabilityArgsMatch;
+ if (SetterMethod->isDeprecated() ||
+ !AttributesMatch(Method, SetterMethod, AvailabilityArgsMatch))
+ return false;
+
+ // Is this a valid setter, matching the target getter?
+ QualType SRT = SetterMethod->getResultType();
+ if (!SRT->isVoidType())
+ return false;
+ const ParmVarDecl *argDecl = *SetterMethod->param_begin();
+ QualType ArgType = argDecl->getType();
+ if (!Ctx.hasSameUnqualifiedType(ArgType, GRT))
+ return false;
+ edit::Commit commit(*Editor);
+ rewriteToObjCProperty(Method, SetterMethod, *NSAPIObj, commit,
+ LengthOfPrefix,
+ (ASTMigrateActions &
+ FrontendOptions::ObjCMT_AtomicProperty) != 0,
+ (ASTMigrateActions &
+ FrontendOptions::ObjCMT_NsAtomicIOSOnlyProperty) != 0,
+ AvailabilityArgsMatch);
+ Editor->commit(commit);
+ return true;
+ }
+ else if (ASTMigrateActions & FrontendOptions::ObjCMT_ReadonlyProperty) {
+ // Try a non-void method with no argument (and no setter or property of same name
+ // as a 'readonly' property.
+ edit::Commit commit(*Editor);
+ rewriteToObjCProperty(Method, 0 /*SetterMethod*/, *NSAPIObj, commit,
+ LengthOfPrefix,
+ (ASTMigrateActions &
+ FrontendOptions::ObjCMT_AtomicProperty) != 0,
+ (ASTMigrateActions &
+ FrontendOptions::ObjCMT_NsAtomicIOSOnlyProperty) != 0,
+ /*AvailabilityArgsMatch*/false);
+ Editor->commit(commit);
+ return true;
+ }
+ return false;
+}
+
+void ObjCMigrateASTConsumer::migrateNsReturnsInnerPointer(ASTContext &Ctx,
+ ObjCMethodDecl *OM) {
+ if (OM->isImplicit() ||
+ !OM->isInstanceMethod() ||
+ OM->hasAttr<ObjCReturnsInnerPointerAttr>())
+ return;
+
+ QualType RT = OM->getResultType();
+ if (!TypeIsInnerPointer(RT) ||
+ !Ctx.Idents.get("NS_RETURNS_INNER_POINTER").hasMacroDefinition())
+ return;
+
+ edit::Commit commit(*Editor);
+ commit.insertBefore(OM->getLocEnd(), " NS_RETURNS_INNER_POINTER");
+ Editor->commit(commit);
+}
+
+void ObjCMigrateASTConsumer::migratePropertyNsReturnsInnerPointer(ASTContext &Ctx,
+ ObjCPropertyDecl *P) {
+ QualType T = P->getType();
+
+ if (!TypeIsInnerPointer(T) ||
+ !Ctx.Idents.get("NS_RETURNS_INNER_POINTER").hasMacroDefinition())
+ return;
+ edit::Commit commit(*Editor);
+ commit.insertBefore(P->getLocEnd(), " NS_RETURNS_INNER_POINTER ");
+ Editor->commit(commit);
+}
+
+void ObjCMigrateASTConsumer::migrateAllMethodInstaceType(ASTContext &Ctx,
+ ObjCContainerDecl *CDecl) {
+ if (CDecl->isDeprecated())
+ return;
+
+ // migrate methods which can have instancetype as their result type.
+ for (ObjCContainerDecl::method_iterator M = CDecl->meth_begin(),
+ MEnd = CDecl->meth_end();
+ M != MEnd; ++M) {
+ ObjCMethodDecl *Method = (*M);
+ if (Method->isDeprecated())
+ continue;
+ migrateMethodInstanceType(Ctx, CDecl, Method);
+ }
+}
+
+void ObjCMigrateASTConsumer::migrateFactoryMethod(ASTContext &Ctx,
+ ObjCContainerDecl *CDecl,
+ ObjCMethodDecl *OM,
+ ObjCInstanceTypeFamily OIT_Family) {
+ if (OM->isInstanceMethod() ||
+ OM->getResultType() == Ctx.getObjCInstanceType() ||
+ !OM->getResultType()->isObjCIdType())
+ return;
+
+ // Candidate factory methods are + (id) NaMeXXX : ... which belong to a class
+ // NSYYYNamE with matching names be at least 3 characters long.
+ ObjCInterfaceDecl *IDecl = dyn_cast<ObjCInterfaceDecl>(CDecl);
+ if (!IDecl) {
+ if (ObjCCategoryDecl *CatDecl = dyn_cast<ObjCCategoryDecl>(CDecl))
+ IDecl = CatDecl->getClassInterface();
+ else if (ObjCImplDecl *ImpDecl = dyn_cast<ObjCImplDecl>(CDecl))
+ IDecl = ImpDecl->getClassInterface();
+ }
+ if (!IDecl)
+ return;
+
+ std::string StringClassName = IDecl->getName();
+ StringRef LoweredClassName(StringClassName);
+ std::string StringLoweredClassName = LoweredClassName.lower();
+ LoweredClassName = StringLoweredClassName;
+
+ IdentifierInfo *MethodIdName = OM->getSelector().getIdentifierInfoForSlot(0);
+ // Handle method with no name at its first selector slot; e.g. + (id):(int)x.
+ if (!MethodIdName)
+ return;
+
+ std::string MethodName = MethodIdName->getName();
+ if (OIT_Family == OIT_Singleton || OIT_Family == OIT_ReturnsSelf) {
+ StringRef STRefMethodName(MethodName);
+ size_t len = 0;
+ if (STRefMethodName.startswith("standard"))
+ len = strlen("standard");
+ else if (STRefMethodName.startswith("shared"))
+ len = strlen("shared");
+ else if (STRefMethodName.startswith("default"))
+ len = strlen("default");
+ else
+ return;
+ MethodName = STRefMethodName.substr(len);
+ }
+ std::string MethodNameSubStr = MethodName.substr(0, 3);
+ StringRef MethodNamePrefix(MethodNameSubStr);
+ std::string StringLoweredMethodNamePrefix = MethodNamePrefix.lower();
+ MethodNamePrefix = StringLoweredMethodNamePrefix;
+ size_t Ix = LoweredClassName.rfind(MethodNamePrefix);
+ if (Ix == StringRef::npos)
+ return;
+ std::string ClassNamePostfix = LoweredClassName.substr(Ix);
+ StringRef LoweredMethodName(MethodName);
+ std::string StringLoweredMethodName = LoweredMethodName.lower();
+ LoweredMethodName = StringLoweredMethodName;
+ if (!LoweredMethodName.startswith(ClassNamePostfix))
+ return;
+ if (OIT_Family == OIT_ReturnsSelf)
+ ReplaceWithClasstype(*this, OM);
+ else
+ ReplaceWithInstancetype(*this, OM);
+}
+
+static bool IsVoidStarType(QualType Ty) {
+ if (!Ty->isPointerType())
+ return false;
+
+ while (const TypedefType *TD = dyn_cast<TypedefType>(Ty.getTypePtr()))
+ Ty = TD->getDecl()->getUnderlyingType();
+
+ // Is the type void*?
+ const PointerType* PT = Ty->getAs<PointerType>();
+ if (PT->getPointeeType().getUnqualifiedType()->isVoidType())
+ return true;
+ return IsVoidStarType(PT->getPointeeType());
+}
+
+/// AuditedType - This routine audits the type AT and returns false if it is one of known
+/// CF object types or of the "void *" variety. It returns true if we don't care about the type
+/// such as a non-pointer or pointers which have no ownership issues (such as "int *").
+static bool AuditedType (QualType AT) {
+ if (!AT->isAnyPointerType() && !AT->isBlockPointerType())
+ return true;
+ // FIXME. There isn't much we can say about CF pointer type; or is there?
+ if (ento::coreFoundation::isCFObjectRef(AT) ||
+ IsVoidStarType(AT) ||
+ // If an ObjC object is type, assuming that it is not a CF function and
+ // that it is an un-audited function.
+ AT->isObjCObjectPointerType() || AT->isObjCBuiltinType())
+ return false;
+ // All other pointers are assumed audited as harmless.
+ return true;
+}
+
+void ObjCMigrateASTConsumer::AnnotateImplicitBridging(ASTContext &Ctx) {
+ if (CFFunctionIBCandidates.empty())
+ return;
+ if (!Ctx.Idents.get("CF_IMPLICIT_BRIDGING_ENABLED").hasMacroDefinition()) {
+ CFFunctionIBCandidates.clear();
+ FileId = FileID();
+ return;
+ }
+ // Insert CF_IMPLICIT_BRIDGING_ENABLE/CF_IMPLICIT_BRIDGING_DISABLED
+ const Decl *FirstFD = CFFunctionIBCandidates[0];
+ const Decl *LastFD =
+ CFFunctionIBCandidates[CFFunctionIBCandidates.size()-1];
+ const char *PragmaString = "\nCF_IMPLICIT_BRIDGING_ENABLED\n\n";
+ edit::Commit commit(*Editor);
+ commit.insertBefore(FirstFD->getLocStart(), PragmaString);
+ PragmaString = "\n\nCF_IMPLICIT_BRIDGING_DISABLED\n";
+ SourceLocation EndLoc = LastFD->getLocEnd();
+ // get location just past end of function location.
+ EndLoc = PP.getLocForEndOfToken(EndLoc);
+ if (isa<FunctionDecl>(LastFD)) {
+ // For Methods, EndLoc points to the ending semcolon. So,
+ // not of these extra work is needed.
+ Token Tok;
+ // get locaiton of token that comes after end of function.
+ bool Failed = PP.getRawToken(EndLoc, Tok, /*IgnoreWhiteSpace=*/true);
+ if (!Failed)
+ EndLoc = Tok.getLocation();
+ }
+ commit.insertAfterToken(EndLoc, PragmaString);
+ Editor->commit(commit);
+ FileId = FileID();
+ CFFunctionIBCandidates.clear();
+}
+
+void ObjCMigrateASTConsumer::migrateCFAnnotation(ASTContext &Ctx, const Decl *Decl) {
+ if (Decl->isDeprecated())
+ return;
+
+ if (Decl->hasAttr<CFAuditedTransferAttr>()) {
+ assert(CFFunctionIBCandidates.empty() &&
+ "Cannot have audited functions/methods inside user "
+ "provided CF_IMPLICIT_BRIDGING_ENABLE");
+ return;
+ }
+
+ // Finction must be annotated first.
+ if (const FunctionDecl *FuncDecl = dyn_cast<FunctionDecl>(Decl)) {
+ CF_BRIDGING_KIND AuditKind = migrateAddFunctionAnnotation(Ctx, FuncDecl);
+ if (AuditKind == CF_BRIDGING_ENABLE) {
+ CFFunctionIBCandidates.push_back(Decl);
+ if (FileId.isInvalid())
+ FileId = PP.getSourceManager().getFileID(Decl->getLocation());
+ }
+ else if (AuditKind == CF_BRIDGING_MAY_INCLUDE) {
+ if (!CFFunctionIBCandidates.empty()) {
+ CFFunctionIBCandidates.push_back(Decl);
+ if (FileId.isInvalid())
+ FileId = PP.getSourceManager().getFileID(Decl->getLocation());
+ }
+ }
+ else
+ AnnotateImplicitBridging(Ctx);
+ }
+ else {
+ migrateAddMethodAnnotation(Ctx, cast<ObjCMethodDecl>(Decl));
+ AnnotateImplicitBridging(Ctx);
+ }
+}
+
+void ObjCMigrateASTConsumer::AddCFAnnotations(ASTContext &Ctx,
+ const CallEffects &CE,
+ const FunctionDecl *FuncDecl,
+ bool ResultAnnotated) {
+ // Annotate function.
+ if (!ResultAnnotated) {
+ RetEffect Ret = CE.getReturnValue();
+ const char *AnnotationString = 0;
+ if (Ret.getObjKind() == RetEffect::CF) {
+ if (Ret.isOwned() &&
+ Ctx.Idents.get("CF_RETURNS_RETAINED").hasMacroDefinition())
+ AnnotationString = " CF_RETURNS_RETAINED";
+ else if (Ret.notOwned() &&
+ Ctx.Idents.get("CF_RETURNS_NOT_RETAINED").hasMacroDefinition())
+ AnnotationString = " CF_RETURNS_NOT_RETAINED";
+ }
+ else if (Ret.getObjKind() == RetEffect::ObjC) {
+ if (Ret.isOwned() &&
+ Ctx.Idents.get("NS_RETURNS_RETAINED").hasMacroDefinition())
+ AnnotationString = " NS_RETURNS_RETAINED";
+ }
+
+ if (AnnotationString) {
+ edit::Commit commit(*Editor);
+ commit.insertAfterToken(FuncDecl->getLocEnd(), AnnotationString);
+ Editor->commit(commit);
+ }
+ }
+ llvm::ArrayRef<ArgEffect> AEArgs = CE.getArgs();
+ unsigned i = 0;
+ for (FunctionDecl::param_const_iterator pi = FuncDecl->param_begin(),
+ pe = FuncDecl->param_end(); pi != pe; ++pi, ++i) {
+ const ParmVarDecl *pd = *pi;
+ ArgEffect AE = AEArgs[i];
+ if (AE == DecRef && !pd->getAttr<CFConsumedAttr>() &&
+ Ctx.Idents.get("CF_CONSUMED").hasMacroDefinition()) {
+ edit::Commit commit(*Editor);
+ commit.insertBefore(pd->getLocation(), "CF_CONSUMED ");
+ Editor->commit(commit);
+ }
+ else if (AE == DecRefMsg && !pd->getAttr<NSConsumedAttr>() &&
+ Ctx.Idents.get("NS_CONSUMED").hasMacroDefinition()) {
+ edit::Commit commit(*Editor);
+ commit.insertBefore(pd->getLocation(), "NS_CONSUMED ");
+ Editor->commit(commit);
+ }
+ }
+}
+
+
+ObjCMigrateASTConsumer::CF_BRIDGING_KIND
+ ObjCMigrateASTConsumer::migrateAddFunctionAnnotation(
+ ASTContext &Ctx,
+ const FunctionDecl *FuncDecl) {
+ if (FuncDecl->hasBody())
+ return CF_BRIDGING_NONE;
+
+ CallEffects CE = CallEffects::getEffect(FuncDecl);
+ bool FuncIsReturnAnnotated = (FuncDecl->getAttr<CFReturnsRetainedAttr>() ||
+ FuncDecl->getAttr<CFReturnsNotRetainedAttr>() ||
+ FuncDecl->getAttr<NSReturnsRetainedAttr>() ||
+ FuncDecl->getAttr<NSReturnsNotRetainedAttr>() ||
+ FuncDecl->getAttr<NSReturnsAutoreleasedAttr>());
+
+ // Trivial case of when funciton is annotated and has no argument.
+ if (FuncIsReturnAnnotated && FuncDecl->getNumParams() == 0)
+ return CF_BRIDGING_NONE;
+
+ bool ReturnCFAudited = false;
+ if (!FuncIsReturnAnnotated) {
+ RetEffect Ret = CE.getReturnValue();
+ if (Ret.getObjKind() == RetEffect::CF &&
+ (Ret.isOwned() || Ret.notOwned()))
+ ReturnCFAudited = true;
+ else if (!AuditedType(FuncDecl->getResultType()))
+ return CF_BRIDGING_NONE;
+ }
+
+ // At this point result type is audited for potential inclusion.
+ // Now, how about argument types.
+ llvm::ArrayRef<ArgEffect> AEArgs = CE.getArgs();
+ unsigned i = 0;
+ bool ArgCFAudited = false;
+ for (FunctionDecl::param_const_iterator pi = FuncDecl->param_begin(),
+ pe = FuncDecl->param_end(); pi != pe; ++pi, ++i) {
+ const ParmVarDecl *pd = *pi;
+ ArgEffect AE = AEArgs[i];
+ if (AE == DecRef /*CFConsumed annotated*/ || AE == IncRef) {
+ if (AE == DecRef && !pd->getAttr<CFConsumedAttr>())
+ ArgCFAudited = true;
+ else if (AE == IncRef)
+ ArgCFAudited = true;
+ }
+ else {
+ QualType AT = pd->getType();
+ if (!AuditedType(AT)) {
+ AddCFAnnotations(Ctx, CE, FuncDecl, FuncIsReturnAnnotated);
+ return CF_BRIDGING_NONE;
+ }
+ }
+ }
+ if (ReturnCFAudited || ArgCFAudited)
+ return CF_BRIDGING_ENABLE;
+
+ return CF_BRIDGING_MAY_INCLUDE;
+}
+
+void ObjCMigrateASTConsumer::migrateARCSafeAnnotation(ASTContext &Ctx,
+ ObjCContainerDecl *CDecl) {
+ if (!isa<ObjCInterfaceDecl>(CDecl) || CDecl->isDeprecated())
+ return;
+
+ // migrate methods which can have instancetype as their result type.
+ for (ObjCContainerDecl::method_iterator M = CDecl->meth_begin(),
+ MEnd = CDecl->meth_end();
+ M != MEnd; ++M) {
+ ObjCMethodDecl *Method = (*M);
+ migrateCFAnnotation(Ctx, Method);
+ }
+}
+
+void ObjCMigrateASTConsumer::AddCFAnnotations(ASTContext &Ctx,
+ const CallEffects &CE,
+ const ObjCMethodDecl *MethodDecl,
+ bool ResultAnnotated) {
+ // Annotate function.
+ if (!ResultAnnotated) {
+ RetEffect Ret = CE.getReturnValue();
+ const char *AnnotationString = 0;
+ if (Ret.getObjKind() == RetEffect::CF) {
+ if (Ret.isOwned() &&
+ Ctx.Idents.get("CF_RETURNS_RETAINED").hasMacroDefinition())
+ AnnotationString = " CF_RETURNS_RETAINED";
+ else if (Ret.notOwned() &&
+ Ctx.Idents.get("CF_RETURNS_NOT_RETAINED").hasMacroDefinition())
+ AnnotationString = " CF_RETURNS_NOT_RETAINED";
+ }
+ else if (Ret.getObjKind() == RetEffect::ObjC) {
+ ObjCMethodFamily OMF = MethodDecl->getMethodFamily();
+ switch (OMF) {
+ case clang::OMF_alloc:
+ case clang::OMF_new:
+ case clang::OMF_copy:
+ case clang::OMF_init:
+ case clang::OMF_mutableCopy:
+ break;
+
+ default:
+ if (Ret.isOwned() &&
+ Ctx.Idents.get("NS_RETURNS_RETAINED").hasMacroDefinition())
+ AnnotationString = " NS_RETURNS_RETAINED";
+ break;
+ }
+ }
+
+ if (AnnotationString) {
+ edit::Commit commit(*Editor);
+ commit.insertBefore(MethodDecl->getLocEnd(), AnnotationString);
+ Editor->commit(commit);
+ }
+ }
+ llvm::ArrayRef<ArgEffect> AEArgs = CE.getArgs();
+ unsigned i = 0;
+ for (ObjCMethodDecl::param_const_iterator pi = MethodDecl->param_begin(),
+ pe = MethodDecl->param_end(); pi != pe; ++pi, ++i) {
+ const ParmVarDecl *pd = *pi;
+ ArgEffect AE = AEArgs[i];
+ if (AE == DecRef && !pd->getAttr<CFConsumedAttr>() &&
+ Ctx.Idents.get("CF_CONSUMED").hasMacroDefinition()) {
+ edit::Commit commit(*Editor);
+ commit.insertBefore(pd->getLocation(), "CF_CONSUMED ");
+ Editor->commit(commit);
+ }
+ }
+}
+
+void ObjCMigrateASTConsumer::migrateAddMethodAnnotation(
+ ASTContext &Ctx,
+ const ObjCMethodDecl *MethodDecl) {
+ if (MethodDecl->hasBody() || MethodDecl->isImplicit())
+ return;
+
+ CallEffects CE = CallEffects::getEffect(MethodDecl);
+ bool MethodIsReturnAnnotated = (MethodDecl->getAttr<CFReturnsRetainedAttr>() ||
+ MethodDecl->getAttr<CFReturnsNotRetainedAttr>() ||
+ MethodDecl->getAttr<NSReturnsRetainedAttr>() ||
+ MethodDecl->getAttr<NSReturnsNotRetainedAttr>() ||
+ MethodDecl->getAttr<NSReturnsAutoreleasedAttr>());
+
+ if (CE.getReceiver() == DecRefMsg &&
+ !MethodDecl->getAttr<NSConsumesSelfAttr>() &&
+ MethodDecl->getMethodFamily() != OMF_init &&
+ MethodDecl->getMethodFamily() != OMF_release &&
+ Ctx.Idents.get("NS_CONSUMES_SELF").hasMacroDefinition()) {
+ edit::Commit commit(*Editor);
+ commit.insertBefore(MethodDecl->getLocEnd(), " NS_CONSUMES_SELF");
+ Editor->commit(commit);
+ }
+
+ // Trivial case of when funciton is annotated and has no argument.
+ if (MethodIsReturnAnnotated &&
+ (MethodDecl->param_begin() == MethodDecl->param_end()))
+ return;
+
+ if (!MethodIsReturnAnnotated) {
+ RetEffect Ret = CE.getReturnValue();
+ if ((Ret.getObjKind() == RetEffect::CF ||
+ Ret.getObjKind() == RetEffect::ObjC) &&
+ (Ret.isOwned() || Ret.notOwned())) {
+ AddCFAnnotations(Ctx, CE, MethodDecl, false);
+ return;
+ }
+ else if (!AuditedType(MethodDecl->getResultType()))
+ return;
+ }
+
+ // At this point result type is either annotated or audited.
+ // Now, how about argument types.
+ llvm::ArrayRef<ArgEffect> AEArgs = CE.getArgs();
+ unsigned i = 0;
+ for (ObjCMethodDecl::param_const_iterator pi = MethodDecl->param_begin(),
+ pe = MethodDecl->param_end(); pi != pe; ++pi, ++i) {
+ const ParmVarDecl *pd = *pi;
+ ArgEffect AE = AEArgs[i];
+ if ((AE == DecRef && !pd->getAttr<CFConsumedAttr>()) || AE == IncRef ||
+ !AuditedType(pd->getType())) {
+ AddCFAnnotations(Ctx, CE, MethodDecl, MethodIsReturnAnnotated);
+ return;
+ }
+ }
+ return;
+}
+
namespace {
class RewritesReceiver : public edit::EditsReceiver {
@@ -202,7 +1582,114 @@ public:
}
+static bool
+IsReallyASystemHeader(ASTContext &Ctx, const FileEntry *file, FileID FID) {
+ bool Invalid = false;
+ const SrcMgr::SLocEntry &SEntry =
+ Ctx.getSourceManager().getSLocEntry(FID, &Invalid);
+ if (!Invalid && SEntry.isFile()) {
+ const SrcMgr::FileInfo &FI = SEntry.getFile();
+ if (!FI.hasLineDirectives()) {
+ if (FI.getFileCharacteristic() == SrcMgr::C_ExternCSystem)
+ return true;
+ if (FI.getFileCharacteristic() == SrcMgr::C_System) {
+ // This file is in a system header directory. Continue with commiting change
+ // only if it is a user specified system directory because user put a
+ // .system_framework file in the framework directory.
+ StringRef Directory(file->getDir()->getName());
+ size_t Ix = Directory.rfind(".framework");
+ if (Ix == StringRef::npos)
+ return true;
+ std::string PatchToSystemFramework = Directory.slice(0, Ix+sizeof(".framework"));
+ PatchToSystemFramework += ".system_framework";
+ if (!llvm::sys::fs::exists(PatchToSystemFramework.data()))
+ return true;
+ }
+ }
+ }
+ return false;
+}
+
void ObjCMigrateASTConsumer::HandleTranslationUnit(ASTContext &Ctx) {
+
+ TranslationUnitDecl *TU = Ctx.getTranslationUnitDecl();
+ if (ASTMigrateActions & FrontendOptions::ObjCMT_MigrateDecls) {
+ for (DeclContext::decl_iterator D = TU->decls_begin(), DEnd = TU->decls_end();
+ D != DEnd; ++D) {
+ FileID FID = PP.getSourceManager().getFileID((*D)->getLocation());
+ if (!FID.isInvalid())
+ if (!FileId.isInvalid() && FileId != FID) {
+ if (ASTMigrateActions & FrontendOptions::ObjCMT_Annotation)
+ AnnotateImplicitBridging(Ctx);
+ }
+
+ if (ObjCInterfaceDecl *CDecl = dyn_cast<ObjCInterfaceDecl>(*D))
+ migrateObjCInterfaceDecl(Ctx, CDecl);
+ if (ObjCCategoryDecl *CatDecl = dyn_cast<ObjCCategoryDecl>(*D)) {
+ migrateObjCInterfaceDecl(Ctx, CatDecl);
+ if (ASTMigrateActions & FrontendOptions::ObjCMT_Annotation)
+ migrateDeprecatedAnnotation(Ctx, CatDecl);
+ }
+ else if (ObjCProtocolDecl *PDecl = dyn_cast<ObjCProtocolDecl>(*D))
+ ObjCProtocolDecls.insert(PDecl);
+ else if (const ObjCImplementationDecl *ImpDecl =
+ dyn_cast<ObjCImplementationDecl>(*D)) {
+ if (ASTMigrateActions & FrontendOptions::ObjCMT_ProtocolConformance)
+ migrateProtocolConformance(Ctx, ImpDecl);
+ }
+ else if (const EnumDecl *ED = dyn_cast<EnumDecl>(*D)) {
+ if (!(ASTMigrateActions & FrontendOptions::ObjCMT_NsMacros))
+ continue;
+ DeclContext::decl_iterator N = D;
+ if (++N != DEnd) {
+ const TypedefDecl *TD = dyn_cast<TypedefDecl>(*N);
+ if (migrateNSEnumDecl(Ctx, ED, TD) && TD)
+ D++;
+ }
+ else
+ migrateNSEnumDecl(Ctx, ED, /*TypedefDecl */0);
+ }
+ else if (const TypedefDecl *TD = dyn_cast<TypedefDecl>(*D)) {
+ if (!(ASTMigrateActions & FrontendOptions::ObjCMT_NsMacros))
+ continue;
+ DeclContext::decl_iterator N = D;
+ if (++N == DEnd)
+ continue;
+ if (const EnumDecl *ED = dyn_cast<EnumDecl>(*N)) {
+ if (++N != DEnd)
+ if (const TypedefDecl *TDF = dyn_cast<TypedefDecl>(*N)) {
+ // prefer typedef-follows-enum to enum-follows-typedef pattern.
+ if (migrateNSEnumDecl(Ctx, ED, TDF)) {
+ ++D; ++D;
+ CacheObjCNSIntegerTypedefed(TD);
+ continue;
+ }
+ }
+ if (migrateNSEnumDecl(Ctx, ED, TD)) {
+ ++D;
+ continue;
+ }
+ }
+ CacheObjCNSIntegerTypedefed(TD);
+ }
+ else if (const FunctionDecl *FD = dyn_cast<FunctionDecl>(*D)) {
+ if (ASTMigrateActions & FrontendOptions::ObjCMT_Annotation)
+ migrateCFAnnotation(Ctx, FD);
+ }
+
+ if (ObjCContainerDecl *CDecl = dyn_cast<ObjCContainerDecl>(*D)) {
+ // migrate methods which can have instancetype as their result type.
+ if (ASTMigrateActions & FrontendOptions::ObjCMT_Instancetype)
+ migrateAllMethodInstaceType(Ctx, CDecl);
+ // annotate methods with CF annotations.
+ if (ASTMigrateActions & FrontendOptions::ObjCMT_Annotation)
+ migrateARCSafeAnnotation(Ctx, CDecl);
+ }
+ }
+ if (ASTMigrateActions & FrontendOptions::ObjCMT_Annotation)
+ AnnotateImplicitBridging(Ctx);
+ }
+
Rewriter rewriter(Ctx.getSourceManager(), Ctx.getLangOpts());
RewritesReceiver Rec(rewriter);
Editor->applyRewrites(Rec);
@@ -213,6 +1700,10 @@ void ObjCMigrateASTConsumer::HandleTranslationUnit(ASTContext &Ctx) {
RewriteBuffer &buf = I->second;
const FileEntry *file = Ctx.getSourceManager().getFileEntryForID(FID);
assert(file);
+ if (IsReallyASystemHeader(Ctx, file, FID))
+ continue;
+ if (!canModifyFile(file->getName()))
+ continue;
SmallString<512> newText;
llvm::raw_svector_ostream vecOS(newText);
buf.write(vecOS);
@@ -236,16 +1727,49 @@ bool MigrateSourceAction::BeginInvocation(CompilerInstance &CI) {
return true;
}
+static std::vector<std::string> getWhiteListFilenames(StringRef DirPath) {
+ using namespace llvm::sys::fs;
+ using namespace llvm::sys::path;
+
+ std::vector<std::string> Filenames;
+ if (DirPath.empty() || !is_directory(DirPath))
+ return Filenames;
+
+ llvm::error_code EC;
+ directory_iterator DI = directory_iterator(DirPath, EC);
+ directory_iterator DE;
+ for (; !EC && DI != DE; DI = DI.increment(EC)) {
+ if (is_regular_file(DI->path()))
+ Filenames.push_back(filename(DI->path()));
+ }
+
+ return Filenames;
+}
+
ASTConsumer *MigrateSourceAction::CreateASTConsumer(CompilerInstance &CI,
StringRef InFile) {
PPConditionalDirectiveRecord *
PPRec = new PPConditionalDirectiveRecord(CI.getSourceManager());
+ unsigned ObjCMTAction = CI.getFrontendOpts().ObjCMTAction;
+ unsigned ObjCMTOpts = ObjCMTAction;
+ // These are companion flags, they do not enable transformations.
+ ObjCMTOpts &= ~(FrontendOptions::ObjCMT_AtomicProperty |
+ FrontendOptions::ObjCMT_NsAtomicIOSOnlyProperty);
+ if (ObjCMTOpts == FrontendOptions::ObjCMT_None) {
+ // If no specific option was given, enable literals+subscripting transforms
+ // by default.
+ ObjCMTAction |= FrontendOptions::ObjCMT_Literals |
+ FrontendOptions::ObjCMT_Subscripting;
+ }
CI.getPreprocessor().addPPCallbacks(PPRec);
+ std::vector<std::string> WhiteList =
+ getWhiteListFilenames(CI.getFrontendOpts().ObjCMTWhiteListPath);
return new ObjCMigrateASTConsumer(CI.getFrontendOpts().OutputFile,
- /*MigrateLiterals=*/true,
- /*MigrateSubscripting=*/true,
+ ObjCMTAction,
Remapper,
CI.getFileManager(),
PPRec,
- /*isOutputFile=*/true);
+ CI.getPreprocessor(),
+ /*isOutputFile=*/true,
+ WhiteList);
}
diff --git a/lib/ARCMigrate/TransUnbridgedCasts.cpp b/lib/ARCMigrate/TransUnbridgedCasts.cpp
index fc4a75fdb838..7b360c640cfd 100644
--- a/lib/ARCMigrate/TransUnbridgedCasts.cpp
+++ b/lib/ARCMigrate/TransUnbridgedCasts.cpp
@@ -77,6 +77,13 @@ public:
TraverseStmt(body);
}
+ bool TraverseBlockDecl(BlockDecl *D) {
+ // ParentMap does not enter into a BlockDecl to record its stmts, so use a
+ // new UnbridgedCastRewriter to handle the block.
+ UnbridgedCastRewriter(Pass).transformBody(D->getBody(), D);
+ return true;
+ }
+
bool VisitCastExpr(CastExpr *E) {
if (E->getCastKind() != CK_CPointerToObjCPointerCast &&
E->getCastKind() != CK_BitCast &&
@@ -148,7 +155,7 @@ private:
if (FD->getName() == "CFRetain" &&
FD->getNumParams() == 1 &&
FD->getParent()->isTranslationUnit() &&
- FD->hasExternalLinkage()) {
+ FD->isExternallyVisible()) {
Expr *Arg = callE->getArg(0);
if (const ImplicitCastExpr *ICE = dyn_cast<ImplicitCastExpr>(Arg)) {
const Expr *sub = ICE->getSubExpr();
@@ -413,7 +420,7 @@ private:
FD = dyn_cast_or_null<FunctionDecl>(callE->getCalleeDecl()))
if (FD->getName() == "CFRetain" && FD->getNumParams() == 1 &&
FD->getParent()->isTranslationUnit() &&
- FD->hasExternalLinkage())
+ FD->isExternallyVisible())
return true;
return false;
diff --git a/lib/ARCMigrate/Transforms.cpp b/lib/ARCMigrate/Transforms.cpp
index 087219535a18..679b924ba009 100644
--- a/lib/ARCMigrate/Transforms.cpp
+++ b/lib/ARCMigrate/Transforms.cpp
@@ -49,7 +49,7 @@ bool trans::canApplyWeak(ASTContext &Ctx, QualType type,
return false;
// iOS is always safe to use 'weak'.
- if (Ctx.getTargetInfo().getTriple().getOS() == llvm::Triple::IOS)
+ if (Ctx.getTargetInfo().getTriple().isiOS())
AllowOnUnknownClass = true;
while (const PointerType *ptr = T->getAs<PointerType>())
@@ -94,7 +94,7 @@ bool trans::isPlusOne(const Expr *E) {
if (FD->isGlobal() &&
FD->getIdentifier() &&
FD->getParent()->isTranslationUnit() &&
- FD->hasExternalLinkage() &&
+ FD->isExternallyVisible() &&
ento::cocoa::isRefType(callE->getType(), "CF",
FD->getIdentifier()->getName())) {
StringRef fname = FD->getIdentifier()->getName();
@@ -122,8 +122,8 @@ bool trans::isPlusOne(const Expr *E) {
/// If no semicolon is found or the location is inside a macro, the returned
/// source location will be invalid.
SourceLocation trans::findLocationAfterSemi(SourceLocation loc,
- ASTContext &Ctx) {
- SourceLocation SemiLoc = findSemiAfterLocation(loc, Ctx);
+ ASTContext &Ctx, bool IsDecl) {
+ SourceLocation SemiLoc = findSemiAfterLocation(loc, Ctx, IsDecl);
if (SemiLoc.isInvalid())
return SourceLocation();
return SemiLoc.getLocWithOffset(1);
@@ -134,7 +134,8 @@ SourceLocation trans::findLocationAfterSemi(SourceLocation loc,
/// If no semicolon is found or the location is inside a macro, the returned
/// source location will be invalid.
SourceLocation trans::findSemiAfterLocation(SourceLocation loc,
- ASTContext &Ctx) {
+ ASTContext &Ctx,
+ bool IsDecl) {
SourceManager &SM = Ctx.getSourceManager();
if (loc.isMacroID()) {
if (!Lexer::isAtEndOfMacroExpansion(loc, SM, Ctx.getLangOpts(), &loc))
@@ -159,8 +160,13 @@ SourceLocation trans::findSemiAfterLocation(SourceLocation loc,
file.begin(), tokenBegin, file.end());
Token tok;
lexer.LexFromRawLexer(tok);
- if (tok.isNot(tok::semi))
- return SourceLocation();
+ if (tok.isNot(tok::semi)) {
+ if (!IsDecl)
+ return SourceLocation();
+ // Declaration may be followed with other tokens; such as an __attribute,
+ // before ending with a semicolon.
+ return findSemiAfterLocation(tok.getLocation(), Ctx, /*IsDecl*/true);
+ }
return tok.getLocation();
}
@@ -198,7 +204,7 @@ bool trans::isGlobalVar(Expr *E) {
E = E->IgnoreParenCasts();
if (DeclRefExpr *DRE = dyn_cast<DeclRefExpr>(E))
return DRE->getDecl()->getDeclContext()->isFileContext() &&
- DRE->getDecl()->hasExternalLinkage();
+ DRE->getDecl()->isExternallyVisible();
if (ConditionalOperator *condOp = dyn_cast<ConditionalOperator>(E))
return isGlobalVar(condOp->getTrueExpr()) &&
isGlobalVar(condOp->getFalseExpr());
diff --git a/lib/ARCMigrate/Transforms.h b/lib/ARCMigrate/Transforms.h
index e20fe5927f39..eab5e85d56b7 100644
--- a/lib/ARCMigrate/Transforms.h
+++ b/lib/ARCMigrate/Transforms.h
@@ -167,13 +167,15 @@ bool isPlusOne(const Expr *E);
/// immediately after the semicolon following the statement.
/// If no semicolon is found or the location is inside a macro, the returned
/// source location will be invalid.
-SourceLocation findLocationAfterSemi(SourceLocation loc, ASTContext &Ctx);
+SourceLocation findLocationAfterSemi(SourceLocation loc, ASTContext &Ctx,
+ bool IsDecl = false);
/// \brief 'Loc' is the end of a statement range. This returns the location
/// of the semicolon following the statement.
/// If no semicolon is found or the location is inside a macro, the returned
/// source location will be invalid.
-SourceLocation findSemiAfterLocation(SourceLocation loc, ASTContext &Ctx);
+SourceLocation findSemiAfterLocation(SourceLocation loc, ASTContext &Ctx,
+ bool IsDecl = false);
bool hasSideEffects(Expr *E, ASTContext &Ctx);
bool isGlobalVar(Expr *E);
diff --git a/lib/AST/APValue.cpp b/lib/AST/APValue.cpp
index 98e825b3bafb..541836b21b70 100644
--- a/lib/AST/APValue.cpp
+++ b/lib/AST/APValue.cpp
@@ -212,6 +212,40 @@ void APValue::DestroyDataAndMakeUninit() {
Kind = Uninitialized;
}
+bool APValue::needsCleanup() const {
+ switch (getKind()) {
+ case Uninitialized:
+ case AddrLabelDiff:
+ return false;
+ case Struct:
+ case Union:
+ case Array:
+ case Vector:
+ return true;
+ case Int:
+ return getInt().needsCleanup();
+ case Float:
+ return getFloat().needsCleanup();
+ case ComplexFloat:
+ assert(getComplexFloatImag().needsCleanup() ==
+ getComplexFloatReal().needsCleanup() &&
+ "In _Complex float types, real and imaginary values always have the "
+ "same size.");
+ return getComplexFloatReal().needsCleanup();
+ case ComplexInt:
+ assert(getComplexIntImag().needsCleanup() ==
+ getComplexIntReal().needsCleanup() &&
+ "In _Complex int types, real and imaginary values must have the "
+ "same size.");
+ return getComplexIntReal().needsCleanup();
+ case LValue:
+ return reinterpret_cast<const LV *>(Data)->hasPathPtr();
+ case MemberPointer:
+ return reinterpret_cast<const MemberPointerData *>(Data)->hasPathPtr();
+ }
+ llvm_unreachable("Unknown APValue kind!");
+}
+
void APValue::swap(APValue &RHS) {
std::swap(Kind, RHS.Kind);
char TmpData[MaxSize];
diff --git a/lib/AST/ASTContext.cpp b/lib/AST/ASTContext.cpp
index 176aec53a252..a03cf9e7d47b 100644
--- a/lib/AST/ASTContext.cpp
+++ b/lib/AST/ASTContext.cpp
@@ -25,13 +25,16 @@
#include "clang/AST/ExprCXX.h"
#include "clang/AST/ExternalASTSource.h"
#include "clang/AST/Mangle.h"
+#include "clang/AST/MangleNumberingContext.h"
#include "clang/AST/RecordLayout.h"
+#include "clang/AST/RecursiveASTVisitor.h"
#include "clang/AST/TypeLoc.h"
#include "clang/Basic/Builtins.h"
#include "clang/Basic/SourceManager.h"
#include "clang/Basic/TargetInfo.h"
#include "llvm/ADT/SmallString.h"
#include "llvm/ADT/StringExtras.h"
+#include "llvm/ADT/Triple.h"
#include "llvm/Support/Capacity.h"
#include "llvm/Support/MathExtras.h"
#include "llvm/Support/raw_ostream.h"
@@ -132,8 +135,14 @@ RawComment *ASTContext::getRawCommentForDeclNoCache(const Decl *D) const {
isa<RedeclarableTemplateDecl>(D) ||
isa<ClassTemplateSpecializationDecl>(D))
DeclLoc = D->getLocStart();
- else
+ else {
DeclLoc = D->getLocation();
+ // If location of the typedef name is in a macro, it is because being
+ // declared via a macro. Try using declaration's starting location
+ // as the "declaration location".
+ if (DeclLoc.isMacroID() && isa<TypedefDecl>(D))
+ DeclLoc = D->getLocStart();
+ }
// If the declaration doesn't map directly to a location in a file, we
// can't find the comment.
@@ -175,7 +184,8 @@ RawComment *ASTContext::getRawCommentForDeclNoCache(const Decl *D) const {
// First check whether we have a trailing comment.
if (Comment != RawComments.end() &&
(*Comment)->isDocumentation() && (*Comment)->isTrailingComment() &&
- (isa<FieldDecl>(D) || isa<EnumConstantDecl>(D) || isa<VarDecl>(D))) {
+ (isa<FieldDecl>(D) || isa<EnumConstantDecl>(D) || isa<VarDecl>(D) ||
+ isa<ObjCMethodDecl>(D) || isa<ObjCPropertyDecl>(D))) {
std::pair<FileID, unsigned> CommentBeginDecomp
= SourceMgr.getDecomposedLoc((*Comment)->getSourceRange().getBegin());
// Check that Doxygen trailing comment comes after the declaration, starts
@@ -220,7 +230,7 @@ RawComment *ASTContext::getRawCommentForDeclNoCache(const Decl *D) const {
// There should be no other declarations or preprocessor directives between
// comment and declaration.
- if (Text.find_first_of(",;{}#@") != StringRef::npos)
+ if (Text.find_first_of(";{}#@") != StringRef::npos)
return NULL;
return *Comment;
@@ -406,9 +416,16 @@ comments::FullComment *ASTContext::cloneFullComment(comments::FullComment *FC,
}
+comments::FullComment *ASTContext::getLocalCommentForDeclUncached(const Decl *D) const {
+ const RawComment *RC = getRawCommentForDeclNoCache(D);
+ return RC ? RC->parse(*this, 0, D) : 0;
+}
+
comments::FullComment *ASTContext::getCommentForDecl(
const Decl *D,
const Preprocessor *PP) const {
+ if (D->isInvalidDecl())
+ return NULL;
D = adjustDeclToTemplate(D);
const Decl *Canonical = D->getCanonicalDecl();
@@ -679,6 +696,19 @@ static const LangAS::Map *getAddressSpaceMap(const TargetInfo &T,
}
}
+static bool isAddrSpaceMapManglingEnabled(const TargetInfo &TI,
+ const LangOptions &LangOpts) {
+ switch (LangOpts.getAddressSpaceMapMangling()) {
+ case LangOptions::ASMM_Target:
+ return TI.useAddressSpaceMapMangling();
+ case LangOptions::ASMM_On:
+ return true;
+ case LangOptions::ASMM_Off:
+ return false;
+ }
+ llvm_unreachable("getAddressSpaceMapMangling() doesn't cover anything.");
+}
+
ASTContext::ASTContext(LangOptions& LOpts, SourceManager &SM,
const TargetInfo *t,
IdentifierTable &idents, SelectorTable &sels,
@@ -690,7 +720,7 @@ ASTContext::ASTContext(LangOptions& LOpts, SourceManager &SM,
DependentTemplateSpecializationTypes(this_()),
SubstTemplateTemplateParmPacks(this_()),
GlobalNestedNameSpecifier(0),
- Int128Decl(0), UInt128Decl(0),
+ Int128Decl(0), UInt128Decl(0), Float128StubDecl(0),
BuiltinVaListDecl(0),
ObjCIdDecl(0), ObjCSelDecl(0), ObjCClassDecl(0), ObjCProtocolClassDecl(0),
BOOLDecl(0),
@@ -709,8 +739,7 @@ ASTContext::ASTContext(LangOptions& LOpts, SourceManager &SM,
ExternalSource(0), Listener(0),
Comments(SM), CommentsLoaded(false),
CommentCommandTraits(BumpAlloc, LOpts.CommentOpts),
- LastSDM(0, 0),
- UniqueBlockByRefTypeID(0)
+ LastSDM(0, 0)
{
if (size_reserve > 0) Types.reserve(size_reserve);
TUDecl = TranslationUnitDecl::Create(*this);
@@ -726,10 +755,12 @@ ASTContext::~ASTContext() {
// FIXME: Is this the ideal solution?
ReleaseDeclContextMaps();
- // Call all of the deallocation functions.
- for (unsigned I = 0, N = Deallocations.size(); I != N; ++I)
- Deallocations[I].first(Deallocations[I].second);
-
+ // Call all of the deallocation functions on all of their targets.
+ for (DeallocationMap::const_iterator I = Deallocations.begin(),
+ E = Deallocations.end(); I != E; ++I)
+ for (unsigned J = 0, N = I->second.size(); J != N; ++J)
+ (I->first)((I->second)[J]);
+
// ASTRecordLayout objects in ASTRecordLayouts must always be destroyed
// because they can contain DenseMaps.
for (llvm::DenseMap<const ObjCContainerDecl*,
@@ -750,10 +781,16 @@ ASTContext::~ASTContext() {
AEnd = DeclAttrs.end();
A != AEnd; ++A)
A->second->~AttrVec();
+
+ for (llvm::DenseMap<const DeclContext *, MangleNumberingContext *>::iterator
+ I = MangleNumberingContexts.begin(),
+ E = MangleNumberingContexts.end();
+ I != E; ++I)
+ delete I->second;
}
void ASTContext::AddDeallocation(void (*Callback)(void*), void *Data) {
- Deallocations.push_back(std::make_pair(Callback, Data));
+ Deallocations[Callback].push_back(Data);
}
void
@@ -848,6 +885,20 @@ TypedefDecl *ASTContext::getUInt128Decl() const {
return UInt128Decl;
}
+TypeDecl *ASTContext::getFloat128StubType() const {
+ assert(LangOpts.CPlusPlus && "should only be called for c++");
+ if (!Float128StubDecl) {
+ Float128StubDecl = CXXRecordDecl::Create(const_cast<ASTContext &>(*this),
+ TTK_Struct,
+ getTranslationUnitDecl(),
+ SourceLocation(),
+ SourceLocation(),
+ &Idents.get("__float128"));
+ }
+
+ return Float128StubDecl;
+}
+
void ASTContext::InitBuiltinType(CanQualType &R, BuiltinType::Kind K) {
BuiltinType *Ty = new (*this, TypeAlignment) BuiltinType(K);
R = CanQualType::CreateUnsafe(QualType(Ty, 0));
@@ -863,6 +914,7 @@ void ASTContext::InitBuiltinTypes(const TargetInfo &Target) {
ABI.reset(createCXXABI(Target));
AddrSpaceMap = getAddressSpaceMap(Target, LangOpts);
+ AddrSpaceMapMangling = isAddrSpaceMapManglingEnabled(Target, LangOpts);
// C99 6.2.5p19.
InitBuiltinType(VoidTy, BuiltinType::Void);
@@ -897,13 +949,17 @@ void ASTContext::InitBuiltinTypes(const TargetInfo &Target) {
InitBuiltinType(Int128Ty, BuiltinType::Int128);
InitBuiltinType(UnsignedInt128Ty, BuiltinType::UInt128);
- if (LangOpts.CPlusPlus && LangOpts.WChar) { // C++ 3.9.1p5
- if (TargetInfo::isTypeSigned(Target.getWCharType()))
- InitBuiltinType(WCharTy, BuiltinType::WChar_S);
- else // -fshort-wchar makes wchar_t be unsigned.
- InitBuiltinType(WCharTy, BuiltinType::WChar_U);
- } else // C99 (or C++ using -fno-wchar)
- WCharTy = getFromTargetType(Target.getWCharType());
+ // C++ 3.9.1p5
+ if (TargetInfo::isTypeSigned(Target.getWCharType()))
+ InitBuiltinType(WCharTy, BuiltinType::WChar_S);
+ else // -fshort-wchar makes wchar_t be unsigned.
+ InitBuiltinType(WCharTy, BuiltinType::WChar_U);
+ if (LangOpts.CPlusPlus && LangOpts.WChar)
+ WideCharTy = WCharTy;
+ else {
+ // C99 (or C++ using -fno-wchar).
+ WideCharTy = getFromTargetType(Target.getWCharType());
+ }
WIntTy = getFromTargetType(Target.getWIntType());
@@ -1008,13 +1064,20 @@ void ASTContext::eraseDeclAttrs(const Decl *D) {
}
}
+// FIXME: Remove ?
MemberSpecializationInfo *
ASTContext::getInstantiatedFromStaticDataMember(const VarDecl *Var) {
assert(Var->isStaticDataMember() && "Not a static data member");
- llvm::DenseMap<const VarDecl *, MemberSpecializationInfo *>::iterator Pos
- = InstantiatedFromStaticDataMember.find(Var);
- if (Pos == InstantiatedFromStaticDataMember.end())
- return 0;
+ return getTemplateOrSpecializationInfo(Var)
+ .dyn_cast<MemberSpecializationInfo *>();
+}
+
+ASTContext::TemplateOrSpecializationInfo
+ASTContext::getTemplateOrSpecializationInfo(const VarDecl *Var) {
+ llvm::DenseMap<const VarDecl *, TemplateOrSpecializationInfo>::iterator Pos =
+ TemplateOrInstantiation.find(Var);
+ if (Pos == TemplateOrInstantiation.end())
+ return TemplateOrSpecializationInfo();
return Pos->second;
}
@@ -1025,10 +1088,16 @@ ASTContext::setInstantiatedFromStaticDataMember(VarDecl *Inst, VarDecl *Tmpl,
SourceLocation PointOfInstantiation) {
assert(Inst->isStaticDataMember() && "Not a static data member");
assert(Tmpl->isStaticDataMember() && "Not a static data member");
- assert(!InstantiatedFromStaticDataMember[Inst] &&
- "Already noted what static data member was instantiated from");
- InstantiatedFromStaticDataMember[Inst]
- = new (*this) MemberSpecializationInfo(Tmpl, TSK, PointOfInstantiation);
+ setTemplateOrSpecializationInfo(Inst, new (*this) MemberSpecializationInfo(
+ Tmpl, TSK, PointOfInstantiation));
+}
+
+void
+ASTContext::setTemplateOrSpecializationInfo(VarDecl *Inst,
+ TemplateOrSpecializationInfo TSI) {
+ assert(!TemplateOrInstantiation[Inst] &&
+ "Already noted what the variable was instantiated from");
+ TemplateOrInstantiation[Inst] = TSI;
}
FunctionDecl *ASTContext::getClassScopeSpecializationPattern(
@@ -1105,38 +1174,6 @@ void ASTContext::setInstantiatedFromUnnamedFieldDecl(FieldDecl *Inst,
InstantiatedFromUnnamedFieldDecl[Inst] = Tmpl;
}
-bool ASTContext::ZeroBitfieldFollowsNonBitfield(const FieldDecl *FD,
- const FieldDecl *LastFD) const {
- return (FD->isBitField() && LastFD && !LastFD->isBitField() &&
- FD->getBitWidthValue(*this) == 0);
-}
-
-bool ASTContext::ZeroBitfieldFollowsBitfield(const FieldDecl *FD,
- const FieldDecl *LastFD) const {
- return (FD->isBitField() && LastFD && LastFD->isBitField() &&
- FD->getBitWidthValue(*this) == 0 &&
- LastFD->getBitWidthValue(*this) != 0);
-}
-
-bool ASTContext::BitfieldFollowsBitfield(const FieldDecl *FD,
- const FieldDecl *LastFD) const {
- return (FD->isBitField() && LastFD && LastFD->isBitField() &&
- FD->getBitWidthValue(*this) &&
- LastFD->getBitWidthValue(*this));
-}
-
-bool ASTContext::NonBitfieldFollowsBitfield(const FieldDecl *FD,
- const FieldDecl *LastFD) const {
- return (!FD->isBitField() && LastFD && LastFD->isBitField() &&
- LastFD->getBitWidthValue(*this));
-}
-
-bool ASTContext::BitfieldFollowsNonBitfield(const FieldDecl *FD,
- const FieldDecl *LastFD) const {
- return (FD->isBitField() && LastFD && !LastFD->isBitField() &&
- FD->getBitWidthValue(*this));
-}
-
ASTContext::overridden_cxx_method_iterator
ASTContext::overridden_methods_begin(const CXXMethodDecl *Method) const {
llvm::DenseMap<const CXXMethodDecl *, CXXMethodVector>::const_iterator Pos
@@ -1224,12 +1261,7 @@ const llvm::fltSemantics &ASTContext::getFloatTypeSemantics(QualType T) const {
}
}
-/// getDeclAlign - Return a conservative estimate of the alignment of the
-/// specified decl. Note that bitfields do not have a valid alignment, so
-/// this method will assert on them.
-/// If @p RefAsPointee, references are treated like their underlying type
-/// (for alignof), else they're treated like pointers (for CodeGen).
-CharUnits ASTContext::getDeclAlign(const Decl *D, bool RefAsPointee) const {
+CharUnits ASTContext::getDeclAlign(const Decl *D, bool ForAlignof) const {
unsigned Align = Target->getCharWidth();
bool UseAlignAttrOnly = false;
@@ -1262,7 +1294,7 @@ CharUnits ASTContext::getDeclAlign(const Decl *D, bool RefAsPointee) const {
} else if (const ValueDecl *VD = dyn_cast<ValueDecl>(D)) {
QualType T = VD->getType();
if (const ReferenceType* RT = T->getAs<ReferenceType>()) {
- if (RefAsPointee)
+ if (ForAlignof)
T = RT->getPointeeType();
else
T = getPointerType(RT->getPointeeType());
@@ -1270,14 +1302,15 @@ CharUnits ASTContext::getDeclAlign(const Decl *D, bool RefAsPointee) const {
if (!T->isIncompleteType() && !T->isFunctionType()) {
// Adjust alignments of declarations with array type by the
// large-array alignment on the target.
- unsigned MinWidth = Target->getLargeArrayMinWidth();
- const ArrayType *arrayType;
- if (MinWidth && (arrayType = getAsArrayType(T))) {
- if (isa<VariableArrayType>(arrayType))
- Align = std::max(Align, Target->getLargeArrayAlign());
- else if (isa<ConstantArrayType>(arrayType) &&
- MinWidth <= getTypeSize(cast<ConstantArrayType>(arrayType)))
- Align = std::max(Align, Target->getLargeArrayAlign());
+ if (const ArrayType *arrayType = getAsArrayType(T)) {
+ unsigned MinWidth = Target->getLargeArrayMinWidth();
+ if (!ForAlignof && MinWidth) {
+ if (isa<VariableArrayType>(arrayType))
+ Align = std::max(Align, Target->getLargeArrayAlign());
+ else if (isa<ConstantArrayType>(arrayType) &&
+ MinWidth <= getTypeSize(cast<ConstantArrayType>(arrayType)))
+ Align = std::max(Align, Target->getLargeArrayAlign());
+ }
// Walk through any array types while we're at it.
T = getBaseElementType(arrayType);
@@ -1294,24 +1327,27 @@ CharUnits ASTContext::getDeclAlign(const Decl *D, bool RefAsPointee) const {
// a max-field-alignment constraint (#pragma pack). So calculate
// the actual alignment of the field within the struct, and then
// (as we're expected to) constrain that by the alignment of the type.
- if (const FieldDecl *field = dyn_cast<FieldDecl>(VD)) {
- // So calculate the alignment of the field.
- const ASTRecordLayout &layout = getASTRecordLayout(field->getParent());
-
- // Start with the record's overall alignment.
- unsigned fieldAlign = toBits(layout.getAlignment());
-
- // Use the GCD of that and the offset within the record.
- uint64_t offset = layout.getFieldOffset(field->getFieldIndex());
- if (offset > 0) {
- // Alignment is always a power of 2, so the GCD will be a power of 2,
- // which means we get to do this crazy thing instead of Euclid's.
- uint64_t lowBitOfOffset = offset & (~offset + 1);
- if (lowBitOfOffset < fieldAlign)
- fieldAlign = static_cast<unsigned>(lowBitOfOffset);
- }
+ if (const FieldDecl *Field = dyn_cast<FieldDecl>(VD)) {
+ const RecordDecl *Parent = Field->getParent();
+ // We can only produce a sensible answer if the record is valid.
+ if (!Parent->isInvalidDecl()) {
+ const ASTRecordLayout &Layout = getASTRecordLayout(Parent);
+
+ // Start with the record's overall alignment.
+ unsigned FieldAlign = toBits(Layout.getAlignment());
+
+ // Use the GCD of that and the offset within the record.
+ uint64_t Offset = Layout.getFieldOffset(Field->getFieldIndex());
+ if (Offset > 0) {
+ // Alignment is always a power of 2, so the GCD will be a power of 2,
+ // which means we get to do this crazy thing instead of Euclid's.
+ uint64_t LowBitOfOffset = Offset & (~Offset + 1);
+ if (LowBitOfOffset < FieldAlign)
+ FieldAlign = static_cast<unsigned>(LowBitOfOffset);
+ }
- Align = std::min(Align, fieldAlign);
+ Align = std::min(Align, FieldAlign);
+ }
}
}
@@ -1339,8 +1375,30 @@ ASTContext::getTypeInfoDataSizeInChars(QualType T) const {
return sizeAndAlign;
}
+/// getConstantArrayInfoInChars - Performing the computation in CharUnits
+/// instead of in bits prevents overflowing the uint64_t for some large arrays.
+std::pair<CharUnits, CharUnits>
+static getConstantArrayInfoInChars(const ASTContext &Context,
+ const ConstantArrayType *CAT) {
+ std::pair<CharUnits, CharUnits> EltInfo =
+ Context.getTypeInfoInChars(CAT->getElementType());
+ uint64_t Size = CAT->getSize().getZExtValue();
+ assert((Size == 0 || static_cast<uint64_t>(EltInfo.first.getQuantity()) <=
+ (uint64_t)(-1)/Size) &&
+ "Overflow in array type char size evaluation");
+ uint64_t Width = EltInfo.first.getQuantity() * Size;
+ unsigned Align = EltInfo.second.getQuantity();
+ if (!Context.getTargetInfo().getCXXABI().isMicrosoft() ||
+ Context.getTargetInfo().getPointerWidth(0) == 64)
+ Width = llvm::RoundUpToAlignment(Width, Align);
+ return std::make_pair(CharUnits::fromQuantity(Width),
+ CharUnits::fromQuantity(Align));
+}
+
std::pair<CharUnits, CharUnits>
ASTContext::getTypeInfoInChars(const Type *T) const {
+ if (const ConstantArrayType *CAT = dyn_cast<ConstantArrayType>(T))
+ return getConstantArrayInfoInChars(*this, CAT);
std::pair<uint64_t, unsigned> Info = getTypeInfo(T);
return std::make_pair(toCharUnitsFromBits(Info.first),
toCharUnitsFromBits(Info.second));
@@ -1376,6 +1434,10 @@ ASTContext::getTypeInfoImpl(const Type *T) const {
#define ABSTRACT_TYPE(Class, Base)
#define NON_CANONICAL_TYPE(Class, Base)
#define DEPENDENT_TYPE(Class, Base) case Type::Class:
+#define NON_CANONICAL_UNLESS_DEPENDENT_TYPE(Class, Base) \
+ case Type::Class: \
+ assert(!T->isDependentType() && "should not see dependent types here"); \
+ return getTypeInfo(cast<Class##Type>(T)->desugar().getTypePtr());
#include "clang/AST/TypeNodes.def"
llvm_unreachable("Should not see dependent types");
@@ -1401,7 +1463,9 @@ ASTContext::getTypeInfoImpl(const Type *T) const {
"Overflow in array type bit size evaluation");
Width = EltInfo.first*Size;
Align = EltInfo.second;
- Width = llvm::RoundUpToAlignment(Width, Align);
+ if (!getTargetInfo().getCXXABI().isMicrosoft() ||
+ getTargetInfo().getPointerWidth(0) == 64)
+ Width = llvm::RoundUpToAlignment(Width, Align);
break;
}
case Type::ExtVector:
@@ -1568,6 +1632,8 @@ ASTContext::getTypeInfoImpl(const Type *T) const {
}
case Type::ObjCObject:
return getTypeInfo(cast<ObjCObjectType>(T)->getBaseType().getTypePtr());
+ case Type::Decayed:
+ return getTypeInfo(cast<DecayedType>(T)->getDecayedType().getTypePtr());
case Type::ObjCInterface: {
const ObjCInterfaceType *ObjCI = cast<ObjCInterfaceType>(T);
const ASTRecordLayout &Layout = getASTObjCInterfaceLayout(ObjCI->getDecl());
@@ -1624,20 +1690,6 @@ ASTContext::getTypeInfoImpl(const Type *T) const {
break;
}
- case Type::TypeOfExpr:
- return getTypeInfo(cast<TypeOfExprType>(T)->getUnderlyingExpr()->getType()
- .getTypePtr());
-
- case Type::TypeOf:
- return getTypeInfo(cast<TypeOfType>(T)->getUnderlyingType().getTypePtr());
-
- case Type::Decltype:
- return getTypeInfo(cast<DecltypeType>(T)->getUnderlyingExpr()->getType()
- .getTypePtr());
-
- case Type::UnaryTransform:
- return getTypeInfo(cast<UnaryTransformType>(T)->getUnderlyingType());
-
case Type::Elaborated:
return getTypeInfo(cast<ElaboratedType>(T)->getNamedType().getTypePtr());
@@ -1645,18 +1697,6 @@ ASTContext::getTypeInfoImpl(const Type *T) const {
return getTypeInfo(
cast<AttributedType>(T)->getEquivalentType().getTypePtr());
- case Type::TemplateSpecialization: {
- assert(getCanonicalType(T) != T &&
- "Cannot request the size of a dependent type");
- const TemplateSpecializationType *TST = cast<TemplateSpecializationType>(T);
- // A type alias template specialization may refer to a typedef with the
- // aligned attribute on it.
- if (TST->isTypeAlias())
- return getTypeInfo(TST->getAliasedType().getTypePtr());
- else
- return getTypeInfo(getCanonicalType(T));
- }
-
case Type::Atomic: {
// Start with the base type information.
std::pair<uint64_t, unsigned> Info
@@ -1696,10 +1736,10 @@ int64_t ASTContext::toBits(CharUnits CharSize) const {
/// getTypeSizeInChars - Return the size of the specified type, in characters.
/// This method does not work on incomplete types.
CharUnits ASTContext::getTypeSizeInChars(QualType T) const {
- return toCharUnitsFromBits(getTypeSize(T));
+ return getTypeInfoInChars(T).first;
}
CharUnits ASTContext::getTypeSizeInChars(const Type *T) const {
- return toCharUnitsFromBits(getTypeSize(T));
+ return getTypeInfoInChars(T).first;
}
/// getTypeAlignInChars - Return the ABI-specified alignment of a type, in
@@ -1718,6 +1758,9 @@ CharUnits ASTContext::getTypeAlignInChars(const Type *T) const {
unsigned ASTContext::getPreferredTypeAlign(const Type *T) const {
unsigned ABIAlign = getTypeAlign(T);
+ if (Target->getTriple().getArch() == llvm::Triple::xcore)
+ return ABIAlign; // Never overalign on XCore.
+
// Double and long long should be naturally aligned if possible.
if (const ComplexType* CT = T->getAs<ComplexType>())
T = CT->getElementType().getTypePtr();
@@ -2042,10 +2085,7 @@ const FunctionType *ASTContext::adjustFunctionType(const FunctionType *T,
const FunctionProtoType *FPT = cast<FunctionProtoType>(T);
FunctionProtoType::ExtProtoInfo EPI = FPT->getExtProtoInfo();
EPI.ExtInfo = Info;
- Result = getFunctionType(FPT->getResultType(),
- ArrayRef<QualType>(FPT->arg_type_begin(),
- FPT->getNumArgs()),
- EPI);
+ Result = getFunctionType(FPT->getResultType(), FPT->getArgTypes(), EPI);
}
return cast<FunctionType>(Result.getTypePtr());
@@ -2053,12 +2093,18 @@ const FunctionType *ASTContext::adjustFunctionType(const FunctionType *T,
void ASTContext::adjustDeducedFunctionResultType(FunctionDecl *FD,
QualType ResultType) {
- // FIXME: Need to inform serialization code about this!
- for (FD = FD->getMostRecentDecl(); FD; FD = FD->getPreviousDecl()) {
+ FD = FD->getMostRecentDecl();
+ while (true) {
const FunctionProtoType *FPT = FD->getType()->castAs<FunctionProtoType>();
FunctionProtoType::ExtProtoInfo EPI = FPT->getExtProtoInfo();
FD->setType(getFunctionType(ResultType, FPT->getArgTypes(), EPI));
+ if (FunctionDecl *Next = FD->getPreviousDecl())
+ FD = Next;
+ else
+ break;
}
+ if (ASTMutationListener *L = getASTMutationListener())
+ L->DeducedReturnType(FD, ResultType);
}
/// getComplexType - Return the uniqued reference to the type for a complex
@@ -2117,6 +2163,45 @@ QualType ASTContext::getPointerType(QualType T) const {
return QualType(New, 0);
}
+QualType ASTContext::getDecayedType(QualType T) const {
+ assert((T->isArrayType() || T->isFunctionType()) && "T does not decay");
+
+ llvm::FoldingSetNodeID ID;
+ DecayedType::Profile(ID, T);
+ void *InsertPos = 0;
+ if (DecayedType *DT = DecayedTypes.FindNodeOrInsertPos(ID, InsertPos))
+ return QualType(DT, 0);
+
+ QualType Decayed;
+
+ // C99 6.7.5.3p7:
+ // A declaration of a parameter as "array of type" shall be
+ // adjusted to "qualified pointer to type", where the type
+ // qualifiers (if any) are those specified within the [ and ] of
+ // the array type derivation.
+ if (T->isArrayType())
+ Decayed = getArrayDecayedType(T);
+
+ // C99 6.7.5.3p8:
+ // A declaration of a parameter as "function returning type"
+ // shall be adjusted to "pointer to function returning type", as
+ // in 6.3.2.1.
+ if (T->isFunctionType())
+ Decayed = getPointerType(T);
+
+ QualType Canonical = getCanonicalType(Decayed);
+
+ // Get the new insert position for the node we care about.
+ DecayedType *NewIP = DecayedTypes.FindNodeOrInsertPos(ID, InsertPos);
+ assert(NewIP == 0 && "Shouldn't be in the map!"); (void)NewIP;
+
+ DecayedType *New =
+ new (*this, TypeAlignment) DecayedType(T, Decayed, Canonical);
+ Types.push_back(New);
+ DecayedTypes.InsertNode(New, InsertPos);
+ return QualType(New, 0);
+}
+
/// getBlockPointerType - Return the uniqued reference to the type for
/// a pointer to the specified block.
QualType ASTContext::getBlockPointerType(QualType T) const {
@@ -2676,9 +2761,8 @@ ASTContext::getDependentSizedExtVectorType(QualType vecType,
QualType
ASTContext::getFunctionNoProtoType(QualType ResultTy,
const FunctionType::ExtInfo &Info) const {
- const CallingConv DefaultCC = Info.getCC();
- const CallingConv CallConv = (LangOpts.MRTD && DefaultCC == CC_Default) ?
- CC_X86StdCall : DefaultCC;
+ const CallingConv CallConv = Info.getCC();
+
// Unique functions, to guarantee there is only one function of a particular
// structure.
llvm::FoldingSetNodeID ID;
@@ -2690,11 +2774,8 @@ ASTContext::getFunctionNoProtoType(QualType ResultTy,
return QualType(FT, 0);
QualType Canonical;
- if (!ResultTy.isCanonical() ||
- getCanonicalCallConv(CallConv) != CallConv) {
- Canonical =
- getFunctionNoProtoType(getCanonicalType(ResultTy),
- Info.withCallingConv(getCanonicalCallConv(CallConv)));
+ if (!ResultTy.isCanonical()) {
+ Canonical = getFunctionNoProtoType(getCanonicalType(ResultTy), Info);
// Get the new insert position for the node we care about.
FunctionNoProtoType *NewIP =
@@ -2743,14 +2824,10 @@ ASTContext::getFunctionType(QualType ResultTy, ArrayRef<QualType> ArgArray,
if (!ArgArray[i].isCanonicalAsParam())
isCanonical = false;
- const CallingConv DefaultCC = EPI.ExtInfo.getCC();
- const CallingConv CallConv = (LangOpts.MRTD && DefaultCC == CC_Default) ?
- CC_X86StdCall : DefaultCC;
-
// If this type isn't canonical, get the canonical version of it.
// The exception spec is not part of the canonical type.
QualType Canonical;
- if (!isCanonical || getCanonicalCallConv(CallConv) != CallConv) {
+ if (!isCanonical) {
SmallVector<QualType, 16> CanonicalArgs;
CanonicalArgs.reserve(NumArgs);
for (unsigned i = 0; i != NumArgs; ++i)
@@ -2760,8 +2837,6 @@ ASTContext::getFunctionType(QualType ResultTy, ArrayRef<QualType> ArgArray,
CanonicalEPI.HasTrailingReturn = false;
CanonicalEPI.ExceptionSpecType = EST_None;
CanonicalEPI.NumExceptions = 0;
- CanonicalEPI.ExtInfo
- = CanonicalEPI.ExtInfo.withCallingConv(getCanonicalCallConv(CallConv));
// Result types do not have ARC lifetime qualifiers.
QualType CanResultTy = getCanonicalType(ResultTy);
@@ -2803,7 +2878,6 @@ ASTContext::getFunctionType(QualType ResultTy, ArrayRef<QualType> ArgArray,
FunctionProtoType *FTP = (FunctionProtoType*) Allocate(Size, TypeAlignment);
FunctionProtoType::ExtProtoInfo newEPI = EPI;
- newEPI.ExtInfo = EPI.ExtInfo.withCallingConv(CallConv);
new (FTP) FunctionProtoType(ResultTy, ArgArray, Canonical, newEPI);
Types.push_back(FTP);
FunctionProtoTypes.InsertNode(FTP, InsertPos);
@@ -2856,13 +2930,11 @@ QualType ASTContext::getTypeDeclTypeSlow(const TypeDecl *Decl) const {
"Template type parameter types are always available.");
if (const RecordDecl *Record = dyn_cast<RecordDecl>(Decl)) {
- assert(!Record->getPreviousDecl() &&
- "struct/union has previous declaration");
+ assert(Record->isFirstDecl() && "struct/union has previous declaration");
assert(!NeedsInjectedClassNameType(Record));
return getRecordType(Record);
} else if (const EnumDecl *Enum = dyn_cast<EnumDecl>(Decl)) {
- assert(!Enum->getPreviousDecl() &&
- "enum has previous declaration");
+ assert(Enum->isFirstDecl() && "enum has previous declaration");
return getEnumType(Enum);
} else if (const UnresolvedUsingTypenameDecl *Using =
dyn_cast<UnresolvedUsingTypenameDecl>(Decl)) {
@@ -4104,22 +4176,9 @@ const ArrayType *ASTContext::getAsArrayType(QualType T) const {
}
QualType ASTContext::getAdjustedParameterType(QualType T) const {
- // C99 6.7.5.3p7:
- // A declaration of a parameter as "array of type" shall be
- // adjusted to "qualified pointer to type", where the type
- // qualifiers (if any) are those specified within the [ and ] of
- // the array type derivation.
- if (T->isArrayType())
- return getArrayDecayedType(T);
-
- // C99 6.7.5.3p8:
- // A declaration of a parameter as "function returning type"
- // shall be adjusted to "pointer to function returning type", as
- // in 6.3.2.1.
- if (T->isFunctionType())
- return getPointerType(T);
-
- return T;
+ if (T->isArrayType() || T->isFunctionType())
+ return getDecayedType(T);
+ return T;
}
QualType ASTContext::getSignatureParameterType(QualType T) const {
@@ -4364,12 +4423,27 @@ Qualifiers::ObjCLifetime ASTContext::getInnerObjCOwnership(QualType T) const {
return Qualifiers::OCL_None;
}
+static const Type *getIntegerTypeForEnum(const EnumType *ET) {
+ // Incomplete enum types are not treated as integer types.
+ // FIXME: In C++, enum types are never integer types.
+ if (ET->getDecl()->isComplete() && !ET->getDecl()->isScoped())
+ return ET->getDecl()->getIntegerType().getTypePtr();
+ return NULL;
+}
+
/// getIntegerTypeOrder - Returns the highest ranked integer type:
/// C99 6.3.1.8p1. If LHS > RHS, return 1. If LHS == RHS, return 0. If
/// LHS < RHS, return -1.
int ASTContext::getIntegerTypeOrder(QualType LHS, QualType RHS) const {
const Type *LHSC = getCanonicalType(LHS).getTypePtr();
const Type *RHSC = getCanonicalType(RHS).getTypePtr();
+
+ // Unwrap enums to their underlying type.
+ if (const EnumType *ET = dyn_cast<EnumType>(LHSC))
+ LHSC = getIntegerTypeForEnum(ET);
+ if (const EnumType *ET = dyn_cast<EnumType>(RHSC))
+ RHSC = getIntegerTypeForEnum(ET);
+
if (LHSC == RHSC) return 0;
bool LHSUnsigned = LHSC->isUnsignedIntegerType();
@@ -4484,7 +4558,7 @@ QualType ASTContext::getBlockDescriptorType() const {
UnsignedLongTy,
};
- const char *FieldNames[] = {
+ static const char *const FieldNames[] = {
"reserved",
"Size"
};
@@ -4525,7 +4599,7 @@ QualType ASTContext::getBlockDescriptorExtendedType() const {
getPointerType(VoidPtrTy)
};
- const char *FieldNames[] = {
+ static const char *const FieldNames[] = {
"reserved",
"Size",
"CopyFuncPtr",
@@ -4910,6 +4984,10 @@ void ASTContext::getObjCEncodingForPropertyDecl(const ObjCPropertyDecl *PD,
if (PD->isReadOnly()) {
S += ",R";
+ if (PD->getPropertyAttributes() & ObjCPropertyDecl::OBJC_PR_copy)
+ S += ",C";
+ if (PD->getPropertyAttributes() & ObjCPropertyDecl::OBJC_PR_retain)
+ S += ",&";
} else {
switch (PD->getSetterKind()) {
case ObjCPropertyDecl::Assign: break;
@@ -5200,12 +5278,9 @@ void ASTContext::getObjCEncodingForTypeImpl(QualType T, std::string& S,
} else {
S += '[';
- if (const ConstantArrayType *CAT = dyn_cast<ConstantArrayType>(AT)) {
- if (getTypeSize(CAT->getElementType()) == 0)
- S += '0';
- else
- S += llvm::utostr(CAT->getSize().getZExtValue());
- } else {
+ if (const ConstantArrayType *CAT = dyn_cast<ConstantArrayType>(AT))
+ S += llvm::utostr(CAT->getSize().getZExtValue());
+ else {
//Variable length arrays are encoded as a regular array with 0 elements.
assert((isa<VariableArrayType>(AT) || isa<IncompleteArrayType>(AT)) &&
"Unknown array type!");
@@ -5384,6 +5459,20 @@ void ASTContext::getObjCEncodingForTypeImpl(QualType T, std::string& S,
// We encode the underlying type which comes out as
// {...};
S += '^';
+ if (FD && OPT->getInterfaceDecl()) {
+ // Prevent recursive encoding of fields in some rare cases.
+ ObjCInterfaceDecl *OI = OPT->getInterfaceDecl();
+ SmallVector<const ObjCIvarDecl*, 32> Ivars;
+ DeepCollectObjCIvars(OI, true, Ivars);
+ for (unsigned i = 0, e = Ivars.size(); i != e; ++i) {
+ if (cast<FieldDecl>(Ivars[i]) == FD) {
+ S += '{';
+ S += OI->getIdentifier()->getName();
+ S += '}';
+ return;
+ }
+ }
+ }
getObjCEncodingForTypeImpl(PointeeTy, S,
false, ExpandPointedToStructures,
NULL,
@@ -5484,7 +5573,8 @@ void ASTContext::getObjCEncodingForStructureImpl(RecordDecl *RDecl,
if (base->isEmpty())
continue;
uint64_t offs = toBits(layout.getVBaseClassOffset(base));
- if (FieldOrBaseOffsets.find(offs) == FieldOrBaseOffsets.end())
+ if (offs >= uint64_t(toBits(layout.getNonVirtualSize())) &&
+ FieldOrBaseOffsets.find(offs) == FieldOrBaseOffsets.end())
FieldOrBaseOffsets.insert(FieldOrBaseOffsets.end(),
std::make_pair(offs, base));
}
@@ -6267,6 +6357,8 @@ ASTContext::getSubstTemplateTemplateParmPack(TemplateTemplateParmDecl *Param,
CanQualType ASTContext::getFromTargetType(unsigned Type) const {
switch (Type) {
case TargetInfo::NoInt: return CanQualType();
+ case TargetInfo::SignedChar: return SignedCharTy;
+ case TargetInfo::UnsignedChar: return UnsignedCharTy;
case TargetInfo::SignedShort: return ShortTy;
case TargetInfo::UnsignedShort: return UnsignedShortTy;
case TargetInfo::SignedInt: return IntTy;
@@ -6369,15 +6461,6 @@ ASTContext::ProtocolCompatibleWithProtocol(ObjCProtocolDecl *lProto,
return false;
}
-/// QualifiedIdConformsQualifiedId - compare id<pr,...> with id<pr1,...>
-/// return true if lhs's protocols conform to rhs's protocol; false
-/// otherwise.
-bool ASTContext::QualifiedIdConformsQualifiedId(QualType lhs, QualType rhs) {
- if (lhs->isObjCQualifiedIdType() && rhs->isObjCQualifiedIdType())
- return ObjCQualifiedIdTypesAreCompatible(lhs, rhs, false);
- return false;
-}
-
/// ObjCQualifiedClassTypesAreCompatible - compare Class<pr,...> and
/// Class<pr1, ...>.
bool ASTContext::ObjCQualifiedClassTypesAreCompatible(QualType lhs,
@@ -6890,7 +6973,7 @@ QualType ASTContext::mergeFunctionTypes(QualType lhs, QualType rhs,
FunctionType::ExtInfo rbaseInfo = rbase->getExtInfo();
// Compatible functions must have compatible calling conventions
- if (!isSameCallConv(lbaseInfo.getCC(), rbaseInfo.getCC()))
+ if (lbaseInfo.getCC() != rbaseInfo.getCC())
return QualType();
// Regparm is part of the calling convention.
@@ -7000,10 +7083,7 @@ QualType ASTContext::mergeFunctionTypes(QualType lhs, QualType rhs,
FunctionProtoType::ExtProtoInfo EPI = proto->getExtProtoInfo();
EPI.ExtInfo = einfo;
- return getFunctionType(retType,
- ArrayRef<QualType>(proto->arg_type_begin(),
- proto->getNumArgs()),
- EPI);
+ return getFunctionType(retType, proto->getArgTypes(), EPI);
}
if (allLTypes) return lhs;
@@ -7351,11 +7431,8 @@ QualType ASTContext::mergeObjCGCQualifiers(QualType LHS, QualType RHS) {
if (const FunctionProtoType *FPT = cast<FunctionProtoType>(F)) {
FunctionProtoType::ExtProtoInfo EPI = FPT->getExtProtoInfo();
EPI.ExtInfo = getFunctionExtInfo(LHS);
- QualType ResultType
- = getFunctionType(OldReturnType,
- ArrayRef<QualType>(FPT->arg_type_begin(),
- FPT->getNumArgs()),
- EPI);
+ QualType ResultType =
+ getFunctionType(OldReturnType, FPT->getArgTypes(), EPI);
return ResultType;
}
}
@@ -7407,7 +7484,7 @@ QualType ASTContext::mergeObjCGCQualifiers(QualType LHS, QualType RHS) {
//===----------------------------------------------------------------------===//
unsigned ASTContext::getIntWidth(QualType T) const {
- if (const EnumType *ET = dyn_cast<EnumType>(T))
+ if (const EnumType *ET = T->getAs<EnumType>())
T = ET->getDecl()->getIntegerType();
if (T->isBooleanType())
return 1;
@@ -7450,6 +7527,8 @@ QualType ASTContext::getCorrespondingUnsignedType(QualType T) const {
ASTMutationListener::~ASTMutationListener() { }
+void ASTMutationListener::DeducedReturnType(const FunctionDecl *FD,
+ QualType ReturnType) {}
//===----------------------------------------------------------------------===//
// Builtin Type Computation
@@ -7507,6 +7586,11 @@ static QualType DecodeTypeFromStr(const char *&Str, const ASTContext &Context,
"Bad modifiers used with 'v'!");
Type = Context.VoidTy;
break;
+ case 'h':
+ assert(HowLong == 0 && !Signed && !Unsigned &&
+ "Bad modifiers used with 'f'!");
+ Type = Context.HalfTy;
+ break;
case 'f':
assert(HowLong == 0 && !Signed && !Unsigned &&
"Bad modifiers used with 'f'!");
@@ -7734,7 +7818,7 @@ QualType ASTContext::GetBuiltinType(unsigned Id,
assert((TypeStr[0] != '.' || TypeStr[1] == 0) &&
"'.' should only occur at end of builtin type list!");
- FunctionType::ExtInfo EI;
+ FunctionType::ExtInfo EI(CC_C);
if (BuiltinInfo.isNoReturn(Id)) EI = EI.withNoReturn(true);
bool Variadic = (TypeStr[0] == '.');
@@ -7751,36 +7835,30 @@ QualType ASTContext::GetBuiltinType(unsigned Id,
}
GVALinkage ASTContext::GetGVALinkageForFunction(const FunctionDecl *FD) {
- GVALinkage External = GVA_StrongExternal;
-
- Linkage L = FD->getLinkage();
- switch (L) {
- case NoLinkage:
- case InternalLinkage:
- case UniqueExternalLinkage:
+ if (!FD->isExternallyVisible())
return GVA_Internal;
-
- case ExternalLinkage:
- switch (FD->getTemplateSpecializationKind()) {
- case TSK_Undeclared:
- case TSK_ExplicitSpecialization:
- External = GVA_StrongExternal;
- break;
- case TSK_ExplicitInstantiationDefinition:
- return GVA_ExplicitTemplateInstantiation;
+ GVALinkage External = GVA_StrongExternal;
+ switch (FD->getTemplateSpecializationKind()) {
+ case TSK_Undeclared:
+ case TSK_ExplicitSpecialization:
+ External = GVA_StrongExternal;
+ break;
- case TSK_ExplicitInstantiationDeclaration:
- case TSK_ImplicitInstantiation:
- External = GVA_TemplateInstantiation;
- break;
- }
+ case TSK_ExplicitInstantiationDefinition:
+ return GVA_ExplicitTemplateInstantiation;
+
+ case TSK_ExplicitInstantiationDeclaration:
+ case TSK_ImplicitInstantiation:
+ External = GVA_TemplateInstantiation;
+ break;
}
if (!FD->isInlined())
return External;
-
- if (!getLangOpts().CPlusPlus || FD->hasAttr<GNUInlineAttr>()) {
+
+ if ((!getLangOpts().CPlusPlus && !getLangOpts().MicrosoftMode) ||
+ FD->hasAttr<GNUInlineAttr>()) {
// GNU or C99 inline semantics. Determine whether this symbol should be
// externally visible.
if (FD->isInlineDefinitionExternallyVisible())
@@ -7804,37 +7882,23 @@ GVALinkage ASTContext::GetGVALinkageForFunction(const FunctionDecl *FD) {
}
GVALinkage ASTContext::GetGVALinkageForVariable(const VarDecl *VD) {
- // If this is a static data member, compute the kind of template
- // specialization. Otherwise, this variable is not part of a
- // template.
- TemplateSpecializationKind TSK = TSK_Undeclared;
- if (VD->isStaticDataMember())
- TSK = VD->getTemplateSpecializationKind();
-
- Linkage L = VD->getLinkage();
-
- switch (L) {
- case NoLinkage:
- case InternalLinkage:
- case UniqueExternalLinkage:
+ if (!VD->isExternallyVisible())
return GVA_Internal;
- case ExternalLinkage:
- switch (TSK) {
- case TSK_Undeclared:
- case TSK_ExplicitSpecialization:
- return GVA_StrongExternal;
+ switch (VD->getTemplateSpecializationKind()) {
+ case TSK_Undeclared:
+ case TSK_ExplicitSpecialization:
+ return GVA_StrongExternal;
- case TSK_ExplicitInstantiationDeclaration:
- llvm_unreachable("Variable should not be instantiated");
- // Fall through to treat this like any other instantiation.
-
- case TSK_ExplicitInstantiationDefinition:
- return GVA_ExplicitTemplateInstantiation;
+ case TSK_ExplicitInstantiationDeclaration:
+ llvm_unreachable("Variable should not be instantiated");
+ // Fall through to treat this like any other instantiation.
- case TSK_ImplicitInstantiation:
- return GVA_TemplateInstantiation;
- }
+ case TSK_ExplicitInstantiationDefinition:
+ return GVA_ExplicitTemplateInstantiation;
+
+ case TSK_ImplicitInstantiation:
+ return GVA_TemplateInstantiation;
}
llvm_unreachable("Invalid Linkage!");
@@ -7918,16 +7982,13 @@ bool ASTContext::DeclMustBeEmitted(const Decl *D) {
return false;
}
-CallingConv ASTContext::getDefaultCXXMethodCallConv(bool isVariadic) {
+CallingConv ASTContext::getDefaultCallingConvention(bool IsVariadic,
+ bool IsCXXMethod) const {
// Pass through to the C++ ABI object
- return ABI->getDefaultMethodCallConv(isVariadic);
-}
+ if (IsCXXMethod)
+ return ABI->getDefaultMethodCallConv(IsVariadic);
-CallingConv ASTContext::getCanonicalCallConv(CallingConv CC) const {
- if (CC == CC_C && !LangOpts.MRTD &&
- getTargetInfo().getCXXABI().isMemberFunctionCCDefault())
- return CC_Default;
- return CC;
+ return (LangOpts.MRTD && !IsVariadic) ? CC_X86StdCall : CC_C;
}
bool ASTContext::isNearlyEmpty(const CXXRecordDecl *RD) const {
@@ -7941,9 +8002,9 @@ MangleContext *ASTContext::createMangleContext() {
case TargetCXXABI::GenericItanium:
case TargetCXXABI::GenericARM:
case TargetCXXABI::iOS:
- return createItaniumMangleContext(*this, getDiagnostics());
+ return ItaniumMangleContext::create(*this, getDiagnostics());
case TargetCXXABI::Microsoft:
- return createMicrosoftMangleContext(*this, getDiagnostics());
+ return MicrosoftMangleContext::create(*this, getDiagnostics());
}
llvm_unreachable("Unsupported ABI");
}
@@ -7951,45 +8012,77 @@ MangleContext *ASTContext::createMangleContext() {
CXXABI::~CXXABI() {}
size_t ASTContext::getSideTableAllocatedMemory() const {
- return ASTRecordLayouts.getMemorySize()
- + llvm::capacity_in_bytes(ObjCLayouts)
- + llvm::capacity_in_bytes(KeyFunctions)
- + llvm::capacity_in_bytes(ObjCImpls)
- + llvm::capacity_in_bytes(BlockVarCopyInits)
- + llvm::capacity_in_bytes(DeclAttrs)
- + llvm::capacity_in_bytes(InstantiatedFromStaticDataMember)
- + llvm::capacity_in_bytes(InstantiatedFromUsingDecl)
- + llvm::capacity_in_bytes(InstantiatedFromUsingShadowDecl)
- + llvm::capacity_in_bytes(InstantiatedFromUnnamedFieldDecl)
- + llvm::capacity_in_bytes(OverriddenMethods)
- + llvm::capacity_in_bytes(Types)
- + llvm::capacity_in_bytes(VariableArrayTypes)
- + llvm::capacity_in_bytes(ClassScopeSpecializationPattern);
-}
-
-void ASTContext::addUnnamedTag(const TagDecl *Tag) {
- // FIXME: This mangling should be applied to function local classes too
- if (!Tag->getName().empty() || Tag->getTypedefNameForAnonDecl() ||
- !isa<CXXRecordDecl>(Tag->getParent()) || Tag->getLinkage() != ExternalLinkage)
- return;
+ return ASTRecordLayouts.getMemorySize() +
+ llvm::capacity_in_bytes(ObjCLayouts) +
+ llvm::capacity_in_bytes(KeyFunctions) +
+ llvm::capacity_in_bytes(ObjCImpls) +
+ llvm::capacity_in_bytes(BlockVarCopyInits) +
+ llvm::capacity_in_bytes(DeclAttrs) +
+ llvm::capacity_in_bytes(TemplateOrInstantiation) +
+ llvm::capacity_in_bytes(InstantiatedFromUsingDecl) +
+ llvm::capacity_in_bytes(InstantiatedFromUsingShadowDecl) +
+ llvm::capacity_in_bytes(InstantiatedFromUnnamedFieldDecl) +
+ llvm::capacity_in_bytes(OverriddenMethods) +
+ llvm::capacity_in_bytes(Types) +
+ llvm::capacity_in_bytes(VariableArrayTypes) +
+ llvm::capacity_in_bytes(ClassScopeSpecializationPattern);
+}
+
+/// getIntTypeForBitwidth -
+/// sets integer QualTy according to specified details:
+/// bitwidth, signed/unsigned.
+/// Returns empty type if there is no appropriate target types.
+QualType ASTContext::getIntTypeForBitwidth(unsigned DestWidth,
+ unsigned Signed) const {
+ TargetInfo::IntType Ty = getTargetInfo().getIntTypeByWidth(DestWidth, Signed);
+ CanQualType QualTy = getFromTargetType(Ty);
+ if (!QualTy && DestWidth == 128)
+ return Signed ? Int128Ty : UnsignedInt128Ty;
+ return QualTy;
+}
+
+/// getRealTypeForBitwidth -
+/// sets floating point QualTy according to specified bitwidth.
+/// Returns empty type if there is no appropriate target types.
+QualType ASTContext::getRealTypeForBitwidth(unsigned DestWidth) const {
+ TargetInfo::RealType Ty = getTargetInfo().getRealTypeByWidth(DestWidth);
+ switch (Ty) {
+ case TargetInfo::Float:
+ return FloatTy;
+ case TargetInfo::Double:
+ return DoubleTy;
+ case TargetInfo::LongDouble:
+ return LongDoubleTy;
+ case TargetInfo::NoFloat:
+ return QualType();
+ }
- std::pair<llvm::DenseMap<const DeclContext *, unsigned>::iterator, bool> P =
- UnnamedMangleContexts.insert(std::make_pair(Tag->getParent(), 0));
- UnnamedMangleNumbers.insert(std::make_pair(Tag, P.first->second++));
+ llvm_unreachable("Unhandled TargetInfo::RealType value");
}
-int ASTContext::getUnnamedTagManglingNumber(const TagDecl *Tag) const {
- llvm::DenseMap<const TagDecl *, unsigned>::const_iterator I =
- UnnamedMangleNumbers.find(Tag);
- return I != UnnamedMangleNumbers.end() ? I->second : -1;
+void ASTContext::setManglingNumber(const NamedDecl *ND, unsigned Number) {
+ if (Number > 1)
+ MangleNumbers[ND] = Number;
}
-unsigned ASTContext::getLambdaManglingNumber(CXXMethodDecl *CallOperator) {
- CXXRecordDecl *Lambda = CallOperator->getParent();
- return LambdaMangleContexts[Lambda->getDeclContext()]
- .getManglingNumber(CallOperator);
+unsigned ASTContext::getManglingNumber(const NamedDecl *ND) const {
+ llvm::DenseMap<const NamedDecl *, unsigned>::const_iterator I =
+ MangleNumbers.find(ND);
+ return I != MangleNumbers.end() ? I->second : 1;
}
+MangleNumberingContext &
+ASTContext::getManglingNumberContext(const DeclContext *DC) {
+ assert(LangOpts.CPlusPlus); // We don't need mangling numbers for plain C.
+ MangleNumberingContext *&MCtx = MangleNumberingContexts[DC];
+ if (!MCtx)
+ MCtx = createMangleNumberingContext();
+ return *MCtx;
+}
+
+MangleNumberingContext *ASTContext::createMangleNumberingContext() const {
+ return ABI->createMangleNumberingContext();
+}
void ASTContext::setParameterIndex(const ParmVarDecl *D, unsigned int index) {
ParamIndices[D] = index;
@@ -8001,3 +8094,160 @@ unsigned ASTContext::getParameterIndex(const ParmVarDecl *D) const {
"ParmIndices lacks entry set by ParmVarDecl");
return I->second;
}
+
+APValue *
+ASTContext::getMaterializedTemporaryValue(const MaterializeTemporaryExpr *E,
+ bool MayCreate) {
+ assert(E && E->getStorageDuration() == SD_Static &&
+ "don't need to cache the computed value for this temporary");
+ if (MayCreate)
+ return &MaterializedTemporaryValues[E];
+
+ llvm::DenseMap<const MaterializeTemporaryExpr *, APValue>::iterator I =
+ MaterializedTemporaryValues.find(E);
+ return I == MaterializedTemporaryValues.end() ? 0 : &I->second;
+}
+
+bool ASTContext::AtomicUsesUnsupportedLibcall(const AtomicExpr *E) const {
+ const llvm::Triple &T = getTargetInfo().getTriple();
+ if (!T.isOSDarwin())
+ return false;
+
+ if (!(T.isiOS() && T.isOSVersionLT(7)) &&
+ !(T.isMacOSX() && T.isOSVersionLT(10, 9)))
+ return false;
+
+ QualType AtomicTy = E->getPtr()->getType()->getPointeeType();
+ CharUnits sizeChars = getTypeSizeInChars(AtomicTy);
+ uint64_t Size = sizeChars.getQuantity();
+ CharUnits alignChars = getTypeAlignInChars(AtomicTy);
+ unsigned Align = alignChars.getQuantity();
+ unsigned MaxInlineWidthInBits = getTargetInfo().getMaxAtomicInlineWidth();
+ return (Size != Align || toBits(sizeChars) > MaxInlineWidthInBits);
+}
+
+namespace {
+
+ /// \brief A \c RecursiveASTVisitor that builds a map from nodes to their
+ /// parents as defined by the \c RecursiveASTVisitor.
+ ///
+ /// Note that the relationship described here is purely in terms of AST
+ /// traversal - there are other relationships (for example declaration context)
+ /// in the AST that are better modeled by special matchers.
+ ///
+ /// FIXME: Currently only builds up the map using \c Stmt and \c Decl nodes.
+ class ParentMapASTVisitor : public RecursiveASTVisitor<ParentMapASTVisitor> {
+
+ public:
+ /// \brief Builds and returns the translation unit's parent map.
+ ///
+ /// The caller takes ownership of the returned \c ParentMap.
+ static ASTContext::ParentMap *buildMap(TranslationUnitDecl &TU) {
+ ParentMapASTVisitor Visitor(new ASTContext::ParentMap);
+ Visitor.TraverseDecl(&TU);
+ return Visitor.Parents;
+ }
+
+ private:
+ typedef RecursiveASTVisitor<ParentMapASTVisitor> VisitorBase;
+
+ ParentMapASTVisitor(ASTContext::ParentMap *Parents) : Parents(Parents) {
+ }
+
+ bool shouldVisitTemplateInstantiations() const {
+ return true;
+ }
+ bool shouldVisitImplicitCode() const {
+ return true;
+ }
+ // Disables data recursion. We intercept Traverse* methods in the RAV, which
+ // are not triggered during data recursion.
+ bool shouldUseDataRecursionFor(clang::Stmt *S) const {
+ return false;
+ }
+
+ template <typename T>
+ bool TraverseNode(T *Node, bool(VisitorBase:: *traverse) (T *)) {
+ if (Node == NULL)
+ return true;
+ if (ParentStack.size() > 0)
+ // FIXME: Currently we add the same parent multiple times, for example
+ // when we visit all subexpressions of template instantiations; this is
+ // suboptimal, bug benign: the only way to visit those is with
+ // hasAncestor / hasParent, and those do not create new matches.
+ // The plan is to enable DynTypedNode to be storable in a map or hash
+ // map. The main problem there is to implement hash functions /
+ // comparison operators for all types that DynTypedNode supports that
+ // do not have pointer identity.
+ (*Parents)[Node].push_back(ParentStack.back());
+ ParentStack.push_back(ast_type_traits::DynTypedNode::create(*Node));
+ bool Result = (this ->* traverse) (Node);
+ ParentStack.pop_back();
+ return Result;
+ }
+
+ bool TraverseDecl(Decl *DeclNode) {
+ return TraverseNode(DeclNode, &VisitorBase::TraverseDecl);
+ }
+
+ bool TraverseStmt(Stmt *StmtNode) {
+ return TraverseNode(StmtNode, &VisitorBase::TraverseStmt);
+ }
+
+ ASTContext::ParentMap *Parents;
+ llvm::SmallVector<ast_type_traits::DynTypedNode, 16> ParentStack;
+
+ friend class RecursiveASTVisitor<ParentMapASTVisitor>;
+ };
+
+} // end namespace
+
+ASTContext::ParentVector
+ASTContext::getParents(const ast_type_traits::DynTypedNode &Node) {
+ assert(Node.getMemoizationData() &&
+ "Invariant broken: only nodes that support memoization may be "
+ "used in the parent map.");
+ if (!AllParents) {
+ // We always need to run over the whole translation unit, as
+ // hasAncestor can escape any subtree.
+ AllParents.reset(
+ ParentMapASTVisitor::buildMap(*getTranslationUnitDecl()));
+ }
+ ParentMap::const_iterator I = AllParents->find(Node.getMemoizationData());
+ if (I == AllParents->end()) {
+ return ParentVector();
+ }
+ return I->second;
+}
+
+bool
+ASTContext::ObjCMethodsAreEqual(const ObjCMethodDecl *MethodDecl,
+ const ObjCMethodDecl *MethodImpl) {
+ // No point trying to match an unavailable/deprecated mothod.
+ if (MethodDecl->hasAttr<UnavailableAttr>()
+ || MethodDecl->hasAttr<DeprecatedAttr>())
+ return false;
+ if (MethodDecl->getObjCDeclQualifier() !=
+ MethodImpl->getObjCDeclQualifier())
+ return false;
+ if (!hasSameType(MethodDecl->getResultType(),
+ MethodImpl->getResultType()))
+ return false;
+
+ if (MethodDecl->param_size() != MethodImpl->param_size())
+ return false;
+
+ for (ObjCMethodDecl::param_const_iterator IM = MethodImpl->param_begin(),
+ IF = MethodDecl->param_begin(), EM = MethodImpl->param_end(),
+ EF = MethodDecl->param_end();
+ IM != EM && IF != EF; ++IM, ++IF) {
+ const ParmVarDecl *DeclVar = (*IF);
+ const ParmVarDecl *ImplVar = (*IM);
+ if (ImplVar->getObjCDeclQualifier() != DeclVar->getObjCDeclQualifier())
+ return false;
+ if (!hasSameType(DeclVar->getType(), ImplVar->getType()))
+ return false;
+ }
+ return (MethodDecl->isVariadic() == MethodImpl->isVariadic());
+
+}
diff --git a/lib/AST/ASTDiagnostic.cpp b/lib/AST/ASTDiagnostic.cpp
index 1ed65e476ce3..fce8f64b3328 100644
--- a/lib/AST/ASTDiagnostic.cpp
+++ b/lib/AST/ASTDiagnostic.cpp
@@ -300,8 +300,7 @@ void clang::FormatASTNodeDiagnosticArgument(
assert(ModLen == 0 && ArgLen == 0 &&
"Invalid modifier for DeclarationName argument");
- DeclarationName N = DeclarationName::getFromOpaqueInteger(Val);
- N.printName(OS);
+ OS << DeclarationName::getFromOpaqueInteger(Val);
break;
}
case DiagnosticsEngine::ak_nameddecl: {
@@ -459,6 +458,10 @@ class TemplateDiff {
/// FromValueDecl, ToValueDecl - Whether the argument is a decl.
ValueDecl *FromValueDecl, *ToValueDecl;
+ /// FromAddressOf, ToAddressOf - Whether the ValueDecl needs an address of
+ /// operator before it.
+ bool FromAddressOf, ToAddressOf;
+
/// FromDefault, ToDefault - Whether the argument is a default argument.
bool FromDefault, ToDefault;
@@ -469,7 +472,8 @@ class TemplateDiff {
: Kind(Invalid), NextNode(0), ChildNode(0), ParentNode(ParentNode),
FromType(), ToType(), FromExpr(0), ToExpr(0), FromTD(0), ToTD(0),
IsValidFromInt(false), IsValidToInt(false), FromValueDecl(0),
- ToValueDecl(0), FromDefault(false), ToDefault(false), Same(false) { }
+ ToValueDecl(0), FromAddressOf(false), ToAddressOf(false),
+ FromDefault(false), ToDefault(false), Same(false) { }
};
/// FlatTree - A flattened tree used to store the DiffNodes.
@@ -526,9 +530,12 @@ class TemplateDiff {
}
/// SetNode - Set FromValueDecl and ToValueDecl of the current node.
- void SetNode(ValueDecl *FromValueDecl, ValueDecl *ToValueDecl) {
+ void SetNode(ValueDecl *FromValueDecl, ValueDecl *ToValueDecl,
+ bool FromAddressOf, bool ToAddressOf) {
FlatTree[CurrentNode].FromValueDecl = FromValueDecl;
FlatTree[CurrentNode].ToValueDecl = ToValueDecl;
+ FlatTree[CurrentNode].FromAddressOf = FromAddressOf;
+ FlatTree[CurrentNode].ToAddressOf = ToAddressOf;
}
/// SetSame - Sets the same flag of the current node.
@@ -620,9 +627,12 @@ class TemplateDiff {
}
/// GetNode - Gets the FromValueDecl and ToValueDecl.
- void GetNode(ValueDecl *&FromValueDecl, ValueDecl *&ToValueDecl) {
+ void GetNode(ValueDecl *&FromValueDecl, ValueDecl *&ToValueDecl,
+ bool &FromAddressOf, bool &ToAddressOf) {
FromValueDecl = FlatTree[ReadNode].FromValueDecl;
ToValueDecl = FlatTree[ReadNode].ToValueDecl;
+ FromAddressOf = FlatTree[ReadNode].FromAddressOf;
+ ToAddressOf = FlatTree[ReadNode].ToAddressOf;
}
/// NodeIsSame - Returns true the arguments are the same.
@@ -821,8 +831,10 @@ class TemplateDiff {
void DiffTemplate(const TemplateSpecializationType *FromTST,
const TemplateSpecializationType *ToTST) {
// Begin descent into diffing template tree.
- TemplateParameterList *Params =
+ TemplateParameterList *ParamsFrom =
FromTST->getTemplateName().getAsTemplateDecl()->getTemplateParameters();
+ TemplateParameterList *ParamsTo =
+ ToTST->getTemplateName().getAsTemplateDecl()->getTemplateParameters();
unsigned TotalArgs = 0;
for (TSTiterator FromIter(Context, FromTST), ToIter(Context, ToTST);
!FromIter.isEnd() || !ToIter.isEnd(); ++TotalArgs) {
@@ -831,15 +843,18 @@ class TemplateDiff {
// Get the parameter at index TotalArgs. If index is larger
// than the total number of parameters, then there is an
// argument pack, so re-use the last parameter.
- NamedDecl *ParamND = Params->getParam(
- (TotalArgs < Params->size()) ? TotalArgs
- : Params->size() - 1);
+ unsigned ParamIndex = std::min(TotalArgs, ParamsFrom->size() - 1);
+ NamedDecl *ParamND = ParamsFrom->getParam(ParamIndex);
+
// Handle Types
if (TemplateTypeParmDecl *DefaultTTPD =
dyn_cast<TemplateTypeParmDecl>(ParamND)) {
QualType FromType, ToType;
FromType = GetType(FromIter, DefaultTTPD);
- ToType = GetType(ToIter, DefaultTTPD);
+ // A forward declaration can have no default arg but the actual class
+ // can, don't mix up iterators and get the original parameter.
+ ToType = GetType(
+ ToIter, cast<TemplateTypeParmDecl>(ParamsTo->getParam(ParamIndex)));
Tree.SetNode(FromType, ToType);
Tree.SetDefault(FromIter.isEnd() && !FromType.isNull(),
ToIter.isEnd() && !ToType.isNull());
@@ -942,7 +957,14 @@ class TemplateDiff {
FromValueDecl = GetValueDecl(FromIter, FromExpr);
if (!HasToValueDecl && ToExpr)
ToValueDecl = GetValueDecl(ToIter, ToExpr);
- Tree.SetNode(FromValueDecl, ToValueDecl);
+ QualType ArgumentType = DefaultNTTPD->getType();
+ bool FromAddressOf = FromValueDecl &&
+ !ArgumentType->isReferenceType() &&
+ !FromValueDecl->getType()->isArrayType();
+ bool ToAddressOf = ToValueDecl &&
+ !ArgumentType->isReferenceType() &&
+ !ToValueDecl->getType()->isArrayType();
+ Tree.SetNode(FromValueDecl, ToValueDecl, FromAddressOf, ToAddressOf);
Tree.SetSame(FromValueDecl && ToValueDecl &&
FromValueDecl->getCanonicalDecl() ==
ToValueDecl->getCanonicalDecl());
@@ -973,7 +995,7 @@ class TemplateDiff {
/// makeTemplateList - Dump every template alias into the vector.
static void makeTemplateList(
- SmallVector<const TemplateSpecializationType*, 1> &TemplateList,
+ SmallVectorImpl<const TemplateSpecializationType *> &TemplateList,
const TemplateSpecializationType *TST) {
while (TST) {
TemplateList.push_back(TST);
@@ -1008,7 +1030,7 @@ class TemplateDiff {
makeTemplateList(FromTemplateList, FromTST);
makeTemplateList(ToTemplateList, ToTST);
- SmallVector<const TemplateSpecializationType*, 1>::reverse_iterator
+ SmallVectorImpl<const TemplateSpecializationType *>::reverse_iterator
FromIter = FromTemplateList.rbegin(), FromEnd = FromTemplateList.rend(),
ToIter = ToTemplateList.rbegin(), ToEnd = ToTemplateList.rend();
@@ -1037,10 +1059,14 @@ class TemplateDiff {
if (!Iter.isEnd())
return Iter->getAsType();
- if (!isVariadic)
- return DefaultTTPD->getDefaultArgument();
+ if (isVariadic)
+ return QualType();
+
+ QualType ArgType = DefaultTTPD->getDefaultArgument();
+ if (ArgType->isDependentType())
+ return Iter.getDesugar().getAsType();
- return QualType();
+ return ArgType;
}
/// GetExpr - Retrieves the template expression argument, including default
@@ -1080,7 +1106,7 @@ class TemplateDiff {
return ArgExpr->EvaluateKnownConstInt(Context);
}
- /// GetValueDecl - Retrieves the template integer argument, including
+ /// GetValueDecl - Retrieves the template Decl argument, including
/// default expression argument.
ValueDecl *GetValueDecl(const TSTiterator &Iter, Expr *ArgExpr) {
// Default, value-depenedent expressions require fetching
@@ -1095,7 +1121,12 @@ class TemplateDiff {
default:
assert(0 && "Unexpected template argument kind");
}
- return cast<DeclRefExpr>(ArgExpr)->getDecl();
+ DeclRefExpr *DRE = dyn_cast<DeclRefExpr>(ArgExpr);
+ if (!DRE) {
+ DRE = cast<DeclRefExpr>(cast<UnaryOperator>(ArgExpr)->getSubExpr());
+ }
+
+ return DRE->getDecl();
}
/// GetTemplateDecl - Retrieves the template template arguments, including
@@ -1228,9 +1259,10 @@ class TemplateDiff {
}
case DiffTree::Declaration: {
ValueDecl *FromValueDecl, *ToValueDecl;
- Tree.GetNode(FromValueDecl, ToValueDecl);
- PrintValueDecl(FromValueDecl, ToValueDecl, Tree.FromDefault(),
- Tree.ToDefault(), Tree.NodeIsSame());
+ bool FromAddressOf, ToAddressOf;
+ Tree.GetNode(FromValueDecl, ToValueDecl, FromAddressOf, ToAddressOf);
+ PrintValueDecl(FromValueDecl, ToValueDecl, FromAddressOf, ToAddressOf,
+ Tree.FromDefault(), Tree.ToDefault(), Tree.NodeIsSame());
return;
}
case DiffTree::Template: {
@@ -1478,7 +1510,8 @@ class TemplateDiff {
/// PrintDecl - Handles printing of Decl arguments, highlighting
/// argument differences.
void PrintValueDecl(ValueDecl *FromValueDecl, ValueDecl *ToValueDecl,
- bool FromDefault, bool ToDefault, bool Same) {
+ bool FromAddressOf, bool ToAddressOf, bool FromDefault,
+ bool ToDefault, bool Same) {
assert((FromValueDecl || ToValueDecl) &&
"Only one Decl argument may be NULL");
@@ -1487,15 +1520,21 @@ class TemplateDiff {
} else if (!PrintTree) {
OS << (FromDefault ? "(default) " : "");
Bold();
+ if (FromAddressOf)
+ OS << "&";
OS << (FromValueDecl ? FromValueDecl->getName() : "(no argument)");
Unbold();
} else {
OS << (FromDefault ? "[(default) " : "[");
Bold();
+ if (FromAddressOf)
+ OS << "&";
OS << (FromValueDecl ? FromValueDecl->getName() : "(no argument)");
Unbold();
OS << " != " << (ToDefault ? "(default) " : "");
Bold();
+ if (ToAddressOf)
+ OS << "&";
OS << (ToValueDecl ? ToValueDecl->getName() : "(no argument)");
Unbold();
OS << ']';
diff --git a/lib/AST/ASTDumper.cpp b/lib/AST/ASTDumper.cpp
index 340cc41f7e81..2f402559f4da 100644
--- a/lib/AST/ASTDumper.cpp
+++ b/lib/AST/ASTDumper.cpp
@@ -16,6 +16,7 @@
#include "clang/AST/Attr.h"
#include "clang/AST/CommentVisitor.h"
#include "clang/AST/DeclCXX.h"
+#include "clang/AST/DeclLookups.h"
#include "clang/AST/DeclObjC.h"
#include "clang/AST/DeclVisitor.h"
#include "clang/AST/StmtVisitor.h"
@@ -62,6 +63,9 @@ namespace {
// Null statements
static const TerminalColor NullColor = { raw_ostream::BLUE, false };
+ // Undeserialized entities
+ static const TerminalColor UndeserializedColor = { raw_ostream::GREEN, true };
+
// CastKind from CastExpr's
static const TerminalColor CastColor = { raw_ostream::RED, false };
@@ -173,6 +177,7 @@ namespace {
void dumpName(const NamedDecl *D);
bool hasNodes(const DeclContext *DC);
void dumpDeclContext(const DeclContext *DC);
+ void dumpLookups(const DeclContext *DC);
void dumpAttr(const Attr *A);
// C++ Utilities
@@ -214,6 +219,11 @@ namespace {
const ClassTemplatePartialSpecializationDecl *D);
void VisitClassScopeFunctionSpecializationDecl(
const ClassScopeFunctionSpecializationDecl *D);
+ void VisitVarTemplateDecl(const VarTemplateDecl *D);
+ void VisitVarTemplateSpecializationDecl(
+ const VarTemplateSpecializationDecl *D);
+ void VisitVarTemplatePartialSpecializationDecl(
+ const VarTemplatePartialSpecializationDecl *D);
void VisitTemplateTypeParmDecl(const TemplateTypeParmDecl *D);
void VisitNonTypeTemplateParmDecl(const NonTypeTemplateParmDecl *D);
void VisitTemplateTemplateParmDecl(const TemplateTemplateParmDecl *D);
@@ -244,6 +254,7 @@ namespace {
void VisitAttributedStmt(const AttributedStmt *Node);
void VisitLabelStmt(const LabelStmt *Node);
void VisitGotoStmt(const GotoStmt *Node);
+ void VisitCXXCatchStmt(const CXXCatchStmt *Node);
// Exprs
void VisitExpr(const Expr *Node);
@@ -271,9 +282,14 @@ namespace {
void VisitCXXFunctionalCastExpr(const CXXFunctionalCastExpr *Node);
void VisitCXXConstructExpr(const CXXConstructExpr *Node);
void VisitCXXBindTemporaryExpr(const CXXBindTemporaryExpr *Node);
+ void VisitMaterializeTemporaryExpr(const MaterializeTemporaryExpr *Node);
void VisitExprWithCleanups(const ExprWithCleanups *Node);
void VisitUnresolvedLookupExpr(const UnresolvedLookupExpr *Node);
void dumpCXXTemporary(const CXXTemporary *Temporary);
+ void VisitLambdaExpr(const LambdaExpr *Node) {
+ VisitExpr(Node);
+ dumpDecl(Node->getLambdaClass());
+ }
// ObjC
void VisitObjCAtCatchStmt(const ObjCAtCatchStmt *Node);
@@ -329,8 +345,8 @@ void ASTDumper::indent() {
OS << "\n";
ColorScope Color(*this, IndentColor);
- for (llvm::SmallVector<IndentType, 32>::const_iterator I = Indents.begin(),
- E = Indents.end();
+ for (SmallVectorImpl<IndentType>::const_iterator I = Indents.begin(),
+ E = Indents.end();
I != E; ++I) {
switch (*I) {
case IT_Child:
@@ -449,9 +465,7 @@ void ASTDumper::dumpBareDeclRef(const Decl *D) {
if (const NamedDecl *ND = dyn_cast<NamedDecl>(D)) {
ColorScope Color(*this, DeclNameColor);
- OS << " '";
- ND->getDeclName().printName(OS);
- OS << "'";
+ OS << " '" << ND->getDeclName() << '\'';
}
if (const ValueDecl *VD = dyn_cast<ValueDecl>(D))
@@ -479,20 +493,76 @@ bool ASTDumper::hasNodes(const DeclContext *DC) {
if (!DC)
return false;
- return DC->decls_begin() != DC->decls_end();
+ return DC->hasExternalLexicalStorage() ||
+ DC->noload_decls_begin() != DC->noload_decls_end();
}
void ASTDumper::dumpDeclContext(const DeclContext *DC) {
if (!DC)
return;
- for (DeclContext::decl_iterator I = DC->decls_begin(), E = DC->decls_end();
+ bool HasUndeserializedDecls = DC->hasExternalLexicalStorage();
+ for (DeclContext::decl_iterator I = DC->noload_decls_begin(),
+ E = DC->noload_decls_end();
I != E; ++I) {
DeclContext::decl_iterator Next = I;
++Next;
- if (Next == E)
+ if (Next == E && !HasUndeserializedDecls)
lastChild();
dumpDecl(*I);
}
+ if (HasUndeserializedDecls) {
+ lastChild();
+ IndentScope Indent(*this);
+ ColorScope Color(*this, UndeserializedColor);
+ OS << "<undeserialized declarations>";
+ }
+}
+
+void ASTDumper::dumpLookups(const DeclContext *DC) {
+ IndentScope Indent(*this);
+
+ OS << "StoredDeclsMap ";
+ dumpBareDeclRef(cast<Decl>(DC));
+
+ const DeclContext *Primary = DC->getPrimaryContext();
+ if (Primary != DC) {
+ OS << " primary";
+ dumpPointer(cast<Decl>(Primary));
+ }
+
+ bool HasUndeserializedLookups = Primary->hasExternalVisibleStorage();
+
+ DeclContext::all_lookups_iterator I = Primary->noload_lookups_begin(),
+ E = Primary->noload_lookups_end();
+ while (I != E) {
+ DeclarationName Name = I.getLookupName();
+ DeclContextLookupResult R = *I++;
+ if (I == E && !HasUndeserializedLookups)
+ lastChild();
+
+ IndentScope Indent(*this);
+ OS << "DeclarationName ";
+ {
+ ColorScope Color(*this, DeclNameColor);
+ OS << '\'' << Name << '\'';
+ }
+
+ for (DeclContextLookupResult::iterator RI = R.begin(), RE = R.end();
+ RI != RE; ++RI) {
+ if (RI + 1 == RE)
+ lastChild();
+ dumpDeclRef(*RI);
+ if ((*RI)->isHidden())
+ OS << " hidden";
+ }
+ }
+
+ if (HasUndeserializedLookups) {
+ lastChild();
+ IndentScope Indent(*this);
+ ColorScope Color(*this, UndeserializedColor);
+ OS << "<undeserialized lookups>";
+ }
}
void ASTDumper::dumpAttr(const Attr *A) {
@@ -511,21 +581,29 @@ void ASTDumper::dumpAttr(const Attr *A) {
#include "clang/AST/AttrDump.inc"
}
-static Decl *getPreviousDeclImpl(...) {
- return 0;
+static void dumpPreviousDeclImpl(raw_ostream &OS, ...) {}
+
+template<typename T>
+static void dumpPreviousDeclImpl(raw_ostream &OS, const Mergeable<T> *D) {
+ const T *First = D->getFirstDecl();
+ if (First != D)
+ OS << " first " << First;
}
template<typename T>
-static const Decl *getPreviousDeclImpl(const Redeclarable<T> *D) {
- return D->getPreviousDecl();
+static void dumpPreviousDeclImpl(raw_ostream &OS, const Redeclarable<T> *D) {
+ const T *Prev = D->getPreviousDecl();
+ if (Prev)
+ OS << " prev " << Prev;
}
-/// Get the previous declaration in the redeclaration chain for a declaration.
-static const Decl *getPreviousDecl(const Decl *D) {
+/// Dump the previous declaration in the redeclaration chain for a declaration,
+/// if any.
+static void dumpPreviousDecl(raw_ostream &OS, const Decl *D) {
switch (D->getKind()) {
#define DECL(DERIVED, BASE) \
case Decl::DERIVED: \
- return getPreviousDeclImpl(cast<DERIVED##Decl>(D));
+ return dumpPreviousDeclImpl(OS, cast<DERIVED##Decl>(D));
#define ABSTRACT_DECL(DECL)
#include "clang/AST/DeclNodes.inc"
}
@@ -662,20 +740,25 @@ void ASTDumper::dumpDecl(const Decl *D) {
dumpPointer(D);
if (D->getLexicalDeclContext() != D->getDeclContext())
OS << " parent " << cast<Decl>(D->getDeclContext());
- if (const Decl *Prev = getPreviousDecl(D))
- OS << " prev " << Prev;
+ dumpPreviousDecl(OS, D);
dumpSourceRange(D->getSourceRange());
+ if (Module *M = D->getOwningModule())
+ OS << " in " << M->getFullModuleName();
+ if (const NamedDecl *ND = dyn_cast<NamedDecl>(D))
+ if (ND->isHidden())
+ OS << " hidden";
bool HasAttrs = D->attr_begin() != D->attr_end();
- bool HasComment = D->getASTContext().getCommentForDecl(D, 0);
+ const FullComment *Comment =
+ D->getASTContext().getLocalCommentForDeclUncached(D);
// Decls within functions are visited by the body
bool HasDeclContext = !isa<FunctionDecl>(*D) && !isa<ObjCMethodDecl>(*D) &&
hasNodes(dyn_cast<DeclContext>(D));
- setMoreChildren(HasAttrs || HasComment || HasDeclContext);
+ setMoreChildren(HasAttrs || Comment || HasDeclContext);
ConstDeclVisitor<ASTDumper>::Visit(D);
- setMoreChildren(HasComment || HasDeclContext);
+ setMoreChildren(Comment || HasDeclContext);
for (Decl::attr_iterator I = D->attr_begin(), E = D->attr_end();
I != E; ++I) {
if (I + 1 == E)
@@ -685,7 +768,10 @@ void ASTDumper::dumpDecl(const Decl *D) {
setMoreChildren(HasDeclContext);
lastChild();
- dumpFullComment(D->getASTContext().getCommentForDecl(D, 0));
+ dumpFullComment(Comment);
+
+ if (D->isInvalidDecl())
+ OS << " invalid";
setMoreChildren(false);
if (HasDeclContext)
@@ -722,6 +808,8 @@ void ASTDumper::VisitRecordDecl(const RecordDecl *D) {
dumpName(D);
if (D->isModulePrivate())
OS << " __module_private__";
+ if (D->isCompleteDefinition())
+ OS << " definition";
}
void ASTDumper::VisitEnumConstantDecl(const EnumConstantDecl *D) {
@@ -764,6 +852,19 @@ void ASTDumper::VisitFunctionDecl(const FunctionDecl *D) {
else if (D->isDeletedAsWritten())
OS << " delete";
+ if (const FunctionProtoType *FPT = D->getType()->getAs<FunctionProtoType>()) {
+ FunctionProtoType::ExtProtoInfo EPI = FPT->getExtProtoInfo();
+ switch (EPI.ExceptionSpecType) {
+ default: break;
+ case EST_Unevaluated:
+ OS << " noexcept-unevaluated " << EPI.ExceptionSpecDecl;
+ break;
+ case EST_Uninstantiated:
+ OS << " noexcept-uninstantiated " << EPI.ExceptionSpecTemplate;
+ break;
+ }
+ }
+
bool OldMoreChildren = hasMoreChildren();
const FunctionTemplateSpecializationInfo *FTSI =
D->getTemplateSpecializationInfo();
@@ -1012,6 +1113,49 @@ void ASTDumper::VisitClassScopeFunctionSpecializationDecl(
dumpTemplateArgumentListInfo(D->templateArgs());
}
+void ASTDumper::VisitVarTemplateDecl(const VarTemplateDecl *D) {
+ dumpName(D);
+ dumpTemplateParameters(D->getTemplateParameters());
+
+ VarTemplateDecl::spec_iterator I = D->spec_begin();
+ VarTemplateDecl::spec_iterator E = D->spec_end();
+ if (I == E)
+ lastChild();
+ dumpDecl(D->getTemplatedDecl());
+ for (; I != E; ++I) {
+ VarTemplateDecl::spec_iterator Next = I;
+ ++Next;
+ if (Next == E)
+ lastChild();
+ switch (I->getTemplateSpecializationKind()) {
+ case TSK_Undeclared:
+ case TSK_ImplicitInstantiation:
+ if (D == D->getCanonicalDecl())
+ dumpDecl(*I);
+ else
+ dumpDeclRef(*I);
+ break;
+ case TSK_ExplicitSpecialization:
+ case TSK_ExplicitInstantiationDeclaration:
+ case TSK_ExplicitInstantiationDefinition:
+ dumpDeclRef(*I);
+ break;
+ }
+ }
+}
+
+void ASTDumper::VisitVarTemplateSpecializationDecl(
+ const VarTemplateSpecializationDecl *D) {
+ dumpTemplateArgumentList(D->getTemplateArgs());
+ VisitVarDecl(D);
+}
+
+void ASTDumper::VisitVarTemplatePartialSpecializationDecl(
+ const VarTemplatePartialSpecializationDecl *D) {
+ dumpTemplateParameters(D->getTemplateParameters());
+ VisitVarTemplateSpecializationDecl(D);
+}
+
void ASTDumper::VisitTemplateTypeParmDecl(const TemplateTypeParmDecl *D) {
if (D->wasDeclaredWithTypename())
OS << " typename";
@@ -1097,6 +1241,8 @@ void ASTDumper::VisitObjCIvarDecl(const ObjCIvarDecl *D) {
dumpType(D->getType());
if (D->getSynthesize())
OS << " synthesize";
+ if (D->getBackingIvarReferencedInAccessor())
+ OS << " BackingIvarReferencedInAccessor";
switch (D->getAccessControl()) {
case ObjCIvarDecl::None:
@@ -1331,7 +1477,7 @@ void ASTDumper::dumpStmt(const Stmt *S) {
return;
}
- setMoreChildren(S->children());
+ setMoreChildren(!S->children().empty());
ConstStmtVisitor<ASTDumper>::Visit(S);
setMoreChildren(false);
for (Stmt::const_child_range CI = S->children(); CI; ++CI) {
@@ -1385,6 +1531,11 @@ void ASTDumper::VisitGotoStmt(const GotoStmt *Node) {
dumpPointer(Node->getLabel());
}
+void ASTDumper::VisitCXXCatchStmt(const CXXCatchStmt *Node) {
+ VisitStmt(Node);
+ dumpDecl(Node->getExceptionDecl());
+}
+
//===----------------------------------------------------------------------===//
// Expr dumping methods.
//===----------------------------------------------------------------------===//
@@ -1510,6 +1661,7 @@ void ASTDumper::VisitPredefinedExpr(const PredefinedExpr *Node) {
default: llvm_unreachable("unknown case");
case PredefinedExpr::Func: OS << " __func__"; break;
case PredefinedExpr::Function: OS << " __FUNCTION__"; break;
+ case PredefinedExpr::FuncDName: OS << " __FUNCDNAME__"; break;
case PredefinedExpr::LFunction: OS << " L__FUNCTION__"; break;
case PredefinedExpr::PrettyFunction: OS << " __PRETTY_FUNCTION__";break;
}
@@ -1659,6 +1811,15 @@ void ASTDumper::VisitCXXBindTemporaryExpr(const CXXBindTemporaryExpr *Node) {
dumpCXXTemporary(Node->getTemporary());
}
+void
+ASTDumper::VisitMaterializeTemporaryExpr(const MaterializeTemporaryExpr *Node) {
+ VisitExpr(Node);
+ if (const ValueDecl *VD = Node->getExtendingDecl()) {
+ OS << " extended by ";
+ dumpBareDeclRef(VD);
+ }
+}
+
void ASTDumper::VisitExprWithCleanups(const ExprWithCleanups *Node) {
VisitExpr(Node);
for (unsigned i = 0, e = Node->getNumObjects(); i != e; ++i)
@@ -1949,6 +2110,20 @@ void Decl::dumpColor() const {
&getASTContext().getSourceManager(), /*ShowColors*/true);
P.dumpDecl(this);
}
+
+void DeclContext::dumpLookups() const {
+ dumpLookups(llvm::errs());
+}
+
+void DeclContext::dumpLookups(raw_ostream &OS) const {
+ const DeclContext *DC = this;
+ while (!DC->isTranslationUnit())
+ DC = DC->getParent();
+ ASTContext &Ctx = cast<TranslationUnitDecl>(DC)->getASTContext();
+ ASTDumper P(OS, &Ctx.getCommentCommandTraits(), &Ctx.getSourceManager());
+ P.dumpLookups(this);
+}
+
//===----------------------------------------------------------------------===//
// Stmt method implementations
//===----------------------------------------------------------------------===//
diff --git a/lib/AST/ASTImporter.cpp b/lib/AST/ASTImporter.cpp
index 915eb6feb85e..e16015b7c4ed 100644
--- a/lib/AST/ASTImporter.cpp
+++ b/lib/AST/ASTImporter.cpp
@@ -106,6 +106,8 @@ namespace clang {
bool ImportDefinition(RecordDecl *From, RecordDecl *To,
ImportDefinitionKind Kind = IDK_Default);
+ bool ImportDefinition(VarDecl *From, VarDecl *To,
+ ImportDefinitionKind Kind = IDK_Default);
bool ImportDefinition(EnumDecl *From, EnumDecl *To,
ImportDefinitionKind Kind = IDK_Default);
bool ImportDefinition(ObjCInterfaceDecl *From, ObjCInterfaceDecl *To,
@@ -120,9 +122,12 @@ namespace clang {
SmallVectorImpl<TemplateArgument> &ToArgs);
bool IsStructuralMatch(RecordDecl *FromRecord, RecordDecl *ToRecord,
bool Complain = true);
+ bool IsStructuralMatch(VarDecl *FromVar, VarDecl *ToVar,
+ bool Complain = true);
bool IsStructuralMatch(EnumDecl *FromEnum, EnumDecl *ToRecord);
bool IsStructuralMatch(EnumConstantDecl *FromEC, EnumConstantDecl *ToEC);
bool IsStructuralMatch(ClassTemplateDecl *From, ClassTemplateDecl *To);
+ bool IsStructuralMatch(VarTemplateDecl *From, VarTemplateDecl *To);
Decl *VisitDecl(Decl *D);
Decl *VisitTranslationUnitDecl(TranslationUnitDecl *D);
Decl *VisitNamespaceDecl(NamespaceDecl *D);
@@ -157,7 +162,9 @@ namespace clang {
Decl *VisitClassTemplateDecl(ClassTemplateDecl *D);
Decl *VisitClassTemplateSpecializationDecl(
ClassTemplateSpecializationDecl *D);
-
+ Decl *VisitVarTemplateDecl(VarTemplateDecl *D);
+ Decl *VisitVarTemplateSpecializationDecl(VarTemplateSpecializationDecl *D);
+
// Importing statements
Stmt *VisitStmt(Stmt *S);
@@ -400,6 +407,13 @@ static bool IsStructurallyEquivalent(StructuralEquivalenceContext &Context,
return false;
break;
+ case Type::Decayed:
+ if (!IsStructurallyEquivalent(Context,
+ cast<DecayedType>(T1)->getPointeeType(),
+ cast<DecayedType>(T2)->getPointeeType()))
+ return false;
+ break;
+
case Type::Pointer:
if (!IsStructurallyEquivalent(Context,
cast<PointerType>(T1)->getPointeeType(),
@@ -1695,7 +1709,8 @@ QualType ASTNodeImporter::VisitAutoType(const AutoType *T) {
return QualType();
}
- return Importer.getToContext().getAutoType(ToDeduced, T->isDecltypeAuto());
+ return Importer.getToContext().getAutoType(ToDeduced, T->isDecltypeAuto(),
+ /*IsDependent*/false);
}
QualType ASTNodeImporter::VisitRecordType(const RecordType *T) {
@@ -1968,9 +1983,6 @@ bool ASTNodeImporter::ImportDefinition(RecordDecl *From, RecordDecl *To,
= FromData.HasDeclaredCopyConstructorWithConstParam;
ToData.HasDeclaredCopyAssignmentWithConstParam
= FromData.HasDeclaredCopyAssignmentWithConstParam;
- ToData.FailedImplicitMoveConstructor
- = FromData.FailedImplicitMoveConstructor;
- ToData.FailedImplicitMoveAssignment = FromData.FailedImplicitMoveAssignment;
ToData.IsLambda = FromData.IsLambda;
SmallVector<CXXBaseSpecifier *, 4> Bases;
@@ -2010,6 +2022,21 @@ bool ASTNodeImporter::ImportDefinition(RecordDecl *From, RecordDecl *To,
return false;
}
+bool ASTNodeImporter::ImportDefinition(VarDecl *From, VarDecl *To,
+ ImportDefinitionKind Kind) {
+ if (To->getDefinition())
+ return false;
+
+ // FIXME: Can we really import any initializer? Alternatively, we could force
+ // ourselves to import every declaration of a variable and then only use
+ // getInit() here.
+ To->setInit(Importer.Import(const_cast<Expr *>(From->getAnyInitializer())));
+
+ // FIXME: Other bits to merge?
+
+ return false;
+}
+
bool ASTNodeImporter::ImportDefinition(EnumDecl *From, EnumDecl *To,
ImportDefinitionKind Kind) {
if (To->getDefinition() || To->isBeingDefined()) {
@@ -2148,13 +2175,30 @@ bool ASTNodeImporter::ImportTemplateArguments(const TemplateArgument *FromArgs,
bool ASTNodeImporter::IsStructuralMatch(RecordDecl *FromRecord,
RecordDecl *ToRecord, bool Complain) {
+ // Eliminate a potential failure point where we attempt to re-import
+ // something we're trying to import while completing ToRecord.
+ Decl *ToOrigin = Importer.GetOriginalDecl(ToRecord);
+ if (ToOrigin) {
+ RecordDecl *ToOriginRecord = dyn_cast<RecordDecl>(ToOrigin);
+ if (ToOriginRecord)
+ ToRecord = ToOriginRecord;
+ }
+
StructuralEquivalenceContext Ctx(Importer.getFromContext(),
- Importer.getToContext(),
+ ToRecord->getASTContext(),
Importer.getNonEquivalentDecls(),
false, Complain);
return Ctx.IsStructurallyEquivalent(FromRecord, ToRecord);
}
+bool ASTNodeImporter::IsStructuralMatch(VarDecl *FromVar, VarDecl *ToVar,
+ bool Complain) {
+ StructuralEquivalenceContext Ctx(
+ Importer.getFromContext(), Importer.getToContext(),
+ Importer.getNonEquivalentDecls(), false, Complain);
+ return Ctx.IsStructurallyEquivalent(FromVar, ToVar);
+}
+
bool ASTNodeImporter::IsStructuralMatch(EnumDecl *FromEnum, EnumDecl *ToEnum) {
StructuralEquivalenceContext Ctx(Importer.getFromContext(),
Importer.getToContext(),
@@ -2181,6 +2225,14 @@ bool ASTNodeImporter::IsStructuralMatch(ClassTemplateDecl *From,
return Ctx.IsStructurallyEquivalent(From, To);
}
+bool ASTNodeImporter::IsStructuralMatch(VarTemplateDecl *From,
+ VarTemplateDecl *To) {
+ StructuralEquivalenceContext Ctx(Importer.getFromContext(),
+ Importer.getToContext(),
+ Importer.getNonEquivalentDecls());
+ return Ctx.IsStructurallyEquivalent(From, To);
+}
+
Decl *ASTNodeImporter::VisitDecl(Decl *D) {
Importer.FromDiag(D->getLocation(), diag::err_unsupported_ast_node)
<< D->getDeclKindName();
@@ -2610,8 +2662,8 @@ Decl *ASTNodeImporter::VisitFunctionDecl(FunctionDecl *D) {
continue;
if (FunctionDecl *FoundFunction = dyn_cast<FunctionDecl>(FoundDecls[I])) {
- if (isExternalLinkage(FoundFunction->getLinkage()) &&
- isExternalLinkage(D->getLinkage())) {
+ if (FoundFunction->hasExternalFormalLinkage() &&
+ D->hasExternalFormalLinkage()) {
if (Importer.IsStructurallyEquivalent(D->getType(),
FoundFunction->getType())) {
// FIXME: Actually try to merge the body and other attributes.
@@ -2664,10 +2716,7 @@ Decl *ASTNodeImporter::VisitFunctionDecl(FunctionDecl *D) {
FromEPI.NoexceptExpr) {
FunctionProtoType::ExtProtoInfo DefaultEPI;
FromTy = Importer.getFromContext().getFunctionType(
- FromFPT->getResultType(),
- ArrayRef<QualType>(FromFPT->arg_type_begin(),
- FromFPT->getNumArgs()),
- DefaultEPI);
+ FromFPT->getResultType(), FromFPT->getArgTypes(), DefaultEPI);
usedDifferentExceptionSpec = true;
}
}
@@ -2878,7 +2927,7 @@ Decl *ASTNodeImporter::VisitIndirectFieldDecl(IndirectFieldDecl *D) {
if (Importer.IsStructurallyEquivalent(D->getType(),
FoundField->getType(),
- Name)) {
+ !Name.isEmpty())) {
Importer.Imported(D, FoundField);
return FoundField;
}
@@ -2965,7 +3014,8 @@ Decl *ASTNodeImporter::VisitObjCIvarDecl(ObjCIvarDecl *D) {
Importer.Import(D->getInnerLocStart()),
Loc, Name.getAsIdentifierInfo(),
T, TInfo, D->getAccessControl(),
- BitWidth, D->getSynthesize());
+ BitWidth, D->getSynthesize(),
+ D->getBackingIvarReferencedInAccessor());
ToIvar->setLexicalDeclContext(LexicalDC);
Importer.Imported(D, ToIvar);
LexicalDC->addDeclInternal(ToIvar);
@@ -2995,8 +3045,8 @@ Decl *ASTNodeImporter::VisitVarDecl(VarDecl *D) {
if (VarDecl *FoundVar = dyn_cast<VarDecl>(FoundDecls[I])) {
// We have found a variable that we may need to merge with. Check it.
- if (isExternalLinkage(FoundVar->getLinkage()) &&
- isExternalLinkage(D->getLinkage())) {
+ if (FoundVar->hasExternalFormalLinkage() &&
+ D->hasExternalFormalLinkage()) {
if (Importer.IsStructurallyEquivalent(D->getType(),
FoundVar->getType())) {
MergeWithVar = FoundVar;
@@ -3088,13 +3138,9 @@ Decl *ASTNodeImporter::VisitVarDecl(VarDecl *D) {
LexicalDC->addDeclInternal(ToVar);
// Merge the initializer.
- // FIXME: Can we really import any initializer? Alternatively, we could force
- // ourselves to import every declaration of a variable and then only use
- // getInit() here.
- ToVar->setInit(Importer.Import(const_cast<Expr *>(D->getAnyInitializer())));
+ if (ImportDefinition(D, ToVar))
+ return 0;
- // FIXME: Other bits to merge?
-
return ToVar;
}
@@ -4108,6 +4154,205 @@ Decl *ASTNodeImporter::VisitClassTemplateSpecializationDecl(
return D2;
}
+Decl *ASTNodeImporter::VisitVarTemplateDecl(VarTemplateDecl *D) {
+ // If this variable has a definition in the translation unit we're coming
+ // from,
+ // but this particular declaration is not that definition, import the
+ // definition and map to that.
+ VarDecl *Definition =
+ cast_or_null<VarDecl>(D->getTemplatedDecl()->getDefinition());
+ if (Definition && Definition != D->getTemplatedDecl()) {
+ Decl *ImportedDef = Importer.Import(Definition->getDescribedVarTemplate());
+ if (!ImportedDef)
+ return 0;
+
+ return Importer.Imported(D, ImportedDef);
+ }
+
+ // Import the major distinguishing characteristics of this variable template.
+ DeclContext *DC, *LexicalDC;
+ DeclarationName Name;
+ SourceLocation Loc;
+ if (ImportDeclParts(D, DC, LexicalDC, Name, Loc))
+ return 0;
+
+ // We may already have a template of the same name; try to find and match it.
+ assert(!DC->isFunctionOrMethod() &&
+ "Variable templates cannot be declared at function scope");
+ SmallVector<NamedDecl *, 4> ConflictingDecls;
+ SmallVector<NamedDecl *, 2> FoundDecls;
+ DC->localUncachedLookup(Name, FoundDecls);
+ for (unsigned I = 0, N = FoundDecls.size(); I != N; ++I) {
+ if (!FoundDecls[I]->isInIdentifierNamespace(Decl::IDNS_Ordinary))
+ continue;
+
+ Decl *Found = FoundDecls[I];
+ if (VarTemplateDecl *FoundTemplate = dyn_cast<VarTemplateDecl>(Found)) {
+ if (IsStructuralMatch(D, FoundTemplate)) {
+ // The variable templates structurally match; call it the same template.
+ Importer.Imported(D->getTemplatedDecl(),
+ FoundTemplate->getTemplatedDecl());
+ return Importer.Imported(D, FoundTemplate);
+ }
+ }
+
+ ConflictingDecls.push_back(FoundDecls[I]);
+ }
+
+ if (!ConflictingDecls.empty()) {
+ Name = Importer.HandleNameConflict(Name, DC, Decl::IDNS_Ordinary,
+ ConflictingDecls.data(),
+ ConflictingDecls.size());
+ }
+
+ if (!Name)
+ return 0;
+
+ VarDecl *DTemplated = D->getTemplatedDecl();
+
+ // Import the type.
+ QualType T = Importer.Import(DTemplated->getType());
+ if (T.isNull())
+ return 0;
+
+ // Create the declaration that is being templated.
+ SourceLocation StartLoc = Importer.Import(DTemplated->getLocStart());
+ SourceLocation IdLoc = Importer.Import(DTemplated->getLocation());
+ TypeSourceInfo *TInfo = Importer.Import(DTemplated->getTypeSourceInfo());
+ VarDecl *D2Templated = VarDecl::Create(Importer.getToContext(), DC, StartLoc,
+ IdLoc, Name.getAsIdentifierInfo(), T,
+ TInfo, DTemplated->getStorageClass());
+ D2Templated->setAccess(DTemplated->getAccess());
+ D2Templated->setQualifierInfo(Importer.Import(DTemplated->getQualifierLoc()));
+ D2Templated->setLexicalDeclContext(LexicalDC);
+
+ // Importer.Imported(DTemplated, D2Templated);
+ // LexicalDC->addDeclInternal(D2Templated);
+
+ // Merge the initializer.
+ if (ImportDefinition(DTemplated, D2Templated))
+ return 0;
+
+ // Create the variable template declaration itself.
+ TemplateParameterList *TemplateParams =
+ ImportTemplateParameterList(D->getTemplateParameters());
+ if (!TemplateParams)
+ return 0;
+
+ VarTemplateDecl *D2 = VarTemplateDecl::Create(
+ Importer.getToContext(), DC, Loc, Name, TemplateParams, D2Templated,
+ /*PrevDecl=*/0);
+ D2Templated->setDescribedVarTemplate(D2);
+
+ D2->setAccess(D->getAccess());
+ D2->setLexicalDeclContext(LexicalDC);
+ LexicalDC->addDeclInternal(D2);
+
+ // Note the relationship between the variable templates.
+ Importer.Imported(D, D2);
+ Importer.Imported(DTemplated, D2Templated);
+
+ if (DTemplated->isThisDeclarationADefinition() &&
+ !D2Templated->isThisDeclarationADefinition()) {
+ // FIXME: Import definition!
+ }
+
+ return D2;
+}
+
+Decl *ASTNodeImporter::VisitVarTemplateSpecializationDecl(
+ VarTemplateSpecializationDecl *D) {
+ // If this record has a definition in the translation unit we're coming from,
+ // but this particular declaration is not that definition, import the
+ // definition and map to that.
+ VarDecl *Definition = D->getDefinition();
+ if (Definition && Definition != D) {
+ Decl *ImportedDef = Importer.Import(Definition);
+ if (!ImportedDef)
+ return 0;
+
+ return Importer.Imported(D, ImportedDef);
+ }
+
+ VarTemplateDecl *VarTemplate = cast_or_null<VarTemplateDecl>(
+ Importer.Import(D->getSpecializedTemplate()));
+ if (!VarTemplate)
+ return 0;
+
+ // Import the context of this declaration.
+ DeclContext *DC = VarTemplate->getDeclContext();
+ if (!DC)
+ return 0;
+
+ DeclContext *LexicalDC = DC;
+ if (D->getDeclContext() != D->getLexicalDeclContext()) {
+ LexicalDC = Importer.ImportContext(D->getLexicalDeclContext());
+ if (!LexicalDC)
+ return 0;
+ }
+
+ // Import the location of this declaration.
+ SourceLocation StartLoc = Importer.Import(D->getLocStart());
+ SourceLocation IdLoc = Importer.Import(D->getLocation());
+
+ // Import template arguments.
+ SmallVector<TemplateArgument, 2> TemplateArgs;
+ if (ImportTemplateArguments(D->getTemplateArgs().data(),
+ D->getTemplateArgs().size(), TemplateArgs))
+ return 0;
+
+ // Try to find an existing specialization with these template arguments.
+ void *InsertPos = 0;
+ VarTemplateSpecializationDecl *D2 = VarTemplate->findSpecialization(
+ TemplateArgs.data(), TemplateArgs.size(), InsertPos);
+ if (D2) {
+ // We already have a variable template specialization with these template
+ // arguments.
+
+ // FIXME: Check for specialization vs. instantiation errors.
+
+ if (VarDecl *FoundDef = D2->getDefinition()) {
+ if (!D->isThisDeclarationADefinition() ||
+ IsStructuralMatch(D, FoundDef)) {
+ // The record types structurally match, or the "from" translation
+ // unit only had a forward declaration anyway; call it the same
+ // variable.
+ return Importer.Imported(D, FoundDef);
+ }
+ }
+ } else {
+
+ // Import the type.
+ QualType T = Importer.Import(D->getType());
+ if (T.isNull())
+ return 0;
+ TypeSourceInfo *TInfo = Importer.Import(D->getTypeSourceInfo());
+
+ // Create a new specialization.
+ D2 = VarTemplateSpecializationDecl::Create(
+ Importer.getToContext(), DC, StartLoc, IdLoc, VarTemplate, T, TInfo,
+ D->getStorageClass(), TemplateArgs.data(), TemplateArgs.size());
+ D2->setSpecializationKind(D->getSpecializationKind());
+ D2->setTemplateArgsInfo(D->getTemplateArgsInfo());
+
+ // Add this specialization to the class template.
+ VarTemplate->AddSpecialization(D2, InsertPos);
+
+ // Import the qualifier, if any.
+ D2->setQualifierInfo(Importer.Import(D->getQualifierLoc()));
+
+ // Add the specialization to this context.
+ D2->setLexicalDeclContext(LexicalDC);
+ LexicalDC->addDeclInternal(D2);
+ }
+ Importer.Imported(D, D2);
+
+ if (D->isThisDeclarationADefinition() && ImportDefinition(D, D2))
+ return 0;
+
+ return D2;
+}
+
//----------------------------------------------------------------------------
// Import Statements
//----------------------------------------------------------------------------
@@ -4406,7 +4651,7 @@ Decl *ASTImporter::Import(Decl *FromD) {
} else if (TypedefNameDecl *FromTypedef = dyn_cast<TypedefNameDecl>(FromD)) {
// When we've finished transforming a typedef, see whether it was the
// typedef for an anonymous tag.
- for (SmallVector<TagDecl *, 4>::iterator
+ for (SmallVectorImpl<TagDecl *>::iterator
FromTag = AnonTagsWithPendingTypedefs.begin(),
FromTagEnd = AnonTagsWithPendingTypedefs.end();
FromTag != FromTagEnd; ++FromTag) {
diff --git a/lib/AST/ASTTypeTraits.cpp b/lib/AST/ASTTypeTraits.cpp
new file mode 100644
index 000000000000..ae47ea98882b
--- /dev/null
+++ b/lib/AST/ASTTypeTraits.cpp
@@ -0,0 +1,105 @@
+//===--- ASTTypeTraits.cpp --------------------------------------*- C++ -*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+//
+// Provides a dynamic type identifier and a dynamically typed node container
+// that can be used to store an AST base node at runtime in the same storage in
+// a type safe way.
+//
+//===----------------------------------------------------------------------===//
+
+#include "clang/AST/ASTTypeTraits.h"
+#include "clang/AST/ASTContext.h"
+#include "clang/AST/DeclCXX.h"
+
+namespace clang {
+namespace ast_type_traits {
+
+const ASTNodeKind::KindInfo ASTNodeKind::AllKindInfo[] = {
+ { NKI_None, "<None>" },
+ { NKI_None, "CXXCtorInitializer" },
+ { NKI_None, "TemplateArgument" },
+ { NKI_None, "NestedNameSpecifier" },
+ { NKI_None, "NestedNameSpecifierLoc" },
+ { NKI_None, "QualType" },
+ { NKI_None, "TypeLoc" },
+ { NKI_None, "Decl" },
+#define DECL(DERIVED, BASE) { NKI_##BASE, #DERIVED "Decl" },
+#include "clang/AST/DeclNodes.inc"
+ { NKI_None, "Stmt" },
+#define STMT(DERIVED, BASE) { NKI_##BASE, #DERIVED },
+#include "clang/AST/StmtNodes.inc"
+ { NKI_None, "Type" },
+#define TYPE(DERIVED, BASE) { NKI_##BASE, #DERIVED "Type" },
+#include "clang/AST/TypeNodes.def"
+};
+
+bool ASTNodeKind::isBaseOf(ASTNodeKind Other) const {
+ return isBaseOf(KindId, Other.KindId);
+}
+
+bool ASTNodeKind::isSame(ASTNodeKind Other) const {
+ return KindId != NKI_None && KindId == Other.KindId;
+}
+
+bool ASTNodeKind::isBaseOf(NodeKindId Base, NodeKindId Derived) {
+ if (Base == NKI_None || Derived == NKI_None) return false;
+ while (Derived != Base && Derived != NKI_None)
+ Derived = AllKindInfo[Derived].ParentId;
+ return Derived == Base;
+}
+
+StringRef ASTNodeKind::asStringRef() const { return AllKindInfo[KindId].Name; }
+
+void DynTypedNode::print(llvm::raw_ostream &OS,
+ const PrintingPolicy &PP) const {
+ if (const TemplateArgument *TA = get<TemplateArgument>())
+ TA->print(PP, OS);
+ else if (const NestedNameSpecifier *NNS = get<NestedNameSpecifier>())
+ NNS->print(OS, PP);
+ else if (const NestedNameSpecifierLoc *NNSL = get<NestedNameSpecifierLoc>())
+ NNSL->getNestedNameSpecifier()->print(OS, PP);
+ else if (const QualType *QT = get<QualType>())
+ QT->print(OS, PP);
+ else if (const TypeLoc *TL = get<TypeLoc>())
+ TL->getType().print(OS, PP);
+ else if (const Decl *D = get<Decl>())
+ D->print(OS, PP);
+ else if (const Stmt *S = get<Stmt>())
+ S->printPretty(OS, 0, PP);
+ else if (const Type *T = get<Type>())
+ QualType(T, 0).print(OS, PP);
+ else
+ OS << "Unable to print values of type " << NodeKind.asStringRef() << "\n";
+}
+
+void DynTypedNode::dump(llvm::raw_ostream &OS, SourceManager &SM) const {
+ if (const Decl *D = get<Decl>())
+ D->dump(OS);
+ else if (const Stmt *S = get<Stmt>())
+ S->dump(OS, SM);
+ else
+ OS << "Unable to dump values of type " << NodeKind.asStringRef() << "\n";
+}
+
+SourceRange DynTypedNode::getSourceRange() const {
+ if (const CXXCtorInitializer *CCI = get<CXXCtorInitializer>())
+ return CCI->getSourceRange();
+ if (const NestedNameSpecifierLoc *NNSL = get<NestedNameSpecifierLoc>())
+ return NNSL->getSourceRange();
+ if (const TypeLoc *TL = get<TypeLoc>())
+ return TL->getSourceRange();
+ if (const Decl *D = get<Decl>())
+ return D->getSourceRange();
+ if (const Stmt *S = get<Stmt>())
+ return S->getSourceRange();
+ return SourceRange();
+}
+
+} // end namespace ast_type_traits
+} // end namespace clang
diff --git a/lib/AST/AttrImpl.cpp b/lib/AST/AttrImpl.cpp
index daf65e56bdc6..7af3c8b16263 100644
--- a/lib/AST/AttrImpl.cpp
+++ b/lib/AST/AttrImpl.cpp
@@ -15,6 +15,7 @@
#include "clang/AST/ASTContext.h"
#include "clang/AST/Expr.h"
#include "clang/AST/Type.h"
+#include "llvm/ADT/StringSwitch.h"
using namespace clang;
Attr::~Attr() { }
diff --git a/lib/AST/CMakeLists.txt b/lib/AST/CMakeLists.txt
index e804fe720558..461e8b3ac18e 100644
--- a/lib/AST/CMakeLists.txt
+++ b/lib/AST/CMakeLists.txt
@@ -7,6 +7,7 @@ add_clang_library(clangAST
ASTDiagnostic.cpp
ASTDumper.cpp
ASTImporter.cpp
+ ASTTypeTraits.cpp
AttrImpl.cpp
CXXInheritance.cpp
Comment.cpp
@@ -25,7 +26,6 @@ add_clang_library(clangAST
DeclOpenMP.cpp
DeclPrinter.cpp
DeclTemplate.cpp
- DumpXML.cpp
Expr.cpp
ExprClassification.cpp
ExprConstant.cpp
@@ -34,8 +34,8 @@ add_clang_library(clangAST
InheritViz.cpp
ItaniumCXXABI.cpp
ItaniumMangle.cpp
- LambdaMangleContext.cpp
Mangle.cpp
+ MangleNumberingContext.cpp
MicrosoftCXXABI.cpp
MicrosoftMangle.cpp
NestedNameSpecifier.cpp
diff --git a/lib/AST/CXXABI.h b/lib/AST/CXXABI.h
index 6d67d9a12b55..89203f18ca77 100644
--- a/lib/AST/CXXABI.h
+++ b/lib/AST/CXXABI.h
@@ -21,6 +21,7 @@ namespace clang {
class ASTContext;
class MemberPointerType;
+class MangleNumberingContext;
/// Implements C++ ABI-specific semantic analysis functions.
class CXXABI {
@@ -34,9 +35,12 @@ public:
/// Returns the default calling convention for C++ methods.
virtual CallingConv getDefaultMethodCallConv(bool isVariadic) const = 0;
- // Returns whether the given class is nearly empty, with just virtual pointers
- // and no data except possibly virtual bases.
+ /// Returns whether the given class is nearly empty, with just virtual
+ /// pointers and no data except possibly virtual bases.
virtual bool isNearlyEmpty(const CXXRecordDecl *RD) const = 0;
+
+ /// Returns a new mangling number context for this C++ ABI.
+ virtual MangleNumberingContext *createMangleNumberingContext() const = 0;
};
/// Creates an instance of a C++ ABI class.
diff --git a/lib/AST/CXXInheritance.cpp b/lib/AST/CXXInheritance.cpp
index 0e0b35d92adf..b51014b7428f 100644
--- a/lib/AST/CXXInheritance.cpp
+++ b/lib/AST/CXXInheritance.cpp
@@ -168,9 +168,9 @@ bool CXXRecordDecl::forallBases(ForallBasesCallback *BaseMatches,
}
}
- if (Queue.empty()) break;
- Record = Queue.back(); // not actually a queue.
- Queue.pop_back();
+ if (Queue.empty())
+ break;
+ Record = Queue.pop_back_val(); // not actually a queue.
}
return AllMatches;
@@ -447,7 +447,7 @@ FindNestedNameSpecifierMember(const CXXBaseSpecifier *Specifier,
void OverridingMethods::add(unsigned OverriddenSubobject,
UniqueVirtualMethod Overriding) {
- SmallVector<UniqueVirtualMethod, 4> &SubobjectOverrides
+ SmallVectorImpl<UniqueVirtualMethod> &SubobjectOverrides
= Overrides[OverriddenSubobject];
if (std::find(SubobjectOverrides.begin(), SubobjectOverrides.end(),
Overriding) == SubobjectOverrides.end())
@@ -650,11 +650,11 @@ CXXRecordDecl::getFinalOverriders(CXXFinalOverriderMap &FinalOverriders) const {
SOEnd = OM->second.end();
SO != SOEnd;
++SO) {
- SmallVector<UniqueVirtualMethod, 4> &Overriding = SO->second;
+ SmallVectorImpl<UniqueVirtualMethod> &Overriding = SO->second;
if (Overriding.size() < 2)
continue;
- for (SmallVector<UniqueVirtualMethod, 4>::iterator
+ for (SmallVectorImpl<UniqueVirtualMethod>::iterator
Pos = Overriding.begin(), PosEnd = Overriding.end();
Pos != PosEnd;
/* increment in loop */) {
@@ -669,7 +669,7 @@ CXXRecordDecl::getFinalOverriders(CXXFinalOverriderMap &FinalOverriders) const {
// in a base class subobject that hides the virtual base class
// subobject.
bool Hidden = false;
- for (SmallVector<UniqueVirtualMethod, 4>::iterator
+ for (SmallVectorImpl<UniqueVirtualMethod>::iterator
OP = Overriding.begin(), OPEnd = Overriding.end();
OP != OPEnd && !Hidden;
++OP) {
diff --git a/lib/AST/Comment.cpp b/lib/AST/Comment.cpp
index 68c73fd48e3c..f24a23d34c57 100644
--- a/lib/AST/Comment.cpp
+++ b/lib/AST/Comment.cpp
@@ -12,6 +12,7 @@
#include "clang/AST/Decl.h"
#include "clang/AST/DeclObjC.h"
#include "clang/AST/DeclTemplate.h"
+#include "clang/Basic/CharInfo.h"
#include "llvm/Support/ErrorHandling.h"
#include "llvm/Support/raw_ostream.h"
@@ -41,14 +42,16 @@ good implements_child_begin_end(Comment::child_iterator (T::*)() const) {
return good();
}
+LLVM_ATTRIBUTE_UNUSED
static inline bad implements_child_begin_end(
Comment::child_iterator (Comment::*)() const) {
return bad();
}
#define ASSERT_IMPLEMENTS_child_begin(function) \
- (void) sizeof(good(implements_child_begin_end(function)))
+ (void) good(implements_child_begin_end(function))
+LLVM_ATTRIBUTE_UNUSED
static inline void CheckCommentASTNodes() {
#define ABSTRACT_COMMENT(COMMENT)
#define COMMENT(CLASS, PARENT) \
@@ -94,9 +97,7 @@ Comment::child_iterator Comment::child_end() const {
bool TextComment::isWhitespaceNoCache() const {
for (StringRef::const_iterator I = Text.begin(), E = Text.end();
I != E; ++I) {
- const char C = *I;
- if (C != ' ' && C != '\n' && C != '\r' &&
- C != '\t' && C != '\f' && C != '\v')
+ if (!clang::isWhitespace(*I))
return false;
}
return true;
@@ -293,12 +294,14 @@ void DeclInfo::fill() {
StringRef ParamCommandComment::getParamName(const FullComment *FC) const {
assert(isParamIndexValid());
- return FC->getThisDeclInfo()->ParamVars[getParamIndex()]->getName();
+ if (isVarArgParam())
+ return "...";
+ return FC->getDeclInfo()->ParamVars[getParamIndex()]->getName();
}
StringRef TParamCommandComment::getParamName(const FullComment *FC) const {
assert(isPositionValid());
- const TemplateParameterList *TPL = FC->getThisDeclInfo()->TemplateParameters;
+ const TemplateParameterList *TPL = FC->getDeclInfo()->TemplateParameters;
for (unsigned i = 0, e = getDepth(); i != e; ++i) {
if (i == e-1)
return TPL->getParam(getIndex(i))->getName();
diff --git a/lib/AST/CommentCommandTraits.cpp b/lib/AST/CommentCommandTraits.cpp
index e24d542c9623..01bd12e5fefa 100644
--- a/lib/AST/CommentCommandTraits.cpp
+++ b/lib/AST/CommentCommandTraits.cpp
@@ -43,6 +43,49 @@ const CommandInfo *CommandTraits::getCommandInfo(unsigned CommandID) const {
return getRegisteredCommandInfo(CommandID);
}
+static void
+HelperTypoCorrectCommandInfo(SmallVectorImpl<const CommandInfo *> &BestCommand,
+ StringRef Typo, const CommandInfo *Command) {
+ const unsigned MaxEditDistance = 1;
+ unsigned BestEditDistance = MaxEditDistance + 1;
+ StringRef Name = Command->Name;
+
+ unsigned MinPossibleEditDistance = abs((int)Name.size() - (int)Typo.size());
+ if (MinPossibleEditDistance > 0 &&
+ Typo.size() / MinPossibleEditDistance < 1)
+ return;
+ unsigned EditDistance = Typo.edit_distance(Name, true, MaxEditDistance);
+ if (EditDistance > MaxEditDistance)
+ return;
+ if (EditDistance == BestEditDistance)
+ BestCommand.push_back(Command);
+ else if (EditDistance < BestEditDistance) {
+ BestCommand.clear();
+ BestCommand.push_back(Command);
+ BestEditDistance = EditDistance;
+ }
+}
+
+const CommandInfo *
+CommandTraits::getTypoCorrectCommandInfo(StringRef Typo) const {
+ // single character command impostures, such as \t or \n must not go
+ // through the fixit logic.
+ if (Typo.size() <= 1)
+ return NULL;
+
+ SmallVector<const CommandInfo *, 2> BestCommand;
+
+ const int NumOfCommands = llvm::array_lengthof(Commands);
+ for (int i = 0; i < NumOfCommands; i++)
+ HelperTypoCorrectCommandInfo(BestCommand, Typo, &Commands[i]);
+
+ for (unsigned i = 0, e = RegisteredCommands.size(); i != e; ++i)
+ if (!RegisteredCommands[i]->IsUnknownCommand)
+ HelperTypoCorrectCommandInfo(BestCommand, Typo, RegisteredCommands[i]);
+
+ return (BestCommand.size() != 1) ? NULL : BestCommand[0];
+}
+
CommandInfo *CommandTraits::createCommandInfoWithName(StringRef CommandName) {
char *Name = Allocator.Allocate<char>(CommandName.size() + 1);
memcpy(Name, CommandName.data(), CommandName.size());
diff --git a/lib/AST/CommentLexer.cpp b/lib/AST/CommentLexer.cpp
index 70410d61085d..01ed3ce80a66 100644
--- a/lib/AST/CommentLexer.cpp
+++ b/lib/AST/CommentLexer.cpp
@@ -157,7 +157,7 @@ const char *skipDecimalCharacterReference(const char *BufferPtr,
}
const char *skipHexCharacterReference(const char *BufferPtr,
- const char *BufferEnd) {
+ const char *BufferEnd) {
for ( ; BufferPtr != BufferEnd; ++BufferPtr) {
if (!isHTMLHexCharacterReferenceCharacter(*BufferPtr))
return BufferPtr;
@@ -265,6 +265,7 @@ const char *findCCommentEnd(const char *BufferPtr, const char *BufferEnd) {
}
llvm_unreachable("buffer end hit before '*/' was seen");
}
+
} // unnamed namespace
void Lexer::lexCommentText(Token &T) {
@@ -352,10 +353,20 @@ void Lexer::lexCommentText(Token &T) {
const CommandInfo *Info = Traits.getCommandInfoOrNULL(CommandName);
if (!Info) {
- formTokenWithChars(T, TokenPtr, tok::unknown_command);
- T.setUnknownCommandName(CommandName);
- Diag(T.getLocation(), diag::warn_unknown_comment_command_name);
- return;
+ if ((Info = Traits.getTypoCorrectCommandInfo(CommandName))) {
+ StringRef CorrectedName = Info->Name;
+ SourceLocation Loc = getSourceLocation(BufferPtr);
+ SourceRange CommandRange(Loc.getLocWithOffset(1),
+ getSourceLocation(TokenPtr));
+ Diag(Loc, diag::warn_correct_comment_command_name)
+ << CommandName << CorrectedName
+ << FixItHint::CreateReplacement(CommandRange, CorrectedName);
+ } else {
+ formTokenWithChars(T, TokenPtr, tok::unknown_command);
+ T.setUnknownCommandName(CommandName);
+ Diag(T.getLocation(), diag::warn_unknown_comment_command_name);
+ return;
+ }
}
if (Info->IsVerbatimBlockCommand) {
setupAndLexVerbatimBlock(T, TokenPtr, *BufferPtr, Info);
diff --git a/lib/AST/CommentParser.cpp b/lib/AST/CommentParser.cpp
index d89c79b3d93d..03e01015b954 100644
--- a/lib/AST/CommentParser.cpp
+++ b/lib/AST/CommentParser.cpp
@@ -16,6 +16,15 @@
#include "llvm/Support/ErrorHandling.h"
namespace clang {
+
+static inline bool isWhitespace(llvm::StringRef S) {
+ for (StringRef::const_iterator I = S.begin(), E = S.end(); I != E; ++I) {
+ if (!isWhitespace(*I))
+ return false;
+ }
+ return true;
+}
+
namespace comments {
/// Re-lexes a sequence of tok::text tokens.
@@ -594,6 +603,18 @@ BlockContentComment *Parser::parseParagraphOrBlockCommand() {
consumeToken();
break; // Two newlines -- end of paragraph.
}
+ // Also allow [tok::newline, tok::text, tok::newline] if the middle
+ // tok::text is just whitespace.
+ if (Tok.is(tok::text) && isWhitespace(Tok.getText())) {
+ Token WhitespaceTok = Tok;
+ consumeToken();
+ if (Tok.is(tok::newline) || Tok.is(tok::eof)) {
+ consumeToken();
+ break;
+ }
+ // We have [tok::newline, tok::text, non-newline]. Put back tok::text.
+ putBack(WhitespaceTok);
+ }
if (Content.size() > 0)
Content.back()->addTrailingNewline();
continue;
diff --git a/lib/AST/CommentSema.cpp b/lib/AST/CommentSema.cpp
index e0138d5f3f27..1c6222f9ec02 100644
--- a/lib/AST/CommentSema.cpp
+++ b/lib/AST/CommentSema.cpp
@@ -29,8 +29,7 @@ Sema::Sema(llvm::BumpPtrAllocator &Allocator, const SourceManager &SourceMgr,
DiagnosticsEngine &Diags, CommandTraits &Traits,
const Preprocessor *PP) :
Allocator(Allocator), SourceMgr(SourceMgr), Diags(Diags), Traits(Traits),
- PP(PP), ThisDeclInfo(NULL), BriefCommand(NULL), ReturnsCommand(NULL),
- HeaderfileCommand(NULL) {
+ PP(PP), ThisDeclInfo(NULL), BriefCommand(NULL), HeaderfileCommand(NULL) {
}
void Sema::setDecl(const Decl *D) {
@@ -99,10 +98,10 @@ void Sema::checkFunctionDeclVerbatimLine(const BlockCommandComment *Comment) {
unsigned DiagSelect;
switch (Comment->getCommandID()) {
case CommandTraits::KCI_function:
- DiagSelect = !isAnyFunctionDecl() ? 1 : 0;
+ DiagSelect = (!isAnyFunctionDecl() && !isFunctionTemplateDecl())? 1 : 0;
break;
case CommandTraits::KCI_functiongroup:
- DiagSelect = !isAnyFunctionDecl() ? 2 : 0;
+ DiagSelect = (!isAnyFunctionDecl() && !isFunctionTemplateDecl())? 2 : 0;
break;
case CommandTraits::KCI_method:
DiagSelect = !isObjCMethodDecl() ? 3 : 0;
@@ -131,7 +130,12 @@ void Sema::checkContainerDeclVerbatimLine(const BlockCommandComment *Comment) {
unsigned DiagSelect;
switch (Comment->getCommandID()) {
case CommandTraits::KCI_class:
- DiagSelect = !isClassOrStructDecl() ? 1 : 0;
+ DiagSelect = (!isClassOrStructDecl() && !isClassTemplateDecl()) ? 1 : 0;
+ // Allow @class command on @interface declarations.
+ // FIXME. Currently, \class and @class are indistinguishable. So,
+ // \class is also allowed on an @interface declaration
+ if (DiagSelect && Comment->getCommandMarker() && isObjCInterfaceDecl())
+ DiagSelect = 0;
break;
case CommandTraits::KCI_interface:
DiagSelect = !isObjCInterfaceDecl() ? 2 : 0;
@@ -206,59 +210,43 @@ void Sema::checkContainerDecl(const BlockCommandComment *Comment) {
<< Comment->getSourceRange();
}
+/// \brief Turn a string into the corresponding PassDirection or -1 if it's not
+/// valid.
+static int getParamPassDirection(StringRef Arg) {
+ return llvm::StringSwitch<int>(Arg)
+ .Case("[in]", ParamCommandComment::In)
+ .Case("[out]", ParamCommandComment::Out)
+ .Cases("[in,out]", "[out,in]", ParamCommandComment::InOut)
+ .Default(-1);
+}
+
void Sema::actOnParamCommandDirectionArg(ParamCommandComment *Command,
SourceLocation ArgLocBegin,
SourceLocation ArgLocEnd,
StringRef Arg) {
- ParamCommandComment::PassDirection Direction;
std::string ArgLower = Arg.lower();
- // TODO: optimize: lower Name first (need an API in SmallString for that),
- // after that StringSwitch.
- if (ArgLower == "[in]")
- Direction = ParamCommandComment::In;
- else if (ArgLower == "[out]")
- Direction = ParamCommandComment::Out;
- else if (ArgLower == "[in,out]" || ArgLower == "[out,in]")
- Direction = ParamCommandComment::InOut;
- else {
- // Remove spaces.
- std::string::iterator O = ArgLower.begin();
- for (std::string::iterator I = ArgLower.begin(), E = ArgLower.end();
- I != E; ++I) {
- const char C = *I;
- if (C != ' ' && C != '\n' && C != '\r' &&
- C != '\t' && C != '\v' && C != '\f')
- *O++ = C;
- }
- ArgLower.resize(O - ArgLower.begin());
-
- bool RemovingWhitespaceHelped = false;
- if (ArgLower == "[in]") {
- Direction = ParamCommandComment::In;
- RemovingWhitespaceHelped = true;
- } else if (ArgLower == "[out]") {
- Direction = ParamCommandComment::Out;
- RemovingWhitespaceHelped = true;
- } else if (ArgLower == "[in,out]" || ArgLower == "[out,in]") {
- Direction = ParamCommandComment::InOut;
- RemovingWhitespaceHelped = true;
- } else {
- Direction = ParamCommandComment::In;
- RemovingWhitespaceHelped = false;
- }
+ int Direction = getParamPassDirection(ArgLower);
+
+ if (Direction == -1) {
+ // Try again with whitespace removed.
+ ArgLower.erase(
+ std::remove_if(ArgLower.begin(), ArgLower.end(), clang::isWhitespace),
+ ArgLower.end());
+ Direction = getParamPassDirection(ArgLower);
SourceRange ArgRange(ArgLocBegin, ArgLocEnd);
- if (RemovingWhitespaceHelped)
+ if (Direction != -1) {
+ const char *FixedName = ParamCommandComment::getDirectionAsString(
+ (ParamCommandComment::PassDirection)Direction);
Diag(ArgLocBegin, diag::warn_doc_param_spaces_in_direction)
- << ArgRange
- << FixItHint::CreateReplacement(
- ArgRange,
- ParamCommandComment::getDirectionAsString(Direction));
- else
- Diag(ArgLocBegin, diag::warn_doc_param_invalid_direction)
- << ArgRange;
+ << ArgRange << FixItHint::CreateReplacement(ArgRange, FixedName);
+ } else {
+ Diag(ArgLocBegin, diag::warn_doc_param_invalid_direction) << ArgRange;
+ Direction = ParamCommandComment::In; // Sane fall back.
+ }
}
- Command->setDirection(Direction, /* Explicit = */ true);
+ Command->setDirection((ParamCommandComment::PassDirection)Direction,
+ /*Explicit=*/true);
}
void Sema::actOnParamCommandParamNameArg(ParamCommandComment *Command,
@@ -326,17 +314,15 @@ void Sema::actOnTParamCommandParamNameArg(TParamCommandComment *Command,
SmallVector<unsigned, 2> Position;
if (resolveTParamReference(Arg, TemplateParameters, &Position)) {
Command->setPosition(copyArray(llvm::makeArrayRef(Position)));
- llvm::StringMap<TParamCommandComment *>::iterator PrevCommandIt =
- TemplateParameterDocs.find(Arg);
- if (PrevCommandIt != TemplateParameterDocs.end()) {
+ TParamCommandComment *&PrevCommand = TemplateParameterDocs[Arg];
+ if (PrevCommand) {
SourceRange ArgRange(ArgLocBegin, ArgLocEnd);
Diag(ArgLocBegin, diag::warn_doc_tparam_duplicate)
<< Arg << ArgRange;
- TParamCommandComment *PrevCommand = PrevCommandIt->second;
Diag(PrevCommand->getLocation(), diag::note_doc_tparam_previous)
<< PrevCommand->getParamNameRange();
}
- TemplateParameterDocs[Arg] = Command;
+ PrevCommand = Command;
return;
}
@@ -511,8 +497,7 @@ HTMLEndTagComment *Sema::actOnHTMLEndTag(SourceLocation LocBegin,
}
while (!HTMLOpenTags.empty()) {
- const HTMLStartTagComment *HST = HTMLOpenTags.back();
- HTMLOpenTags.pop_back();
+ const HTMLStartTagComment *HST = HTMLOpenTags.pop_back_val();
StringRef LastNotClosedTagName = HST->getTagName();
if (LastNotClosedTagName == TagName)
break;
@@ -618,12 +603,6 @@ void Sema::checkBlockCommandDuplicate(const BlockCommandComment *Command) {
return;
}
PrevCommand = BriefCommand;
- } else if (Info->IsReturnsCommand) {
- if (!ReturnsCommand) {
- ReturnsCommand = Command;
- return;
- }
- PrevCommand = ReturnsCommand;
} else if (Info->IsHeaderfileCommand) {
if (!HeaderfileCommand) {
HeaderfileCommand = Command;
@@ -728,6 +707,10 @@ void Sema::resolveParamCommandIndexes(const FullComment *FC) {
// Check that referenced parameter name is in the function decl.
const unsigned ResolvedParamIndex = resolveParmVarReference(ParamName,
ParamVars);
+ if (ResolvedParamIndex == ParamCommandComment::VarArgParamIndex) {
+ PCC->setIsVarArgParam();
+ continue;
+ }
if (ResolvedParamIndex == ParamCommandComment::InvalidParamIndex) {
UnresolvedParamCommands.push_back(PCC);
continue;
@@ -798,14 +781,24 @@ bool Sema::isAnyFunctionDecl() {
return isFunctionDecl() && ThisDeclInfo->CurrentDecl &&
isa<FunctionDecl>(ThisDeclInfo->CurrentDecl);
}
-
+
+bool Sema::isFunctionOrMethodVariadic() {
+ if (!isAnyFunctionDecl() && !isObjCMethodDecl())
+ return false;
+ if (const FunctionDecl *FD =
+ dyn_cast<FunctionDecl>(ThisDeclInfo->CurrentDecl))
+ return FD->isVariadic();
+ if (const ObjCMethodDecl *MD =
+ dyn_cast<ObjCMethodDecl>(ThisDeclInfo->CurrentDecl))
+ return MD->isVariadic();
+ return false;
+}
+
bool Sema::isObjCMethodDecl() {
return isFunctionDecl() && ThisDeclInfo->CurrentDecl &&
isa<ObjCMethodDecl>(ThisDeclInfo->CurrentDecl);
}
-
-/// isFunctionPointerVarDecl - returns 'true' if declaration is a pointer to
-/// function decl.
+
bool Sema::isFunctionPointerVarDecl() {
if (!ThisDeclInfo)
return false;
@@ -865,6 +858,24 @@ bool Sema::isClassOrStructDecl() {
isa<RecordDecl>(ThisDeclInfo->CurrentDecl) &&
!isUnionDecl();
}
+
+bool Sema::isClassTemplateDecl() {
+ if (!ThisDeclInfo)
+ return false;
+ if (!ThisDeclInfo->IsFilled)
+ inspectThisDecl();
+ return ThisDeclInfo->CurrentDecl &&
+ (isa<ClassTemplateDecl>(ThisDeclInfo->CurrentDecl));
+}
+
+bool Sema::isFunctionTemplateDecl() {
+ if (!ThisDeclInfo)
+ return false;
+ if (!ThisDeclInfo->IsFilled)
+ inspectThisDecl();
+ return ThisDeclInfo->CurrentDecl &&
+ (isa<FunctionTemplateDecl>(ThisDeclInfo->CurrentDecl));
+}
bool Sema::isObjCInterfaceDecl() {
if (!ThisDeclInfo)
@@ -901,6 +912,8 @@ unsigned Sema::resolveParmVarReference(StringRef Name,
if (II && II->getName() == Name)
return i;
}
+ if (Name == "..." && isFunctionOrMethodVariadic())
+ return ParamCommandComment::VarArgParamIndex;
return ParamCommandComment::InvalidParamIndex;
}
diff --git a/lib/AST/Decl.cpp b/lib/AST/Decl.cpp
index ab9d73b9178e..6bd985851a39 100644
--- a/lib/AST/Decl.cpp
+++ b/lib/AST/Decl.cpp
@@ -34,6 +34,10 @@
using namespace clang;
+Decl *clang::getPrimaryMergedDecl(Decl *D) {
+ return D->getASTContext().getPrimaryMergedDecl(D);
+}
+
//===----------------------------------------------------------------------===//
// NamedDecl Implementation
//===----------------------------------------------------------------------===//
@@ -85,6 +89,7 @@ using namespace clang;
// and settings from the immediate context.
const unsigned IgnoreExplicitVisibilityBit = 2;
+const unsigned IgnoreAllVisibilityBit = 4;
/// Kinds of LV computation. The linkage side of the computation is
/// always the same, but different things can change how visibility is
@@ -108,7 +113,11 @@ enum LVComputationKind {
/// Do an LV computation for, ultimately, a non-type declaration
/// that already has some sort of explicit visibility. Visibility
/// may only be restricted by the visibility of template arguments.
- LVForExplicitValue = (LVForValue | IgnoreExplicitVisibilityBit)
+ LVForExplicitValue = (LVForValue | IgnoreExplicitVisibilityBit),
+
+ /// Do an LV computation when we only care about the linkage.
+ LVForLinkageOnly =
+ LVForValue | IgnoreExplicitVisibilityBit | IgnoreAllVisibilityBit
};
/// Does this computation kind permit us to consider additional
@@ -211,11 +220,19 @@ static Optional<Visibility> getVisibilityOf(const NamedDecl *D,
return None;
}
+static LinkageInfo
+getLVForType(const Type &T, LVComputationKind computation) {
+ if (computation == LVForLinkageOnly)
+ return LinkageInfo(T.getLinkage(), DefaultVisibility, true);
+ return T.getLinkageAndVisibility();
+}
+
/// \brief Get the most restrictive linkage for the types in the given
/// template parameter list. For visibility purposes, template
/// parameters are part of the signature of a template.
static LinkageInfo
-getLVForTemplateParameterList(const TemplateParameterList *params) {
+getLVForTemplateParameterList(const TemplateParameterList *params,
+ LVComputationKind computation) {
LinkageInfo LV;
for (TemplateParameterList::const_iterator P = params->begin(),
PEnd = params->end();
@@ -234,7 +251,7 @@ getLVForTemplateParameterList(const TemplateParameterList *params) {
// Handle the non-pack case first.
if (!NTTP->isExpandedParameterPack()) {
if (!NTTP->getType()->isDependentType()) {
- LV.merge(NTTP->getType()->getLinkageAndVisibility());
+ LV.merge(getLVForType(*NTTP->getType(), computation));
}
continue;
}
@@ -254,7 +271,8 @@ getLVForTemplateParameterList(const TemplateParameterList *params) {
// Handle the non-pack case first.
if (!TTP->isExpandedParameterPack()) {
- LV.merge(getLVForTemplateParameterList(TTP->getTemplateParameters()));
+ LV.merge(getLVForTemplateParameterList(TTP->getTemplateParameters(),
+ computation));
continue;
}
@@ -262,7 +280,7 @@ getLVForTemplateParameterList(const TemplateParameterList *params) {
for (unsigned i = 0, n = TTP->getNumExpansionTemplateParameters();
i != n; ++i) {
LV.merge(getLVForTemplateParameterList(
- TTP->getExpansionTemplateParameters(i)));
+ TTP->getExpansionTemplateParameters(i), computation));
}
}
@@ -273,13 +291,25 @@ getLVForTemplateParameterList(const TemplateParameterList *params) {
static LinkageInfo getLVForDecl(const NamedDecl *D,
LVComputationKind computation);
+static const Decl *getOutermostFuncOrBlockContext(const Decl *D) {
+ const Decl *Ret = NULL;
+ const DeclContext *DC = D->getDeclContext();
+ while (DC->getDeclKind() != Decl::TranslationUnit) {
+ if (isa<FunctionDecl>(DC) || isa<BlockDecl>(DC))
+ Ret = cast<Decl>(DC);
+ DC = DC->getParent();
+ }
+ return Ret;
+}
+
/// \brief Get the most restrictive linkage for the types and
/// declarations in the given template argument list.
///
/// Note that we don't take an LVComputationKind because we always
/// want to honor the visibility of template arguments in the same way.
static LinkageInfo
-getLVForTemplateArgumentList(ArrayRef<TemplateArgument> args) {
+getLVForTemplateArgumentList(ArrayRef<TemplateArgument> args,
+ LVComputationKind computation) {
LinkageInfo LV;
for (unsigned i = 0, e = args.size(); i != e; ++i) {
@@ -291,13 +321,13 @@ getLVForTemplateArgumentList(ArrayRef<TemplateArgument> args) {
continue;
case TemplateArgument::Type:
- LV.merge(arg.getAsType()->getLinkageAndVisibility());
+ LV.merge(getLVForType(*arg.getAsType(), computation));
continue;
case TemplateArgument::Declaration:
if (NamedDecl *ND = dyn_cast<NamedDecl>(arg.getAsDecl())) {
assert(!usesTypeVisibility(ND));
- LV.merge(getLVForDecl(ND, LVForValue));
+ LV.merge(getLVForDecl(ND, computation));
}
continue;
@@ -309,11 +339,11 @@ getLVForTemplateArgumentList(ArrayRef<TemplateArgument> args) {
case TemplateArgument::TemplateExpansion:
if (TemplateDecl *Template
= arg.getAsTemplateOrTemplatePattern().getAsTemplateDecl())
- LV.merge(getLVForDecl(Template, LVForValue));
+ LV.merge(getLVForDecl(Template, computation));
continue;
case TemplateArgument::Pack:
- LV.merge(getLVForTemplateArgumentList(arg.getPackAsArray()));
+ LV.merge(getLVForTemplateArgumentList(arg.getPackAsArray(), computation));
continue;
}
llvm_unreachable("bad template argument kind");
@@ -323,8 +353,9 @@ getLVForTemplateArgumentList(ArrayRef<TemplateArgument> args) {
}
static LinkageInfo
-getLVForTemplateArgumentList(const TemplateArgumentList &TArgs) {
- return getLVForTemplateArgumentList(TArgs.asArray());
+getLVForTemplateArgumentList(const TemplateArgumentList &TArgs,
+ LVComputationKind computation) {
+ return getLVForTemplateArgumentList(TArgs.asArray(), computation);
}
static bool shouldConsiderTemplateVisibility(const FunctionDecl *fn,
@@ -348,19 +379,20 @@ static bool shouldConsiderTemplateVisibility(const FunctionDecl *fn,
/// \param[out] LV the computation to use for the parent
static void
mergeTemplateLV(LinkageInfo &LV, const FunctionDecl *fn,
- const FunctionTemplateSpecializationInfo *specInfo) {
+ const FunctionTemplateSpecializationInfo *specInfo,
+ LVComputationKind computation) {
bool considerVisibility =
shouldConsiderTemplateVisibility(fn, specInfo);
// Merge information from the template parameters.
FunctionTemplateDecl *temp = specInfo->getTemplate();
LinkageInfo tempLV =
- getLVForTemplateParameterList(temp->getTemplateParameters());
+ getLVForTemplateParameterList(temp->getTemplateParameters(), computation);
LV.mergeMaybeWithVisibility(tempLV, considerVisibility);
// Merge information from the template arguments.
const TemplateArgumentList &templateArgs = *specInfo->TemplateArguments;
- LinkageInfo argsLV = getLVForTemplateArgumentList(templateArgs);
+ LinkageInfo argsLV = getLVForTemplateArgumentList(templateArgs, computation);
LV.mergeMaybeWithVisibility(argsLV, considerVisibility);
}
@@ -379,6 +411,8 @@ static bool hasDirectVisibilityAttribute(const NamedDecl *D,
if (D->hasAttr<VisibilityAttr>())
return true;
return false;
+ case LVForLinkageOnly:
+ return false;
}
llvm_unreachable("bad visibility computation kind");
}
@@ -431,7 +465,7 @@ static void mergeTemplateLV(LinkageInfo &LV,
ClassTemplateDecl *temp = spec->getSpecializedTemplate();
LinkageInfo tempLV =
- getLVForTemplateParameterList(temp->getTemplateParameters());
+ getLVForTemplateParameterList(temp->getTemplateParameters(), computation);
LV.mergeMaybeWithVisibility(tempLV,
considerVisibility && !hasExplicitVisibilityAlready(computation));
@@ -439,8 +473,10 @@ static void mergeTemplateLV(LinkageInfo &LV,
// template-argument visibility if we've got an explicit
// instantiation with a visibility attribute.
const TemplateArgumentList &templateArgs = spec->getTemplateArgs();
- LinkageInfo argsLV = getLVForTemplateArgumentList(templateArgs);
- LV.mergeMaybeWithVisibility(argsLV, considerVisibility);
+ LinkageInfo argsLV = getLVForTemplateArgumentList(templateArgs, computation);
+ if (considerVisibility)
+ LV.mergeVisibility(argsLV);
+ LV.mergeExternalVisibility(argsLV);
}
static bool useInlineVisibilityHidden(const NamedDecl *D) {
@@ -472,7 +508,7 @@ static bool useInlineVisibilityHidden(const NamedDecl *D) {
}
template <typename T> static bool isFirstInExternCContext(T *D) {
- const T *First = D->getFirstDeclaration();
+ const T *First = D->getFirstDecl();
return First->isInExternCContext();
}
@@ -508,7 +544,7 @@ static LinkageInfo getLVForNamespaceScopeDecl(const NamedDecl *D,
!Var->getType().isVolatileQualified()) {
const VarDecl *PrevVar = Var->getPreviousDecl();
if (PrevVar)
- return PrevVar->getLinkageAndVisibility();
+ return getLVForDecl(PrevVar, computation);
if (Var->getStorageClass() != SC_Extern &&
Var->getStorageClass() != SC_PrivateExtern &&
@@ -539,11 +575,10 @@ static LinkageInfo getLVForNamespaceScopeDecl(const NamedDecl *D,
// Explicitly declared static.
if (Function->getCanonicalDecl()->getStorageClass() == SC_Static)
return LinkageInfo(InternalLinkage, DefaultVisibility, false);
- } else if (const FieldDecl *Field = dyn_cast<FieldDecl>(D)) {
- // - a data member of an anonymous union.
- if (cast<RecordDecl>(Field->getDeclContext())->isAnonymousStructOrUnion())
- return LinkageInfo::internal();
}
+ // - a data member of an anonymous union.
+ assert(!isa<IndirectFieldDecl>(D) && "Didn't expect an IndirectFieldDecl!");
+ assert(!isa<FieldDecl>(D) && "Didn't expect a FieldDecl!");
if (D->isInAnonymousNamespace()) {
const VarDecl *Var = dyn_cast<VarDecl>(D);
@@ -627,7 +662,7 @@ static LinkageInfo getLVForNamespaceScopeDecl(const NamedDecl *D,
// Note that we don't want to make the variable non-external
// because of this, but unique-external linkage suits us.
if (Context.getLangOpts().CPlusPlus && !isFirstInExternCContext(Var)) {
- LinkageInfo TypeLV = Var->getType()->getLinkageAndVisibility();
+ LinkageInfo TypeLV = getLVForType(*Var->getType(), computation);
if (TypeLV.getLinkage() != ExternalLinkage)
return LinkageInfo::uniqueExternal();
if (!LV.isVisibilityExplicit())
@@ -660,16 +695,27 @@ static LinkageInfo getLVForNamespaceScopeDecl(const NamedDecl *D,
// this translation unit. However, we should use the C linkage
// rules instead for extern "C" declarations.
if (Context.getLangOpts().CPlusPlus &&
- !Function->isInExternCContext() &&
- Function->getType()->getLinkage() == UniqueExternalLinkage)
- return LinkageInfo::uniqueExternal();
+ !Function->isInExternCContext()) {
+ // Only look at the type-as-written. If this function has an auto-deduced
+ // return type, we can't compute the linkage of that type because it could
+ // require looking at the linkage of this function, and we don't need this
+ // for correctness because the type is not part of the function's
+ // signature.
+ // FIXME: This is a hack. We should be able to solve this circularity and
+ // the one in getLVForClassMember for Functions some other way.
+ QualType TypeAsWritten = Function->getType();
+ if (TypeSourceInfo *TSI = Function->getTypeSourceInfo())
+ TypeAsWritten = TSI->getType();
+ if (TypeAsWritten->getLinkage() == UniqueExternalLinkage)
+ return LinkageInfo::uniqueExternal();
+ }
// Consider LV from the template and the template arguments.
// We're at file scope, so we do not need to worry about nested
// specializations.
if (FunctionTemplateSpecializationInfo *specInfo
= Function->getTemplateSpecializationInfo()) {
- mergeTemplateLV(LV, Function, specInfo);
+ mergeTemplateLV(LV, Function, specInfo, computation);
}
// - a named class (Clause 9), or an unnamed class defined in a
@@ -695,7 +741,7 @@ static LinkageInfo getLVForNamespaceScopeDecl(const NamedDecl *D,
} else if (isa<EnumConstantDecl>(D)) {
LinkageInfo EnumLV = getLVForDecl(cast<NamedDecl>(D->getDeclContext()),
computation);
- if (!isExternalLinkage(EnumLV.getLinkage()))
+ if (!isExternalFormalLinkage(EnumLV.getLinkage()))
return LinkageInfo::none();
LV.merge(EnumLV);
@@ -704,7 +750,7 @@ static LinkageInfo getLVForNamespaceScopeDecl(const NamedDecl *D,
} else if (const TemplateDecl *temp = dyn_cast<TemplateDecl>(D)) {
bool considerVisibility = !hasExplicitVisibilityAlready(computation);
LinkageInfo tempLV =
- getLVForTemplateParameterList(temp->getTemplateParameters());
+ getLVForTemplateParameterList(temp->getTemplateParameters(), computation);
LV.mergeMaybeWithVisibility(tempLV, considerVisibility);
// - a namespace (7.3), unless it is declared within an unnamed
@@ -739,6 +785,7 @@ static LinkageInfo getLVForClassMember(const NamedDecl *D,
if (!(isa<CXXMethodDecl>(D) ||
isa<VarDecl>(D) ||
isa<FieldDecl>(D) ||
+ isa<IndirectFieldDecl>(D) ||
isa<TagDecl>(D)))
return LinkageInfo::none();
@@ -766,13 +813,14 @@ static LinkageInfo getLVForClassMember(const NamedDecl *D,
LinkageInfo classLV =
getLVForDecl(cast<RecordDecl>(D->getDeclContext()), classComputation);
- if (!isExternalLinkage(classLV.getLinkage()))
- return LinkageInfo::none();
-
// If the class already has unique-external linkage, we can't improve.
if (classLV.getLinkage() == UniqueExternalLinkage)
return LinkageInfo::uniqueExternal();
+ if (!isExternallyVisible(classLV.getLinkage()))
+ return LinkageInfo::none();
+
+
// Otherwise, don't merge in classLV yet, because in certain cases
// we need to completely ignore the visibility from it.
@@ -782,14 +830,25 @@ static LinkageInfo getLVForClassMember(const NamedDecl *D,
if (const CXXMethodDecl *MD = dyn_cast<CXXMethodDecl>(D)) {
// If the type of the function uses a type with unique-external
// linkage, it's not legally usable from outside this translation unit.
- if (MD->getType()->getLinkage() == UniqueExternalLinkage)
- return LinkageInfo::uniqueExternal();
-
+ // But only look at the type-as-written. If this function has an auto-deduced
+ // return type, we can't compute the linkage of that type because it could
+ // require looking at the linkage of this function, and we don't need this
+ // for correctness because the type is not part of the function's
+ // signature.
+ // FIXME: This is a hack. We should be able to solve this circularity and the
+ // one in getLVForNamespaceScopeDecl for Functions some other way.
+ {
+ QualType TypeAsWritten = MD->getType();
+ if (TypeSourceInfo *TSI = MD->getTypeSourceInfo())
+ TypeAsWritten = TSI->getType();
+ if (TypeAsWritten->getLinkage() == UniqueExternalLinkage)
+ return LinkageInfo::uniqueExternal();
+ }
// If this is a method template specialization, use the linkage for
// the template parameters and arguments.
if (FunctionTemplateSpecializationInfo *spec
= MD->getTemplateSpecializationInfo()) {
- mergeTemplateLV(LV, MD, spec);
+ mergeTemplateLV(LV, MD, spec, computation);
if (spec->isExplicitSpecialization()) {
explicitSpecSuppressor = MD;
} else if (isExplicitMemberSpecialization(spec->getTemplate())) {
@@ -819,9 +878,10 @@ static LinkageInfo getLVForClassMember(const NamedDecl *D,
} else if (const VarDecl *VD = dyn_cast<VarDecl>(D)) {
// Modify the variable's linkage by its type, but ignore the
// type's visibility unless it's a definition.
- LinkageInfo typeLV = VD->getType()->getLinkageAndVisibility();
- LV.mergeMaybeWithVisibility(typeLV,
- !LV.isVisibilityExplicit() && !classLV.isVisibilityExplicit());
+ LinkageInfo typeLV = getLVForType(*VD->getType(), computation);
+ if (!LV.isVisibilityExplicit() && !classLV.isVisibilityExplicit())
+ LV.mergeVisibility(typeLV);
+ LV.mergeExternalVisibility(typeLV);
if (isExplicitMemberSpecialization(VD)) {
explicitSpecSuppressor = VD;
@@ -834,7 +894,7 @@ static LinkageInfo getLVForClassMember(const NamedDecl *D,
!classLV.isVisibilityExplicit() &&
!hasExplicitVisibilityAlready(computation));
LinkageInfo tempLV =
- getLVForTemplateParameterList(temp->getTemplateParameters());
+ getLVForTemplateParameterList(temp->getTemplateParameters(), computation);
LV.mergeMaybeWithVisibility(tempLV, considerVisibility);
if (const RedeclarableTemplateDecl *redeclTemp =
@@ -866,81 +926,42 @@ static LinkageInfo getLVForClassMember(const NamedDecl *D,
void NamedDecl::anchor() { }
+static LinkageInfo computeLVForDecl(const NamedDecl *D,
+ LVComputationKind computation);
+
bool NamedDecl::isLinkageValid() const {
- if (!HasCachedLinkage)
+ if (!hasCachedLinkage())
return true;
- return getLVForDecl(this, LVForExplicitValue).getLinkage() ==
- Linkage(CachedLinkage);
+ return computeLVForDecl(this, LVForLinkageOnly).getLinkage() ==
+ getCachedLinkage();
}
-Linkage NamedDecl::getLinkage() const {
- if (HasCachedLinkage)
- return Linkage(CachedLinkage);
-
+Linkage NamedDecl::getLinkageInternal() const {
// We don't care about visibility here, so ask for the cheapest
// possible visibility analysis.
- CachedLinkage = getLVForDecl(this, LVForExplicitValue).getLinkage();
- HasCachedLinkage = 1;
-
-#ifndef NDEBUG
- verifyLinkage();
-#endif
-
- return Linkage(CachedLinkage);
+ return getLVForDecl(this, LVForLinkageOnly).getLinkage();
}
LinkageInfo NamedDecl::getLinkageAndVisibility() const {
LVComputationKind computation =
(usesTypeVisibility(this) ? LVForType : LVForValue);
- LinkageInfo LI = getLVForDecl(this, computation);
- if (HasCachedLinkage) {
- assert(Linkage(CachedLinkage) == LI.getLinkage());
- return LI;
- }
- HasCachedLinkage = 1;
- CachedLinkage = LI.getLinkage();
-
-#ifndef NDEBUG
- verifyLinkage();
-#endif
-
- return LI;
+ return getLVForDecl(this, computation);
}
-void NamedDecl::verifyLinkage() const {
- // In C (because of gnu inline) and in c++ with microsoft extensions an
- // static can follow an extern, so we can have two decls with different
- // linkages.
- const LangOptions &Opts = getASTContext().getLangOpts();
- if (!Opts.CPlusPlus || Opts.MicrosoftExt)
- return;
-
- // We have just computed the linkage for this decl. By induction we know
- // that all other computed linkages match, check that the one we just computed
- // also does.
- NamedDecl *D = NULL;
- for (redecl_iterator I = redecls_begin(), E = redecls_end(); I != E; ++I) {
- NamedDecl *T = cast<NamedDecl>(*I);
- if (T == this)
- continue;
- if (T->HasCachedLinkage != 0) {
- D = T;
- break;
- }
- }
- assert(!D || D->CachedLinkage == CachedLinkage);
-}
+static Optional<Visibility>
+getExplicitVisibilityAux(const NamedDecl *ND,
+ NamedDecl::ExplicitVisibilityKind kind,
+ bool IsMostRecent) {
+ assert(!IsMostRecent || ND == ND->getMostRecentDecl());
-Optional<Visibility>
-NamedDecl::getExplicitVisibility(ExplicitVisibilityKind kind) const {
// Check the declaration itself first.
- if (Optional<Visibility> V = getVisibilityOf(this, kind))
+ if (Optional<Visibility> V = getVisibilityOf(ND, kind))
return V;
// If this is a member class of a specialization of a class template
// and the corresponding decl has explicit visibility, use that.
- if (const CXXRecordDecl *RD = dyn_cast<CXXRecordDecl>(this)) {
+ if (const CXXRecordDecl *RD = dyn_cast<CXXRecordDecl>(ND)) {
CXXRecordDecl *InstantiatedFrom = RD->getInstantiatedFromMemberClass();
if (InstantiatedFrom)
return getVisibilityOf(InstantiatedFrom, kind);
@@ -950,16 +971,18 @@ NamedDecl::getExplicitVisibility(ExplicitVisibilityKind kind) const {
// specialization of a class template, check for visibility
// on the pattern.
if (const ClassTemplateSpecializationDecl *spec
- = dyn_cast<ClassTemplateSpecializationDecl>(this))
+ = dyn_cast<ClassTemplateSpecializationDecl>(ND))
return getVisibilityOf(spec->getSpecializedTemplate()->getTemplatedDecl(),
kind);
// Use the most recent declaration.
- const NamedDecl *MostRecent = cast<NamedDecl>(this->getMostRecentDecl());
- if (MostRecent != this)
- return MostRecent->getExplicitVisibility(kind);
+ if (!IsMostRecent && !isa<NamespaceDecl>(ND)) {
+ const NamedDecl *MostRecent = ND->getMostRecentDecl();
+ if (MostRecent != ND)
+ return getExplicitVisibilityAux(MostRecent, kind, true);
+ }
- if (const VarDecl *Var = dyn_cast<VarDecl>(this)) {
+ if (const VarDecl *Var = dyn_cast<VarDecl>(ND)) {
if (Var->isStaticDataMember()) {
VarDecl *InstantiatedFrom = Var->getInstantiatedFromStaticDataMember();
if (InstantiatedFrom)
@@ -969,7 +992,7 @@ NamedDecl::getExplicitVisibility(ExplicitVisibilityKind kind) const {
return None;
}
// Also handle function template specializations.
- if (const FunctionDecl *fn = dyn_cast<FunctionDecl>(this)) {
+ if (const FunctionDecl *fn = dyn_cast<FunctionDecl>(ND)) {
// If the function is a specialization of a template with an
// explicit visibility attribute, use that.
if (FunctionTemplateSpecializationInfo *templateInfo
@@ -987,12 +1010,33 @@ NamedDecl::getExplicitVisibility(ExplicitVisibilityKind kind) const {
}
// The visibility of a template is stored in the templated decl.
- if (const TemplateDecl *TD = dyn_cast<TemplateDecl>(this))
+ if (const TemplateDecl *TD = dyn_cast<TemplateDecl>(ND))
return getVisibilityOf(TD->getTemplatedDecl(), kind);
return None;
}
+Optional<Visibility>
+NamedDecl::getExplicitVisibility(ExplicitVisibilityKind kind) const {
+ return getExplicitVisibilityAux(this, kind, false);
+}
+
+static LinkageInfo getLVForClosure(const DeclContext *DC, Decl *ContextDecl,
+ LVComputationKind computation) {
+ // This lambda has its linkage/visibility determined by its owner.
+ if (ContextDecl) {
+ if (isa<ParmVarDecl>(ContextDecl))
+ DC = ContextDecl->getDeclContext()->getRedeclContext();
+ else
+ return getLVForDecl(cast<NamedDecl>(ContextDecl), computation);
+ }
+
+ if (const NamedDecl *ND = dyn_cast<NamedDecl>(DC))
+ return getLVForDecl(ND, computation);
+
+ return LinkageInfo::external();
+}
+
static LinkageInfo getLVForLocalDecl(const NamedDecl *D,
LVComputationKind computation) {
if (const FunctionDecl *Function = dyn_cast<FunctionDecl>(D)) {
@@ -1040,13 +1084,55 @@ static LinkageInfo getLVForLocalDecl(const NamedDecl *D,
return LV;
}
+
+ if (!Var->isStaticLocal())
+ return LinkageInfo::none();
}
- return LinkageInfo::none();
+ ASTContext &Context = D->getASTContext();
+ if (!Context.getLangOpts().CPlusPlus)
+ return LinkageInfo::none();
+
+ const Decl *OuterD = getOutermostFuncOrBlockContext(D);
+ if (!OuterD)
+ return LinkageInfo::none();
+
+ LinkageInfo LV;
+ if (const BlockDecl *BD = dyn_cast<BlockDecl>(OuterD)) {
+ if (!BD->getBlockManglingNumber())
+ return LinkageInfo::none();
+
+ LV = getLVForClosure(BD->getDeclContext()->getRedeclContext(),
+ BD->getBlockManglingContextDecl(), computation);
+ } else {
+ const FunctionDecl *FD = cast<FunctionDecl>(OuterD);
+ if (!FD->isInlined() &&
+ FD->getTemplateSpecializationKind() == TSK_Undeclared)
+ return LinkageInfo::none();
+
+ LV = getLVForDecl(FD, computation);
+ }
+ if (!isExternallyVisible(LV.getLinkage()))
+ return LinkageInfo::none();
+ return LinkageInfo(VisibleNoLinkage, LV.getVisibility(),
+ LV.isVisibilityExplicit());
}
-static LinkageInfo getLVForDecl(const NamedDecl *D,
- LVComputationKind computation) {
+static inline const CXXRecordDecl*
+getOutermostEnclosingLambda(const CXXRecordDecl *Record) {
+ const CXXRecordDecl *Ret = Record;
+ while (Record && Record->isLambda()) {
+ Ret = Record;
+ if (!Record->getParent()) break;
+ // Get the Containing Class of this Lambda Class
+ Record = dyn_cast_or_null<CXXRecordDecl>(
+ Record->getParent()->getParent());
+ }
+ return Ret;
+}
+
+static LinkageInfo computeLVForDecl(const NamedDecl *D,
+ LVComputationKind computation) {
// Objective-C: treat all Objective-C declarations as having external
// linkage.
switch (D->getKind()) {
@@ -1074,20 +1160,25 @@ static LinkageInfo getLVForDecl(const NamedDecl *D,
// This lambda has no mangling number, so it's internal.
return LinkageInfo::internal();
}
-
- // This lambda has its linkage/visibility determined by its owner.
- const DeclContext *DC = D->getDeclContext()->getRedeclContext();
- if (Decl *ContextDecl = Record->getLambdaContextDecl()) {
- if (isa<ParmVarDecl>(ContextDecl))
- DC = ContextDecl->getDeclContext()->getRedeclContext();
- else
- return getLVForDecl(cast<NamedDecl>(ContextDecl), computation);
- }
- if (const NamedDecl *ND = dyn_cast<NamedDecl>(DC))
- return getLVForDecl(ND, computation);
+ // This lambda has its linkage/visibility determined:
+ // - either by the outermost lambda if that lambda has no mangling
+ // number.
+ // - or by the parent of the outer most lambda
+ // This prevents infinite recursion in settings such as nested lambdas
+ // used in NSDMI's, for e.g.
+ // struct L {
+ // int t{};
+ // int t2 = ([](int a) { return [](int b) { return b; };})(t)(t);
+ // };
+ const CXXRecordDecl *OuterMostLambda =
+ getOutermostEnclosingLambda(Record);
+ if (!OuterMostLambda->getLambdaManglingNumber())
+ return LinkageInfo::internal();
- return LinkageInfo::external();
+ return getLVForClosure(
+ OuterMostLambda->getDeclContext()->getRedeclContext(),
+ OuterMostLambda->getLambdaContextDecl(), computation);
}
break;
@@ -1127,6 +1218,57 @@ static LinkageInfo getLVForDecl(const NamedDecl *D,
return LinkageInfo::none();
}
+namespace clang {
+class LinkageComputer {
+public:
+ static LinkageInfo getLVForDecl(const NamedDecl *D,
+ LVComputationKind computation) {
+ if (computation == LVForLinkageOnly && D->hasCachedLinkage())
+ return LinkageInfo(D->getCachedLinkage(), DefaultVisibility, false);
+
+ LinkageInfo LV = computeLVForDecl(D, computation);
+ if (D->hasCachedLinkage())
+ assert(D->getCachedLinkage() == LV.getLinkage());
+
+ D->setCachedLinkage(LV.getLinkage());
+
+#ifndef NDEBUG
+ // In C (because of gnu inline) and in c++ with microsoft extensions an
+ // static can follow an extern, so we can have two decls with different
+ // linkages.
+ const LangOptions &Opts = D->getASTContext().getLangOpts();
+ if (!Opts.CPlusPlus || Opts.MicrosoftExt)
+ return LV;
+
+ // We have just computed the linkage for this decl. By induction we know
+ // that all other computed linkages match, check that the one we just
+ // computed
+ // also does.
+ NamedDecl *Old = NULL;
+ for (NamedDecl::redecl_iterator I = D->redecls_begin(),
+ E = D->redecls_end();
+ I != E; ++I) {
+ NamedDecl *T = cast<NamedDecl>(*I);
+ if (T == D)
+ continue;
+ if (T->hasCachedLinkage()) {
+ Old = T;
+ break;
+ }
+ }
+ assert(!Old || Old->getCachedLinkage() == D->getCachedLinkage());
+#endif
+
+ return LV;
+ }
+};
+}
+
+static LinkageInfo getLVForDecl(const NamedDecl *D,
+ LVComputationKind computation) {
+ return clang::LinkageComputer::getLVForDecl(D, computation);
+}
+
std::string NamedDecl::getQualifiedNameAsString() const {
return getQualifiedNameAsString(getASTContext().getPrintingPolicy());
}
@@ -1265,6 +1407,15 @@ bool NamedDecl::declarationReplaces(NamedDecl *OldD) const {
cast<UsingDecl>(OldD)->getQualifier());
}
+ if (isa<UnresolvedUsingValueDecl>(this) &&
+ isa<UnresolvedUsingValueDecl>(OldD)) {
+ ASTContext &Context = getASTContext();
+ return Context.getCanonicalNestedNameSpecifier(
+ cast<UnresolvedUsingValueDecl>(this)->getQualifier()) ==
+ Context.getCanonicalNestedNameSpecifier(
+ cast<UnresolvedUsingValueDecl>(OldD)->getQualifier());
+ }
+
// A typedef of an Objective-C class type can replace an Objective-C class
// declaration or definition, and vice versa.
if ((isa<TypedefNameDecl>(this) && isa<ObjCInterfaceDecl>(OldD)) ||
@@ -1278,7 +1429,7 @@ bool NamedDecl::declarationReplaces(NamedDecl *OldD) const {
}
bool NamedDecl::hasLinkage() const {
- return getLinkage() != NoLinkage;
+ return getFormalLinkage() != NoLinkage;
}
NamedDecl *NamedDecl::getUnderlyingDeclImpl() {
@@ -1469,6 +1620,17 @@ const char *VarDecl::getStorageClassSpecifierString(StorageClass SC) {
llvm_unreachable("Invalid storage class");
}
+VarDecl::VarDecl(Kind DK, DeclContext *DC, SourceLocation StartLoc,
+ SourceLocation IdLoc, IdentifierInfo *Id, QualType T,
+ TypeSourceInfo *TInfo, StorageClass SC)
+ : DeclaratorDecl(DK, DC, IdLoc, Id, T, TInfo, StartLoc), Init() {
+ assert(sizeof(VarDeclBitfields) <= sizeof(unsigned));
+ assert(sizeof(ParmVarDeclBitfields) <= sizeof(unsigned));
+ AllBits = 0;
+ VarDeclBits.SClass = SC;
+ // Everything else is implicitly initialized to false.
+}
+
VarDecl *VarDecl::Create(ASTContext &C, DeclContext *DC,
SourceLocation StartL, SourceLocation IdL,
IdentifierInfo *Id, QualType T, TypeSourceInfo *TInfo,
@@ -1502,7 +1664,7 @@ template<typename T>
static LanguageLinkage getLanguageLinkageTemplate(const T &D) {
// C++ [dcl.link]p1: All function types, function names with external linkage,
// and variable names with external linkage have a language linkage.
- if (!isExternalLinkage(D.getLinkage()))
+ if (!D.hasExternalFormalLinkage())
return NoLanguageLinkage;
// Language linkage is a C++ concept, but saying that everything else in C has
@@ -1547,32 +1709,15 @@ bool VarDecl::isExternC() const {
return isExternCTemplate(*this);
}
-static bool isLinkageSpecContext(const DeclContext *DC,
- LinkageSpecDecl::LanguageIDs ID) {
- while (DC->getDeclKind() != Decl::TranslationUnit) {
- if (DC->getDeclKind() == Decl::LinkageSpec)
- return cast<LinkageSpecDecl>(DC)->getLanguage() == ID;
- DC = DC->getParent();
- }
- return false;
-}
-
-template <typename T>
-static bool isInLanguageSpecContext(T *D, LinkageSpecDecl::LanguageIDs ID) {
- return isLinkageSpecContext(D->getLexicalDeclContext(), ID);
-}
-
bool VarDecl::isInExternCContext() const {
- return isInLanguageSpecContext(this, LinkageSpecDecl::lang_c);
+ return getLexicalDeclContext()->isExternCContext();
}
bool VarDecl::isInExternCXXContext() const {
- return isInLanguageSpecContext(this, LinkageSpecDecl::lang_cxx);
+ return getLexicalDeclContext()->isExternCXXContext();
}
-VarDecl *VarDecl::getCanonicalDecl() {
- return getFirstDeclaration();
-}
+VarDecl *VarDecl::getCanonicalDecl() { return getFirstDecl(); }
VarDecl::DefinitionKind VarDecl::isThisDeclarationADefinition(
ASTContext &C) const
@@ -1581,13 +1726,24 @@ VarDecl::DefinitionKind VarDecl::isThisDeclarationADefinition(
// A declaration is a definition unless [...] it contains the 'extern'
// specifier or a linkage-specification and neither an initializer [...],
// it declares a static data member in a class declaration [...].
- // C++ [temp.expl.spec]p15:
- // An explicit specialization of a static data member of a template is a
- // definition if the declaration includes an initializer; otherwise, it is
- // a declaration.
+ // C++1y [temp.expl.spec]p15:
+ // An explicit specialization of a static data member or an explicit
+ // specialization of a static data member template is a definition if the
+ // declaration includes an initializer; otherwise, it is a declaration.
+ //
+ // FIXME: How do you declare (but not define) a partial specialization of
+ // a static data member template outside the containing class?
if (isStaticDataMember()) {
- if (isOutOfLine() && (hasInit() ||
- getTemplateSpecializationKind() != TSK_ExplicitSpecialization))
+ if (isOutOfLine() &&
+ (hasInit() ||
+ // If the first declaration is out-of-line, this may be an
+ // instantiation of an out-of-line partial specialization of a variable
+ // template for which we have not yet instantiated the initializer.
+ (getFirstDecl()->isOutOfLine()
+ ? getTemplateSpecializationKind() == TSK_Undeclared
+ : getTemplateSpecializationKind() !=
+ TSK_ExplicitSpecialization) ||
+ isa<VarTemplatePartialSpecializationDecl>(this)))
return Definition;
else
return DeclarationOnly;
@@ -1602,6 +1758,16 @@ VarDecl::DefinitionKind VarDecl::isThisDeclarationADefinition(
if (hasInit())
return Definition;
+ if (hasAttr<AliasAttr>())
+ return Definition;
+
+ // A variable template specialization (other than a static data member
+ // template or an explicit specialization) is a declaration until we
+ // instantiate its initializer.
+ if (isa<VarTemplateSpecializationDecl>(this) &&
+ getTemplateSpecializationKind() != TSK_ExplicitSpecialization)
+ return DeclarationOnly;
+
if (hasExternalStorage())
return DeclarationOnly;
@@ -1631,7 +1797,7 @@ VarDecl *VarDecl::getActingDefinition() {
return 0;
VarDecl *LastTentative = 0;
- VarDecl *First = getFirstDeclaration();
+ VarDecl *First = getFirstDecl();
for (redecl_iterator I = First->redecls_begin(), E = First->redecls_end();
I != E; ++I) {
Kind = (*I)->isThisDeclarationADefinition();
@@ -1643,20 +1809,8 @@ VarDecl *VarDecl::getActingDefinition() {
return LastTentative;
}
-bool VarDecl::isTentativeDefinitionNow() const {
- DefinitionKind Kind = isThisDeclarationADefinition();
- if (Kind != TentativeDefinition)
- return false;
-
- for (redecl_iterator I = redecls_begin(), E = redecls_end(); I != E; ++I) {
- if ((*I)->isThisDeclarationADefinition() == Definition)
- return false;
- }
- return true;
-}
-
VarDecl *VarDecl::getDefinition(ASTContext &C) {
- VarDecl *First = getFirstDeclaration();
+ VarDecl *First = getFirstDecl();
for (redecl_iterator I = First->redecls_begin(), E = First->redecls_end();
I != E; ++I) {
if ((*I)->isThisDeclarationADefinition(C) == Definition)
@@ -1668,7 +1822,7 @@ VarDecl *VarDecl::getDefinition(ASTContext &C) {
VarDecl::DefinitionKind VarDecl::hasDefinition(ASTContext &C) const {
DefinitionKind Kind = DeclarationOnly;
- const VarDecl *First = getFirstDeclaration();
+ const VarDecl *First = getFirstDecl();
for (redecl_iterator I = First->redecls_begin(), E = First->redecls_end();
I != E; ++I) {
Kind = std::max(Kind, (*I)->isThisDeclarationADefinition(C));
@@ -1763,6 +1917,10 @@ EvaluatedStmt *VarDecl::ensureEvaluatedStmt() const {
EvaluatedStmt *Eval = Init.dyn_cast<EvaluatedStmt *>();
if (!Eval) {
Stmt *S = Init.get<Stmt *>();
+ // Note: EvaluatedStmt contains an APValue, which usually holds
+ // resources not allocated from the ASTContext. We need to do some
+ // work to avoid leaking those, but we do so in VarDecl::evaluateValue
+ // where we can detect whether there's anything to clean up or not.
Eval = new (getASTContext()) EvaluatedStmt;
Eval->Value = S;
Init = Eval;
@@ -1775,6 +1933,13 @@ APValue *VarDecl::evaluateValue() const {
return evaluateValue(Notes);
}
+namespace {
+// Destroy an APValue that was allocated in an ASTContext.
+void DestroyAPValue(void* UntypedValue) {
+ static_cast<APValue*>(UntypedValue)->~APValue();
+}
+} // namespace
+
APValue *VarDecl::evaluateValue(
SmallVectorImpl<PartialDiagnosticAt> &Notes) const {
EvaluatedStmt *Eval = ensureEvaluatedStmt();
@@ -1800,9 +1965,13 @@ APValue *VarDecl::evaluateValue(
bool Result = Init->EvaluateAsInitializer(Eval->Evaluated, getASTContext(),
this, Notes);
- // Ensure the result is an uninitialized APValue if evaluation fails.
+ // Ensure the computed APValue is cleaned up later if evaluation succeeded,
+ // or that it's empty (so that there's nothing to clean up) if evaluation
+ // failed.
if (!Result)
Eval->Evaluated = APValue();
+ else if (Eval->Evaluated.needsCleanup())
+ getASTContext().AddDeallocation(DestroyAPValue, &Eval->Evaluated);
Eval->IsEvaluating = false;
Eval->WasEvaluated = true;
@@ -1853,19 +2022,6 @@ bool VarDecl::checkInitIsICE() const {
return Eval->IsICE;
}
-bool VarDecl::extendsLifetimeOfTemporary() const {
- assert(getType()->isReferenceType() &&"Non-references never extend lifetime");
-
- const Expr *E = getInit();
- if (!E)
- return false;
-
- if (const ExprWithCleanups *Cleanups = dyn_cast<ExprWithCleanups>(E))
- E = Cleanups->getSubExpr();
-
- return isa<MaterializeTemporaryExpr>(E);
-}
-
VarDecl *VarDecl::getInstantiatedFromStaticDataMember() const {
if (MemberSpecializationInfo *MSI = getMemberSpecializationInfo())
return cast<VarDecl>(MSI->getInstantiatedFrom());
@@ -1874,25 +2030,73 @@ VarDecl *VarDecl::getInstantiatedFromStaticDataMember() const {
}
TemplateSpecializationKind VarDecl::getTemplateSpecializationKind() const {
+ if (const VarTemplateSpecializationDecl *Spec =
+ dyn_cast<VarTemplateSpecializationDecl>(this))
+ return Spec->getSpecializationKind();
+
if (MemberSpecializationInfo *MSI = getMemberSpecializationInfo())
return MSI->getTemplateSpecializationKind();
-
+
return TSK_Undeclared;
}
+SourceLocation VarDecl::getPointOfInstantiation() const {
+ if (const VarTemplateSpecializationDecl *Spec =
+ dyn_cast<VarTemplateSpecializationDecl>(this))
+ return Spec->getPointOfInstantiation();
+
+ if (MemberSpecializationInfo *MSI = getMemberSpecializationInfo())
+ return MSI->getPointOfInstantiation();
+
+ return SourceLocation();
+}
+
+VarTemplateDecl *VarDecl::getDescribedVarTemplate() const {
+ return getASTContext().getTemplateOrSpecializationInfo(this)
+ .dyn_cast<VarTemplateDecl *>();
+}
+
+void VarDecl::setDescribedVarTemplate(VarTemplateDecl *Template) {
+ getASTContext().setTemplateOrSpecializationInfo(this, Template);
+}
+
MemberSpecializationInfo *VarDecl::getMemberSpecializationInfo() const {
- return getASTContext().getInstantiatedFromStaticDataMember(this);
+ if (isStaticDataMember())
+ // FIXME: Remove ?
+ // return getASTContext().getInstantiatedFromStaticDataMember(this);
+ return getASTContext().getTemplateOrSpecializationInfo(this)
+ .dyn_cast<MemberSpecializationInfo *>();
+ return 0;
}
void VarDecl::setTemplateSpecializationKind(TemplateSpecializationKind TSK,
SourceLocation PointOfInstantiation) {
- MemberSpecializationInfo *MSI = getMemberSpecializationInfo();
- assert(MSI && "Not an instantiated static data member?");
- MSI->setTemplateSpecializationKind(TSK);
- if (TSK != TSK_ExplicitSpecialization &&
- PointOfInstantiation.isValid() &&
- MSI->getPointOfInstantiation().isInvalid())
- MSI->setPointOfInstantiation(PointOfInstantiation);
+ assert((isa<VarTemplateSpecializationDecl>(this) ||
+ getMemberSpecializationInfo()) &&
+ "not a variable or static data member template specialization");
+
+ if (VarTemplateSpecializationDecl *Spec =
+ dyn_cast<VarTemplateSpecializationDecl>(this)) {
+ Spec->setSpecializationKind(TSK);
+ if (TSK != TSK_ExplicitSpecialization && PointOfInstantiation.isValid() &&
+ Spec->getPointOfInstantiation().isInvalid())
+ Spec->setPointOfInstantiation(PointOfInstantiation);
+ }
+
+ if (MemberSpecializationInfo *MSI = getMemberSpecializationInfo()) {
+ MSI->setTemplateSpecializationKind(TSK);
+ if (TSK != TSK_ExplicitSpecialization && PointOfInstantiation.isValid() &&
+ MSI->getPointOfInstantiation().isInvalid())
+ MSI->setPointOfInstantiation(PointOfInstantiation);
+ }
+}
+
+void
+VarDecl::setInstantiationOfStaticDataMember(VarDecl *VD,
+ TemplateSpecializationKind TSK) {
+ assert(getASTContext().getTemplateOrSpecializationInfo(this).isNull() &&
+ "Previous template or instantiation?");
+ getASTContext().setInstantiatedFromStaticDataMember(this, VD, TSK);
}
//===----------------------------------------------------------------------===//
@@ -1908,6 +2112,14 @@ ParmVarDecl *ParmVarDecl::Create(ASTContext &C, DeclContext *DC,
S, DefArg);
}
+QualType ParmVarDecl::getOriginalType() const {
+ TypeSourceInfo *TSI = getTypeSourceInfo();
+ QualType T = TSI ? TSI->getType() : getType();
+ if (const DecayedType *DT = dyn_cast<DecayedType>(T))
+ return DT->getOriginalType();
+ return T;
+}
+
ParmVarDecl *ParmVarDecl::CreateDeserialized(ASTContext &C, unsigned ID) {
void *Mem = AllocateDeserializedDecl(C, ID, sizeof(ParmVarDecl));
return new (Mem) ParmVarDecl(ParmVar, 0, SourceLocation(), SourceLocation(),
@@ -2010,7 +2222,8 @@ bool FunctionDecl::hasTrivialBody() const
bool FunctionDecl::isDefined(const FunctionDecl *&Definition) const {
for (redecl_iterator I = redecls_begin(), E = redecls_end(); I != E; ++I) {
- if (I->IsDeleted || I->IsDefaulted || I->Body || I->IsLateTemplateParsed) {
+ if (I->IsDeleted || I->IsDefaulted || I->Body || I->IsLateTemplateParsed ||
+ I->hasAttr<AliasAttr>()) {
Definition = I->IsDeleted ? I->getCanonicalDecl() : *I;
return true;
}
@@ -2020,15 +2233,11 @@ bool FunctionDecl::isDefined(const FunctionDecl *&Definition) const {
}
Stmt *FunctionDecl::getBody(const FunctionDecl *&Definition) const {
- for (redecl_iterator I = redecls_begin(), E = redecls_end(); I != E; ++I) {
- if (I->Body) {
- Definition = *I;
- return I->Body.get(getASTContext().getExternalSource());
- } else if (I->IsLateTemplateParsed) {
- Definition = *I;
- return 0;
- }
- }
+ if (!hasBody(Definition))
+ return 0;
+
+ if (Definition->Body)
+ return Definition->Body.get(getASTContext().getExternalSource());
return 0;
}
@@ -2046,13 +2255,45 @@ void FunctionDecl::setPure(bool P) {
Parent->markedVirtualFunctionPure();
}
+template<std::size_t Len>
+static bool isNamed(const NamedDecl *ND, const char (&Str)[Len]) {
+ IdentifierInfo *II = ND->getIdentifier();
+ return II && II->isStr(Str);
+}
+
bool FunctionDecl::isMain() const {
const TranslationUnitDecl *tunit =
dyn_cast<TranslationUnitDecl>(getDeclContext()->getRedeclContext());
return tunit &&
!tunit->getASTContext().getLangOpts().Freestanding &&
- getIdentifier() &&
- getIdentifier()->isStr("main");
+ isNamed(this, "main");
+}
+
+bool FunctionDecl::isMSVCRTEntryPoint() const {
+ const TranslationUnitDecl *TUnit =
+ dyn_cast<TranslationUnitDecl>(getDeclContext()->getRedeclContext());
+ if (!TUnit)
+ return false;
+
+ // Even though we aren't really targeting MSVCRT if we are freestanding,
+ // semantic analysis for these functions remains the same.
+
+ // MSVCRT entry points only exist on MSVCRT targets.
+ if (!TUnit->getASTContext().getTargetInfo().getTriple().isOSMSVCRT())
+ return false;
+
+ // Nameless functions like constructors cannot be entry points.
+ if (!getIdentifier())
+ return false;
+
+ return llvm::StringSwitch<bool>(getName())
+ .Cases("main", // an ANSI console app
+ "wmain", // a Unicode console App
+ "WinMain", // an ANSI GUI app
+ "wWinMain", // a Unicode GUI app
+ "DllMain", // a DLL
+ true)
+ .Default(false);
}
bool FunctionDecl::isReservedGlobalPlacementOperator() const {
@@ -2077,13 +2318,83 @@ bool FunctionDecl::isReservedGlobalPlacementOperator() const {
return (proto->getArgType(1).getCanonicalType() == Context.VoidPtrTy);
}
-LanguageLinkage FunctionDecl::getLanguageLinkage() const {
- // Users expect to be able to write
- // extern "C" void *__builtin_alloca (size_t);
- // so consider builtins as having C language linkage.
- if (getBuiltinID())
- return CLanguageLinkage;
+static bool isNamespaceStd(const DeclContext *DC) {
+ const NamespaceDecl *ND = dyn_cast<NamespaceDecl>(DC->getRedeclContext());
+ return ND && isNamed(ND, "std") &&
+ ND->getParent()->getRedeclContext()->isTranslationUnit();
+}
+bool FunctionDecl::isReplaceableGlobalAllocationFunction() const {
+ if (getDeclName().getNameKind() != DeclarationName::CXXOperatorName)
+ return false;
+ if (getDeclName().getCXXOverloadedOperator() != OO_New &&
+ getDeclName().getCXXOverloadedOperator() != OO_Delete &&
+ getDeclName().getCXXOverloadedOperator() != OO_Array_New &&
+ getDeclName().getCXXOverloadedOperator() != OO_Array_Delete)
+ return false;
+
+ if (isa<CXXRecordDecl>(getDeclContext()))
+ return false;
+ assert(getDeclContext()->getRedeclContext()->isTranslationUnit());
+
+ const FunctionProtoType *FPT = getType()->castAs<FunctionProtoType>();
+ if (FPT->getNumArgs() > 2 || FPT->isVariadic())
+ return false;
+
+ // If this is a single-parameter function, it must be a replaceable global
+ // allocation or deallocation function.
+ if (FPT->getNumArgs() == 1)
+ return true;
+
+ // Otherwise, we're looking for a second parameter whose type is
+ // 'const std::nothrow_t &', or, in C++1y, 'std::size_t'.
+ QualType Ty = FPT->getArgType(1);
+ ASTContext &Ctx = getASTContext();
+ if (Ctx.getLangOpts().SizedDeallocation &&
+ Ctx.hasSameType(Ty, Ctx.getSizeType()))
+ return true;
+ if (!Ty->isReferenceType())
+ return false;
+ Ty = Ty->getPointeeType();
+ if (Ty.getCVRQualifiers() != Qualifiers::Const)
+ return false;
+ // FIXME: Recognise nothrow_t in an inline namespace inside std?
+ const CXXRecordDecl *RD = Ty->getAsCXXRecordDecl();
+ return RD && isNamed(RD, "nothrow_t") && isNamespaceStd(RD->getDeclContext());
+}
+
+FunctionDecl *
+FunctionDecl::getCorrespondingUnsizedGlobalDeallocationFunction() const {
+ ASTContext &Ctx = getASTContext();
+ if (!Ctx.getLangOpts().SizedDeallocation)
+ return 0;
+
+ if (getDeclName().getNameKind() != DeclarationName::CXXOperatorName)
+ return 0;
+ if (getDeclName().getCXXOverloadedOperator() != OO_Delete &&
+ getDeclName().getCXXOverloadedOperator() != OO_Array_Delete)
+ return 0;
+ if (isa<CXXRecordDecl>(getDeclContext()))
+ return 0;
+ assert(getDeclContext()->getRedeclContext()->isTranslationUnit());
+
+ if (getNumParams() != 2 || isVariadic() ||
+ !Ctx.hasSameType(getType()->castAs<FunctionProtoType>()->getArgType(1),
+ Ctx.getSizeType()))
+ return 0;
+
+ // This is a sized deallocation function. Find the corresponding unsized
+ // deallocation function.
+ lookup_const_result R = getDeclContext()->lookup(getDeclName());
+ for (lookup_const_result::iterator RI = R.begin(), RE = R.end(); RI != RE;
+ ++RI)
+ if (FunctionDecl *FD = dyn_cast<FunctionDecl>(*RI))
+ if (FD->getNumParams() == 1 && !FD->isVariadic())
+ return FD;
+ return 0;
+}
+
+LanguageLinkage FunctionDecl::getLanguageLinkage() const {
return getLanguageLinkageTemplate(*this);
}
@@ -2092,11 +2403,11 @@ bool FunctionDecl::isExternC() const {
}
bool FunctionDecl::isInExternCContext() const {
- return isInLanguageSpecContext(this, LinkageSpecDecl::lang_c);
+ return getLexicalDeclContext()->isExternCContext();
}
bool FunctionDecl::isInExternCXXContext() const {
- return isInLanguageSpecContext(this, LinkageSpecDecl::lang_cxx);
+ return getLexicalDeclContext()->isExternCXXContext();
}
bool FunctionDecl::isGlobal() const {
@@ -2127,13 +2438,13 @@ bool FunctionDecl::isNoReturn() const {
void
FunctionDecl::setPreviousDeclaration(FunctionDecl *PrevDecl) {
- redeclarable_base::setPreviousDeclaration(PrevDecl);
+ redeclarable_base::setPreviousDecl(PrevDecl);
if (FunctionTemplateDecl *FunTmpl = getDescribedFunctionTemplate()) {
FunctionTemplateDecl *PrevFunTmpl
= PrevDecl? PrevDecl->getDescribedFunctionTemplate() : 0;
assert((!PrevDecl || PrevFunTmpl) && "Function/function template mismatch");
- FunTmpl->setPreviousDeclaration(PrevFunTmpl);
+ FunTmpl->setPreviousDecl(PrevFunTmpl);
}
if (PrevDecl && PrevDecl->IsInline)
@@ -2141,12 +2452,10 @@ FunctionDecl::setPreviousDeclaration(FunctionDecl *PrevDecl) {
}
const FunctionDecl *FunctionDecl::getCanonicalDecl() const {
- return getFirstDeclaration();
+ return getFirstDecl();
}
-FunctionDecl *FunctionDecl::getCanonicalDecl() {
- return getFirstDeclaration();
-}
+FunctionDecl *FunctionDecl::getCanonicalDecl() { return getFirstDecl(); }
/// \brief Returns a value indicating whether this function
/// corresponds to a builtin function.
@@ -2166,6 +2475,22 @@ unsigned FunctionDecl::getBuiltinID() const {
return 0;
ASTContext &Context = getASTContext();
+ if (Context.getLangOpts().CPlusPlus) {
+ const LinkageSpecDecl *LinkageDecl = dyn_cast<LinkageSpecDecl>(
+ getFirstDecl()->getDeclContext());
+ // In C++, the first declaration of a builtin is always inside an implicit
+ // extern "C".
+ // FIXME: A recognised library function may not be directly in an extern "C"
+ // declaration, for instance "extern "C" { namespace std { decl } }".
+ if (!LinkageDecl || LinkageDecl->getLanguage() != LinkageSpecDecl::lang_c)
+ return 0;
+ }
+
+ // If the function is marked "overloadable", it has a different mangled name
+ // and is not the C library function.
+ if (getAttr<OverloadableAttr>())
+ return 0;
+
if (!Context.BuiltinInfo.isPredefinedLibFunction(BuiltinID))
return BuiltinID;
@@ -2177,22 +2502,7 @@ unsigned FunctionDecl::getBuiltinID() const {
if (getStorageClass() == SC_Static)
return 0;
- // If this function is at translation-unit scope and we're not in
- // C++, it refers to the C library function.
- if (!Context.getLangOpts().CPlusPlus &&
- getDeclContext()->isTranslationUnit())
- return BuiltinID;
-
- // If the function is in an extern "C" linkage specification and is
- // not marked "overloadable", it's the real function.
- if (isa<LinkageSpecDecl>(getDeclContext()) &&
- cast<LinkageSpecDecl>(getDeclContext())->getLanguage()
- == LinkageSpecDecl::lang_c &&
- !getAttr<OverloadableAttr>())
- return BuiltinID;
-
- // Not a builtin
- return 0;
+ return BuiltinID;
}
@@ -2304,7 +2614,7 @@ bool FunctionDecl::doesDeclarationForceExternallyVisibleDefinition() const {
const FunctionDecl *Prev = this;
bool FoundBody = false;
while ((Prev = Prev->getPreviousDecl())) {
- FoundBody |= Prev->Body;
+ FoundBody |= Prev->Body.isValid();
if (Prev->Body) {
// If it's not the case that both 'inline' and 'extern' are
@@ -2332,7 +2642,7 @@ bool FunctionDecl::doesDeclarationForceExternallyVisibleDefinition() const {
const FunctionDecl *Prev = this;
bool FoundBody = false;
while ((Prev = Prev->getPreviousDecl())) {
- FoundBody |= Prev->Body;
+ FoundBody |= Prev->Body.isValid();
if (RedeclForcesDefC99(Prev))
return false;
}
@@ -2818,26 +3128,18 @@ unsigned FieldDecl::getBitWidthValue(const ASTContext &Ctx) const {
}
unsigned FieldDecl::getFieldIndex() const {
+ const FieldDecl *Canonical = getCanonicalDecl();
+ if (Canonical != this)
+ return Canonical->getFieldIndex();
+
if (CachedFieldIndex) return CachedFieldIndex - 1;
unsigned Index = 0;
const RecordDecl *RD = getParent();
- const FieldDecl *LastFD = 0;
- bool IsMsStruct = RD->isMsStruct(getASTContext());
for (RecordDecl::field_iterator I = RD->field_begin(), E = RD->field_end();
- I != E; ++I, ++Index) {
- I->CachedFieldIndex = Index + 1;
-
- if (IsMsStruct) {
- // Zero-length bitfields following non-bitfield members are ignored.
- if (getASTContext().ZeroBitfieldFollowsNonBitfield(*I, LastFD)) {
- --Index;
- continue;
- }
- LastFD = *I;
- }
- }
+ I != E; ++I, ++Index)
+ I->getCanonicalDecl()->CachedFieldIndex = Index + 1;
assert(CachedFieldIndex && "failed to find field in parent");
return CachedFieldIndex - 1;
@@ -2874,12 +3176,10 @@ SourceRange TagDecl::getSourceRange() const {
return SourceRange(getOuterLocStart(), E);
}
-TagDecl* TagDecl::getCanonicalDecl() {
- return getFirstDeclaration();
-}
+TagDecl *TagDecl::getCanonicalDecl() { return getFirstDecl(); }
void TagDecl::setTypedefNameForAnonDecl(TypedefNameDecl *TDD) {
- TypedefNameDeclOrQualifier = TDD;
+ NamedDeclOrQualifier = TDD;
if (TypeForDecl)
assert(TypeForDecl->isLinkageValid());
assert(isLinkageValid());
@@ -2936,7 +3236,7 @@ void TagDecl::setQualifierInfo(NestedNameSpecifierLoc QualifierLoc) {
if (QualifierLoc) {
// Make sure the extended qualifier info is allocated.
if (!hasExtInfo())
- TypedefNameDeclOrQualifier = new (getASTContext()) ExtInfo;
+ NamedDeclOrQualifier = new (getASTContext()) ExtInfo;
// Set qualifier info.
getExtInfo()->QualifierLoc = QualifierLoc;
} else {
@@ -2944,7 +3244,7 @@ void TagDecl::setQualifierInfo(NestedNameSpecifierLoc QualifierLoc) {
if (hasExtInfo()) {
if (getExtInfo()->NumTemplParamLists == 0) {
getASTContext().Deallocate(getExtInfo());
- TypedefNameDeclOrQualifier = (TypedefNameDecl*) 0;
+ NamedDeclOrQualifier = (TypedefNameDecl*) 0;
}
else
getExtInfo()->QualifierLoc = QualifierLoc;
@@ -2959,7 +3259,7 @@ void TagDecl::setTemplateParameterListsInfo(ASTContext &Context,
// Make sure the extended decl info is allocated.
if (!hasExtInfo())
// Allocate external info struct.
- TypedefNameDeclOrQualifier = new (getASTContext()) ExtInfo;
+ NamedDeclOrQualifier = new (getASTContext()) ExtInfo;
// Set the template parameter lists info.
getExtInfo()->setTemplateParameterListsInfo(Context, NumTPLists, TPLists);
}
diff --git a/lib/AST/DeclBase.cpp b/lib/AST/DeclBase.cpp
index 084a4321d8f1..121c5a671a29 100644
--- a/lib/AST/DeclBase.cpp
+++ b/lib/AST/DeclBase.cpp
@@ -291,6 +291,16 @@ bool Decl::isUsed(bool CheckUsedAttr) const {
return false;
}
+void Decl::markUsed(ASTContext &C) {
+ if (Used)
+ return;
+
+ if (C.getASTMutationListener())
+ C.getASTMutationListener()->DeclarationMarkedUsed(this);
+
+ Used = true;
+}
+
bool Decl::isReferenced() const {
if (Referenced)
return true;
@@ -538,6 +548,7 @@ unsigned Decl::getIdentifierNamespaceForKind(Kind DeclKind) {
return IDNS_Namespace;
case FunctionTemplate:
+ case VarTemplate:
return IDNS_Ordinary;
case ClassTemplate:
@@ -560,6 +571,8 @@ unsigned Decl::getIdentifierNamespaceForKind(Kind DeclKind) {
case ClassTemplateSpecialization:
case ClassTemplatePartialSpecialization:
case ClassScopeFunctionSpecialization:
+ case VarTemplateSpecialization:
+ case VarTemplatePartialSpecialization:
case ObjCImplementation:
case ObjCCategory:
case ObjCCategoryImpl:
@@ -595,32 +608,6 @@ const AttrVec &Decl::getAttrs() const {
return getASTContext().getDeclAttrs(this);
}
-void Decl::swapAttrs(Decl *RHS) {
- bool HasLHSAttr = this->HasAttrs;
- bool HasRHSAttr = RHS->HasAttrs;
-
- // Usually, neither decl has attrs, nothing to do.
- if (!HasLHSAttr && !HasRHSAttr) return;
-
- // If 'this' has no attrs, swap the other way.
- if (!HasLHSAttr)
- return RHS->swapAttrs(this);
-
- ASTContext &Context = getASTContext();
-
- // Handle the case when both decls have attrs.
- if (HasRHSAttr) {
- std::swap(Context.getDeclAttrs(this), Context.getDeclAttrs(RHS));
- return;
- }
-
- // Otherwise, LHS has an attr and RHS doesn't.
- Context.getDeclAttrs(RHS) = Context.getDeclAttrs(this);
- Context.eraseDeclAttrs(this);
- this->HasAttrs = false;
- RHS->HasAttrs = true;
-}
-
Decl *Decl::castFromDeclContext (const DeclContext *D) {
Decl::Kind DK = D->getDeclKind();
switch(DK) {
@@ -819,6 +806,24 @@ bool DeclContext::isTransparentContext() const {
return false;
}
+static bool isLinkageSpecContext(const DeclContext *DC,
+ LinkageSpecDecl::LanguageIDs ID) {
+ while (DC->getDeclKind() != Decl::TranslationUnit) {
+ if (DC->getDeclKind() == Decl::LinkageSpec)
+ return cast<LinkageSpecDecl>(DC)->getLanguage() == ID;
+ DC = DC->getParent();
+ }
+ return false;
+}
+
+bool DeclContext::isExternCContext() const {
+ return isLinkageSpecContext(this, clang::LinkageSpecDecl::lang_c);
+}
+
+bool DeclContext::isExternCXXContext() const {
+ return isLinkageSpecContext(this, clang::LinkageSpecDecl::lang_cxx);
+}
+
bool DeclContext::Encloses(const DeclContext *DC) const {
if (getPrimaryContext() != this)
return getPrimaryContext()->Encloses(DC);
@@ -939,11 +944,8 @@ void DeclContext::reconcileExternalVisibleStorage() {
NeedToReconcileExternalVisibleStorage = false;
StoredDeclsMap &Map = *LookupPtr.getPointer();
- ExternalASTSource *Source = getParentASTContext().getExternalSource();
- for (StoredDeclsMap::iterator I = Map.begin(); I != Map.end(); ++I) {
- I->second.removeExternalDecls();
- Source->FindExternalVisibleDeclsByName(this, I->first);
- }
+ for (StoredDeclsMap::iterator I = Map.begin(); I != Map.end(); ++I)
+ I->second.setHasExternalDecls();
}
/// \brief Load the declarations within this lexical storage from an
@@ -996,8 +998,7 @@ ExternalASTSource::SetNoExternalVisibleDeclsForName(const DeclContext *DC,
if (!(Map = DC->LookupPtr.getPointer()))
Map = DC->CreateStoredDeclsMap(Context);
- // Add an entry to the map for this name, if it's not already present.
- (*Map)[Name];
+ (*Map)[Name].removeExternalDecls();
return DeclContext::lookup_result();
}
@@ -1012,13 +1013,38 @@ ExternalASTSource::SetExternalVisibleDeclsForName(const DeclContext *DC,
Map = DC->CreateStoredDeclsMap(Context);
StoredDeclsList &List = (*Map)[Name];
- for (ArrayRef<NamedDecl*>::iterator
- I = Decls.begin(), E = Decls.end(); I != E; ++I) {
- if (List.isNull())
- List.setOnlyValue(*I);
- else
- // FIXME: Need declarationReplaces handling for redeclarations in modules.
- List.AddSubsequentDecl(*I);
+
+ // Clear out any old external visible declarations, to avoid quadratic
+ // performance in the redeclaration checks below.
+ List.removeExternalDecls();
+
+ if (!List.isNull()) {
+ // We have both existing declarations and new declarations for this name.
+ // Some of the declarations may simply replace existing ones. Handle those
+ // first.
+ llvm::SmallVector<unsigned, 8> Skip;
+ for (unsigned I = 0, N = Decls.size(); I != N; ++I)
+ if (List.HandleRedeclaration(Decls[I]))
+ Skip.push_back(I);
+ Skip.push_back(Decls.size());
+
+ // Add in any new declarations.
+ unsigned SkipPos = 0;
+ for (unsigned I = 0, N = Decls.size(); I != N; ++I) {
+ if (I == Skip[SkipPos])
+ ++SkipPos;
+ else
+ List.AddSubsequentDecl(Decls[I]);
+ }
+ } else {
+ // Convert the array to a StoredDeclsList.
+ for (ArrayRef<NamedDecl*>::iterator
+ I = Decls.begin(), E = Decls.end(); I != E; ++I) {
+ if (List.isNull())
+ List.setOnlyValue(*I);
+ else
+ List.AddSubsequentDecl(*I);
+ }
}
return List.getLookupResult();
@@ -1171,7 +1197,8 @@ StoredDeclsMap *DeclContext::buildLookup() {
SmallVector<DeclContext *, 2> Contexts;
collectAllContexts(Contexts);
for (unsigned I = 0, N = Contexts.size(); I != N; ++I)
- buildLookupImpl(Contexts[I]);
+ buildLookupImpl<&DeclContext::decls_begin,
+ &DeclContext::decls_end>(Contexts[I]);
// We no longer have any lazy decls.
LookupPtr.setInt(false);
@@ -1183,16 +1210,26 @@ StoredDeclsMap *DeclContext::buildLookup() {
/// declarations contained within DCtx, which will either be this
/// DeclContext, a DeclContext linked to it, or a transparent context
/// nested within it.
+template<DeclContext::decl_iterator (DeclContext::*Begin)() const,
+ DeclContext::decl_iterator (DeclContext::*End)() const>
void DeclContext::buildLookupImpl(DeclContext *DCtx) {
- for (decl_iterator I = DCtx->decls_begin(), E = DCtx->decls_end();
+ for (decl_iterator I = (DCtx->*Begin)(), E = (DCtx->*End)();
I != E; ++I) {
Decl *D = *I;
// Insert this declaration into the lookup structure, but only if
// it's semantically within its decl context. Any other decls which
// should be found in this context are added eagerly.
+ //
+ // If it's from an AST file, don't add it now. It'll get handled by
+ // FindExternalVisibleDeclsByName if needed. Exception: if we're not
+ // in C++, we do not track external visible decls for the TU, so in
+ // that case we need to collect them all here.
if (NamedDecl *ND = dyn_cast<NamedDecl>(D))
- if (ND->getDeclContext() == DCtx && !shouldBeHidden(ND))
+ if (ND->getDeclContext() == DCtx && !shouldBeHidden(ND) &&
+ (!ND->isFromASTFile() ||
+ (isTranslationUnit() &&
+ !getParentASTContext().getLangOpts().CPlusPlus)))
makeDeclVisibleInContextImpl(ND, false);
// If this declaration is itself a transparent declaration context
@@ -1200,7 +1237,7 @@ void DeclContext::buildLookupImpl(DeclContext *DCtx) {
// context (recursively).
if (DeclContext *InnerCtx = dyn_cast<DeclContext>(D))
if (InnerCtx->isTransparentContext() || InnerCtx->isInlineNamespace())
- buildLookupImpl(InnerCtx);
+ buildLookupImpl<Begin, End>(InnerCtx);
}
}
@@ -1223,16 +1260,14 @@ DeclContext::lookup(DeclarationName Name) {
if (!Map)
Map = CreateStoredDeclsMap(getParentASTContext());
- // If a PCH/module has a result for this name, and we have a local
- // declaration, we will have imported the PCH/module result when adding the
- // local declaration or when reconciling the module.
+ // If we have a lookup result with no external decls, we are done.
std::pair<StoredDeclsMap::iterator, bool> R =
Map->insert(std::make_pair(Name, StoredDeclsList()));
- if (!R.second)
+ if (!R.second && !R.first->second.hasExternalDecls())
return R.first->second.getLookupResult();
ExternalASTSource *Source = getParentASTContext().getExternalSource();
- if (Source->FindExternalVisibleDeclsByName(this, Name)) {
+ if (Source->FindExternalVisibleDeclsByName(this, Name) || R.second) {
if (StoredDeclsMap *Map = LookupPtr.getPointer()) {
StoredDeclsMap::iterator I = Map->find(Name);
if (I != Map->end())
@@ -1257,6 +1292,46 @@ DeclContext::lookup(DeclarationName Name) {
return I->second.getLookupResult();
}
+DeclContext::lookup_result
+DeclContext::noload_lookup(DeclarationName Name) {
+ assert(DeclKind != Decl::LinkageSpec &&
+ "Should not perform lookups into linkage specs!");
+ if (!hasExternalVisibleStorage())
+ return lookup(Name);
+
+ DeclContext *PrimaryContext = getPrimaryContext();
+ if (PrimaryContext != this)
+ return PrimaryContext->noload_lookup(Name);
+
+ StoredDeclsMap *Map = LookupPtr.getPointer();
+ if (LookupPtr.getInt()) {
+ // Carefully build the lookup map, without deserializing anything.
+ SmallVector<DeclContext *, 2> Contexts;
+ collectAllContexts(Contexts);
+ for (unsigned I = 0, N = Contexts.size(); I != N; ++I)
+ buildLookupImpl<&DeclContext::noload_decls_begin,
+ &DeclContext::noload_decls_end>(Contexts[I]);
+
+ // We no longer have any lazy decls.
+ LookupPtr.setInt(false);
+
+ // There may now be names for which we have local decls but are
+ // missing the external decls. FIXME: Just set the hasExternalDecls
+ // flag on those names that have external decls.
+ NeedToReconcileExternalVisibleStorage = true;
+
+ Map = LookupPtr.getPointer();
+ }
+
+ if (!Map)
+ return lookup_result(lookup_iterator(0), lookup_iterator(0));
+
+ StoredDeclsMap::iterator I = Map->find(Name);
+ return I != Map->end()
+ ? I->second.getLookupResult()
+ : lookup_result(lookup_iterator(0), lookup_iterator(0));
+}
+
void DeclContext::localUncachedLookup(DeclarationName Name,
SmallVectorImpl<NamedDecl *> &Results) {
Results.clear();
@@ -1338,14 +1413,7 @@ void DeclContext::makeDeclVisibleInContextWithFlags(NamedDecl *D, bool Internal,
assert(this == getPrimaryContext() && "expected a primary DC");
// Skip declarations within functions.
- // FIXME: We shouldn't need to build lookup tables for function declarations
- // ever, and we can't do so correctly because we can't model the nesting of
- // scopes which occurs within functions. We use "qualified" lookup into
- // function declarations when handling friend declarations inside nested
- // classes, and consequently accept the following invalid code:
- //
- // void f() { void g(); { int g; struct S { friend void g(); }; } }
- if (isFunctionOrMethod() && !isa<FunctionDecl>(D))
+ if (isFunctionOrMethod())
return;
// Skip declarations which should be invisible to name lookup.
@@ -1406,7 +1474,18 @@ void DeclContext::makeDeclVisibleInContextImpl(NamedDecl *D, bool Internal) {
// Insert this declaration into the map.
StoredDeclsList &DeclNameEntries = (*Map)[D->getDeclName()];
- if (DeclNameEntries.isNull()) {
+
+ if (Internal) {
+ // If this is being added as part of loading an external declaration,
+ // this may not be the only external declaration with this name.
+ // In this case, we never try to replace an existing declaration; we'll
+ // handle that when we finalize the list of declarations for this name.
+ DeclNameEntries.setHasExternalDecls();
+ DeclNameEntries.AddSubsequentDecl(D);
+ return;
+ }
+
+ else if (DeclNameEntries.isNull()) {
DeclNameEntries.setOnlyValue(D);
return;
}
diff --git a/lib/AST/DeclCXX.cpp b/lib/AST/DeclCXX.cpp
index 064649904d30..a17abdd0ae2a 100644
--- a/lib/AST/DeclCXX.cpp
+++ b/lib/AST/DeclCXX.cpp
@@ -10,9 +10,9 @@
// This file implements the C++ related Decl classes.
//
//===----------------------------------------------------------------------===//
-
#include "clang/AST/DeclCXX.h"
#include "clang/AST/ASTContext.h"
+#include "clang/AST/ASTLambda.h"
#include "clang/AST/ASTMutationListener.h"
#include "clang/AST/CXXInheritance.h"
#include "clang/AST/DeclTemplate.h"
@@ -35,6 +35,17 @@ AccessSpecDecl *AccessSpecDecl::CreateDeserialized(ASTContext &C, unsigned ID) {
return new (Mem) AccessSpecDecl(EmptyShell());
}
+void LazyASTUnresolvedSet::getFromExternalSource(ASTContext &C) const {
+ ExternalASTSource *Source = C.getExternalSource();
+ assert(Impl.Decls.isLazy() && "getFromExternalSource for non-lazy set");
+ assert(Source && "getFromExternalSource with no external source");
+
+ for (ASTUnresolvedSet::iterator I = Impl.begin(); I != Impl.end(); ++I)
+ I.setDecl(cast<NamedDecl>(Source->GetExternalDecl(
+ reinterpret_cast<uintptr_t>(I.getDecl()) >> 2)));
+ Impl.Decls.setLazy(false);
+}
+
CXXRecordDecl::DefinitionData::DefinitionData(CXXRecordDecl *D)
: UserDeclaredConstructor(false), UserDeclaredSpecialMembers(0),
Aggregate(true), PlainOldData(true), Empty(true), Polymorphic(false),
@@ -60,9 +71,8 @@ CXXRecordDecl::DefinitionData::DefinitionData(CXXRecordDecl *D)
ImplicitCopyAssignmentHasConstParam(true),
HasDeclaredCopyConstructorWithConstParam(false),
HasDeclaredCopyAssignmentWithConstParam(false),
- FailedImplicitMoveConstructor(false), FailedImplicitMoveAssignment(false),
IsLambda(false), NumBases(0), NumVBases(0), Bases(), VBases(),
- Definition(D), FirstFriend(0) {
+ Definition(D), FirstFriend() {
}
CXXBaseSpecifier *CXXRecordDecl::DefinitionData::getBasesSlowCase() const {
@@ -97,12 +107,17 @@ CXXRecordDecl *CXXRecordDecl::Create(const ASTContext &C, TagKind TK,
CXXRecordDecl *CXXRecordDecl::CreateLambda(const ASTContext &C, DeclContext *DC,
TypeSourceInfo *Info, SourceLocation Loc,
- bool Dependent) {
+ bool Dependent, bool IsGeneric,
+ LambdaCaptureDefault CaptureDefault) {
CXXRecordDecl* R = new (C) CXXRecordDecl(CXXRecord, TTK_Class, DC, Loc, Loc,
0, 0);
R->IsBeingDefined = true;
- R->DefinitionData = new (C) struct LambdaDefinitionData(R, Info, Dependent);
+ R->DefinitionData = new (C) struct LambdaDefinitionData(R, Info,
+ Dependent,
+ IsGeneric,
+ CaptureDefault);
R->MayHaveOutOfDateDef = false;
+ R->setImplicit(true);
C.getTypeDeclType(R, /*PrevDecl=*/0);
return R;
}
@@ -552,18 +567,16 @@ void CXXRecordDecl::addedMember(Decl *D) {
if (Conversion->getPrimaryTemplate()) {
// We don't record specializations.
- } else if (FunTmpl) {
- if (FunTmpl->getPreviousDecl())
- data().Conversions.replace(FunTmpl->getPreviousDecl(),
- FunTmpl, AS);
- else
- data().Conversions.addDecl(getASTContext(), FunTmpl, AS);
} else {
- if (Conversion->getPreviousDecl())
- data().Conversions.replace(Conversion->getPreviousDecl(),
- Conversion, AS);
+ ASTContext &Ctx = getASTContext();
+ ASTUnresolvedSet &Conversions = data().Conversions.get(Ctx);
+ NamedDecl *Primary =
+ FunTmpl ? cast<NamedDecl>(FunTmpl) : cast<NamedDecl>(Conversion);
+ if (Primary->getPreviousDecl())
+ Conversions.replace(cast<NamedDecl>(Primary->getPreviousDecl()),
+ Primary, AS);
else
- data().Conversions.addDecl(getASTContext(), Conversion, AS);
+ Conversions.addDecl(Ctx, Primary, AS);
}
}
@@ -662,7 +675,7 @@ void CXXRecordDecl::addedMember(Decl *D) {
if (!Context.getLangOpts().ObjCAutoRefCount ||
T.getObjCLifetime() != Qualifiers::OCL_ExplicitNone)
setHasObjectMember(true);
- } else if (!T.isPODType(Context))
+ } else if (!T.isCXX98PODType(Context))
data().PlainOldData = false;
if (T->isReferenceType()) {
@@ -712,6 +725,13 @@ void CXXRecordDecl::addedMember(Decl *D) {
if (FieldRec->getDefinition()) {
addedClassSubobject(FieldRec);
+ // We may need to perform overload resolution to determine whether a
+ // field can be moved if it's const or volatile qualified.
+ if (T.getCVRQualifiers() & (Qualifiers::Const | Qualifiers::Volatile)) {
+ data().NeedOverloadResolutionForMoveConstructor = true;
+ data().NeedOverloadResolutionForMoveAssignment = true;
+ }
+
// C++11 [class.ctor]p5, C++11 [class.copy]p11:
// A defaulted [special member] for a class X is defined as
// deleted if:
@@ -880,10 +900,13 @@ void CXXRecordDecl::addedMember(Decl *D) {
}
// Handle using declarations of conversion functions.
- if (UsingShadowDecl *Shadow = dyn_cast<UsingShadowDecl>(D))
+ if (UsingShadowDecl *Shadow = dyn_cast<UsingShadowDecl>(D)) {
if (Shadow->getDeclName().getNameKind()
- == DeclarationName::CXXConversionFunctionName)
- data().Conversions.addDecl(getASTContext(), Shadow, Shadow->getAccess());
+ == DeclarationName::CXXConversionFunctionName) {
+ ASTContext &Ctx = getASTContext();
+ data().Conversions.get(Ctx).addDecl(Ctx, Shadow, Shadow->getAccess());
+ }
+ }
}
void CXXRecordDecl::finishedDefaultedOrDeletedMember(CXXMethodDecl *D) {
@@ -929,6 +952,43 @@ bool CXXRecordDecl::isCLike() const {
return isPOD() && data().HasOnlyCMembers;
}
+
+bool CXXRecordDecl::isGenericLambda() const {
+ if (!isLambda()) return false;
+ return getLambdaData().IsGenericLambda;
+}
+
+CXXMethodDecl* CXXRecordDecl::getLambdaCallOperator() const {
+ if (!isLambda()) return 0;
+ DeclarationName Name =
+ getASTContext().DeclarationNames.getCXXOperatorName(OO_Call);
+ DeclContext::lookup_const_result Calls = lookup(Name);
+
+ assert(!Calls.empty() && "Missing lambda call operator!");
+ assert(Calls.size() == 1 && "More than one lambda call operator!");
+
+ NamedDecl *CallOp = Calls.front();
+ if (FunctionTemplateDecl *CallOpTmpl =
+ dyn_cast<FunctionTemplateDecl>(CallOp))
+ return cast<CXXMethodDecl>(CallOpTmpl->getTemplatedDecl());
+
+ return cast<CXXMethodDecl>(CallOp);
+}
+
+CXXMethodDecl* CXXRecordDecl::getLambdaStaticInvoker() const {
+ if (!isLambda()) return 0;
+ DeclarationName Name =
+ &getASTContext().Idents.get(getLambdaStaticInvokerName());
+ DeclContext::lookup_const_result Invoker = lookup(Name);
+ if (Invoker.empty()) return 0;
+ assert(Invoker.size() == 1 && "More than one static invoker operator!");
+ NamedDecl *InvokerFun = Invoker.front();
+ if (FunctionTemplateDecl *InvokerTemplate =
+ dyn_cast<FunctionTemplateDecl>(InvokerFun))
+ return cast<CXXMethodDecl>(InvokerTemplate->getTemplatedDecl());
+
+ return cast<CXXMethodDecl>(InvokerFun);
+}
void CXXRecordDecl::getCaptureFields(
llvm::DenseMap<const VarDecl *, FieldDecl *> &Captures,
@@ -940,15 +1000,22 @@ void CXXRecordDecl::getCaptureFields(
RecordDecl::field_iterator Field = field_begin();
for (LambdaExpr::Capture *C = Lambda.Captures, *CEnd = C + Lambda.NumCaptures;
C != CEnd; ++C, ++Field) {
- if (C->capturesThis()) {
+ if (C->capturesThis())
ThisCapture = *Field;
- continue;
- }
-
- Captures[C->getCapturedVar()] = *Field;
+ else if (C->capturesVariable())
+ Captures[C->getCapturedVar()] = *Field;
}
+ assert(Field == field_end());
}
+TemplateParameterList *
+CXXRecordDecl::getGenericLambdaTemplateParameterList() const {
+ if (!isLambda()) return 0;
+ CXXMethodDecl *CallOp = getLambdaCallOperator();
+ if (FunctionTemplateDecl *Tmpl = CallOp->getDescribedFunctionTemplate())
+ return Tmpl->getTemplateParameters();
+ return 0;
+}
static CanQualType GetConversionType(ASTContext &Context, NamedDecl *Conv) {
QualType T;
@@ -1085,16 +1152,21 @@ static void CollectVisibleConversions(ASTContext &Context,
/// in current class; including conversion function templates.
std::pair<CXXRecordDecl::conversion_iterator,CXXRecordDecl::conversion_iterator>
CXXRecordDecl::getVisibleConversionFunctions() {
- // If root class, all conversions are visible.
- if (bases_begin() == bases_end())
- return std::make_pair(data().Conversions.begin(), data().Conversions.end());
- // If visible conversion list is already evaluated, return it.
- if (!data().ComputedVisibleConversions) {
- CollectVisibleConversions(getASTContext(), this, data().VisibleConversions);
- data().ComputedVisibleConversions = true;
+ ASTContext &Ctx = getASTContext();
+
+ ASTUnresolvedSet *Set;
+ if (bases_begin() == bases_end()) {
+ // If root class, all conversions are visible.
+ Set = &data().Conversions.get(Ctx);
+ } else {
+ Set = &data().VisibleConversions.get(Ctx);
+ // If visible conversion list is not evaluated, evaluate it.
+ if (!data().ComputedVisibleConversions) {
+ CollectVisibleConversions(Ctx, this, *Set);
+ data().ComputedVisibleConversions = true;
+ }
}
- return std::make_pair(data().VisibleConversions.begin(),
- data().VisibleConversions.end());
+ return std::make_pair(Set->begin(), Set->end());
}
void CXXRecordDecl::removeConversion(const NamedDecl *ConvDecl) {
@@ -1109,7 +1181,7 @@ void CXXRecordDecl::removeConversion(const NamedDecl *ConvDecl) {
// with sufficiently large numbers of directly-declared conversions
// that asymptotic behavior matters.
- ASTUnresolvedSet &Convs = data().Conversions;
+ ASTUnresolvedSet &Convs = data().Conversions.get(getASTContext());
for (unsigned I = 0, E = Convs.size(); I != E; ++I) {
if (Convs[I].getDecl() == ConvDecl) {
Convs.erase(I);
@@ -1134,7 +1206,7 @@ CXXRecordDecl::setInstantiationOfMemberClass(CXXRecordDecl *RD,
TemplateSpecializationKind TSK) {
assert(TemplateOrInstantiation.isNull() &&
"Previous template or instantiation?");
- assert(!isa<ClassTemplateSpecializationDecl>(this));
+ assert(!isa<ClassTemplatePartialSpecializationDecl>(this));
TemplateOrInstantiation
= new (getASTContext()) MemberSpecializationInfo(RD, TSK);
}
@@ -1235,8 +1307,7 @@ void CXXRecordDecl::completeDefinition(CXXFinalOverriderMap *FinalOverriders) {
}
// Set access bits correctly on the directly-declared conversions.
- for (UnresolvedSetIterator I = data().Conversions.begin(),
- E = data().Conversions.end();
+ for (conversion_iterator I = conversion_begin(), E = conversion_end();
I != E; ++I)
I.setAccess((*I)->getAccess());
}
@@ -1266,21 +1337,8 @@ bool CXXMethodDecl::isStatic() const {
if (MD->getStorageClass() == SC_Static)
return true;
- DeclarationName Name = getDeclName();
- // [class.free]p1:
- // Any allocation function for a class T is a static member
- // (even if not explicitly declared static).
- if (Name.getCXXOverloadedOperator() == OO_New ||
- Name.getCXXOverloadedOperator() == OO_Array_New)
- return true;
-
- // [class.free]p6 Any deallocation function for a class X is a static member
- // (even if not explicitly declared static).
- if (Name.getCXXOverloadedOperator() == OO_Delete ||
- Name.getCXXOverloadedOperator() == OO_Array_Delete)
- return true;
-
- return false;
+ OverloadedOperatorKind OOK = getDeclName().getCXXOverloadedOperator();
+ return isStaticOverloadedOperator(OOK);
}
static bool recursivelyOverrides(const CXXMethodDecl *DerivedMD,
@@ -1408,7 +1466,8 @@ bool CXXMethodDecl::isCopyAssignmentOperator() const {
// type X, X&, const X&, volatile X& or const volatile X&.
if (/*operator=*/getOverloadedOperator() != OO_Equal ||
/*non-static*/ isStatic() ||
- /*non-template*/getPrimaryTemplate() || getDescribedFunctionTemplate())
+ /*non-template*/getPrimaryTemplate() || getDescribedFunctionTemplate() ||
+ getNumParams() != 1)
return false;
QualType ParamType = getParamDecl(0)->getType();
@@ -1427,7 +1486,8 @@ bool CXXMethodDecl::isMoveAssignmentOperator() const {
// non-template member function of class X with exactly one parameter of type
// X&&, const X&&, volatile X&&, or const volatile X&&.
if (getOverloadedOperator() != OO_Equal || isStatic() ||
- getPrimaryTemplate() || getDescribedFunctionTemplate())
+ getPrimaryTemplate() || getDescribedFunctionTemplate() ||
+ getNumParams() != 1)
return false;
QualType ParamType = getParamDecl(0)->getType();
@@ -1492,11 +1552,17 @@ bool CXXMethodDecl::hasInlineBody() const {
}
bool CXXMethodDecl::isLambdaStaticInvoker() const {
- return getParent()->isLambda() &&
- getIdentifier() && getIdentifier()->getName() == "__invoke";
+ const CXXRecordDecl *P = getParent();
+ if (P->isLambda()) {
+ if (const CXXMethodDecl *StaticInvoker = P->getLambdaStaticInvoker()) {
+ if (StaticInvoker == this) return true;
+ if (P->isGenericLambda() && this->isFunctionTemplateSpecialization())
+ return StaticInvoker == this->getPrimaryTemplate()->getTemplatedDecl();
+ }
+ }
+ return false;
}
-
CXXCtorInitializer::CXXCtorInitializer(ASTContext &Context,
TypeSourceInfo *TInfo, bool IsVirtual,
SourceLocation L, Expr *Init,
@@ -1865,7 +1931,7 @@ NamespaceDecl::NamespaceDecl(DeclContext *DC, bool Inline,
: NamedDecl(Namespace, DC, IdLoc, Id), DeclContext(Namespace),
LocStart(StartLoc), RBraceLoc(), AnonOrFirstNamespaceAndInline(0, Inline)
{
- setPreviousDeclaration(PrevDecl);
+ setPreviousDecl(PrevDecl);
if (PrevDecl)
AnonOrFirstNamespaceAndInline.setPointer(PrevDecl->getOriginalNamespace());
@@ -1959,8 +2025,8 @@ void UsingDecl::removeShadowDecl(UsingShadowDecl *S) {
UsingDecl *UsingDecl::Create(ASTContext &C, DeclContext *DC, SourceLocation UL,
NestedNameSpecifierLoc QualifierLoc,
const DeclarationNameInfo &NameInfo,
- bool IsTypeNameArg) {
- return new (C) UsingDecl(DC, UL, QualifierLoc, NameInfo, IsTypeNameArg);
+ bool HasTypename) {
+ return new (C) UsingDecl(DC, UL, QualifierLoc, NameInfo, HasTypename);
}
UsingDecl *UsingDecl::CreateDeserialized(ASTContext &C, unsigned ID) {
@@ -1969,6 +2035,12 @@ UsingDecl *UsingDecl::CreateDeserialized(ASTContext &C, unsigned ID) {
DeclarationNameInfo(), false);
}
+SourceRange UsingDecl::getSourceRange() const {
+ SourceLocation Begin = isAccessDeclaration()
+ ? getQualifierLoc().getBeginLoc() : UsingLocation;
+ return SourceRange(Begin, getNameInfo().getEndLoc());
+}
+
void UnresolvedUsingValueDecl::anchor() { }
UnresolvedUsingValueDecl *
@@ -1988,6 +2060,12 @@ UnresolvedUsingValueDecl::CreateDeserialized(ASTContext &C, unsigned ID) {
DeclarationNameInfo());
}
+SourceRange UnresolvedUsingValueDecl::getSourceRange() const {
+ SourceLocation Begin = isAccessDeclaration()
+ ? getQualifierLoc().getBeginLoc() : UsingLocation;
+ return SourceRange(Begin, getNameInfo().getEndLoc());
+}
+
void UnresolvedUsingTypenameDecl::anchor() { }
UnresolvedUsingTypenameDecl *
diff --git a/lib/AST/DeclFriend.cpp b/lib/AST/DeclFriend.cpp
index 37a812e71aae..1c639d676dc9 100644
--- a/lib/AST/DeclFriend.cpp
+++ b/lib/AST/DeclFriend.cpp
@@ -63,3 +63,8 @@ FriendDecl *FriendDecl::CreateDeserialized(ASTContext &C, unsigned ID,
return new (Mem) FriendDecl(EmptyShell(), FriendTypeNumTPLists);
}
+FriendDecl *CXXRecordDecl::getFirstFriend() const {
+ ExternalASTSource *Source = getParentASTContext().getExternalSource();
+ Decl *First = data().FirstFriend.get(Source);
+ return First ? cast<FriendDecl>(First) : 0;
+}
diff --git a/lib/AST/DeclObjC.cpp b/lib/AST/DeclObjC.cpp
index 4ddbb22199b2..b2b5b70197b7 100644
--- a/lib/AST/DeclObjC.cpp
+++ b/lib/AST/DeclObjC.cpp
@@ -441,6 +441,17 @@ ObjCInterfaceDecl *ObjCInterfaceDecl::lookupInheritedClass(
return NULL;
}
+ObjCProtocolDecl *
+ObjCInterfaceDecl::lookupNestedProtocol(IdentifierInfo *Name) {
+ for (ObjCInterfaceDecl::all_protocol_iterator P =
+ all_referenced_protocol_begin(), PE = all_referenced_protocol_end();
+ P != PE; ++P)
+ if ((*P)->lookupProtocolNamed(Name))
+ return (*P);
+ ObjCInterfaceDecl *SuperClass = getSuperClass();
+ return SuperClass ? SuperClass->lookupNestedProtocol(Name) : NULL;
+}
+
/// lookupMethod - This method returns an instance/class method by looking in
/// the class, its categories, and its super classes (using a linear search).
/// When argument category "C" is specified, any implicit method found
@@ -627,23 +638,29 @@ ObjCMethodDecl *ObjCMethodDecl::getNextRedeclaration() {
Decl *CtxD = cast<Decl>(getDeclContext());
- if (ObjCInterfaceDecl *IFD = dyn_cast<ObjCInterfaceDecl>(CtxD)) {
- if (ObjCImplementationDecl *ImplD = Ctx.getObjCImplementation(IFD))
- Redecl = ImplD->getMethod(getSelector(), isInstanceMethod());
-
- } else if (ObjCCategoryDecl *CD = dyn_cast<ObjCCategoryDecl>(CtxD)) {
- if (ObjCCategoryImplDecl *ImplD = Ctx.getObjCImplementation(CD))
- Redecl = ImplD->getMethod(getSelector(), isInstanceMethod());
-
- } else if (ObjCImplementationDecl *ImplD =
- dyn_cast<ObjCImplementationDecl>(CtxD)) {
- if (ObjCInterfaceDecl *IFD = ImplD->getClassInterface())
- Redecl = IFD->getMethod(getSelector(), isInstanceMethod());
-
- } else if (ObjCCategoryImplDecl *CImplD =
- dyn_cast<ObjCCategoryImplDecl>(CtxD)) {
- if (ObjCCategoryDecl *CatD = CImplD->getCategoryDecl())
- Redecl = CatD->getMethod(getSelector(), isInstanceMethod());
+ if (!CtxD->isInvalidDecl()) {
+ if (ObjCInterfaceDecl *IFD = dyn_cast<ObjCInterfaceDecl>(CtxD)) {
+ if (ObjCImplementationDecl *ImplD = Ctx.getObjCImplementation(IFD))
+ if (!ImplD->isInvalidDecl())
+ Redecl = ImplD->getMethod(getSelector(), isInstanceMethod());
+
+ } else if (ObjCCategoryDecl *CD = dyn_cast<ObjCCategoryDecl>(CtxD)) {
+ if (ObjCCategoryImplDecl *ImplD = Ctx.getObjCImplementation(CD))
+ if (!ImplD->isInvalidDecl())
+ Redecl = ImplD->getMethod(getSelector(), isInstanceMethod());
+
+ } else if (ObjCImplementationDecl *ImplD =
+ dyn_cast<ObjCImplementationDecl>(CtxD)) {
+ if (ObjCInterfaceDecl *IFD = ImplD->getClassInterface())
+ if (!IFD->isInvalidDecl())
+ Redecl = IFD->getMethod(getSelector(), isInstanceMethod());
+
+ } else if (ObjCCategoryImplDecl *CImplD =
+ dyn_cast<ObjCCategoryImplDecl>(CtxD)) {
+ if (ObjCCategoryDecl *CatD = CImplD->getCategoryDecl())
+ if (!CatD->isInvalidDecl())
+ Redecl = CatD->getMethod(getSelector(), isInstanceMethod());
+ }
}
if (!Redecl && isRedeclaration()) {
@@ -1062,7 +1079,7 @@ ObjCInterfaceDecl(DeclContext *DC, SourceLocation atLoc, IdentifierInfo *Id,
: ObjCContainerDecl(ObjCInterface, DC, Id, CLoc, atLoc),
TypeForDecl(0), Data()
{
- setPreviousDeclaration(PrevDecl);
+ setPreviousDecl(PrevDecl);
// Copy the 'data' pointer over.
if (PrevDecl)
@@ -1308,7 +1325,8 @@ ObjCIvarDecl *ObjCIvarDecl::Create(ASTContext &C, ObjCContainerDecl *DC,
SourceLocation IdLoc, IdentifierInfo *Id,
QualType T, TypeSourceInfo *TInfo,
AccessControl ac, Expr *BW,
- bool synthesized) {
+ bool synthesized,
+ bool backingIvarReferencedInAccessor) {
if (DC) {
// Ivar's can only appear in interfaces, implementations (via synthesized
// properties), and class extensions (via direct declaration, or synthesized
@@ -1336,13 +1354,13 @@ ObjCIvarDecl *ObjCIvarDecl::Create(ASTContext &C, ObjCContainerDecl *DC,
}
return new (C) ObjCIvarDecl(DC, StartLoc, IdLoc, Id, T, TInfo,
- ac, BW, synthesized);
+ ac, BW, synthesized, backingIvarReferencedInAccessor);
}
ObjCIvarDecl *ObjCIvarDecl::CreateDeserialized(ASTContext &C, unsigned ID) {
void *Mem = AllocateDeserializedDecl(C, ID, sizeof(ObjCIvarDecl));
return new (Mem) ObjCIvarDecl(0, SourceLocation(), SourceLocation(), 0,
- QualType(), 0, ObjCIvarDecl::None, 0, false);
+ QualType(), 0, ObjCIvarDecl::None, 0, false, false);
}
const ObjCInterfaceDecl *ObjCIvarDecl::getContainingInterface() const {
@@ -1401,7 +1419,7 @@ ObjCProtocolDecl::ObjCProtocolDecl(DeclContext *DC, IdentifierInfo *Id,
ObjCProtocolDecl *PrevDecl)
: ObjCContainerDecl(ObjCProtocol, DC, Id, nameLoc, atStartLoc), Data()
{
- setPreviousDeclaration(PrevDecl);
+ setPreviousDecl(PrevDecl);
if (PrevDecl)
Data = PrevDecl->Data;
}
@@ -1493,6 +1511,30 @@ void ObjCProtocolDecl::collectPropertiesToImplement(PropertyMap &PM,
}
}
+
+void ObjCProtocolDecl::collectInheritedProtocolProperties(
+ const ObjCPropertyDecl *Property,
+ ProtocolPropertyMap &PM) const {
+ if (const ObjCProtocolDecl *PDecl = getDefinition()) {
+ bool MatchFound = false;
+ for (ObjCProtocolDecl::prop_iterator P = PDecl->prop_begin(),
+ E = PDecl->prop_end(); P != E; ++P) {
+ ObjCPropertyDecl *Prop = *P;
+ if (Prop == Property)
+ continue;
+ if (Prop->getIdentifier() == Property->getIdentifier()) {
+ PM[PDecl] = Prop;
+ MatchFound = true;
+ break;
+ }
+ }
+ // Scan through protocol's protocols which did not have a matching property.
+ if (!MatchFound)
+ for (ObjCProtocolDecl::protocol_iterator PI = PDecl->protocol_begin(),
+ E = PDecl->protocol_end(); PI != E; ++PI)
+ (*PI)->collectInheritedProtocolProperties(Property, PM);
+ }
+}
//===----------------------------------------------------------------------===//
// ObjCCategoryDecl
diff --git a/lib/AST/DeclOpenMP.cpp b/lib/AST/DeclOpenMP.cpp
index c0d10a0f418c..0d195f74623d 100644
--- a/lib/AST/DeclOpenMP.cpp
+++ b/lib/AST/DeclOpenMP.cpp
@@ -28,9 +28,9 @@ void OMPThreadPrivateDecl::anchor() { }
OMPThreadPrivateDecl *OMPThreadPrivateDecl::Create(ASTContext &C,
DeclContext *DC,
SourceLocation L,
- ArrayRef<DeclRefExpr *> VL) {
+ ArrayRef<Expr *> VL) {
unsigned Size = sizeof(OMPThreadPrivateDecl) +
- (VL.size() * sizeof(DeclRefExpr *));
+ (VL.size() * sizeof(Expr *));
void *Mem = C.Allocate(Size, llvm::alignOf<OMPThreadPrivateDecl>());
OMPThreadPrivateDecl *D = new (Mem) OMPThreadPrivateDecl(OMPThreadPrivate,
@@ -43,7 +43,7 @@ OMPThreadPrivateDecl *OMPThreadPrivateDecl::Create(ASTContext &C,
OMPThreadPrivateDecl *OMPThreadPrivateDecl::CreateDeserialized(ASTContext &C,
unsigned ID,
unsigned N) {
- unsigned Size = sizeof(OMPThreadPrivateDecl) + (N * sizeof(DeclRefExpr *));
+ unsigned Size = sizeof(OMPThreadPrivateDecl) + (N * sizeof(Expr *));
void *Mem = AllocateDeserializedDecl(C, ID, Size);
OMPThreadPrivateDecl *D = new (Mem) OMPThreadPrivateDecl(OMPThreadPrivate,
@@ -52,9 +52,10 @@ OMPThreadPrivateDecl *OMPThreadPrivateDecl::CreateDeserialized(ASTContext &C,
return D;
}
-void OMPThreadPrivateDecl::setVars(ArrayRef<DeclRefExpr *> VL) {
+void OMPThreadPrivateDecl::setVars(ArrayRef<Expr *> VL) {
assert(VL.size() == NumVars &&
"Number of variables is not the same as the preallocated buffer");
- DeclRefExpr **Vars = reinterpret_cast<DeclRefExpr **>(this + 1);
+ Expr **Vars = reinterpret_cast<Expr **>(this + 1);
std::copy(VL.begin(), VL.end(), Vars);
}
+
diff --git a/lib/AST/DeclPrinter.cpp b/lib/AST/DeclPrinter.cpp
index d47972bc6130..767f6620a295 100644
--- a/lib/AST/DeclPrinter.cpp
+++ b/lib/AST/DeclPrinter.cpp
@@ -260,6 +260,8 @@ void DeclPrinter::VisitDeclContext(DeclContext *DC, bool Indent) {
QualType CurDeclType = getDeclType(*D);
if (!Decls.empty() && !CurDeclType.isNull()) {
QualType BaseType = GetBaseType(CurDeclType);
+ if (!BaseType.isNull() && isa<ElaboratedType>(BaseType))
+ BaseType = cast<ElaboratedType>(BaseType)->getNamedType();
if (!BaseType.isNull() && isa<TagType>(BaseType) &&
cast<TagType>(BaseType)->getDecl() == Decls[0]) {
Decls.push_back(*D);
@@ -337,12 +339,14 @@ void DeclPrinter::VisitTypedefDecl(TypedefDecl *D) {
if (D->isModulePrivate())
Out << "__module_private__ ";
}
- D->getUnderlyingType().print(Out, Policy, D->getName());
+ D->getTypeSourceInfo()->getType().print(Out, Policy, D->getName());
prettyPrintAttributes(D);
}
void DeclPrinter::VisitTypeAliasDecl(TypeAliasDecl *D) {
- Out << "using " << *D << " = " << D->getUnderlyingType().getAsString(Policy);
+ Out << "using " << *D;
+ prettyPrintAttributes(D);
+ Out << " = " << D->getTypeSourceInfo()->getType().getAsString(Policy);
}
void DeclPrinter::VisitEnumDecl(EnumDecl *D) {
@@ -665,9 +669,9 @@ void DeclPrinter::VisitVarDecl(VarDecl *D) {
Out << "__module_private__ ";
}
- QualType T = D->getASTContext().getUnqualifiedObjCPointerType(D->getType());
- if (ParmVarDecl *Parm = dyn_cast<ParmVarDecl>(D))
- T = Parm->getOriginalType();
+ QualType T = D->getTypeSourceInfo()
+ ? D->getTypeSourceInfo()->getType()
+ : D->getASTContext().getUnqualifiedObjCPointerType(D->getType());
T.print(Out, Policy, D->getName());
Expr *Init = D->getInit();
if (!Policy.SuppressInitializers && Init) {
@@ -1153,7 +1157,10 @@ void DeclPrinter::VisitObjCPropertyImplDecl(ObjCPropertyImplDecl *PID) {
}
void DeclPrinter::VisitUsingDecl(UsingDecl *D) {
- Out << "using ";
+ if (!D->isAccessDeclaration())
+ Out << "using ";
+ if (D->hasTypename())
+ Out << "typename ";
D->getQualifier()->print(Out, Policy);
Out << *D;
}
@@ -1166,7 +1173,8 @@ DeclPrinter::VisitUnresolvedUsingTypenameDecl(UnresolvedUsingTypenameDecl *D) {
}
void DeclPrinter::VisitUnresolvedUsingValueDecl(UnresolvedUsingValueDecl *D) {
- Out << "using ";
+ if (!D->isAccessDeclaration())
+ Out << "using ";
D->getQualifier()->print(Out, Policy);
Out << D->getName();
}
@@ -1180,9 +1188,10 @@ void DeclPrinter::VisitOMPThreadPrivateDecl(OMPThreadPrivateDecl *D) {
if (!D->varlist_empty()) {
for (OMPThreadPrivateDecl::varlist_iterator I = D->varlist_begin(),
E = D->varlist_end();
- I != E; ++I) {
- Out << (I == D->varlist_begin() ? '(' : ',')
- << *cast<NamedDecl>((*I)->getDecl());
+ I != E; ++I) {
+ Out << (I == D->varlist_begin() ? '(' : ',');
+ NamedDecl *ND = cast<NamedDecl>(cast<DeclRefExpr>(*I)->getDecl());
+ ND->printQualifiedName(Out);
}
Out << ")";
}
diff --git a/lib/AST/DeclTemplate.cpp b/lib/AST/DeclTemplate.cpp
index 0b94f7d2c49b..7172fb7b487f 100644
--- a/lib/AST/DeclTemplate.cpp
+++ b/lib/AST/DeclTemplate.cpp
@@ -129,33 +129,34 @@ static void AdoptTemplateParameterList(TemplateParameterList *Params,
//===----------------------------------------------------------------------===//
RedeclarableTemplateDecl::CommonBase *RedeclarableTemplateDecl::getCommonPtr() const {
- if (!Common) {
- // Walk the previous-declaration chain until we either find a declaration
- // with a common pointer or we run out of previous declarations.
- SmallVector<const RedeclarableTemplateDecl *, 2> PrevDecls;
- for (const RedeclarableTemplateDecl *Prev = getPreviousDecl(); Prev;
- Prev = Prev->getPreviousDecl()) {
- if (Prev->Common) {
- Common = Prev->Common;
- break;
- }
-
- PrevDecls.push_back(Prev);
+ if (Common)
+ return Common;
+
+ // Walk the previous-declaration chain until we either find a declaration
+ // with a common pointer or we run out of previous declarations.
+ SmallVector<const RedeclarableTemplateDecl *, 2> PrevDecls;
+ for (const RedeclarableTemplateDecl *Prev = getPreviousDecl(); Prev;
+ Prev = Prev->getPreviousDecl()) {
+ if (Prev->Common) {
+ Common = Prev->Common;
+ break;
}
- // If we never found a common pointer, allocate one now.
- if (!Common) {
- // FIXME: If any of the declarations is from an AST file, we probably
- // need an update record to add the common data.
-
- Common = newCommon(getASTContext());
- }
-
- // Update any previous declarations we saw with the common pointer.
- for (unsigned I = 0, N = PrevDecls.size(); I != N; ++I)
- PrevDecls[I]->Common = Common;
+ PrevDecls.push_back(Prev);
+ }
+
+ // If we never found a common pointer, allocate one now.
+ if (!Common) {
+ // FIXME: If any of the declarations is from an AST file, we probably
+ // need an update record to add the common data.
+
+ Common = newCommon(getASTContext());
}
+ // Update any previous declarations we saw with the common pointer.
+ for (unsigned I = 0, N = PrevDecls.size(); I != N; ++I)
+ PrevDecls[I]->Common = Common;
+
return Common;
}
@@ -245,6 +246,23 @@ FunctionTemplateDecl::newCommon(ASTContext &C) const {
return CommonPtr;
}
+void FunctionTemplateDecl::LoadLazySpecializations() const {
+ Common *CommonPtr = getCommonPtr();
+ if (CommonPtr->LazySpecializations) {
+ ASTContext &Context = getASTContext();
+ uint32_t *Specs = CommonPtr->LazySpecializations;
+ CommonPtr->LazySpecializations = 0;
+ for (uint32_t I = 0, N = *Specs++; I != N; ++I)
+ (void)Context.getExternalSource()->GetExternalDecl(Specs[I]);
+ }
+}
+
+llvm::FoldingSetVector<FunctionTemplateSpecializationInfo> &
+FunctionTemplateDecl::getSpecializations() const {
+ LoadLazySpecializations();
+ return getCommonPtr()->Specializations;
+}
+
FunctionDecl *
FunctionTemplateDecl::findSpecialization(const TemplateArgument *Args,
unsigned NumArgs, void *&InsertPos) {
@@ -261,18 +279,17 @@ void FunctionTemplateDecl::addSpecialization(
L->AddedCXXTemplateSpecialization(this, Info->Function);
}
-std::pair<const TemplateArgument *, unsigned>
-FunctionTemplateDecl::getInjectedTemplateArgs() {
+ArrayRef<TemplateArgument> FunctionTemplateDecl::getInjectedTemplateArgs() {
TemplateParameterList *Params = getTemplateParameters();
Common *CommonPtr = getCommonPtr();
if (!CommonPtr->InjectedArgs) {
CommonPtr->InjectedArgs
- = new (getASTContext()) TemplateArgument [Params->size()];
- GenerateInjectedTemplateArgs(getASTContext(), Params,
+ = new (getASTContext()) TemplateArgument[Params->size()];
+ GenerateInjectedTemplateArgs(getASTContext(), Params,
CommonPtr->InjectedArgs);
}
-
- return std::make_pair(CommonPtr->InjectedArgs, Params->size());
+
+ return llvm::makeArrayRef(CommonPtr->InjectedArgs, Params->size());
}
//===----------------------------------------------------------------------===//
@@ -292,7 +309,7 @@ ClassTemplateDecl *ClassTemplateDecl::Create(ASTContext &C,
ClassTemplateDecl *PrevDecl) {
AdoptTemplateParameterList(Params, cast<DeclContext>(Decl));
ClassTemplateDecl *New = new (C) ClassTemplateDecl(DC, L, Name, Params, Decl);
- New->setPreviousDeclaration(PrevDecl);
+ New->setPreviousDecl(PrevDecl);
return New;
}
@@ -381,13 +398,11 @@ void ClassTemplateDecl::getPartialSpecializations(
llvm::FoldingSetVector<ClassTemplatePartialSpecializationDecl> &PartialSpecs
= getPartialSpecializations();
PS.clear();
- PS.resize(PartialSpecs.size());
+ PS.reserve(PartialSpecs.size());
for (llvm::FoldingSetVector<ClassTemplatePartialSpecializationDecl>::iterator
P = PartialSpecs.begin(), PEnd = PartialSpecs.end();
- P != PEnd; ++P) {
- assert(!PS[P->getSequenceNumber()]);
- PS[P->getSequenceNumber()] = P->getMostRecentDecl();
- }
+ P != PEnd; ++P)
+ PS.push_back(P->getMostRecentDecl());
}
ClassTemplatePartialSpecializationDecl *
@@ -813,19 +828,16 @@ ClassTemplatePartialSpecializationDecl(ASTContext &Context, TagKind TK,
ClassTemplateDecl *SpecializedTemplate,
const TemplateArgument *Args,
unsigned NumArgs,
- TemplateArgumentLoc *ArgInfos,
- unsigned NumArgInfos,
- ClassTemplatePartialSpecializationDecl *PrevDecl,
- unsigned SequenceNumber)
+ const ASTTemplateArgumentListInfo *ArgInfos,
+ ClassTemplatePartialSpecializationDecl *PrevDecl)
: ClassTemplateSpecializationDecl(Context,
ClassTemplatePartialSpecialization,
TK, DC, StartLoc, IdLoc,
SpecializedTemplate,
Args, NumArgs, PrevDecl),
TemplateParams(Params), ArgsAsWritten(ArgInfos),
- NumArgsAsWritten(NumArgInfos), SequenceNumber(SequenceNumber),
InstantiatedFromMember(0, false)
-{
+{
AdoptTemplateParameterList(Params, this);
}
@@ -839,12 +851,9 @@ Create(ASTContext &Context, TagKind TK,DeclContext *DC,
unsigned NumArgs,
const TemplateArgumentListInfo &ArgInfos,
QualType CanonInjectedType,
- ClassTemplatePartialSpecializationDecl *PrevDecl,
- unsigned SequenceNumber) {
- unsigned N = ArgInfos.size();
- TemplateArgumentLoc *ClonedArgs = new (Context) TemplateArgumentLoc[N];
- for (unsigned I = 0; I != N; ++I)
- ClonedArgs[I] = ArgInfos[I];
+ ClassTemplatePartialSpecializationDecl *PrevDecl) {
+ const ASTTemplateArgumentListInfo *ASTArgInfos =
+ ASTTemplateArgumentListInfo::Create(Context, ArgInfos);
ClassTemplatePartialSpecializationDecl *Result
= new (Context)ClassTemplatePartialSpecializationDecl(Context, TK, DC,
@@ -852,9 +861,8 @@ Create(ASTContext &Context, TagKind TK,DeclContext *DC,
Params,
SpecializedTemplate,
Args, NumArgs,
- ClonedArgs, N,
- PrevDecl,
- SequenceNumber);
+ ASTArgInfos,
+ PrevDecl);
Result->setSpecializationKind(TSK_ExplicitSpecialization);
Result->MayHaveOutOfDateDef = false;
@@ -942,3 +950,252 @@ ClassScopeFunctionSpecializationDecl::CreateDeserialized(ASTContext &C,
return new (Mem) ClassScopeFunctionSpecializationDecl(0, SourceLocation(), 0,
false, TemplateArgumentListInfo());
}
+
+//===----------------------------------------------------------------------===//
+// VarTemplateDecl Implementation
+//===----------------------------------------------------------------------===//
+
+void VarTemplateDecl::DeallocateCommon(void *Ptr) {
+ static_cast<Common *>(Ptr)->~Common();
+}
+
+VarTemplateDecl *VarTemplateDecl::getDefinition() {
+ VarTemplateDecl *CurD = this;
+ while (CurD) {
+ if (CurD->isThisDeclarationADefinition())
+ return CurD;
+ CurD = CurD->getPreviousDecl();
+ }
+ return 0;
+}
+
+VarTemplateDecl *VarTemplateDecl::Create(ASTContext &C, DeclContext *DC,
+ SourceLocation L, DeclarationName Name,
+ TemplateParameterList *Params,
+ NamedDecl *Decl,
+ VarTemplateDecl *PrevDecl) {
+ VarTemplateDecl *New = new (C) VarTemplateDecl(DC, L, Name, Params, Decl);
+ New->setPreviousDecl(PrevDecl);
+ return New;
+}
+
+VarTemplateDecl *VarTemplateDecl::CreateDeserialized(ASTContext &C,
+ unsigned ID) {
+ void *Mem = AllocateDeserializedDecl(C, ID, sizeof(VarTemplateDecl));
+ return new (Mem) VarTemplateDecl(EmptyShell());
+}
+
+// TODO: Unify accross class, function and variable templates?
+// May require moving this and Common to RedeclarableTemplateDecl.
+void VarTemplateDecl::LoadLazySpecializations() const {
+ Common *CommonPtr = getCommonPtr();
+ if (CommonPtr->LazySpecializations) {
+ ASTContext &Context = getASTContext();
+ uint32_t *Specs = CommonPtr->LazySpecializations;
+ CommonPtr->LazySpecializations = 0;
+ for (uint32_t I = 0, N = *Specs++; I != N; ++I)
+ (void)Context.getExternalSource()->GetExternalDecl(Specs[I]);
+ }
+}
+
+llvm::FoldingSetVector<VarTemplateSpecializationDecl> &
+VarTemplateDecl::getSpecializations() const {
+ LoadLazySpecializations();
+ return getCommonPtr()->Specializations;
+}
+
+llvm::FoldingSetVector<VarTemplatePartialSpecializationDecl> &
+VarTemplateDecl::getPartialSpecializations() {
+ LoadLazySpecializations();
+ return getCommonPtr()->PartialSpecializations;
+}
+
+RedeclarableTemplateDecl::CommonBase *
+VarTemplateDecl::newCommon(ASTContext &C) const {
+ Common *CommonPtr = new (C) Common;
+ C.AddDeallocation(DeallocateCommon, CommonPtr);
+ return CommonPtr;
+}
+
+VarTemplateSpecializationDecl *
+VarTemplateDecl::findSpecialization(const TemplateArgument *Args,
+ unsigned NumArgs, void *&InsertPos) {
+ return findSpecializationImpl(getSpecializations(), Args, NumArgs, InsertPos);
+}
+
+void VarTemplateDecl::AddSpecialization(VarTemplateSpecializationDecl *D,
+ void *InsertPos) {
+ if (InsertPos)
+ getSpecializations().InsertNode(D, InsertPos);
+ else {
+ VarTemplateSpecializationDecl *Existing =
+ getSpecializations().GetOrInsertNode(D);
+ (void)Existing;
+ assert(Existing->isCanonicalDecl() && "Non-canonical specialization?");
+ }
+ if (ASTMutationListener *L = getASTMutationListener())
+ L->AddedCXXTemplateSpecialization(this, D);
+}
+
+VarTemplatePartialSpecializationDecl *
+VarTemplateDecl::findPartialSpecialization(const TemplateArgument *Args,
+ unsigned NumArgs, void *&InsertPos) {
+ return findSpecializationImpl(getPartialSpecializations(), Args, NumArgs,
+ InsertPos);
+}
+
+void VarTemplateDecl::AddPartialSpecialization(
+ VarTemplatePartialSpecializationDecl *D, void *InsertPos) {
+ if (InsertPos)
+ getPartialSpecializations().InsertNode(D, InsertPos);
+ else {
+ VarTemplatePartialSpecializationDecl *Existing =
+ getPartialSpecializations().GetOrInsertNode(D);
+ (void)Existing;
+ assert(Existing->isCanonicalDecl() && "Non-canonical specialization?");
+ }
+
+ if (ASTMutationListener *L = getASTMutationListener())
+ L->AddedCXXTemplateSpecialization(this, D);
+}
+
+void VarTemplateDecl::getPartialSpecializations(
+ SmallVectorImpl<VarTemplatePartialSpecializationDecl *> &PS) {
+ llvm::FoldingSetVector<VarTemplatePartialSpecializationDecl> &PartialSpecs =
+ getPartialSpecializations();
+ PS.clear();
+ PS.reserve(PartialSpecs.size());
+ for (llvm::FoldingSetVector<VarTemplatePartialSpecializationDecl>::iterator
+ P = PartialSpecs.begin(),
+ PEnd = PartialSpecs.end();
+ P != PEnd; ++P)
+ PS.push_back(P->getMostRecentDecl());
+}
+
+VarTemplatePartialSpecializationDecl *
+VarTemplateDecl::findPartialSpecInstantiatedFromMember(
+ VarTemplatePartialSpecializationDecl *D) {
+ Decl *DCanon = D->getCanonicalDecl();
+ for (llvm::FoldingSetVector<VarTemplatePartialSpecializationDecl>::iterator
+ P = getPartialSpecializations().begin(),
+ PEnd = getPartialSpecializations().end();
+ P != PEnd; ++P) {
+ if (P->getInstantiatedFromMember()->getCanonicalDecl() == DCanon)
+ return P->getMostRecentDecl();
+ }
+
+ return 0;
+}
+
+//===----------------------------------------------------------------------===//
+// VarTemplateSpecializationDecl Implementation
+//===----------------------------------------------------------------------===//
+VarTemplateSpecializationDecl::VarTemplateSpecializationDecl(
+ ASTContext &Context, Kind DK, DeclContext *DC, SourceLocation StartLoc,
+ SourceLocation IdLoc, VarTemplateDecl *SpecializedTemplate, QualType T,
+ TypeSourceInfo *TInfo, StorageClass S, const TemplateArgument *Args,
+ unsigned NumArgs)
+ : VarDecl(DK, DC, StartLoc, IdLoc, SpecializedTemplate->getIdentifier(), T,
+ TInfo, S),
+ SpecializedTemplate(SpecializedTemplate), ExplicitInfo(0),
+ TemplateArgs(TemplateArgumentList::CreateCopy(Context, Args, NumArgs)),
+ SpecializationKind(TSK_Undeclared) {}
+
+VarTemplateSpecializationDecl::VarTemplateSpecializationDecl(Kind DK)
+ : VarDecl(DK, 0, SourceLocation(), SourceLocation(), 0, QualType(), 0,
+ SC_None),
+ ExplicitInfo(0), SpecializationKind(TSK_Undeclared) {}
+
+VarTemplateSpecializationDecl *VarTemplateSpecializationDecl::Create(
+ ASTContext &Context, DeclContext *DC, SourceLocation StartLoc,
+ SourceLocation IdLoc, VarTemplateDecl *SpecializedTemplate, QualType T,
+ TypeSourceInfo *TInfo, StorageClass S, const TemplateArgument *Args,
+ unsigned NumArgs) {
+ VarTemplateSpecializationDecl *Result = new (Context)
+ VarTemplateSpecializationDecl(Context, VarTemplateSpecialization, DC,
+ StartLoc, IdLoc, SpecializedTemplate, T,
+ TInfo, S, Args, NumArgs);
+ return Result;
+}
+
+VarTemplateSpecializationDecl *
+VarTemplateSpecializationDecl::CreateDeserialized(ASTContext &C, unsigned ID) {
+ void *Mem =
+ AllocateDeserializedDecl(C, ID, sizeof(VarTemplateSpecializationDecl));
+ VarTemplateSpecializationDecl *Result =
+ new (Mem) VarTemplateSpecializationDecl(VarTemplateSpecialization);
+ return Result;
+}
+
+void VarTemplateSpecializationDecl::getNameForDiagnostic(
+ raw_ostream &OS, const PrintingPolicy &Policy, bool Qualified) const {
+ NamedDecl::getNameForDiagnostic(OS, Policy, Qualified);
+
+ const TemplateArgumentList &TemplateArgs = getTemplateArgs();
+ TemplateSpecializationType::PrintTemplateArgumentList(
+ OS, TemplateArgs.data(), TemplateArgs.size(), Policy);
+}
+
+VarTemplateDecl *VarTemplateSpecializationDecl::getSpecializedTemplate() const {
+ if (SpecializedPartialSpecialization *PartialSpec =
+ SpecializedTemplate.dyn_cast<SpecializedPartialSpecialization *>())
+ return PartialSpec->PartialSpecialization->getSpecializedTemplate();
+ return SpecializedTemplate.get<VarTemplateDecl *>();
+}
+
+void VarTemplateSpecializationDecl::setTemplateArgsInfo(
+ const TemplateArgumentListInfo &ArgsInfo) {
+ unsigned N = ArgsInfo.size();
+ TemplateArgsInfo.setLAngleLoc(ArgsInfo.getLAngleLoc());
+ TemplateArgsInfo.setRAngleLoc(ArgsInfo.getRAngleLoc());
+ for (unsigned I = 0; I != N; ++I)
+ TemplateArgsInfo.addArgument(ArgsInfo[I]);
+}
+
+//===----------------------------------------------------------------------===//
+// VarTemplatePartialSpecializationDecl Implementation
+//===----------------------------------------------------------------------===//
+void VarTemplatePartialSpecializationDecl::anchor() {}
+
+VarTemplatePartialSpecializationDecl::VarTemplatePartialSpecializationDecl(
+ ASTContext &Context, DeclContext *DC, SourceLocation StartLoc,
+ SourceLocation IdLoc, TemplateParameterList *Params,
+ VarTemplateDecl *SpecializedTemplate, QualType T, TypeSourceInfo *TInfo,
+ StorageClass S, const TemplateArgument *Args, unsigned NumArgs,
+ const ASTTemplateArgumentListInfo *ArgInfos)
+ : VarTemplateSpecializationDecl(Context, VarTemplatePartialSpecialization,
+ DC, StartLoc, IdLoc, SpecializedTemplate, T,
+ TInfo, S, Args, NumArgs),
+ TemplateParams(Params), ArgsAsWritten(ArgInfos),
+ InstantiatedFromMember(0, false) {
+ // TODO: The template parameters should be in DC by now. Verify.
+ // AdoptTemplateParameterList(Params, DC);
+}
+
+VarTemplatePartialSpecializationDecl *
+VarTemplatePartialSpecializationDecl::Create(
+ ASTContext &Context, DeclContext *DC, SourceLocation StartLoc,
+ SourceLocation IdLoc, TemplateParameterList *Params,
+ VarTemplateDecl *SpecializedTemplate, QualType T, TypeSourceInfo *TInfo,
+ StorageClass S, const TemplateArgument *Args, unsigned NumArgs,
+ const TemplateArgumentListInfo &ArgInfos) {
+ const ASTTemplateArgumentListInfo *ASTArgInfos
+ = ASTTemplateArgumentListInfo::Create(Context, ArgInfos);
+
+ VarTemplatePartialSpecializationDecl *Result =
+ new (Context) VarTemplatePartialSpecializationDecl(
+ Context, DC, StartLoc, IdLoc, Params, SpecializedTemplate, T, TInfo,
+ S, Args, NumArgs, ASTArgInfos);
+ Result->setSpecializationKind(TSK_ExplicitSpecialization);
+ return Result;
+}
+
+VarTemplatePartialSpecializationDecl *
+VarTemplatePartialSpecializationDecl::CreateDeserialized(ASTContext &C,
+ unsigned ID) {
+ void *Mem = AllocateDeserializedDecl(
+ C, ID, sizeof(VarTemplatePartialSpecializationDecl));
+ VarTemplatePartialSpecializationDecl *Result =
+ new (Mem) VarTemplatePartialSpecializationDecl();
+ return Result;
+}
diff --git a/lib/AST/DeclarationName.cpp b/lib/AST/DeclarationName.cpp
index e4a41b6ffb50..e064e23a0ae9 100644
--- a/lib/AST/DeclarationName.cpp
+++ b/lib/AST/DeclarationName.cpp
@@ -133,6 +133,66 @@ int DeclarationName::compare(DeclarationName LHS, DeclarationName RHS) {
llvm_unreachable("Invalid DeclarationName Kind!");
}
+raw_ostream &operator<<(raw_ostream &OS, DeclarationName N) {
+ switch (N.getNameKind()) {
+ case DeclarationName::Identifier:
+ if (const IdentifierInfo *II = N.getAsIdentifierInfo())
+ OS << II->getName();
+ return OS;
+
+ case DeclarationName::ObjCZeroArgSelector:
+ case DeclarationName::ObjCOneArgSelector:
+ case DeclarationName::ObjCMultiArgSelector:
+ return OS << N.getObjCSelector().getAsString();
+
+ case DeclarationName::CXXConstructorName: {
+ QualType ClassType = N.getCXXNameType();
+ if (const RecordType *ClassRec = ClassType->getAs<RecordType>())
+ return OS << *ClassRec->getDecl();
+ return OS << ClassType.getAsString();
+ }
+
+ case DeclarationName::CXXDestructorName: {
+ OS << '~';
+ QualType Type = N.getCXXNameType();
+ if (const RecordType *Rec = Type->getAs<RecordType>())
+ return OS << *Rec->getDecl();
+ return OS << Type.getAsString();
+ }
+
+ case DeclarationName::CXXOperatorName: {
+ static const char* const OperatorNames[NUM_OVERLOADED_OPERATORS] = {
+ 0,
+#define OVERLOADED_OPERATOR(Name,Spelling,Token,Unary,Binary,MemberOnly) \
+ Spelling,
+#include "clang/Basic/OperatorKinds.def"
+ };
+ const char *OpName = OperatorNames[N.getCXXOverloadedOperator()];
+ assert(OpName && "not an overloaded operator");
+
+ OS << "operator";
+ if (OpName[0] >= 'a' && OpName[0] <= 'z')
+ OS << ' ';
+ return OS << OpName;
+ }
+
+ case DeclarationName::CXXLiteralOperatorName:
+ return OS << "operator \"\" " << N.getCXXLiteralIdentifier()->getName();
+
+ case DeclarationName::CXXConversionFunctionName: {
+ OS << "operator ";
+ QualType Type = N.getCXXNameType();
+ if (const RecordType *Rec = Type->getAs<RecordType>())
+ return OS << *Rec->getDecl();
+ return OS << Type.getAsString();
+ }
+ case DeclarationName::CXXUsingDirective:
+ return OS << "<using-directive>";
+ }
+
+ llvm_unreachable("Unexpected declaration name kind");
+}
+
} // end namespace clang
DeclarationName::NameKind DeclarationName::getNameKind() const {
@@ -180,80 +240,10 @@ bool DeclarationName::isDependentName() const {
std::string DeclarationName::getAsString() const {
std::string Result;
llvm::raw_string_ostream OS(Result);
- printName(OS);
+ OS << *this;
return OS.str();
}
-void DeclarationName::printName(raw_ostream &OS) const {
- switch (getNameKind()) {
- case Identifier:
- if (const IdentifierInfo *II = getAsIdentifierInfo())
- OS << II->getName();
- return;
-
- case ObjCZeroArgSelector:
- case ObjCOneArgSelector:
- case ObjCMultiArgSelector:
- OS << getObjCSelector().getAsString();
- return;
-
- case CXXConstructorName: {
- QualType ClassType = getCXXNameType();
- if (const RecordType *ClassRec = ClassType->getAs<RecordType>())
- OS << *ClassRec->getDecl();
- else
- OS << ClassType.getAsString();
- return;
- }
-
- case CXXDestructorName: {
- OS << '~';
- QualType Type = getCXXNameType();
- if (const RecordType *Rec = Type->getAs<RecordType>())
- OS << *Rec->getDecl();
- else
- OS << Type.getAsString();
- return;
- }
-
- case CXXOperatorName: {
- static const char* const OperatorNames[NUM_OVERLOADED_OPERATORS] = {
- 0,
-#define OVERLOADED_OPERATOR(Name,Spelling,Token,Unary,Binary,MemberOnly) \
- Spelling,
-#include "clang/Basic/OperatorKinds.def"
- };
- const char *OpName = OperatorNames[getCXXOverloadedOperator()];
- assert(OpName && "not an overloaded operator");
-
- OS << "operator";
- if (OpName[0] >= 'a' && OpName[0] <= 'z')
- OS << ' ';
- OS << OpName;
- return;
- }
-
- case CXXLiteralOperatorName:
- OS << "operator \"\" " << getCXXLiteralIdentifier()->getName();
- return;
-
- case CXXConversionFunctionName: {
- OS << "operator ";
- QualType Type = getCXXNameType();
- if (const RecordType *Rec = Type->getAs<RecordType>())
- OS << *Rec->getDecl();
- else
- OS << Type.getAsString();
- return;
- }
- case CXXUsingDirective:
- OS << "<using-directive>";
- return;
- }
-
- llvm_unreachable("Unexpected declaration name kind");
-}
-
QualType DeclarationName::getCXXNameType() const {
if (CXXSpecialName *CXXName = getAsCXXSpecialName())
return CXXName->Type;
@@ -336,8 +326,7 @@ DeclarationName DeclarationName::getUsingDirectiveName() {
}
void DeclarationName::dump() const {
- printName(llvm::errs());
- llvm::errs() << '\n';
+ llvm::errs() << *this << '\n';
}
DeclarationNameTable::DeclarationNameTable(const ASTContext &C) : Ctx(C) {
@@ -537,7 +526,7 @@ void DeclarationNameInfo::printName(raw_ostream &OS) const {
case DeclarationName::CXXOperatorName:
case DeclarationName::CXXLiteralOperatorName:
case DeclarationName::CXXUsingDirective:
- Name.printName(OS);
+ OS << Name;
return;
case DeclarationName::CXXConstructorName:
@@ -549,9 +538,8 @@ void DeclarationNameInfo::printName(raw_ostream &OS) const {
else if (Name.getNameKind() == DeclarationName::CXXConversionFunctionName)
OS << "operator ";
OS << TInfo->getType().getAsString();
- }
- else
- Name.printName(OS);
+ } else
+ OS << Name;
return;
}
llvm_unreachable("Unexpected declaration name kind");
diff --git a/lib/AST/DumpXML.cpp b/lib/AST/DumpXML.cpp
deleted file mode 100644
index be22ae450b62..000000000000
--- a/lib/AST/DumpXML.cpp
+++ /dev/null
@@ -1,1053 +0,0 @@
-//===--- DumpXML.cpp - Detailed XML dumping -------------------------------===//
-//
-// 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 Decl::dumpXML() method, a debugging tool to
-// print a detailed graph of an AST in an unspecified XML format.
-//
-// There is no guarantee of stability for this format.
-//
-//===----------------------------------------------------------------------===//
-
-// Only pay for this in code size in assertions-enabled builds.
-
-#include "clang/AST/ASTContext.h"
-#include "clang/AST/Attr.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/DeclVisitor.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/StmtVisitor.h"
-#include "clang/AST/TemplateBase.h"
-#include "clang/AST/TemplateName.h"
-#include "clang/AST/Type.h"
-#include "clang/AST/TypeLoc.h"
-#include "clang/AST/TypeLocVisitor.h"
-#include "clang/AST/TypeVisitor.h"
-#include "llvm/ADT/SmallString.h"
-
-using namespace clang;
-
-#ifndef NDEBUG
-
-namespace {
-
-enum NodeState {
- NS_Attrs, NS_LazyChildren, NS_Children
-};
-
-struct Node {
- StringRef Name;
- NodeState State;
- Node(StringRef name) : Name(name), State(NS_Attrs) {}
-
- bool isDoneWithAttrs() const { return State != NS_Attrs; }
-};
-
-template <class Impl> struct XMLDeclVisitor {
-#define DISPATCH(NAME, CLASS) \
- static_cast<Impl*>(this)->NAME(static_cast<CLASS*>(D))
-
- void dispatch(Decl *D) {
- if (D->isUsed())
- static_cast<Impl*>(this)->set("used", "1");
- switch (D->getKind()) {
-#define DECL(DERIVED, BASE) \
- case Decl::DERIVED: \
- DISPATCH(dispatch##DERIVED##DeclAttrs, DERIVED##Decl); \
- static_cast<Impl*>(this)->completeAttrs(); \
- DISPATCH(dispatch##DERIVED##DeclChildren, DERIVED##Decl); \
- DISPATCH(dispatch##DERIVED##DeclAsContext, DERIVED##Decl); \
- break;
-#define ABSTRACT_DECL(DECL)
-#include "clang/AST/DeclNodes.inc"
- }
- }
-
-#define DECL(DERIVED, BASE) \
- void dispatch##DERIVED##DeclAttrs(DERIVED##Decl *D) { \
- DISPATCH(dispatch##BASE##Attrs, BASE); \
- DISPATCH(visit##DERIVED##DeclAttrs, DERIVED##Decl); \
- } \
- void visit##DERIVED##DeclAttrs(DERIVED##Decl *D) {} \
- void dispatch##DERIVED##DeclChildren(DERIVED##Decl *D) { \
- DISPATCH(dispatch##BASE##Children, BASE); \
- DISPATCH(visit##DERIVED##DeclChildren, DERIVED##Decl); \
- } \
- void visit##DERIVED##DeclChildren(DERIVED##Decl *D) {} \
- void dispatch##DERIVED##DeclAsContext(DERIVED##Decl *D) { \
- DISPATCH(dispatch##BASE##AsContext, BASE); \
- DISPATCH(visit##DERIVED##DeclAsContext, DERIVED##Decl); \
- } \
- void visit##DERIVED##DeclAsContext(DERIVED##Decl *D) {}
-#include "clang/AST/DeclNodes.inc"
-
- void dispatchDeclAttrs(Decl *D) {
- DISPATCH(visitDeclAttrs, Decl);
- }
- void visitDeclAttrs(Decl *D) {}
-
- void dispatchDeclChildren(Decl *D) {
- DISPATCH(visitDeclChildren, Decl);
- }
- void visitDeclChildren(Decl *D) {}
-
- void dispatchDeclAsContext(Decl *D) {
- DISPATCH(visitDeclAsContext, Decl);
- }
- void visitDeclAsContext(Decl *D) {}
-
-#undef DISPATCH
-};
-
-template <class Impl> struct XMLTypeVisitor {
-#define DISPATCH(NAME, CLASS) \
- static_cast<Impl*>(this)->NAME(static_cast<CLASS*>(T))
-
- void dispatch(Type *T) {
- switch (T->getTypeClass()) {
-#define TYPE(DERIVED, BASE) \
- case Type::DERIVED: \
- DISPATCH(dispatch##DERIVED##TypeAttrs, DERIVED##Type); \
- static_cast<Impl*>(this)->completeAttrs(); \
- DISPATCH(dispatch##DERIVED##TypeChildren, DERIVED##Type); \
- break;
-#define ABSTRACT_TYPE(DERIVED, BASE)
-#include "clang/AST/TypeNodes.def"
- }
- }
-
-#define TYPE(DERIVED, BASE) \
- void dispatch##DERIVED##TypeAttrs(DERIVED##Type *T) { \
- DISPATCH(dispatch##BASE##Attrs, BASE); \
- DISPATCH(visit##DERIVED##TypeAttrs, DERIVED##Type); \
- } \
- void visit##DERIVED##TypeAttrs(DERIVED##Type *T) {} \
- void dispatch##DERIVED##TypeChildren(DERIVED##Type *T) { \
- DISPATCH(dispatch##BASE##Children, BASE); \
- DISPATCH(visit##DERIVED##TypeChildren, DERIVED##Type); \
- } \
- void visit##DERIVED##TypeChildren(DERIVED##Type *T) {}
-#include "clang/AST/TypeNodes.def"
-
- void dispatchTypeAttrs(Type *T) {
- DISPATCH(visitTypeAttrs, Type);
- }
- void visitTypeAttrs(Type *T) {}
-
- void dispatchTypeChildren(Type *T) {
- DISPATCH(visitTypeChildren, Type);
- }
- void visitTypeChildren(Type *T) {}
-
-#undef DISPATCH
-};
-
-static StringRef getTypeKindName(Type *T) {
- switch (T->getTypeClass()) {
-#define TYPE(DERIVED, BASE) case Type::DERIVED: return #DERIVED "Type";
-#define ABSTRACT_TYPE(DERIVED, BASE)
-#include "clang/AST/TypeNodes.def"
- }
-
- llvm_unreachable("unknown type kind!");
-}
-
-struct XMLDumper : public XMLDeclVisitor<XMLDumper>,
- public XMLTypeVisitor<XMLDumper> {
- raw_ostream &out;
- ASTContext &Context;
- SmallVector<Node, 16> Stack;
- unsigned Indent;
- explicit XMLDumper(raw_ostream &OS, ASTContext &context)
- : out(OS), Context(context), Indent(0) {}
-
- void indent() {
- for (unsigned I = Indent; I; --I)
- out << ' ';
- }
-
- /// Push a new node on the stack.
- void push(StringRef name) {
- if (!Stack.empty()) {
- assert(Stack.back().isDoneWithAttrs());
- if (Stack.back().State == NS_LazyChildren) {
- Stack.back().State = NS_Children;
- out << ">\n";
- }
- Indent++;
- indent();
- }
- Stack.push_back(Node(name));
- out << '<' << name;
- }
-
- /// Set the given attribute to the given value.
- void set(StringRef attr, StringRef value) {
- assert(!Stack.empty() && !Stack.back().isDoneWithAttrs());
- out << ' ' << attr << '=' << '"' << value << '"'; // TODO: quotation
- }
-
- /// Finish attributes.
- void completeAttrs() {
- assert(!Stack.empty() && !Stack.back().isDoneWithAttrs());
- Stack.back().State = NS_LazyChildren;
- }
-
- /// Pop a node.
- void pop() {
- assert(!Stack.empty() && Stack.back().isDoneWithAttrs());
- if (Stack.back().State == NS_LazyChildren) {
- out << "/>\n";
- } else {
- indent();
- out << "</" << Stack.back().Name << ">\n";
- }
- if (Stack.size() > 1) Indent--;
- Stack.pop_back();
- }
-
- //---- General utilities -------------------------------------------//
-
- void setPointer(StringRef prop, const void *p) {
- SmallString<10> buffer;
- llvm::raw_svector_ostream os(buffer);
- os << p;
- os.flush();
- set(prop, buffer);
- }
-
- void setPointer(void *p) {
- setPointer("ptr", p);
- }
-
- void setInteger(StringRef prop, const llvm::APSInt &v) {
- set(prop, v.toString(10));
- }
-
- void setInteger(StringRef prop, unsigned n) {
- SmallString<10> buffer;
- llvm::raw_svector_ostream os(buffer);
- os << n;
- os.flush();
- set(prop, buffer);
- }
-
- void setFlag(StringRef prop, bool flag) {
- if (flag) set(prop, "true");
- }
-
- void setName(DeclarationName Name) {
- if (!Name)
- return set("name", "");
-
- // Common case.
- if (Name.isIdentifier())
- return set("name", Name.getAsIdentifierInfo()->getName());
-
- set("name", Name.getAsString());
- }
-
- class TemporaryContainer {
- XMLDumper &Dumper;
- public:
- TemporaryContainer(XMLDumper &dumper, StringRef name)
- : Dumper(dumper) {
- Dumper.push(name);
- Dumper.completeAttrs();
- }
-
- ~TemporaryContainer() {
- Dumper.pop();
- }
- };
-
- void visitTemplateParameters(TemplateParameterList *L) {
- push("template_parameters");
- completeAttrs();
- for (TemplateParameterList::iterator
- I = L->begin(), E = L->end(); I != E; ++I)
- dispatch(*I);
- pop();
- }
-
- void visitTemplateArguments(const TemplateArgumentList &L) {
- push("template_arguments");
- completeAttrs();
- for (unsigned I = 0, E = L.size(); I != E; ++I)
- dispatch(L[I]);
- pop();
- }
-
- /// Visits a reference to the given declaration.
- void visitDeclRef(Decl *D) {
- push(D->getDeclKindName());
- setPointer("ref", D);
- completeAttrs();
- pop();
- }
- void visitDeclRef(StringRef Name, Decl *D) {
- TemporaryContainer C(*this, Name);
- if (D) visitDeclRef(D);
- }
-
- void dispatch(const TemplateArgument &A) {
- switch (A.getKind()) {
- case TemplateArgument::Null: {
- TemporaryContainer C(*this, "null");
- break;
- }
- case TemplateArgument::Type: {
- dispatch(A.getAsType());
- break;
- }
- case TemplateArgument::Template:
- case TemplateArgument::TemplateExpansion:
- case TemplateArgument::NullPtr:
- // FIXME: Implement!
- break;
-
- case TemplateArgument::Declaration: {
- visitDeclRef(A.getAsDecl());
- break;
- }
- case TemplateArgument::Integral: {
- push("integer");
- setInteger("value", A.getAsIntegral());
- completeAttrs();
- pop();
- break;
- }
- case TemplateArgument::Expression: {
- dispatch(A.getAsExpr());
- break;
- }
- case TemplateArgument::Pack: {
- for (TemplateArgument::pack_iterator P = A.pack_begin(),
- PEnd = A.pack_end();
- P != PEnd; ++P)
- dispatch(*P);
- break;
- }
- }
- }
-
- void dispatch(const TemplateArgumentLoc &A) {
- dispatch(A.getArgument());
- }
-
- //---- Declarations ------------------------------------------------//
- // Calls are made in this order:
- // # Enter a new node.
- // push("FieldDecl")
- //
- // # In this phase, attributes are set on the node.
- // visitDeclAttrs(D)
- // visitNamedDeclAttrs(D)
- // ...
- // visitFieldDeclAttrs(D)
- //
- // # No more attributes after this point.
- // completeAttrs()
- //
- // # Create "header" child nodes, i.e. those which logically
- // # belong to the declaration itself.
- // visitDeclChildren(D)
- // visitNamedDeclChildren(D)
- // ...
- // visitFieldDeclChildren(D)
- //
- // # Create nodes for the lexical children.
- // visitDeclAsContext(D)
- // visitNamedDeclAsContext(D)
- // ...
- // visitFieldDeclAsContext(D)
- //
- // # Finish the node.
- // pop();
- void dispatch(Decl *D) {
- push(D->getDeclKindName());
- XMLDeclVisitor<XMLDumper>::dispatch(D);
- pop();
- }
- void visitDeclAttrs(Decl *D) {
- setPointer(D);
- }
-
- /// Visit all the lexical decls in the given context.
- void visitDeclContext(DeclContext *DC) {
- for (DeclContext::decl_iterator
- I = DC->decls_begin(), E = DC->decls_end(); I != E; ++I)
- dispatch(*I);
-
- // FIXME: point out visible declarations not in lexical context?
- }
-
- /// Set the "access" attribute on the current node according to the
- /// given specifier.
- void setAccess(AccessSpecifier AS) {
- switch (AS) {
- case AS_public: return set("access", "public");
- case AS_protected: return set("access", "protected");
- case AS_private: return set("access", "private");
- case AS_none: llvm_unreachable("explicit forbidden access");
- }
- }
-
- template <class T> void visitRedeclarableAttrs(T *D) {
- if (T *Prev = D->getPreviousDecl())
- setPointer("previous", Prev);
- }
-
-
- // TranslationUnitDecl
- void visitTranslationUnitDeclAsContext(TranslationUnitDecl *D) {
- visitDeclContext(D);
- }
-
- // LinkageSpecDecl
- void visitLinkageSpecDeclAttrs(LinkageSpecDecl *D) {
- StringRef lang = "";
- switch (D->getLanguage()) {
- case LinkageSpecDecl::lang_c: lang = "C"; break;
- case LinkageSpecDecl::lang_cxx: lang = "C++"; break;
- }
- set("lang", lang);
- }
- void visitLinkageSpecDeclAsContext(LinkageSpecDecl *D) {
- visitDeclContext(D);
- }
-
- // NamespaceDecl
- void visitNamespaceDeclAttrs(NamespaceDecl *D) {
- setFlag("inline", D->isInline());
- if (!D->isOriginalNamespace())
- setPointer("original", D->getOriginalNamespace());
- }
- void visitNamespaceDeclAsContext(NamespaceDecl *D) {
- visitDeclContext(D);
- }
-
- // NamedDecl
- void visitNamedDeclAttrs(NamedDecl *D) {
- setName(D->getDeclName());
- }
-
- // ValueDecl
- void visitValueDeclChildren(ValueDecl *D) {
- dispatch(D->getType());
- }
-
- // DeclaratorDecl
- void visitDeclaratorDeclChildren(DeclaratorDecl *D) {
- //dispatch(D->getTypeSourceInfo()->getTypeLoc());
- }
-
- // VarDecl
- void visitVarDeclAttrs(VarDecl *D) {
- visitRedeclarableAttrs(D);
- if (D->getStorageClass() != SC_None)
- set("storage",
- VarDecl::getStorageClassSpecifierString(D->getStorageClass()));
- StringRef initStyle = "";
- switch (D->getInitStyle()) {
- case VarDecl::CInit: initStyle = "c"; break;
- case VarDecl::CallInit: initStyle = "call"; break;
- case VarDecl::ListInit: initStyle = "list"; break;
- }
- set("initstyle", initStyle);
- setFlag("nrvo", D->isNRVOVariable());
- // TODO: instantiation, etc.
- }
- void visitVarDeclChildren(VarDecl *D) {
- if (D->hasInit()) dispatch(D->getInit());
- }
-
- // ParmVarDecl?
-
- // FunctionDecl
- void visitFunctionDeclAttrs(FunctionDecl *D) {
- visitRedeclarableAttrs(D);
- setFlag("pure", D->isPure());
- setFlag("trivial", D->isTrivial());
- setFlag("returnzero", D->hasImplicitReturnZero());
- setFlag("prototype", D->hasWrittenPrototype());
- setFlag("deleted", D->isDeletedAsWritten());
- if (D->getStorageClass() != SC_None)
- set("storage",
- VarDecl::getStorageClassSpecifierString(D->getStorageClass()));
- setFlag("inline", D->isInlineSpecified());
- if (const AsmLabelAttr *ALA = D->getAttr<AsmLabelAttr>())
- set("asmlabel", ALA->getLabel());
- // TODO: instantiation, etc.
- }
- void visitFunctionDeclChildren(FunctionDecl *D) {
- for (FunctionDecl::param_iterator
- I = D->param_begin(), E = D->param_end(); I != E; ++I)
- dispatch(*I);
- for (ArrayRef<NamedDecl *>::iterator I = D->getDeclsInPrototypeScope().begin(),
- E = D->getDeclsInPrototypeScope().end();
- I != E; ++I)
- dispatch(*I);
- if (D->doesThisDeclarationHaveABody())
- dispatch(D->getBody());
- }
-
- // CXXMethodDecl ?
- // CXXConstructorDecl ?
- // CXXDestructorDecl ?
- // CXXConversionDecl ?
-
- void dispatch(CXXCtorInitializer *Init) {
- // TODO
- }
-
- // FieldDecl
- void visitFieldDeclAttrs(FieldDecl *D) {
- setFlag("mutable", D->isMutable());
- }
- void visitFieldDeclChildren(FieldDecl *D) {
- if (D->isBitField()) {
- TemporaryContainer C(*this, "bitwidth");
- dispatch(D->getBitWidth());
- }
- // TODO: C++0x member initializer
- }
-
- // EnumConstantDecl
- void visitEnumConstantDeclChildren(EnumConstantDecl *D) {
- // value in any case?
- if (D->getInitExpr()) dispatch(D->getInitExpr());
- }
-
- // IndirectFieldDecl
- void visitIndirectFieldDeclChildren(IndirectFieldDecl *D) {
- for (IndirectFieldDecl::chain_iterator
- I = D->chain_begin(), E = D->chain_end(); I != E; ++I) {
- NamedDecl *VD = const_cast<NamedDecl*>(*I);
- push(isa<VarDecl>(VD) ? "variable" : "field");
- setPointer("ptr", VD);
- completeAttrs();
- pop();
- }
- }
-
- // TypeDecl
- void visitTypeDeclAttrs(TypeDecl *D) {
- setPointer("typeptr", D->getTypeForDecl());
- }
-
- // TypedefDecl
- void visitTypedefDeclAttrs(TypedefDecl *D) {
- visitRedeclarableAttrs<TypedefNameDecl>(D);
- }
- void visitTypedefDeclChildren(TypedefDecl *D) {
- dispatch(D->getTypeSourceInfo()->getTypeLoc());
- }
-
- // TypeAliasDecl
- void visitTypeAliasDeclAttrs(TypeAliasDecl *D) {
- visitRedeclarableAttrs<TypedefNameDecl>(D);
- }
- void visitTypeAliasDeclChildren(TypeAliasDecl *D) {
- dispatch(D->getTypeSourceInfo()->getTypeLoc());
- }
-
- // TagDecl
- void visitTagDeclAttrs(TagDecl *D) {
- visitRedeclarableAttrs(D);
- }
- void visitTagDeclAsContext(TagDecl *D) {
- visitDeclContext(D);
- }
-
- // EnumDecl
- void visitEnumDeclAttrs(EnumDecl *D) {
- setFlag("scoped", D->isScoped());
- setFlag("fixed", D->isFixed());
- }
- void visitEnumDeclChildren(EnumDecl *D) {
- {
- TemporaryContainer C(*this, "promotion_type");
- dispatch(D->getPromotionType());
- }
- {
- TemporaryContainer C(*this, "integer_type");
- dispatch(D->getIntegerType());
- }
- }
-
- // RecordDecl ?
-
- void visitCXXRecordDeclChildren(CXXRecordDecl *D) {
- if (!D->isThisDeclarationADefinition()) return;
-
- for (CXXRecordDecl::base_class_iterator
- I = D->bases_begin(), E = D->bases_end(); I != E; ++I) {
- push("base");
- setAccess(I->getAccessSpecifier());
- completeAttrs();
- dispatch(I->getTypeSourceInfo()->getTypeLoc());
- pop();
- }
- }
-
- // ClassTemplateSpecializationDecl ?
-
- // FileScopeAsmDecl ?
-
- // BlockDecl
- void visitBlockDeclAttrs(BlockDecl *D) {
- setFlag("variadic", D->isVariadic());
- }
- void visitBlockDeclChildren(BlockDecl *D) {
- for (FunctionDecl::param_iterator
- I = D->param_begin(), E = D->param_end(); I != E; ++I)
- dispatch(*I);
- dispatch(D->getBody());
- }
-
- // AccessSpecDecl
- void visitAccessSpecDeclAttrs(AccessSpecDecl *D) {
- setAccess(D->getAccess());
- }
-
- // TemplateDecl
- void visitTemplateDeclChildren(TemplateDecl *D) {
- visitTemplateParameters(D->getTemplateParameters());
- if (D->getTemplatedDecl())
- dispatch(D->getTemplatedDecl());
- }
-
- // FunctionTemplateDecl
- void visitFunctionTemplateDeclAttrs(FunctionTemplateDecl *D) {
- visitRedeclarableAttrs(D);
- }
- void visitFunctionTemplateDeclChildren(FunctionTemplateDecl *D) {
- // Mention all the specializations which don't have explicit
- // declarations elsewhere.
- for (FunctionTemplateDecl::spec_iterator
- I = D->spec_begin(), E = D->spec_end(); I != E; ++I) {
- FunctionTemplateSpecializationInfo *Info
- = I->getTemplateSpecializationInfo();
-
- bool Unknown = false;
- switch (Info->getTemplateSpecializationKind()) {
- case TSK_ImplicitInstantiation: Unknown = false; break;
- case TSK_Undeclared: Unknown = true; break;
-
- // These will be covered at their respective sites.
- case TSK_ExplicitSpecialization: continue;
- case TSK_ExplicitInstantiationDeclaration: continue;
- case TSK_ExplicitInstantiationDefinition: continue;
- }
-
- TemporaryContainer C(*this,
- Unknown ? "uninstantiated" : "instantiation");
- visitTemplateArguments(*Info->TemplateArguments);
- dispatch(Info->Function);
- }
- }
-
- // ClasTemplateDecl
- void visitClassTemplateDeclAttrs(ClassTemplateDecl *D) {
- visitRedeclarableAttrs(D);
- }
- void visitClassTemplateDeclChildren(ClassTemplateDecl *D) {
- // Mention all the specializations which don't have explicit
- // declarations elsewhere.
- for (ClassTemplateDecl::spec_iterator
- I = D->spec_begin(), E = D->spec_end(); I != E; ++I) {
-
- bool Unknown = false;
- switch (I->getTemplateSpecializationKind()) {
- case TSK_ImplicitInstantiation: Unknown = false; break;
- case TSK_Undeclared: Unknown = true; break;
-
- // These will be covered at their respective sites.
- case TSK_ExplicitSpecialization: continue;
- case TSK_ExplicitInstantiationDeclaration: continue;
- case TSK_ExplicitInstantiationDefinition: continue;
- }
-
- TemporaryContainer C(*this,
- Unknown ? "uninstantiated" : "instantiation");
- visitTemplateArguments(I->getTemplateArgs());
- dispatch(*I);
- }
- }
-
- // TemplateTypeParmDecl
- void visitTemplateTypeParmDeclAttrs(TemplateTypeParmDecl *D) {
- setInteger("depth", D->getDepth());
- setInteger("index", D->getIndex());
- }
- void visitTemplateTypeParmDeclChildren(TemplateTypeParmDecl *D) {
- if (D->hasDefaultArgument() && !D->defaultArgumentWasInherited())
- dispatch(D->getDefaultArgumentInfo()->getTypeLoc());
- // parameter pack?
- }
-
- // NonTypeTemplateParmDecl
- void visitNonTypeTemplateParmDeclAttrs(NonTypeTemplateParmDecl *D) {
- setInteger("depth", D->getDepth());
- setInteger("index", D->getIndex());
- }
- void visitNonTypeTemplateParmDeclChildren(NonTypeTemplateParmDecl *D) {
- if (D->hasDefaultArgument() && !D->defaultArgumentWasInherited())
- dispatch(D->getDefaultArgument());
- // parameter pack?
- }
-
- // TemplateTemplateParmDecl
- void visitTemplateTemplateParmDeclAttrs(TemplateTemplateParmDecl *D) {
- setInteger("depth", D->getDepth());
- setInteger("index", D->getIndex());
- }
- void visitTemplateTemplateParmDeclChildren(TemplateTemplateParmDecl *D) {
- if (D->hasDefaultArgument() && !D->defaultArgumentWasInherited())
- dispatch(D->getDefaultArgument());
- // parameter pack?
- }
-
- // FriendDecl
- void visitFriendDeclChildren(FriendDecl *D) {
- if (TypeSourceInfo *T = D->getFriendType())
- dispatch(T->getTypeLoc());
- else
- dispatch(D->getFriendDecl());
- }
-
- // UsingDirectiveDecl ?
- // UsingDecl ?
- // UsingShadowDecl ?
- // NamespaceAliasDecl ?
- // UnresolvedUsingValueDecl ?
- // UnresolvedUsingTypenameDecl ?
- // StaticAssertDecl ?
-
- // ObjCImplDecl
- void visitObjCImplDeclChildren(ObjCImplDecl *D) {
- visitDeclRef(D->getClassInterface());
- }
- void visitObjCImplDeclAsContext(ObjCImplDecl *D) {
- visitDeclContext(D);
- }
-
- void visitObjCInterfaceDeclAttrs(ObjCInterfaceDecl *D) {
- setPointer("typeptr", D->getTypeForDecl());
- setFlag("forward_decl", !D->isThisDeclarationADefinition());
- setFlag("implicit_interface", D->isImplicitInterfaceDecl());
- }
- void visitObjCInterfaceDeclChildren(ObjCInterfaceDecl *D) {
- visitDeclRef("super", D->getSuperClass());
- visitDeclRef("implementation", D->getImplementation());
- if (D->protocol_begin() != D->protocol_end()) {
- TemporaryContainer C(*this, "protocols");
- for (ObjCInterfaceDecl::protocol_iterator
- I = D->protocol_begin(), E = D->protocol_end(); I != E; ++I)
- visitDeclRef(*I);
- }
-
- if (!D->visible_categories_empty()) {
- TemporaryContainer C(*this, "categories");
-
- for (ObjCInterfaceDecl::visible_categories_iterator
- Cat = D->visible_categories_begin(),
- CatEnd = D->visible_categories_end();
- Cat != CatEnd; ++Cat) {
- visitDeclRef(*Cat);
- }
- }
- }
- void visitObjCInterfaceDeclAsContext(ObjCInterfaceDecl *D) {
- visitDeclContext(D);
- }
-
- // ObjCCategoryDecl
- void visitObjCCategoryDeclAttrs(ObjCCategoryDecl *D) {
- setFlag("extension", D->IsClassExtension());
- }
- void visitObjCCategoryDeclChildren(ObjCCategoryDecl *D) {
- visitDeclRef("interface", D->getClassInterface());
- visitDeclRef("implementation", D->getImplementation());
- if (D->protocol_begin() != D->protocol_end()) {
- TemporaryContainer C(*this, "protocols");
- for (ObjCCategoryDecl::protocol_iterator
- I = D->protocol_begin(), E = D->protocol_end(); I != E; ++I)
- visitDeclRef(*I);
- }
- }
- void visitObjCCategoryDeclAsContext(ObjCCategoryDecl *D) {
- visitDeclContext(D);
- }
-
- // ObjCCategoryImplDecl
- void visitObjCCategoryImplDeclAttrs(ObjCCategoryImplDecl *D) {
- set("identifier", D->getName());
- }
- void visitObjCCategoryImplDeclChildren(ObjCCategoryImplDecl *D) {
- visitDeclRef(D->getCategoryDecl());
- }
-
- // ObjCImplementationDecl
- void visitObjCImplementationDeclAttrs(ObjCImplementationDecl *D) {
- set("identifier", D->getName());
- }
- void visitObjCImplementationDeclChildren(ObjCImplementationDecl *D) {
- visitDeclRef("super", D->getSuperClass());
- if (D->init_begin() != D->init_end()) {
- TemporaryContainer C(*this, "initializers");
- for (ObjCImplementationDecl::init_iterator
- I = D->init_begin(), E = D->init_end(); I != E; ++I)
- dispatch(*I);
- }
- }
-
- // ObjCProtocolDecl
- void visitObjCProtocolDeclChildren(ObjCProtocolDecl *D) {
- if (!D->isThisDeclarationADefinition())
- return;
-
- if (D->protocol_begin() != D->protocol_end()) {
- TemporaryContainer C(*this, "protocols");
- for (ObjCInterfaceDecl::protocol_iterator
- I = D->protocol_begin(), E = D->protocol_end(); I != E; ++I)
- visitDeclRef(*I);
- }
- }
- void visitObjCProtocolDeclAsContext(ObjCProtocolDecl *D) {
- if (!D->isThisDeclarationADefinition())
- return;
-
- visitDeclContext(D);
- }
-
- // ObjCMethodDecl
- void visitObjCMethodDeclAttrs(ObjCMethodDecl *D) {
- // decl qualifier?
- // implementation control?
-
- setFlag("instance", D->isInstanceMethod());
- setFlag("variadic", D->isVariadic());
- setFlag("property_accessor", D->isPropertyAccessor());
- setFlag("defined", D->isDefined());
- setFlag("related_result_type", D->hasRelatedResultType());
- }
- void visitObjCMethodDeclChildren(ObjCMethodDecl *D) {
- dispatch(D->getResultType());
- for (ObjCMethodDecl::param_iterator
- I = D->param_begin(), E = D->param_end(); I != E; ++I)
- dispatch(*I);
- if (D->isThisDeclarationADefinition())
- dispatch(D->getBody());
- }
-
- // ObjCIvarDecl
- void setAccessControl(StringRef prop, ObjCIvarDecl::AccessControl AC) {
- switch (AC) {
- case ObjCIvarDecl::None: return set(prop, "none");
- case ObjCIvarDecl::Private: return set(prop, "private");
- case ObjCIvarDecl::Protected: return set(prop, "protected");
- case ObjCIvarDecl::Public: return set(prop, "public");
- case ObjCIvarDecl::Package: return set(prop, "package");
- }
- }
- void visitObjCIvarDeclAttrs(ObjCIvarDecl *D) {
- setFlag("synthesize", D->getSynthesize());
- setAccessControl("access", D->getAccessControl());
- }
-
- // ObjCCompatibleAliasDecl
- void visitObjCCompatibleAliasDeclChildren(ObjCCompatibleAliasDecl *D) {
- visitDeclRef(D->getClassInterface());
- }
-
- // FIXME: ObjCPropertyDecl
- // FIXME: ObjCPropertyImplDecl
-
- //---- Types -----------------------------------------------------//
- void dispatch(TypeLoc TL) {
- dispatch(TL.getType()); // for now
- }
-
- void dispatch(QualType T) {
- if (T.hasLocalQualifiers()) {
- push("QualType");
- Qualifiers Qs = T.getLocalQualifiers();
- setFlag("const", Qs.hasConst());
- setFlag("volatile", Qs.hasVolatile());
- setFlag("restrict", Qs.hasRestrict());
- if (Qs.hasAddressSpace()) setInteger("addrspace", Qs.getAddressSpace());
- if (Qs.hasObjCGCAttr()) {
- switch (Qs.getObjCGCAttr()) {
- case Qualifiers::Weak: set("gc", "weak"); break;
- case Qualifiers::Strong: set("gc", "strong"); break;
- case Qualifiers::GCNone: llvm_unreachable("explicit none");
- }
- }
-
- completeAttrs();
- dispatch(QualType(T.getTypePtr(), 0));
- pop();
- return;
- }
-
- Type *Ty = const_cast<Type*>(T.getTypePtr());
- push(getTypeKindName(Ty));
- XMLTypeVisitor<XMLDumper>::dispatch(const_cast<Type*>(T.getTypePtr()));
- pop();
- }
-
- void setCallingConv(CallingConv CC) {
- switch (CC) {
- case CC_Default: return;
- case CC_C: return set("cc", "cdecl");
- case CC_X86FastCall: return set("cc", "x86_fastcall");
- case CC_X86StdCall: return set("cc", "x86_stdcall");
- case CC_X86ThisCall: return set("cc", "x86_thiscall");
- case CC_X86Pascal: return set("cc", "x86_pascal");
- case CC_AAPCS: return set("cc", "aapcs");
- case CC_AAPCS_VFP: return set("cc", "aapcs_vfp");
- case CC_PnaclCall: return set("cc", "pnaclcall");
- case CC_IntelOclBicc: return set("cc", "intel_ocl_bicc");
- }
- }
-
- void visitTypeAttrs(Type *D) {
- setPointer(D);
- setFlag("dependent", D->isDependentType());
- setFlag("variably_modified", D->isVariablyModifiedType());
-
- setPointer("canonical", D->getCanonicalTypeInternal().getAsOpaquePtr());
- }
-
- void visitPointerTypeChildren(PointerType *T) {
- dispatch(T->getPointeeType());
- }
- void visitReferenceTypeChildren(ReferenceType *T) {
- dispatch(T->getPointeeType());
- }
- void visitObjCObjectPointerTypeChildren(ObjCObjectPointerType *T) {
- dispatch(T->getPointeeType());
- }
- void visitBlockPointerTypeChildren(BlockPointerType *T) {
- dispatch(T->getPointeeType());
- }
-
- // Types that just wrap declarations.
- void visitTagTypeChildren(TagType *T) {
- visitDeclRef(T->getDecl());
- }
- void visitTypedefTypeChildren(TypedefType *T) {
- visitDeclRef(T->getDecl());
- }
- void visitObjCInterfaceTypeChildren(ObjCInterfaceType *T) {
- visitDeclRef(T->getDecl());
- }
- void visitUnresolvedUsingTypeChildren(UnresolvedUsingType *T) {
- visitDeclRef(T->getDecl());
- }
- void visitInjectedClassNameTypeChildren(InjectedClassNameType *T) {
- visitDeclRef(T->getDecl());
- }
-
- void visitFunctionTypeAttrs(FunctionType *T) {
- setFlag("noreturn", T->getNoReturnAttr());
- setCallingConv(T->getCallConv());
- if (T->getHasRegParm()) setInteger("regparm", T->getRegParmType());
- }
- void visitFunctionTypeChildren(FunctionType *T) {
- dispatch(T->getResultType());
- }
-
- void visitFunctionProtoTypeAttrs(FunctionProtoType *T) {
- setFlag("const", T->isConst());
- setFlag("volatile", T->isVolatile());
- setFlag("restrict", T->isRestrict());
- switch (T->getExceptionSpecType()) {
- case EST_None: break;
- case EST_DynamicNone: set("exception_spec", "throw()"); break;
- case EST_Dynamic: set("exception_spec", "throw(T)"); break;
- case EST_MSAny: set("exception_spec", "throw(...)"); break;
- case EST_BasicNoexcept: set("exception_spec", "noexcept"); break;
- case EST_ComputedNoexcept: set("exception_spec", "noexcept(expr)"); break;
- case EST_Unevaluated: set("exception_spec", "unevaluated"); break;
- case EST_Uninstantiated: set("exception_spec", "uninstantiated"); break;
- }
- }
- void visitFunctionProtoTypeChildren(FunctionProtoType *T) {
- push("parameters");
- setFlag("variadic", T->isVariadic());
- completeAttrs();
- for (FunctionProtoType::arg_type_iterator
- I = T->arg_type_begin(), E = T->arg_type_end(); I != E; ++I)
- dispatch(*I);
- pop();
-
- if (T->hasDynamicExceptionSpec()) {
- push("exception_specifiers");
- setFlag("any", T->getExceptionSpecType() == EST_MSAny);
- completeAttrs();
- for (FunctionProtoType::exception_iterator
- I = T->exception_begin(), E = T->exception_end(); I != E; ++I)
- dispatch(*I);
- pop();
- }
- // FIXME: noexcept specifier
- }
-
- void visitTemplateSpecializationTypeChildren(TemplateSpecializationType *T) {
- if (const RecordType *RT = T->getAs<RecordType>())
- visitDeclRef(RT->getDecl());
-
- // TODO: TemplateName
-
- push("template_arguments");
- completeAttrs();
- for (unsigned I = 0, E = T->getNumArgs(); I != E; ++I)
- dispatch(T->getArg(I));
- pop();
- }
-
- //---- Statements ------------------------------------------------//
- void dispatch(Stmt *S) {
- // FIXME: this is not really XML at all
- push("Stmt");
- out << ">\n";
- Stack.back().State = NS_Children; // explicitly become non-lazy
- S->dump(out, Context.getSourceManager());
- out << '\n';
- pop();
- }
-};
-}
-
-void Decl::dumpXML() const {
- dumpXML(llvm::errs());
-}
-
-void Decl::dumpXML(raw_ostream &out) const {
- XMLDumper(out, getASTContext()).dispatch(const_cast<Decl*>(this));
-}
-
-#else /* ifndef NDEBUG */
-
-void Decl::dumpXML() const {}
-void Decl::dumpXML(raw_ostream &out) const {}
-
-#endif
diff --git a/lib/AST/Expr.cpp b/lib/AST/Expr.cpp
index 9538ddf9416c..9055ddac35e3 100644
--- a/lib/AST/Expr.cpp
+++ b/lib/AST/Expr.cpp
@@ -20,6 +20,7 @@
#include "clang/AST/EvaluatedExprVisitor.h"
#include "clang/AST/Expr.h"
#include "clang/AST/ExprCXX.h"
+#include "clang/AST/Mangle.h"
#include "clang/AST/RecordLayout.h"
#include "clang/AST/StmtVisitor.h"
#include "clang/Basic/Builtins.h"
@@ -50,9 +51,9 @@ const CXXRecordDecl *Expr::getBestDynamicClassType() const {
return cast<CXXRecordDecl>(D);
}
-const Expr *
-Expr::skipRValueSubobjectAdjustments(
- SmallVectorImpl<SubobjectAdjustment> &Adjustments) const {
+const Expr *Expr::skipRValueSubobjectAdjustments(
+ SmallVectorImpl<const Expr *> &CommaLHSs,
+ SmallVectorImpl<SubobjectAdjustment> &Adjustments) const {
const Expr *E = this;
while (true) {
E = E->IgnoreParens();
@@ -73,12 +74,14 @@ Expr::skipRValueSubobjectAdjustments(
continue;
}
} else if (const MemberExpr *ME = dyn_cast<MemberExpr>(E)) {
- if (!ME->isArrow() && ME->getBase()->isRValue()) {
+ if (!ME->isArrow()) {
assert(ME->getBase()->getType()->isRecordType());
if (FieldDecl *Field = dyn_cast<FieldDecl>(ME->getMemberDecl())) {
- E = ME->getBase();
- Adjustments.push_back(SubobjectAdjustment(Field));
- continue;
+ if (!Field->isBitField() && !Field->getType()->isReferenceType()) {
+ E = ME->getBase();
+ Adjustments.push_back(SubobjectAdjustment(Field));
+ continue;
+ }
}
}
} else if (const BinaryOperator *BO = dyn_cast<BinaryOperator>(E)) {
@@ -88,6 +91,11 @@ Expr::skipRValueSubobjectAdjustments(
const MemberPointerType *MPT =
BO->getRHS()->getType()->getAs<MemberPointerType>();
Adjustments.push_back(SubobjectAdjustment(MPT, BO->getRHS()));
+ continue;
+ } else if (BO->getOpcode() == BO_Comma) {
+ CommaLHSs.push_back(BO->getLHS());
+ E = BO->getRHS();
+ continue;
}
}
@@ -231,8 +239,8 @@ SourceLocation Expr::getExprLoc() const {
/// \brief Compute the type-, value-, and instantiation-dependence of a
/// declaration reference
/// based on the declaration being referenced.
-static void computeDeclRefDependence(ASTContext &Ctx, NamedDecl *D, QualType T,
- bool &TypeDependent,
+static void computeDeclRefDependence(const ASTContext &Ctx, NamedDecl *D,
+ QualType T, bool &TypeDependent,
bool &ValueDependent,
bool &InstantiationDependent) {
TypeDependent = false;
@@ -307,6 +315,9 @@ static void computeDeclRefDependence(ASTContext &Ctx, NamedDecl *D, QualType T,
Var->getDeclContext()->isDependentContext()) {
ValueDependent = true;
InstantiationDependent = true;
+ TypeSourceInfo *TInfo = Var->getFirstDecl()->getTypeSourceInfo();
+ if (TInfo->getType()->isIncompleteArrayType())
+ TypeDependent = true;
}
return;
@@ -321,7 +332,7 @@ static void computeDeclRefDependence(ASTContext &Ctx, NamedDecl *D, QualType T,
}
}
-void DeclRefExpr::computeDependence(ASTContext &Ctx) {
+void DeclRefExpr::computeDependence(const ASTContext &Ctx) {
bool TypeDependent = false;
bool ValueDependent = false;
bool InstantiationDependent = false;
@@ -355,7 +366,7 @@ void DeclRefExpr::computeDependence(ASTContext &Ctx) {
ExprBits.ContainsUnexpandedParameterPack = true;
}
-DeclRefExpr::DeclRefExpr(ASTContext &Ctx,
+DeclRefExpr::DeclRefExpr(const ASTContext &Ctx,
NestedNameSpecifierLoc QualifierLoc,
SourceLocation TemplateKWLoc,
ValueDecl *D, bool RefersToEnclosingLocal,
@@ -392,7 +403,7 @@ DeclRefExpr::DeclRefExpr(ASTContext &Ctx,
computeDependence(Ctx);
}
-DeclRefExpr *DeclRefExpr::Create(ASTContext &Context,
+DeclRefExpr *DeclRefExpr::Create(const ASTContext &Context,
NestedNameSpecifierLoc QualifierLoc,
SourceLocation TemplateKWLoc,
ValueDecl *D,
@@ -408,7 +419,7 @@ DeclRefExpr *DeclRefExpr::Create(ASTContext &Context,
T, VK, FoundD, TemplateArgs);
}
-DeclRefExpr *DeclRefExpr::Create(ASTContext &Context,
+DeclRefExpr *DeclRefExpr::Create(const ASTContext &Context,
NestedNameSpecifierLoc QualifierLoc,
SourceLocation TemplateKWLoc,
ValueDecl *D,
@@ -423,7 +434,7 @@ DeclRefExpr *DeclRefExpr::Create(ASTContext &Context,
FoundD = 0;
std::size_t Size = sizeof(DeclRefExpr);
- if (QualifierLoc != 0)
+ if (QualifierLoc)
Size += sizeof(NestedNameSpecifierLoc);
if (FoundD)
Size += sizeof(NamedDecl *);
@@ -438,7 +449,7 @@ DeclRefExpr *DeclRefExpr::Create(ASTContext &Context,
NameInfo, FoundD, TemplateArgs, T, VK);
}
-DeclRefExpr *DeclRefExpr::CreateEmpty(ASTContext &Context,
+DeclRefExpr *DeclRefExpr::CreateEmpty(const ASTContext &Context,
bool HasQualifier,
bool HasFoundDecl,
bool HasTemplateKWAndArgsInfo,
@@ -471,6 +482,30 @@ SourceLocation DeclRefExpr::getLocEnd() const {
std::string PredefinedExpr::ComputeName(IdentType IT, const Decl *CurrentDecl) {
ASTContext &Context = CurrentDecl->getASTContext();
+ if (IT == PredefinedExpr::FuncDName) {
+ if (const NamedDecl *ND = dyn_cast<NamedDecl>(CurrentDecl)) {
+ OwningPtr<MangleContext> MC;
+ MC.reset(Context.createMangleContext());
+
+ if (MC->shouldMangleDeclName(ND)) {
+ SmallString<256> Buffer;
+ llvm::raw_svector_ostream Out(Buffer);
+ if (const CXXConstructorDecl *CD = dyn_cast<CXXConstructorDecl>(ND))
+ MC->mangleCXXCtor(CD, Ctor_Base, Out);
+ else if (const CXXDestructorDecl *DD = dyn_cast<CXXDestructorDecl>(ND))
+ MC->mangleCXXDtor(DD, Dtor_Base, Out);
+ else
+ MC->mangleName(ND, Out);
+
+ Out.flush();
+ if (!Buffer.empty() && Buffer.front() == '\01')
+ return Buffer.substr(1);
+ return Buffer.str();
+ } else
+ return ND->getIdentifier()->getName();
+ }
+ return "";
+ }
if (const FunctionDecl *FD = dyn_cast<FunctionDecl>(CurrentDecl)) {
if (IT != PrettyFunction && IT != PrettyFunctionNoVirtual)
return FD->getNameAsString();
@@ -578,7 +613,18 @@ std::string PredefinedExpr::ComputeName(IdentType IT, const Decl *CurrentDecl) {
POut.flush();
- if (!isa<CXXConstructorDecl>(FD) && !isa<CXXDestructorDecl>(FD))
+ // Print "auto" for all deduced return types. This includes C++1y return
+ // type deduction and lambdas. For trailing return types resolve the
+ // decltype expression. Otherwise print the real type when this is
+ // not a constructor or destructor.
+ if ((isa<CXXMethodDecl>(FD) &&
+ cast<CXXMethodDecl>(FD)->getParent()->isLambda()) ||
+ (FT && FT->getResultType()->getAs<AutoType>()))
+ Proto = "auto " + Proto;
+ else if (FT && FT->getResultType()->getAs<DecltypeType>())
+ FT->getResultType()->getAs<DecltypeType>()->getUnderlyingType()
+ .getAsStringInternal(Proto, Policy);
+ else if (!isa<CXXConstructorDecl>(FD) && !isa<CXXDestructorDecl>(FD))
AFT->getResultType().getAsStringInternal(Proto, Policy);
Out << Proto;
@@ -586,6 +632,16 @@ std::string PredefinedExpr::ComputeName(IdentType IT, const Decl *CurrentDecl) {
Out.flush();
return Name.str().str();
}
+ if (const CapturedDecl *CD = dyn_cast<CapturedDecl>(CurrentDecl)) {
+ for (const DeclContext *DC = CD->getParent(); DC; DC = DC->getParent())
+ // Skip to its enclosing function or method, but not its enclosing
+ // CapturedDecl.
+ if (DC->isFunctionOrMethod() && (DC->getDeclKind() != Decl::Captured)) {
+ const Decl *D = Decl::castFromDeclContext(DC);
+ return ComputeName(IT, D);
+ }
+ llvm_unreachable("CapturedDecl not inside a function or method");
+ }
if (const ObjCMethodDecl *MD = dyn_cast<ObjCMethodDecl>(CurrentDecl)) {
SmallString<256> Name;
llvm::raw_svector_ostream Out(Name);
@@ -615,7 +671,8 @@ std::string PredefinedExpr::ComputeName(IdentType IT, const Decl *CurrentDecl) {
return "";
}
-void APNumericStorage::setIntValue(ASTContext &C, const llvm::APInt &Val) {
+void APNumericStorage::setIntValue(const ASTContext &C,
+ const llvm::APInt &Val) {
if (hasAllocation())
C.Deallocate(pVal);
@@ -631,7 +688,7 @@ void APNumericStorage::setIntValue(ASTContext &C, const llvm::APInt &Val) {
VAL = 0;
}
-IntegerLiteral::IntegerLiteral(ASTContext &C, const llvm::APInt &V,
+IntegerLiteral::IntegerLiteral(const ASTContext &C, const llvm::APInt &V,
QualType type, SourceLocation l)
: Expr(IntegerLiteralClass, type, VK_RValue, OK_Ordinary, false, false,
false, false),
@@ -643,17 +700,17 @@ IntegerLiteral::IntegerLiteral(ASTContext &C, const llvm::APInt &V,
}
IntegerLiteral *
-IntegerLiteral::Create(ASTContext &C, const llvm::APInt &V,
+IntegerLiteral::Create(const ASTContext &C, const llvm::APInt &V,
QualType type, SourceLocation l) {
return new (C) IntegerLiteral(C, V, type, l);
}
IntegerLiteral *
-IntegerLiteral::Create(ASTContext &C, EmptyShell Empty) {
+IntegerLiteral::Create(const ASTContext &C, EmptyShell Empty) {
return new (C) IntegerLiteral(Empty);
}
-FloatingLiteral::FloatingLiteral(ASTContext &C, const llvm::APFloat &V,
+FloatingLiteral::FloatingLiteral(const ASTContext &C, const llvm::APFloat &V,
bool isexact, QualType Type, SourceLocation L)
: Expr(FloatingLiteralClass, Type, VK_RValue, OK_Ordinary, false, false,
false, false), Loc(L) {
@@ -662,20 +719,20 @@ FloatingLiteral::FloatingLiteral(ASTContext &C, const llvm::APFloat &V,
setValue(C, V);
}
-FloatingLiteral::FloatingLiteral(ASTContext &C, EmptyShell Empty)
+FloatingLiteral::FloatingLiteral(const ASTContext &C, EmptyShell Empty)
: Expr(FloatingLiteralClass, Empty) {
setRawSemantics(IEEEhalf);
FloatingLiteralBits.IsExact = false;
}
FloatingLiteral *
-FloatingLiteral::Create(ASTContext &C, const llvm::APFloat &V,
+FloatingLiteral::Create(const ASTContext &C, const llvm::APFloat &V,
bool isexact, QualType Type, SourceLocation L) {
return new (C) FloatingLiteral(C, V, isexact, Type, L);
}
FloatingLiteral *
-FloatingLiteral::Create(ASTContext &C, EmptyShell Empty) {
+FloatingLiteral::Create(const ASTContext &C, EmptyShell Empty) {
return new (C) FloatingLiteral(C, Empty);
}
@@ -749,7 +806,7 @@ int StringLiteral::mapCharByteWidth(TargetInfo const &target,StringKind k) {
return CharByteWidth;
}
-StringLiteral *StringLiteral::Create(ASTContext &C, StringRef Str,
+StringLiteral *StringLiteral::Create(const ASTContext &C, StringRef Str,
StringKind Kind, bool Pascal, QualType Ty,
const SourceLocation *Loc,
unsigned NumStrs) {
@@ -771,7 +828,8 @@ StringLiteral *StringLiteral::Create(ASTContext &C, StringRef Str,
return SL;
}
-StringLiteral *StringLiteral::CreateEmpty(ASTContext &C, unsigned NumStrs) {
+StringLiteral *StringLiteral::CreateEmpty(const ASTContext &C,
+ unsigned NumStrs) {
void *Mem = C.Allocate(sizeof(StringLiteral)+
sizeof(SourceLocation)*(NumStrs-1),
llvm::alignOf<StringLiteral>());
@@ -875,7 +933,7 @@ void StringLiteral::outputString(raw_ostream &OS) const {
OS << '"';
}
-void StringLiteral::setString(ASTContext &C, StringRef Str,
+void StringLiteral::setString(const ASTContext &C, StringRef Str,
StringKind Kind, bool IsPascal) {
//FIXME: we assume that the string data comes from a target that uses the same
// code unit size and endianess for the type of string.
@@ -1028,9 +1086,9 @@ OverloadedOperatorKind UnaryOperator::getOverloadedOperator(Opcode Opc) {
// Postfix Operators.
//===----------------------------------------------------------------------===//
-CallExpr::CallExpr(ASTContext& C, StmtClass SC, Expr *fn, unsigned NumPreArgs,
- ArrayRef<Expr*> args, QualType t, ExprValueKind VK,
- SourceLocation rparenloc)
+CallExpr::CallExpr(const ASTContext& C, StmtClass SC, Expr *fn,
+ unsigned NumPreArgs, ArrayRef<Expr*> args, QualType t,
+ ExprValueKind VK, SourceLocation rparenloc)
: Expr(SC, t, VK, OK_Ordinary,
fn->isTypeDependent(),
fn->isValueDependent(),
@@ -1057,7 +1115,7 @@ CallExpr::CallExpr(ASTContext& C, StmtClass SC, Expr *fn, unsigned NumPreArgs,
RParenLoc = rparenloc;
}
-CallExpr::CallExpr(ASTContext& C, Expr *fn, ArrayRef<Expr*> args,
+CallExpr::CallExpr(const ASTContext& C, Expr *fn, ArrayRef<Expr*> args,
QualType t, ExprValueKind VK, SourceLocation rparenloc)
: Expr(CallExprClass, t, VK, OK_Ordinary,
fn->isTypeDependent(),
@@ -1085,14 +1143,14 @@ CallExpr::CallExpr(ASTContext& C, Expr *fn, ArrayRef<Expr*> args,
RParenLoc = rparenloc;
}
-CallExpr::CallExpr(ASTContext &C, StmtClass SC, EmptyShell Empty)
+CallExpr::CallExpr(const ASTContext &C, StmtClass SC, EmptyShell Empty)
: Expr(SC, Empty), SubExprs(0), NumArgs(0) {
// FIXME: Why do we allocate this?
SubExprs = new (C) Stmt*[PREARGS_START];
CallExprBits.NumPreArgs = 0;
}
-CallExpr::CallExpr(ASTContext &C, StmtClass SC, unsigned NumPreArgs,
+CallExpr::CallExpr(const ASTContext &C, StmtClass SC, unsigned NumPreArgs,
EmptyShell Empty)
: Expr(SC, Empty), SubExprs(0), NumArgs(0) {
// FIXME: Why do we allocate this?
@@ -1131,7 +1189,7 @@ FunctionDecl *CallExpr::getDirectCallee() {
/// setNumArgs - This changes the number of arguments present in this call.
/// Any orphaned expressions are deleted by this, and any new operands are set
/// to null.
-void CallExpr::setNumArgs(ASTContext& C, unsigned NumArgs) {
+void CallExpr::setNumArgs(const ASTContext& C, unsigned NumArgs) {
// No change, just return.
if (NumArgs == getNumArgs()) return;
@@ -1220,7 +1278,7 @@ SourceLocation CallExpr::getLocEnd() const {
return end;
}
-OffsetOfExpr *OffsetOfExpr::Create(ASTContext &C, QualType type,
+OffsetOfExpr *OffsetOfExpr::Create(const ASTContext &C, QualType type,
SourceLocation OperatorLoc,
TypeSourceInfo *tsi,
ArrayRef<OffsetOfNode> comps,
@@ -1234,7 +1292,7 @@ OffsetOfExpr *OffsetOfExpr::Create(ASTContext &C, QualType type,
RParenLoc);
}
-OffsetOfExpr *OffsetOfExpr::CreateEmpty(ASTContext &C,
+OffsetOfExpr *OffsetOfExpr::CreateEmpty(const ASTContext &C,
unsigned numComps, unsigned numExprs) {
void *Mem = C.Allocate(sizeof(OffsetOfExpr) +
sizeof(OffsetOfNode) * numComps +
@@ -1242,7 +1300,7 @@ OffsetOfExpr *OffsetOfExpr::CreateEmpty(ASTContext &C,
return new (Mem) OffsetOfExpr(numComps, numExprs);
}
-OffsetOfExpr::OffsetOfExpr(ASTContext &C, QualType type,
+OffsetOfExpr::OffsetOfExpr(const ASTContext &C, QualType type,
SourceLocation OperatorLoc, TypeSourceInfo *tsi,
ArrayRef<OffsetOfNode> comps, ArrayRef<Expr*> exprs,
SourceLocation RParenLoc)
@@ -1276,7 +1334,7 @@ IdentifierInfo *OffsetOfExpr::OffsetOfNode::getFieldName() const {
return reinterpret_cast<IdentifierInfo *> (Data & ~(uintptr_t)Mask);
}
-MemberExpr *MemberExpr::Create(ASTContext &C, Expr *base, bool isarrow,
+MemberExpr *MemberExpr::Create(const ASTContext &C, Expr *base, bool isarrow,
NestedNameSpecifierLoc QualifierLoc,
SourceLocation TemplateKWLoc,
ValueDecl *memberdecl,
@@ -1630,7 +1688,7 @@ void CastExpr::setCastPath(const CXXCastPath &Path) {
memcpy(path_buffer(), Path.data(), Path.size() * sizeof(CXXBaseSpecifier*));
}
-ImplicitCastExpr *ImplicitCastExpr::Create(ASTContext &C, QualType T,
+ImplicitCastExpr *ImplicitCastExpr::Create(const ASTContext &C, QualType T,
CastKind Kind, Expr *Operand,
const CXXCastPath *BasePath,
ExprValueKind VK) {
@@ -1643,7 +1701,7 @@ ImplicitCastExpr *ImplicitCastExpr::Create(ASTContext &C, QualType T,
return E;
}
-ImplicitCastExpr *ImplicitCastExpr::CreateEmpty(ASTContext &C,
+ImplicitCastExpr *ImplicitCastExpr::CreateEmpty(const ASTContext &C,
unsigned PathSize) {
void *Buffer =
C.Allocate(sizeof(ImplicitCastExpr) + PathSize * sizeof(CXXBaseSpecifier*));
@@ -1651,7 +1709,7 @@ ImplicitCastExpr *ImplicitCastExpr::CreateEmpty(ASTContext &C,
}
-CStyleCastExpr *CStyleCastExpr::Create(ASTContext &C, QualType T,
+CStyleCastExpr *CStyleCastExpr::Create(const ASTContext &C, QualType T,
ExprValueKind VK, CastKind K, Expr *Op,
const CXXCastPath *BasePath,
TypeSourceInfo *WrittenTy,
@@ -1665,7 +1723,8 @@ CStyleCastExpr *CStyleCastExpr::Create(ASTContext &C, QualType T,
return E;
}
-CStyleCastExpr *CStyleCastExpr::CreateEmpty(ASTContext &C, unsigned PathSize) {
+CStyleCastExpr *CStyleCastExpr::CreateEmpty(const ASTContext &C,
+ unsigned PathSize) {
void *Buffer =
C.Allocate(sizeof(CStyleCastExpr) + PathSize * sizeof(CXXBaseSpecifier*));
return new (Buffer) CStyleCastExpr(EmptyShell(), PathSize);
@@ -1774,7 +1833,7 @@ OverloadedOperatorKind BinaryOperator::getOverloadedOperator(Opcode Opc) {
return OverOps[Opc];
}
-InitListExpr::InitListExpr(ASTContext &C, SourceLocation lbraceloc,
+InitListExpr::InitListExpr(const ASTContext &C, SourceLocation lbraceloc,
ArrayRef<Expr*> initExprs, SourceLocation rbraceloc)
: Expr(InitListExprClass, QualType(), VK_RValue, OK_Ordinary, false, false,
false, false),
@@ -1782,7 +1841,6 @@ InitListExpr::InitListExpr(ASTContext &C, SourceLocation lbraceloc,
LBraceLoc(lbraceloc), RBraceLoc(rbraceloc), AltForm(0, true)
{
sawArrayRangeDesignator(false);
- setInitializesStdInitializerList(false);
for (unsigned I = 0; I != initExprs.size(); ++I) {
if (initExprs[I]->isTypeDependent())
ExprBits.TypeDependent = true;
@@ -1797,16 +1855,16 @@ InitListExpr::InitListExpr(ASTContext &C, SourceLocation lbraceloc,
InitExprs.insert(C, InitExprs.end(), initExprs.begin(), initExprs.end());
}
-void InitListExpr::reserveInits(ASTContext &C, unsigned NumInits) {
+void InitListExpr::reserveInits(const ASTContext &C, unsigned NumInits) {
if (NumInits > InitExprs.size())
InitExprs.reserve(C, NumInits);
}
-void InitListExpr::resizeInits(ASTContext &C, unsigned NumInits) {
+void InitListExpr::resizeInits(const ASTContext &C, unsigned NumInits) {
InitExprs.resize(C, NumInits, 0);
}
-Expr *InitListExpr::updateInit(ASTContext &C, unsigned Init, Expr *expr) {
+Expr *InitListExpr::updateInit(const ASTContext &C, unsigned Init, Expr *expr) {
if (Init >= InitExprs.size()) {
InitExprs.insert(C, InitExprs.end(), Init - InitExprs.size() + 1, 0);
InitExprs.back() = expr;
@@ -1923,6 +1981,9 @@ bool Expr::isUnusedResultAWarning(const Expr *&WarnE, SourceLocation &Loc,
case GenericSelectionExprClass:
return cast<GenericSelectionExpr>(this)->getResultExpr()->
isUnusedResultAWarning(WarnE, Loc, R1, R2, Ctx);
+ case ChooseExprClass:
+ return cast<ChooseExpr>(this)->getChosenSubExpr()->
+ isUnusedResultAWarning(WarnE, Loc, R1, R2, Ctx);
case UnaryOperatorClass: {
const UnaryOperator *UO = cast<UnaryOperator>(this);
@@ -2066,17 +2127,24 @@ bool Expr::isUnusedResultAWarning(const Expr *&WarnE, SourceLocation &Loc,
return false;
case CXXTemporaryObjectExprClass:
- case CXXConstructExprClass:
+ case CXXConstructExprClass: {
+ if (const CXXRecordDecl *Type = getType()->getAsCXXRecordDecl()) {
+ if (Type->hasAttr<WarnUnusedAttr>()) {
+ WarnE = this;
+ Loc = getLocStart();
+ R1 = getSourceRange();
+ return true;
+ }
+ }
return false;
+ }
case ObjCMessageExprClass: {
const ObjCMessageExpr *ME = cast<ObjCMessageExpr>(this);
if (Ctx.getLangOpts().ObjCAutoRefCount &&
ME->isInstanceMessage() &&
!ME->getType()->isVoidType() &&
- ME->getSelector().getIdentifierInfoForSlot(0) &&
- ME->getSelector().getIdentifierInfoForSlot(0)
- ->getName().startswith("init")) {
+ ME->getMethodFamily() == OMF_init) {
WarnE = this;
Loc = getExprLoc();
R1 = ME->getSourceRange();
@@ -2161,7 +2229,7 @@ bool Expr::isUnusedResultAWarning(const Expr *&WarnE, SourceLocation &Loc,
WarnE = this;
if (const CXXFunctionalCastExpr *CXXCE =
dyn_cast<CXXFunctionalCastExpr>(this)) {
- Loc = CXXCE->getTypeBeginLoc();
+ Loc = CXXCE->getLocStart();
R1 = CXXCE->getSubExpr()->getSourceRange();
} else {
const CStyleCastExpr *CStyleCE = cast<CStyleCastExpr>(this);
@@ -2291,6 +2359,12 @@ Expr* Expr::IgnoreParens() {
continue;
}
}
+ if (ChooseExpr* P = dyn_cast<ChooseExpr>(E)) {
+ if (!P->isConditionDependent()) {
+ E = P->getChosenSubExpr();
+ continue;
+ }
+ }
return E;
}
}
@@ -2300,26 +2374,11 @@ Expr* Expr::IgnoreParens() {
Expr *Expr::IgnoreParenCasts() {
Expr *E = this;
while (true) {
- if (ParenExpr* P = dyn_cast<ParenExpr>(E)) {
- E = P->getSubExpr();
- continue;
- }
+ E = E->IgnoreParens();
if (CastExpr *P = dyn_cast<CastExpr>(E)) {
E = P->getSubExpr();
continue;
}
- if (UnaryOperator* P = dyn_cast<UnaryOperator>(E)) {
- if (P->getOpcode() == UO_Extension) {
- E = P->getSubExpr();
- continue;
- }
- }
- if (GenericSelectionExpr* P = dyn_cast<GenericSelectionExpr>(E)) {
- if (!P->isResultDependent()) {
- E = P->getResultExpr();
- continue;
- }
- }
if (MaterializeTemporaryExpr *Materialize
= dyn_cast<MaterializeTemporaryExpr>(E)) {
E = Materialize->GetTemporaryExpr();
@@ -2341,24 +2400,12 @@ Expr *Expr::IgnoreParenCasts() {
Expr *Expr::IgnoreParenLValueCasts() {
Expr *E = this;
while (true) {
- if (ParenExpr *P = dyn_cast<ParenExpr>(E)) {
- E = P->getSubExpr();
- continue;
- } else if (CastExpr *P = dyn_cast<CastExpr>(E)) {
+ E = E->IgnoreParens();
+ if (CastExpr *P = dyn_cast<CastExpr>(E)) {
if (P->getCastKind() == CK_LValueToRValue) {
E = P->getSubExpr();
continue;
}
- } else if (UnaryOperator* P = dyn_cast<UnaryOperator>(E)) {
- if (P->getOpcode() == UO_Extension) {
- E = P->getSubExpr();
- continue;
- }
- } else if (GenericSelectionExpr* P = dyn_cast<GenericSelectionExpr>(E)) {
- if (!P->isResultDependent()) {
- E = P->getResultExpr();
- continue;
- }
} else if (MaterializeTemporaryExpr *Materialize
= dyn_cast<MaterializeTemporaryExpr>(E)) {
E = Materialize->GetTemporaryExpr();
@@ -2376,10 +2423,7 @@ Expr *Expr::IgnoreParenLValueCasts() {
Expr *Expr::ignoreParenBaseCasts() {
Expr *E = this;
while (true) {
- if (ParenExpr *P = dyn_cast<ParenExpr>(E)) {
- E = P->getSubExpr();
- continue;
- }
+ E = E->IgnoreParens();
if (CastExpr *CE = dyn_cast<CastExpr>(E)) {
if (CE->getCastKind() == CK_DerivedToBase ||
CE->getCastKind() == CK_UncheckedDerivedToBase ||
@@ -2396,26 +2440,11 @@ Expr *Expr::ignoreParenBaseCasts() {
Expr *Expr::IgnoreParenImpCasts() {
Expr *E = this;
while (true) {
- if (ParenExpr *P = dyn_cast<ParenExpr>(E)) {
- E = P->getSubExpr();
- continue;
- }
+ E = E->IgnoreParens();
if (ImplicitCastExpr *P = dyn_cast<ImplicitCastExpr>(E)) {
E = P->getSubExpr();
continue;
}
- if (UnaryOperator* P = dyn_cast<UnaryOperator>(E)) {
- if (P->getOpcode() == UO_Extension) {
- E = P->getSubExpr();
- continue;
- }
- }
- if (GenericSelectionExpr* P = dyn_cast<GenericSelectionExpr>(E)) {
- if (!P->isResultDependent()) {
- E = P->getResultExpr();
- continue;
- }
- }
if (MaterializeTemporaryExpr *Materialize
= dyn_cast<MaterializeTemporaryExpr>(E)) {
E = Materialize->GetTemporaryExpr();
@@ -2444,10 +2473,7 @@ Expr *Expr::IgnoreConversionOperator() {
Expr *Expr::IgnoreParenNoopCasts(ASTContext &Ctx) {
Expr *E = this;
while (true) {
- if (ParenExpr *P = dyn_cast<ParenExpr>(E)) {
- E = P->getSubExpr();
- continue;
- }
+ E = E->IgnoreParens();
if (CastExpr *P = dyn_cast<CastExpr>(E)) {
// We ignore integer <-> casts that are of the same width, ptr<->ptr and
@@ -2469,20 +2495,6 @@ Expr *Expr::IgnoreParenNoopCasts(ASTContext &Ctx) {
}
}
- if (UnaryOperator* P = dyn_cast<UnaryOperator>(E)) {
- if (P->getOpcode() == UO_Extension) {
- E = P->getSubExpr();
- continue;
- }
- }
-
- if (GenericSelectionExpr* P = dyn_cast<GenericSelectionExpr>(E)) {
- if (!P->isResultDependent()) {
- E = P->getResultExpr();
- continue;
- }
- }
-
if (SubstNonTypeTemplateParmExpr *NTTP
= dyn_cast<SubstNonTypeTemplateParmExpr>(E)) {
E = NTTP->getReplacement();
@@ -2628,11 +2640,11 @@ bool Expr::hasAnyTypeDependentArguments(ArrayRef<Expr *> Exprs) {
bool Expr::isConstantInitializer(ASTContext &Ctx, bool IsForRef) const {
// This function is attempting whether an expression is an initializer
- // which can be evaluated at compile-time. isEvaluatable handles most
- // of the cases, but it can't deal with some initializer-specific
- // expressions, and it can't deal with aggregates; we deal with those here,
- // and fall back to isEvaluatable for the other cases.
-
+ // which can be evaluated at compile-time. It very closely parallels
+ // ConstExprEmitter in CGExprConstant.cpp; if they don't match, it
+ // will lead to unexpected results. Like ConstExprEmitter, it falls back
+ // to isEvaluatable most of the time.
+ //
// If we ever capture reference-binding directly in the AST, we can
// kill the second parameter.
@@ -2643,30 +2655,23 @@ bool Expr::isConstantInitializer(ASTContext &Ctx, bool IsForRef) const {
switch (getStmtClass()) {
default: break;
- case IntegerLiteralClass:
- case FloatingLiteralClass:
case StringLiteralClass:
- case ObjCStringLiteralClass:
case ObjCEncodeExprClass:
return true;
case CXXTemporaryObjectExprClass:
case CXXConstructExprClass: {
const CXXConstructExpr *CE = cast<CXXConstructExpr>(this);
- // Only if it's
- if (CE->getConstructor()->isTrivial()) {
- // 1) an application of the trivial default constructor or
+ if (CE->getConstructor()->isTrivial() &&
+ CE->getConstructor()->getParent()->hasTrivialDestructor()) {
+ // Trivial default constructor
if (!CE->getNumArgs()) return true;
- // 2) an elidable trivial copy construction of an operand which is
- // itself a constant initializer. Note that we consider the
- // operand on its own, *not* as a reference binding.
- if (CE->isElidable() &&
- CE->getArg(0)->isConstantInitializer(Ctx, false))
- return true;
+ // Trivial copy constructor
+ assert(CE->getNumArgs() == 1 && "trivial ctor with > 1 argument");
+ return CE->getArg(0)->isConstantInitializer(Ctx, false);
}
- // 3) a foldable constexpr constructor.
break;
}
case CompoundLiteralExprClass: {
@@ -2677,16 +2682,47 @@ bool Expr::isConstantInitializer(ASTContext &Ctx, bool IsForRef) const {
return Exp->isConstantInitializer(Ctx, false);
}
case InitListExprClass: {
- // FIXME: This doesn't deal with fields with reference types correctly.
- // FIXME: This incorrectly allows pointers cast to integers to be assigned
- // to bitfields.
- const InitListExpr *Exp = cast<InitListExpr>(this);
- unsigned numInits = Exp->getNumInits();
- for (unsigned i = 0; i < numInits; i++) {
- if (!Exp->getInit(i)->isConstantInitializer(Ctx, false))
- return false;
+ const InitListExpr *ILE = cast<InitListExpr>(this);
+ if (ILE->getType()->isArrayType()) {
+ unsigned numInits = ILE->getNumInits();
+ for (unsigned i = 0; i < numInits; i++) {
+ if (!ILE->getInit(i)->isConstantInitializer(Ctx, false))
+ return false;
+ }
+ return true;
}
- return true;
+
+ if (ILE->getType()->isRecordType()) {
+ unsigned ElementNo = 0;
+ RecordDecl *RD = ILE->getType()->getAs<RecordType>()->getDecl();
+ for (RecordDecl::field_iterator Field = RD->field_begin(),
+ FieldEnd = RD->field_end(); Field != FieldEnd; ++Field) {
+ // If this is a union, skip all the fields that aren't being initialized.
+ if (RD->isUnion() && ILE->getInitializedFieldInUnion() != *Field)
+ continue;
+
+ // Don't emit anonymous bitfields, they just affect layout.
+ if (Field->isUnnamedBitfield())
+ continue;
+
+ if (ElementNo < ILE->getNumInits()) {
+ const Expr *Elt = ILE->getInit(ElementNo++);
+ if (Field->isBitField()) {
+ // Bitfields have to evaluate to an integer.
+ llvm::APSInt ResultTmp;
+ if (!Elt->EvaluateAsInt(ResultTmp, Ctx))
+ return false;
+ } else {
+ bool RefType = Field->getType()->isReferenceType();
+ if (!Elt->isConstantInitializer(Ctx, RefType))
+ return false;
+ }
+ }
+ }
+ return true;
+ }
+
+ break;
}
case ImplicitValueInitExprClass:
return true;
@@ -2694,12 +2730,12 @@ bool Expr::isConstantInitializer(ASTContext &Ctx, bool IsForRef) const {
return cast<ParenExpr>(this)->getSubExpr()
->isConstantInitializer(Ctx, IsForRef);
case GenericSelectionExprClass:
- if (cast<GenericSelectionExpr>(this)->isResultDependent())
- return false;
return cast<GenericSelectionExpr>(this)->getResultExpr()
->isConstantInitializer(Ctx, IsForRef);
case ChooseExprClass:
- return cast<ChooseExpr>(this)->getChosenSubExpr(Ctx)
+ if (cast<ChooseExpr>(this)->isConditionDependent())
+ return false;
+ return cast<ChooseExpr>(this)->getChosenSubExpr()
->isConstantInitializer(Ctx, IsForRef);
case UnaryOperatorClass: {
const UnaryOperator* Exp = cast<UnaryOperator>(this);
@@ -2710,31 +2746,20 @@ bool Expr::isConstantInitializer(ASTContext &Ctx, bool IsForRef) const {
case CXXFunctionalCastExprClass:
case CXXStaticCastExprClass:
case ImplicitCastExprClass:
- case CStyleCastExprClass: {
+ case CStyleCastExprClass:
+ case ObjCBridgedCastExprClass:
+ case CXXDynamicCastExprClass:
+ case CXXReinterpretCastExprClass:
+ case CXXConstCastExprClass: {
const CastExpr *CE = cast<CastExpr>(this);
- // If we're promoting an integer to an _Atomic type then this is constant
- // if the integer is constant. We also need to check the converse in case
- // someone does something like:
- //
- // int a = (_Atomic(int))42;
- //
- // I doubt anyone would write code like this directly, but it's quite
- // possible as the result of macro expansions.
- if (CE->getCastKind() == CK_NonAtomicToAtomic ||
- CE->getCastKind() == CK_AtomicToNonAtomic)
- return CE->getSubExpr()->isConstantInitializer(Ctx, false);
-
- // Handle bitcasts of vector constants.
- if (getType()->isVectorType() && CE->getCastKind() == CK_BitCast)
- return CE->getSubExpr()->isConstantInitializer(Ctx, false);
-
// Handle misc casts we want to ignore.
- // FIXME: Is it really safe to ignore all these?
if (CE->getCastKind() == CK_NoOp ||
CE->getCastKind() == CK_LValueToRValue ||
CE->getCastKind() == CK_ToUnion ||
- CE->getCastKind() == CK_ConstructorConversion)
+ CE->getCastKind() == CK_ConstructorConversion ||
+ CE->getCastKind() == CK_NonAtomicToAtomic ||
+ CE->getCastKind() == CK_AtomicToNonAtomic)
return CE->getSubExpr()->isConstantInitializer(Ctx, false);
break;
@@ -2742,6 +2767,16 @@ bool Expr::isConstantInitializer(ASTContext &Ctx, bool IsForRef) const {
case MaterializeTemporaryExprClass:
return cast<MaterializeTemporaryExpr>(this)->GetTemporaryExpr()
->isConstantInitializer(Ctx, false);
+
+ case SubstNonTypeTemplateParmExprClass:
+ return cast<SubstNonTypeTemplateParmExpr>(this)->getReplacement()
+ ->isConstantInitializer(Ctx, false);
+ case CXXDefaultArgExprClass:
+ return cast<CXXDefaultArgExpr>(this)->getExpr()
+ ->isConstantInitializer(Ctx, false);
+ case CXXDefaultInitExprClass:
+ return cast<CXXDefaultInitExpr>(this)->getExpr()
+ ->isConstantInitializer(Ctx, false);
}
return isEvaluatable(Ctx);
}
@@ -2829,9 +2864,11 @@ bool Expr::HasSideEffects(const ASTContext &Ctx) const {
case DesignatedInitExprClass:
case ParenListExprClass:
case CXXPseudoDestructorExprClass:
+ case CXXStdInitializerListExprClass:
case SubstNonTypeTemplateParmExprClass:
case MaterializeTemporaryExprClass:
case ShuffleVectorExprClass:
+ case ConvertVectorExprClass:
case AsTypeExprClass:
// These have a side-effect if any subexpression does.
break;
@@ -2858,7 +2895,7 @@ bool Expr::HasSideEffects(const ASTContext &Ctx) const {
HasSideEffects(Ctx);
case ChooseExprClass:
- return cast<ChooseExpr>(this)->getChosenSubExpr(Ctx)->HasSideEffects(Ctx);
+ return cast<ChooseExpr>(this)->getChosenSubExpr()->HasSideEffects(Ctx);
case CXXDefaultArgExprClass:
return cast<CXXDefaultArgExpr>(this)->getExpr()->HasSideEffects(Ctx);
@@ -3017,7 +3054,8 @@ bool Expr::hasNonTrivialCall(ASTContext &Ctx) {
Expr::NullPointerConstantKind
Expr::isNullPointerConstant(ASTContext &Ctx,
NullPointerConstantValueDependence NPC) const {
- if (isValueDependent()) {
+ if (isValueDependent() &&
+ (!Ctx.getLangOpts().CPlusPlus11 || Ctx.getLangOpts().MicrosoftMode)) {
switch (NPC) {
case NPC_NeverValueDependent:
llvm_unreachable("Unexpected value dependent expression!");
@@ -3053,7 +3091,13 @@ Expr::isNullPointerConstant(ASTContext &Ctx,
return PE->getSubExpr()->isNullPointerConstant(Ctx, NPC);
} else if (const GenericSelectionExpr *GE =
dyn_cast<GenericSelectionExpr>(this)) {
+ if (GE->isResultDependent())
+ return NPCK_NotNull;
return GE->getResultExpr()->isNullPointerConstant(Ctx, NPC);
+ } else if (const ChooseExpr *CE = dyn_cast<ChooseExpr>(this)) {
+ if (CE->isConditionDependent())
+ return NPCK_NotNull;
+ return CE->getChosenSubExpr()->isNullPointerConstant(Ctx, NPC);
} else if (const CXXDefaultArgExpr *DefaultArg
= dyn_cast<CXXDefaultArgExpr>(this)) {
// See through default argument expressions.
@@ -3078,7 +3122,8 @@ Expr::isNullPointerConstant(ASTContext &Ctx,
return NPCK_CXX11_nullptr;
if (const RecordType *UT = getType()->getAsUnionType())
- if (UT && UT->getDecl()->hasAttr<TransparentUnionAttr>())
+ if (!Ctx.getLangOpts().CPlusPlus11 &&
+ UT && UT->getDecl()->hasAttr<TransparentUnionAttr>())
if (const CompoundLiteralExpr *CLE = dyn_cast<CompoundLiteralExpr>(this)){
const Expr *InitExpr = CLE->getInitializer();
if (const InitListExpr *ILE = dyn_cast<InitListExpr>(InitExpr))
@@ -3089,14 +3134,19 @@ Expr::isNullPointerConstant(ASTContext &Ctx,
(Ctx.getLangOpts().CPlusPlus && getType()->isEnumeralType()))
return NPCK_NotNull;
- // If we have an integer constant expression, we need to *evaluate* it and
- // test for the value 0. Don't use the C++11 constant expression semantics
- // for this, for now; once the dust settles on core issue 903, we might only
- // allow a literal 0 here in C++11 mode.
if (Ctx.getLangOpts().CPlusPlus11) {
- if (!isCXX98IntegralConstantExpr(Ctx))
+ // C++11 [conv.ptr]p1: A null pointer constant is an integer literal with
+ // value zero or a prvalue of type std::nullptr_t.
+ // Microsoft mode permits C++98 rules reflecting MSVC behavior.
+ const IntegerLiteral *Lit = dyn_cast<IntegerLiteral>(this);
+ if (Lit && !Lit->getValue())
+ return NPCK_ZeroLiteral;
+ else if (!Ctx.getLangOpts().MicrosoftMode ||
+ !isCXX98IntegralConstantExpr(Ctx))
return NPCK_NotNull;
} else {
+ // If we have an integer constant expression, we need to *evaluate* it and
+ // test for the value 0.
if (!isIntegerConstantExpr(Ctx))
return NPCK_NotNull;
}
@@ -3370,7 +3420,7 @@ void ObjCMessageExpr::initArgsAndSelLocs(ArrayRef<Expr *> Args,
}
}
-ObjCMessageExpr *ObjCMessageExpr::Create(ASTContext &Context, QualType T,
+ObjCMessageExpr *ObjCMessageExpr::Create(const ASTContext &Context, QualType T,
ExprValueKind VK,
SourceLocation LBracLoc,
SourceLocation SuperLoc,
@@ -3395,7 +3445,7 @@ ObjCMessageExpr *ObjCMessageExpr::Create(ASTContext &Context, QualType T,
Method, Args, RBracLoc, isImplicit);
}
-ObjCMessageExpr *ObjCMessageExpr::Create(ASTContext &Context, QualType T,
+ObjCMessageExpr *ObjCMessageExpr::Create(const ASTContext &Context, QualType T,
ExprValueKind VK,
SourceLocation LBracLoc,
TypeSourceInfo *Receiver,
@@ -3418,7 +3468,7 @@ ObjCMessageExpr *ObjCMessageExpr::Create(ASTContext &Context, QualType T,
isImplicit);
}
-ObjCMessageExpr *ObjCMessageExpr::Create(ASTContext &Context, QualType T,
+ObjCMessageExpr *ObjCMessageExpr::Create(const ASTContext &Context, QualType T,
ExprValueKind VK,
SourceLocation LBracLoc,
Expr *Receiver,
@@ -3441,14 +3491,14 @@ ObjCMessageExpr *ObjCMessageExpr::Create(ASTContext &Context, QualType T,
isImplicit);
}
-ObjCMessageExpr *ObjCMessageExpr::CreateEmpty(ASTContext &Context,
+ObjCMessageExpr *ObjCMessageExpr::CreateEmpty(const ASTContext &Context,
unsigned NumArgs,
unsigned NumStoredSelLocs) {
ObjCMessageExpr *Mem = alloc(Context, NumArgs, NumStoredSelLocs);
return new (Mem) ObjCMessageExpr(EmptyShell(), NumArgs);
}
-ObjCMessageExpr *ObjCMessageExpr::alloc(ASTContext &C,
+ObjCMessageExpr *ObjCMessageExpr::alloc(const ASTContext &C,
ArrayRef<Expr *> Args,
SourceLocation RBraceLoc,
ArrayRef<SourceLocation> SelLocs,
@@ -3460,7 +3510,7 @@ ObjCMessageExpr *ObjCMessageExpr::alloc(ASTContext &C,
return alloc(C, Args.size(), NumStoredSelLocs);
}
-ObjCMessageExpr *ObjCMessageExpr::alloc(ASTContext &C,
+ObjCMessageExpr *ObjCMessageExpr::alloc(const ASTContext &C,
unsigned NumArgs,
unsigned NumStoredSelLocs) {
unsigned Size = sizeof(ObjCMessageExpr) + sizeof(void *) +
@@ -3537,11 +3587,7 @@ StringRef ObjCBridgedCastExpr::getBridgeKindName() const {
llvm_unreachable("Invalid BridgeKind!");
}
-bool ChooseExpr::isConditionTrue(const ASTContext &C) const {
- return getCond()->EvaluateKnownConstInt(C) != 0;
-}
-
-ShuffleVectorExpr::ShuffleVectorExpr(ASTContext &C, ArrayRef<Expr*> args,
+ShuffleVectorExpr::ShuffleVectorExpr(const ASTContext &C, ArrayRef<Expr*> args,
QualType Type, SourceLocation BLoc,
SourceLocation RP)
: Expr(ShuffleVectorExprClass, Type, VK_RValue, OK_Ordinary,
@@ -3565,16 +3611,15 @@ ShuffleVectorExpr::ShuffleVectorExpr(ASTContext &C, ArrayRef<Expr*> args,
}
}
-void ShuffleVectorExpr::setExprs(ASTContext &C, Expr ** Exprs,
- unsigned NumExprs) {
+void ShuffleVectorExpr::setExprs(const ASTContext &C, ArrayRef<Expr *> Exprs) {
if (SubExprs) C.Deallocate(SubExprs);
- SubExprs = new (C) Stmt* [NumExprs];
- this->NumExprs = NumExprs;
- memcpy(SubExprs, Exprs, sizeof(Expr *) * NumExprs);
+ this->NumExprs = Exprs.size();
+ SubExprs = new (C) Stmt*[NumExprs];
+ memcpy(SubExprs, Exprs.data(), sizeof(Expr *) * Exprs.size());
}
-GenericSelectionExpr::GenericSelectionExpr(ASTContext &Context,
+GenericSelectionExpr::GenericSelectionExpr(const ASTContext &Context,
SourceLocation GenericLoc, Expr *ControllingExpr,
ArrayRef<TypeSourceInfo*> AssocTypes,
ArrayRef<Expr*> AssocExprs,
@@ -3600,7 +3645,7 @@ GenericSelectionExpr::GenericSelectionExpr(ASTContext &Context,
std::copy(AssocExprs.begin(), AssocExprs.end(), SubExprs+END_EXPR);
}
-GenericSelectionExpr::GenericSelectionExpr(ASTContext &Context,
+GenericSelectionExpr::GenericSelectionExpr(const ASTContext &Context,
SourceLocation GenericLoc, Expr *ControllingExpr,
ArrayRef<TypeSourceInfo*> AssocTypes,
ArrayRef<Expr*> AssocExprs,
@@ -3637,7 +3682,7 @@ IdentifierInfo *DesignatedInitExpr::Designator::getFieldName() const {
return getField()->getIdentifier();
}
-DesignatedInitExpr::DesignatedInitExpr(ASTContext &C, QualType Ty,
+DesignatedInitExpr::DesignatedInitExpr(const ASTContext &C, QualType Ty,
unsigned NumDesignators,
const Designator *Designators,
SourceLocation EqualOrColonLoc,
@@ -3704,7 +3749,7 @@ DesignatedInitExpr::DesignatedInitExpr(ASTContext &C, QualType Ty,
}
DesignatedInitExpr *
-DesignatedInitExpr::Create(ASTContext &C, Designator *Designators,
+DesignatedInitExpr::Create(const ASTContext &C, Designator *Designators,
unsigned NumDesignators,
ArrayRef<Expr*> IndexExprs,
SourceLocation ColonOrEqualLoc,
@@ -3716,14 +3761,14 @@ DesignatedInitExpr::Create(ASTContext &C, Designator *Designators,
IndexExprs, Init);
}
-DesignatedInitExpr *DesignatedInitExpr::CreateEmpty(ASTContext &C,
+DesignatedInitExpr *DesignatedInitExpr::CreateEmpty(const ASTContext &C,
unsigned NumIndexExprs) {
void *Mem = C.Allocate(sizeof(DesignatedInitExpr) +
sizeof(Stmt *) * (NumIndexExprs + 1), 8);
return new (Mem) DesignatedInitExpr(NumIndexExprs + 1);
}
-void DesignatedInitExpr::setDesignators(ASTContext &C,
+void DesignatedInitExpr::setDesignators(const ASTContext &C,
const Designator *Desigs,
unsigned NumDesigs) {
Designators = new (C) Designator[NumDesigs];
@@ -3790,7 +3835,7 @@ Expr *DesignatedInitExpr::getArrayRangeEnd(const Designator &D) const {
/// \brief Replaces the designator at index @p Idx with the series
/// of designators in [First, Last).
-void DesignatedInitExpr::ExpandDesignator(ASTContext &C, unsigned Idx,
+void DesignatedInitExpr::ExpandDesignator(const ASTContext &C, unsigned Idx,
const Designator *First,
const Designator *Last) {
unsigned NumNewDesignators = Last - First;
@@ -3815,7 +3860,7 @@ void DesignatedInitExpr::ExpandDesignator(ASTContext &C, unsigned Idx,
NumDesignators = NumDesignators - 1 + NumNewDesignators;
}
-ParenListExpr::ParenListExpr(ASTContext& C, SourceLocation lparenloc,
+ParenListExpr::ParenListExpr(const ASTContext& C, SourceLocation lparenloc,
ArrayRef<Expr*> exprs,
SourceLocation rparenloc)
: Expr(ParenListExprClass, QualType(), VK_RValue, OK_Ordinary,
@@ -3847,7 +3892,8 @@ const OpaqueValueExpr *OpaqueValueExpr::findInCopyConstruct(const Expr *e) {
return cast<OpaqueValueExpr>(e);
}
-PseudoObjectExpr *PseudoObjectExpr::Create(ASTContext &Context, EmptyShell sh,
+PseudoObjectExpr *PseudoObjectExpr::Create(const ASTContext &Context,
+ EmptyShell sh,
unsigned numSemanticExprs) {
void *buffer = Context.Allocate(sizeof(PseudoObjectExpr) +
(1 + numSemanticExprs) * sizeof(Expr*),
@@ -3860,7 +3906,7 @@ PseudoObjectExpr::PseudoObjectExpr(EmptyShell shell, unsigned numSemanticExprs)
PseudoObjectExprBits.NumSubExprs = numSemanticExprs + 1;
}
-PseudoObjectExpr *PseudoObjectExpr::Create(ASTContext &C, Expr *syntax,
+PseudoObjectExpr *PseudoObjectExpr::Create(const ASTContext &C, Expr *syntax,
ArrayRef<Expr*> semantics,
unsigned resultIndex) {
assert(syntax && "no syntactic expression!");
@@ -3975,7 +4021,7 @@ ObjCArrayLiteral::ObjCArrayLiteral(ArrayRef<Expr *> Elements,
}
}
-ObjCArrayLiteral *ObjCArrayLiteral::Create(ASTContext &C,
+ObjCArrayLiteral *ObjCArrayLiteral::Create(const ASTContext &C,
ArrayRef<Expr *> Elements,
QualType T, ObjCMethodDecl * Method,
SourceRange SR) {
@@ -3984,7 +4030,7 @@ ObjCArrayLiteral *ObjCArrayLiteral::Create(ASTContext &C,
return new (Mem) ObjCArrayLiteral(Elements, T, Method, SR);
}
-ObjCArrayLiteral *ObjCArrayLiteral::CreateEmpty(ASTContext &C,
+ObjCArrayLiteral *ObjCArrayLiteral::CreateEmpty(const ASTContext &C,
unsigned NumElements) {
void *Mem = C.Allocate(sizeof(ObjCArrayLiteral)
@@ -4029,7 +4075,7 @@ ObjCDictionaryLiteral::ObjCDictionaryLiteral(
}
ObjCDictionaryLiteral *
-ObjCDictionaryLiteral::Create(ASTContext &C,
+ObjCDictionaryLiteral::Create(const ASTContext &C,
ArrayRef<ObjCDictionaryElement> VK,
bool HasPackExpansions,
QualType T, ObjCMethodDecl *method,
@@ -4044,7 +4090,7 @@ ObjCDictionaryLiteral::Create(ASTContext &C,
}
ObjCDictionaryLiteral *
-ObjCDictionaryLiteral::CreateEmpty(ASTContext &C, unsigned NumElements,
+ObjCDictionaryLiteral::CreateEmpty(const ASTContext &C, unsigned NumElements,
bool HasPackExpansions) {
unsigned ExpansionsSize = 0;
if (HasPackExpansions)
@@ -4055,7 +4101,7 @@ ObjCDictionaryLiteral::CreateEmpty(ASTContext &C, unsigned NumElements,
HasPackExpansions);
}
-ObjCSubscriptRefExpr *ObjCSubscriptRefExpr::Create(ASTContext &C,
+ObjCSubscriptRefExpr *ObjCSubscriptRefExpr::Create(const ASTContext &C,
Expr *base,
Expr *key, QualType T,
ObjCMethodDecl *getMethod,
diff --git a/lib/AST/ExprCXX.cpp b/lib/AST/ExprCXX.cpp
index 402d7b532b21..3738c0e4f2c9 100644
--- a/lib/AST/ExprCXX.cpp
+++ b/lib/AST/ExprCXX.cpp
@@ -40,46 +40,106 @@ bool CXXTypeidExpr::isPotentiallyEvaluated() const {
return false;
}
-QualType CXXTypeidExpr::getTypeOperand() const {
+QualType CXXTypeidExpr::getTypeOperand(ASTContext &Context) const {
assert(isTypeOperand() && "Cannot call getTypeOperand for typeid(expr)");
- return Operand.get<TypeSourceInfo *>()->getType().getNonReferenceType()
- .getUnqualifiedType();
+ Qualifiers Quals;
+ return Context.getUnqualifiedArrayType(
+ Operand.get<TypeSourceInfo *>()->getType().getNonReferenceType(), Quals);
}
-QualType CXXUuidofExpr::getTypeOperand() const {
+QualType CXXUuidofExpr::getTypeOperand(ASTContext &Context) const {
assert(isTypeOperand() && "Cannot call getTypeOperand for __uuidof(expr)");
- return Operand.get<TypeSourceInfo *>()->getType().getNonReferenceType()
- .getUnqualifiedType();
+ Qualifiers Quals;
+ return Context.getUnqualifiedArrayType(
+ Operand.get<TypeSourceInfo *>()->getType().getNonReferenceType(), Quals);
}
// static
-UuidAttr *CXXUuidofExpr::GetUuidAttrOfType(QualType QT) {
+UuidAttr *CXXUuidofExpr::GetUuidAttrOfType(QualType QT,
+ bool *RDHasMultipleGUIDsPtr) {
// Optionally remove one level of pointer, reference or array indirection.
const Type *Ty = QT.getTypePtr();
if (QT->isPointerType() || QT->isReferenceType())
Ty = QT->getPointeeType().getTypePtr();
else if (QT->isArrayType())
- Ty = cast<ArrayType>(QT)->getElementType().getTypePtr();
+ Ty = Ty->getBaseElementTypeUnsafe();
// Loop all record redeclaration looking for an uuid attribute.
CXXRecordDecl *RD = Ty->getAsCXXRecordDecl();
+ if (!RD)
+ return 0;
+
+ // __uuidof can grab UUIDs from template arguments.
+ if (ClassTemplateSpecializationDecl *CTSD =
+ dyn_cast<ClassTemplateSpecializationDecl>(RD)) {
+ const TemplateArgumentList &TAL = CTSD->getTemplateArgs();
+ UuidAttr *UuidForRD = 0;
+
+ for (unsigned I = 0, N = TAL.size(); I != N; ++I) {
+ const TemplateArgument &TA = TAL[I];
+ bool SeenMultipleGUIDs = false;
+
+ UuidAttr *UuidForTA = 0;
+ if (TA.getKind() == TemplateArgument::Type)
+ UuidForTA = GetUuidAttrOfType(TA.getAsType(), &SeenMultipleGUIDs);
+ else if (TA.getKind() == TemplateArgument::Declaration)
+ UuidForTA =
+ GetUuidAttrOfType(TA.getAsDecl()->getType(), &SeenMultipleGUIDs);
+
+ // If the template argument has a UUID, there are three cases:
+ // - This is the first UUID seen for this RecordDecl.
+ // - This is a different UUID than previously seen for this RecordDecl.
+ // - This is the same UUID than previously seen for this RecordDecl.
+ if (UuidForTA) {
+ if (!UuidForRD)
+ UuidForRD = UuidForTA;
+ else if (UuidForRD != UuidForTA)
+ SeenMultipleGUIDs = true;
+ }
+
+ // Seeing multiple UUIDs means that we couldn't find a UUID
+ if (SeenMultipleGUIDs) {
+ if (RDHasMultipleGUIDsPtr)
+ *RDHasMultipleGUIDsPtr = true;
+ return 0;
+ }
+ }
+
+ return UuidForRD;
+ }
+
for (CXXRecordDecl::redecl_iterator I = RD->redecls_begin(),
- E = RD->redecls_end(); I != E; ++I) {
+ E = RD->redecls_end();
+ I != E; ++I)
if (UuidAttr *Uuid = I->getAttr<UuidAttr>())
return Uuid;
- }
return 0;
}
+StringRef CXXUuidofExpr::getUuidAsStringRef(ASTContext &Context) const {
+ StringRef Uuid;
+ if (isTypeOperand())
+ Uuid = CXXUuidofExpr::GetUuidAttrOfType(getTypeOperand(Context))->getGuid();
+ else {
+ // Special case: __uuidof(0) means an all-zero GUID.
+ Expr *Op = getExprOperand();
+ if (!Op->isNullPointerConstant(Context, Expr::NPC_ValueDependentIsNull))
+ Uuid = CXXUuidofExpr::GetUuidAttrOfType(Op->getType())->getGuid();
+ else
+ Uuid = "00000000-0000-0000-0000-000000000000";
+ }
+ return Uuid;
+}
+
// CXXScalarValueInitExpr
SourceLocation CXXScalarValueInitExpr::getLocStart() const {
return TypeInfo ? TypeInfo->getTypeLoc().getBeginLoc() : RParenLoc;
}
// CXXNewExpr
-CXXNewExpr::CXXNewExpr(ASTContext &C, bool globalNew, FunctionDecl *operatorNew,
- FunctionDecl *operatorDelete,
+CXXNewExpr::CXXNewExpr(const ASTContext &C, bool globalNew,
+ FunctionDecl *operatorNew, FunctionDecl *operatorDelete,
bool usualArrayDeleteWantsSize,
ArrayRef<Expr*> placementArgs,
SourceRange typeIdParens, Expr *arraySize,
@@ -134,11 +194,14 @@ CXXNewExpr::CXXNewExpr(ASTContext &C, bool globalNew, FunctionDecl *operatorNew,
this->Range.setEnd(DirectInitRange.getEnd()); break;
case ListInit:
this->Range.setEnd(getInitializer()->getSourceRange().getEnd()); break;
- default: break;
+ default:
+ if (TypeIdParens.isValid())
+ this->Range.setEnd(TypeIdParens.getEnd());
+ break;
}
}
-void CXXNewExpr::AllocateArgsArray(ASTContext &C, bool isArray,
+void CXXNewExpr::AllocateArgsArray(const ASTContext &C, bool isArray,
unsigned numPlaceArgs, bool hasInitializer){
assert(SubExprs == 0 && "SubExprs already allocated");
Array = isArray;
@@ -148,7 +211,7 @@ void CXXNewExpr::AllocateArgsArray(ASTContext &C, bool isArray,
SubExprs = new (C) Stmt*[TotalSize];
}
-bool CXXNewExpr::shouldNullCheckAllocation(ASTContext &Ctx) const {
+bool CXXNewExpr::shouldNullCheckAllocation(const ASTContext &Ctx) const {
return getOperatorNew()->getType()->
castAs<FunctionProtoType>()->isNothrow(Ctx);
}
@@ -172,14 +235,16 @@ PseudoDestructorTypeStorage::PseudoDestructorTypeStorage(TypeSourceInfo *Info)
Location = Info->getTypeLoc().getLocalSourceRange().getBegin();
}
-CXXPseudoDestructorExpr::CXXPseudoDestructorExpr(ASTContext &Context,
+CXXPseudoDestructorExpr::CXXPseudoDestructorExpr(const ASTContext &Context,
Expr *Base, bool isArrow, SourceLocation OperatorLoc,
NestedNameSpecifierLoc QualifierLoc, TypeSourceInfo *ScopeType,
SourceLocation ColonColonLoc, SourceLocation TildeLoc,
PseudoDestructorTypeStorage DestroyedType)
: Expr(CXXPseudoDestructorExprClass,
- Context.getPointerType(Context.getFunctionType(Context.VoidTy, None,
- FunctionProtoType::ExtProtoInfo())),
+ Context.getPointerType(Context.getFunctionType(
+ Context.VoidTy, None,
+ FunctionProtoType::ExtProtoInfo(
+ Context.getDefaultCallingConvention(false, true)))),
VK_RValue, OK_Ordinary,
/*isTypeDependent=*/(Base->isTypeDependent() ||
(DestroyedType.getTypeSourceInfo() &&
@@ -224,7 +289,7 @@ SourceLocation CXXPseudoDestructorExpr::getLocEnd() const {
// UnresolvedLookupExpr
UnresolvedLookupExpr *
-UnresolvedLookupExpr::Create(ASTContext &C,
+UnresolvedLookupExpr::Create(const ASTContext &C,
CXXRecordDecl *NamingClass,
NestedNameSpecifierLoc QualifierLoc,
SourceLocation TemplateKWLoc,
@@ -245,7 +310,7 @@ UnresolvedLookupExpr::Create(ASTContext &C,
}
UnresolvedLookupExpr *
-UnresolvedLookupExpr::CreateEmpty(ASTContext &C,
+UnresolvedLookupExpr::CreateEmpty(const ASTContext &C,
bool HasTemplateKWAndArgsInfo,
unsigned NumTemplateArgs) {
std::size_t size = sizeof(UnresolvedLookupExpr);
@@ -258,7 +323,7 @@ UnresolvedLookupExpr::CreateEmpty(ASTContext &C,
return E;
}
-OverloadExpr::OverloadExpr(StmtClass K, ASTContext &C,
+OverloadExpr::OverloadExpr(StmtClass K, const ASTContext &C,
NestedNameSpecifierLoc QualifierLoc,
SourceLocation TemplateKWLoc,
const DeclarationNameInfo &NameInfo,
@@ -330,7 +395,7 @@ OverloadExpr::OverloadExpr(StmtClass K, ASTContext &C,
setType(C.DependentTy);
}
-void OverloadExpr::initializeResults(ASTContext &C,
+void OverloadExpr::initializeResults(const ASTContext &C,
UnresolvedSetIterator Begin,
UnresolvedSetIterator End) {
assert(Results == 0 && "Results already initialized!");
@@ -386,11 +451,12 @@ DependentScopeDeclRefExpr::DependentScopeDeclRefExpr(QualType T,
}
DependentScopeDeclRefExpr *
-DependentScopeDeclRefExpr::Create(ASTContext &C,
+DependentScopeDeclRefExpr::Create(const ASTContext &C,
NestedNameSpecifierLoc QualifierLoc,
SourceLocation TemplateKWLoc,
const DeclarationNameInfo &NameInfo,
const TemplateArgumentListInfo *Args) {
+ assert(QualifierLoc && "should be created for dependent qualifiers");
std::size_t size = sizeof(DependentScopeDeclRefExpr);
if (Args)
size += ASTTemplateKWAndArgsInfo::sizeFor(Args->size());
@@ -402,7 +468,7 @@ DependentScopeDeclRefExpr::Create(ASTContext &C,
}
DependentScopeDeclRefExpr *
-DependentScopeDeclRefExpr::CreateEmpty(ASTContext &C,
+DependentScopeDeclRefExpr::CreateEmpty(const ASTContext &C,
bool HasTemplateKWAndArgsInfo,
unsigned NumTemplateArgs) {
std::size_t size = sizeof(DependentScopeDeclRefExpr);
@@ -427,8 +493,8 @@ SourceLocation CXXConstructExpr::getLocEnd() const {
if (isa<CXXTemporaryObjectExpr>(this))
return cast<CXXTemporaryObjectExpr>(this)->getLocEnd();
- if (ParenRange.isValid())
- return ParenRange.getEnd();
+ if (ParenOrBraceRange.isValid())
+ return ParenOrBraceRange.getEnd();
SourceLocation End = Loc;
for (unsigned I = getNumArgs(); I > 0; --I) {
@@ -520,7 +586,7 @@ const char *CXXNamedCastExpr::getCastName() const {
}
}
-CXXStaticCastExpr *CXXStaticCastExpr::Create(ASTContext &C, QualType T,
+CXXStaticCastExpr *CXXStaticCastExpr::Create(const ASTContext &C, QualType T,
ExprValueKind VK,
CastKind K, Expr *Op,
const CXXCastPath *BasePath,
@@ -538,14 +604,14 @@ CXXStaticCastExpr *CXXStaticCastExpr::Create(ASTContext &C, QualType T,
return E;
}
-CXXStaticCastExpr *CXXStaticCastExpr::CreateEmpty(ASTContext &C,
+CXXStaticCastExpr *CXXStaticCastExpr::CreateEmpty(const ASTContext &C,
unsigned PathSize) {
void *Buffer =
C.Allocate(sizeof(CXXStaticCastExpr) + PathSize * sizeof(CXXBaseSpecifier*));
return new (Buffer) CXXStaticCastExpr(EmptyShell(), PathSize);
}
-CXXDynamicCastExpr *CXXDynamicCastExpr::Create(ASTContext &C, QualType T,
+CXXDynamicCastExpr *CXXDynamicCastExpr::Create(const ASTContext &C, QualType T,
ExprValueKind VK,
CastKind K, Expr *Op,
const CXXCastPath *BasePath,
@@ -563,7 +629,7 @@ CXXDynamicCastExpr *CXXDynamicCastExpr::Create(ASTContext &C, QualType T,
return E;
}
-CXXDynamicCastExpr *CXXDynamicCastExpr::CreateEmpty(ASTContext &C,
+CXXDynamicCastExpr *CXXDynamicCastExpr::CreateEmpty(const ASTContext &C,
unsigned PathSize) {
void *Buffer =
C.Allocate(sizeof(CXXDynamicCastExpr) + PathSize * sizeof(CXXBaseSpecifier*));
@@ -604,8 +670,8 @@ bool CXXDynamicCastExpr::isAlwaysNull() const
}
CXXReinterpretCastExpr *
-CXXReinterpretCastExpr::Create(ASTContext &C, QualType T, ExprValueKind VK,
- CastKind K, Expr *Op,
+CXXReinterpretCastExpr::Create(const ASTContext &C, QualType T,
+ ExprValueKind VK, CastKind K, Expr *Op,
const CXXCastPath *BasePath,
TypeSourceInfo *WrittenTy, SourceLocation L,
SourceLocation RParenLoc,
@@ -621,13 +687,13 @@ CXXReinterpretCastExpr::Create(ASTContext &C, QualType T, ExprValueKind VK,
}
CXXReinterpretCastExpr *
-CXXReinterpretCastExpr::CreateEmpty(ASTContext &C, unsigned PathSize) {
+CXXReinterpretCastExpr::CreateEmpty(const ASTContext &C, unsigned PathSize) {
void *Buffer = C.Allocate(sizeof(CXXReinterpretCastExpr)
+ PathSize * sizeof(CXXBaseSpecifier*));
return new (Buffer) CXXReinterpretCastExpr(EmptyShell(), PathSize);
}
-CXXConstCastExpr *CXXConstCastExpr::Create(ASTContext &C, QualType T,
+CXXConstCastExpr *CXXConstCastExpr::Create(const ASTContext &C, QualType T,
ExprValueKind VK, Expr *Op,
TypeSourceInfo *WrittenTy,
SourceLocation L,
@@ -636,31 +702,39 @@ CXXConstCastExpr *CXXConstCastExpr::Create(ASTContext &C, QualType T,
return new (C) CXXConstCastExpr(T, VK, Op, WrittenTy, L, RParenLoc, AngleBrackets);
}
-CXXConstCastExpr *CXXConstCastExpr::CreateEmpty(ASTContext &C) {
+CXXConstCastExpr *CXXConstCastExpr::CreateEmpty(const ASTContext &C) {
return new (C) CXXConstCastExpr(EmptyShell());
}
CXXFunctionalCastExpr *
-CXXFunctionalCastExpr::Create(ASTContext &C, QualType T, ExprValueKind VK,
- TypeSourceInfo *Written, SourceLocation L,
- CastKind K, Expr *Op, const CXXCastPath *BasePath,
- SourceLocation R) {
+CXXFunctionalCastExpr::Create(const ASTContext &C, QualType T, ExprValueKind VK,
+ TypeSourceInfo *Written, CastKind K, Expr *Op,
+ const CXXCastPath *BasePath,
+ SourceLocation L, SourceLocation R) {
unsigned PathSize = (BasePath ? BasePath->size() : 0);
void *Buffer = C.Allocate(sizeof(CXXFunctionalCastExpr)
+ PathSize * sizeof(CXXBaseSpecifier*));
CXXFunctionalCastExpr *E =
- new (Buffer) CXXFunctionalCastExpr(T, VK, Written, L, K, Op, PathSize, R);
+ new (Buffer) CXXFunctionalCastExpr(T, VK, Written, K, Op, PathSize, L, R);
if (PathSize) E->setCastPath(*BasePath);
return E;
}
CXXFunctionalCastExpr *
-CXXFunctionalCastExpr::CreateEmpty(ASTContext &C, unsigned PathSize) {
+CXXFunctionalCastExpr::CreateEmpty(const ASTContext &C, unsigned PathSize) {
void *Buffer = C.Allocate(sizeof(CXXFunctionalCastExpr)
+ PathSize * sizeof(CXXBaseSpecifier*));
return new (Buffer) CXXFunctionalCastExpr(EmptyShell(), PathSize);
}
+SourceLocation CXXFunctionalCastExpr::getLocStart() const {
+ return getTypeInfoAsWritten()->getTypeLoc().getLocStart();
+}
+
+SourceLocation CXXFunctionalCastExpr::getLocEnd() const {
+ return RParenLoc.isValid() ? RParenLoc : getSubExpr()->getLocEnd();
+}
+
UserDefinedLiteral::LiteralOperatorKind
UserDefinedLiteral::getLiteralOperatorKind() const {
if (getNumArgs() == 0)
@@ -696,14 +770,14 @@ const IdentifierInfo *UserDefinedLiteral::getUDSuffix() const {
}
CXXDefaultArgExpr *
-CXXDefaultArgExpr::Create(ASTContext &C, SourceLocation Loc,
+CXXDefaultArgExpr::Create(const ASTContext &C, SourceLocation Loc,
ParmVarDecl *Param, Expr *SubExpr) {
void *Mem = C.Allocate(sizeof(CXXDefaultArgExpr) + sizeof(Stmt *));
return new (Mem) CXXDefaultArgExpr(CXXDefaultArgExprClass, Loc, Param,
SubExpr);
}
-CXXDefaultInitExpr::CXXDefaultInitExpr(ASTContext &C, SourceLocation Loc,
+CXXDefaultInitExpr::CXXDefaultInitExpr(const ASTContext &C, SourceLocation Loc,
FieldDecl *Field, QualType T)
: Expr(CXXDefaultInitExprClass, T.getNonLValueExprType(C),
T->isLValueReferenceType() ? VK_LValue : T->isRValueReferenceType()
@@ -714,12 +788,12 @@ CXXDefaultInitExpr::CXXDefaultInitExpr(ASTContext &C, SourceLocation Loc,
assert(Field->hasInClassInitializer());
}
-CXXTemporary *CXXTemporary::Create(ASTContext &C,
+CXXTemporary *CXXTemporary::Create(const ASTContext &C,
const CXXDestructorDecl *Destructor) {
return new (C) CXXTemporary(Destructor);
}
-CXXBindTemporaryExpr *CXXBindTemporaryExpr::Create(ASTContext &C,
+CXXBindTemporaryExpr *CXXBindTemporaryExpr::Create(const ASTContext &C,
CXXTemporary *Temp,
Expr* SubExpr) {
assert((SubExpr->getType()->isRecordType() ||
@@ -729,11 +803,11 @@ CXXBindTemporaryExpr *CXXBindTemporaryExpr::Create(ASTContext &C,
return new (C) CXXBindTemporaryExpr(Temp, SubExpr);
}
-CXXTemporaryObjectExpr::CXXTemporaryObjectExpr(ASTContext &C,
+CXXTemporaryObjectExpr::CXXTemporaryObjectExpr(const ASTContext &C,
CXXConstructorDecl *Cons,
TypeSourceInfo *Type,
ArrayRef<Expr*> Args,
- SourceRange parenRange,
+ SourceRange ParenOrBraceRange,
bool HadMultipleCandidates,
bool ListInitialization,
bool ZeroInitialization)
@@ -743,7 +817,7 @@ CXXTemporaryObjectExpr::CXXTemporaryObjectExpr(ASTContext &C,
Cons, false, Args,
HadMultipleCandidates,
ListInitialization, ZeroInitialization,
- CXXConstructExpr::CK_Complete, parenRange),
+ CXXConstructExpr::CK_Complete, ParenOrBraceRange),
Type(Type) {
}
@@ -752,10 +826,13 @@ SourceLocation CXXTemporaryObjectExpr::getLocStart() const {
}
SourceLocation CXXTemporaryObjectExpr::getLocEnd() const {
- return getParenRange().getEnd();
+ SourceLocation Loc = getParenOrBraceRange().getEnd();
+ if (Loc.isInvalid() && getNumArgs())
+ Loc = getArg(getNumArgs()-1)->getLocEnd();
+ return Loc;
}
-CXXConstructExpr *CXXConstructExpr::Create(ASTContext &C, QualType T,
+CXXConstructExpr *CXXConstructExpr::Create(const ASTContext &C, QualType T,
SourceLocation Loc,
CXXConstructorDecl *D, bool Elidable,
ArrayRef<Expr*> Args,
@@ -763,28 +840,29 @@ CXXConstructExpr *CXXConstructExpr::Create(ASTContext &C, QualType T,
bool ListInitialization,
bool ZeroInitialization,
ConstructionKind ConstructKind,
- SourceRange ParenRange) {
+ SourceRange ParenOrBraceRange) {
return new (C) CXXConstructExpr(C, CXXConstructExprClass, T, Loc, D,
Elidable, Args,
HadMultipleCandidates, ListInitialization,
ZeroInitialization, ConstructKind,
- ParenRange);
+ ParenOrBraceRange);
}
-CXXConstructExpr::CXXConstructExpr(ASTContext &C, StmtClass SC, QualType T,
- SourceLocation Loc,
+CXXConstructExpr::CXXConstructExpr(const ASTContext &C, StmtClass SC,
+ QualType T, SourceLocation Loc,
CXXConstructorDecl *D, bool elidable,
ArrayRef<Expr*> args,
bool HadMultipleCandidates,
bool ListInitialization,
bool ZeroInitialization,
ConstructionKind ConstructKind,
- SourceRange ParenRange)
+ SourceRange ParenOrBraceRange)
: Expr(SC, T, VK_RValue, OK_Ordinary,
T->isDependentType(), T->isDependentType(),
T->isInstantiationDependentType(),
T->containsUnexpandedParameterPack()),
- Constructor(D), Loc(Loc), ParenRange(ParenRange), NumArgs(args.size()),
+ Constructor(D), Loc(Loc), ParenOrBraceRange(ParenOrBraceRange),
+ NumArgs(args.size()),
Elidable(elidable), HadMultipleCandidates(HadMultipleCandidates),
ListInitialization(ListInitialization),
ZeroInitialization(ZeroInitialization),
@@ -811,7 +889,7 @@ CXXConstructExpr::CXXConstructExpr(ASTContext &C, StmtClass SC, QualType T,
LambdaExpr::Capture::Capture(SourceLocation Loc, bool Implicit,
LambdaCaptureKind Kind, VarDecl *Var,
SourceLocation EllipsisLoc)
- : VarAndBits(Var, 0), Loc(Loc), EllipsisLoc(EllipsisLoc)
+ : DeclAndBits(Var, 0), Loc(Loc), EllipsisLoc(EllipsisLoc)
{
unsigned Bits = 0;
if (Implicit)
@@ -829,20 +907,22 @@ LambdaExpr::Capture::Capture(SourceLocation Loc, bool Implicit,
assert(Var && "capture must have a variable!");
break;
}
- VarAndBits.setInt(Bits);
+ DeclAndBits.setInt(Bits);
}
LambdaCaptureKind LambdaExpr::Capture::getCaptureKind() const {
- if (capturesThis())
+ Decl *D = DeclAndBits.getPointer();
+ if (!D)
return LCK_This;
- return (VarAndBits.getInt() & Capture_ByCopy)? LCK_ByCopy : LCK_ByRef;
+ return (DeclAndBits.getInt() & Capture_ByCopy) ? LCK_ByCopy : LCK_ByRef;
}
-LambdaExpr::LambdaExpr(QualType T,
+LambdaExpr::LambdaExpr(QualType T,
SourceRange IntroducerRange,
LambdaCaptureDefault CaptureDefault,
- ArrayRef<Capture> Captures,
+ SourceLocation CaptureDefaultLoc,
+ ArrayRef<Capture> Captures,
bool ExplicitParams,
bool ExplicitResultType,
ArrayRef<Expr *> CaptureInits,
@@ -854,6 +934,7 @@ LambdaExpr::LambdaExpr(QualType T,
T->isDependentType(), T->isDependentType(), T->isDependentType(),
ContainsUnexpandedParameterPack),
IntroducerRange(IntroducerRange),
+ CaptureDefaultLoc(CaptureDefaultLoc),
NumCaptures(Captures.size()),
CaptureDefault(CaptureDefault),
ExplicitParams(ExplicitParams),
@@ -867,7 +948,7 @@ LambdaExpr::LambdaExpr(QualType T,
// FIXME: Propagate "has unexpanded parameter pack" bit.
// Copy captures.
- ASTContext &Context = Class->getASTContext();
+ const ASTContext &Context = Class->getASTContext();
Data.NumCaptures = NumCaptures;
Data.NumExplicitCaptures = 0;
Data.Captures = (Capture *)Context.Allocate(sizeof(Capture) * NumCaptures);
@@ -899,11 +980,12 @@ LambdaExpr::LambdaExpr(QualType T,
}
}
-LambdaExpr *LambdaExpr::Create(ASTContext &Context,
+LambdaExpr *LambdaExpr::Create(const ASTContext &Context,
CXXRecordDecl *Class,
SourceRange IntroducerRange,
LambdaCaptureDefault CaptureDefault,
- ArrayRef<Capture> Captures,
+ SourceLocation CaptureDefaultLoc,
+ ArrayRef<Capture> Captures,
bool ExplicitParams,
bool ExplicitResultType,
ArrayRef<Expr *> CaptureInits,
@@ -923,13 +1005,15 @@ LambdaExpr *LambdaExpr::Create(ASTContext &Context,
Size += sizeof(VarDecl *) * ArrayIndexVars.size();
}
void *Mem = Context.Allocate(Size);
- return new (Mem) LambdaExpr(T, IntroducerRange, CaptureDefault,
- Captures, ExplicitParams, ExplicitResultType,
+ return new (Mem) LambdaExpr(T, IntroducerRange,
+ CaptureDefault, CaptureDefaultLoc, Captures,
+ ExplicitParams, ExplicitResultType,
CaptureInits, ArrayIndexVars, ArrayIndexStarts,
ClosingBrace, ContainsUnexpandedParameterPack);
}
-LambdaExpr *LambdaExpr::CreateDeserialized(ASTContext &C, unsigned NumCaptures,
+LambdaExpr *LambdaExpr::CreateDeserialized(const ASTContext &C,
+ unsigned NumCaptures,
unsigned NumArrayIndexVars) {
unsigned Size = sizeof(LambdaExpr) + sizeof(Stmt *) * (NumCaptures + 1);
if (NumArrayIndexVars)
@@ -984,13 +1068,13 @@ CXXRecordDecl *LambdaExpr::getLambdaClass() const {
CXXMethodDecl *LambdaExpr::getCallOperator() const {
CXXRecordDecl *Record = getLambdaClass();
- DeclarationName Name
- = Record->getASTContext().DeclarationNames.getCXXOperatorName(OO_Call);
- DeclContext::lookup_result Calls = Record->lookup(Name);
- assert(!Calls.empty() && "Missing lambda call operator!");
- assert(Calls.size() == 1 && "More than one lambda call operator!");
- CXXMethodDecl *Result = cast<CXXMethodDecl>(Calls.front());
- return Result;
+ return Record->getLambdaCallOperator();
+}
+
+TemplateParameterList *LambdaExpr::getTemplateParameterList() const {
+ CXXRecordDecl *Record = getLambdaClass();
+ return Record->getGenericLambdaTemplateParameterList();
+
}
CompoundStmt *LambdaExpr::getBody() const {
@@ -1017,7 +1101,7 @@ ExprWithCleanups::ExprWithCleanups(Expr *subexpr,
getObjectsBuffer()[i] = objects[i];
}
-ExprWithCleanups *ExprWithCleanups::Create(ASTContext &C, Expr *subexpr,
+ExprWithCleanups *ExprWithCleanups::Create(const ASTContext &C, Expr *subexpr,
ArrayRef<CleanupObject> objects) {
size_t size = sizeof(ExprWithCleanups)
+ objects.size() * sizeof(CleanupObject);
@@ -1030,7 +1114,8 @@ ExprWithCleanups::ExprWithCleanups(EmptyShell empty, unsigned numObjects)
ExprWithCleanupsBits.NumObjects = numObjects;
}
-ExprWithCleanups *ExprWithCleanups::Create(ASTContext &C, EmptyShell empty,
+ExprWithCleanups *ExprWithCleanups::Create(const ASTContext &C,
+ EmptyShell empty,
unsigned numObjects) {
size_t size = sizeof(ExprWithCleanups) + numObjects * sizeof(CleanupObject);
void *buffer = C.Allocate(size, llvm::alignOf<ExprWithCleanups>());
@@ -1063,7 +1148,7 @@ CXXUnresolvedConstructExpr::CXXUnresolvedConstructExpr(TypeSourceInfo *Type,
}
CXXUnresolvedConstructExpr *
-CXXUnresolvedConstructExpr::Create(ASTContext &C,
+CXXUnresolvedConstructExpr::Create(const ASTContext &C,
TypeSourceInfo *Type,
SourceLocation LParenLoc,
ArrayRef<Expr*> Args,
@@ -1074,7 +1159,7 @@ CXXUnresolvedConstructExpr::Create(ASTContext &C,
}
CXXUnresolvedConstructExpr *
-CXXUnresolvedConstructExpr::CreateEmpty(ASTContext &C, unsigned NumArgs) {
+CXXUnresolvedConstructExpr::CreateEmpty(const ASTContext &C, unsigned NumArgs) {
Stmt::EmptyShell Empty;
void *Mem = C.Allocate(sizeof(CXXUnresolvedConstructExpr) +
sizeof(Expr *) * NumArgs);
@@ -1085,7 +1170,7 @@ SourceLocation CXXUnresolvedConstructExpr::getLocStart() const {
return Type->getTypeLoc().getBeginLoc();
}
-CXXDependentScopeMemberExpr::CXXDependentScopeMemberExpr(ASTContext &C,
+CXXDependentScopeMemberExpr::CXXDependentScopeMemberExpr(const ASTContext &C,
Expr *Base, QualType BaseType,
bool IsArrow,
SourceLocation OperatorLoc,
@@ -1121,7 +1206,7 @@ CXXDependentScopeMemberExpr::CXXDependentScopeMemberExpr(ASTContext &C,
}
}
-CXXDependentScopeMemberExpr::CXXDependentScopeMemberExpr(ASTContext &C,
+CXXDependentScopeMemberExpr::CXXDependentScopeMemberExpr(const ASTContext &C,
Expr *Base, QualType BaseType,
bool IsArrow,
SourceLocation OperatorLoc,
@@ -1142,7 +1227,7 @@ CXXDependentScopeMemberExpr::CXXDependentScopeMemberExpr(ASTContext &C,
MemberNameInfo(MemberNameInfo) { }
CXXDependentScopeMemberExpr *
-CXXDependentScopeMemberExpr::Create(ASTContext &C,
+CXXDependentScopeMemberExpr::Create(const ASTContext &C,
Expr *Base, QualType BaseType, bool IsArrow,
SourceLocation OperatorLoc,
NestedNameSpecifierLoc QualifierLoc,
@@ -1171,7 +1256,7 @@ CXXDependentScopeMemberExpr::Create(ASTContext &C,
}
CXXDependentScopeMemberExpr *
-CXXDependentScopeMemberExpr::CreateEmpty(ASTContext &C,
+CXXDependentScopeMemberExpr::CreateEmpty(const ASTContext &C,
bool HasTemplateKWAndArgsInfo,
unsigned NumTemplateArgs) {
if (!HasTemplateKWAndArgsInfo)
@@ -1222,7 +1307,7 @@ static bool hasOnlyNonStaticMemberFunctions(UnresolvedSetIterator begin,
return true;
}
-UnresolvedMemberExpr::UnresolvedMemberExpr(ASTContext &C,
+UnresolvedMemberExpr::UnresolvedMemberExpr(const ASTContext &C,
bool HasUnresolvedUsing,
Expr *Base, QualType BaseType,
bool IsArrow,
@@ -1260,8 +1345,7 @@ bool UnresolvedMemberExpr::isImplicitAccess() const {
}
UnresolvedMemberExpr *
-UnresolvedMemberExpr::Create(ASTContext &C,
- bool HasUnresolvedUsing,
+UnresolvedMemberExpr::Create(const ASTContext &C, bool HasUnresolvedUsing,
Expr *Base, QualType BaseType, bool IsArrow,
SourceLocation OperatorLoc,
NestedNameSpecifierLoc QualifierLoc,
@@ -1284,7 +1368,8 @@ UnresolvedMemberExpr::Create(ASTContext &C,
}
UnresolvedMemberExpr *
-UnresolvedMemberExpr::CreateEmpty(ASTContext &C, bool HasTemplateKWAndArgsInfo,
+UnresolvedMemberExpr::CreateEmpty(const ASTContext &C,
+ bool HasTemplateKWAndArgsInfo,
unsigned NumTemplateArgs) {
std::size_t size = sizeof(UnresolvedMemberExpr);
if (HasTemplateKWAndArgsInfo)
@@ -1352,7 +1437,7 @@ FunctionParmPackExpr::FunctionParmPackExpr(QualType T, ParmVarDecl *ParamPack,
}
FunctionParmPackExpr *
-FunctionParmPackExpr::Create(ASTContext &Context, QualType T,
+FunctionParmPackExpr::Create(const ASTContext &Context, QualType T,
ParmVarDecl *ParamPack, SourceLocation NameLoc,
ArrayRef<Decl *> Params) {
return new (Context.Allocate(sizeof(FunctionParmPackExpr) +
@@ -1361,7 +1446,8 @@ FunctionParmPackExpr::Create(ASTContext &Context, QualType T,
}
FunctionParmPackExpr *
-FunctionParmPackExpr::CreateEmpty(ASTContext &Context, unsigned NumParams) {
+FunctionParmPackExpr::CreateEmpty(const ASTContext &Context,
+ unsigned NumParams) {
return new (Context.Allocate(sizeof(FunctionParmPackExpr) +
sizeof(ParmVarDecl*) * NumParams))
FunctionParmPackExpr(QualType(), 0, SourceLocation(), 0, 0);
@@ -1396,7 +1482,7 @@ TypeTraitExpr::TypeTraitExpr(QualType T, SourceLocation Loc, TypeTrait Kind,
}
}
-TypeTraitExpr *TypeTraitExpr::Create(ASTContext &C, QualType T,
+TypeTraitExpr *TypeTraitExpr::Create(const ASTContext &C, QualType T,
SourceLocation Loc,
TypeTrait Kind,
ArrayRef<TypeSourceInfo *> Args,
@@ -1407,7 +1493,7 @@ TypeTraitExpr *TypeTraitExpr::Create(ASTContext &C, QualType T,
return new (Mem) TypeTraitExpr(T, Loc, Kind, Args, RParenLoc, Value);
}
-TypeTraitExpr *TypeTraitExpr::CreateDeserialized(ASTContext &C,
+TypeTraitExpr *TypeTraitExpr::CreateDeserialized(const ASTContext &C,
unsigned NumArgs) {
unsigned Size = sizeof(TypeTraitExpr) + sizeof(TypeSourceInfo*) * NumArgs;
void *Mem = C.Allocate(Size);
diff --git a/lib/AST/ExprClassification.cpp b/lib/AST/ExprClassification.cpp
index bcb6d4e809bf..54f77efef0f9 100644
--- a/lib/AST/ExprClassification.cpp
+++ b/lib/AST/ExprClassification.cpp
@@ -155,6 +155,7 @@ static Cl::Kinds ClassifyInternal(ASTContext &Ctx, const Expr *E) {
case Expr::OffsetOfExprClass:
case Expr::CXXThrowExprClass:
case Expr::ShuffleVectorExprClass:
+ case Expr::ConvertVectorExprClass:
case Expr::IntegerLiteralClass:
case Expr::CharacterLiteralClass:
case Expr::AddrLabelExprClass:
@@ -286,13 +287,16 @@ static Cl::Kinds ClassifyInternal(ASTContext &Ctx, const Expr *E) {
// __builtin_choose_expr is equivalent to the chosen expression.
case Expr::ChooseExprClass:
- return ClassifyInternal(Ctx, cast<ChooseExpr>(E)->getChosenSubExpr(Ctx));
+ return ClassifyInternal(Ctx, cast<ChooseExpr>(E)->getChosenSubExpr());
// Extended vector element access is an lvalue unless there are duplicates
// in the shuffle expression.
case Expr::ExtVectorElementExprClass:
- return cast<ExtVectorElementExpr>(E)->containsDuplicateElements() ?
- Cl::CL_DuplicateVectorComponents : Cl::CL_LValue;
+ if (cast<ExtVectorElementExpr>(E)->containsDuplicateElements())
+ return Cl::CL_DuplicateVectorComponents;
+ if (cast<ExtVectorElementExpr>(E)->isArrow())
+ return Cl::CL_LValue;
+ return ClassifyInternal(Ctx, cast<ExtVectorElementExpr>(E)->getBase());
// Simply look at the actual default argument.
case Expr::CXXDefaultArgExprClass:
@@ -353,6 +357,7 @@ static Cl::Kinds ClassifyInternal(ASTContext &Ctx, const Expr *E) {
case Expr::CXXConstructExprClass:
case Expr::CXXTemporaryObjectExprClass:
case Expr::LambdaExprClass:
+ case Expr::CXXStdInitializerListExprClass:
return Cl::CL_ClassTemporary;
case Expr::VAArgExprClass:
@@ -587,6 +592,8 @@ static Cl::ModifiableType IsModifiable(ASTContext &Ctx, const Expr *E,
// Const stuff is obviously not modifiable.
if (CT.isConstQualified())
return Cl::CM_ConstQualified;
+ if (CT.getQualifiers().getAddressSpace() == LangAS::opencl_constant)
+ return Cl::CM_ConstQualified;
// Arrays are not modifiable, only their elements are.
if (CT->isArrayType())
diff --git a/lib/AST/ExprConstant.cpp b/lib/AST/ExprConstant.cpp
index 8c650290b579..390cfe9cd235 100644
--- a/lib/AST/ExprConstant.cpp
+++ b/lib/AST/ExprConstant.cpp
@@ -23,8 +23,8 @@
// where it is possible to determine the evaluated result regardless.
//
// * A set of notes indicating why the evaluation was not a constant expression
-// (under the C++11 rules only, at the moment), or, if folding failed too,
-// why the expression could not be folded.
+// (under the C++11 / C++1y rules only, at the moment), or, if folding failed
+// too, why the expression could not be folded.
//
// If we are checking for a potential constant expression, failure to constant
// fold a potential constant sub-expression will be indicated by a 'false'
@@ -63,7 +63,25 @@ namespace {
if (!B) return QualType();
if (const ValueDecl *D = B.dyn_cast<const ValueDecl*>())
return D->getType();
- return B.get<const Expr*>()->getType();
+
+ const Expr *Base = B.get<const Expr*>();
+
+ // For a materialized temporary, the type of the temporary we materialized
+ // may not be the type of the expression.
+ if (const MaterializeTemporaryExpr *MTE =
+ dyn_cast<MaterializeTemporaryExpr>(Base)) {
+ SmallVector<const Expr *, 2> CommaLHSs;
+ SmallVector<SubobjectAdjustment, 2> Adjustments;
+ const Expr *Temp = MTE->GetTemporaryExpr();
+ const Expr *Inner = Temp->skipRValueSubobjectAdjustments(CommaLHSs,
+ Adjustments);
+ // Keep any cv-qualifiers from the reference if we generated a temporary
+ // for it.
+ if (Inner != Temp)
+ return Inner->getType();
+ }
+
+ return Base->getType();
}
/// Get an LValue path entry, which is known to not be an array index, as a
@@ -284,7 +302,7 @@ namespace {
/// This - The binding for the this pointer in this call, if any.
const LValue *This;
- /// ParmBindings - Parameter bindings for this function call, indexed by
+ /// Arguments - Parameter bindings for this function call, indexed by
/// parameters' function scope indices.
APValue *Arguments;
@@ -299,6 +317,12 @@ namespace {
const FunctionDecl *Callee, const LValue *This,
APValue *Arguments);
~CallStackFrame();
+
+ APValue *getTemporary(const void *Key) {
+ MapTy::iterator I = Temporaries.find(Key);
+ return I == Temporaries.end() ? 0 : &I->second;
+ }
+ APValue &createTemporary(const void *Key, bool IsLifetimeExtended);
};
/// Temporarily override 'this'.
@@ -343,14 +367,37 @@ namespace {
OptionalDiagnostic &operator<<(const APFloat &F) {
if (Diag) {
+ // FIXME: Force the precision of the source value down so we don't
+ // print digits which are usually useless (we don't really care here if
+ // we truncate a digit by accident in edge cases). Ideally,
+ // APFloat::toString would automatically print the shortest
+ // representation which rounds to the correct value, but it's a bit
+ // tricky to implement.
+ unsigned precision =
+ llvm::APFloat::semanticsPrecision(F.getSemantics());
+ precision = (precision * 59 + 195) / 196;
SmallVector<char, 32> Buffer;
- F.toString(Buffer);
+ F.toString(Buffer, precision);
*Diag << StringRef(Buffer.data(), Buffer.size());
}
return *this;
}
};
+ /// A cleanup, and a flag indicating whether it is lifetime-extended.
+ class Cleanup {
+ llvm::PointerIntPair<APValue*, 1, bool> Value;
+
+ public:
+ Cleanup(APValue *Val, bool IsLifetimeExtended)
+ : Value(Val, IsLifetimeExtended) {}
+
+ bool isLifetimeExtended() const { return Value.getInt(); }
+ void endLifetime() {
+ *Value.getPointer() = APValue();
+ }
+ };
+
/// EvalInfo - This is a private struct used by the evaluator to capture
/// information about a subexpression as it is folded. It retains information
/// about the AST context, but also maintains information about the folded
@@ -380,13 +427,22 @@ namespace {
/// NextCallIndex - The next call index to assign.
unsigned NextCallIndex;
+ /// StepsLeft - The remaining number of evaluation steps we're permitted
+ /// to perform. This is essentially a limit for the number of statements
+ /// we will evaluate.
+ unsigned StepsLeft;
+
/// BottomFrame - The frame in which evaluation started. This must be
/// initialized after CurrentCall and CallStackDepth.
CallStackFrame BottomFrame;
+ /// A stack of values whose lifetimes end at the end of some surrounding
+ /// evaluation frame.
+ llvm::SmallVector<Cleanup, 16> CleanupStack;
+
/// EvaluatingDecl - This is the declaration whose initializer is being
/// evaluated, if any.
- const VarDecl *EvaluatingDecl;
+ APValue::LValueBase EvaluatingDecl;
/// EvaluatingDeclValue - This is the value being constructed for the
/// declaration whose initializer is being evaluated, if any.
@@ -396,24 +452,52 @@ namespace {
/// notes attached to it will also be stored, otherwise they will not be.
bool HasActiveDiagnostic;
- /// CheckingPotentialConstantExpression - Are we checking whether the
- /// expression is a potential constant expression? If so, some diagnostics
- /// are suppressed.
- bool CheckingPotentialConstantExpression;
-
- bool IntOverflowCheckMode;
+ enum EvaluationMode {
+ /// Evaluate as a constant expression. Stop if we find that the expression
+ /// is not a constant expression.
+ EM_ConstantExpression,
+
+ /// Evaluate as a potential constant expression. Keep going if we hit a
+ /// construct that we can't evaluate yet (because we don't yet know the
+ /// value of something) but stop if we hit something that could never be
+ /// a constant expression.
+ EM_PotentialConstantExpression,
+
+ /// Fold the expression to a constant. Stop if we hit a side-effect that
+ /// we can't model.
+ EM_ConstantFold,
+
+ /// Evaluate the expression looking for integer overflow and similar
+ /// issues. Don't worry about side-effects, and try to visit all
+ /// subexpressions.
+ EM_EvaluateForOverflow,
- EvalInfo(const ASTContext &C, Expr::EvalStatus &S,
- bool OverflowCheckMode=false)
+ /// Evaluate in any way we know how. Don't worry about side-effects that
+ /// can't be modeled.
+ EM_IgnoreSideEffects
+ } EvalMode;
+
+ /// Are we checking whether the expression is a potential constant
+ /// expression?
+ bool checkingPotentialConstantExpression() const {
+ return EvalMode == EM_PotentialConstantExpression;
+ }
+
+ /// Are we checking an expression for overflow?
+ // FIXME: We should check for any kind of undefined or suspicious behavior
+ // in such constructs, not just overflow.
+ bool checkingForOverflow() { return EvalMode == EM_EvaluateForOverflow; }
+
+ EvalInfo(const ASTContext &C, Expr::EvalStatus &S, EvaluationMode Mode)
: Ctx(const_cast<ASTContext&>(C)), EvalStatus(S), CurrentCall(0),
CallStackDepth(0), NextCallIndex(1),
+ StepsLeft(getLangOpts().ConstexprStepLimit),
BottomFrame(*this, SourceLocation(), 0, 0, 0),
- EvaluatingDecl(0), EvaluatingDeclValue(0), HasActiveDiagnostic(false),
- CheckingPotentialConstantExpression(false),
- IntOverflowCheckMode(OverflowCheckMode) {}
+ EvaluatingDecl((const ValueDecl*)0), EvaluatingDeclValue(0),
+ HasActiveDiagnostic(false), EvalMode(Mode) {}
- void setEvaluatingDecl(const VarDecl *VD, APValue &Value) {
- EvaluatingDecl = VD;
+ void setEvaluatingDecl(APValue::LValueBase Base, APValue &Value) {
+ EvaluatingDecl = Base;
EvaluatingDeclValue = &Value;
}
@@ -422,7 +506,7 @@ namespace {
bool CheckCallLimit(SourceLocation Loc) {
// Don't perform any constexpr calls (other than the call we're checking)
// when checking a potential constant expression.
- if (CheckingPotentialConstantExpression && CallStackDepth > 1)
+ if (checkingPotentialConstantExpression() && CallStackDepth > 1)
return false;
if (NextCallIndex == 0) {
// NextCallIndex has wrapped around.
@@ -446,6 +530,15 @@ namespace {
return (Frame->Index == CallIndex) ? Frame : 0;
}
+ bool nextStep(const Stmt *S) {
+ if (!StepsLeft) {
+ Diag(S->getLocStart(), diag::note_constexpr_step_limit_exceeded);
+ return false;
+ }
+ --StepsLeft;
+ return true;
+ }
+
private:
/// Add a diagnostic to the diagnostics list.
PartialDiagnostic &addDiag(SourceLocation Loc, diag::kind DiagId) {
@@ -462,22 +555,41 @@ namespace {
OptionalDiagnostic Diag(SourceLocation Loc, diag::kind DiagId
= diag::note_invalid_subexpr_in_const_expr,
unsigned ExtraNotes = 0) {
- // If we have a prior diagnostic, it will be noting that the expression
- // isn't a constant expression. This diagnostic is more important.
- // FIXME: We might want to show both diagnostics to the user.
if (EvalStatus.Diag) {
+ // If we have a prior diagnostic, it will be noting that the expression
+ // isn't a constant expression. This diagnostic is more important,
+ // unless we require this evaluation to produce a constant expression.
+ //
+ // FIXME: We might want to show both diagnostics to the user in
+ // EM_ConstantFold mode.
+ if (!EvalStatus.Diag->empty()) {
+ switch (EvalMode) {
+ case EM_ConstantFold:
+ case EM_IgnoreSideEffects:
+ case EM_EvaluateForOverflow:
+ if (!EvalStatus.HasSideEffects)
+ break;
+ // We've had side-effects; we want the diagnostic from them, not
+ // some later problem.
+ case EM_ConstantExpression:
+ case EM_PotentialConstantExpression:
+ HasActiveDiagnostic = false;
+ return OptionalDiagnostic();
+ }
+ }
+
unsigned CallStackNotes = CallStackDepth - 1;
unsigned Limit = Ctx.getDiagnostics().getConstexprBacktraceLimit();
if (Limit)
CallStackNotes = std::min(CallStackNotes, Limit + 1);
- if (CheckingPotentialConstantExpression)
+ if (checkingPotentialConstantExpression())
CallStackNotes = 0;
HasActiveDiagnostic = true;
EvalStatus.Diag->clear();
EvalStatus.Diag->reserve(1 + ExtraNotes + CallStackNotes);
addDiag(Loc, DiagId);
- if (!CheckingPotentialConstantExpression)
+ if (!checkingPotentialConstantExpression())
addCallStack(Limit);
return OptionalDiagnostic(&(*EvalStatus.Diag)[0].second);
}
@@ -494,15 +606,17 @@ namespace {
return OptionalDiagnostic();
}
- bool getIntOverflowCheckMode() { return IntOverflowCheckMode; }
-
/// Diagnose that the evaluation does not produce a C++11 core constant
/// expression.
+ ///
+ /// FIXME: Stop evaluating if we're in EM_ConstantExpression or
+ /// EM_PotentialConstantExpression mode and we produce one of these.
template<typename LocArg>
OptionalDiagnostic CCEDiag(LocArg Loc, diag::kind DiagId
= diag::note_invalid_subexpr_in_const_expr,
unsigned ExtraNotes = 0) {
- // Don't override a previous diagnostic.
+ // Don't override a previous diagnostic. Don't bother collecting
+ // diagnostics if we're evaluating for overflow.
if (!EvalStatus.Diag || !EvalStatus.Diag->empty()) {
HasActiveDiagnostic = false;
return OptionalDiagnostic();
@@ -525,30 +639,72 @@ namespace {
}
}
+ /// Should we continue evaluation after encountering a side-effect that we
+ /// couldn't model?
+ bool keepEvaluatingAfterSideEffect() {
+ switch (EvalMode) {
+ case EM_PotentialConstantExpression:
+ case EM_EvaluateForOverflow:
+ case EM_IgnoreSideEffects:
+ return true;
+
+ case EM_ConstantExpression:
+ case EM_ConstantFold:
+ return false;
+ }
+ llvm_unreachable("Missed EvalMode case");
+ }
+
+ /// Note that we have had a side-effect, and determine whether we should
+ /// keep evaluating.
+ bool noteSideEffect() {
+ EvalStatus.HasSideEffects = true;
+ return keepEvaluatingAfterSideEffect();
+ }
+
/// Should we continue evaluation as much as possible after encountering a
- /// construct which can't be folded?
+ /// construct which can't be reduced to a value?
bool keepEvaluatingAfterFailure() {
- // Should return true in IntOverflowCheckMode, so that we check for
- // overflow even if some subexpressions can't be evaluated as constants.
- return IntOverflowCheckMode ||
- (CheckingPotentialConstantExpression &&
- EvalStatus.Diag && EvalStatus.Diag->empty());
+ if (!StepsLeft)
+ return false;
+
+ switch (EvalMode) {
+ case EM_PotentialConstantExpression:
+ case EM_EvaluateForOverflow:
+ return true;
+
+ case EM_ConstantExpression:
+ case EM_ConstantFold:
+ case EM_IgnoreSideEffects:
+ return false;
+ }
+ llvm_unreachable("Missed EvalMode case");
}
};
/// Object used to treat all foldable expressions as constant expressions.
struct FoldConstant {
+ EvalInfo &Info;
bool Enabled;
-
- explicit FoldConstant(EvalInfo &Info)
- : Enabled(Info.EvalStatus.Diag && Info.EvalStatus.Diag->empty() &&
- !Info.EvalStatus.HasSideEffects) {
- }
- // Treat the value we've computed since this object was created as constant.
- void Fold(EvalInfo &Info) {
- if (Enabled && !Info.EvalStatus.Diag->empty() &&
+ bool HadNoPriorDiags;
+ EvalInfo::EvaluationMode OldMode;
+
+ explicit FoldConstant(EvalInfo &Info, bool Enabled)
+ : Info(Info),
+ Enabled(Enabled),
+ HadNoPriorDiags(Info.EvalStatus.Diag &&
+ Info.EvalStatus.Diag->empty() &&
+ !Info.EvalStatus.HasSideEffects),
+ OldMode(Info.EvalMode) {
+ if (Enabled && Info.EvalMode == EvalInfo::EM_ConstantExpression)
+ Info.EvalMode = EvalInfo::EM_ConstantFold;
+ }
+ void keepDiagnostics() { Enabled = false; }
+ ~FoldConstant() {
+ if (Enabled && HadNoPriorDiags && !Info.EvalStatus.Diag->empty() &&
!Info.EvalStatus.HasSideEffects)
Info.EvalStatus.Diag->clear();
+ Info.EvalMode = OldMode;
}
};
@@ -563,11 +719,50 @@ namespace {
SmallVectorImpl<PartialDiagnosticAt> *NewDiag = 0)
: Info(Info), Old(Info.EvalStatus) {
Info.EvalStatus.Diag = NewDiag;
+ // If we're speculatively evaluating, we may have skipped over some
+ // evaluations and missed out a side effect.
+ Info.EvalStatus.HasSideEffects = true;
}
~SpeculativeEvaluationRAII() {
Info.EvalStatus = Old;
}
};
+
+ /// RAII object wrapping a full-expression or block scope, and handling
+ /// the ending of the lifetime of temporaries created within it.
+ template<bool IsFullExpression>
+ class ScopeRAII {
+ EvalInfo &Info;
+ unsigned OldStackSize;
+ public:
+ ScopeRAII(EvalInfo &Info)
+ : Info(Info), OldStackSize(Info.CleanupStack.size()) {}
+ ~ScopeRAII() {
+ // Body moved to a static method to encourage the compiler to inline away
+ // instances of this class.
+ cleanup(Info, OldStackSize);
+ }
+ private:
+ static void cleanup(EvalInfo &Info, unsigned OldStackSize) {
+ unsigned NewEnd = OldStackSize;
+ for (unsigned I = OldStackSize, N = Info.CleanupStack.size();
+ I != N; ++I) {
+ if (IsFullExpression && Info.CleanupStack[I].isLifetimeExtended()) {
+ // Full-expression cleanup of a lifetime-extended temporary: nothing
+ // to do, just move this cleanup to the right place in the stack.
+ std::swap(Info.CleanupStack[I], Info.CleanupStack[NewEnd]);
+ ++NewEnd;
+ } else {
+ // End the lifetime of the object.
+ Info.CleanupStack[I].endLifetime();
+ }
+ }
+ Info.CleanupStack.erase(Info.CleanupStack.begin() + NewEnd,
+ Info.CleanupStack.end());
+ }
+ };
+ typedef ScopeRAII<false> BlockScopeRAII;
+ typedef ScopeRAII<true> FullExpressionRAII;
}
bool SubobjectDesignator::checkSubobject(EvalInfo &Info, const Expr *E,
@@ -610,32 +805,16 @@ CallStackFrame::~CallStackFrame() {
Info.CurrentCall = Caller;
}
-/// Produce a string describing the given constexpr call.
-static void describeCall(CallStackFrame *Frame, raw_ostream &Out) {
- unsigned ArgIndex = 0;
- bool IsMemberCall = isa<CXXMethodDecl>(Frame->Callee) &&
- !isa<CXXConstructorDecl>(Frame->Callee) &&
- cast<CXXMethodDecl>(Frame->Callee)->isInstance();
-
- if (!IsMemberCall)
- Out << *Frame->Callee << '(';
-
- for (FunctionDecl::param_const_iterator I = Frame->Callee->param_begin(),
- E = Frame->Callee->param_end(); I != E; ++I, ++ArgIndex) {
- if (ArgIndex > (unsigned)IsMemberCall)
- Out << ", ";
-
- const ParmVarDecl *Param = *I;
- const APValue &Arg = Frame->Arguments[ArgIndex];
- Arg.printPretty(Out, Frame->Info.Ctx, Param->getType());
-
- if (ArgIndex == 0 && IsMemberCall)
- Out << "->" << *Frame->Callee << '(';
- }
-
- Out << ')';
+APValue &CallStackFrame::createTemporary(const void *Key,
+ bool IsLifetimeExtended) {
+ APValue &Result = Temporaries[Key];
+ assert(Result.isUninit() && "temporary created multiple times");
+ Info.CleanupStack.push_back(Cleanup(&Result, IsLifetimeExtended));
+ return Result;
}
+static void describeCall(CallStackFrame *Frame, raw_ostream &Out);
+
void EvalInfo::addCallStack(unsigned Limit) {
// Determine which calls to skip, if any.
unsigned ActiveCalls = CallStackDepth - 1;
@@ -884,19 +1063,11 @@ namespace {
return false;
return LHS.Path == RHS.Path;
}
-
- /// Kinds of constant expression checking, for diagnostics.
- enum CheckConstantExpressionKind {
- CCEK_Constant, ///< A normal constant.
- CCEK_ReturnValue, ///< A constexpr function return value.
- CCEK_MemberInit ///< A constexpr constructor mem-initializer.
- };
}
static bool Evaluate(APValue &Result, EvalInfo &Info, const Expr *E);
static bool EvaluateInPlace(APValue &Result, EvalInfo &Info,
const LValue &This, const Expr *E,
- CheckConstantExpressionKind CCEK = CCEK_Constant,
bool AllowNonLiteralTypes = false);
static bool EvaluateLValue(const Expr *E, LValue &Result, EvalInfo &Info);
static bool EvaluatePointer(const Expr *E, LValue &Result, EvalInfo &Info);
@@ -908,23 +1079,66 @@ 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, ComplexValue &Res, EvalInfo &Info);
+static bool EvaluateAtomic(const Expr *E, APValue &Result, EvalInfo &Info);
//===----------------------------------------------------------------------===//
// Misc utilities
//===----------------------------------------------------------------------===//
+/// Produce a string describing the given constexpr call.
+static void describeCall(CallStackFrame *Frame, raw_ostream &Out) {
+ unsigned ArgIndex = 0;
+ bool IsMemberCall = isa<CXXMethodDecl>(Frame->Callee) &&
+ !isa<CXXConstructorDecl>(Frame->Callee) &&
+ cast<CXXMethodDecl>(Frame->Callee)->isInstance();
+
+ if (!IsMemberCall)
+ Out << *Frame->Callee << '(';
+
+ if (Frame->This && IsMemberCall) {
+ APValue Val;
+ Frame->This->moveInto(Val);
+ Val.printPretty(Out, Frame->Info.Ctx,
+ Frame->This->Designator.MostDerivedType);
+ // FIXME: Add parens around Val if needed.
+ Out << "->" << *Frame->Callee << '(';
+ IsMemberCall = false;
+ }
+
+ for (FunctionDecl::param_const_iterator I = Frame->Callee->param_begin(),
+ E = Frame->Callee->param_end(); I != E; ++I, ++ArgIndex) {
+ if (ArgIndex > (unsigned)IsMemberCall)
+ Out << ", ";
+
+ const ParmVarDecl *Param = *I;
+ const APValue &Arg = Frame->Arguments[ArgIndex];
+ Arg.printPretty(Out, Frame->Info.Ctx, Param->getType());
+
+ if (ArgIndex == 0 && IsMemberCall)
+ Out << "->" << *Frame->Callee << '(';
+ }
+
+ Out << ')';
+}
+
/// Evaluate an expression to see if it had side-effects, and discard its
/// result.
/// \return \c true if the caller should keep evaluating.
static bool EvaluateIgnoredValue(EvalInfo &Info, const Expr *E) {
APValue Scratch;
- if (!Evaluate(Scratch, Info, E)) {
- Info.EvalStatus.HasSideEffects = true;
- return Info.keepEvaluatingAfterFailure();
- }
+ if (!Evaluate(Scratch, Info, E))
+ // We don't need the value, but we might have skipped a side effect here.
+ return Info.noteSideEffect();
return true;
}
+/// Sign- or zero-extend a value to 64 bits. If it's already 64 bits, just
+/// return its existing value.
+static int64_t getExtValue(const APSInt &Value) {
+ return Value.isSigned() ? Value.getSExtValue()
+ : static_cast<int64_t>(Value.getZExtValue());
+}
+
/// Should this call expression be treated as a string literal?
static bool IsStringLiteralCall(const CallExpr *E) {
unsigned Builtin = E->isBuiltinCall();
@@ -956,6 +1170,10 @@ static bool IsGlobalLValue(APValue::LValueBase B) {
const CompoundLiteralExpr *CLE = cast<CompoundLiteralExpr>(E);
return CLE->isFileScope() && CLE->isLValue();
}
+ case Expr::MaterializeTemporaryExprClass:
+ // A materialized temporary might have been lifetime-extended to static
+ // storage duration.
+ return cast<MaterializeTemporaryExpr>(E)->getStorageDuration() == SD_Static;
// A string literal has static storage duration.
case Expr::StringLiteralClass:
case Expr::PredefinedExprClass:
@@ -1020,7 +1238,7 @@ static bool CheckLValueConstantExpression(EvalInfo &Info, SourceLocation Loc,
// Don't allow references to temporaries to escape.
return false;
}
- assert((Info.CheckingPotentialConstantExpression ||
+ assert((Info.checkingPotentialConstantExpression() ||
LVal.getLValueCallIndex() == 0) &&
"have call index for global lvalue");
@@ -1057,10 +1275,18 @@ static bool CheckLValueConstantExpression(EvalInfo &Info, SourceLocation Loc,
/// Check that this core constant expression is of literal type, and if not,
/// produce an appropriate diagnostic.
-static bool CheckLiteralType(EvalInfo &Info, const Expr *E) {
+static bool CheckLiteralType(EvalInfo &Info, const Expr *E,
+ const LValue *This = 0) {
if (!E->isRValue() || E->getType()->isLiteralType(Info.Ctx))
return true;
+ // C++1y: A constant initializer for an object o [...] may also invoke
+ // constexpr constructors for o and its subobjects even if those objects
+ // are of non-literal class types.
+ if (Info.getLangOpts().CPlusPlus1y && This &&
+ Info.EvaluatingDecl == This->getLValueBase())
+ return true;
+
// Prvalue constant expressions must be of literal types.
if (Info.getLangOpts().CPlusPlus11)
Info.Diag(E, diag::note_constexpr_nonliteral)
@@ -1075,6 +1301,12 @@ static bool CheckLiteralType(EvalInfo &Info, const Expr *E) {
/// check that the expression is of literal type.
static bool CheckConstantExpression(EvalInfo &Info, SourceLocation DiagLoc,
QualType Type, const APValue &Value) {
+ if (Value.isUninit()) {
+ Info.Diag(DiagLoc, diag::note_constexpr_uninitialized)
+ << true << Type;
+ return false;
+ }
+
// Core issue 1454: For a literal constant expression of array or class type,
// each subobject of its value shall have been initialized by a constant
// expression.
@@ -1129,7 +1361,10 @@ const ValueDecl *GetLValueBaseDecl(const LValue &LVal) {
}
static bool IsLiteralLValue(const LValue &Value) {
- return Value.Base.dyn_cast<const Expr*>() && !Value.CallIndex;
+ if (Value.CallIndex)
+ return false;
+ const Expr *E = Value.Base.dyn_cast<const Expr*>();
+ return E && !isa<MaterializeTemporaryExpr>(E);
}
static bool IsWeakLValue(const LValue &Value) {
@@ -1252,6 +1487,27 @@ static bool HandleIntToFloatCast(EvalInfo &Info, const Expr *E,
return true;
}
+static bool truncateBitfieldValue(EvalInfo &Info, const Expr *E,
+ APValue &Value, const FieldDecl *FD) {
+ assert(FD->isBitField() && "truncateBitfieldValue on non-bitfield");
+
+ if (!Value.isInt()) {
+ // Trying to store a pointer-cast-to-integer into a bitfield.
+ // FIXME: In this case, we should provide the diagnostic for casting
+ // a pointer to an integer.
+ assert(Value.isLValue() && "integral value neither int nor lvalue?");
+ Info.Diag(E);
+ return false;
+ }
+
+ APSInt &Int = Value.getInt();
+ unsigned OldBitWidth = Int.getBitWidth();
+ unsigned NewBitWidth = FD->getBitWidthValue(Info.Ctx);
+ if (NewBitWidth < OldBitWidth)
+ Int = Int.trunc(NewBitWidth).extend(OldBitWidth);
+ return true;
+}
+
static bool EvalAndBitcastToAPInt(EvalInfo &Info, const Expr *E,
llvm::APInt &Res) {
APValue SVal;
@@ -1299,6 +1555,155 @@ static bool EvalAndBitcastToAPInt(EvalInfo &Info, const Expr *E,
return false;
}
+/// Perform the given integer operation, which is known to need at most BitWidth
+/// bits, and check for overflow in the original type (if that type was not an
+/// unsigned type).
+template<typename Operation>
+static APSInt CheckedIntArithmetic(EvalInfo &Info, const Expr *E,
+ const APSInt &LHS, const APSInt &RHS,
+ unsigned BitWidth, Operation Op) {
+ if (LHS.isUnsigned())
+ return Op(LHS, RHS);
+
+ APSInt Value(Op(LHS.extend(BitWidth), RHS.extend(BitWidth)), false);
+ APSInt Result = Value.trunc(LHS.getBitWidth());
+ if (Result.extend(BitWidth) != Value) {
+ if (Info.checkingForOverflow())
+ Info.Ctx.getDiagnostics().Report(E->getExprLoc(),
+ diag::warn_integer_constant_overflow)
+ << Result.toString(10) << E->getType();
+ else
+ HandleOverflow(Info, E, Value, E->getType());
+ }
+ return Result;
+}
+
+/// Perform the given binary integer operation.
+static bool handleIntIntBinOp(EvalInfo &Info, const Expr *E, const APSInt &LHS,
+ BinaryOperatorKind Opcode, APSInt RHS,
+ APSInt &Result) {
+ switch (Opcode) {
+ default:
+ Info.Diag(E);
+ return false;
+ case BO_Mul:
+ Result = CheckedIntArithmetic(Info, E, LHS, RHS, LHS.getBitWidth() * 2,
+ std::multiplies<APSInt>());
+ return true;
+ case BO_Add:
+ Result = CheckedIntArithmetic(Info, E, LHS, RHS, LHS.getBitWidth() + 1,
+ std::plus<APSInt>());
+ return true;
+ case BO_Sub:
+ Result = CheckedIntArithmetic(Info, E, LHS, RHS, LHS.getBitWidth() + 1,
+ std::minus<APSInt>());
+ return true;
+ case BO_And: Result = LHS & RHS; return true;
+ case BO_Xor: Result = LHS ^ RHS; return true;
+ case BO_Or: Result = LHS | RHS; return true;
+ case BO_Div:
+ case BO_Rem:
+ if (RHS == 0) {
+ Info.Diag(E, diag::note_expr_divide_by_zero);
+ return false;
+ }
+ // Check for overflow case: INT_MIN / -1 or INT_MIN % -1.
+ if (RHS.isNegative() && RHS.isAllOnesValue() &&
+ LHS.isSigned() && LHS.isMinSignedValue())
+ HandleOverflow(Info, E, -LHS.extend(LHS.getBitWidth() + 1), E->getType());
+ Result = (Opcode == BO_Rem ? LHS % RHS : LHS / RHS);
+ return true;
+ case BO_Shl: {
+ if (Info.getLangOpts().OpenCL)
+ // OpenCL 6.3j: shift values are effectively % word size of LHS.
+ RHS &= APSInt(llvm::APInt(RHS.getBitWidth(),
+ static_cast<uint64_t>(LHS.getBitWidth() - 1)),
+ RHS.isUnsigned());
+ else if (RHS.isSigned() && RHS.isNegative()) {
+ // During constant-folding, a negative shift is an opposite shift. Such
+ // a shift is not a constant expression.
+ Info.CCEDiag(E, diag::note_constexpr_negative_shift) << RHS;
+ RHS = -RHS;
+ goto shift_right;
+ }
+ shift_left:
+ // C++11 [expr.shift]p1: Shift width must be less than the bit width of
+ // the shifted type.
+ unsigned SA = (unsigned) RHS.getLimitedValue(LHS.getBitWidth()-1);
+ if (SA != RHS) {
+ Info.CCEDiag(E, diag::note_constexpr_large_shift)
+ << RHS << E->getType() << LHS.getBitWidth();
+ } else if (LHS.isSigned()) {
+ // C++11 [expr.shift]p2: A signed left shift must have a non-negative
+ // operand, and must not overflow the corresponding unsigned type.
+ if (LHS.isNegative())
+ Info.CCEDiag(E, diag::note_constexpr_lshift_of_negative) << LHS;
+ else if (LHS.countLeadingZeros() < SA)
+ Info.CCEDiag(E, diag::note_constexpr_lshift_discards);
+ }
+ Result = LHS << SA;
+ return true;
+ }
+ case BO_Shr: {
+ if (Info.getLangOpts().OpenCL)
+ // OpenCL 6.3j: shift values are effectively % word size of LHS.
+ RHS &= APSInt(llvm::APInt(RHS.getBitWidth(),
+ static_cast<uint64_t>(LHS.getBitWidth() - 1)),
+ RHS.isUnsigned());
+ else if (RHS.isSigned() && RHS.isNegative()) {
+ // During constant-folding, a negative shift is an opposite shift. Such a
+ // shift is not a constant expression.
+ Info.CCEDiag(E, diag::note_constexpr_negative_shift) << RHS;
+ RHS = -RHS;
+ goto shift_left;
+ }
+ shift_right:
+ // C++11 [expr.shift]p1: Shift width must be less than the bit width of the
+ // shifted type.
+ unsigned SA = (unsigned) RHS.getLimitedValue(LHS.getBitWidth()-1);
+ if (SA != RHS)
+ Info.CCEDiag(E, diag::note_constexpr_large_shift)
+ << RHS << E->getType() << LHS.getBitWidth();
+ Result = LHS >> SA;
+ return true;
+ }
+
+ case BO_LT: Result = LHS < RHS; return true;
+ case BO_GT: Result = LHS > RHS; return true;
+ case BO_LE: Result = LHS <= RHS; return true;
+ case BO_GE: Result = LHS >= RHS; return true;
+ case BO_EQ: Result = LHS == RHS; return true;
+ case BO_NE: Result = LHS != RHS; return true;
+ }
+}
+
+/// Perform the given binary floating-point operation, in-place, on LHS.
+static bool handleFloatFloatBinOp(EvalInfo &Info, const Expr *E,
+ APFloat &LHS, BinaryOperatorKind Opcode,
+ const APFloat &RHS) {
+ switch (Opcode) {
+ default:
+ Info.Diag(E);
+ return false;
+ case BO_Mul:
+ LHS.multiply(RHS, APFloat::rmNearestTiesToEven);
+ break;
+ case BO_Add:
+ LHS.add(RHS, APFloat::rmNearestTiesToEven);
+ break;
+ case BO_Sub:
+ LHS.subtract(RHS, APFloat::rmNearestTiesToEven);
+ break;
+ case BO_Div:
+ LHS.divide(RHS, APFloat::rmNearestTiesToEven);
+ break;
+ }
+
+ if (LHS.isInfinity() || LHS.isNaN())
+ Info.CCEDiag(E, diag::note_constexpr_float_arithmetic) << LHS.isNaN();
+ return true;
+}
+
/// Cast an lvalue referring to a base subobject to a derived class, by
/// truncating the lvalue's path to the given length.
static bool CastToDerivedClass(EvalInfo &Info, const Expr *E, LValue &Result,
@@ -1369,6 +1774,19 @@ static bool HandleLValueBase(EvalInfo &Info, const Expr *E, LValue &Obj,
return true;
}
+static bool HandleLValueBasePath(EvalInfo &Info, const CastExpr *E,
+ QualType Type, LValue &Result) {
+ for (CastExpr::path_const_iterator PathI = E->path_begin(),
+ PathE = E->path_end();
+ PathI != PathE; ++PathI) {
+ if (!HandleLValueBase(Info, E, Result, Type->getAsCXXRecordDecl(),
+ *PathI))
+ return false;
+ Type = (*PathI)->getType();
+ }
+ return true;
+}
+
/// Update LVal to refer to the given field, which must be a member of the type
/// currently described by LVal.
static bool HandleLValueMember(EvalInfo &Info, const Expr *E, LValue &LVal,
@@ -1470,7 +1888,7 @@ static bool evaluateVarDeclInit(EvalInfo &Info, const Expr *E,
if (const ParmVarDecl *PVD = dyn_cast<ParmVarDecl>(VD)) {
// Assume arguments of a potential constant expression are unknown
// constant expressions.
- if (Info.CheckingPotentialConstantExpression)
+ if (Info.checkingPotentialConstantExpression())
return false;
if (!Frame || !Frame->Arguments) {
Info.Diag(E, diag::note_invalid_subexpr_in_const_expr);
@@ -1482,11 +1900,9 @@ static bool evaluateVarDeclInit(EvalInfo &Info, const Expr *E,
// If this is a local variable, dig out its value.
if (Frame) {
- Result = &Frame->Temporaries[VD];
- // If we've carried on past an unevaluatable local variable initializer,
- // we can't go any further. This can happen during potential constant
- // expression checking.
- return !Result->isUninit();
+ Result = Frame->getTemporary(VD);
+ assert(Result && "missing value for local variable");
+ return true;
}
// Dig out the initializer, and use the declaration which it's attached to.
@@ -1494,16 +1910,16 @@ static bool evaluateVarDeclInit(EvalInfo &Info, const Expr *E,
if (!Init || Init->isValueDependent()) {
// If we're checking a potential constant expression, the variable could be
// initialized later.
- if (!Info.CheckingPotentialConstantExpression)
+ if (!Info.checkingPotentialConstantExpression())
Info.Diag(E, diag::note_invalid_subexpr_in_const_expr);
return false;
}
// If we're currently evaluating the initializer of this declaration, use that
// in-flight value.
- if (Info.EvaluatingDecl == VD) {
+ if (Info.EvaluatingDecl.dyn_cast<const ValueDecl*>() == VD) {
Result = Info.EvaluatingDeclValue;
- return !Result->isUninit();
+ return true;
}
// Never evaluate the initializer of a weak variable. We can't be sure that
@@ -1615,7 +2031,7 @@ static void expandArray(APValue &Array, unsigned Index) {
Array.swap(NewValue);
}
-/// Kinds of access we can perform on an object.
+/// Kinds of access we can perform on an object, for diagnostics.
enum AccessKinds {
AK_Read,
AK_Assign,
@@ -1637,7 +2053,7 @@ struct CompleteObject {
assert(Value && "missing value for complete object");
}
- operator bool() const { return Value; }
+ LLVM_EXPLICIT operator bool() const { return Value; }
};
/// Find the designated sub-object of an rvalue.
@@ -1656,16 +2072,33 @@ findSubobject(EvalInfo &Info, const Expr *E, const CompleteObject &Obj,
Info.Diag(E);
return handler.failed();
}
- if (Sub.Entries.empty())
- return handler.found(*Obj.Value, Obj.Type);
- if (Info.CheckingPotentialConstantExpression && Obj.Value->isUninit())
- // This object might be initialized later.
- return handler.failed();
APValue *O = Obj.Value;
QualType ObjType = Obj.Type;
+ const FieldDecl *LastField = 0;
+
// Walk the designator's path to find the subobject.
- for (unsigned I = 0, N = Sub.Entries.size(); I != N; ++I) {
+ for (unsigned I = 0, N = Sub.Entries.size(); /**/; ++I) {
+ if (O->isUninit()) {
+ if (!Info.checkingPotentialConstantExpression())
+ Info.Diag(E, diag::note_constexpr_access_uninit) << handler.AccessKind;
+ return handler.failed();
+ }
+
+ if (I == N) {
+ if (!handler.found(*O, ObjType))
+ return false;
+
+ // If we modified a bit-field, truncate it to the right width.
+ if (handler.AccessKind != AK_Read &&
+ LastField && LastField->isBitField() &&
+ !truncateBitfieldValue(Info, E, *O, LastField))
+ return false;
+
+ return true;
+ }
+
+ LastField = 0;
if (ObjType->isArrayType()) {
// Next subobject is an array element.
const ConstantArrayType *CAT = Info.Ctx.getAsConstantArrayType(ObjType);
@@ -1767,6 +2200,8 @@ findSubobject(EvalInfo &Info, const Expr *E, const CompleteObject &Obj,
}
return handler.failed();
}
+
+ LastField = Field;
} else {
// Next subobject is a base class.
const CXXRecordDecl *Derived = ObjType->getAsCXXRecordDecl();
@@ -1778,15 +2213,7 @@ findSubobject(EvalInfo &Info, const Expr *E, const CompleteObject &Obj,
if (WasConstQualified)
ObjType.addConst();
}
-
- if (O->isUninit()) {
- if (!Info.CheckingPotentialConstantExpression)
- Info.Diag(E, diag::note_constexpr_access_uninit) << handler.AccessKind;
- return handler.failed();
- }
}
-
- return handler.found(*O, ObjType);
}
namespace {
@@ -1963,9 +2390,6 @@ CompleteObject findCompleteObject(EvalInfo &Info, const Expr *E, AccessKinds AK,
NoteLValueLocation(Info, LVal.Base);
return CompleteObject();
}
- } else if (AK != AK_Read) {
- Info.Diag(E, diag::note_constexpr_modify_global);
- return CompleteObject();
}
// C++11 DR1311: An lvalue-to-rvalue conversion on a volatile-qualified type
@@ -1983,7 +2407,7 @@ CompleteObject findCompleteObject(EvalInfo &Info, const Expr *E, AccessKinds AK,
// Compute value storage location and type of base object.
APValue *BaseVal = 0;
- QualType BaseType;
+ QualType BaseType = getType(LVal.Base);
if (const ValueDecl *D = LVal.Base.dyn_cast<const ValueDecl*>()) {
// In C++98, const, non-volatile integers initialized with ICEs are ICEs.
@@ -2004,7 +2428,6 @@ CompleteObject findCompleteObject(EvalInfo &Info, const Expr *E, AccessKinds AK,
}
// Accesses of volatile-qualified objects are not allowed.
- BaseType = VD->getType();
if (BaseType.isVolatileQualified()) {
if (Info.getLangOpts().CPlusPlus) {
Info.Diag(E, diag::note_constexpr_access_volatile_obj, 1)
@@ -2019,8 +2442,16 @@ CompleteObject findCompleteObject(EvalInfo &Info, const Expr *E, AccessKinds AK,
// Unless we're looking at a local variable or argument in a constexpr call,
// the variable we're reading must be const.
if (!Frame) {
- assert(AK == AK_Read && "can't modify non-local");
- if (VD->isConstexpr()) {
+ if (Info.getLangOpts().CPlusPlus1y &&
+ VD == Info.EvaluatingDecl.dyn_cast<const ValueDecl *>()) {
+ // OK, we can read and modify an object if we're in the process of
+ // evaluating its initializer, because its lifetime began in this
+ // evaluation.
+ } else if (AK != AK_Read) {
+ // All the remaining cases only permit reading.
+ Info.Diag(E, diag::note_constexpr_modify_global);
+ return CompleteObject();
+ } else if (VD->isConstexpr()) {
// OK, we can read this variable.
} else if (BaseType->isIntegralOrEnumerationType()) {
if (!BaseType.isConstQualified()) {
@@ -2060,12 +2491,45 @@ CompleteObject findCompleteObject(EvalInfo &Info, const Expr *E, AccessKinds AK,
const Expr *Base = LVal.Base.dyn_cast<const Expr*>();
if (!Frame) {
- Info.Diag(E);
- return CompleteObject();
- }
+ if (const MaterializeTemporaryExpr *MTE =
+ dyn_cast<MaterializeTemporaryExpr>(Base)) {
+ assert(MTE->getStorageDuration() == SD_Static &&
+ "should have a frame for a non-global materialized temporary");
+
+ // Per C++1y [expr.const]p2:
+ // an lvalue-to-rvalue conversion [is not allowed unless it applies to]
+ // - a [...] glvalue of integral or enumeration type that refers to
+ // a non-volatile const object [...]
+ // [...]
+ // - a [...] glvalue of literal type that refers to a non-volatile
+ // object whose lifetime began within the evaluation of e.
+ //
+ // C++11 misses the 'began within the evaluation of e' check and
+ // instead allows all temporaries, including things like:
+ // int &&r = 1;
+ // int x = ++r;
+ // constexpr int k = r;
+ // Therefore we use the C++1y rules in C++11 too.
+ const ValueDecl *VD = Info.EvaluatingDecl.dyn_cast<const ValueDecl*>();
+ const ValueDecl *ED = MTE->getExtendingDecl();
+ if (!(BaseType.isConstQualified() &&
+ BaseType->isIntegralOrEnumerationType()) &&
+ !(VD && VD->getCanonicalDecl() == ED->getCanonicalDecl())) {
+ Info.Diag(E, diag::note_constexpr_access_static_temporary, 1) << AK;
+ Info.Note(MTE->getExprLoc(), diag::note_constexpr_temporary_here);
+ return CompleteObject();
+ }
- BaseType = Base->getType();
- BaseVal = &Frame->Temporaries[Base];
+ BaseVal = Info.Ctx.getMaterializedTemporaryValue(MTE, false);
+ assert(BaseVal && "got reference to unevaluated temporary");
+ } else {
+ Info.Diag(E);
+ return CompleteObject();
+ }
+ } else {
+ BaseVal = Frame->getTemporary(Base);
+ assert(BaseVal && "missing value for temporary");
+ }
// Volatile temporary objects cannot be accessed in constant expressions.
if (BaseType.isVolatileQualified()) {
@@ -2080,10 +2544,22 @@ CompleteObject findCompleteObject(EvalInfo &Info, const Expr *E, AccessKinds AK,
}
}
- // In C++1y, we can't safely access any mutable state when checking a
- // potential constant expression.
+ // During the construction of an object, it is not yet 'const'.
+ // FIXME: We don't set up EvaluatingDecl for local variables or temporaries,
+ // and this doesn't do quite the right thing for const subobjects of the
+ // object under construction.
+ if (LVal.getLValueBase() == Info.EvaluatingDecl) {
+ BaseType = Info.Ctx.getCanonicalType(BaseType);
+ BaseType.removeLocalConst();
+ }
+
+ // In C++1y, we can't safely access any mutable state when we might be
+ // evaluating after an unmodeled side effect or an evaluation failure.
+ //
+ // FIXME: Not all local state is mutable. Allow local constant subobjects
+ // to be read here (but take care with 'mutable' fields).
if (Frame && Info.getLangOpts().CPlusPlus1y &&
- Info.CheckingPotentialConstantExpression)
+ (Info.EvalStatus.HasSideEffects || Info.keepEvaluatingAfterFailure()))
return CompleteObject();
return CompleteObject(BaseVal, BaseType);
@@ -2159,6 +2635,124 @@ static bool isOverflowingIntegerType(ASTContext &Ctx, QualType T) {
}
namespace {
+struct CompoundAssignSubobjectHandler {
+ EvalInfo &Info;
+ const Expr *E;
+ QualType PromotedLHSType;
+ BinaryOperatorKind Opcode;
+ const APValue &RHS;
+
+ static const AccessKinds AccessKind = AK_Assign;
+
+ typedef bool result_type;
+
+ bool checkConst(QualType QT) {
+ // Assigning to a const object has undefined behavior.
+ if (QT.isConstQualified()) {
+ Info.Diag(E, diag::note_constexpr_modify_const_type) << QT;
+ return false;
+ }
+ return true;
+ }
+
+ bool failed() { return false; }
+ bool found(APValue &Subobj, QualType SubobjType) {
+ switch (Subobj.getKind()) {
+ case APValue::Int:
+ return found(Subobj.getInt(), SubobjType);
+ case APValue::Float:
+ return found(Subobj.getFloat(), SubobjType);
+ case APValue::ComplexInt:
+ case APValue::ComplexFloat:
+ // FIXME: Implement complex compound assignment.
+ Info.Diag(E);
+ return false;
+ case APValue::LValue:
+ return foundPointer(Subobj, SubobjType);
+ default:
+ // FIXME: can this happen?
+ Info.Diag(E);
+ return false;
+ }
+ }
+ bool found(APSInt &Value, QualType SubobjType) {
+ if (!checkConst(SubobjType))
+ return false;
+
+ if (!SubobjType->isIntegerType() || !RHS.isInt()) {
+ // We don't support compound assignment on integer-cast-to-pointer
+ // values.
+ Info.Diag(E);
+ return false;
+ }
+
+ APSInt LHS = HandleIntToIntCast(Info, E, PromotedLHSType,
+ SubobjType, Value);
+ if (!handleIntIntBinOp(Info, E, LHS, Opcode, RHS.getInt(), LHS))
+ return false;
+ Value = HandleIntToIntCast(Info, E, SubobjType, PromotedLHSType, LHS);
+ return true;
+ }
+ bool found(APFloat &Value, QualType SubobjType) {
+ return checkConst(SubobjType) &&
+ HandleFloatToFloatCast(Info, E, SubobjType, PromotedLHSType,
+ Value) &&
+ handleFloatFloatBinOp(Info, E, Value, Opcode, RHS.getFloat()) &&
+ HandleFloatToFloatCast(Info, E, PromotedLHSType, SubobjType, Value);
+ }
+ bool foundPointer(APValue &Subobj, QualType SubobjType) {
+ if (!checkConst(SubobjType))
+ return false;
+
+ QualType PointeeType;
+ if (const PointerType *PT = SubobjType->getAs<PointerType>())
+ PointeeType = PT->getPointeeType();
+
+ if (PointeeType.isNull() || !RHS.isInt() ||
+ (Opcode != BO_Add && Opcode != BO_Sub)) {
+ Info.Diag(E);
+ return false;
+ }
+
+ int64_t Offset = getExtValue(RHS.getInt());
+ if (Opcode == BO_Sub)
+ Offset = -Offset;
+
+ LValue LVal;
+ LVal.setFrom(Info.Ctx, Subobj);
+ if (!HandleLValueArrayAdjustment(Info, E, LVal, PointeeType, Offset))
+ return false;
+ LVal.moveInto(Subobj);
+ return true;
+ }
+ bool foundString(APValue &Subobj, QualType SubobjType, uint64_t Character) {
+ llvm_unreachable("shouldn't encounter string elements here");
+ }
+};
+} // end anonymous namespace
+
+const AccessKinds CompoundAssignSubobjectHandler::AccessKind;
+
+/// Perform a compound assignment of LVal <op>= RVal.
+static bool handleCompoundAssignment(
+ EvalInfo &Info, const Expr *E,
+ const LValue &LVal, QualType LValType, QualType PromotedLValType,
+ BinaryOperatorKind Opcode, const APValue &RVal) {
+ if (LVal.Designator.Invalid)
+ return false;
+
+ if (!Info.getLangOpts().CPlusPlus1y) {
+ Info.Diag(E);
+ return false;
+ }
+
+ CompleteObject Obj = findCompleteObject(Info, E, AK_Assign, LVal, LValType);
+ CompoundAssignSubobjectHandler Handler = { Info, E, PromotedLValType, Opcode,
+ RVal };
+ return Obj && findSubobject(Info, E, Obj, LVal.Designator, Handler);
+}
+
+namespace {
struct IncDecSubobjectHandler {
EvalInfo &Info;
const Expr *E;
@@ -2326,54 +2920,53 @@ static bool EvaluateObjectArgument(EvalInfo &Info, const Expr *Object,
/// lvalue referring to the result.
///
/// \param Info - Information about the ongoing evaluation.
-/// \param BO - The member pointer access operation.
-/// \param LV - Filled in with a reference to the resulting object.
+/// \param LV - An lvalue referring to the base of the member pointer.
+/// \param RHS - The member pointer expression.
/// \param IncludeMember - Specifies whether the member itself is included in
/// the resulting LValue subobject designator. This is not possible when
/// creating a bound member function.
/// \return The field or method declaration to which the member pointer refers,
/// or 0 if evaluation fails.
static const ValueDecl *HandleMemberPointerAccess(EvalInfo &Info,
- const BinaryOperator *BO,
+ QualType LVType,
LValue &LV,
+ const Expr *RHS,
bool IncludeMember = true) {
- assert(BO->getOpcode() == BO_PtrMemD || BO->getOpcode() == BO_PtrMemI);
-
- bool EvalObjOK = EvaluateObjectArgument(Info, BO->getLHS(), LV);
- if (!EvalObjOK && !Info.keepEvaluatingAfterFailure())
- return 0;
-
MemberPtr MemPtr;
- if (!EvaluateMemberPointer(BO->getRHS(), MemPtr, Info))
+ if (!EvaluateMemberPointer(RHS, MemPtr, Info))
return 0;
// C++11 [expr.mptr.oper]p6: If the second operand is the null pointer to
// member value, the behavior is undefined.
- if (!MemPtr.getDecl())
- return 0;
-
- if (!EvalObjOK)
+ if (!MemPtr.getDecl()) {
+ // FIXME: Specific diagnostic.
+ Info.Diag(RHS);
return 0;
+ }
if (MemPtr.isDerivedMember()) {
// This is a member of some derived class. Truncate LV appropriately.
// The end of the derived-to-base path for the base object must match the
// derived-to-base path for the member pointer.
if (LV.Designator.MostDerivedPathLength + MemPtr.Path.size() >
- LV.Designator.Entries.size())
+ LV.Designator.Entries.size()) {
+ Info.Diag(RHS);
return 0;
+ }
unsigned PathLengthToMember =
LV.Designator.Entries.size() - MemPtr.Path.size();
for (unsigned I = 0, N = MemPtr.Path.size(); I != N; ++I) {
const CXXRecordDecl *LVDecl = getAsBaseClass(
LV.Designator.Entries[PathLengthToMember + I]);
const CXXRecordDecl *MPDecl = MemPtr.Path[I];
- if (LVDecl->getCanonicalDecl() != MPDecl->getCanonicalDecl())
+ if (LVDecl->getCanonicalDecl() != MPDecl->getCanonicalDecl()) {
+ Info.Diag(RHS);
return 0;
+ }
}
// Truncate the lvalue to the appropriate derived class.
- if (!CastToDerivedClass(Info, BO, LV, MemPtr.getContainingRecord(),
+ if (!CastToDerivedClass(Info, RHS, LV, MemPtr.getContainingRecord(),
PathLengthToMember))
return 0;
} else if (!MemPtr.Path.empty()) {
@@ -2382,7 +2975,6 @@ static const ValueDecl *HandleMemberPointerAccess(EvalInfo &Info,
MemPtr.Path.size() + IncludeMember);
// Walk down to the appropriate base class.
- QualType LVType = BO->getLHS()->getType();
if (const PointerType *PT = LVType->getAs<PointerType>())
LVType = PT->getPointeeType();
const CXXRecordDecl *RD = LVType->getAsCXXRecordDecl();
@@ -2390,23 +2982,24 @@ static const ValueDecl *HandleMemberPointerAccess(EvalInfo &Info,
// The first class in the path is that of the lvalue.
for (unsigned I = 1, N = MemPtr.Path.size(); I != N; ++I) {
const CXXRecordDecl *Base = MemPtr.Path[N - I - 1];
- if (!HandleLValueDirectBase(Info, BO, LV, RD, Base))
+ if (!HandleLValueDirectBase(Info, RHS, LV, RD, Base))
return 0;
RD = Base;
}
// Finally cast to the class containing the member.
- if (!HandleLValueDirectBase(Info, BO, LV, RD, MemPtr.getContainingRecord()))
+ if (!HandleLValueDirectBase(Info, RHS, LV, RD,
+ MemPtr.getContainingRecord()))
return 0;
}
// Add the member. Note that we cannot build bound member functions here.
if (IncludeMember) {
if (const FieldDecl *FD = dyn_cast<FieldDecl>(MemPtr.getDecl())) {
- if (!HandleLValueMember(Info, BO, LV, FD))
+ if (!HandleLValueMember(Info, RHS, LV, FD))
return 0;
} else if (const IndirectFieldDecl *IFD =
dyn_cast<IndirectFieldDecl>(MemPtr.getDecl())) {
- if (!HandleLValueIndirectMember(Info, BO, LV, IFD))
+ if (!HandleLValueIndirectMember(Info, RHS, LV, IFD))
return 0;
} else {
llvm_unreachable("can't construct reference to bound member function");
@@ -2416,6 +3009,24 @@ static const ValueDecl *HandleMemberPointerAccess(EvalInfo &Info,
return MemPtr.getDecl();
}
+static const ValueDecl *HandleMemberPointerAccess(EvalInfo &Info,
+ const BinaryOperator *BO,
+ LValue &LV,
+ bool IncludeMember = true) {
+ assert(BO->getOpcode() == BO_PtrMemD || BO->getOpcode() == BO_PtrMemI);
+
+ if (!EvaluateObjectArgument(Info, BO->getLHS(), LV)) {
+ if (Info.keepEvaluatingAfterFailure()) {
+ MemberPtr MemPtr;
+ EvaluateMemberPointer(BO->getRHS(), MemPtr, Info);
+ }
+ return 0;
+ }
+
+ return HandleMemberPointerAccess(Info, BO->getLHS()->getType(), LV,
+ BO->getRHS(), IncludeMember);
+}
+
/// HandleBaseToDerivedCast - Apply the given base-to-derived cast operation on
/// the provided lvalue, which currently refers to the base object.
static bool HandleBaseToDerivedCast(EvalInfo &Info, const CastExpr *E,
@@ -2465,7 +3076,9 @@ enum EvalStmtResult {
/// Hit a 'continue' statement.
ESR_Continue,
/// Hit a 'break' statement.
- ESR_Break
+ ESR_Break,
+ /// Still scanning for 'case' or 'default' statement.
+ ESR_CaseNotFound
};
}
@@ -2477,7 +3090,14 @@ static bool EvaluateDecl(EvalInfo &Info, const Decl *D) {
LValue Result;
Result.set(VD, Info.CurrentCall->Index);
- APValue &Val = Info.CurrentCall->Temporaries[VD];
+ APValue &Val = Info.CurrentCall->createTemporary(VD, true);
+
+ if (!VD->getInit()) {
+ Info.Diag(D->getLocStart(), diag::note_constexpr_uninitialized)
+ << false << VD->getType();
+ Val = APValue();
+ return false;
+ }
if (!EvaluateInPlace(Val, Info, Result, VD->getInit())) {
// Wipe out any partially-computed value, to allow tracking that this
@@ -2493,18 +3113,21 @@ static bool EvaluateDecl(EvalInfo &Info, const Decl *D) {
/// Evaluate a condition (either a variable declaration or an expression).
static bool EvaluateCond(EvalInfo &Info, const VarDecl *CondDecl,
const Expr *Cond, bool &Result) {
+ FullExpressionRAII Scope(Info);
if (CondDecl && !EvaluateDecl(Info, CondDecl))
return false;
return EvaluateAsBooleanCondition(Cond, Result, Info);
}
static EvalStmtResult EvaluateStmt(APValue &Result, EvalInfo &Info,
- const Stmt *S);
+ const Stmt *S, const SwitchCase *SC = 0);
/// Evaluate the body of a loop, and translate the result as appropriate.
static EvalStmtResult EvaluateLoopBody(APValue &Result, EvalInfo &Info,
- const Stmt *Body) {
- switch (EvalStmtResult ESR = EvaluateStmt(Result, Info, Body)) {
+ const Stmt *Body,
+ const SwitchCase *Case = 0) {
+ BlockScopeRAII Scope(Info);
+ switch (EvalStmtResult ESR = EvaluateStmt(Result, Info, Body, Case)) {
case ESR_Break:
return ESR_Succeeded;
case ESR_Succeeded:
@@ -2512,21 +3135,149 @@ static EvalStmtResult EvaluateLoopBody(APValue &Result, EvalInfo &Info,
return ESR_Continue;
case ESR_Failed:
case ESR_Returned:
+ case ESR_CaseNotFound:
+ return ESR;
+ }
+ llvm_unreachable("Invalid EvalStmtResult!");
+}
+
+/// Evaluate a switch statement.
+static EvalStmtResult EvaluateSwitch(APValue &Result, EvalInfo &Info,
+ const SwitchStmt *SS) {
+ BlockScopeRAII Scope(Info);
+
+ // Evaluate the switch condition.
+ APSInt Value;
+ {
+ FullExpressionRAII Scope(Info);
+ if (SS->getConditionVariable() &&
+ !EvaluateDecl(Info, SS->getConditionVariable()))
+ return ESR_Failed;
+ if (!EvaluateInteger(SS->getCond(), Value, Info))
+ return ESR_Failed;
+ }
+
+ // Find the switch case corresponding to the value of the condition.
+ // FIXME: Cache this lookup.
+ const SwitchCase *Found = 0;
+ for (const SwitchCase *SC = SS->getSwitchCaseList(); SC;
+ SC = SC->getNextSwitchCase()) {
+ if (isa<DefaultStmt>(SC)) {
+ Found = SC;
+ continue;
+ }
+
+ const CaseStmt *CS = cast<CaseStmt>(SC);
+ APSInt LHS = CS->getLHS()->EvaluateKnownConstInt(Info.Ctx);
+ APSInt RHS = CS->getRHS() ? CS->getRHS()->EvaluateKnownConstInt(Info.Ctx)
+ : LHS;
+ if (LHS <= Value && Value <= RHS) {
+ Found = SC;
+ break;
+ }
+ }
+
+ if (!Found)
+ return ESR_Succeeded;
+
+ // Search the switch body for the switch case and evaluate it from there.
+ switch (EvalStmtResult ESR = EvaluateStmt(Result, Info, SS->getBody(), Found)) {
+ case ESR_Break:
+ return ESR_Succeeded;
+ case ESR_Succeeded:
+ case ESR_Continue:
+ case ESR_Failed:
+ case ESR_Returned:
return ESR;
+ case ESR_CaseNotFound:
+ // This can only happen if the switch case is nested within a statement
+ // expression. We have no intention of supporting that.
+ Info.Diag(Found->getLocStart(), diag::note_constexpr_stmt_expr_unsupported);
+ return ESR_Failed;
}
llvm_unreachable("Invalid EvalStmtResult!");
}
// Evaluate a statement.
static EvalStmtResult EvaluateStmt(APValue &Result, EvalInfo &Info,
- const Stmt *S) {
- // FIXME: Mark all temporaries in the current frame as destroyed at
- // the end of each full-expression.
+ const Stmt *S, const SwitchCase *Case) {
+ if (!Info.nextStep(S))
+ return ESR_Failed;
+
+ // If we're hunting down a 'case' or 'default' label, recurse through
+ // substatements until we hit the label.
+ if (Case) {
+ // FIXME: We don't start the lifetime of objects whose initialization we
+ // jump over. However, such objects must be of class type with a trivial
+ // default constructor that initialize all subobjects, so must be empty,
+ // so this almost never matters.
+ switch (S->getStmtClass()) {
+ case Stmt::CompoundStmtClass:
+ // FIXME: Precompute which substatement of a compound statement we
+ // would jump to, and go straight there rather than performing a
+ // linear scan each time.
+ case Stmt::LabelStmtClass:
+ case Stmt::AttributedStmtClass:
+ case Stmt::DoStmtClass:
+ break;
+
+ case Stmt::CaseStmtClass:
+ case Stmt::DefaultStmtClass:
+ if (Case == S)
+ Case = 0;
+ break;
+
+ case Stmt::IfStmtClass: {
+ // FIXME: Precompute which side of an 'if' we would jump to, and go
+ // straight there rather than scanning both sides.
+ const IfStmt *IS = cast<IfStmt>(S);
+
+ // Wrap the evaluation in a block scope, in case it's a DeclStmt
+ // preceded by our switch label.
+ BlockScopeRAII Scope(Info);
+
+ EvalStmtResult ESR = EvaluateStmt(Result, Info, IS->getThen(), Case);
+ if (ESR != ESR_CaseNotFound || !IS->getElse())
+ return ESR;
+ return EvaluateStmt(Result, Info, IS->getElse(), Case);
+ }
+
+ case Stmt::WhileStmtClass: {
+ EvalStmtResult ESR =
+ EvaluateLoopBody(Result, Info, cast<WhileStmt>(S)->getBody(), Case);
+ if (ESR != ESR_Continue)
+ return ESR;
+ break;
+ }
+
+ case Stmt::ForStmtClass: {
+ const ForStmt *FS = cast<ForStmt>(S);
+ EvalStmtResult ESR =
+ EvaluateLoopBody(Result, Info, FS->getBody(), Case);
+ if (ESR != ESR_Continue)
+ return ESR;
+ if (FS->getInc()) {
+ FullExpressionRAII IncScope(Info);
+ if (!EvaluateIgnoredValue(Info, FS->getInc()))
+ return ESR_Failed;
+ }
+ break;
+ }
+
+ case Stmt::DeclStmtClass:
+ // FIXME: If the variable has initialization that can't be jumped over,
+ // bail out of any immediately-surrounding compound-statement too.
+ default:
+ return ESR_CaseNotFound;
+ }
+ }
+
switch (S->getStmtClass()) {
default:
if (const Expr *E = dyn_cast<Expr>(S)) {
// Don't bother evaluating beyond an expression-statement which couldn't
// be evaluated.
+ FullExpressionRAII Scope(Info);
if (!EvaluateIgnoredValue(Info, E))
return ESR_Failed;
return ESR_Succeeded;
@@ -2541,34 +3292,45 @@ static EvalStmtResult EvaluateStmt(APValue &Result, EvalInfo &Info,
case Stmt::DeclStmtClass: {
const DeclStmt *DS = cast<DeclStmt>(S);
for (DeclStmt::const_decl_iterator DclIt = DS->decl_begin(),
- DclEnd = DS->decl_end(); DclIt != DclEnd; ++DclIt)
+ DclEnd = DS->decl_end(); DclIt != DclEnd; ++DclIt) {
+ // Each declaration initialization is its own full-expression.
+ // FIXME: This isn't quite right; if we're performing aggregate
+ // initialization, each braced subexpression is its own full-expression.
+ FullExpressionRAII Scope(Info);
if (!EvaluateDecl(Info, *DclIt) && !Info.keepEvaluatingAfterFailure())
return ESR_Failed;
+ }
return ESR_Succeeded;
}
case Stmt::ReturnStmtClass: {
const Expr *RetExpr = cast<ReturnStmt>(S)->getRetValue();
+ FullExpressionRAII Scope(Info);
if (RetExpr && !Evaluate(Result, Info, RetExpr))
return ESR_Failed;
return ESR_Returned;
}
case Stmt::CompoundStmtClass: {
+ BlockScopeRAII Scope(Info);
+
const CompoundStmt *CS = cast<CompoundStmt>(S);
for (CompoundStmt::const_body_iterator BI = CS->body_begin(),
BE = CS->body_end(); BI != BE; ++BI) {
- EvalStmtResult ESR = EvaluateStmt(Result, Info, *BI);
- if (ESR != ESR_Succeeded)
+ EvalStmtResult ESR = EvaluateStmt(Result, Info, *BI, Case);
+ if (ESR == ESR_Succeeded)
+ Case = 0;
+ else if (ESR != ESR_CaseNotFound)
return ESR;
}
- return ESR_Succeeded;
+ return Case ? ESR_CaseNotFound : ESR_Succeeded;
}
case Stmt::IfStmtClass: {
const IfStmt *IS = cast<IfStmt>(S);
// Evaluate the condition, as either a var decl or as an expression.
+ BlockScopeRAII Scope(Info);
bool Cond;
if (!EvaluateCond(Info, IS->getConditionVariable(), IS->getCond(), Cond))
return ESR_Failed;
@@ -2584,6 +3346,7 @@ static EvalStmtResult EvaluateStmt(APValue &Result, EvalInfo &Info,
case Stmt::WhileStmtClass: {
const WhileStmt *WS = cast<WhileStmt>(S);
while (true) {
+ BlockScopeRAII Scope(Info);
bool Continue;
if (!EvaluateCond(Info, WS->getConditionVariable(), WS->getCond(),
Continue))
@@ -2602,10 +3365,12 @@ static EvalStmtResult EvaluateStmt(APValue &Result, EvalInfo &Info,
const DoStmt *DS = cast<DoStmt>(S);
bool Continue;
do {
- EvalStmtResult ESR = EvaluateLoopBody(Result, Info, DS->getBody());
+ EvalStmtResult ESR = EvaluateLoopBody(Result, Info, DS->getBody(), Case);
if (ESR != ESR_Continue)
return ESR;
+ Case = 0;
+ FullExpressionRAII CondScope(Info);
if (!EvaluateAsBooleanCondition(DS->getCond(), Continue, Info))
return ESR_Failed;
} while (Continue);
@@ -2614,12 +3379,14 @@ static EvalStmtResult EvaluateStmt(APValue &Result, EvalInfo &Info,
case Stmt::ForStmtClass: {
const ForStmt *FS = cast<ForStmt>(S);
+ BlockScopeRAII Scope(Info);
if (FS->getInit()) {
EvalStmtResult ESR = EvaluateStmt(Result, Info, FS->getInit());
if (ESR != ESR_Succeeded)
return ESR;
}
while (true) {
+ BlockScopeRAII Scope(Info);
bool Continue = true;
if (FS->getCond() && !EvaluateCond(Info, FS->getConditionVariable(),
FS->getCond(), Continue))
@@ -2631,14 +3398,18 @@ static EvalStmtResult EvaluateStmt(APValue &Result, EvalInfo &Info,
if (ESR != ESR_Continue)
return ESR;
- if (FS->getInc() && !EvaluateIgnoredValue(Info, FS->getInc()))
- return ESR_Failed;
+ if (FS->getInc()) {
+ FullExpressionRAII IncScope(Info);
+ if (!EvaluateIgnoredValue(Info, FS->getInc()))
+ return ESR_Failed;
+ }
}
return ESR_Succeeded;
}
case Stmt::CXXForRangeStmtClass: {
const CXXForRangeStmt *FS = cast<CXXForRangeStmt>(S);
+ BlockScopeRAII Scope(Info);
// Initialize the __range variable.
EvalStmtResult ESR = EvaluateStmt(Result, Info, FS->getRangeStmt());
@@ -2652,13 +3423,17 @@ static EvalStmtResult EvaluateStmt(APValue &Result, EvalInfo &Info,
while (true) {
// Condition: __begin != __end.
- bool Continue = true;
- if (!EvaluateAsBooleanCondition(FS->getCond(), Continue, Info))
- return ESR_Failed;
- if (!Continue)
- break;
+ {
+ bool Continue = true;
+ FullExpressionRAII CondExpr(Info);
+ if (!EvaluateAsBooleanCondition(FS->getCond(), Continue, Info))
+ return ESR_Failed;
+ if (!Continue)
+ break;
+ }
// User's variable declaration, initialized by *__begin.
+ BlockScopeRAII InnerScope(Info);
ESR = EvaluateStmt(Result, Info, FS->getLoopVarStmt());
if (ESR != ESR_Succeeded)
return ESR;
@@ -2676,11 +3451,27 @@ static EvalStmtResult EvaluateStmt(APValue &Result, EvalInfo &Info,
return ESR_Succeeded;
}
+ case Stmt::SwitchStmtClass:
+ return EvaluateSwitch(Result, Info, cast<SwitchStmt>(S));
+
case Stmt::ContinueStmtClass:
return ESR_Continue;
case Stmt::BreakStmtClass:
return ESR_Break;
+
+ case Stmt::LabelStmtClass:
+ return EvaluateStmt(Result, Info, cast<LabelStmt>(S)->getSubStmt(), Case);
+
+ case Stmt::AttributedStmtClass:
+ // As a general principle, C++11 attributes can be ignored without
+ // any semantic impact.
+ return EvaluateStmt(Result, Info, cast<AttributedStmt>(S)->getSubStmt(),
+ Case);
+
+ case Stmt::CaseStmtClass:
+ case Stmt::DefaultStmtClass:
+ return EvaluateStmt(Result, Info, cast<SwitchCase>(S)->getSubStmt(), Case);
}
}
@@ -2718,10 +3509,15 @@ static bool CheckConstexprFunction(EvalInfo &Info, SourceLocation CallLoc,
const FunctionDecl *Definition) {
// Potential constant expressions can contain calls to declared, but not yet
// defined, constexpr functions.
- if (Info.CheckingPotentialConstantExpression && !Definition &&
+ if (Info.checkingPotentialConstantExpression() && !Definition &&
Declaration->isConstexpr())
return false;
+ // Bail out with no diagnostic if the function declaration itself is invalid.
+ // We will have produced a relevant diagnostic while parsing it.
+ if (Declaration->isInvalidDecl())
+ return false;
+
// Can we evaluate this function call?
if (Definition && Definition->isConstexpr() && !Definition->isInvalidDecl())
return true;
@@ -2774,6 +3570,27 @@ static bool HandleFunctionCall(SourceLocation CallLoc,
return false;
CallStackFrame Frame(Info, CallLoc, Callee, This, ArgValues.data());
+
+ // For a trivial copy or move assignment, perform an APValue copy. This is
+ // essential for unions, where the operations performed by the assignment
+ // operator cannot be represented as statements.
+ const CXXMethodDecl *MD = dyn_cast<CXXMethodDecl>(Callee);
+ if (MD && MD->isDefaulted() && MD->isTrivial()) {
+ assert(This &&
+ (MD->isCopyAssignmentOperator() || MD->isMoveAssignmentOperator()));
+ LValue RHS;
+ RHS.setFrom(Info.Ctx, ArgValues[0]);
+ APValue RHSValue;
+ if (!handleLValueToRValueConversion(Info, Args[0], Args[0]->getType(),
+ RHS, RHSValue))
+ return false;
+ if (!handleAssignment(Info, Args[0], *This, MD->getThisType(Info.Ctx),
+ RHSValue))
+ return false;
+ This->moveInto(Result);
+ return true;
+ }
+
EvalStmtResult ESR = EvaluateStmt(Result, Info, Body);
if (ESR == ESR_Succeeded) {
if (Callee->getResultType()->isVoidType())
@@ -2806,8 +3623,11 @@ static bool HandleConstructorCall(SourceLocation CallLoc, const LValue &This,
// If it's a delegating constructor, just delegate.
if (Definition->isDelegatingConstructor()) {
CXXConstructorDecl::init_const_iterator I = Definition->init_begin();
- if (!EvaluateInPlace(Result, Info, This, (*I)->getInit()))
- return false;
+ {
+ FullExpressionRAII InitScope(Info);
+ if (!EvaluateInPlace(Result, Info, This, (*I)->getInit()))
+ return false;
+ }
return EvaluateStmt(Result, Info, Definition->getBody()) != ESR_Failed;
}
@@ -2831,6 +3651,9 @@ static bool HandleConstructorCall(SourceLocation CallLoc, const LValue &This,
if (RD->isInvalidDecl()) return false;
const ASTRecordLayout &Layout = Info.Ctx.getASTRecordLayout(RD);
+ // A scope for temporaries lifetime-extended by reference members.
+ BlockScopeRAII LifetimeExtendedScope(Info);
+
bool Success = true;
unsigned BasesSeen = 0;
#ifndef NDEBUG
@@ -2842,6 +3665,7 @@ static bool HandleConstructorCall(SourceLocation CallLoc, const LValue &This,
APValue *Value = &Result;
// Determine the subobject to initialize.
+ FieldDecl *FD = 0;
if ((*I)->isBaseInitializer()) {
QualType BaseType((*I)->getBaseClass(), 0);
#ifndef NDEBUG
@@ -2856,7 +3680,7 @@ static bool HandleConstructorCall(SourceLocation CallLoc, const LValue &This,
BaseType->getAsCXXRecordDecl(), &Layout))
return false;
Value = &Result.getStructBase(BasesSeen++);
- } else if (FieldDecl *FD = (*I)->getMember()) {
+ } else if ((FD = (*I)->getMember())) {
if (!HandleLValueMember(Info, (*I)->getInit(), Subobject, FD, &Layout))
return false;
if (RD->isUnion()) {
@@ -2871,7 +3695,7 @@ static bool HandleConstructorCall(SourceLocation CallLoc, const LValue &This,
for (IndirectFieldDecl::chain_iterator C = IFD->chain_begin(),
CE = IFD->chain_end();
C != CE; ++C) {
- FieldDecl *FD = cast<FieldDecl>(*C);
+ FD = cast<FieldDecl>(*C);
CXXRecordDecl *CD = cast<CXXRecordDecl>(FD->getParent());
// Switch the union field if it differs. This happens if we had
// preceding zero-initialization, and we're now initializing a union
@@ -2897,9 +3721,10 @@ static bool HandleConstructorCall(SourceLocation CallLoc, const LValue &This,
llvm_unreachable("unknown base initializer kind");
}
- if (!EvaluateInPlace(*Value, Info, Subobject, (*I)->getInit(),
- (*I)->isBaseInitializer()
- ? CCEK_Constant : CCEK_MemberInit)) {
+ FullExpressionRAII InitScope(Info);
+ if (!EvaluateInPlace(*Value, Info, Subobject, (*I)->getInit()) ||
+ (FD && FD->isBitField() && !truncateBitfieldValue(Info, (*I)->getInit(),
+ *Value, FD))) {
// If we're checking for a potential constant expression, evaluate all
// initializers even if some of them fail.
if (!Info.keepEvaluatingAfterFailure())
@@ -2934,7 +3759,7 @@ private:
// expression, then the conditional operator is not either.
template<typename ConditionalOperator>
void CheckPotentialConstantConditional(const ConditionalOperator *E) {
- assert(Info.CheckingPotentialConstantExpression);
+ assert(Info.checkingPotentialConstantExpression());
// Speculatively evaluate both arms.
{
@@ -2959,7 +3784,7 @@ private:
bool HandleConditionalOperator(const ConditionalOperator *E) {
bool BoolResult;
if (!EvaluateAsBooleanCondition(E->getCond(), BoolResult, Info)) {
- if (Info.CheckingPotentialConstantExpression)
+ if (Info.checkingPotentialConstantExpression())
CheckPotentialConstantConditional(E);
return false;
}
@@ -3008,15 +3833,19 @@ public:
RetTy VisitUnaryPlus(const UnaryOperator *E)
{ return StmtVisitorTy::Visit(E->getSubExpr()); }
RetTy VisitChooseExpr(const ChooseExpr *E)
- { return StmtVisitorTy::Visit(E->getChosenSubExpr(Info.Ctx)); }
+ { return StmtVisitorTy::Visit(E->getChosenSubExpr()); }
RetTy VisitGenericSelectionExpr(const GenericSelectionExpr *E)
{ return StmtVisitorTy::Visit(E->getResultExpr()); }
RetTy VisitSubstNonTypeTemplateParmExpr(const SubstNonTypeTemplateParmExpr *E)
{ return StmtVisitorTy::Visit(E->getReplacement()); }
RetTy VisitCXXDefaultArgExpr(const CXXDefaultArgExpr *E)
{ return StmtVisitorTy::Visit(E->getExpr()); }
- RetTy VisitCXXDefaultInitExpr(const CXXDefaultInitExpr *E)
- { return StmtVisitorTy::Visit(E->getExpr()); }
+ RetTy VisitCXXDefaultInitExpr(const CXXDefaultInitExpr *E) {
+ // The initializer may not have been parsed yet, or might be erroneous.
+ if (!E->getExpr())
+ return Error(E);
+ return StmtVisitorTy::Visit(E->getExpr());
+ }
// We cannot create any objects for which cleanups are required, so there is
// nothing to do here; all cleanups must come from unevaluated subexpressions.
RetTy VisitExprWithCleanups(const ExprWithCleanups *E)
@@ -3056,7 +3885,7 @@ public:
RetTy VisitBinaryConditionalOperator(const BinaryConditionalOperator *E) {
// Evaluate and cache the common expression. We treat it as a temporary,
// even though it's not quite the same thing.
- if (!Evaluate(Info.CurrentCall->Temporaries[E->getOpaqueValue()],
+ if (!Evaluate(Info.CurrentCall->createTemporary(E->getOpaqueValue(), false),
Info, E->getCommon()))
return false;
@@ -3076,33 +3905,30 @@ public:
// Always assume __builtin_constant_p(...) ? ... : ... is a potential
// constant expression; we can't check whether it's potentially foldable.
- if (Info.CheckingPotentialConstantExpression && IsBcpCall)
+ if (Info.checkingPotentialConstantExpression() && IsBcpCall)
return false;
- FoldConstant Fold(Info);
-
- if (!HandleConditionalOperator(E))
+ FoldConstant Fold(Info, IsBcpCall);
+ if (!HandleConditionalOperator(E)) {
+ Fold.keepDiagnostics();
return false;
-
- if (IsBcpCall)
- Fold.Fold(Info);
+ }
return true;
}
RetTy VisitOpaqueValueExpr(const OpaqueValueExpr *E) {
- APValue &Value = Info.CurrentCall->Temporaries[E];
- if (Value.isUninit()) {
- const Expr *Source = E->getSourceExpr();
- if (!Source)
- return Error(E);
- if (Source == E) { // sanity checking.
- assert(0 && "OpaqueValueExpr recursively refers to itself");
- return Error(E);
- }
- return StmtVisitorTy::Visit(Source);
+ if (APValue *Value = Info.CurrentCall->getTemporary(E))
+ return DerivedSuccess(*Value, E);
+
+ const Expr *Source = E->getSourceExpr();
+ if (!Source)
+ return Error(E);
+ if (Source == E) { // sanity checking.
+ assert(0 && "OpaqueValueExpr recursively refers to itself");
+ return Error(E);
}
- return DerivedSuccess(Value, E);
+ return StmtVisitorTy::Visit(Source);
}
RetTy VisitCallExpr(const CallExpr *E) {
@@ -3240,8 +4066,13 @@ public:
default:
break;
- case CK_AtomicToNonAtomic:
- case CK_NonAtomicToAtomic:
+ case CK_AtomicToNonAtomic: {
+ APValue AtomicVal;
+ if (!EvaluateAtomic(E->getSubExpr(), AtomicVal, Info))
+ return false;
+ return DerivedSuccess(AtomicVal, E);
+ }
+
case CK_NoOp:
case CK_UserDefinedConversion:
return StmtVisitorTy::Visit(E->getSubExpr());
@@ -3282,6 +4113,41 @@ public:
return DerivedSuccess(RVal, UO);
}
+ RetTy VisitStmtExpr(const StmtExpr *E) {
+ // We will have checked the full-expressions inside the statement expression
+ // when they were completed, and don't need to check them again now.
+ if (Info.checkingForOverflow())
+ return Error(E);
+
+ BlockScopeRAII Scope(Info);
+ const CompoundStmt *CS = E->getSubStmt();
+ for (CompoundStmt::const_body_iterator BI = CS->body_begin(),
+ BE = CS->body_end();
+ /**/; ++BI) {
+ if (BI + 1 == BE) {
+ const Expr *FinalExpr = dyn_cast<Expr>(*BI);
+ if (!FinalExpr) {
+ Info.Diag((*BI)->getLocStart(),
+ diag::note_constexpr_stmt_expr_unsupported);
+ return false;
+ }
+ return this->Visit(FinalExpr);
+ }
+
+ APValue ReturnValue;
+ EvalStmtResult ESR = EvaluateStmt(ReturnValue, Info, *BI);
+ if (ESR != ESR_Succeeded) {
+ // FIXME: If the statement-expression terminated due to 'return',
+ // 'break', or 'continue', it would be nice to propagate that to
+ // the outer statement evaluation rather than bailing out.
+ if (ESR != ESR_Failed)
+ Info.Diag((*BI)->getLocStart(),
+ diag::note_constexpr_stmt_expr_unsupported);
+ return false;
+ }
+ }
+ }
+
/// Visit a value which is evaluated, but whose value is ignored.
void VisitIgnoredValue(const Expr *E) {
EvaluateIgnoredValue(Info, E);
@@ -3374,24 +4240,14 @@ public:
return ExprEvaluatorBaseTy::VisitCastExpr(E);
case CK_DerivedToBase:
- case CK_UncheckedDerivedToBase: {
+ case CK_UncheckedDerivedToBase:
if (!this->Visit(E->getSubExpr()))
return false;
// Now figure out the necessary offset to add to the base LV to get from
// the derived class to the base class.
- QualType Type = E->getSubExpr()->getType();
-
- for (CastExpr::path_const_iterator PathI = E->path_begin(),
- PathE = E->path_end(); PathI != PathE; ++PathI) {
- if (!HandleLValueBase(this->Info, E, Result, Type->getAsCXXRecordDecl(),
- *PathI))
- return false;
- Type = (*PathI)->getType();
- }
-
- return true;
- }
+ return HandleLValueBasePath(this->Info, E, E->getSubExpr()->getType(),
+ Result);
}
}
};
@@ -3420,8 +4276,12 @@ public:
// * BlockExpr
// * CallExpr for a MakeStringConstant builtin
// - Locals and temporaries
+// * MaterializeTemporaryExpr
// * Any Expr, with a CallIndex indicating the function in which the temporary
-// was evaluated.
+// was evaluated, for cases where the MaterializeTemporaryExpr is missing
+// from the AST (FIXME).
+// * A MaterializeTemporaryExpr that has static storage duration, with no
+// CallIndex, for a lifetime-extended temporary.
// plus an offset in bytes.
//===----------------------------------------------------------------------===//
namespace {
@@ -3511,17 +4371,78 @@ bool LValueExprEvaluator::VisitVarDecl(const Expr *E, const VarDecl *VD) {
APValue *V;
if (!evaluateVarDeclInit(Info, E, VD, Frame, V))
return false;
+ if (V->isUninit()) {
+ if (!Info.checkingPotentialConstantExpression())
+ Info.Diag(E, diag::note_constexpr_use_uninit_reference);
+ return false;
+ }
return Success(*V, E);
}
bool LValueExprEvaluator::VisitMaterializeTemporaryExpr(
const MaterializeTemporaryExpr *E) {
- if (E->getType()->isRecordType())
- return EvaluateTemporary(E->GetTemporaryExpr(), Result, Info);
+ // Walk through the expression to find the materialized temporary itself.
+ SmallVector<const Expr *, 2> CommaLHSs;
+ SmallVector<SubobjectAdjustment, 2> Adjustments;
+ const Expr *Inner = E->GetTemporaryExpr()->
+ skipRValueSubobjectAdjustments(CommaLHSs, Adjustments);
+
+ // If we passed any comma operators, evaluate their LHSs.
+ for (unsigned I = 0, N = CommaLHSs.size(); I != N; ++I)
+ if (!EvaluateIgnoredValue(Info, CommaLHSs[I]))
+ return false;
+
+ // A materialized temporary with static storage duration can appear within the
+ // result of a constant expression evaluation, so we need to preserve its
+ // value for use outside this evaluation.
+ APValue *Value;
+ if (E->getStorageDuration() == SD_Static) {
+ Value = Info.Ctx.getMaterializedTemporaryValue(E, true);
+ *Value = APValue();
+ Result.set(E);
+ } else {
+ Value = &Info.CurrentCall->
+ createTemporary(E, E->getStorageDuration() == SD_Automatic);
+ Result.set(E, Info.CurrentCall->Index);
+ }
- Result.set(E, Info.CurrentCall->Index);
- return EvaluateInPlace(Info.CurrentCall->Temporaries[E], Info,
- Result, E->GetTemporaryExpr());
+ QualType Type = Inner->getType();
+
+ // Materialize the temporary itself.
+ if (!EvaluateInPlace(*Value, Info, Result, Inner) ||
+ (E->getStorageDuration() == SD_Static &&
+ !CheckConstantExpression(Info, E->getExprLoc(), Type, *Value))) {
+ *Value = APValue();
+ return false;
+ }
+
+ // Adjust our lvalue to refer to the desired subobject.
+ for (unsigned I = Adjustments.size(); I != 0; /**/) {
+ --I;
+ switch (Adjustments[I].Kind) {
+ case SubobjectAdjustment::DerivedToBaseAdjustment:
+ if (!HandleLValueBasePath(Info, Adjustments[I].DerivedToBase.BasePath,
+ Type, Result))
+ return false;
+ Type = Adjustments[I].DerivedToBase.BasePath->getType();
+ break;
+
+ case SubobjectAdjustment::FieldAdjustment:
+ if (!HandleLValueMember(Info, E, Result, Adjustments[I].Field))
+ return false;
+ Type = Adjustments[I].Field->getType();
+ break;
+
+ case SubobjectAdjustment::MemberPointerAdjustment:
+ if (!HandleMemberPointerAccess(this->Info, Type, Result,
+ Adjustments[I].Ptr.RHS))
+ return false;
+ Type = Adjustments[I].Ptr.MPT->getPointeeType();
+ break;
+ }
+ }
+
+ return true;
}
bool
@@ -3576,11 +4497,9 @@ bool LValueExprEvaluator::VisitArraySubscriptExpr(const ArraySubscriptExpr *E) {
APSInt Index;
if (!EvaluateInteger(E->getIdx(), Index, Info))
return false;
- int64_t IndexValue
- = Index.isSigned() ? Index.getSExtValue()
- : static_cast<int64_t>(Index.getZExtValue());
- return HandleLValueArrayAdjustment(Info, E, Result, E->getType(), IndexValue);
+ return HandleLValueArrayAdjustment(Info, E, Result, E->getType(),
+ getExtValue(Index));
}
bool LValueExprEvaluator::VisitUnaryDeref(const UnaryOperator *E) {
@@ -3634,14 +4553,10 @@ bool LValueExprEvaluator::VisitCompoundAssignOperator(
if (!Evaluate(RHS, this->Info, CAO->getRHS()))
return false;
- // FIXME:
- //return handleCompoundAssignment(
- // this->Info, CAO,
- // Result, CAO->getLHS()->getType(), CAO->getComputationLHSType(),
- // RHS, CAO->getRHS()->getType(),
- // CAO->getOpForCompoundAssignment(CAO->getOpcode()),
- // CAO->getComputationResultType());
- return Error(CAO);
+ return handleCompoundAssignment(
+ this->Info, CAO,
+ Result, CAO->getLHS()->getType(), CAO->getComputationLHSType(),
+ CAO->getOpForCompoundAssignment(CAO->getOpcode()), RHS);
}
bool LValueExprEvaluator::VisitBinAssign(const BinaryOperator *E) {
@@ -3705,6 +4620,9 @@ public:
return Error(E);
}
bool VisitCXXThisExpr(const CXXThisExpr *E) {
+ // Can't look at 'this' when checking a potential constant expression.
+ if (Info.checkingPotentialConstantExpression())
+ return false;
if (!Info.CurrentCall->This)
return Error(E);
Result = *Info.CurrentCall->This;
@@ -3737,9 +4655,8 @@ bool PointerExprEvaluator::VisitBinaryOperator(const BinaryOperator *E) {
llvm::APSInt Offset;
if (!EvaluateInteger(IExp, Offset, Info) || !EvalPtrOK)
return false;
- int64_t AdditionalOffset
- = Offset.isSigned() ? Offset.getSExtValue()
- : static_cast<int64_t>(Offset.getZExtValue());
+
+ int64_t AdditionalOffset = getExtValue(Offset);
if (E->getOpcode() == BO_Sub)
AdditionalOffset = -AdditionalOffset;
@@ -3779,7 +4696,7 @@ bool PointerExprEvaluator::VisitCastExpr(const CastExpr* E) {
return true;
case CK_DerivedToBase:
- case CK_UncheckedDerivedToBase: {
+ case CK_UncheckedDerivedToBase:
if (!EvaluatePointer(E->getSubExpr(), Result, Info))
return false;
if (!Result.Base && Result.Offset.isZero())
@@ -3787,19 +4704,9 @@ bool PointerExprEvaluator::VisitCastExpr(const CastExpr* E) {
// Now figure out the necessary offset to add to the base LV to get from
// the derived class to the base class.
- QualType Type =
- E->getSubExpr()->getType()->castAs<PointerType>()->getPointeeType();
-
- for (CastExpr::path_const_iterator PathI = E->path_begin(),
- PathE = E->path_end(); PathI != PathE; ++PathI) {
- if (!HandleLValueBase(Info, E, Result, Type->getAsCXXRecordDecl(),
- *PathI))
- return false;
- Type = (*PathI)->getType();
- }
-
- return true;
- }
+ return HandleLValueBasePath(Info, E, E->getSubExpr()->getType()->
+ castAs<PointerType>()->getPointeeType(),
+ Result);
case CK_BaseToDerived:
if (!Visit(E->getSubExpr()))
@@ -3839,7 +4746,7 @@ bool PointerExprEvaluator::VisitCastExpr(const CastExpr* E) {
return false;
} else {
Result.set(SubExpr, Info.CurrentCall->Index);
- if (!EvaluateInPlace(Info.CurrentCall->Temporaries[SubExpr],
+ if (!EvaluateInPlace(Info.CurrentCall->createTemporary(SubExpr, false),
Info, Result, SubExpr))
return false;
}
@@ -3862,7 +4769,13 @@ bool PointerExprEvaluator::VisitCallExpr(const CallExpr *E) {
if (IsStringLiteralCall(E))
return Success(E);
- return ExprEvaluatorBaseTy::VisitCallExpr(E);
+ switch (E->isBuiltinCall()) {
+ case Builtin::BI__builtin_addressof:
+ return EvaluateLValue(E->getArg(0), Result, Info);
+
+ default:
+ return ExprEvaluatorBaseTy::VisitCallExpr(E);
+ }
}
//===----------------------------------------------------------------------===//
@@ -3976,6 +4889,7 @@ namespace {
bool VisitCastExpr(const CastExpr *E);
bool VisitInitListExpr(const InitListExpr *E);
bool VisitCXXConstructExpr(const CXXConstructExpr *E);
+ bool VisitCXXStdInitializerListExpr(const CXXStdInitializerListExpr *E);
};
}
@@ -4091,10 +5005,6 @@ bool RecordExprEvaluator::VisitCastExpr(const CastExpr *E) {
}
bool RecordExprEvaluator::VisitInitListExpr(const InitListExpr *E) {
- // Cannot constant-evaluate std::initializer_list inits.
- if (E->initializesStdInitializerList())
- return false;
-
const RecordDecl *RD = E->getType()->castAs<RecordType>()->getDecl();
if (RD->isInvalidDecl()) return false;
const ASTRecordLayout &Layout = Info.Ctx.getASTRecordLayout(RD);
@@ -4156,8 +5066,10 @@ bool RecordExprEvaluator::VisitInitListExpr(const InitListExpr *E) {
ThisOverrideRAII ThisOverride(*Info.CurrentCall, &This,
isa<CXXDefaultInitExpr>(Init));
- if (!EvaluateInPlace(Result.getStructField(Field->getFieldIndex()), Info,
- Subobject, Init)) {
+ APValue &FieldVal = Result.getStructField(Field->getFieldIndex());
+ if (!EvaluateInPlace(FieldVal, Info, Subobject, Init) ||
+ (Field->isBitField() && !truncateBitfieldValue(Info, Init,
+ FieldVal, *Field))) {
if (!Info.keepEvaluatingAfterFailure())
return false;
Success = false;
@@ -4210,6 +5122,58 @@ bool RecordExprEvaluator::VisitCXXConstructExpr(const CXXConstructExpr *E) {
Result);
}
+bool RecordExprEvaluator::VisitCXXStdInitializerListExpr(
+ const CXXStdInitializerListExpr *E) {
+ const ConstantArrayType *ArrayType =
+ Info.Ctx.getAsConstantArrayType(E->getSubExpr()->getType());
+
+ LValue Array;
+ if (!EvaluateLValue(E->getSubExpr(), Array, Info))
+ return false;
+
+ // Get a pointer to the first element of the array.
+ Array.addArray(Info, E, ArrayType);
+
+ // FIXME: Perform the checks on the field types in SemaInit.
+ RecordDecl *Record = E->getType()->castAs<RecordType>()->getDecl();
+ RecordDecl::field_iterator Field = Record->field_begin();
+ if (Field == Record->field_end())
+ return Error(E);
+
+ // Start pointer.
+ if (!Field->getType()->isPointerType() ||
+ !Info.Ctx.hasSameType(Field->getType()->getPointeeType(),
+ ArrayType->getElementType()))
+ return Error(E);
+
+ // FIXME: What if the initializer_list type has base classes, etc?
+ Result = APValue(APValue::UninitStruct(), 0, 2);
+ Array.moveInto(Result.getStructField(0));
+
+ if (++Field == Record->field_end())
+ return Error(E);
+
+ if (Field->getType()->isPointerType() &&
+ Info.Ctx.hasSameType(Field->getType()->getPointeeType(),
+ ArrayType->getElementType())) {
+ // End pointer.
+ if (!HandleLValueArrayAdjustment(Info, E, Array,
+ ArrayType->getElementType(),
+ ArrayType->getSize().getZExtValue()))
+ return false;
+ Array.moveInto(Result.getStructField(1));
+ } else if (Info.Ctx.hasSameType(Field->getType(), Info.Ctx.getSizeType()))
+ // Length.
+ Result.getStructField(1) = APValue(APSInt(ArrayType->getSize()));
+ else
+ return Error(E);
+
+ if (++Field != Record->field_end())
+ return Error(E);
+
+ return true;
+}
+
static bool EvaluateRecord(const Expr *E, const LValue &This,
APValue &Result, EvalInfo &Info) {
assert(E->isRValue() && E->getType()->isRecordType() &&
@@ -4234,7 +5198,8 @@ public:
/// Visit an expression which constructs the value of this temporary.
bool VisitConstructExpr(const Expr *E) {
Result.set(E, Info.CurrentCall->Index);
- return EvaluateInPlace(Info.CurrentCall->Temporaries[E], Info, Result, E);
+ return EvaluateInPlace(Info.CurrentCall->createTemporary(E, false),
+ Info, Result, E);
}
bool VisitCastExpr(const CastExpr *E) {
@@ -4393,7 +5358,7 @@ VectorExprEvaluator::VisitInitListExpr(const InitListExpr *E) {
while (CountElts < NumElements) {
// Handle nested vector initialization.
if (CountInits < NumInits
- && E->getInit(CountInits)->getType()->isExtVectorType()) {
+ && E->getInit(CountInits)->getType()->isVectorType()) {
APValue v;
if (!EvaluateVector(E->getInit(CountInits), v, Info))
return Error(E);
@@ -4951,7 +5916,7 @@ static bool EvaluateBuiltinConstantP(ASTContext &Ctx, const Expr *Arg) {
} else if (ArgType->isPointerType() || Arg->isGLValue()) {
LValue LV;
Expr::EvalStatus Status;
- EvalInfo Info(Ctx, Status);
+ EvalInfo Info(Ctx, Status, EvalInfo::EM_ConstantFold);
if ((Arg->isGLValue() ? EvaluateLValue(Arg, LV, Info)
: EvaluatePointer(Arg, LV, Info)) &&
!Status.HasSideEffects)
@@ -5045,9 +6010,37 @@ bool IntExprEvaluator::VisitCallExpr(const CallExpr *E) {
case Builtin::BI__builtin_classify_type:
return Success(EvaluateBuiltinClassifyType(E), E);
+ // FIXME: BI__builtin_clrsb
+ // FIXME: BI__builtin_clrsbl
+ // FIXME: BI__builtin_clrsbll
+
+ case Builtin::BI__builtin_clz:
+ case Builtin::BI__builtin_clzl:
+ case Builtin::BI__builtin_clzll: {
+ APSInt Val;
+ if (!EvaluateInteger(E->getArg(0), Val, Info))
+ return false;
+ if (!Val)
+ return Error(E);
+
+ return Success(Val.countLeadingZeros(), E);
+ }
+
case Builtin::BI__builtin_constant_p:
return Success(EvaluateBuiltinConstantP(Info.Ctx, E->getArg(0)), E);
+ case Builtin::BI__builtin_ctz:
+ case Builtin::BI__builtin_ctzl:
+ case Builtin::BI__builtin_ctzll: {
+ APSInt Val;
+ if (!EvaluateInteger(E->getArg(0), Val, Info))
+ return false;
+ if (!Val)
+ return Error(E);
+
+ return Success(Val.countTrailingZeros(), E);
+ }
+
case Builtin::BI__builtin_eh_return_data_regno: {
int Operand = E->getArg(0)->EvaluateKnownConstInt(Info.Ctx).getZExtValue();
Operand = Info.Ctx.getTargetInfo().getEHDataRegisterNumber(Operand);
@@ -5057,6 +6050,81 @@ bool IntExprEvaluator::VisitCallExpr(const CallExpr *E) {
case Builtin::BI__builtin_expect:
return Visit(E->getArg(0));
+ case Builtin::BI__builtin_ffs:
+ case Builtin::BI__builtin_ffsl:
+ case Builtin::BI__builtin_ffsll: {
+ APSInt Val;
+ if (!EvaluateInteger(E->getArg(0), Val, Info))
+ return false;
+
+ unsigned N = Val.countTrailingZeros();
+ return Success(N == Val.getBitWidth() ? 0 : N + 1, E);
+ }
+
+ case Builtin::BI__builtin_fpclassify: {
+ APFloat Val(0.0);
+ if (!EvaluateFloat(E->getArg(5), Val, Info))
+ return false;
+ unsigned Arg;
+ switch (Val.getCategory()) {
+ case APFloat::fcNaN: Arg = 0; break;
+ case APFloat::fcInfinity: Arg = 1; break;
+ case APFloat::fcNormal: Arg = Val.isDenormal() ? 3 : 2; break;
+ case APFloat::fcZero: Arg = 4; break;
+ }
+ return Visit(E->getArg(Arg));
+ }
+
+ case Builtin::BI__builtin_isinf_sign: {
+ APFloat Val(0.0);
+ return EvaluateFloat(E->getArg(0), Val, Info) &&
+ Success(Val.isInfinity() ? (Val.isNegative() ? -1 : 1) : 0, E);
+ }
+
+ case Builtin::BI__builtin_isinf: {
+ APFloat Val(0.0);
+ return EvaluateFloat(E->getArg(0), Val, Info) &&
+ Success(Val.isInfinity() ? 1 : 0, E);
+ }
+
+ case Builtin::BI__builtin_isfinite: {
+ APFloat Val(0.0);
+ return EvaluateFloat(E->getArg(0), Val, Info) &&
+ Success(Val.isFinite() ? 1 : 0, E);
+ }
+
+ case Builtin::BI__builtin_isnan: {
+ APFloat Val(0.0);
+ return EvaluateFloat(E->getArg(0), Val, Info) &&
+ Success(Val.isNaN() ? 1 : 0, E);
+ }
+