aboutsummaryrefslogtreecommitdiffstats
path: root/lib
diff options
context:
space:
mode:
authorDimitry Andric <dim@FreeBSD.org>2011-05-02 19:39:53 +0000
committerDimitry Andric <dim@FreeBSD.org>2011-05-02 19:39:53 +0000
commit01af97d3b23bded2b2b21af19bbc6e4cce49e5b3 (patch)
tree64a10f4c4154739d4a8191d7e1b52ce497f4ebd6 /lib
parentc3b054d250cdca485c71845089c316e10610ebad (diff)
downloadsrc-01af97d3b23bded2b2b21af19bbc6e4cce49e5b3.tar.gz
src-01af97d3b23bded2b2b21af19bbc6e4cce49e5b3.zip
Vendor import of clang trunk r130700:vendor/clang/clang-r130700
Notes
Notes: svn path=/vendor/clang/dist/; revision=221339 svn path=/vendor/clang/clang-r130700/; revision=221340; tag=vendor/clang/clang-r130700
Diffstat (limited to 'lib')
-rw-r--r--lib/AST/ASTContext.cpp296
-rw-r--r--lib/AST/ASTDiagnostic.cpp7
-rw-r--r--lib/AST/ASTImporter.cpp237
-rw-r--r--lib/AST/CMakeLists.txt1
-rw-r--r--lib/AST/CXXInheritance.cpp2
-rw-r--r--lib/AST/Decl.cpp417
-rw-r--r--lib/AST/DeclBase.cpp181
-rw-r--r--lib/AST/DeclCXX.cpp404
-rw-r--r--lib/AST/DeclObjC.cpp69
-rw-r--r--lib/AST/DeclPrinter.cpp59
-rw-r--r--lib/AST/DeclTemplate.cpp256
-rw-r--r--lib/AST/DumpXML.cpp19
-rw-r--r--lib/AST/Expr.cpp368
-rw-r--r--lib/AST/ExprCXX.cpp156
-rw-r--r--lib/AST/ExprClassification.cpp38
-rw-r--r--lib/AST/ExprConstant.cpp372
-rw-r--r--lib/AST/ExternalASTSource.cpp59
-rw-r--r--lib/AST/InheritViz.cpp39
-rw-r--r--lib/AST/ItaniumCXXABI.cpp2
-rw-r--r--lib/AST/ItaniumMangle.cpp558
-rw-r--r--lib/AST/MicrosoftCXXABI.cpp2
-rw-r--r--lib/AST/MicrosoftMangle.cpp15
-rw-r--r--lib/AST/NestedNameSpecifier.cpp246
-rw-r--r--lib/AST/RecordLayoutBuilder.cpp141
-rw-r--r--lib/AST/Stmt.cpp98
-rw-r--r--lib/AST/StmtDumper.cpp30
-rw-r--r--lib/AST/StmtIterator.cpp2
-rw-r--r--lib/AST/StmtPrinter.cpp148
-rw-r--r--lib/AST/StmtProfile.cpp58
-rw-r--r--lib/AST/TemplateBase.cpp12
-rw-r--r--lib/AST/TemplateName.cpp4
-rw-r--r--lib/AST/Type.cpp291
-rw-r--r--lib/AST/TypeLoc.cpp87
-rw-r--r--lib/AST/TypePrinter.cpp76
-rw-r--r--lib/Analysis/AnalysisContext.cpp118
-rw-r--r--lib/Analysis/CFG.cpp652
-rw-r--r--lib/Analysis/CFGReachabilityAnalysis.cpp6
-rw-r--r--lib/Analysis/CFGStmtMap.cpp6
-rw-r--r--lib/Analysis/CMakeLists.txt1
-rw-r--r--lib/Analysis/CocoaConventions.cpp92
-rw-r--r--lib/Analysis/PrintfFormatString.cpp43
-rw-r--r--lib/Analysis/ReachableCode.cpp10
-rw-r--r--lib/Analysis/UninitializedValues.cpp874
-rw-r--r--lib/Analysis/UninitializedValuesV2.cpp610
-rw-r--r--lib/Basic/CMakeLists.txt4
-rw-r--r--lib/Basic/Diagnostic.cpp23
-rw-r--r--lib/Basic/DiagnosticIDs.cpp144
-rw-r--r--lib/Basic/FileManager.cpp73
-rw-r--r--lib/Basic/IdentifierTable.cpp85
-rw-r--r--lib/Basic/SourceManager.cpp220
-rw-r--r--lib/Basic/TargetInfo.cpp12
-rw-r--r--lib/Basic/Targets.cpp227
-rw-r--r--lib/Basic/Version.cpp19
-rw-r--r--lib/Basic/VersionTuple.cpp36
-rw-r--r--lib/CMakeLists.txt1
-rw-r--r--lib/CodeGen/BackendUtil.cpp29
-rw-r--r--lib/CodeGen/CGBlocks.cpp586
-rw-r--r--lib/CodeGen/CGBlocks.h4
-rw-r--r--lib/CodeGen/CGBuiltin.cpp230
-rw-r--r--lib/CodeGen/CGCXX.cpp103
-rw-r--r--lib/CodeGen/CGCXXABI.cpp4
-rw-r--r--lib/CodeGen/CGCall.cpp164
-rw-r--r--lib/CodeGen/CGCall.h26
-rw-r--r--lib/CodeGen/CGClass.cpp156
-rw-r--r--lib/CodeGen/CGCleanup.cpp23
-rw-r--r--lib/CodeGen/CGDebugInfo.cpp399
-rw-r--r--lib/CodeGen/CGDebugInfo.h32
-rw-r--r--lib/CodeGen/CGDecl.cpp353
-rw-r--r--lib/CodeGen/CGDeclCXX.cpp48
-rw-r--r--lib/CodeGen/CGException.cpp108
-rw-r--r--lib/CodeGen/CGException.h1
-rw-r--r--lib/CodeGen/CGExpr.cpp99
-rw-r--r--lib/CodeGen/CGExprAgg.cpp134
-rw-r--r--lib/CodeGen/CGExprCXX.cpp650
-rw-r--r--lib/CodeGen/CGExprComplex.cpp9
-rw-r--r--lib/CodeGen/CGExprConstant.cpp401
-rw-r--r--lib/CodeGen/CGExprScalar.cpp245
-rw-r--r--lib/CodeGen/CGObjC.cpp335
-rw-r--r--lib/CodeGen/CGObjCGNU.cpp1416
-rw-r--r--lib/CodeGen/CGObjCMac.cpp364
-rw-r--r--lib/CodeGen/CGObjCRuntime.cpp310
-rw-r--r--lib/CodeGen/CGObjCRuntime.h24
-rw-r--r--lib/CodeGen/CGRTTI.cpp17
-rw-r--r--lib/CodeGen/CGRecordLayout.h5
-rw-r--r--lib/CodeGen/CGRecordLayoutBuilder.cpp188
-rw-r--r--lib/CodeGen/CGStmt.cpp360
-rw-r--r--lib/CodeGen/CGVTT.cpp45
-rw-r--r--lib/CodeGen/CGVTables.cpp539
-rw-r--r--lib/CodeGen/CGVTables.h26
-rw-r--r--lib/CodeGen/CMakeLists.txt2
-rw-r--r--lib/CodeGen/CodeGenAction.cpp2
-rw-r--r--lib/CodeGen/CodeGenFunction.cpp138
-rw-r--r--lib/CodeGen/CodeGenFunction.h97
-rw-r--r--lib/CodeGen/CodeGenModule.cpp179
-rw-r--r--lib/CodeGen/CodeGenModule.h69
-rw-r--r--lib/CodeGen/CodeGenTBAA.cpp5
-rw-r--r--lib/CodeGen/CodeGenTypes.cpp82
-rw-r--r--lib/CodeGen/CodeGenTypes.h14
-rw-r--r--lib/CodeGen/ItaniumCXXABI.cpp55
-rw-r--r--lib/CodeGen/MicrosoftCXXABI.cpp2
-rw-r--r--lib/CodeGen/TargetInfo.cpp178
-rw-r--r--lib/Driver/Compilation.cpp6
-rw-r--r--lib/Driver/Driver.cpp117
-rw-r--r--lib/Driver/HostInfo.cpp7
-rw-r--r--lib/Driver/OptTable.cpp4
-rw-r--r--lib/Driver/ToolChain.cpp16
-rw-r--r--lib/Driver/ToolChains.cpp475
-rw-r--r--lib/Driver/ToolChains.h82
-rw-r--r--lib/Driver/Tools.cpp504
-rw-r--r--lib/Driver/Tools.h3
-rw-r--r--lib/Frontend/ASTConsumers.cpp39
-rw-r--r--lib/Frontend/ASTUnit.cpp463
-rw-r--r--lib/Frontend/CMakeLists.txt6
-rw-r--r--lib/Frontend/CacheTokens.cpp6
-rw-r--r--lib/Frontend/CompilerInstance.cpp107
-rw-r--r--lib/Frontend/CompilerInvocation.cpp117
-rw-r--r--lib/Frontend/CreateInvocationFromCommandLine.cpp90
-rw-r--r--lib/Frontend/DeclXML.cpp183
-rw-r--r--lib/Frontend/DependencyFile.cpp2
-rw-r--r--lib/Frontend/DocumentXML.cpp381
-rw-r--r--lib/Frontend/FrontendAction.cpp31
-rw-r--r--lib/Frontend/FrontendActions.cpp7
-rw-r--r--lib/Frontend/HeaderIncludeGen.cpp32
-rw-r--r--lib/Frontend/InitHeaderSearch.cpp124
-rw-r--r--lib/Frontend/InitPreprocessor.cpp37
-rw-r--r--lib/Frontend/LogDiagnosticPrinter.cpp146
-rw-r--r--lib/Frontend/MultiplexConsumer.cpp19
-rw-r--r--lib/Frontend/PrintPreprocessedOutput.cpp2
-rw-r--r--lib/Frontend/StmtXML.cpp439
-rw-r--r--lib/Frontend/TextDiagnosticPrinter.cpp34
-rw-r--r--lib/Frontend/TypeXML.cpp119
-rw-r--r--lib/FrontendTool/ExecuteCompilerInvocation.cpp1
-rw-r--r--lib/Headers/CMakeLists.txt30
-rw-r--r--lib/Headers/avxintrin.h42
-rw-r--r--lib/Headers/emmintrin.h10
-rw-r--r--lib/Headers/mm3dnow.h161
-rw-r--r--lib/Headers/mm_malloc.h2
-rw-r--r--lib/Headers/stddef.h5
-rw-r--r--lib/Headers/stdint.h37
-rw-r--r--lib/Headers/xmmintrin.h2
-rw-r--r--lib/Index/DeclReferenceMap.cpp2
-rw-r--r--lib/Index/Entity.cpp2
-rw-r--r--lib/Lex/HeaderMap.cpp4
-rw-r--r--lib/Lex/HeaderSearch.cpp123
-rw-r--r--lib/Lex/Lexer.cpp104
-rw-r--r--lib/Lex/LiteralSupport.cpp2
-rw-r--r--lib/Lex/MacroArgs.cpp2
-rw-r--r--lib/Lex/PPDirectives.cpp128
-rw-r--r--lib/Lex/PPExpressions.cpp18
-rw-r--r--lib/Lex/PPLexerChange.cpp20
-rw-r--r--lib/Lex/PPMacroExpansion.cpp39
-rw-r--r--lib/Lex/PTHLexer.cpp4
-rw-r--r--lib/Lex/Pragma.cpp26
-rw-r--r--lib/Lex/PreprocessingRecord.cpp15
-rw-r--r--lib/Lex/Preprocessor.cpp52
-rw-r--r--lib/Lex/PreprocessorLexer.cpp2
-rw-r--r--lib/Lex/TokenLexer.cpp8
-rwxr-xr-xlib/Makefile3
-rw-r--r--lib/Parse/ParseAST.cpp23
-rw-r--r--lib/Parse/ParseCXXInlineMethods.cpp52
-rw-r--r--lib/Parse/ParseDecl.cpp832
-rw-r--r--lib/Parse/ParseDeclCXX.cpp440
-rw-r--r--lib/Parse/ParseExpr.cpp302
-rw-r--r--lib/Parse/ParseExprCXX.cpp322
-rw-r--r--lib/Parse/ParseInit.cpp2
-rw-r--r--lib/Parse/ParseObjc.cpp95
-rw-r--r--lib/Parse/ParsePragma.cpp44
-rw-r--r--lib/Parse/ParsePragma.h10
-rw-r--r--lib/Parse/ParseStmt.cpp438
-rw-r--r--lib/Parse/ParseTemplate.cpp151
-rw-r--r--lib/Parse/ParseTentative.cpp21
-rw-r--r--lib/Parse/Parser.cpp144
-rw-r--r--lib/Parse/RAIIObjectsForParser.h26
-rw-r--r--lib/Rewrite/RewriteObjC.cpp160
-rw-r--r--lib/Rewrite/Rewriter.cpp177
-rw-r--r--lib/Sema/AnalysisBasedWarnings.cpp279
-rw-r--r--lib/Sema/AttributeList.cpp100
-rw-r--r--lib/Sema/CMakeLists.txt2
-rw-r--r--lib/Sema/CodeCompleteConsumer.cpp17
-rw-r--r--lib/Sema/DeclSpec.cpp331
-rw-r--r--lib/Sema/DelayedDiagnostic.cpp51
-rw-r--r--lib/Sema/IdentifierResolver.cpp46
-rw-r--r--lib/Sema/JumpDiagnostics.cpp5
-rw-r--r--lib/Sema/Scope.cpp57
-rw-r--r--lib/Sema/Sema.cpp144
-rw-r--r--lib/Sema/SemaAccess.cpp16
-rw-r--r--lib/Sema/SemaAttr.cpp12
-rw-r--r--lib/Sema/SemaCXXCast.cpp366
-rw-r--r--lib/Sema/SemaCXXScopeSpec.cpp85
-rw-r--r--lib/Sema/SemaChecking.cpp314
-rw-r--r--lib/Sema/SemaCodeComplete.cpp166
-rw-r--r--lib/Sema/SemaDecl.cpp1222
-rw-r--r--lib/Sema/SemaDeclAttr.cpp361
-rw-r--r--lib/Sema/SemaDeclCXX.cpp710
-rw-r--r--lib/Sema/SemaDeclObjC.cpp105
-rw-r--r--lib/Sema/SemaExceptionSpec.cpp304
-rw-r--r--lib/Sema/SemaExpr.cpp2844
-rw-r--r--lib/Sema/SemaExprCXX.cpp1068
-rw-r--r--lib/Sema/SemaExprObjC.cpp219
-rw-r--r--lib/Sema/SemaInit.cpp240
-rw-r--r--lib/Sema/SemaLookup.cpp53
-rw-r--r--lib/Sema/SemaObjCProperty.cpp46
-rw-r--r--lib/Sema/SemaOverload.cpp801
-rw-r--r--lib/Sema/SemaStmt.cpp494
-rw-r--r--lib/Sema/SemaTemplate.cpp726
-rw-r--r--lib/Sema/SemaTemplateDeduction.cpp125
-rw-r--r--lib/Sema/SemaTemplateInstantiate.cpp117
-rw-r--r--lib/Sema/SemaTemplateInstantiateDecl.cpp236
-rw-r--r--lib/Sema/SemaTemplateVariadic.cpp5
-rw-r--r--lib/Sema/SemaType.cpp396
-rw-r--r--lib/Sema/TargetAttributesSema.cpp2
-rw-r--r--lib/Sema/TreeTransform.h1475
-rw-r--r--lib/Sema/TypeLocBuilder.h3
-rw-r--r--lib/Serialization/ASTCommon.cpp2
-rw-r--r--lib/Serialization/ASTCommon.h4
-rw-r--r--lib/Serialization/ASTReader.cpp273
-rw-r--r--lib/Serialization/ASTReaderDecl.cpp219
-rw-r--r--lib/Serialization/ASTReaderStmt.cpp195
-rw-r--r--lib/Serialization/ASTWriter.cpp215
-rw-r--r--lib/Serialization/ASTWriterDecl.cpp57
-rw-r--r--lib/Serialization/ASTWriterStmt.cpp119
-rw-r--r--lib/Serialization/CMakeLists.txt3
-rw-r--r--lib/Serialization/ChainedIncludesSource.cpp235
-rw-r--r--lib/StaticAnalyzer/Checkers/AdjustedReturnValueChecker.cpp29
-rw-r--r--lib/StaticAnalyzer/Checkers/AnalyzerStatsChecker.cpp44
-rw-r--r--lib/StaticAnalyzer/Checkers/ArrayBoundChecker.cpp4
-rw-r--r--lib/StaticAnalyzer/Checkers/ArrayBoundCheckerV2.cpp90
-rw-r--r--lib/StaticAnalyzer/Checkers/AttrNonNullChecker.cpp34
-rw-r--r--lib/StaticAnalyzer/Checkers/BasicObjCFoundationChecks.cpp204
-rw-r--r--lib/StaticAnalyzer/Checkers/BasicObjCFoundationChecks.h35
-rw-r--r--lib/StaticAnalyzer/Checkers/BuiltinFunctionChecker.cpp22
-rw-r--r--lib/StaticAnalyzer/Checkers/CMakeLists.txt3
-rw-r--r--lib/StaticAnalyzer/Checkers/CStringChecker.cpp309
-rw-r--r--lib/StaticAnalyzer/Checkers/CallAndMessageChecker.cpp121
-rw-r--r--lib/StaticAnalyzer/Checkers/CastSizeChecker.cpp4
-rw-r--r--lib/StaticAnalyzer/Checkers/CastToStructChecker.cpp4
-rw-r--r--lib/StaticAnalyzer/Checkers/CheckObjCDealloc.cpp4
-rw-r--r--lib/StaticAnalyzer/Checkers/CheckObjCInstMethSignature.cpp4
-rw-r--r--lib/StaticAnalyzer/Checkers/CheckSecuritySyntaxOnly.cpp216
-rw-r--r--lib/StaticAnalyzer/Checkers/CheckSizeofPointer.cpp10
-rw-r--r--lib/StaticAnalyzer/Checkers/Checkers.td414
-rw-r--r--lib/StaticAnalyzer/Checkers/ChrootChecker.cpp4
-rw-r--r--lib/StaticAnalyzer/Checkers/ClangSACheckerProvider.cpp118
-rw-r--r--lib/StaticAnalyzer/Checkers/ClangSACheckers.h2
-rw-r--r--lib/StaticAnalyzer/Checkers/DeadStoresChecker.cpp5
-rw-r--r--lib/StaticAnalyzer/Checkers/DebugCheckers.cpp8
-rw-r--r--lib/StaticAnalyzer/Checkers/DereferenceChecker.cpp69
-rw-r--r--lib/StaticAnalyzer/Checkers/DivZeroChecker.cpp33
-rw-r--r--lib/StaticAnalyzer/Checkers/ExperimentalChecks.cpp26
-rw-r--r--lib/StaticAnalyzer/Checkers/ExperimentalChecks.h31
-rw-r--r--lib/StaticAnalyzer/Checkers/FixedAddressChecker.cpp4
-rw-r--r--lib/StaticAnalyzer/Checkers/IdempotentOperationChecker.cpp40
-rw-r--r--lib/StaticAnalyzer/Checkers/InternalChecks.h48
-rw-r--r--lib/StaticAnalyzer/Checkers/IteratorsChecker.cpp582
-rw-r--r--lib/StaticAnalyzer/Checkers/LLVMConventionsChecker.cpp7
-rw-r--r--lib/StaticAnalyzer/Checkers/MacOSXAPIChecker.cpp4
-rw-r--r--lib/StaticAnalyzer/Checkers/MallocChecker.cpp187
-rw-r--r--lib/StaticAnalyzer/Checkers/NSAutoreleasePoolChecker.cpp4
-rw-r--r--lib/StaticAnalyzer/Checkers/NSErrorChecker.cpp380
-rw-r--r--lib/StaticAnalyzer/Checkers/NoReturnFunctionChecker.cpp23
-rw-r--r--lib/StaticAnalyzer/Checkers/OSAtomicChecker.cpp30
-rw-r--r--lib/StaticAnalyzer/Checkers/ObjCAtSyncChecker.cpp4
-rw-r--r--lib/StaticAnalyzer/Checkers/ObjCSelfInitChecker.cpp15
-rw-r--r--lib/StaticAnalyzer/Checkers/ObjCUnusedIVarsChecker.cpp4
-rw-r--r--lib/StaticAnalyzer/Checkers/PointerArithChecker.cpp4
-rw-r--r--lib/StaticAnalyzer/Checkers/PointerSubChecker.cpp4
-rw-r--r--lib/StaticAnalyzer/Checkers/PthreadLockChecker.cpp4
-rw-r--r--lib/StaticAnalyzer/Checkers/ReturnPointerRangeChecker.cpp4
-rw-r--r--lib/StaticAnalyzer/Checkers/ReturnUndefChecker.cpp35
-rw-r--r--lib/StaticAnalyzer/Checkers/StackAddrEscapeChecker.cpp4
-rw-r--r--lib/StaticAnalyzer/Checkers/StreamChecker.cpp4
-rw-r--r--lib/StaticAnalyzer/Checkers/UndefBranchChecker.cpp38
-rw-r--r--lib/StaticAnalyzer/Checkers/UndefCapturedBlockVarChecker.cpp28
-rw-r--r--lib/StaticAnalyzer/Checkers/UndefResultChecker.cpp28
-rw-r--r--lib/StaticAnalyzer/Checkers/UndefinedArraySubscriptChecker.cpp33
-rw-r--r--lib/StaticAnalyzer/Checkers/UndefinedAssignmentChecker.cpp39
-rw-r--r--lib/StaticAnalyzer/Checkers/UnixAPIChecker.cpp4
-rw-r--r--lib/StaticAnalyzer/Checkers/UnreachableCodeChecker.cpp14
-rw-r--r--lib/StaticAnalyzer/Checkers/VLASizeChecker.cpp37
-rw-r--r--lib/StaticAnalyzer/Core/AggExprVisitor.cpp2
-rw-r--r--lib/StaticAnalyzer/Core/BasicStore.cpp15
-rw-r--r--lib/StaticAnalyzer/Core/BasicValueFactory.cpp8
-rw-r--r--lib/StaticAnalyzer/Core/BugReporter.cpp14
-rw-r--r--lib/StaticAnalyzer/Core/CFRefCount.cpp63
-rw-r--r--lib/StaticAnalyzer/Core/CMakeLists.txt9
-rw-r--r--lib/StaticAnalyzer/Core/CXXExprEngine.cpp300
-rw-r--r--lib/StaticAnalyzer/Core/CheckerContext.cpp (renamed from lib/StaticAnalyzer/Core/Checker.cpp)10
-rw-r--r--lib/StaticAnalyzer/Core/CheckerManager.cpp97
-rw-r--r--lib/StaticAnalyzer/Core/CoreEngine.cpp23
-rw-r--r--lib/StaticAnalyzer/Core/Environment.cpp19
-rw-r--r--lib/StaticAnalyzer/Core/ExplodedGraph.cpp2
-rw-r--r--lib/StaticAnalyzer/Core/ExprEngine.cpp (renamed from lib/StaticAnalyzer/Checkers/ExprEngine.cpp)1099
-rw-r--r--lib/StaticAnalyzer/Core/FlatStore.cpp13
-rw-r--r--lib/StaticAnalyzer/Core/ObjCMessage.cpp56
-rw-r--r--lib/StaticAnalyzer/Core/RegionStore.cpp77
-rw-r--r--lib/StaticAnalyzer/Core/SValBuilder.cpp139
-rw-r--r--lib/StaticAnalyzer/Core/SimpleConstraintManager.cpp1
-rw-r--r--lib/StaticAnalyzer/Core/SimpleSValBuilder.cpp30
-rw-r--r--lib/StaticAnalyzer/Core/Store.cpp4
-rw-r--r--lib/StaticAnalyzer/Frontend/AnalysisConsumer.cpp91
-rw-r--r--lib/StaticAnalyzer/Frontend/CheckerRegistration.cpp5
-rw-r--r--lib/Tooling/CMakeLists.txt6
-rw-r--r--lib/Tooling/JsonCompileCommandLineDatabase.cpp214
-rw-r--r--lib/Tooling/JsonCompileCommandLineDatabase.h107
-rw-r--r--lib/Tooling/Makefile15
-rw-r--r--lib/Tooling/Tooling.cpp322
306 files changed, 29868 insertions, 15140 deletions
diff --git a/lib/AST/ASTContext.cpp b/lib/AST/ASTContext.cpp
index 9c2455034d68..8316ea68e9e4 100644
--- a/lib/AST/ASTContext.cpp
+++ b/lib/AST/ASTContext.cpp
@@ -107,7 +107,9 @@ ASTContext::getCanonicalTemplateTemplateParmDecl(
if (TemplateTypeParmDecl *TTP = dyn_cast<TemplateTypeParmDecl>(*P))
CanonParams.push_back(
TemplateTypeParmDecl::Create(*this, getTranslationUnitDecl(),
- SourceLocation(), TTP->getDepth(),
+ SourceLocation(),
+ SourceLocation(),
+ TTP->getDepth(),
TTP->getIndex(), 0, false,
TTP->isParameterPack()));
else if (NonTypeTemplateParmDecl *NTTP
@@ -125,7 +127,8 @@ ASTContext::getCanonicalTemplateTemplateParmDecl(
}
Param = NonTypeTemplateParmDecl::Create(*this, getTranslationUnitDecl(),
- SourceLocation(),
+ SourceLocation(),
+ SourceLocation(),
NTTP->getDepth(),
NTTP->getPosition(), 0,
T,
@@ -135,7 +138,8 @@ ASTContext::getCanonicalTemplateTemplateParmDecl(
ExpandedTInfos.data());
} else {
Param = NonTypeTemplateParmDecl::Create(*this, getTranslationUnitDecl(),
- SourceLocation(),
+ SourceLocation(),
+ SourceLocation(),
NTTP->getDepth(),
NTTP->getPosition(), 0,
T,
@@ -186,11 +190,28 @@ CXXABI *ASTContext::createCXXABI(const TargetInfo &T) {
return 0;
}
+static const LangAS::Map &getAddressSpaceMap(const TargetInfo &T,
+ const LangOptions &LOpts) {
+ if (LOpts.FakeAddressSpaceMap) {
+ // The fake address space map must have a distinct entry for each
+ // language-specific address space.
+ static const unsigned FakeAddrSpaceMap[] = {
+ 1, // opencl_global
+ 2, // opencl_local
+ 3 // opencl_constant
+ };
+ return FakeAddrSpaceMap;
+ } else {
+ return T.getAddressSpaceMap();
+ }
+}
+
ASTContext::ASTContext(const LangOptions& LOpts, SourceManager &SM,
const TargetInfo &t,
IdentifierTable &idents, SelectorTable &sels,
Builtin::Context &builtins,
unsigned size_reserve) :
+ FunctionProtoTypes(this_()),
TemplateSpecializationTypes(this_()),
DependentTemplateSpecializationTypes(this_()),
GlobalNestedNameSpecifier(0), IsInt128Installed(false),
@@ -199,7 +220,8 @@ ASTContext::ASTContext(const LangOptions& LOpts, SourceManager &SM,
sigjmp_bufDecl(0), BlockDescriptorType(0), BlockDescriptorExtendedType(0),
cudaConfigureCallDecl(0),
NullTypeSourceInfo(QualType()),
- SourceMgr(SM), LangOpts(LOpts), ABI(createCXXABI(t)), Target(t),
+ SourceMgr(SM), LangOpts(LOpts), ABI(createCXXABI(t)),
+ AddrSpaceMap(getAddressSpaceMap(t, LOpts)), Target(t),
Idents(idents), Selectors(sels),
BuiltinInfo(builtins),
DeclarationNames(*this),
@@ -353,7 +375,7 @@ void ASTContext::InitBuiltinTypes() {
InitBuiltinType(UnsignedInt128Ty, BuiltinType::UInt128);
if (LangOpts.CPlusPlus) { // C++ 3.9.1p5
- if (!LangOpts.ShortWChar)
+ if (TargetInfo::isTypeSigned(Target.getWCharType()))
InitBuiltinType(WCharTy, BuiltinType::WChar_S);
else // -fshort-wchar makes wchar_t be unsigned.
InitBuiltinType(WCharTy, BuiltinType::WChar_U);
@@ -380,6 +402,12 @@ void ASTContext::InitBuiltinTypes() {
// Placeholder type for functions.
InitBuiltinType(OverloadTy, BuiltinType::Overload);
+ // Placeholder type for bound members.
+ InitBuiltinType(BoundMemberTy, BuiltinType::BoundMember);
+
+ // "any" type; useful for debugger-like clients.
+ InitBuiltinType(UnknownAnyTy, BuiltinType::UnknownAny);
+
// C99 6.2.5p11.
FloatComplexTy = getComplexType(FloatTy);
DoubleComplexTy = getComplexType(DoubleTy);
@@ -429,7 +457,6 @@ void ASTContext::eraseDeclAttrs(const Decl *D) {
}
}
-
MemberSpecializationInfo *
ASTContext::getInstantiatedFromStaticDataMember(const VarDecl *Var) {
assert(Var->isStaticDataMember() && "Not a static data member");
@@ -509,6 +536,20 @@ 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->getBitWidth()-> EvaluateAsInt(*this).getZExtValue() == 0);
+
+}
+
+bool ASTContext::ZeroBitfieldFollowsBitfield(const FieldDecl *FD,
+ const FieldDecl *LastFD) const {
+ return (FD->isBitField() && LastFD && LastFD->isBitField() &&
+ FD->getBitWidth()-> EvaluateAsInt(*this).getZExtValue() == 0);
+
+}
+
ASTContext::overridden_cxx_method_iterator
ASTContext::overridden_methods_begin(const CXXMethodDecl *Method) const {
llvm::DenseMap<const CXXMethodDecl *, CXXMethodVector>::const_iterator Pos
@@ -697,6 +738,7 @@ ASTContext::getTypeInfo(const Type *T) const {
std::pair<uint64_t, unsigned> EltInfo = getTypeInfo(CAT->getElementType());
Width = EltInfo.first*CAT->getSize().getZExtValue();
Align = EltInfo.second;
+ Width = llvm::RoundUpToAlignment(Width, Align);
break;
}
case Type::ExtVector:
@@ -801,7 +843,8 @@ ASTContext::getTypeInfo(const Type *T) const {
Align = Target.getPointerAlign(0);
break;
case Type::BlockPointer: {
- unsigned AS = cast<BlockPointerType>(T)->getPointeeType().getAddressSpace();
+ unsigned AS = getTargetAddressSpace(
+ cast<BlockPointerType>(T)->getPointeeType());
Width = Target.getPointerWidth(AS);
Align = Target.getPointerAlign(AS);
break;
@@ -810,13 +853,14 @@ ASTContext::getTypeInfo(const Type *T) const {
case Type::RValueReference: {
// alignof and sizeof should never enter this code path here, so we go
// the pointer route.
- unsigned AS = cast<ReferenceType>(T)->getPointeeType().getAddressSpace();
+ unsigned AS = getTargetAddressSpace(
+ cast<ReferenceType>(T)->getPointeeType());
Width = Target.getPointerWidth(AS);
Align = Target.getPointerAlign(AS);
break;
}
case Type::Pointer: {
- unsigned AS = cast<PointerType>(T)->getPointeeType().getAddressSpace();
+ unsigned AS = getTargetAddressSpace(cast<PointerType>(T)->getPointeeType());
Width = Target.getPointerWidth(AS);
Align = Target.getPointerAlign(AS);
break;
@@ -852,8 +896,8 @@ ASTContext::getTypeInfo(const Type *T) const {
const TagType *TT = cast<TagType>(T);
if (TT->getDecl()->isInvalidDecl()) {
- Width = 1;
- Align = 1;
+ Width = 8;
+ Align = 8;
break;
}
@@ -881,7 +925,7 @@ ASTContext::getTypeInfo(const Type *T) const {
return getTypeInfo(cast<ParenType>(T)->getInnerType().getTypePtr());
case Type::Typedef: {
- const TypedefDecl *Typedef = cast<TypedefType>(T)->getDecl();
+ const TypedefNameDecl *Typedef = cast<TypedefType>(T)->getDecl();
std::pair<uint64_t, unsigned> Info
= getTypeInfo(Typedef->getUnderlyingType().getTypePtr());
// If the typedef has an aligned attribute on it, it overrides any computed
@@ -1463,7 +1507,7 @@ QualType ASTContext::getConstantArrayType(QualType EltTy,
// the target.
llvm::APInt ArySize(ArySizeIn);
ArySize =
- ArySize.zextOrTrunc(Target.getPointerWidth(EltTy.getAddressSpace()));
+ ArySize.zextOrTrunc(Target.getPointerWidth(getTargetAddressSpace(EltTy)));
llvm::FoldingSetNodeID ID;
ConstantArrayType::Profile(ID, EltTy, ArySize, ASM, IndexTypeQuals);
@@ -1862,7 +1906,9 @@ ASTContext::getDependentSizedExtVectorType(QualType vecType,
QualType
ASTContext::getFunctionNoProtoType(QualType ResultTy,
const FunctionType::ExtInfo &Info) const {
- const CallingConv CallConv = Info.getCC();
+ const CallingConv DefaultCC = Info.getCC();
+ const CallingConv CallConv = (LangOpts.MRTD && DefaultCC == CC_Default) ?
+ CC_X86StdCall : DefaultCC;
// Unique functions, to guarantee there is only one function of a particular
// structure.
llvm::FoldingSetNodeID ID;
@@ -1886,8 +1932,9 @@ ASTContext::getFunctionNoProtoType(QualType ResultTy,
assert(NewIP == 0 && "Shouldn't be in the map!"); (void)NewIP;
}
+ FunctionProtoType::ExtInfo newInfo = Info.withCallingConv(CallConv);
FunctionNoProtoType *New = new (*this, TypeAlignment)
- FunctionNoProtoType(ResultTy, Canonical, Info);
+ FunctionNoProtoType(ResultTy, Canonical, newInfo);
Types.push_back(New);
FunctionNoProtoTypes.InsertNode(New, InsertPos);
return QualType(New, 0);
@@ -1902,7 +1949,7 @@ ASTContext::getFunctionType(QualType ResultTy,
// Unique functions, to guarantee there is only one function of a particular
// structure.
llvm::FoldingSetNodeID ID;
- FunctionProtoType::Profile(ID, ResultTy, ArgArray, NumArgs, EPI);
+ FunctionProtoType::Profile(ID, ResultTy, ArgArray, NumArgs, EPI, *this);
void *InsertPos = 0;
if (FunctionProtoType *FTP =
@@ -1910,12 +1957,14 @@ ASTContext::getFunctionType(QualType ResultTy,
return QualType(FTP, 0);
// Determine whether the type being created is already canonical or not.
- bool isCanonical = !EPI.HasExceptionSpec && ResultTy.isCanonical();
+ bool isCanonical= EPI.ExceptionSpecType == EST_None && ResultTy.isCanonical();
for (unsigned i = 0; i != NumArgs && isCanonical; ++i)
if (!ArgArray[i].isCanonicalAsParam())
isCanonical = false;
- const CallingConv CallConv = EPI.ExtInfo.getCC();
+ 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.
@@ -1927,11 +1976,8 @@ ASTContext::getFunctionType(QualType ResultTy,
CanonicalArgs.push_back(getCanonicalParamType(ArgArray[i]));
FunctionProtoType::ExtProtoInfo CanonicalEPI = EPI;
- if (CanonicalEPI.HasExceptionSpec) {
- CanonicalEPI.HasExceptionSpec = false;
- CanonicalEPI.HasAnyExceptionSpec = false;
- CanonicalEPI.NumExceptions = 0;
- }
+ CanonicalEPI.ExceptionSpecType = EST_None;
+ CanonicalEPI.NumExceptions = 0;
CanonicalEPI.ExtInfo
= CanonicalEPI.ExtInfo.withCallingConv(getCanonicalCallConv(CallConv));
@@ -1947,12 +1993,19 @@ ASTContext::getFunctionType(QualType ResultTy,
// FunctionProtoType objects are allocated with extra bytes after them
// for two variable size arrays (for parameter and exception types) at the
- // end of them.
+ // end of them. Instead of the exception types, there could be a noexcept
+ // expression and a context pointer.
size_t Size = sizeof(FunctionProtoType) +
- NumArgs * sizeof(QualType) +
- EPI.NumExceptions * sizeof(QualType);
+ NumArgs * sizeof(QualType);
+ if (EPI.ExceptionSpecType == EST_Dynamic)
+ Size += EPI.NumExceptions * sizeof(QualType);
+ else if (EPI.ExceptionSpecType == EST_ComputedNoexcept) {
+ Size += sizeof(Expr*);
+ }
FunctionProtoType *FTP = (FunctionProtoType*) Allocate(Size, TypeAlignment);
- new (FTP) FunctionProtoType(ResultTy, ArgArray, NumArgs, Canonical, EPI);
+ FunctionProtoType::ExtProtoInfo newEPI = EPI;
+ newEPI.ExtInfo = EPI.ExtInfo.withCallingConv(CallConv);
+ new (FTP) FunctionProtoType(ResultTy, ArgArray, NumArgs, Canonical, newEPI);
Types.push_back(FTP);
FunctionProtoTypes.InsertNode(FTP, InsertPos);
return QualType(FTP, 0);
@@ -1997,7 +2050,7 @@ QualType ASTContext::getTypeDeclTypeSlow(const TypeDecl *Decl) const {
assert(Decl && "Passed null for Decl param");
assert(!Decl->TypeForDecl && "TypeForDecl present in slow case");
- if (const TypedefDecl *Typedef = dyn_cast<TypedefDecl>(Decl))
+ if (const TypedefNameDecl *Typedef = dyn_cast<TypedefNameDecl>(Decl))
return getTypedefType(Typedef);
assert(!isa<TemplateTypeParmDecl>(Decl) &&
@@ -2024,9 +2077,10 @@ QualType ASTContext::getTypeDeclTypeSlow(const TypeDecl *Decl) const {
}
/// getTypedefType - Return the unique reference to the type for the
-/// specified typename decl.
+/// specified typedef name decl.
QualType
-ASTContext::getTypedefType(const TypedefDecl *Decl, QualType Canonical) const {
+ASTContext::getTypedefType(const TypedefNameDecl *Decl,
+ QualType Canonical) const {
if (Decl->TypeForDecl) return QualType(Decl->TypeForDecl, 0);
if (Canonical.isNull())
@@ -2149,9 +2203,9 @@ QualType ASTContext::getSubstTemplateTypeParmPackType(
/// name.
QualType ASTContext::getTemplateTypeParmType(unsigned Depth, unsigned Index,
bool ParameterPack,
- IdentifierInfo *Name) const {
+ TemplateTypeParmDecl *TTPDecl) const {
llvm::FoldingSetNodeID ID;
- TemplateTypeParmType::Profile(ID, Depth, Index, ParameterPack, Name);
+ TemplateTypeParmType::Profile(ID, Depth, Index, ParameterPack, TTPDecl);
void *InsertPos = 0;
TemplateTypeParmType *TypeParm
= TemplateTypeParmTypes.FindNodeOrInsertPos(ID, InsertPos);
@@ -2159,10 +2213,9 @@ QualType ASTContext::getTemplateTypeParmType(unsigned Depth, unsigned Index,
if (TypeParm)
return QualType(TypeParm, 0);
- if (Name) {
+ if (TTPDecl) {
QualType Canon = getTemplateTypeParmType(Depth, Index, ParameterPack);
- TypeParm = new (*this, TypeAlignment)
- TemplateTypeParmType(Depth, Index, ParameterPack, Name, Canon);
+ TypeParm = new (*this, TypeAlignment) TemplateTypeParmType(TTPDecl, Canon);
TemplateTypeParmType *TypeCheck
= TemplateTypeParmTypes.FindNodeOrInsertPos(ID, InsertPos);
@@ -2183,6 +2236,8 @@ ASTContext::getTemplateSpecializationTypeInfo(TemplateName Name,
SourceLocation NameLoc,
const TemplateArgumentListInfo &Args,
QualType CanonType) const {
+ assert(!Name.getAsDependentTemplateName() &&
+ "No dependent template names here!");
QualType TST = getTemplateSpecializationType(Name, Args, CanonType);
TypeSourceInfo *DI = CreateTypeSourceInfo(TST);
@@ -2200,6 +2255,9 @@ QualType
ASTContext::getTemplateSpecializationType(TemplateName Template,
const TemplateArgumentListInfo &Args,
QualType Canon) const {
+ assert(!Template.getAsDependentTemplateName() &&
+ "No dependent template names here!");
+
unsigned NumArgs = Args.size();
llvm::SmallVector<TemplateArgument, 4> ArgVec;
@@ -2216,6 +2274,12 @@ ASTContext::getTemplateSpecializationType(TemplateName Template,
const TemplateArgument *Args,
unsigned NumArgs,
QualType Canon) const {
+ assert(!Template.getAsDependentTemplateName() &&
+ "No dependent template names here!");
+ // Look through qualified template names.
+ if (QualifiedTemplateName *QTN = Template.getAsQualifiedTemplateName())
+ Template = TemplateName(QTN->getTemplateDecl());
+
if (!Canon.isNull())
Canon = getCanonicalType(Canon);
else
@@ -2240,6 +2304,12 @@ QualType
ASTContext::getCanonicalTemplateSpecializationType(TemplateName Template,
const TemplateArgument *Args,
unsigned NumArgs) const {
+ assert(!Template.getAsDependentTemplateName() &&
+ "No dependent template names here!");
+ // Look through qualified template names.
+ if (QualifiedTemplateName *QTN = Template.getAsQualifiedTemplateName())
+ Template = TemplateName(QTN->getTemplateDecl());
+
// Build the canonical template specialization type.
TemplateName CanonTemplate = getCanonicalTemplateName(Template);
llvm::SmallVector<TemplateArgument, 4> CanonArgs;
@@ -2377,7 +2447,8 @@ ASTContext::getDependentTemplateSpecializationType(
const IdentifierInfo *Name,
unsigned NumArgs,
const TemplateArgument *Args) const {
- assert(NNS->isDependent() && "nested-name-specifier must be dependent");
+ assert((!NNS || NNS->isDependent()) &&
+ "nested-name-specifier must be dependent");
llvm::FoldingSetNodeID ID;
DependentTemplateSpecializationType::Profile(ID, *this, Keyword, NNS,
@@ -2701,6 +2772,22 @@ QualType ASTContext::getAutoType(QualType DeducedType) const {
return QualType(AT, 0);
}
+/// getAutoDeductType - Get type pattern for deducing against 'auto'.
+QualType ASTContext::getAutoDeductType() const {
+ if (AutoDeductTy.isNull())
+ AutoDeductTy = getAutoType(QualType());
+ assert(!AutoDeductTy.isNull() && "can't build 'auto' pattern");
+ return AutoDeductTy;
+}
+
+/// getAutoRRefDeductType - Get type pattern for deducing against 'auto &&'.
+QualType ASTContext::getAutoRRefDeductType() const {
+ if (AutoRRefDeductTy.isNull())
+ AutoRRefDeductTy = getRValueReferenceType(getAutoDeductType());
+ assert(!AutoRRefDeductTy.isNull() && "can't build 'auto &&' pattern");
+ return AutoRRefDeductTy;
+}
+
/// getTagDeclType - Return the unique reference to the type for the
/// specified TagDecl (struct/union/class/enum) decl.
QualType ASTContext::getTagDeclType(const TagDecl *Decl) const {
@@ -3014,10 +3101,11 @@ ASTContext::getCanonicalNestedNameSpecifier(NestedNameSpecifier *NNS) const {
= T->getAs<DependentTemplateSpecializationType>()) {
NestedNameSpecifier *Prefix
= getCanonicalNestedNameSpecifier(DTST->getQualifier());
- TemplateName Name
- = getDependentTemplateName(Prefix, DTST->getIdentifier());
- T = getTemplateSpecializationType(Name,
- DTST->getArgs(), DTST->getNumArgs());
+
+ T = getDependentTemplateSpecializationType(DTST->getKeyword(),
+ Prefix, DTST->getIdentifier(),
+ DTST->getNumArgs(),
+ DTST->getArgs());
T = getCanonicalType(T);
}
@@ -3334,19 +3422,20 @@ int ASTContext::getIntegerTypeOrder(QualType LHS, QualType RHS) const {
}
static RecordDecl *
-CreateRecordDecl(const ASTContext &Ctx, RecordDecl::TagKind TK, DeclContext *DC,
- SourceLocation L, IdentifierInfo *Id) {
+CreateRecordDecl(const ASTContext &Ctx, RecordDecl::TagKind TK,
+ DeclContext *DC, IdentifierInfo *Id) {
+ SourceLocation Loc;
if (Ctx.getLangOptions().CPlusPlus)
- return CXXRecordDecl::Create(Ctx, TK, DC, L, Id);
+ return CXXRecordDecl::Create(Ctx, TK, DC, Loc, Loc, Id);
else
- return RecordDecl::Create(Ctx, TK, DC, L, Id);
+ return RecordDecl::Create(Ctx, TK, DC, Loc, Loc, Id);
}
-
+
// getCFConstantStringType - Return the type used for constant CFStrings.
QualType ASTContext::getCFConstantStringType() const {
if (!CFConstantStringTypeDecl) {
CFConstantStringTypeDecl =
- CreateRecordDecl(*this, TTK_Struct, TUDecl, SourceLocation(),
+ CreateRecordDecl(*this, TTK_Struct, TUDecl,
&Idents.get("NSConstantString"));
CFConstantStringTypeDecl->startDefinition();
@@ -3364,6 +3453,7 @@ QualType ASTContext::getCFConstantStringType() const {
// Create fields
for (unsigned i = 0; i < 4; ++i) {
FieldDecl *Field = FieldDecl::Create(*this, CFConstantStringTypeDecl,
+ SourceLocation(),
SourceLocation(), 0,
FieldTypes[i], /*TInfo=*/0,
/*BitWidth=*/0,
@@ -3388,7 +3478,7 @@ void ASTContext::setCFConstantStringType(QualType T) {
QualType ASTContext::getNSConstantStringType() const {
if (!NSConstantStringTypeDecl) {
NSConstantStringTypeDecl =
- CreateRecordDecl(*this, TTK_Struct, TUDecl, SourceLocation(),
+ CreateRecordDecl(*this, TTK_Struct, TUDecl,
&Idents.get("__builtin_NSString"));
NSConstantStringTypeDecl->startDefinition();
@@ -3404,6 +3494,7 @@ QualType ASTContext::getNSConstantStringType() const {
// Create fields
for (unsigned i = 0; i < 3; ++i) {
FieldDecl *Field = FieldDecl::Create(*this, NSConstantStringTypeDecl,
+ SourceLocation(),
SourceLocation(), 0,
FieldTypes[i], /*TInfo=*/0,
/*BitWidth=*/0,
@@ -3427,7 +3518,7 @@ void ASTContext::setNSConstantStringType(QualType T) {
QualType ASTContext::getObjCFastEnumerationStateType() const {
if (!ObjCFastEnumerationStateTypeDecl) {
ObjCFastEnumerationStateTypeDecl =
- CreateRecordDecl(*this, TTK_Struct, TUDecl, SourceLocation(),
+ CreateRecordDecl(*this, TTK_Struct, TUDecl,
&Idents.get("__objcFastEnumerationState"));
ObjCFastEnumerationStateTypeDecl->startDefinition();
@@ -3442,6 +3533,7 @@ QualType ASTContext::getObjCFastEnumerationStateType() const {
for (size_t i = 0; i < 4; ++i) {
FieldDecl *Field = FieldDecl::Create(*this,
ObjCFastEnumerationStateTypeDecl,
+ SourceLocation(),
SourceLocation(), 0,
FieldTypes[i], /*TInfo=*/0,
/*BitWidth=*/0,
@@ -3462,7 +3554,7 @@ QualType ASTContext::getBlockDescriptorType() const {
RecordDecl *T;
// FIXME: Needs the FlagAppleBlock bit.
- T = CreateRecordDecl(*this, TTK_Struct, TUDecl, SourceLocation(),
+ T = CreateRecordDecl(*this, TTK_Struct, TUDecl,
&Idents.get("__block_descriptor"));
T->startDefinition();
@@ -3477,8 +3569,7 @@ QualType ASTContext::getBlockDescriptorType() const {
};
for (size_t i = 0; i < 2; ++i) {
- FieldDecl *Field = FieldDecl::Create(*this,
- T,
+ FieldDecl *Field = FieldDecl::Create(*this, T, SourceLocation(),
SourceLocation(),
&Idents.get(FieldNames[i]),
FieldTypes[i], /*TInfo=*/0,
@@ -3507,7 +3598,7 @@ QualType ASTContext::getBlockDescriptorExtendedType() const {
RecordDecl *T;
// FIXME: Needs the FlagAppleBlock bit.
- T = CreateRecordDecl(*this, TTK_Struct, TUDecl, SourceLocation(),
+ T = CreateRecordDecl(*this, TTK_Struct, TUDecl,
&Idents.get("__block_descriptor_withcopydispose"));
T->startDefinition();
@@ -3526,8 +3617,7 @@ QualType ASTContext::getBlockDescriptorExtendedType() const {
};
for (size_t i = 0; i < 4; ++i) {
- FieldDecl *Field = FieldDecl::Create(*this,
- T,
+ FieldDecl *Field = FieldDecl::Create(*this, T, SourceLocation(),
SourceLocation(),
&Idents.get(FieldNames[i]),
FieldTypes[i], /*TInfo=*/0,
@@ -3586,8 +3676,7 @@ ASTContext::BuildByRefType(llvm::StringRef DeclName, QualType Ty) const {
llvm::raw_svector_ostream(Name) << "__Block_byref_" <<
++UniqueBlockByRefTypeID << '_' << DeclName;
RecordDecl *T;
- T = CreateRecordDecl(*this, TTK_Struct, TUDecl, SourceLocation(),
- &Idents.get(Name.str()));
+ T = CreateRecordDecl(*this, TTK_Struct, TUDecl, &Idents.get(Name.str()));
T->startDefinition();
QualType Int32Ty = IntTy;
assert(getIntWidth(IntTy) == 32 && "non-32bit int not supported");
@@ -3615,6 +3704,7 @@ ASTContext::BuildByRefType(llvm::StringRef DeclName, QualType Ty) const {
if (!HasCopyAndDispose && i >=4 && i <= 5)
continue;
FieldDecl *Field = FieldDecl::Create(*this, T, SourceLocation(),
+ SourceLocation(),
&Idents.get(FieldNames[i]),
FieldTypes[i], /*TInfo=*/0,
/*BitWidth=*/0, /*Mutable=*/false);
@@ -4367,6 +4457,8 @@ TemplateName
ASTContext::getQualifiedTemplateName(NestedNameSpecifier *NNS,
bool TemplateKeyword,
TemplateDecl *Template) const {
+ assert(NNS && "Missing nested-name-specifier in qualified template name");
+
// FIXME: Canonicalization?
llvm::FoldingSetNodeID ID;
QualifiedTemplateName::Profile(ID, NNS, TemplateKeyword, Template);
@@ -4503,7 +4595,7 @@ CanQualType ASTContext::getFromTargetType(unsigned Type) const {
///
bool ASTContext::isObjCNSObjectType(QualType Ty) const {
if (const TypedefType *TDT = dyn_cast<TypedefType>(Ty)) {
- if (TypedefDecl *TD = TDT->getDecl())
+ if (TypedefNameDecl *TD = TDT->getDecl())
if (TD->getAttr<ObjCNSObjectAttr>())
return true;
}
@@ -4795,13 +4887,14 @@ bool ASTContext::canAssignObjCInterfaces(const ObjCObjectPointerType *LHSOPT,
}
/// canAssignObjCInterfacesInBlockPointer - This routine is specifically written
-/// for providing type-safty for objective-c pointers used to pass/return
+/// for providing type-safety for objective-c pointers used to pass/return
/// arguments in block literals. When passed as arguments, passing 'A*' where
/// 'id' is expected is not OK. Passing 'Sub *" where 'Super *" is expected is
/// not OK. For the return type, the opposite is not OK.
bool ASTContext::canAssignObjCInterfacesInBlockPointer(
const ObjCObjectPointerType *LHSOPT,
- const ObjCObjectPointerType *RHSOPT) {
+ const ObjCObjectPointerType *RHSOPT,
+ bool BlockReturnType) {
if (RHSOPT->isObjCBuiltinType() || LHSOPT->isObjCIdType())
return true;
@@ -4819,9 +4912,9 @@ bool ASTContext::canAssignObjCInterfacesInBlockPointer(
if (LHS && RHS) { // We have 2 user-defined types.
if (LHS != RHS) {
if (LHS->getDecl()->isSuperClassOf(RHS->getDecl()))
- return false;
+ return BlockReturnType;
if (RHS->getDecl()->isSuperClassOf(LHS->getDecl()))
- return true;
+ return !BlockReturnType;
}
else
return true;
@@ -4887,10 +4980,10 @@ QualType ASTContext::areCommonBaseCompatible(
const ObjCObjectType *RHS = Rptr->getObjectType();
const ObjCInterfaceDecl* LDecl = LHS->getInterface();
const ObjCInterfaceDecl* RDecl = RHS->getInterface();
- if (!LDecl || !RDecl)
+ if (!LDecl || !RDecl || (LDecl == RDecl))
return QualType();
- while ((LDecl = LDecl->getSuperClass())) {
+ do {
LHS = cast<ObjCInterfaceType>(getObjCInterfaceType(LDecl));
if (canAssignObjCInterfaces(LHS, RHS)) {
llvm::SmallVector<ObjCProtocolDecl *, 8> Protocols;
@@ -4902,7 +4995,7 @@ QualType ASTContext::areCommonBaseCompatible(
Result = getObjCObjectPointerType(Result);
return Result;
}
- }
+ } while ((LDecl = LDecl->getSuperClass()));
return QualType();
}
@@ -4922,10 +5015,47 @@ bool ASTContext::canAssignObjCInterfaces(const ObjCObjectType *LHS,
if (LHS->getNumProtocols() == 0)
return true;
- // Okay, we know the LHS has protocol qualifiers. If the RHS doesn't, then it
- // isn't a superset.
- if (RHS->getNumProtocols() == 0)
- return true; // FIXME: should return false!
+ // Okay, we know the LHS has protocol qualifiers. If the RHS doesn't,
+ // more detailed analysis is required.
+ if (RHS->getNumProtocols() == 0) {
+ // OK, if LHS is a superclass of RHS *and*
+ // this superclass is assignment compatible with LHS.
+ // false otherwise.
+ bool IsSuperClass =
+ LHS->getInterface()->isSuperClassOf(RHS->getInterface());
+ if (IsSuperClass) {
+ // OK if conversion of LHS to SuperClass results in narrowing of types
+ // ; i.e., SuperClass may implement at least one of the protocols
+ // in LHS's protocol list. Example, SuperObj<P1> = lhs<P1,P2> is ok.
+ // But not SuperObj<P1,P2,P3> = lhs<P1,P2>.
+ llvm::SmallPtrSet<ObjCProtocolDecl *, 8> SuperClassInheritedProtocols;
+ CollectInheritedProtocols(RHS->getInterface(), SuperClassInheritedProtocols);
+ // If super class has no protocols, it is not a match.
+ if (SuperClassInheritedProtocols.empty())
+ return false;
+
+ for (ObjCObjectType::qual_iterator LHSPI = LHS->qual_begin(),
+ LHSPE = LHS->qual_end();
+ LHSPI != LHSPE; LHSPI++) {
+ bool SuperImplementsProtocol = false;
+ ObjCProtocolDecl *LHSProto = (*LHSPI);
+
+ for (llvm::SmallPtrSet<ObjCProtocolDecl*,8>::iterator I =
+ SuperClassInheritedProtocols.begin(),
+ E = SuperClassInheritedProtocols.end(); I != E; ++I) {
+ ObjCProtocolDecl *SuperClassProto = (*I);
+ if (SuperClassProto->lookupProtocolNamed(LHSProto->getIdentifier())) {
+ SuperImplementsProtocol = true;
+ break;
+ }
+ }
+ if (!SuperImplementsProtocol)
+ return false;
+ }
+ return true;
+ }
+ return false;
+ }
for (ObjCObjectType::qual_iterator LHSPI = LHS->qual_begin(),
LHSPE = LHS->qual_end();
@@ -5045,7 +5175,7 @@ QualType ASTContext::mergeFunctionTypes(QualType lhs, QualType rhs,
bool UnqualifiedResult = Unqualified;
if (!UnqualifiedResult)
UnqualifiedResult = (!RHS.hasQualifiers() && LHS.hasQualifiers());
- retType = mergeTypes(RHS, LHS, true, UnqualifiedResult);
+ retType = mergeTypes(LHS, RHS, true, UnqualifiedResult, true);
}
else
retType = mergeTypes(lbase->getResultType(), rbase->getResultType(), false,
@@ -5079,6 +5209,8 @@ QualType ASTContext::mergeFunctionTypes(QualType lhs, QualType rhs,
return QualType();
// Regparm is part of the calling convention.
+ if (lbaseInfo.getHasRegParm() != rbaseInfo.getHasRegParm())
+ return QualType();
if (lbaseInfo.getRegParm() != rbaseInfo.getRegParm())
return QualType();
@@ -5091,6 +5223,7 @@ QualType ASTContext::mergeFunctionTypes(QualType lhs, QualType rhs,
allRTypes = false;
FunctionType::ExtInfo einfo(NoReturn,
+ lbaseInfo.getHasRegParm(),
lbaseInfo.getRegParm(),
lbaseInfo.getCC());
@@ -5185,7 +5318,7 @@ QualType ASTContext::mergeFunctionTypes(QualType lhs, QualType rhs,
QualType ASTContext::mergeTypes(QualType LHS, QualType RHS,
bool OfBlockPointer,
- bool Unqualified) {
+ bool Unqualified, bool BlockReturnType) {
// C++ [expr]: If an expression initially has the type "reference to T", the
// type is adjusted to "T" prior to any further analysis, the expression
// designates the object or function denoted by the reference, and the
@@ -5419,7 +5552,8 @@ QualType ASTContext::mergeTypes(QualType LHS, QualType RHS,
if (OfBlockPointer) {
if (canAssignObjCInterfacesInBlockPointer(
LHS->getAs<ObjCObjectPointerType>(),
- RHS->getAs<ObjCObjectPointerType>()))
+ RHS->getAs<ObjCObjectPointerType>(),
+ BlockReturnType))
return LHS;
return QualType();
}
@@ -5557,10 +5691,6 @@ QualType ASTContext::getCorrespondingUnsignedType(QualType T) {
}
}
-ExternalASTSource::~ExternalASTSource() { }
-
-void ExternalASTSource::PrintStats() { }
-
ASTMutationListener::~ASTMutationListener() { }
@@ -6015,3 +6145,19 @@ MangleContext *ASTContext::createMangleContext() {
}
CXXABI::~CXXABI() {}
+
+size_t ASTContext::getSideTableAllocatedMemory() const {
+ size_t bytes = 0;
+ bytes += ASTRecordLayouts.getMemorySize();
+ bytes += ObjCLayouts.getMemorySize();
+ bytes += KeyFunctions.getMemorySize();
+ bytes += ObjCImpls.getMemorySize();
+ bytes += BlockVarCopyInits.getMemorySize();
+ bytes += DeclAttrs.getMemorySize();
+ bytes += InstantiatedFromStaticDataMember.getMemorySize();
+ bytes += InstantiatedFromUsingDecl.getMemorySize();
+ bytes += InstantiatedFromUsingShadowDecl.getMemorySize();
+ bytes += InstantiatedFromUnnamedFieldDecl.getMemorySize();
+ return bytes;
+}
+
diff --git a/lib/AST/ASTDiagnostic.cpp b/lib/AST/ASTDiagnostic.cpp
index 5bf8a38199b6..897b4a4c1f27 100644
--- a/lib/AST/ASTDiagnostic.cpp
+++ b/lib/AST/ASTDiagnostic.cpp
@@ -43,6 +43,11 @@ static QualType Desugar(ASTContext &Context, QualType QT, bool &ShouldAKA) {
QT = ST->desugar();
continue;
}
+ // ...or an attributed type...
+ if (const AttributedType *AT = dyn_cast<AttributedType>(Ty)) {
+ QT = AT->desugar();
+ continue;
+ }
// ... or an auto type.
if (const AutoType *AT = dyn_cast<AutoType>(Ty)) {
if (!AT->isSugared())
@@ -95,7 +100,7 @@ break; \
// Don't desugar through the primary typedef of an anonymous type.
if (const TagType *UTT = Underlying->getAs<TagType>())
if (const TypedefType *QTT = dyn_cast<TypedefType>(QT))
- if (UTT->getDecl()->getTypedefForAnonDecl() == QTT->getDecl())
+ if (UTT->getDecl()->getTypedefNameForAnonDecl() == QTT->getDecl())
break;
// Record that we actually looked through an opaque type here.
diff --git a/lib/AST/ASTImporter.cpp b/lib/AST/ASTImporter.cpp
index 21f10fb7ad99..dc881ba86960 100644
--- a/lib/AST/ASTImporter.cpp
+++ b/lib/AST/ASTImporter.cpp
@@ -97,7 +97,9 @@ namespace {
bool IsStructuralMatch(ClassTemplateDecl *From, ClassTemplateDecl *To);
Decl *VisitDecl(Decl *D);
Decl *VisitNamespaceDecl(NamespaceDecl *D);
+ Decl *VisitTypedefNameDecl(TypedefNameDecl *D, bool IsAlias);
Decl *VisitTypedefDecl(TypedefDecl *D);
+ Decl *VisitTypeAliasDecl(TypeAliasDecl *D);
Decl *VisitEnumDecl(EnumDecl *D);
Decl *VisitRecordDecl(RecordDecl *D);
Decl *VisitEnumConstantDecl(EnumConstantDecl *D);
@@ -139,7 +141,7 @@ namespace {
Expr *VisitCharacterLiteral(CharacterLiteral *E);
Expr *VisitParenExpr(ParenExpr *E);
Expr *VisitUnaryOperator(UnaryOperator *E);
- Expr *VisitSizeOfAlignOfExpr(SizeOfAlignOfExpr *E);
+ Expr *VisitUnaryExprOrTypeTraitExpr(UnaryExprOrTypeTraitExpr *E);
Expr *VisitBinaryOperator(BinaryOperator *E);
Expr *VisitCompoundAssignOperator(CompoundAssignOperator *E);
Expr *VisitImplicitCastExpr(ImplicitCastExpr *E);
@@ -521,16 +523,21 @@ static bool IsStructurallyEquivalent(StructuralEquivalenceContext &Context,
}
if (Proto1->isVariadic() != Proto2->isVariadic())
return false;
- if (Proto1->hasExceptionSpec() != Proto2->hasExceptionSpec())
+ if (Proto1->getExceptionSpecType() != Proto2->getExceptionSpecType())
return false;
- if (Proto1->hasAnyExceptionSpec() != Proto2->hasAnyExceptionSpec())
- return false;
- if (Proto1->getNumExceptions() != Proto2->getNumExceptions())
- return false;
- for (unsigned I = 0, N = Proto1->getNumExceptions(); I != N; ++I) {
+ if (Proto1->getExceptionSpecType() == EST_Dynamic) {
+ if (Proto1->getNumExceptions() != Proto2->getNumExceptions())
+ return false;
+ for (unsigned I = 0, N = Proto1->getNumExceptions(); I != N; ++I) {
+ if (!IsStructurallyEquivalent(Context,
+ Proto1->getExceptionType(I),
+ Proto2->getExceptionType(I)))
+ return false;
+ }
+ } else if (Proto1->getExceptionSpecType() == EST_ComputedNoexcept) {
if (!IsStructurallyEquivalent(Context,
- Proto1->getExceptionType(I),
- Proto2->getExceptionType(I)))
+ Proto1->getNoexceptExpr(),
+ Proto2->getNoexceptExpr()))
return false;
}
if (Proto1->getTypeQuals() != Proto2->getTypeQuals())
@@ -830,7 +837,7 @@ static bool IsStructurallyEquivalent(StructuralEquivalenceContext &Context,
return false;
}
// If one is a class template specialization and the other is not, these
- // structures are diferent.
+ // structures are different.
else if (Spec1 || Spec2)
return false;
@@ -1189,11 +1196,11 @@ bool StructuralEquivalenceContext::Finish() {
if (RecordDecl *Record2 = dyn_cast<RecordDecl>(D2)) {
// Check for equivalent structure names.
IdentifierInfo *Name1 = Record1->getIdentifier();
- if (!Name1 && Record1->getTypedefForAnonDecl())
- Name1 = Record1->getTypedefForAnonDecl()->getIdentifier();
+ if (!Name1 && Record1->getTypedefNameForAnonDecl())
+ Name1 = Record1->getTypedefNameForAnonDecl()->getIdentifier();
IdentifierInfo *Name2 = Record2->getIdentifier();
- if (!Name2 && Record2->getTypedefForAnonDecl())
- Name2 = Record2->getTypedefForAnonDecl()->getIdentifier();
+ if (!Name2 && Record2->getTypedefNameForAnonDecl())
+ Name2 = Record2->getTypedefNameForAnonDecl()->getIdentifier();
if (!::IsStructurallyEquivalent(Name1, Name2) ||
!::IsStructurallyEquivalent(*this, Record1, Record2))
Equivalent = false;
@@ -1205,11 +1212,11 @@ bool StructuralEquivalenceContext::Finish() {
if (EnumDecl *Enum2 = dyn_cast<EnumDecl>(D2)) {
// Check for equivalent enum names.
IdentifierInfo *Name1 = Enum1->getIdentifier();
- if (!Name1 && Enum1->getTypedefForAnonDecl())
- Name1 = Enum1->getTypedefForAnonDecl()->getIdentifier();
+ if (!Name1 && Enum1->getTypedefNameForAnonDecl())
+ Name1 = Enum1->getTypedefNameForAnonDecl()->getIdentifier();
IdentifierInfo *Name2 = Enum2->getIdentifier();
- if (!Name2 && Enum2->getTypedefForAnonDecl())
- Name2 = Enum2->getTypedefForAnonDecl()->getIdentifier();
+ if (!Name2 && Enum2->getTypedefNameForAnonDecl())
+ Name2 = Enum2->getTypedefNameForAnonDecl()->getIdentifier();
if (!::IsStructurallyEquivalent(Name1, Name2) ||
!::IsStructurallyEquivalent(*this, Enum1, Enum2))
Equivalent = false;
@@ -1217,8 +1224,8 @@ bool StructuralEquivalenceContext::Finish() {
// Enum/non-enum mismatch
Equivalent = false;
}
- } else if (TypedefDecl *Typedef1 = dyn_cast<TypedefDecl>(D1)) {
- if (TypedefDecl *Typedef2 = dyn_cast<TypedefDecl>(D2)) {
+ } else if (TypedefNameDecl *Typedef1 = dyn_cast<TypedefNameDecl>(D1)) {
+ if (TypedefNameDecl *Typedef2 = dyn_cast<TypedefNameDecl>(D2)) {
if (!::IsStructurallyEquivalent(Typedef1->getIdentifier(),
Typedef2->getIdentifier()) ||
!::IsStructurallyEquivalent(*this,
@@ -1355,6 +1362,8 @@ QualType ASTNodeImporter::VisitBuiltinType(const BuiltinType *T) {
case BuiltinType::Overload: return Importer.getToContext().OverloadTy;
case BuiltinType::Dependent: return Importer.getToContext().DependentTy;
+ case BuiltinType::UnknownAny: return Importer.getToContext().UnknownAnyTy;
+ case BuiltinType::BoundMember: return Importer.getToContext().BoundMemberTy;
case BuiltinType::ObjCId:
// FIXME: Make sure that the "to" context supports Objective-C!
@@ -1530,8 +1539,8 @@ QualType ASTNodeImporter::VisitFunctionProtoType(const FunctionProtoType *T) {
}
QualType ASTNodeImporter::VisitTypedefType(const TypedefType *T) {
- TypedefDecl *ToDecl
- = dyn_cast_or_null<TypedefDecl>(Importer.Import(T->getDecl()));
+ TypedefNameDecl *ToDecl
+ = dyn_cast_or_null<TypedefNameDecl>(Importer.Import(T->getDecl()));
if (!ToDecl)
return QualType();
@@ -1967,8 +1976,9 @@ Decl *ASTNodeImporter::VisitNamespaceDecl(NamespaceDecl *D) {
// Create the "to" namespace, if needed.
NamespaceDecl *ToNamespace = MergeWithNamespace;
if (!ToNamespace) {
- ToNamespace = NamespaceDecl::Create(Importer.getToContext(), DC, Loc,
- Name.getAsIdentifierInfo());
+ ToNamespace = NamespaceDecl::Create(Importer.getToContext(), DC,
+ Importer.Import(D->getLocStart()),
+ Loc, Name.getAsIdentifierInfo());
ToNamespace->setLexicalDeclContext(LexicalDC);
LexicalDC->addDecl(ToNamespace);
@@ -1988,7 +1998,7 @@ Decl *ASTNodeImporter::VisitNamespaceDecl(NamespaceDecl *D) {
return ToNamespace;
}
-Decl *ASTNodeImporter::VisitTypedefDecl(TypedefDecl *D) {
+Decl *ASTNodeImporter::VisitTypedefNameDecl(TypedefNameDecl *D, bool IsAlias) {
// Import the major distinguishing characteristics of this typedef.
DeclContext *DC, *LexicalDC;
DeclarationName Name;
@@ -2007,7 +2017,8 @@ Decl *ASTNodeImporter::VisitTypedefDecl(TypedefDecl *D) {
++Lookup.first) {
if (!(*Lookup.first)->isInIdentifierNamespace(IDNS))
continue;
- if (TypedefDecl *FoundTypedef = dyn_cast<TypedefDecl>(*Lookup.first)) {
+ if (TypedefNameDecl *FoundTypedef =
+ dyn_cast<TypedefNameDecl>(*Lookup.first)) {
if (Importer.IsStructurallyEquivalent(D->getUnderlyingType(),
FoundTypedef->getUnderlyingType()))
return Importer.Imported(D, FoundTypedef);
@@ -2032,9 +2043,18 @@ Decl *ASTNodeImporter::VisitTypedefDecl(TypedefDecl *D) {
// Create the new typedef node.
TypeSourceInfo *TInfo = Importer.Import(D->getTypeSourceInfo());
- TypedefDecl *ToTypedef = TypedefDecl::Create(Importer.getToContext(), DC,
- Loc, Name.getAsIdentifierInfo(),
- TInfo);
+ SourceLocation StartL = Importer.Import(D->getLocStart());
+ TypedefNameDecl *ToTypedef;
+ if (IsAlias)
+ ToTypedef = TypedefDecl::Create(Importer.getToContext(), DC,
+ StartL, Loc,
+ Name.getAsIdentifierInfo(),
+ TInfo);
+ else
+ ToTypedef = TypeAliasDecl::Create(Importer.getToContext(), DC,
+ StartL, Loc,
+ Name.getAsIdentifierInfo(),
+ TInfo);
ToTypedef->setAccess(D->getAccess());
ToTypedef->setLexicalDeclContext(LexicalDC);
Importer.Imported(D, ToTypedef);
@@ -2043,6 +2063,14 @@ Decl *ASTNodeImporter::VisitTypedefDecl(TypedefDecl *D) {
return ToTypedef;
}
+Decl *ASTNodeImporter::VisitTypedefDecl(TypedefDecl *D) {
+ return VisitTypedefNameDecl(D, /*IsAlias=*/false);
+}
+
+Decl *ASTNodeImporter::VisitTypeAliasDecl(TypeAliasDecl *D) {
+ return VisitTypedefNameDecl(D, /*IsAlias=*/true);
+}
+
Decl *ASTNodeImporter::VisitEnumDecl(EnumDecl *D) {
// Import the major distinguishing characteristics of this enum.
DeclContext *DC, *LexicalDC;
@@ -2054,8 +2082,8 @@ Decl *ASTNodeImporter::VisitEnumDecl(EnumDecl *D) {
// Figure out what enum name we're looking for.
unsigned IDNS = Decl::IDNS_Tag;
DeclarationName SearchName = Name;
- if (!SearchName && D->getTypedefForAnonDecl()) {
- SearchName = Importer.Import(D->getTypedefForAnonDecl()->getDeclName());
+ if (!SearchName && D->getTypedefNameForAnonDecl()) {
+ SearchName = Importer.Import(D->getTypedefNameForAnonDecl()->getDeclName());
IDNS = Decl::IDNS_Ordinary;
} else if (Importer.getToContext().getLangOptions().CPlusPlus)
IDNS |= Decl::IDNS_Ordinary;
@@ -2070,7 +2098,7 @@ Decl *ASTNodeImporter::VisitEnumDecl(EnumDecl *D) {
continue;
Decl *Found = *Lookup.first;
- if (TypedefDecl *Typedef = dyn_cast<TypedefDecl>(Found)) {
+ if (TypedefNameDecl *Typedef = dyn_cast<TypedefNameDecl>(Found)) {
if (const TagType *Tag = Typedef->getUnderlyingType()->getAs<TagType>())
Found = Tag->getDecl();
}
@@ -2091,9 +2119,9 @@ Decl *ASTNodeImporter::VisitEnumDecl(EnumDecl *D) {
}
// Create the enum declaration.
- EnumDecl *D2 = EnumDecl::Create(Importer.getToContext(), DC, Loc,
- Name.getAsIdentifierInfo(),
- Importer.Import(D->getTagKeywordLoc()), 0,
+ EnumDecl *D2 = EnumDecl::Create(Importer.getToContext(), DC,
+ Importer.Import(D->getLocStart()),
+ Loc, Name.getAsIdentifierInfo(), 0,
D->isScoped(), D->isScopedUsingClassTag(),
D->isFixed());
// Import the qualifier, if any.
@@ -2155,8 +2183,8 @@ Decl *ASTNodeImporter::VisitRecordDecl(RecordDecl *D) {
// Figure out what structure name we're looking for.
unsigned IDNS = Decl::IDNS_Tag;
DeclarationName SearchName = Name;
- if (!SearchName && D->getTypedefForAnonDecl()) {
- SearchName = Importer.Import(D->getTypedefForAnonDecl()->getDeclName());
+ if (!SearchName && D->getTypedefNameForAnonDecl()) {
+ SearchName = Importer.Import(D->getTypedefNameForAnonDecl()->getDeclName());
IDNS = Decl::IDNS_Ordinary;
} else if (Importer.getToContext().getLangOptions().CPlusPlus)
IDNS |= Decl::IDNS_Ordinary;
@@ -2172,7 +2200,7 @@ Decl *ASTNodeImporter::VisitRecordDecl(RecordDecl *D) {
continue;
Decl *Found = *Lookup.first;
- if (TypedefDecl *Typedef = dyn_cast<TypedefDecl>(Found)) {
+ if (TypedefNameDecl *Typedef = dyn_cast<TypedefNameDecl>(Found)) {
if (const TagType *Tag = Typedef->getUnderlyingType()->getAs<TagType>())
Found = Tag->getDecl();
}
@@ -2206,20 +2234,18 @@ Decl *ASTNodeImporter::VisitRecordDecl(RecordDecl *D) {
// Create the record declaration.
RecordDecl *D2 = AdoptDecl;
+ SourceLocation StartLoc = Importer.Import(D->getLocStart());
if (!D2) {
if (isa<CXXRecordDecl>(D)) {
CXXRecordDecl *D2CXX = CXXRecordDecl::Create(Importer.getToContext(),
D->getTagKind(),
- DC, Loc,
- Name.getAsIdentifierInfo(),
- Importer.Import(D->getTagKeywordLoc()));
+ DC, StartLoc, Loc,
+ Name.getAsIdentifierInfo());
D2 = D2CXX;
D2->setAccess(D->getAccess());
} else {
D2 = RecordDecl::Create(Importer.getToContext(), D->getTagKind(),
- DC, Loc,
- Name.getAsIdentifierInfo(),
- Importer.Import(D->getTagKeywordLoc()));
+ DC, StartLoc, Loc, Name.getAsIdentifierInfo());
}
D2->setQualifierInfo(Importer.Import(D->getQualifierLoc()));
@@ -2367,6 +2393,7 @@ Decl *ASTNodeImporter::VisitFunctionDecl(FunctionDecl *D) {
if (CXXConstructorDecl *FromConstructor = dyn_cast<CXXConstructorDecl>(D)) {
ToFunction = CXXConstructorDecl::Create(Importer.getToContext(),
cast<CXXRecordDecl>(DC),
+ D->getInnerLocStart(),
NameInfo, T, TInfo,
FromConstructor->isExplicit(),
D->isInlineSpecified(),
@@ -2374,6 +2401,7 @@ Decl *ASTNodeImporter::VisitFunctionDecl(FunctionDecl *D) {
} else if (isa<CXXDestructorDecl>(D)) {
ToFunction = CXXDestructorDecl::Create(Importer.getToContext(),
cast<CXXRecordDecl>(DC),
+ D->getInnerLocStart(),
NameInfo, T, TInfo,
D->isInlineSpecified(),
D->isImplicit());
@@ -2381,18 +2409,23 @@ Decl *ASTNodeImporter::VisitFunctionDecl(FunctionDecl *D) {
= dyn_cast<CXXConversionDecl>(D)) {
ToFunction = CXXConversionDecl::Create(Importer.getToContext(),
cast<CXXRecordDecl>(DC),
+ D->getInnerLocStart(),
NameInfo, T, TInfo,
D->isInlineSpecified(),
- FromConversion->isExplicit());
+ FromConversion->isExplicit(),
+ Importer.Import(D->getLocEnd()));
} else if (CXXMethodDecl *Method = dyn_cast<CXXMethodDecl>(D)) {
ToFunction = CXXMethodDecl::Create(Importer.getToContext(),
cast<CXXRecordDecl>(DC),
+ D->getInnerLocStart(),
NameInfo, T, TInfo,
Method->isStatic(),
Method->getStorageClassAsWritten(),
- Method->isInlineSpecified());
+ Method->isInlineSpecified(),
+ Importer.Import(D->getLocEnd()));
} else {
ToFunction = FunctionDecl::Create(Importer.getToContext(), DC,
+ D->getInnerLocStart(),
NameInfo, T, TInfo, D->getStorageClass(),
D->getStorageClassAsWritten(),
D->isInlineSpecified(),
@@ -2457,7 +2490,8 @@ Decl *ASTNodeImporter::VisitFieldDecl(FieldDecl *D) {
if (!BitWidth && D->getBitWidth())
return 0;
- FieldDecl *ToField = FieldDecl::Create(Importer.getToContext(), DC,
+ FieldDecl *ToField = FieldDecl::Create(Importer.getToContext(), DC,
+ Importer.Import(D->getInnerLocStart()),
Loc, Name.getAsIdentifierInfo(),
T, TInfo, BitWidth, D->isMutable());
ToField->setAccess(D->getAccess());
@@ -2542,6 +2576,7 @@ Decl *ASTNodeImporter::VisitObjCIvarDecl(ObjCIvarDecl *D) {
ObjCIvarDecl *ToIvar = ObjCIvarDecl::Create(Importer.getToContext(),
cast<ObjCContainerDecl>(DC),
+ Importer.Import(D->getInnerLocStart()),
Loc, Name.getAsIdentifierInfo(),
T, TInfo, D->getAccessControl(),
BitWidth, D->getSynthesize());
@@ -2650,8 +2685,10 @@ Decl *ASTNodeImporter::VisitVarDecl(VarDecl *D) {
// Create the imported variable.
TypeSourceInfo *TInfo = Importer.Import(D->getTypeSourceInfo());
- VarDecl *ToVar = VarDecl::Create(Importer.getToContext(), DC, Loc,
- Name.getAsIdentifierInfo(), T, TInfo,
+ VarDecl *ToVar = VarDecl::Create(Importer.getToContext(), DC,
+ Importer.Import(D->getInnerLocStart()),
+ Loc, Name.getAsIdentifierInfo(),
+ T, TInfo,
D->getStorageClass(),
D->getStorageClassAsWritten());
ToVar->setQualifierInfo(Importer.Import(D->getQualifierLoc()));
@@ -2718,6 +2755,7 @@ Decl *ASTNodeImporter::VisitParmVarDecl(ParmVarDecl *D) {
// Create the imported parameter.
TypeSourceInfo *TInfo = Importer.Import(D->getTypeSourceInfo());
ParmVarDecl *ToParm = ParmVarDecl::Create(Importer.getToContext(), DC,
+ Importer.Import(D->getInnerLocStart()),
Loc, Name.getAsIdentifierInfo(),
T, TInfo, D->getStorageClass(),
D->getStorageClassAsWritten(),
@@ -3444,6 +3482,7 @@ Decl *ASTNodeImporter::VisitTemplateTypeParmDecl(TemplateTypeParmDecl *D) {
// FIXME: Import default argument.
return TemplateTypeParmDecl::Create(Importer.getToContext(),
Importer.getToContext().getTranslationUnitDecl(),
+ Importer.Import(D->getLocStart()),
Importer.Import(D->getLocation()),
D->getDepth(),
D->getIndex(),
@@ -3476,6 +3515,7 @@ ASTNodeImporter::VisitNonTypeTemplateParmDecl(NonTypeTemplateParmDecl *D) {
return NonTypeTemplateParmDecl::Create(Importer.getToContext(),
Importer.getToContext().getTranslationUnitDecl(),
+ Importer.Import(D->getInnerLocStart()),
Loc, D->getDepth(), D->getPosition(),
Name.getAsIdentifierInfo(),
T, D->isParameterPack(), TInfo);
@@ -3567,12 +3607,12 @@ Decl *ASTNodeImporter::VisitClassTemplateDecl(ClassTemplateDecl *D) {
CXXRecordDecl *DTemplated = D->getTemplatedDecl();
// Create the declaration that is being templated.
+ SourceLocation StartLoc = Importer.Import(DTemplated->getLocStart());
+ SourceLocation IdLoc = Importer.Import(DTemplated->getLocation());
CXXRecordDecl *D2Templated = CXXRecordDecl::Create(Importer.getToContext(),
DTemplated->getTagKind(),
- DC,
- Importer.Import(DTemplated->getLocation()),
- Name.getAsIdentifierInfo(),
- Importer.Import(DTemplated->getTagKeywordLoc()));
+ DC, StartLoc, IdLoc,
+ Name.getAsIdentifierInfo());
D2Templated->setAccess(DTemplated->getAccess());
D2Templated->setQualifierInfo(Importer.Import(DTemplated->getQualifierLoc()));
D2Templated->setLexicalDeclContext(LexicalDC);
@@ -3637,7 +3677,8 @@ Decl *ASTNodeImporter::VisitClassTemplateSpecializationDecl(
}
// Import the location of this declaration.
- SourceLocation Loc = Importer.Import(D->getLocation());
+ SourceLocation StartLoc = Importer.Import(D->getLocStart());
+ SourceLocation IdLoc = Importer.Import(D->getLocation());
// Import template arguments.
llvm::SmallVector<TemplateArgument, 2> TemplateArgs;
@@ -3669,7 +3710,8 @@ Decl *ASTNodeImporter::VisitClassTemplateSpecializationDecl(
// Create a new specialization.
D2 = ClassTemplateSpecializationDecl::Create(Importer.getToContext(),
D->getTagKind(), DC,
- Loc, ClassTemplate,
+ StartLoc, IdLoc,
+ ClassTemplate,
TemplateArgs.data(),
TemplateArgs.size(),
/*PrevDecl=*/0);
@@ -3713,26 +3755,27 @@ Expr *ASTNodeImporter::VisitExpr(Expr *E) {
}
Expr *ASTNodeImporter::VisitDeclRefExpr(DeclRefExpr *E) {
- NestedNameSpecifier *Qualifier = 0;
- if (E->getQualifier()) {
- Qualifier = Importer.Import(E->getQualifier());
- if (!E->getQualifier())
- return 0;
- }
-
ValueDecl *ToD = cast_or_null<ValueDecl>(Importer.Import(E->getDecl()));
if (!ToD)
return 0;
+
+ NamedDecl *FoundD = 0;
+ if (E->getDecl() != E->getFoundDecl()) {
+ FoundD = cast_or_null<NamedDecl>(Importer.Import(E->getFoundDecl()));
+ if (!FoundD)
+ return 0;
+ }
QualType T = Importer.Import(E->getType());
if (T.isNull())
return 0;
- return DeclRefExpr::Create(Importer.getToContext(), Qualifier,
- Importer.Import(E->getQualifierRange()),
+ return DeclRefExpr::Create(Importer.getToContext(),
+ Importer.Import(E->getQualifierLoc()),
ToD,
Importer.Import(E->getLocation()),
T, E->getValueKind(),
+ FoundD,
/*FIXME:TemplateArgs=*/0);
}
@@ -3782,7 +3825,8 @@ Expr *ASTNodeImporter::VisitUnaryOperator(UnaryOperator *E) {
Importer.Import(E->getOperatorLoc()));
}
-Expr *ASTNodeImporter::VisitSizeOfAlignOfExpr(SizeOfAlignOfExpr *E) {
+Expr *ASTNodeImporter::VisitUnaryExprOrTypeTraitExpr(
+ UnaryExprOrTypeTraitExpr *E) {
QualType ResultType = Importer.Import(E->getType());
if (E->isArgumentType()) {
@@ -3790,8 +3834,8 @@ Expr *ASTNodeImporter::VisitSizeOfAlignOfExpr(SizeOfAlignOfExpr *E) {
if (!TInfo)
return 0;
- return new (Importer.getToContext()) SizeOfAlignOfExpr(E->isSizeOf(),
- TInfo, ResultType,
+ return new (Importer.getToContext()) UnaryExprOrTypeTraitExpr(E->getKind(),
+ TInfo, ResultType,
Importer.Import(E->getOperatorLoc()),
Importer.Import(E->getRParenLoc()));
}
@@ -3800,8 +3844,8 @@ Expr *ASTNodeImporter::VisitSizeOfAlignOfExpr(SizeOfAlignOfExpr *E) {
if (!SubExpr)
return 0;
- return new (Importer.getToContext()) SizeOfAlignOfExpr(E->isSizeOf(),
- SubExpr, ResultType,
+ return new (Importer.getToContext()) UnaryExprOrTypeTraitExpr(E->getKind(),
+ SubExpr, ResultType,
Importer.Import(E->getOperatorLoc()),
Importer.Import(E->getRParenLoc()));
}
@@ -3854,7 +3898,7 @@ Expr *ASTNodeImporter::VisitCompoundAssignOperator(CompoundAssignOperator *E) {
Importer.Import(E->getOperatorLoc()));
}
-bool ImportCastPath(CastExpr *E, CXXCastPath &Path) {
+static bool ImportCastPath(CastExpr *E, CXXCastPath &Path) {
if (E->path_empty()) return false;
// TODO: import cast paths
@@ -3973,19 +4017,19 @@ Decl *ASTImporter::Import(Decl *FromD) {
if (TagDecl *FromTag = dyn_cast<TagDecl>(FromD)) {
// Keep track of anonymous tags that have an associated typedef.
- if (FromTag->getTypedefForAnonDecl())
+ if (FromTag->getTypedefNameForAnonDecl())
AnonTagsWithPendingTypedefs.push_back(FromTag);
- } else if (TypedefDecl *FromTypedef = dyn_cast<TypedefDecl>(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 (llvm::SmallVector<TagDecl *, 4>::iterator
FromTag = AnonTagsWithPendingTypedefs.begin(),
FromTagEnd = AnonTagsWithPendingTypedefs.end();
FromTag != FromTagEnd; ++FromTag) {
- if ((*FromTag)->getTypedefForAnonDecl() == FromTypedef) {
+ if ((*FromTag)->getTypedefNameForAnonDecl() == FromTypedef) {
if (TagDecl *ToTag = cast_or_null<TagDecl>(Import(*FromTag))) {
// We found the typedef for an anonymous tag; link them.
- ToTag->setTypedefForAnonDecl(cast<TypedefDecl>(ToD));
+ ToTag->setTypedefNameForAnonDecl(cast<TypedefNameDecl>(ToD));
AnonTagsWithPendingTypedefs.erase(FromTag);
break;
}
@@ -4034,7 +4078,46 @@ NestedNameSpecifier *ASTImporter::Import(NestedNameSpecifier *FromNNS) {
if (!FromNNS)
return 0;
- // FIXME: Implement!
+ NestedNameSpecifier *prefix = Import(FromNNS->getPrefix());
+
+ switch (FromNNS->getKind()) {
+ case NestedNameSpecifier::Identifier:
+ if (IdentifierInfo *II = Import(FromNNS->getAsIdentifier())) {
+ return NestedNameSpecifier::Create(ToContext, prefix, II);
+ }
+ return 0;
+
+ case NestedNameSpecifier::Namespace:
+ if (NamespaceDecl *NS =
+ cast<NamespaceDecl>(Import(FromNNS->getAsNamespace()))) {
+ return NestedNameSpecifier::Create(ToContext, prefix, NS);
+ }
+ return 0;
+
+ case NestedNameSpecifier::NamespaceAlias:
+ if (NamespaceAliasDecl *NSAD =
+ cast<NamespaceAliasDecl>(Import(FromNNS->getAsNamespaceAlias()))) {
+ return NestedNameSpecifier::Create(ToContext, prefix, NSAD);
+ }
+ return 0;
+
+ case NestedNameSpecifier::Global:
+ return NestedNameSpecifier::GlobalSpecifier(ToContext);
+
+ case NestedNameSpecifier::TypeSpec:
+ case NestedNameSpecifier::TypeSpecWithTemplate: {
+ QualType T = Import(QualType(FromNNS->getAsType(), 0u));
+ if (!T.isNull()) {
+ bool bTemplate = FromNNS->getKind() ==
+ NestedNameSpecifier::TypeSpecWithTemplate;
+ return NestedNameSpecifier::Create(ToContext, prefix,
+ bTemplate, T.getTypePtr());
+ }
+ }
+ return 0;
+ }
+
+ llvm_unreachable("Invalid nested name specifier kind");
return 0;
}
@@ -4156,12 +4239,12 @@ FileID ASTImporter::Import(FileID FromID) {
// Map the FileID for to the "to" source manager.
FileID ToID;
const SrcMgr::ContentCache *Cache = FromSLoc.getFile().getContentCache();
- if (Cache->Entry) {
+ if (Cache->OrigEntry) {
// FIXME: We probably want to use getVirtualFile(), so we don't hit the
// disk again
// FIXME: We definitely want to re-use the existing MemoryBuffer, rather
// than mmap the files several times.
- const FileEntry *Entry = ToFileManager.getFile(Cache->Entry->getName());
+ const FileEntry *Entry = ToFileManager.getFile(Cache->OrigEntry->getName());
ToID = ToSM.createFileID(Entry, ToIncludeLoc,
FromSLoc.getFile().getFileCharacteristic());
} else {
diff --git a/lib/AST/CMakeLists.txt b/lib/AST/CMakeLists.txt
index 9fe18407a839..63583a02bfd1 100644
--- a/lib/AST/CMakeLists.txt
+++ b/lib/AST/CMakeLists.txt
@@ -24,6 +24,7 @@ add_clang_library(clangAST
ExprClassification.cpp
ExprConstant.cpp
ExprCXX.cpp
+ ExternalASTSource.cpp
InheritViz.cpp
ItaniumCXXABI.cpp
ItaniumMangle.cpp
diff --git a/lib/AST/CXXInheritance.cpp b/lib/AST/CXXInheritance.cpp
index ca9ec18b3997..9ffe1f865689 100644
--- a/lib/AST/CXXInheritance.cpp
+++ b/lib/AST/CXXInheritance.cpp
@@ -415,7 +415,7 @@ FindNestedNameSpecifierMember(const CXXBaseSpecifier *Specifier,
Path.Decls.first != Path.Decls.second;
++Path.Decls.first) {
// FIXME: Refactor the "is it a nested-name-specifier?" check
- if (isa<TypedefDecl>(*Path.Decls.first) ||
+ if (isa<TypedefNameDecl>(*Path.Decls.first) ||
(*Path.Decls.first)->isInIdentifierNamespace(IDNS_Tag))
return true;
}
diff --git a/lib/AST/Decl.cpp b/lib/AST/Decl.cpp
index 73fe117b1e4e..b21ba9a65e76 100644
--- a/lib/AST/Decl.cpp
+++ b/lib/AST/Decl.cpp
@@ -25,6 +25,7 @@
#include "clang/Basic/Builtins.h"
#include "clang/Basic/IdentifierTable.h"
#include "clang/Basic/Specifiers.h"
+#include "clang/Basic/TargetInfo.h"
#include "llvm/Support/ErrorHandling.h"
using namespace clang;
@@ -33,53 +34,33 @@ using namespace clang;
// NamedDecl Implementation
//===----------------------------------------------------------------------===//
-static const VisibilityAttr *GetExplicitVisibility(const Decl *d) {
- // Use the most recent declaration of a variable.
- if (const VarDecl *var = dyn_cast<VarDecl>(d))
- return var->getMostRecentDeclaration()->getAttr<VisibilityAttr>();
-
- // Use the most recent declaration of a function, and also handle
- // function template specializations.
- if (const FunctionDecl *fn = dyn_cast<FunctionDecl>(d)) {
- if (const VisibilityAttr *attr
- = fn->getMostRecentDeclaration()->getAttr<VisibilityAttr>())
- return attr;
-
- // If the function is a specialization of a template with an
- // explicit visibility attribute, use that.
- if (FunctionTemplateSpecializationInfo *templateInfo
- = fn->getTemplateSpecializationInfo())
- return templateInfo->getTemplate()->getTemplatedDecl()
- ->getAttr<VisibilityAttr>();
+static llvm::Optional<Visibility> getVisibilityOf(const Decl *D) {
+ // If this declaration has an explicit visibility attribute, use it.
+ if (const VisibilityAttr *A = D->getAttr<VisibilityAttr>()) {
+ switch (A->getVisibility()) {
+ case VisibilityAttr::Default:
+ return DefaultVisibility;
+ case VisibilityAttr::Hidden:
+ return HiddenVisibility;
+ case VisibilityAttr::Protected:
+ return ProtectedVisibility;
+ }
- return 0;
+ return DefaultVisibility;
}
- // Otherwise, just check the declaration itself first.
- if (const VisibilityAttr *attr = d->getAttr<VisibilityAttr>())
- return attr;
-
- // If there wasn't explicit visibility there, and this is a
- // specialization of a class template, check for visibility
- // on the pattern.
- if (const ClassTemplateSpecializationDecl *spec
- = dyn_cast<ClassTemplateSpecializationDecl>(d))
- return spec->getSpecializedTemplate()->getTemplatedDecl()
- ->getAttr<VisibilityAttr>();
-
- return 0;
-}
-
-static Visibility GetVisibilityFromAttr(const VisibilityAttr *A) {
- switch (A->getVisibility()) {
- case VisibilityAttr::Default:
- return DefaultVisibility;
- case VisibilityAttr::Hidden:
- return HiddenVisibility;
- case VisibilityAttr::Protected:
- return ProtectedVisibility;
+ // If we're on Mac OS X, an 'availability' for Mac OS X attribute
+ // implies visibility(default).
+ if (D->getASTContext().Target.getTriple().isOSDarwin()) {
+ for (specific_attr_iterator<AvailabilityAttr>
+ A = D->specific_attr_begin<AvailabilityAttr>(),
+ AEnd = D->specific_attr_end<AvailabilityAttr>();
+ A != AEnd; ++A)
+ if ((*A)->getPlatform()->getName().equals("macosx"))
+ return DefaultVisibility;
}
- return DefaultVisibility;
+
+ return llvm::Optional<Visibility>();
}
typedef NamedDecl::LinkageInfo LinkageInfo;
@@ -100,9 +81,11 @@ namespace {
struct LVFlags {
bool ConsiderGlobalVisibility;
bool ConsiderVisibilityAttributes;
+ bool ConsiderTemplateParameterTypes;
LVFlags() : ConsiderGlobalVisibility(true),
- ConsiderVisibilityAttributes(true) {
+ ConsiderVisibilityAttributes(true),
+ ConsiderTemplateParameterTypes(true) {
}
/// \brief Returns a set of flags that is only useful for computing the
@@ -111,6 +94,7 @@ struct LVFlags {
LVFlags F;
F.ConsiderGlobalVisibility = false;
F.ConsiderVisibilityAttributes = false;
+ F.ConsiderTemplateParameterTypes = false;
return F;
}
@@ -120,6 +104,7 @@ struct LVFlags {
LVFlags F = *this;
F.ConsiderGlobalVisibility = false;
F.ConsiderVisibilityAttributes = false;
+ F.ConsiderTemplateParameterTypes = false;
return F;
}
};
@@ -282,8 +267,8 @@ static LinkageInfo getLVForNamespaceScopeDecl(const NamedDecl *D, LVFlags F) {
LinkageInfo LV;
if (F.ConsiderVisibilityAttributes) {
- if (const VisibilityAttr *VA = GetExplicitVisibility(D)) {
- LV.setVisibility(GetVisibilityFromAttr(VA), true);
+ if (llvm::Optional<Visibility> Vis = D->getExplicitVisibility()) {
+ LV.setVisibility(*Vis, true);
F.ConsiderGlobalVisibility = false;
} else {
// If we're declared in a namespace with a visibility attribute,
@@ -292,9 +277,9 @@ static LinkageInfo getLVForNamespaceScopeDecl(const NamedDecl *D, LVFlags F) {
!isa<TranslationUnitDecl>(DC);
DC = DC->getParent()) {
if (!isa<NamespaceDecl>(DC)) continue;
- if (const VisibilityAttr *VA =
- cast<NamespaceDecl>(DC)->getAttr<VisibilityAttr>()) {
- LV.setVisibility(GetVisibilityFromAttr(VA), false);
+ if (llvm::Optional<Visibility> Vis
+ = cast<NamespaceDecl>(DC)->getExplicitVisibility()) {
+ LV.setVisibility(*Vis, false);
F.ConsiderGlobalVisibility = false;
break;
}
@@ -420,7 +405,7 @@ static LinkageInfo getLVForNamespaceScopeDecl(const NamedDecl *D, LVFlags F) {
// has the typedef name for linkage purposes (7.1.3); or
} else if (const TagDecl *Tag = dyn_cast<TagDecl>(D)) {
// Unnamed tags have no linkage.
- if (!Tag->getDeclName() && !Tag->getTypedefForAnonDecl())
+ if (!Tag->getDeclName() && !Tag->getTypedefNameForAnonDecl())
return LinkageInfo::none();
// If this is a class template specialization, consider the
@@ -451,8 +436,9 @@ static LinkageInfo getLVForNamespaceScopeDecl(const NamedDecl *D, LVFlags F) {
// - a template, unless it is a function template that has
// internal linkage (Clause 14);
- } else if (const TemplateDecl *Template = dyn_cast<TemplateDecl>(D)) {
- LV.merge(getLVForTemplateParameterList(Template->getTemplateParameters()));
+ } else if (const TemplateDecl *temp = dyn_cast<TemplateDecl>(D)) {
+ if (F.ConsiderTemplateParameterTypes)
+ LV.merge(getLVForTemplateParameterList(temp->getTemplateParameters()));
// - a namespace (7.3), unless it is declared within an unnamed
// namespace.
@@ -491,7 +477,7 @@ static LinkageInfo getLVForClassMember(const NamedDecl *D, LVFlags F) {
isa<VarDecl>(D) ||
isa<FieldDecl>(D) ||
(isa<TagDecl>(D) &&
- (D->getDeclName() || cast<TagDecl>(D)->getTypedefForAnonDecl()))))
+ (D->getDeclName() || cast<TagDecl>(D)->getTypedefNameForAnonDecl()))))
return LinkageInfo::none();
LinkageInfo LV;
@@ -501,8 +487,8 @@ static LinkageInfo getLVForClassMember(const NamedDecl *D, LVFlags F) {
// If we have an explicit visibility attribute, merge that in.
if (F.ConsiderVisibilityAttributes) {
- if (const VisibilityAttr *VA = GetExplicitVisibility(D)) {
- LV.mergeVisibility(GetVisibilityFromAttr(VA), true);
+ if (llvm::Optional<Visibility> Vis = D->getExplicitVisibility()) {
+ LV.mergeVisibility(*Vis, true);
// Ignore global visibility later, but not this attribute.
F.ConsiderGlobalVisibility = false;
@@ -536,7 +522,8 @@ static LinkageInfo getLVForClassMember(const NamedDecl *D, LVFlags F) {
if (FunctionTemplateSpecializationInfo *Spec
= MD->getTemplateSpecializationInfo()) {
LV.merge(getLVForTemplateArgumentList(*Spec->TemplateArguments, F));
- LV.merge(getLVForTemplateParameterList(
+ if (F.ConsiderTemplateParameterTypes)
+ LV.merge(getLVForTemplateParameterList(
Spec->getTemplate()->getTemplateParameters()));
TSK = Spec->getTemplateSpecializationKind();
@@ -571,7 +558,8 @@ static LinkageInfo getLVForClassMember(const NamedDecl *D, LVFlags F) {
// Merge template argument/parameter information for member
// class template specializations.
LV.merge(getLVForTemplateArgumentList(Spec->getTemplateArgs(), F));
- LV.merge(getLVForTemplateParameterList(
+ if (F.ConsiderTemplateParameterTypes)
+ LV.merge(getLVForTemplateParameterList(
Spec->getSpecializedTemplate()->getTemplateParameters()));
}
@@ -632,10 +620,12 @@ void NamedDecl::ClearLinkageCache() {
// Clear cached linkage for function template decls, too.
if (FunctionTemplateDecl *temp =
- dyn_cast<FunctionTemplateDecl>(const_cast<NamedDecl*>(this)))
+ dyn_cast<FunctionTemplateDecl>(const_cast<NamedDecl*>(this))) {
+ temp->getTemplatedDecl()->ClearLinkageCache();
for (FunctionTemplateDecl::spec_iterator
i = temp->spec_begin(), e = temp->spec_end(); i != e; ++i)
i->ClearLinkageCache();
+ }
}
@@ -660,6 +650,41 @@ LinkageInfo NamedDecl::getLinkageAndVisibility() const {
return LI;
}
+llvm::Optional<Visibility> NamedDecl::getExplicitVisibility() const {
+ // Use the most recent declaration of a variable.
+ if (const VarDecl *var = dyn_cast<VarDecl>(this))
+ return getVisibilityOf(var->getMostRecentDeclaration());
+
+ // Use the most recent declaration of a function, and also handle
+ // function template specializations.
+ if (const FunctionDecl *fn = dyn_cast<FunctionDecl>(this)) {
+ if (llvm::Optional<Visibility> V
+ = getVisibilityOf(fn->getMostRecentDeclaration()))
+ return V;
+
+ // If the function is a specialization of a template with an
+ // explicit visibility attribute, use that.
+ if (FunctionTemplateSpecializationInfo *templateInfo
+ = fn->getTemplateSpecializationInfo())
+ return getVisibilityOf(templateInfo->getTemplate()->getTemplatedDecl());
+
+ return llvm::Optional<Visibility>();
+ }
+
+ // Otherwise, just check the declaration itself first.
+ if (llvm::Optional<Visibility> V = getVisibilityOf(this))
+ return V;
+
+ // If there wasn't explicit visibility there, and this is a
+ // specialization of a class template, check for visibility
+ // on the pattern.
+ if (const ClassTemplateSpecializationDecl *spec
+ = dyn_cast<ClassTemplateSpecializationDecl>(this))
+ return getVisibilityOf(spec->getSpecializedTemplate()->getTemplatedDecl());
+
+ return llvm::Optional<Visibility>();
+}
+
static LinkageInfo getLVForDecl(const NamedDecl *D, LVFlags Flags) {
// Objective-C: treat all Objective-C declarations as having external
// linkage.
@@ -713,8 +738,8 @@ static LinkageInfo getLVForDecl(const NamedDecl *D, LVFlags Flags) {
LinkageInfo LV;
if (Flags.ConsiderVisibilityAttributes) {
- if (const VisibilityAttr *VA = GetExplicitVisibility(Function))
- LV.setVisibility(GetVisibilityFromAttr(VA));
+ if (llvm::Optional<Visibility> Vis = Function->getExplicitVisibility())
+ LV.setVisibility(*Vis);
}
if (const FunctionDecl *Prev = Function->getPreviousDeclaration()) {
@@ -736,8 +761,8 @@ static LinkageInfo getLVForDecl(const NamedDecl *D, LVFlags Flags) {
if (Var->getStorageClass() == SC_PrivateExtern)
LV.setVisibility(HiddenVisibility);
else if (Flags.ConsiderVisibilityAttributes) {
- if (const VisibilityAttr *VA = GetExplicitVisibility(Var))
- LV.setVisibility(GetVisibilityFromAttr(VA));
+ if (llvm::Optional<Visibility> Vis = Var->getExplicitVisibility())
+ LV.setVisibility(*Vis);
}
if (const VarDecl *Prev = Var->getPreviousDeclaration()) {
@@ -954,28 +979,97 @@ void DeclaratorDecl::setQualifierInfo(NestedNameSpecifierLoc QualifierLoc) {
else {
// Here Qualifier == 0, i.e., we are removing the qualifier (if any).
if (hasExtInfo()) {
- // Save type source info pointer.
- TypeSourceInfo *savedTInfo = getExtInfo()->TInfo;
- // Deallocate the extended decl info.
- getASTContext().Deallocate(getExtInfo());
- // Restore savedTInfo into (non-extended) decl info.
- DeclInfo = savedTInfo;
+ if (getExtInfo()->NumTemplParamLists == 0) {
+ // Save type source info pointer.
+ TypeSourceInfo *savedTInfo = getExtInfo()->TInfo;
+ // Deallocate the extended decl info.
+ getASTContext().Deallocate(getExtInfo());
+ // Restore savedTInfo into (non-extended) decl info.
+ DeclInfo = savedTInfo;
+ }
+ else
+ getExtInfo()->QualifierLoc = QualifierLoc;
}
}
}
+void
+DeclaratorDecl::setTemplateParameterListsInfo(ASTContext &Context,
+ unsigned NumTPLists,
+ TemplateParameterList **TPLists) {
+ assert(NumTPLists > 0);
+ // Make sure the extended decl info is allocated.
+ if (!hasExtInfo()) {
+ // Save (non-extended) type source info pointer.
+ TypeSourceInfo *savedTInfo = DeclInfo.get<TypeSourceInfo*>();
+ // Allocate external info struct.
+ DeclInfo = new (getASTContext()) ExtInfo;
+ // Restore savedTInfo into (extended) decl info.
+ getExtInfo()->TInfo = savedTInfo;
+ }
+ // Set the template parameter lists info.
+ getExtInfo()->setTemplateParameterListsInfo(Context, NumTPLists, TPLists);
+}
+
SourceLocation DeclaratorDecl::getOuterLocStart() const {
return getTemplateOrInnerLocStart(this);
}
+namespace {
+
+// Helper function: returns true if QT is or contains a type
+// having a postfix component.
+bool typeIsPostfix(clang::QualType QT) {
+ while (true) {
+ const Type* T = QT.getTypePtr();
+ switch (T->getTypeClass()) {
+ default:
+ return false;
+ case Type::Pointer:
+ QT = cast<PointerType>(T)->getPointeeType();
+ break;
+ case Type::BlockPointer:
+ QT = cast<BlockPointerType>(T)->getPointeeType();
+ break;
+ case Type::MemberPointer:
+ QT = cast<MemberPointerType>(T)->getPointeeType();
+ break;
+ case Type::LValueReference:
+ case Type::RValueReference:
+ QT = cast<ReferenceType>(T)->getPointeeType();
+ break;
+ case Type::PackExpansion:
+ QT = cast<PackExpansionType>(T)->getPattern();
+ break;
+ case Type::Paren:
+ case Type::ConstantArray:
+ case Type::DependentSizedArray:
+ case Type::IncompleteArray:
+ case Type::VariableArray:
+ case Type::FunctionProto:
+ case Type::FunctionNoProto:
+ return true;
+ }
+ }
+}
+
+} // namespace
+
+SourceRange DeclaratorDecl::getSourceRange() const {
+ SourceLocation RangeEnd = getLocation();
+ if (TypeSourceInfo *TInfo = getTypeSourceInfo()) {
+ if (typeIsPostfix(TInfo->getType()))
+ RangeEnd = TInfo->getTypeLoc().getSourceRange().getEnd();
+ }
+ return SourceRange(getOuterLocStart(), RangeEnd);
+}
+
void
QualifierInfo::setTemplateParameterListsInfo(ASTContext &Context,
unsigned NumTPLists,
TemplateParameterList **TPLists) {
assert((NumTPLists == 0 || TPLists != 0) &&
"Empty array of template parameters with positive size!");
- assert((NumTPLists == 0 || QualifierLoc) &&
- "Nonempty array of template parameters with no qualifier!");
// Free previous template parameters (if any).
if (NumTemplParamLists > 0) {
@@ -1010,10 +1104,11 @@ const char *VarDecl::getStorageClassSpecifierString(StorageClass SC) {
return 0;
}
-VarDecl *VarDecl::Create(ASTContext &C, DeclContext *DC, SourceLocation L,
+VarDecl *VarDecl::Create(ASTContext &C, DeclContext *DC,
+ SourceLocation StartL, SourceLocation IdL,
IdentifierInfo *Id, QualType T, TypeSourceInfo *TInfo,
StorageClass S, StorageClass SCAsWritten) {
- return new (C) VarDecl(Var, DC, L, Id, T, TInfo, S, SCAsWritten);
+ return new (C) VarDecl(Var, DC, StartL, IdL, Id, T, TInfo, S, SCAsWritten);
}
void VarDecl::setStorageClass(StorageClass SC) {
@@ -1021,20 +1116,13 @@ void VarDecl::setStorageClass(StorageClass SC) {
if (getStorageClass() != SC)
ClearLinkageCache();
- SClass = SC;
-}
-
-SourceLocation VarDecl::getInnerLocStart() const {
- SourceLocation Start = getTypeSpecStartLoc();
- if (Start.isInvalid())
- Start = getLocation();
- return Start;
+ VarDeclBits.SClass = SC;
}
SourceRange VarDecl::getSourceRange() const {
if (getInit())
return SourceRange(getOuterLocStart(), getInit()->getLocEnd());
- return SourceRange(getOuterLocStart(), getLocation());
+ return DeclaratorDecl::getSourceRange();
}
bool VarDecl::isExternC() const {
@@ -1250,11 +1338,12 @@ void VarDecl::setTemplateSpecializationKind(TemplateSpecializationKind TSK,
//===----------------------------------------------------------------------===//
ParmVarDecl *ParmVarDecl::Create(ASTContext &C, DeclContext *DC,
- SourceLocation L, IdentifierInfo *Id,
+ SourceLocation StartLoc,
+ SourceLocation IdLoc, IdentifierInfo *Id,
QualType T, TypeSourceInfo *TInfo,
StorageClass S, StorageClass SCAsWritten,
Expr *DefArg) {
- return new (C) ParmVarDecl(ParmVar, DC, L, Id, T, TInfo,
+ return new (C) ParmVarDecl(ParmVar, DC, StartLoc, IdLoc, Id, T, TInfo,
S, SCAsWritten, DefArg);
}
@@ -1324,7 +1413,7 @@ bool FunctionDecl::isVariadic() const {
bool FunctionDecl::hasBody(const FunctionDecl *&Definition) const {
for (redecl_iterator I = redecls_begin(), E = redecls_end(); I != E; ++I) {
- if (I->Body) {
+ if (I->Body || I->IsLateTemplateParsed) {
Definition = *I;
return true;
}
@@ -1338,6 +1427,9 @@ Stmt *FunctionDecl::getBody(const FunctionDecl *&Definition) const {
if (I->Body) {
Definition = *I;
return I->Body.get(getASTContext().getExternalSource());
+ } else if (I->IsLateTemplateParsed) {
+ Definition = *I;
+ return 0;
}
}
@@ -1804,7 +1896,7 @@ FunctionDecl::setFunctionTemplateSpecialization(ASTContext &C,
// Insert this function template specialization into the set of known
// function template specializations.
if (InsertPos)
- Template->getSpecializations().InsertNode(Info, InsertPos);
+ Template->addSpecialization(Info, InsertPos);
else {
// Try to insert the new node. If there is an existing node, leave it, the
// set will contain the canonical decls while
@@ -1925,14 +2017,20 @@ bool FunctionDecl::isOutOfLine() const {
return false;
}
+SourceRange FunctionDecl::getSourceRange() const {
+ return SourceRange(getOuterLocStart(), EndRangeLoc);
+}
+
//===----------------------------------------------------------------------===//
// FieldDecl Implementation
//===----------------------------------------------------------------------===//
FieldDecl *FieldDecl::Create(const ASTContext &C, DeclContext *DC,
- SourceLocation L, IdentifierInfo *Id, QualType T,
+ SourceLocation StartLoc, SourceLocation IdLoc,
+ IdentifierInfo *Id, QualType T,
TypeSourceInfo *TInfo, Expr *BW, bool Mutable) {
- return new (C) FieldDecl(Decl::Field, DC, L, Id, T, TInfo, BW, Mutable);
+ return new (C) FieldDecl(Decl::Field, DC, StartLoc, IdLoc, Id, T, TInfo,
+ BW, Mutable);
}
bool FieldDecl::isAnonymousStructOrUnion() const {
@@ -1949,13 +2047,25 @@ unsigned FieldDecl::getFieldIndex() const {
if (CachedFieldIndex) return CachedFieldIndex - 1;
unsigned index = 0;
- RecordDecl::field_iterator
- i = getParent()->field_begin(), e = getParent()->field_end();
+ const RecordDecl *RD = getParent();
+ const FieldDecl *LastFD = 0;
+ bool IsMsStruct = RD->hasAttr<MsStructAttr>();
+
+ RecordDecl::field_iterator i = RD->field_begin(), e = RD->field_end();
while (true) {
assert(i != e && "failed to find field in parent!");
if (*i == this)
break;
+ if (IsMsStruct) {
+ // Zero-length bitfields following non-bitfield members are ignored.
+ if (getASTContext().ZeroBitfieldFollowsNonBitfield((*i), LastFD) ||
+ getASTContext().ZeroBitfieldFollowsBitfield((*i), LastFD)) {
+ ++i;
+ continue;
+ }
+ LastFD = (*i);
+ }
++i;
++index;
}
@@ -1964,6 +2074,12 @@ unsigned FieldDecl::getFieldIndex() const {
return index;
}
+SourceRange FieldDecl::getSourceRange() const {
+ if (isBitField())
+ return SourceRange(getInnerLocStart(), BitWidth->getLocEnd());
+ return DeclaratorDecl::getSourceRange();
+}
+
//===----------------------------------------------------------------------===//
// TagDecl Implementation
//===----------------------------------------------------------------------===//
@@ -1981,8 +2097,8 @@ TagDecl* TagDecl::getCanonicalDecl() {
return getFirstDeclaration();
}
-void TagDecl::setTypedefForAnonDecl(TypedefDecl *TDD) {
- TypedefDeclOrQualifier = TDD;
+void TagDecl::setTypedefNameForAnonDecl(TypedefNameDecl *TDD) {
+ TypedefNameDeclOrQualifier = TDD;
if (TypeForDecl)
const_cast<Type*>(TypeForDecl)->ClearLinkageCache();
ClearLinkageCache();
@@ -2030,35 +2146,52 @@ void TagDecl::setQualifierInfo(NestedNameSpecifierLoc QualifierLoc) {
if (QualifierLoc) {
// Make sure the extended qualifier info is allocated.
if (!hasExtInfo())
- TypedefDeclOrQualifier = new (getASTContext()) ExtInfo;
+ TypedefNameDeclOrQualifier = new (getASTContext()) ExtInfo;
// Set qualifier info.
getExtInfo()->QualifierLoc = QualifierLoc;
}
else {
// Here Qualifier == 0, i.e., we are removing the qualifier (if any).
if (hasExtInfo()) {
- getASTContext().Deallocate(getExtInfo());
- TypedefDeclOrQualifier = (TypedefDecl*) 0;
+ if (getExtInfo()->NumTemplParamLists == 0) {
+ getASTContext().Deallocate(getExtInfo());
+ TypedefNameDeclOrQualifier = (TypedefNameDecl*) 0;
+ }
+ else
+ getExtInfo()->QualifierLoc = QualifierLoc;
}
}
}
+void TagDecl::setTemplateParameterListsInfo(ASTContext &Context,
+ unsigned NumTPLists,
+ TemplateParameterList **TPLists) {
+ assert(NumTPLists > 0);
+ // Make sure the extended decl info is allocated.
+ if (!hasExtInfo())
+ // Allocate external info struct.
+ TypedefNameDeclOrQualifier = new (getASTContext()) ExtInfo;
+ // Set the template parameter lists info.
+ getExtInfo()->setTemplateParameterListsInfo(Context, NumTPLists, TPLists);
+}
+
//===----------------------------------------------------------------------===//
// EnumDecl Implementation
//===----------------------------------------------------------------------===//
-EnumDecl *EnumDecl::Create(ASTContext &C, DeclContext *DC, SourceLocation L,
- IdentifierInfo *Id, SourceLocation TKL,
+EnumDecl *EnumDecl::Create(ASTContext &C, DeclContext *DC,
+ SourceLocation StartLoc, SourceLocation IdLoc,
+ IdentifierInfo *Id,
EnumDecl *PrevDecl, bool IsScoped,
bool IsScopedUsingClassTag, bool IsFixed) {
- EnumDecl *Enum = new (C) EnumDecl(DC, L, Id, PrevDecl, TKL,
+ EnumDecl *Enum = new (C) EnumDecl(DC, StartLoc, IdLoc, Id, PrevDecl,
IsScoped, IsScopedUsingClassTag, IsFixed);
C.getTypeDeclType(Enum, PrevDecl);
return Enum;
}
EnumDecl *EnumDecl::Create(ASTContext &C, EmptyShell Empty) {
- return new (C) EnumDecl(0, SourceLocation(), 0, 0, SourceLocation(),
+ return new (C) EnumDecl(0, SourceLocation(), SourceLocation(), 0, 0,
false, false, false);
}
@@ -2079,10 +2212,10 @@ void EnumDecl::completeDefinition(QualType NewType,
// RecordDecl Implementation
//===----------------------------------------------------------------------===//
-RecordDecl::RecordDecl(Kind DK, TagKind TK, DeclContext *DC, SourceLocation L,
- IdentifierInfo *Id, RecordDecl *PrevDecl,
- SourceLocation TKL)
- : TagDecl(DK, TK, DC, L, Id, PrevDecl, TKL) {
+RecordDecl::RecordDecl(Kind DK, TagKind TK, DeclContext *DC,
+ SourceLocation StartLoc, SourceLocation IdLoc,
+ IdentifierInfo *Id, RecordDecl *PrevDecl)
+ : TagDecl(DK, TK, DC, IdLoc, Id, PrevDecl, StartLoc) {
HasFlexibleArrayMember = false;
AnonymousStructOrUnion = false;
HasObjectMember = false;
@@ -2091,17 +2224,17 @@ RecordDecl::RecordDecl(Kind DK, TagKind TK, DeclContext *DC, SourceLocation L,
}
RecordDecl *RecordDecl::Create(const ASTContext &C, TagKind TK, DeclContext *DC,
- SourceLocation L, IdentifierInfo *Id,
- SourceLocation TKL, RecordDecl* PrevDecl) {
-
- RecordDecl* R = new (C) RecordDecl(Record, TK, DC, L, Id, PrevDecl, TKL);
+ SourceLocation StartLoc, SourceLocation IdLoc,
+ IdentifierInfo *Id, RecordDecl* PrevDecl) {
+ RecordDecl* R = new (C) RecordDecl(Record, TK, DC, StartLoc, IdLoc, Id,
+ PrevDecl);
C.getTypeDeclType(R, PrevDecl);
return R;
}
RecordDecl *RecordDecl::Create(const ASTContext &C, EmptyShell Empty) {
- return new (C) RecordDecl(Record, TTK_Struct, 0, SourceLocation(), 0, 0,
- SourceLocation());
+ return new (C) RecordDecl(Record, TTK_Struct, 0, SourceLocation(),
+ SourceLocation(), 0, 0);
}
bool RecordDecl::isInjectedClassName() const {
@@ -2200,14 +2333,22 @@ TranslationUnitDecl *TranslationUnitDecl::Create(ASTContext &C) {
}
LabelDecl *LabelDecl::Create(ASTContext &C, DeclContext *DC,
- SourceLocation L, IdentifierInfo *II) {
- return new (C) LabelDecl(DC, L, II, 0);
+ SourceLocation IdentL, IdentifierInfo *II) {
+ return new (C) LabelDecl(DC, IdentL, II, 0, IdentL);
+}
+
+LabelDecl *LabelDecl::Create(ASTContext &C, DeclContext *DC,
+ SourceLocation IdentL, IdentifierInfo *II,
+ SourceLocation GnuLabelL) {
+ assert(GnuLabelL != IdentL && "Use this only for GNU local labels");
+ return new (C) LabelDecl(DC, IdentL, II, 0, GnuLabelL);
}
NamespaceDecl *NamespaceDecl::Create(ASTContext &C, DeclContext *DC,
- SourceLocation L, IdentifierInfo *Id) {
- return new (C) NamespaceDecl(DC, L, Id);
+ SourceLocation StartLoc,
+ SourceLocation IdLoc, IdentifierInfo *Id) {
+ return new (C) NamespaceDecl(DC, StartLoc, IdLoc, Id);
}
NamespaceDecl *NamespaceDecl::getNextNamespace() {
@@ -2216,20 +2357,22 @@ NamespaceDecl *NamespaceDecl::getNextNamespace() {
}
ImplicitParamDecl *ImplicitParamDecl::Create(ASTContext &C, DeclContext *DC,
- SourceLocation loc,
- IdentifierInfo *name,
- QualType type) {
- return new (C) ImplicitParamDecl(DC, loc, name, type);
+ SourceLocation IdLoc,
+ IdentifierInfo *Id,
+ QualType Type) {
+ return new (C) ImplicitParamDecl(DC, IdLoc, Id, Type);
}
FunctionDecl *FunctionDecl::Create(ASTContext &C, DeclContext *DC,
+ SourceLocation StartLoc,
const DeclarationNameInfo &NameInfo,
QualType T, TypeSourceInfo *TInfo,
- StorageClass S, StorageClass SCAsWritten,
+ StorageClass SC, StorageClass SCAsWritten,
bool isInlineSpecified,
bool hasWrittenPrototype) {
- FunctionDecl *New = new (C) FunctionDecl(Function, DC, NameInfo, T, TInfo,
- S, SCAsWritten, isInlineSpecified);
+ FunctionDecl *New = new (C) FunctionDecl(Function, DC, StartLoc, NameInfo,
+ T, TInfo, SC, SCAsWritten,
+ isInlineSpecified);
New->HasWrittenPrototype = hasWrittenPrototype;
return New;
}
@@ -2260,13 +2403,37 @@ SourceRange EnumConstantDecl::getSourceRange() const {
}
TypedefDecl *TypedefDecl::Create(ASTContext &C, DeclContext *DC,
- SourceLocation L, IdentifierInfo *Id,
- TypeSourceInfo *TInfo) {
- return new (C) TypedefDecl(DC, L, Id, TInfo);
+ SourceLocation StartLoc, SourceLocation IdLoc,
+ IdentifierInfo *Id, TypeSourceInfo *TInfo) {
+ return new (C) TypedefDecl(DC, StartLoc, IdLoc, Id, TInfo);
+}
+
+TypeAliasDecl *TypeAliasDecl::Create(ASTContext &C, DeclContext *DC,
+ SourceLocation StartLoc,
+ SourceLocation IdLoc, IdentifierInfo *Id,
+ TypeSourceInfo *TInfo) {
+ return new (C) TypeAliasDecl(DC, StartLoc, IdLoc, Id, TInfo);
+}
+
+SourceRange TypedefDecl::getSourceRange() const {
+ SourceLocation RangeEnd = getLocation();
+ if (TypeSourceInfo *TInfo = getTypeSourceInfo()) {
+ if (typeIsPostfix(TInfo->getType()))
+ RangeEnd = TInfo->getTypeLoc().getSourceRange().getEnd();
+ }
+ return SourceRange(getLocStart(), RangeEnd);
+}
+
+SourceRange TypeAliasDecl::getSourceRange() const {
+ SourceLocation RangeEnd = getLocStart();
+ if (TypeSourceInfo *TInfo = getTypeSourceInfo())
+ RangeEnd = TInfo->getTypeLoc().getSourceRange().getEnd();
+ return SourceRange(getLocStart(), RangeEnd);
}
FileScopeAsmDecl *FileScopeAsmDecl::Create(ASTContext &C, DeclContext *DC,
- SourceLocation L,
- StringLiteral *Str) {
- return new (C) FileScopeAsmDecl(DC, L, Str);
+ StringLiteral *Str,
+ SourceLocation AsmLoc,
+ SourceLocation RParenLoc) {
+ return new (C) FileScopeAsmDecl(DC, Str, AsmLoc, RParenLoc);
}
diff --git a/lib/AST/DeclBase.cpp b/lib/AST/DeclBase.cpp
index 81df00d6c7e8..6d517c544089 100644
--- a/lib/AST/DeclBase.cpp
+++ b/lib/AST/DeclBase.cpp
@@ -25,11 +25,11 @@
#include "clang/AST/Stmt.h"
#include "clang/AST/StmtCXX.h"
#include "clang/AST/ASTMutationListener.h"
+#include "clang/Basic/TargetInfo.h"
#include "llvm/ADT/DenseMap.h"
#include "llvm/Support/raw_ostream.h"
#include <algorithm>
#include <cstdio>
-#include <vector>
using namespace clang;
//===----------------------------------------------------------------------===//
@@ -173,9 +173,6 @@ void PrettyStackTraceDecl::print(llvm::raw_ostream &OS) const {
Decl::~Decl() { }
void Decl::setDeclContext(DeclContext *DC) {
- if (isOutOfSemaDC())
- delete getMultipleDC();
-
DeclCtx = DC;
}
@@ -244,6 +241,177 @@ bool Decl::isUsed(bool CheckUsedAttr) const {
return false;
}
+bool Decl::isReferenced() const {
+ if (Referenced)
+ return true;
+
+ // Check redeclarations.
+ for (redecl_iterator I = redecls_begin(), E = redecls_end(); I != E; ++I)
+ if (I->Referenced)
+ return true;
+
+ return false;
+}
+
+/// \brief Determine the availability of the given declaration based on
+/// the target platform.
+///
+/// When it returns an availability result other than \c AR_Available,
+/// if the \p Message parameter is non-NULL, it will be set to a
+/// string describing why the entity is unavailable.
+///
+/// FIXME: Make these strings localizable, since they end up in
+/// diagnostics.
+static AvailabilityResult CheckAvailability(ASTContext &Context,
+ const AvailabilityAttr *A,
+ std::string *Message) {
+ llvm::StringRef TargetPlatform = Context.Target.getPlatformName();
+ llvm::StringRef PrettyPlatformName
+ = AvailabilityAttr::getPrettyPlatformName(TargetPlatform);
+ if (PrettyPlatformName.empty())
+ PrettyPlatformName = TargetPlatform;
+
+ VersionTuple TargetMinVersion = Context.Target.getPlatformMinVersion();
+ if (TargetMinVersion.empty())
+ return AR_Available;
+
+ // Match the platform name.
+ if (A->getPlatform()->getName() != TargetPlatform)
+ return AR_Available;
+
+ // Make sure that this declaration has not been marked 'unavailable'.
+ if (A->getUnavailable()) {
+ if (Message) {
+ Message->clear();
+ llvm::raw_string_ostream Out(*Message);
+ Out << "not available on " << PrettyPlatformName;
+ }
+
+ return AR_Unavailable;
+ }
+
+ // Make sure that this declaration has already been introduced.
+ if (!A->getIntroduced().empty() &&
+ TargetMinVersion < A->getIntroduced()) {
+ if (Message) {
+ Message->clear();
+ llvm::raw_string_ostream Out(*Message);
+ Out << "introduced in " << PrettyPlatformName << ' '
+ << A->getIntroduced();
+ }
+
+ return AR_NotYetIntroduced;
+ }
+
+ // Make sure that this declaration hasn't been obsoleted.
+ if (!A->getObsoleted().empty() && TargetMinVersion >= A->getObsoleted()) {
+ if (Message) {
+ Message->clear();
+ llvm::raw_string_ostream Out(*Message);
+ Out << "obsoleted in " << PrettyPlatformName << ' '
+ << A->getObsoleted();
+ }
+
+ return AR_Unavailable;
+ }
+
+ // Make sure that this declaration hasn't been deprecated.
+ if (!A->getDeprecated().empty() && TargetMinVersion >= A->getDeprecated()) {
+ if (Message) {
+ Message->clear();
+ llvm::raw_string_ostream Out(*Message);
+ Out << "first deprecated in " << PrettyPlatformName << ' '
+ << A->getDeprecated();
+ }
+
+ return AR_Deprecated;
+ }
+
+ return AR_Available;
+}
+
+AvailabilityResult Decl::getAvailability(std::string *Message) const {
+ AvailabilityResult Result = AR_Available;
+ std::string ResultMessage;
+
+ for (attr_iterator A = attr_begin(), AEnd = attr_end(); A != AEnd; ++A) {
+ if (DeprecatedAttr *Deprecated = dyn_cast<DeprecatedAttr>(*A)) {
+ if (Result >= AR_Deprecated)
+ continue;
+
+ if (Message)
+ ResultMessage = Deprecated->getMessage();
+
+ Result = AR_Deprecated;
+ continue;
+ }
+
+ if (UnavailableAttr *Unavailable = dyn_cast<UnavailableAttr>(*A)) {
+ if (Message)
+ *Message = Unavailable->getMessage();
+ return AR_Unavailable;
+ }
+
+ if (AvailabilityAttr *Availability = dyn_cast<AvailabilityAttr>(*A)) {
+ AvailabilityResult AR = CheckAvailability(getASTContext(), Availability,
+ Message);
+
+ if (AR == AR_Unavailable)
+ return AR_Unavailable;
+
+ if (AR > Result) {
+ Result = AR;
+ if (Message)
+ ResultMessage.swap(*Message);
+ }
+ continue;
+ }
+ }
+
+ if (Message)
+ Message->swap(ResultMessage);
+ return Result;
+}
+
+bool Decl::canBeWeakImported(bool &IsDefinition) const {
+ IsDefinition = false;
+ if (const VarDecl *Var = dyn_cast<VarDecl>(this)) {
+ if (!Var->hasExternalStorage() || Var->getInit()) {
+ IsDefinition = true;
+ return false;
+ }
+ } else if (const FunctionDecl *FD = dyn_cast<FunctionDecl>(this)) {
+ if (FD->hasBody()) {
+ IsDefinition = true;
+ return false;
+ }
+ } else if (isa<ObjCPropertyDecl>(this) || isa<ObjCMethodDecl>(this))
+ return false;
+ else if (!(getASTContext().getLangOptions().ObjCNonFragileABI &&
+ isa<ObjCInterfaceDecl>(this)))
+ return false;
+
+ return true;
+}
+
+bool Decl::isWeakImported() const {
+ bool IsDefinition;
+ if (!canBeWeakImported(IsDefinition))
+ return false;
+
+ for (attr_iterator A = attr_begin(), AEnd = attr_end(); A != AEnd; ++A) {
+ if (isa<WeakImportAttr>(*A))
+ return true;
+
+ if (AvailabilityAttr *Availability = dyn_cast<AvailabilityAttr>(*A)) {
+ if (CheckAvailability(getASTContext(), Availability, 0)
+ == AR_NotYetIntroduced)
+ return true;
+ }
+ }
+
+ return false;
+}
unsigned Decl::getIdentifierNamespaceForKind(Kind DeclKind) {
switch (DeclKind) {
@@ -270,6 +438,7 @@ unsigned Decl::getIdentifierNamespaceForKind(Kind DeclKind) {
return IDNS_Ordinary | IDNS_Type;
case Typedef:
+ case TypeAlias:
case UnresolvedUsingTypename:
case TemplateTypeParm:
return IDNS_Ordinary | IDNS_Type;
@@ -960,7 +1129,7 @@ void DeclContext::makeDeclVisibleInContext(NamedDecl *D, bool Recoverable) {
// FIXME: This feels like a hack. Should DeclarationName support
// template-ids, or is there a better way to keep specializations
// from being visible?
- if (isa<ClassTemplateSpecializationDecl>(D))
+ if (isa<ClassTemplateSpecializationDecl>(D) || D->isTemplateParameter())
return;
if (FunctionDecl *FD = dyn_cast<FunctionDecl>(D))
if (FD->isFunctionTemplateSpecialization())
@@ -999,7 +1168,7 @@ void DeclContext::makeDeclVisibleInContextImpl(NamedDecl *D) {
// FIXME: This feels like a hack. Should DeclarationName support
// template-ids, or is there a better way to keep specializations
// from being visible?
- if (isa<ClassTemplateSpecializationDecl>(D))
+ if (isa<ClassTemplateSpecializationDecl>(D) || D->isTemplateParameter())
return;
ASTContext *C = 0;
diff --git a/lib/AST/DeclCXX.cpp b/lib/AST/DeclCXX.cpp
index 46768c12d879..9099cd524f1a 100644
--- a/lib/AST/DeclCXX.cpp
+++ b/lib/AST/DeclCXX.cpp
@@ -31,9 +31,13 @@ CXXRecordDecl::DefinitionData::DefinitionData(CXXRecordDecl *D)
: UserDeclaredConstructor(false), UserDeclaredCopyConstructor(false),
UserDeclaredCopyAssignment(false), UserDeclaredDestructor(false),
Aggregate(true), PlainOldData(true), Empty(true), Polymorphic(false),
- Abstract(false), HasTrivialConstructor(true),
- HasTrivialCopyConstructor(true), HasTrivialCopyAssignment(true),
- HasTrivialDestructor(true), ComputedVisibleConversions(false),
+ Abstract(false), IsStandardLayout(true), HasNoNonEmptyBases(true),
+ HasPrivateFields(false), HasProtectedFields(false), HasPublicFields(false),
+ HasTrivialConstructor(true), HasConstExprNonCopyMoveConstructor(false),
+ HasTrivialCopyConstructor(true), HasTrivialMoveConstructor(true),
+ HasTrivialCopyAssignment(true), HasTrivialMoveAssignment(true),
+ HasTrivialDestructor(true), HasNonLiteralTypeFieldsOrBases(false),
+ ComputedVisibleConversions(false),
DeclaredDefaultConstructor(false), DeclaredCopyConstructor(false),
DeclaredCopyAssignment(false), DeclaredDestructor(false),
NumBases(0), NumVBases(0), Bases(), VBases(),
@@ -41,20 +45,19 @@ CXXRecordDecl::DefinitionData::DefinitionData(CXXRecordDecl *D)
}
CXXRecordDecl::CXXRecordDecl(Kind K, TagKind TK, DeclContext *DC,
- SourceLocation L, IdentifierInfo *Id,
- CXXRecordDecl *PrevDecl,
- SourceLocation TKL)
- : RecordDecl(K, TK, DC, L, Id, PrevDecl, TKL),
+ SourceLocation StartLoc, SourceLocation IdLoc,
+ IdentifierInfo *Id, CXXRecordDecl *PrevDecl)
+ : RecordDecl(K, TK, DC, StartLoc, IdLoc, Id, PrevDecl),
DefinitionData(PrevDecl ? PrevDecl->DefinitionData : 0),
TemplateOrInstantiation() { }
CXXRecordDecl *CXXRecordDecl::Create(const ASTContext &C, TagKind TK,
- DeclContext *DC, SourceLocation L,
- IdentifierInfo *Id, SourceLocation TKL,
+ DeclContext *DC, SourceLocation StartLoc,
+ SourceLocation IdLoc, IdentifierInfo *Id,
CXXRecordDecl* PrevDecl,
bool DelayTypeCreation) {
- CXXRecordDecl* R = new (C) CXXRecordDecl(CXXRecord, TK, DC, L, Id,
- PrevDecl, TKL);
+ CXXRecordDecl* R = new (C) CXXRecordDecl(CXXRecord, TK, DC, StartLoc, IdLoc,
+ Id, PrevDecl);
// FIXME: DelayTypeCreation seems like such a hack
if (!DelayTypeCreation)
@@ -63,8 +66,8 @@ CXXRecordDecl *CXXRecordDecl::Create(const ASTContext &C, TagKind TK,
}
CXXRecordDecl *CXXRecordDecl::Create(const ASTContext &C, EmptyShell Empty) {
- return new (C) CXXRecordDecl(CXXRecord, TTK_Struct, 0, SourceLocation(), 0, 0,
- SourceLocation());
+ return new (C) CXXRecordDecl(CXXRecord, TTK_Struct, 0, SourceLocation(),
+ SourceLocation(), 0, 0);
}
void
@@ -109,14 +112,38 @@ CXXRecordDecl::setBases(CXXBaseSpecifier const * const *Bases,
// A class with a non-empty base class is not empty.
// FIXME: Standard ref?
- if (!BaseClassDecl->isEmpty())
+ if (!BaseClassDecl->isEmpty()) {
+ if (!data().Empty) {
+ // C++0x [class]p7:
+ // A standard-layout class is a class that:
+ // [...]
+ // -- either has no non-static data members in the most derived
+ // class and at most one base class with non-static data members,
+ // or has no base classes with non-static data members, and
+ // If this is the second non-empty base, then neither of these two
+ // clauses can be true.
+ data().IsStandardLayout = false;
+ }
+
data().Empty = false;
+ data().HasNoNonEmptyBases = false;
+ }
// C++ [class.virtual]p1:
// A class that declares or inherits a virtual function is called a
// polymorphic class.
if (BaseClassDecl->isPolymorphic())
data().Polymorphic = true;
+
+ // C++0x [class]p7:
+ // A standard-layout class is a class that: [...]
+ // -- has no non-standard-layout base classes
+ if (!BaseClassDecl->isStandardLayout())
+ data().IsStandardLayout = false;
+
+ // Record if this base is the first non-literal field or base.
+ if (!hasNonLiteralTypeFieldsOrBases() && !BaseType->isLiteralType())
+ data().HasNonLiteralTypeFieldsOrBases = true;
// Now go through all virtual bases of this base and add them.
for (CXXRecordDecl::base_class_iterator VBase =
@@ -140,16 +167,25 @@ CXXRecordDecl::setBases(CXXBaseSpecifier const * const *Bases,
// C++ [class.ctor]p5:
// A constructor is trivial if its class has no virtual base classes.
data().HasTrivialConstructor = false;
-
- // C++ [class.copy]p6:
- // A copy constructor is trivial if its class has no virtual base
- // classes.
+
+ // C++0x [class.copy]p13:
+ // A copy/move constructor for class X is trivial if it is neither
+ // user-provided nor deleted and if
+ // -- class X has no virtual functions and no virtual base classes, and
data().HasTrivialCopyConstructor = false;
-
- // C++ [class.copy]p11:
- // A copy assignment operator is trivial if its class has no virtual
- // base classes.
+ data().HasTrivialMoveConstructor = false;
+
+ // C++0x [class.copy]p27:
+ // A copy/move assignment operator for class X is trivial if it is
+ // neither user-provided nor deleted and if
+ // -- class X has no virtual functions and no virtual base classes, and
data().HasTrivialCopyAssignment = false;
+ data().HasTrivialMoveAssignment = false;
+
+ // C++0x [class]p7:
+ // A standard-layout class is a class that: [...]
+ // -- has [...] no virtual base classes
+ data().IsStandardLayout = false;
} else {
// C++ [class.ctor]p5:
// A constructor is trivial if all the direct base classes of its
@@ -157,17 +193,29 @@ CXXRecordDecl::setBases(CXXBaseSpecifier const * const *Bases,
if (!BaseClassDecl->hasTrivialConstructor())
data().HasTrivialConstructor = false;
- // C++ [class.copy]p6:
- // A copy constructor is trivial if all the direct base classes of its
- // class have trivial copy constructors.
+ // C++0x [class.copy]p13:
+ // A copy/move constructor for class X is trivial if [...]
+ // [...]
+ // -- the constructor selected to copy/move each direct base class
+ // subobject is trivial, and
+ // FIXME: C++0x: We need to only consider the selected constructor
+ // instead of all of them.
if (!BaseClassDecl->hasTrivialCopyConstructor())
data().HasTrivialCopyConstructor = false;
-
- // C++ [class.copy]p11:
- // A copy assignment operator is trivial if all the direct base classes
- // of its class have trivial copy assignment operators.
+ if (!BaseClassDecl->hasTrivialMoveConstructor())
+ data().HasTrivialMoveConstructor = false;
+
+ // C++0x [class.copy]p27:
+ // A copy/move assignment operator for class X is trivial if [...]
+ // [...]
+ // -- the assignment operator selected to copy/move each direct base
+ // class subobject is trivial, and
+ // FIXME: C++0x: We need to only consider the selected operator instead
+ // of all of them.
if (!BaseClassDecl->hasTrivialCopyAssignment())
data().HasTrivialCopyAssignment = false;
+ if (!BaseClassDecl->hasTrivialMoveAssignment())
+ data().HasTrivialMoveAssignment = false;
}
// C++ [class.ctor]p3:
@@ -218,6 +266,23 @@ bool CXXRecordDecl::hasConstCopyConstructor(const ASTContext &Context) const {
return getCopyConstructor(Context, Qualifiers::Const) != 0;
}
+bool CXXRecordDecl::isTriviallyCopyable() const {
+ // C++0x [class]p5:
+ // A trivially copyable class is a class that:
+ // -- has no non-trivial copy constructors,
+ if (!hasTrivialCopyConstructor()) return false;
+ // -- has no non-trivial move constructors,
+ if (!hasTrivialMoveConstructor()) return false;
+ // -- has no non-trivial copy assignment operators,
+ if (!hasTrivialCopyAssignment()) return false;
+ // -- has no non-trivial move assignment operators, and
+ if (!hasTrivialMoveAssignment()) return false;
+ // -- has a trivial destructor.
+ if (!hasTrivialDestructor()) return false;
+
+ return true;
+}
+
/// \brief Perform a simplistic form of overload resolution that only considers
/// cv-qualifiers on a single parameter, and return the best overload candidate
/// (if there is one).
@@ -231,11 +296,11 @@ GetBestOverloadCandidateSimple(
unsigned Best = 0, N = Cands.size();
for (unsigned I = 1; I != N; ++I)
- if (Cands[Best].second.isSupersetOf(Cands[I].second))
+ if (Cands[Best].second.compatiblyIncludes(Cands[I].second))
Best = I;
for (unsigned I = 1; I != N; ++I)
- if (Cands[Best].second.isSupersetOf(Cands[I].second))
+ if (Cands[Best].second.compatiblyIncludes(Cands[I].second))
return 0;
return Cands[Best].first;
@@ -358,9 +423,24 @@ void CXXRecordDecl::addedMember(Decl *D) {
// None of the special member functions are trivial.
data().HasTrivialConstructor = false;
+
+ // C++0x [class.copy]p13:
+ // A copy/move constructor for class X is trivial if [...]
+ // -- class X has no virtual functions [...]
data().HasTrivialCopyConstructor = false;
+ data().HasTrivialMoveConstructor = false;
+
+ // C++0x [class.copy]p27:
+ // A copy/move assignment operator for class X is trivial if [...]
+ // -- class X has no virtual functions [...]
data().HasTrivialCopyAssignment = false;
+ data().HasTrivialMoveAssignment = false;
// FIXME: Destructor?
+
+ // C++0x [class]p7:
+ // A standard-layout class is a class that: [...]
+ // -- has no virtual functions
+ data().IsStandardLayout = false;
}
}
@@ -423,18 +503,33 @@ void CXXRecordDecl::addedMember(Decl *D) {
// FIXME: C++0x: don't do this for "= default" default constructors.
data().HasTrivialConstructor = false;
- // Note when we have a user-declared copy constructor, which will
- // suppress the implicit declaration of a copy constructor.
- if (!FunTmpl && Constructor->isCopyConstructor()) {
- data().UserDeclaredCopyConstructor = true;
- data().DeclaredCopyConstructor = true;
-
- // C++ [class.copy]p6:
- // A copy constructor is trivial if it is implicitly declared.
- // FIXME: C++0x: don't do this for "= default" copy constructors.
- data().HasTrivialCopyConstructor = false;
+ // Note when we have a user-declared copy or move constructor, which will
+ // suppress the implicit declaration of those constructors.
+ if (!FunTmpl) {
+ if (Constructor->isCopyConstructor()) {
+ data().UserDeclaredCopyConstructor = true;
+ data().DeclaredCopyConstructor = true;
+
+ // C++0x [class.copy]p13:
+ // A copy/move constructor for class X is trivial if it is neither
+ // user-provided nor deleted
+ // FIXME: C++0x: don't do this for "= default" copy constructors.
+ data().HasTrivialCopyConstructor = false;
+ } else if (Constructor->isMoveConstructor()) {
+ // C++0x [class.copy]p13:
+ // A copy/move constructor for class X is trivial if it is neither
+ // user-provided nor deleted
+ // FIXME: C++0x: don't do this for "= default" move constructors.
+ data().HasTrivialMoveConstructor = false;
+ }
}
-
+ if (Constructor->isConstExpr() &&
+ !Constructor->isCopyOrMoveConstructor()) {
+ // Record if we see any constexpr constructors which are niether copy
+ // nor move constructors.
+ data().HasConstExprNonCopyMoveConstructor = true;
+ }
+
return;
}
@@ -472,35 +567,53 @@ void CXXRecordDecl::addedMember(Decl *D) {
return;
ASTContext &Context = getASTContext();
- QualType ArgType = FnType->getArgType(0);
- if (const LValueReferenceType *Ref =ArgType->getAs<LValueReferenceType>())
- ArgType = Ref->getPointeeType();
-
- ArgType = ArgType.getUnqualifiedType();
QualType ClassType = Context.getCanonicalType(Context.getTypeDeclType(
const_cast<CXXRecordDecl*>(this)));
-
+
+ bool isRValueRefArg = false;
+ QualType ArgType = FnType->getArgType(0);
+ if (const LValueReferenceType *Ref =
+ ArgType->getAs<LValueReferenceType>()) {
+ ArgType = Ref->getPointeeType();
+ } else if (const RValueReferenceType *Ref =
+ ArgType->getAs<RValueReferenceType>()) {
+ ArgType = Ref->getPointeeType();
+ isRValueRefArg = true;
+ }
if (!Context.hasSameUnqualifiedType(ClassType, ArgType))
return;
-
- // This is a copy assignment operator.
- // FIXME: Move assignment operators.
-
- // Suppress the implicit declaration of a copy constructor.
- data().UserDeclaredCopyAssignment = true;
- data().DeclaredCopyAssignment = true;
-
- // C++ [class.copy]p11:
- // A copy assignment operator is trivial if it is implicitly declared.
- // FIXME: C++0x: don't do this for "= default" copy operators.
- data().HasTrivialCopyAssignment = false;
-
+
// C++ [class]p4:
- // A POD-struct is an aggregate class that [...] has no user-defined copy
- // assignment operator [...].
+ // A POD-struct is an aggregate class that [...] has no user-defined
+ // copy assignment operator [...].
+ // FIXME: This should be probably determined dynamically in terms of
+ // other more precise attributes to correctly model how it is specified
+ // in C++0x. Setting it here happens to do the right thing.
data().PlainOldData = false;
+
+ if (!isRValueRefArg) {
+ // This is a copy assignment operator.
+
+ // Suppress the implicit declaration of a copy constructor.
+ data().UserDeclaredCopyAssignment = true;
+ data().DeclaredCopyAssignment = true;
+
+ // C++0x [class.copy]p27:
+ // A copy/move assignment operator for class X is trivial if it is
+ // neither user-provided nor deleted [...]
+ // FIXME: C++0x: don't do this for "= default" copy operators.
+ data().HasTrivialCopyAssignment = false;
+ } else {
+ // This is a move assignment operator.
+
+ // C++0x [class.copy]p27:
+ // A copy/move assignment operator for class X is trivial if it is
+ // neither user-provided nor deleted [...]
+ // FIXME: C++0x: don't do this for "= default" copy operators.
+ data().HasTrivialMoveAssignment = false;
+ }
}
-
+
// Keep the list of conversion functions up-to-date.
if (CXXConversionDecl *Conversion = dyn_cast<CXXConversionDecl>(D)) {
// We don't record specializations.
@@ -539,8 +652,22 @@ void CXXRecordDecl::addedMember(Decl *D) {
data().Aggregate = false;
data().PlainOldData = false;
}
-
- // C++ [class]p9:
+
+ // C++0x [class]p7:
+ // A standard-layout class is a class that:
+ // [...]
+ // -- has the same access control for all non-static data members,
+ switch (D->getAccess()) {
+ case AS_private: data().HasPrivateFields = true; break;
+ case AS_protected: data().HasProtectedFields = true; break;
+ case AS_public: data().HasPublicFields = true; break;
+ case AS_none: assert(0 && "Invalid access specifier");
+ };
+ if ((data().HasPrivateFields + data().HasProtectedFields +
+ data().HasPublicFields) > 1)
+ data().IsStandardLayout = false;
+
+ // C++0x [class]p9:
// A POD struct is a class that is both a trivial class and a
// standard-layout class, and has no non-static data members of type
// non-POD struct, non-POD union (or array of such types).
@@ -548,23 +675,98 @@ void CXXRecordDecl::addedMember(Decl *D) {
QualType T = Context.getBaseElementType(Field->getType());
if (!T->isPODType())
data().PlainOldData = false;
- if (T->isReferenceType())
+ if (T->isReferenceType()) {
data().HasTrivialConstructor = false;
-
+
+ // C++0x [class]p7:
+ // A standard-layout class is a class that:
+ // -- has no non-static data members of type [...] reference,
+ data().IsStandardLayout = false;
+ }
+
+ // Record if this field is the first non-literal field or base.
+ if (!hasNonLiteralTypeFieldsOrBases() && !T->isLiteralType())
+ data().HasNonLiteralTypeFieldsOrBases = true;
+
if (const RecordType *RecordTy = T->getAs<RecordType>()) {
CXXRecordDecl* FieldRec = cast<CXXRecordDecl>(RecordTy->getDecl());
if (FieldRec->getDefinition()) {
if (!FieldRec->hasTrivialConstructor())
data().HasTrivialConstructor = false;
+
+ // C++0x [class.copy]p13:
+ // A copy/move constructor for class X is trivial if [...]
+ // [...]
+ // -- for each non-static data member of X that is of class type (or
+ // an array thereof), the constructor selected to copy/move that
+ // member is trivial;
+ // FIXME: C++0x: We don't correctly model 'selected' constructors.
if (!FieldRec->hasTrivialCopyConstructor())
data().HasTrivialCopyConstructor = false;
+ if (!FieldRec->hasTrivialMoveConstructor())
+ data().HasTrivialMoveConstructor = false;
+
+ // C++0x [class.copy]p27:
+ // A copy/move assignment operator for class X is trivial if [...]
+ // [...]
+ // -- for each non-static data member of X that is of class type (or
+ // an array thereof), the assignment operator selected to
+ // copy/move that member is trivial;
+ // FIXME: C++0x: We don't correctly model 'selected' operators.
if (!FieldRec->hasTrivialCopyAssignment())
data().HasTrivialCopyAssignment = false;
+ if (!FieldRec->hasTrivialMoveAssignment())
+ data().HasTrivialMoveAssignment = false;
+
if (!FieldRec->hasTrivialDestructor())
data().HasTrivialDestructor = false;
+
+ // C++0x [class]p7:
+ // A standard-layout class is a class that:
+ // -- has no non-static data members of type non-standard-layout
+ // class (or array of such types) [...]
+ if (!FieldRec->isStandardLayout())
+ data().IsStandardLayout = false;
+
+ // C++0x [class]p7:
+ // A standard-layout class is a class that:
+ // [...]
+ // -- has no base classes of the same type as the first non-static
+ // data member.
+ // We don't want to expend bits in the state of the record decl
+ // tracking whether this is the first non-static data member so we
+ // cheat a bit and use some of the existing state: the empty bit.
+ // Virtual bases and virtual methods make a class non-empty, but they
+ // also make it non-standard-layout so we needn't check here.
+ // A non-empty base class may leave the class standard-layout, but not
+ // if we have arrived here, and have at least on non-static data
+ // member. If IsStandardLayout remains true, then the first non-static
+ // data member must come through here with Empty still true, and Empty
+ // will subsequently be set to false below.
+ if (data().IsStandardLayout && data().Empty) {
+ for (CXXRecordDecl::base_class_const_iterator BI = bases_begin(),
+ BE = bases_end();
+ BI != BE; ++BI) {
+ if (Context.hasSameUnqualifiedType(BI->getType(), T)) {
+ data().IsStandardLayout = false;
+ break;
+ }
+ }
+ }
}
}
-
+
+ // C++0x [class]p7:
+ // A standard-layout class is a class that:
+ // [...]
+ // -- either has no non-static data members in the most derived
+ // class and at most one base class with non-static data members,
+ // or has no base classes with non-static data members, and
+ // At this point we know that we have a non-static data member, so the last
+ // clause holds.
+ if (!data().HasNoNonEmptyBases)
+ data().IsStandardLayout = false;
+
// If this is not a zero-length bit-field, then the class is not empty.
if (data().Empty) {
if (!Field->getBitWidth())
@@ -814,8 +1016,6 @@ CXXDestructorDecl *CXXRecordDecl::getDestructor() const {
return 0;
CXXDestructorDecl *Dtor = cast<CXXDestructorDecl>(*I);
- assert(++I == E && "Found more than one destructor!");
-
return Dtor;
}
@@ -884,11 +1084,13 @@ bool CXXRecordDecl::mayBeAbstract() const {
CXXMethodDecl *
CXXMethodDecl::Create(ASTContext &C, CXXRecordDecl *RD,
+ SourceLocation StartLoc,
const DeclarationNameInfo &NameInfo,
QualType T, TypeSourceInfo *TInfo,
- bool isStatic, StorageClass SCAsWritten, bool isInline) {
- return new (C) CXXMethodDecl(CXXMethod, RD, NameInfo, T, TInfo,
- isStatic, SCAsWritten, isInline);
+ bool isStatic, StorageClass SCAsWritten, bool isInline,
+ SourceLocation EndLocation) {
+ return new (C) CXXMethodDecl(CXXMethod, RD, StartLoc, NameInfo, T, TInfo,
+ isStatic, SCAsWritten, isInline, EndLocation);
}
bool CXXMethodDecl::isUsualDeallocationFunction() const {
@@ -1033,6 +1235,16 @@ CXXCtorInitializer::CXXCtorInitializer(ASTContext &Context,
}
CXXCtorInitializer::CXXCtorInitializer(ASTContext &Context,
+ SourceLocation D, SourceLocation L,
+ CXXConstructorDecl *Target, Expr *Init,
+ SourceLocation R)
+ : Initializee(Target), MemberOrEllipsisLocation(D), Init(Init),
+ LParenLoc(L), RParenLoc(R), IsVirtual(false),
+ IsWritten(false), SourceOrderOrNumArrayIndices(0)
+{
+}
+
+CXXCtorInitializer::CXXCtorInitializer(ASTContext &Context,
FieldDecl *Member,
SourceLocation MemberLoc,
SourceLocation L, Expr *Init,
@@ -1076,7 +1288,7 @@ const Type *CXXCtorInitializer::getBaseClass() const {
}
SourceLocation CXXCtorInitializer::getSourceLocation() const {
- if (isAnyMemberInitializer())
+ if (isAnyMemberInitializer() || isDelegatingInitializer())
return getMemberLocation();
return getBaseClassLoc().getLocalSourceRange().getBegin();
@@ -1088,12 +1300,13 @@ SourceRange CXXCtorInitializer::getSourceRange() const {
CXXConstructorDecl *
CXXConstructorDecl::Create(ASTContext &C, EmptyShell Empty) {
- return new (C) CXXConstructorDecl(0, DeclarationNameInfo(),
+ return new (C) CXXConstructorDecl(0, SourceLocation(), DeclarationNameInfo(),
QualType(), 0, false, false, false);
}
CXXConstructorDecl *
CXXConstructorDecl::Create(ASTContext &C, CXXRecordDecl *RD,
+ SourceLocation StartLoc,
const DeclarationNameInfo &NameInfo,
QualType T, TypeSourceInfo *TInfo,
bool isExplicit,
@@ -1102,8 +1315,8 @@ CXXConstructorDecl::Create(ASTContext &C, CXXRecordDecl *RD,
assert(NameInfo.getName().getNameKind()
== DeclarationName::CXXConstructorName &&
"Name must refer to a constructor");
- return new (C) CXXConstructorDecl(RD, NameInfo, T, TInfo, isExplicit,
- isInline, isImplicitlyDeclared);
+ return new (C) CXXConstructorDecl(RD, StartLoc, NameInfo, T, TInfo,
+ isExplicit, isInline, isImplicitlyDeclared);
}
bool CXXConstructorDecl::isDefaultConstructor() const {
@@ -1222,12 +1435,13 @@ CXXConstructorDecl::setInheritedConstructor(const CXXConstructorDecl *BaseCtor){
CXXDestructorDecl *
CXXDestructorDecl::Create(ASTContext &C, EmptyShell Empty) {
- return new (C) CXXDestructorDecl(0, DeclarationNameInfo(),
+ return new (C) CXXDestructorDecl(0, SourceLocation(), DeclarationNameInfo(),
QualType(), 0, false, false);
}
CXXDestructorDecl *
CXXDestructorDecl::Create(ASTContext &C, CXXRecordDecl *RD,
+ SourceLocation StartLoc,
const DeclarationNameInfo &NameInfo,
QualType T, TypeSourceInfo *TInfo,
bool isInline,
@@ -1235,33 +1449,38 @@ CXXDestructorDecl::Create(ASTContext &C, CXXRecordDecl *RD,
assert(NameInfo.getName().getNameKind()
== DeclarationName::CXXDestructorName &&
"Name must refer to a destructor");
- return new (C) CXXDestructorDecl(RD, NameInfo, T, TInfo, isInline,
+ return new (C) CXXDestructorDecl(RD, StartLoc, NameInfo, T, TInfo, isInline,
isImplicitlyDeclared);
}
CXXConversionDecl *
CXXConversionDecl::Create(ASTContext &C, EmptyShell Empty) {
- return new (C) CXXConversionDecl(0, DeclarationNameInfo(),
- QualType(), 0, false, false);
+ return new (C) CXXConversionDecl(0, SourceLocation(), DeclarationNameInfo(),
+ QualType(), 0, false, false,
+ SourceLocation());
}
CXXConversionDecl *
CXXConversionDecl::Create(ASTContext &C, CXXRecordDecl *RD,
+ SourceLocation StartLoc,
const DeclarationNameInfo &NameInfo,
QualType T, TypeSourceInfo *TInfo,
- bool isInline, bool isExplicit) {
+ bool isInline, bool isExplicit,
+ SourceLocation EndLocation) {
assert(NameInfo.getName().getNameKind()
== DeclarationName::CXXConversionFunctionName &&
"Name must refer to a conversion function");
- return new (C) CXXConversionDecl(RD, NameInfo, T, TInfo,
- isInline, isExplicit);
+ return new (C) CXXConversionDecl(RD, StartLoc, NameInfo, T, TInfo,
+ isInline, isExplicit, EndLocation);
}
LinkageSpecDecl *LinkageSpecDecl::Create(ASTContext &C,
DeclContext *DC,
- SourceLocation L,
- LanguageIDs Lang, bool Braces) {
- return new (C) LinkageSpecDecl(DC, L, Lang, Braces);
+ SourceLocation ExternLoc,
+ SourceLocation LangLoc,
+ LanguageIDs Lang,
+ SourceLocation RBraceLoc) {
+ return new (C) LinkageSpecDecl(DC, ExternLoc, LangLoc, Lang, RBraceLoc);
}
UsingDirectiveDecl *UsingDirectiveDecl::Create(ASTContext &C, DeclContext *DC,
@@ -1364,9 +1583,12 @@ UnresolvedUsingTypenameDecl::Create(ASTContext &C, DeclContext *DC,
}
StaticAssertDecl *StaticAssertDecl::Create(ASTContext &C, DeclContext *DC,
- SourceLocation L, Expr *AssertExpr,
- StringLiteral *Message) {
- return new (C) StaticAssertDecl(DC, L, AssertExpr, Message);
+ SourceLocation StaticAssertLoc,
+ Expr *AssertExpr,
+ StringLiteral *Message,
+ SourceLocation RParenLoc) {
+ return new (C) StaticAssertDecl(DC, StaticAssertLoc, AssertExpr, Message,
+ RParenLoc);
}
static const char *getAccessName(AccessSpecifier AS) {
diff --git a/lib/AST/DeclObjC.cpp b/lib/AST/DeclObjC.cpp
index 45f5188d4043..24d281e8b66d 100644
--- a/lib/AST/DeclObjC.cpp
+++ b/lib/AST/DeclObjC.cpp
@@ -398,6 +398,64 @@ ObjCMethodDecl *ObjCMethodDecl::getCanonicalDecl() {
return this;
}
+ObjCMethodFamily ObjCMethodDecl::getMethodFamily() const {
+ ObjCMethodFamily family = static_cast<ObjCMethodFamily>(Family);
+ if (family != static_cast<unsigned>(InvalidObjCMethodFamily))
+ return family;
+
+ // Check for an explicit attribute.
+ if (const ObjCMethodFamilyAttr *attr = getAttr<ObjCMethodFamilyAttr>()) {
+ // The unfortunate necessity of mapping between enums here is due
+ // to the attributes framework.
+ switch (attr->getFamily()) {
+ case ObjCMethodFamilyAttr::OMF_None: family = OMF_None; break;
+ case ObjCMethodFamilyAttr::OMF_alloc: family = OMF_alloc; break;
+ case ObjCMethodFamilyAttr::OMF_copy: family = OMF_copy; break;
+ case ObjCMethodFamilyAttr::OMF_init: family = OMF_init; break;
+ case ObjCMethodFamilyAttr::OMF_mutableCopy: family = OMF_mutableCopy; break;
+ case ObjCMethodFamilyAttr::OMF_new: family = OMF_new; break;
+ }
+ Family = static_cast<unsigned>(family);
+ return family;
+ }
+
+ family = getSelector().getMethodFamily();
+ switch (family) {
+ case OMF_None: break;
+
+ // init only has a conventional meaning for an instance method, and
+ // it has to return an object.
+ case OMF_init:
+ if (!isInstanceMethod() || !getResultType()->isObjCObjectPointerType())
+ family = OMF_None;
+ break;
+
+ // alloc/copy/new have a conventional meaning for both class and
+ // instance methods, but they require an object return.
+ case OMF_alloc:
+ case OMF_copy:
+ case OMF_mutableCopy:
+ case OMF_new:
+ if (!getResultType()->isObjCObjectPointerType())
+ family = OMF_None;
+ break;
+
+ // These selectors have a conventional meaning only for instance methods.
+ case OMF_dealloc:
+ case OMF_retain:
+ case OMF_release:
+ case OMF_autorelease:
+ case OMF_retainCount:
+ if (!isInstanceMethod())
+ family = OMF_None;
+ break;
+ }
+
+ // Cache the result.
+ Family = static_cast<unsigned>(family);
+ return family;
+}
+
void ObjCMethodDecl::createImplicitParams(ASTContext &Context,
const ObjCInterfaceDecl *OID) {
QualType selfTy;
@@ -614,7 +672,8 @@ bool ObjCInterfaceDecl::ClassImplementsProtocol(ObjCProtocolDecl *lProto,
//===----------------------------------------------------------------------===//
ObjCIvarDecl *ObjCIvarDecl::Create(ASTContext &C, ObjCContainerDecl *DC,
- SourceLocation L, IdentifierInfo *Id,
+ SourceLocation StartLoc,
+ SourceLocation IdLoc, IdentifierInfo *Id,
QualType T, TypeSourceInfo *TInfo,
AccessControl ac, Expr *BW,
bool synthesized) {
@@ -651,7 +710,8 @@ ObjCIvarDecl *ObjCIvarDecl::Create(ASTContext &C, ObjCContainerDecl *DC,
ID->setIvarList(0);
}
- return new (C) ObjCIvarDecl(DC, L, Id, T, TInfo, ac, BW, synthesized);
+ return new (C) ObjCIvarDecl(DC, StartLoc, IdLoc, Id, T, TInfo,
+ ac, BW, synthesized);
}
const ObjCInterfaceDecl *ObjCIvarDecl::getContainingInterface() const {
@@ -684,9 +744,10 @@ const ObjCInterfaceDecl *ObjCIvarDecl::getContainingInterface() const {
//===----------------------------------------------------------------------===//
ObjCAtDefsFieldDecl
-*ObjCAtDefsFieldDecl::Create(ASTContext &C, DeclContext *DC, SourceLocation L,
+*ObjCAtDefsFieldDecl::Create(ASTContext &C, DeclContext *DC,
+ SourceLocation StartLoc, SourceLocation IdLoc,
IdentifierInfo *Id, QualType T, Expr *BW) {
- return new (C) ObjCAtDefsFieldDecl(DC, L, Id, T, BW);
+ return new (C) ObjCAtDefsFieldDecl(DC, StartLoc, IdLoc, Id, T, BW);
}
//===----------------------------------------------------------------------===//
diff --git a/lib/AST/DeclPrinter.cpp b/lib/AST/DeclPrinter.cpp
index c6ae128e42b5..2fd88d7c808d 100644
--- a/lib/AST/DeclPrinter.cpp
+++ b/lib/AST/DeclPrinter.cpp
@@ -45,6 +45,7 @@ namespace {
void VisitTranslationUnitDecl(TranslationUnitDecl *D);
void VisitTypedefDecl(TypedefDecl *D);
+ void VisitTypeAliasDecl(TypeAliasDecl *D);
void VisitEnumDecl(EnumDecl *D);
void VisitRecordDecl(RecordDecl *D);
void VisitEnumConstantDecl(EnumConstantDecl *D);
@@ -54,12 +55,13 @@ namespace {
void VisitLabelDecl(LabelDecl *D);
void VisitParmVarDecl(ParmVarDecl *D);
void VisitFileScopeAsmDecl(FileScopeAsmDecl *D);
+ void VisitStaticAssertDecl(StaticAssertDecl *D);
void VisitNamespaceDecl(NamespaceDecl *D);
void VisitUsingDirectiveDecl(UsingDirectiveDecl *D);
void VisitNamespaceAliasDecl(NamespaceAliasDecl *D);
void VisitCXXRecordDecl(CXXRecordDecl *D);
void VisitLinkageSpecDecl(LinkageSpecDecl *D);
- void VisitTemplateDecl(TemplateDecl *D);
+ void VisitTemplateDecl(const TemplateDecl *D);
void VisitObjCMethodDecl(ObjCMethodDecl *D);
void VisitObjCClassDecl(ObjCClassDecl *D);
void VisitObjCImplementationDecl(ObjCImplementationDecl *D);
@@ -109,7 +111,7 @@ static QualType GetBaseType(QualType T) {
}
static QualType getDeclType(Decl* D) {
- if (TypedefDecl* TDD = dyn_cast<TypedefDecl>(D))
+ if (TypedefNameDecl* TDD = dyn_cast<TypedefNameDecl>(D))
return TDD->getUnderlyingType();
if (ValueDecl* VD = dyn_cast<ValueDecl>(D))
return VD->getType();
@@ -307,6 +309,11 @@ void DeclPrinter::VisitTypedefDecl(TypedefDecl *D) {
Out << S;
}
+void DeclPrinter::VisitTypeAliasDecl(TypeAliasDecl *D) {
+ Out << "using " << D->getNameAsString() << " = "
+ << D->getUnderlyingType().getAsString(Policy);
+}
+
void DeclPrinter::VisitEnumDecl(EnumDecl *D) {
Out << "enum ";
if (D->isScoped()) {
@@ -412,22 +419,32 @@ void DeclPrinter::VisitFunctionDecl(FunctionDecl *D) {
if (TypeQuals & Qualifiers::Restrict)
Proto += " restrict";
}
-
- if (FT && FT->hasExceptionSpec()) {
+
+ if (FT && FT->hasDynamicExceptionSpec()) {
Proto += " throw(";
- if (FT->hasAnyExceptionSpec())
+ if (FT->getExceptionSpecType() == EST_MSAny)
Proto += "...";
else
for (unsigned I = 0, N = FT->getNumExceptions(); I != N; ++I) {
if (I)
Proto += ", ";
-
-
+
std::string ExceptionType;
FT->getExceptionType(I).getAsStringInternal(ExceptionType, SubPolicy);
Proto += ExceptionType;
}
Proto += ")";
+ } else if (FT && isNoexceptExceptionSpec(FT->getExceptionSpecType())) {
+ Proto += " noexcept";
+ if (FT->getExceptionSpecType() == EST_ComputedNoexcept) {
+ Proto += "(";
+ llvm::raw_string_ostream EOut(Proto);
+ FT->getNoexceptExpr()->printPretty(EOut, Context, 0, SubPolicy,
+ Indentation);
+ EOut.flush();
+ Proto += EOut.str();
+ Proto += ")";
+ }
}
if (D->hasAttr<NoReturnAttr>())
@@ -556,7 +573,8 @@ void DeclPrinter::VisitVarDecl(VarDecl *D) {
T = Parm->getOriginalType();
T.getAsStringInternal(Name, Policy);
Out << Name;
- if (Expr *Init = D->getInit()) {
+ Expr *Init = D->getInit();
+ if (!Policy.SuppressInitializers && Init) {
if (D->hasCXXDirectInitializer())
Out << "(";
else {
@@ -580,6 +598,14 @@ void DeclPrinter::VisitFileScopeAsmDecl(FileScopeAsmDecl *D) {
Out << ")";
}
+void DeclPrinter::VisitStaticAssertDecl(StaticAssertDecl *D) {
+ Out << "static_assert(";
+ D->getAssertExpr()->printPretty(Out, Context, 0, Policy, Indentation);
+ Out << ", ";
+ D->getMessage()->printPretty(Out, Context, 0, Policy, Indentation);
+ Out << ")";
+}
+
//----------------------------------------------------------------------------
// C++ declarations
//----------------------------------------------------------------------------
@@ -624,6 +650,9 @@ void DeclPrinter::VisitCXXRecordDecl(CXXRecordDecl *D) {
if (AS != AS_none)
Print(AS);
Out << " " << Base->getType().getAsString(Policy);
+
+ if (Base->isPackExpansion())
+ Out << "...";
}
}
@@ -654,7 +683,7 @@ void DeclPrinter::VisitLinkageSpecDecl(LinkageSpecDecl *D) {
Visit(*D->decls_begin());
}
-void DeclPrinter::VisitTemplateDecl(TemplateDecl *D) {
+void DeclPrinter::VisitTemplateDecl(const TemplateDecl *D) {
Out << "template <";
TemplateParameterList *Params = D->getTemplateParameters();
@@ -666,9 +695,6 @@ void DeclPrinter::VisitTemplateDecl(TemplateDecl *D) {
if (const TemplateTypeParmDecl *TTP =
dyn_cast<TemplateTypeParmDecl>(Param)) {
- QualType ParamType =
- Context.getTypeDeclType(const_cast<TemplateTypeParmDecl*>(TTP));
-
if (TTP->wasDeclaredWithTypename())
Out << "typename ";
else
@@ -677,7 +703,7 @@ void DeclPrinter::VisitTemplateDecl(TemplateDecl *D) {
if (TTP->isParameterPack())
Out << "... ";
- Out << ParamType.getAsString(Policy);
+ Out << TTP->getNameAsString();
if (TTP->hasDefaultArgument()) {
Out << " = ";
@@ -700,12 +726,17 @@ void DeclPrinter::VisitTemplateDecl(TemplateDecl *D) {
NTTP->getDefaultArgument()->printPretty(Out, Context, 0, Policy,
Indentation);
}
+ } else if (const TemplateTemplateParmDecl *TTPD =
+ dyn_cast<TemplateTemplateParmDecl>(Param)) {
+ VisitTemplateDecl(TTPD);
+ // FIXME: print the default argument, if present.
}
}
Out << "> ";
- if (TemplateTemplateParmDecl *TTP = dyn_cast<TemplateTemplateParmDecl>(D)) {
+ if (const TemplateTemplateParmDecl *TTP =
+ dyn_cast<TemplateTemplateParmDecl>(D)) {
Out << "class ";
if (TTP->isParameterPack())
Out << "...";
diff --git a/lib/AST/DeclTemplate.cpp b/lib/AST/DeclTemplate.cpp
index a73deeab3a61..6272340691bf 100644
--- a/lib/AST/DeclTemplate.cpp
+++ b/lib/AST/DeclTemplate.cpp
@@ -95,6 +95,18 @@ unsigned TemplateParameterList::getDepth() const {
return cast<TemplateTemplateParmDecl>(FirstParm)->getDepth();
}
+static void AdoptTemplateParameterList(TemplateParameterList *Params,
+ DeclContext *Owner) {
+ for (TemplateParameterList::iterator P = Params->begin(),
+ PEnd = Params->end();
+ P != PEnd; ++P) {
+ (*P)->setDeclContext(Owner);
+
+ if (TemplateTemplateParmDecl *TTP = dyn_cast<TemplateTemplateParmDecl>(*P))
+ AdoptTemplateParameterList(TTP->getTemplateParameters(), Owner);
+ }
+}
+
//===----------------------------------------------------------------------===//
// RedeclarableTemplateDecl Implementation
//===----------------------------------------------------------------------===//
@@ -151,6 +163,49 @@ RedeclarableTemplateDecl::findSpecializationImpl(
return Entry ? SETraits::getMostRecentDeclaration(Entry) : 0;
}
+/// \brief Generate the injected template arguments for the given template
+/// parameter list, e.g., for the injected-class-name of a class template.
+static void GenerateInjectedTemplateArgs(ASTContext &Context,
+ TemplateParameterList *Params,
+ TemplateArgument *Args) {
+ for (TemplateParameterList::iterator Param = Params->begin(),
+ ParamEnd = Params->end();
+ Param != ParamEnd; ++Param) {
+ TemplateArgument Arg;
+ if (TemplateTypeParmDecl *TTP = dyn_cast<TemplateTypeParmDecl>(*Param)) {
+ QualType ArgType = Context.getTypeDeclType(TTP);
+ if (TTP->isParameterPack())
+ ArgType = Context.getPackExpansionType(ArgType,
+ llvm::Optional<unsigned>());
+
+ Arg = TemplateArgument(ArgType);
+ } else if (NonTypeTemplateParmDecl *NTTP =
+ dyn_cast<NonTypeTemplateParmDecl>(*Param)) {
+ Expr *E = new (Context) DeclRefExpr(NTTP,
+ NTTP->getType().getNonLValueExprType(Context),
+ Expr::getValueKindForType(NTTP->getType()),
+ NTTP->getLocation());
+
+ if (NTTP->isParameterPack())
+ E = new (Context) PackExpansionExpr(Context.DependentTy, E,
+ NTTP->getLocation(),
+ llvm::Optional<unsigned>());
+ Arg = TemplateArgument(E);
+ } else {
+ TemplateTemplateParmDecl *TTP = cast<TemplateTemplateParmDecl>(*Param);
+ if (TTP->isParameterPack())
+ Arg = TemplateArgument(TemplateName(TTP), llvm::Optional<unsigned>());
+ else
+ Arg = TemplateArgument(TemplateName(TTP));
+ }
+
+ if ((*Param)->isTemplateParameterPack())
+ Arg = TemplateArgument::CreatePackCopy(Context, &Arg, 1);
+
+ *Args++ = Arg;
+ }
+}
+
//===----------------------------------------------------------------------===//
// FunctionTemplateDecl Implementation
//===----------------------------------------------------------------------===//
@@ -165,9 +220,15 @@ FunctionTemplateDecl *FunctionTemplateDecl::Create(ASTContext &C,
DeclarationName Name,
TemplateParameterList *Params,
NamedDecl *Decl) {
+ AdoptTemplateParameterList(Params, cast<DeclContext>(Decl));
return new (C) FunctionTemplateDecl(DC, L, Name, Params, Decl);
}
+FunctionTemplateDecl *FunctionTemplateDecl::Create(ASTContext &C, EmptyShell) {
+ return new (C) FunctionTemplateDecl(0, SourceLocation(), DeclarationName(),
+ 0, 0);
+}
+
RedeclarableTemplateDecl::CommonBase *
FunctionTemplateDecl::newCommon(ASTContext &C) {
Common *CommonPtr = new (C) Common;
@@ -181,6 +242,27 @@ FunctionTemplateDecl::findSpecialization(const TemplateArgument *Args,
return findSpecializationImpl(getSpecializations(), Args, NumArgs, InsertPos);
}
+void FunctionTemplateDecl::addSpecialization(
+ FunctionTemplateSpecializationInfo *Info, void *InsertPos) {
+ getSpecializations().InsertNode(Info, InsertPos);
+ if (ASTMutationListener *L = getASTMutationListener())
+ L->AddedCXXTemplateSpecialization(this, Info->Function);
+}
+
+std::pair<const TemplateArgument *, unsigned>
+FunctionTemplateDecl::getInjectedTemplateArgs() {
+ TemplateParameterList *Params = getTemplateParameters();
+ Common *CommonPtr = getCommonPtr();
+ if (!CommonPtr->InjectedArgs) {
+ CommonPtr->InjectedArgs
+ = new (getASTContext()) TemplateArgument [Params->size()];
+ GenerateInjectedTemplateArgs(getASTContext(), Params,
+ CommonPtr->InjectedArgs);
+ }
+
+ return std::make_pair(CommonPtr->InjectedArgs, Params->size());
+}
+
//===----------------------------------------------------------------------===//
// ClassTemplateDecl Implementation
//===----------------------------------------------------------------------===//
@@ -196,11 +278,16 @@ ClassTemplateDecl *ClassTemplateDecl::Create(ASTContext &C,
TemplateParameterList *Params,
NamedDecl *Decl,
ClassTemplateDecl *PrevDecl) {
+ AdoptTemplateParameterList(Params, cast<DeclContext>(Decl));
ClassTemplateDecl *New = new (C) ClassTemplateDecl(DC, L, Name, Params, Decl);
New->setPreviousDeclaration(PrevDecl);
return New;
}
+ClassTemplateDecl *ClassTemplateDecl::Create(ASTContext &C, EmptyShell Empty) {
+ return new (C) ClassTemplateDecl(Empty);
+}
+
void ClassTemplateDecl::LoadLazySpecializations() {
Common *CommonPtr = getCommonPtr();
if (CommonPtr->LazySpecializations) {
@@ -320,44 +407,8 @@ ClassTemplateDecl::getInjectedClassNameSpecialization() {
ASTContext &Context = getASTContext();
TemplateParameterList *Params = getTemplateParameters();
llvm::SmallVector<TemplateArgument, 16> TemplateArgs;
- TemplateArgs.reserve(Params->size());
- for (TemplateParameterList::iterator Param = Params->begin(),
- ParamEnd = Params->end();
- Param != ParamEnd; ++Param) {
- TemplateArgument Arg;
- if (TemplateTypeParmDecl *TTP = dyn_cast<TemplateTypeParmDecl>(*Param)) {
- QualType ArgType = Context.getTypeDeclType(TTP);
- if (TTP->isParameterPack())
- ArgType = Context.getPackExpansionType(ArgType,
- llvm::Optional<unsigned>());
-
- Arg = TemplateArgument(ArgType);
- } else if (NonTypeTemplateParmDecl *NTTP =
- dyn_cast<NonTypeTemplateParmDecl>(*Param)) {
- Expr *E = new (Context) DeclRefExpr(NTTP,
- NTTP->getType().getNonLValueExprType(Context),
- Expr::getValueKindForType(NTTP->getType()),
- NTTP->getLocation());
-
- if (NTTP->isParameterPack())
- E = new (Context) PackExpansionExpr(Context.DependentTy, E,
- NTTP->getLocation(),
- llvm::Optional<unsigned>());
- Arg = TemplateArgument(E);
- } else {
- TemplateTemplateParmDecl *TTP = cast<TemplateTemplateParmDecl>(*Param);
- if (TTP->isParameterPack())
- Arg = TemplateArgument(TemplateName(TTP), llvm::Optional<unsigned>());
- else
- Arg = TemplateArgument(TemplateName(TTP));
- }
-
- if ((*Param)->isTemplateParameterPack())
- Arg = TemplateArgument::CreatePackCopy(Context, &Arg, 1);
-
- TemplateArgs.push_back(Arg);
- }
-
+ TemplateArgs.resize(Params->size());
+ GenerateInjectedTemplateArgs(getASTContext(), Params, TemplateArgs.data());
CommonPtr->InjectedClassNameType
= Context.getTemplateSpecializationType(TemplateName(this),
&TemplateArgs[0],
@@ -371,21 +422,34 @@ ClassTemplateDecl::getInjectedClassNameSpecialization() {
TemplateTypeParmDecl *
TemplateTypeParmDecl::Create(const ASTContext &C, DeclContext *DC,
- SourceLocation L, unsigned D, unsigned P,
- IdentifierInfo *Id, bool Typename,
- bool ParameterPack) {
- QualType Type = C.getTemplateTypeParmType(D, P, ParameterPack, Id);
- return new (C) TemplateTypeParmDecl(DC, L, Id, Typename, Type, ParameterPack);
+ SourceLocation KeyLoc, SourceLocation NameLoc,
+ unsigned D, unsigned P, IdentifierInfo *Id,
+ bool Typename, bool ParameterPack) {
+ TemplateTypeParmDecl *TTPDecl =
+ new (C) TemplateTypeParmDecl(DC, KeyLoc, NameLoc, Id, Typename);
+ QualType TTPType = C.getTemplateTypeParmType(D, P, ParameterPack, TTPDecl);
+ TTPDecl->TypeForDecl = TTPType.getTypePtr();
+ return TTPDecl;
}
TemplateTypeParmDecl *
TemplateTypeParmDecl::Create(const ASTContext &C, EmptyShell Empty) {
- return new (C) TemplateTypeParmDecl(0, SourceLocation(), 0, false,
- QualType(), false);
+ return new (C) TemplateTypeParmDecl(0, SourceLocation(), SourceLocation(),
+ 0, false);
}
SourceLocation TemplateTypeParmDecl::getDefaultArgumentLoc() const {
- return DefaultArgument->getTypeLoc().getSourceRange().getBegin();
+ return hasDefaultArgument()
+ ? DefaultArgument->getTypeLoc().getBeginLoc()
+ : SourceLocation();
+}
+
+SourceRange TemplateTypeParmDecl::getSourceRange() const {
+ if (hasDefaultArgument() && !defaultArgumentWasInherited())
+ return SourceRange(getLocStart(),
+ DefaultArgument->getTypeLoc().getEndLoc());
+ else
+ return TypeDecl::getSourceRange();
}
unsigned TemplateTypeParmDecl::getDepth() const {
@@ -396,19 +460,25 @@ unsigned TemplateTypeParmDecl::getIndex() const {
return TypeForDecl->getAs<TemplateTypeParmType>()->getIndex();
}
+bool TemplateTypeParmDecl::isParameterPack() const {
+ return TypeForDecl->getAs<TemplateTypeParmType>()->isParameterPack();
+}
+
//===----------------------------------------------------------------------===//
// NonTypeTemplateParmDecl Method Implementations
//===----------------------------------------------------------------------===//
NonTypeTemplateParmDecl::NonTypeTemplateParmDecl(DeclContext *DC,
- SourceLocation L, unsigned D,
- unsigned P, IdentifierInfo *Id,
+ SourceLocation StartLoc,
+ SourceLocation IdLoc,
+ unsigned D, unsigned P,
+ IdentifierInfo *Id,
QualType T,
TypeSourceInfo *TInfo,
const QualType *ExpandedTypes,
unsigned NumExpandedTypes,
TypeSourceInfo **ExpandedTInfos)
- : DeclaratorDecl(NonTypeTemplateParm, DC, L, Id, T, TInfo),
+ : DeclaratorDecl(NonTypeTemplateParm, DC, IdLoc, Id, T, TInfo, StartLoc),
TemplateParmPosition(D, P), DefaultArgumentAndInherited(0, false),
ParameterPack(true), ExpandedParameterPack(true),
NumExpandedTypes(NumExpandedTypes)
@@ -424,16 +494,18 @@ NonTypeTemplateParmDecl::NonTypeTemplateParmDecl(DeclContext *DC,
NonTypeTemplateParmDecl *
NonTypeTemplateParmDecl::Create(const ASTContext &C, DeclContext *DC,
- SourceLocation L, unsigned D, unsigned P,
- IdentifierInfo *Id, QualType T,
- bool ParameterPack, TypeSourceInfo *TInfo) {
- return new (C) NonTypeTemplateParmDecl(DC, L, D, P, Id, T, ParameterPack,
- TInfo);
+ SourceLocation StartLoc, SourceLocation IdLoc,
+ unsigned D, unsigned P, IdentifierInfo *Id,
+ QualType T, bool ParameterPack,
+ TypeSourceInfo *TInfo) {
+ return new (C) NonTypeTemplateParmDecl(DC, StartLoc, IdLoc, D, P, Id,
+ T, ParameterPack, TInfo);
}
NonTypeTemplateParmDecl *
NonTypeTemplateParmDecl::Create(const ASTContext &C, DeclContext *DC,
- SourceLocation L, unsigned D, unsigned P,
+ SourceLocation StartLoc, SourceLocation IdLoc,
+ unsigned D, unsigned P,
IdentifierInfo *Id, QualType T,
TypeSourceInfo *TInfo,
const QualType *ExpandedTypes,
@@ -442,20 +514,17 @@ NonTypeTemplateParmDecl::Create(const ASTContext &C, DeclContext *DC,
unsigned Size = sizeof(NonTypeTemplateParmDecl)
+ NumExpandedTypes * 2 * sizeof(void*);
void *Mem = C.Allocate(Size);
- return new (Mem) NonTypeTemplateParmDecl(DC, L, D, P, Id, T, TInfo,
+ return new (Mem) NonTypeTemplateParmDecl(DC, StartLoc, IdLoc,
+ D, P, Id, T, TInfo,
ExpandedTypes, NumExpandedTypes,
ExpandedTInfos);
}
-SourceLocation NonTypeTemplateParmDecl::getInnerLocStart() const {
- SourceLocation Start = getTypeSpecStartLoc();
- if (Start.isInvalid())
- Start = getLocation();
- return Start;
-}
-
SourceRange NonTypeTemplateParmDecl::getSourceRange() const {
- return SourceRange(getOuterLocStart(), getLocation());
+ if (hasDefaultArgument() && !defaultArgumentWasInherited())
+ return SourceRange(getOuterLocStart(),
+ getDefaultArgument()->getSourceRange().getEnd());
+ return DeclaratorDecl::getSourceRange();
}
SourceLocation NonTypeTemplateParmDecl::getDefaultArgumentLoc() const {
@@ -499,12 +568,13 @@ TemplateArgumentList::CreateCopy(ASTContext &Context,
//===----------------------------------------------------------------------===//
ClassTemplateSpecializationDecl::
ClassTemplateSpecializationDecl(ASTContext &Context, Kind DK, TagKind TK,
- DeclContext *DC, SourceLocation L,
+ DeclContext *DC, SourceLocation StartLoc,
+ SourceLocation IdLoc,
ClassTemplateDecl *SpecializedTemplate,
const TemplateArgument *Args,
unsigned NumArgs,
ClassTemplateSpecializationDecl *PrevDecl)
- : CXXRecordDecl(DK, TK, DC, L,
+ : CXXRecordDecl(DK, TK, DC, StartLoc, IdLoc,
SpecializedTemplate->getIdentifier(),
PrevDecl),
SpecializedTemplate(SpecializedTemplate),
@@ -514,14 +584,16 @@ ClassTemplateSpecializationDecl(ASTContext &Context, Kind DK, TagKind TK,
}
ClassTemplateSpecializationDecl::ClassTemplateSpecializationDecl(Kind DK)
- : CXXRecordDecl(DK, TTK_Struct, 0, SourceLocation(), 0, 0),
+ : CXXRecordDecl(DK, TTK_Struct, 0, SourceLocation(), SourceLocation(), 0, 0),
ExplicitInfo(0),
SpecializationKind(TSK_Undeclared) {
}
ClassTemplateSpecializationDecl *
ClassTemplateSpecializationDecl::Create(ASTContext &Context, TagKind TK,
- DeclContext *DC, SourceLocation L,
+ DeclContext *DC,
+ SourceLocation StartLoc,
+ SourceLocation IdLoc,
ClassTemplateDecl *SpecializedTemplate,
const TemplateArgument *Args,
unsigned NumArgs,
@@ -529,7 +601,7 @@ ClassTemplateSpecializationDecl::Create(ASTContext &Context, TagKind TK,
ClassTemplateSpecializationDecl *Result
= new (Context)ClassTemplateSpecializationDecl(Context,
ClassTemplateSpecialization,
- TK, DC, L,
+ TK, DC, StartLoc, IdLoc,
SpecializedTemplate,
Args, NumArgs,
PrevDecl);
@@ -564,12 +636,51 @@ ClassTemplateSpecializationDecl::getSpecializedTemplate() const {
return SpecializedTemplate.get<ClassTemplateDecl*>();
}
+SourceRange
+ClassTemplateSpecializationDecl::getSourceRange() const {
+ if (!ExplicitInfo)
+ return SourceRange();
+ SourceLocation Begin = getExternLoc();
+ if (Begin.isInvalid())
+ Begin = getTemplateKeywordLoc();
+ SourceLocation End = getRBraceLoc();
+ if (End.isInvalid())
+ End = getTypeAsWritten()->getTypeLoc().getEndLoc();
+ return SourceRange(Begin, End);
+}
+
//===----------------------------------------------------------------------===//
// ClassTemplatePartialSpecializationDecl Implementation
//===----------------------------------------------------------------------===//
+ClassTemplatePartialSpecializationDecl::
+ClassTemplatePartialSpecializationDecl(ASTContext &Context, TagKind TK,
+ DeclContext *DC,
+ SourceLocation StartLoc,
+ SourceLocation IdLoc,
+ TemplateParameterList *Params,
+ ClassTemplateDecl *SpecializedTemplate,
+ const TemplateArgument *Args,
+ unsigned NumArgs,
+ TemplateArgumentLoc *ArgInfos,
+ unsigned NumArgInfos,
+ ClassTemplatePartialSpecializationDecl *PrevDecl,
+ unsigned SequenceNumber)
+ : 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);
+}
+
ClassTemplatePartialSpecializationDecl *
ClassTemplatePartialSpecializationDecl::
-Create(ASTContext &Context, TagKind TK,DeclContext *DC, SourceLocation L,
+Create(ASTContext &Context, TagKind TK,DeclContext *DC,
+ SourceLocation StartLoc, SourceLocation IdLoc,
TemplateParameterList *Params,
ClassTemplateDecl *SpecializedTemplate,
const TemplateArgument *Args,
@@ -584,8 +695,9 @@ Create(ASTContext &Context, TagKind TK,DeclContext *DC, SourceLocation L,
ClonedArgs[I] = ArgInfos[I];
ClassTemplatePartialSpecializationDecl *Result
- = new (Context)ClassTemplatePartialSpecializationDecl(Context, TK,
- DC, L, Params,
+ = new (Context)ClassTemplatePartialSpecializationDecl(Context, TK, DC,
+ StartLoc, IdLoc,
+ Params,
SpecializedTemplate,
Args, NumArgs,
ClonedArgs, N,
diff --git a/lib/AST/DumpXML.cpp b/lib/AST/DumpXML.cpp
index 9d828fcfb85a..7d593bc46f6c 100644
--- a/lib/AST/DumpXML.cpp
+++ b/lib/AST/DumpXML.cpp
@@ -543,12 +543,20 @@ struct XMLDumper : public XMLDeclVisitor<XMLDumper>,
// TypedefDecl
void visitTypedefDeclAttrs(TypedefDecl *D) {
- visitRedeclarableAttrs(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);
@@ -911,6 +919,8 @@ struct XMLDumper : public XMLDeclVisitor<XMLDumper>,
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");
}
}
@@ -955,7 +965,7 @@ struct XMLDumper : public XMLDeclVisitor<XMLDumper>,
void visitFunctionTypeAttrs(FunctionType *T) {
setFlag("noreturn", T->getNoReturnAttr());
setCallingConv(T->getCallConv());
- if (T->getRegParmType()) setInteger("regparm", T->getRegParmType());
+ if (T->getHasRegParm()) setInteger("regparm", T->getRegParmType());
}
void visitFunctionTypeChildren(FunctionType *T) {
dispatch(T->getResultType());
@@ -975,15 +985,16 @@ struct XMLDumper : public XMLDeclVisitor<XMLDumper>,
dispatch(*I);
pop();
- if (T->hasExceptionSpec()) {
+ if (T->hasDynamicExceptionSpec()) {
push("exception_specifiers");
- setFlag("any", T->hasAnyExceptionSpec());
+ 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) {
diff --git a/lib/AST/Expr.cpp b/lib/AST/Expr.cpp
index 1c1061b5a229..6499f327b07e 100644
--- a/lib/AST/Expr.cpp
+++ b/lib/AST/Expr.cpp
@@ -35,18 +35,16 @@ using namespace clang;
/// but also int expressions which are produced by things like comparisons in
/// C.
bool Expr::isKnownToHaveBooleanValue() const {
+ const Expr *E = IgnoreParens();
+
// If this value has _Bool type, it is obvious 0/1.
- if (getType()->isBooleanType()) return true;
+ if (E->getType()->isBooleanType()) return true;
// If this is a non-scalar-integer type, we don't care enough to try.
- if (!getType()->isIntegralOrEnumerationType()) return false;
-
- if (const ParenExpr *PE = dyn_cast<ParenExpr>(this))
- return PE->getSubExpr()->isKnownToHaveBooleanValue();
+ if (!E->getType()->isIntegralOrEnumerationType()) return false;
- if (const UnaryOperator *UO = dyn_cast<UnaryOperator>(this)) {
+ if (const UnaryOperator *UO = dyn_cast<UnaryOperator>(E)) {
switch (UO->getOpcode()) {
case UO_Plus:
- case UO_Extension:
return UO->getSubExpr()->isKnownToHaveBooleanValue();
default:
return false;
@@ -55,10 +53,10 @@ bool Expr::isKnownToHaveBooleanValue() const {
// Only look through implicit casts. If the user writes
// '(int) (a && b)' treat it as an arbitrary int.
- if (const ImplicitCastExpr *CE = dyn_cast<ImplicitCastExpr>(this))
+ if (const ImplicitCastExpr *CE = dyn_cast<ImplicitCastExpr>(E))
return CE->getSubExpr()->isKnownToHaveBooleanValue();
- if (const BinaryOperator *BO = dyn_cast<BinaryOperator>(this)) {
+ if (const BinaryOperator *BO = dyn_cast<BinaryOperator>(E)) {
switch (BO->getOpcode()) {
default: return false;
case BO_LT: // Relational operators.
@@ -84,7 +82,7 @@ bool Expr::isKnownToHaveBooleanValue() const {
}
}
- if (const ConditionalOperator *CO = dyn_cast<ConditionalOperator>(this))
+ if (const ConditionalOperator *CO = dyn_cast<ConditionalOperator>(E))
return CO->getTrueExpr()->isKnownToHaveBooleanValue() &&
CO->getFalseExpr()->isKnownToHaveBooleanValue();
@@ -276,44 +274,20 @@ void DeclRefExpr::computeDependence() {
ExprBits.ContainsUnexpandedParameterPack = true;
}
-DeclRefExpr::DeclRefExpr(NestedNameSpecifier *Qualifier,
- SourceRange QualifierRange,
- ValueDecl *D, SourceLocation NameLoc,
- const TemplateArgumentListInfo *TemplateArgs,
- QualType T, ExprValueKind VK)
- : Expr(DeclRefExprClass, T, VK, OK_Ordinary, false, false, false),
- DecoratedD(D,
- (Qualifier? HasQualifierFlag : 0) |
- (TemplateArgs ? HasExplicitTemplateArgumentListFlag : 0)),
- Loc(NameLoc) {
- if (Qualifier) {
- NameQualifier *NQ = getNameQualifier();
- NQ->NNS = Qualifier;
- NQ->Range = QualifierRange;
- }
-
- if (TemplateArgs)
- getExplicitTemplateArgs().initializeFrom(*TemplateArgs);
-
- computeDependence();
-}
-
-DeclRefExpr::DeclRefExpr(NestedNameSpecifier *Qualifier,
- SourceRange QualifierRange,
+DeclRefExpr::DeclRefExpr(NestedNameSpecifierLoc QualifierLoc,
ValueDecl *D, const DeclarationNameInfo &NameInfo,
+ NamedDecl *FoundD,
const TemplateArgumentListInfo *TemplateArgs,
QualType T, ExprValueKind VK)
: Expr(DeclRefExprClass, T, VK, OK_Ordinary, false, false, false),
- DecoratedD(D,
- (Qualifier? HasQualifierFlag : 0) |
- (TemplateArgs ? HasExplicitTemplateArgumentListFlag : 0)),
- Loc(NameInfo.getLoc()), DNLoc(NameInfo.getInfo()) {
- if (Qualifier) {
- NameQualifier *NQ = getNameQualifier();
- NQ->NNS = Qualifier;
- NQ->Range = QualifierRange;
- }
-
+ D(D), Loc(NameInfo.getLoc()), DNLoc(NameInfo.getInfo()) {
+ DeclRefExprBits.HasQualifier = QualifierLoc ? 1 : 0;
+ if (QualifierLoc)
+ getInternalQualifierLoc() = QualifierLoc;
+ DeclRefExprBits.HasFoundDecl = FoundD ? 1 : 0;
+ if (FoundD)
+ getInternalFoundDecl() = FoundD;
+ DeclRefExprBits.HasExplicitTemplateArgs = TemplateArgs ? 1 : 0;
if (TemplateArgs)
getExplicitTemplateArgs().initializeFrom(*TemplateArgs);
@@ -321,49 +295,56 @@ DeclRefExpr::DeclRefExpr(NestedNameSpecifier *Qualifier,
}
DeclRefExpr *DeclRefExpr::Create(ASTContext &Context,
- NestedNameSpecifier *Qualifier,
- SourceRange QualifierRange,
+ NestedNameSpecifierLoc QualifierLoc,
ValueDecl *D,
SourceLocation NameLoc,
QualType T,
ExprValueKind VK,
+ NamedDecl *FoundD,
const TemplateArgumentListInfo *TemplateArgs) {
- return Create(Context, Qualifier, QualifierRange, D,
+ return Create(Context, QualifierLoc, D,
DeclarationNameInfo(D->getDeclName(), NameLoc),
- T, VK, TemplateArgs);
+ T, VK, FoundD, TemplateArgs);
}
DeclRefExpr *DeclRefExpr::Create(ASTContext &Context,
- NestedNameSpecifier *Qualifier,
- SourceRange QualifierRange,
+ NestedNameSpecifierLoc QualifierLoc,
ValueDecl *D,
const DeclarationNameInfo &NameInfo,
QualType T,
ExprValueKind VK,
+ NamedDecl *FoundD,
const TemplateArgumentListInfo *TemplateArgs) {
+ // Filter out cases where the found Decl is the same as the value refenenced.
+ if (D == FoundD)
+ FoundD = 0;
+
std::size_t Size = sizeof(DeclRefExpr);
- if (Qualifier != 0)
- Size += sizeof(NameQualifier);
-
+ if (QualifierLoc != 0)
+ Size += sizeof(NestedNameSpecifierLoc);
+ if (FoundD)
+ Size += sizeof(NamedDecl *);
if (TemplateArgs)
Size += ExplicitTemplateArgumentList::sizeFor(*TemplateArgs);
-
+
void *Mem = Context.Allocate(Size, llvm::alignOf<DeclRefExpr>());
- return new (Mem) DeclRefExpr(Qualifier, QualifierRange, D, NameInfo,
- TemplateArgs, T, VK);
+ return new (Mem) DeclRefExpr(QualifierLoc, D, NameInfo, FoundD, TemplateArgs,
+ T, VK);
}
-DeclRefExpr *DeclRefExpr::CreateEmpty(ASTContext &Context,
+DeclRefExpr *DeclRefExpr::CreateEmpty(ASTContext &Context,
bool HasQualifier,
+ bool HasFoundDecl,
bool HasExplicitTemplateArgs,
unsigned NumTemplateArgs) {
std::size_t Size = sizeof(DeclRefExpr);
if (HasQualifier)
- Size += sizeof(NameQualifier);
-
+ Size += sizeof(NestedNameSpecifierLoc);
+ if (HasFoundDecl)
+ Size += sizeof(NamedDecl *);
if (HasExplicitTemplateArgs)
Size += ExplicitTemplateArgumentList::sizeFor(NumTemplateArgs);
-
+
void *Mem = Context.Allocate(Size, llvm::alignOf<DeclRefExpr>());
return new (Mem) DeclRefExpr(EmptyShell());
}
@@ -371,7 +352,7 @@ DeclRefExpr *DeclRefExpr::CreateEmpty(ASTContext &Context,
SourceRange DeclRefExpr::getSourceRange() const {
SourceRange R = getNameInfo().getSourceRange();
if (hasQualifier())
- R.setBegin(getQualifierRange().getBegin());
+ R.setBegin(getQualifierLoc().getBeginLoc());
if (hasExplicitTemplateArgs())
R.setEnd(getRAngleLoc());
return R;
@@ -518,7 +499,7 @@ double FloatingLiteral::getValueAsApproximateDouble() const {
StringLiteral *StringLiteral::Create(ASTContext &C, const char *StrData,
unsigned ByteLength, bool Wide,
- QualType Ty,
+ bool Pascal, QualType Ty,
const SourceLocation *Loc,
unsigned NumStrs) {
// Allocate enough space for the StringLiteral plus an array of locations for
@@ -534,6 +515,7 @@ StringLiteral *StringLiteral::Create(ASTContext &C, const char *StrData,
SL->StrData = AStrData;
SL->ByteLength = ByteLength;
SL->IsWide = Wide;
+ SL->IsPascal = Pascal;
SL->TokLocs[0] = Loc[0];
SL->NumConcatenated = NumStrs;
@@ -828,11 +810,11 @@ QualType CallExpr::getCallReturnType() const {
CalleeType = FnTypePtr->getPointeeType();
else if (const BlockPointerType *BPT = CalleeType->getAs<BlockPointerType>())
CalleeType = BPT->getPointeeType();
- else if (const MemberPointerType *MPT
- = CalleeType->getAs<MemberPointerType>())
- CalleeType = MPT->getPointeeType();
+ else if (CalleeType->isSpecificPlaceholderType(BuiltinType::BoundMember))
+ // This should never be overloaded and so should never return null.
+ CalleeType = Expr::findBoundMemberType(getCallee());
- const FunctionType *FnType = CalleeType->getAs<FunctionType>();
+ const FunctionType *FnType = CalleeType->castAs<FunctionType>();
return FnType->getResultType();
}
@@ -906,8 +888,7 @@ IdentifierInfo *OffsetOfExpr::OffsetOfNode::getFieldName() const {
}
MemberExpr *MemberExpr::Create(ASTContext &C, Expr *base, bool isarrow,
- NestedNameSpecifier *qual,
- SourceRange qualrange,
+ NestedNameSpecifierLoc QualifierLoc,
ValueDecl *memberdecl,
DeclAccessPair founddecl,
DeclarationNameInfo nameinfo,
@@ -917,7 +898,7 @@ MemberExpr *MemberExpr::Create(ASTContext &C, Expr *base, bool isarrow,
ExprObjectKind ok) {
std::size_t Size = sizeof(MemberExpr);
- bool hasQualOrFound = (qual != 0 ||
+ bool hasQualOrFound = (QualifierLoc ||
founddecl.getDecl() != memberdecl ||
founddecl.getAccess() != memberdecl->getAccess());
if (hasQualOrFound)
@@ -931,15 +912,15 @@ MemberExpr *MemberExpr::Create(ASTContext &C, Expr *base, bool isarrow,
ty, vk, ok);
if (hasQualOrFound) {
- if (qual && qual->isDependent()) {
+ // FIXME: Wrong. We should be looking at the member declaration we found.
+ if (QualifierLoc && QualifierLoc.getNestedNameSpecifier()->isDependent()) {
E->setValueDependent(true);
E->setTypeDependent(true);
}
E->HasQualifierOrFoundDecl = true;
MemberNameQualifier *NQ = E->getMemberQualifier();
- NQ->NNS = qual;
- NQ->Range = qualrange;
+ NQ->QualifierLoc = QualifierLoc;
NQ->FoundDecl = founddecl;
}
@@ -951,6 +932,28 @@ MemberExpr *MemberExpr::Create(ASTContext &C, Expr *base, bool isarrow,
return E;
}
+SourceRange MemberExpr::getSourceRange() const {
+ SourceLocation StartLoc;
+ if (isImplicitAccess()) {
+ if (hasQualifier())
+ StartLoc = getQualifierLoc().getBeginLoc();
+ else
+ StartLoc = MemberLoc;
+ } else {
+ // FIXME: We don't want this to happen. Rather, we should be able to
+ // detect all kinds of implicit accesses more cleanly.
+ StartLoc = getBase()->getLocStart();
+ if (StartLoc.isInvalid())
+ StartLoc = MemberLoc;
+ }
+
+ SourceLocation EndLoc =
+ HasExplicitTemplateArgumentList? getRAngleLoc()
+ : getMemberNameInfo().getEndLoc();
+
+ return SourceRange(StartLoc, EndLoc);
+}
+
const char *CastExpr::getCastKindName() const {
switch (getCastKind()) {
case CK_Dependent:
@@ -1241,7 +1244,7 @@ InitListExpr::InitListExpr(ASTContext &C, SourceLocation lbraceloc,
false),
InitExprs(C, numInits),
LBraceLoc(lbraceloc), RBraceLoc(rbraceloc), SyntacticForm(0),
- UnionFieldInit(0), HadArrayRangeDesignator(false)
+ HadArrayRangeDesignator(false)
{
for (unsigned I = 0; I != numInits; ++I) {
if (initExprs[I]->isTypeDependent())
@@ -1276,6 +1279,15 @@ Expr *InitListExpr::updateInit(ASTContext &C, unsigned Init, Expr *expr) {
return Result;
}
+void InitListExpr::setArrayFiller(Expr *filler) {
+ ArrayFillerOrUnionFieldInit = filler;
+ // Fill out any "holes" in the array due to designated initializers.
+ Expr **inits = getInits();
+ for (unsigned i = 0, e = getNumInits(); i != e; ++i)
+ if (inits[i] == 0)
+ inits[i] = filler;
+}
+
SourceRange InitListExpr::getSourceRange() const {
if (SyntacticForm)
return SyntacticForm->getSourceRange();
@@ -1348,6 +1360,9 @@ bool Expr::isUnusedResultAWarning(SourceLocation &Loc, SourceRange &R1,
case ParenExprClass:
return cast<ParenExpr>(this)->getSubExpr()->
isUnusedResultAWarning(Loc, R1, R2, Ctx);
+ case GenericSelectionExprClass:
+ return cast<GenericSelectionExpr>(this)->getResultExpr()->
+ isUnusedResultAWarning(Loc, R1, R2, Ctx);
case UnaryOperatorClass: {
const UnaryOperator *UO = cast<UnaryOperator>(this);
@@ -1412,13 +1427,15 @@ bool Expr::isUnusedResultAWarning(SourceLocation &Loc, SourceRange &R1,
return false;
case ConditionalOperatorClass: {
- // The condition must be evaluated, but if either the LHS or RHS is a
- // warning, warn about them.
+ // If only one of the LHS or RHS is a warning, the operator might
+ // be being used for control flow. Only warn if both the LHS and
+ // RHS are warnings.
const ConditionalOperator *Exp = cast<ConditionalOperator>(this);
- if (Exp->getLHS() &&
- Exp->getLHS()->isUnusedResultAWarning(Loc, R1, R2, Ctx))
+ if (!Exp->getRHS()->isUnusedResultAWarning(Loc, R1, R2, Ctx))
+ return false;
+ if (!Exp->getLHS())
return true;
- return Exp->getRHS()->isUnusedResultAWarning(Loc, R1, R2, Ctx);
+ return Exp->getLHS()->isUnusedResultAWarning(Loc, R1, R2, Ctx);
}
case MemberExprClass:
@@ -1556,21 +1573,20 @@ bool Expr::isUnusedResultAWarning(SourceLocation &Loc, SourceRange &R1,
/// isOBJCGCCandidate - Check if an expression is objc gc'able.
/// returns true, if it is; false otherwise.
bool Expr::isOBJCGCCandidate(ASTContext &Ctx) const {
- switch (getStmtClass()) {
+ const Expr *E = IgnoreParens();
+ switch (E->getStmtClass()) {
default:
return false;
case ObjCIvarRefExprClass:
return true;
case Expr::UnaryOperatorClass:
- return cast<UnaryOperator>(this)->getSubExpr()->isOBJCGCCandidate(Ctx);
- case ParenExprClass:
- return cast<ParenExpr>(this)->getSubExpr()->isOBJCGCCandidate(Ctx);
+ return cast<UnaryOperator>(E)->getSubExpr()->isOBJCGCCandidate(Ctx);
case ImplicitCastExprClass:
- return cast<ImplicitCastExpr>(this)->getSubExpr()->isOBJCGCCandidate(Ctx);
+ return cast<ImplicitCastExpr>(E)->getSubExpr()->isOBJCGCCandidate(Ctx);
case CStyleCastExprClass:
- return cast<CStyleCastExpr>(this)->getSubExpr()->isOBJCGCCandidate(Ctx);
+ return cast<CStyleCastExpr>(E)->getSubExpr()->isOBJCGCCandidate(Ctx);
case DeclRefExprClass: {
- const Decl *D = cast<DeclRefExpr>(this)->getDecl();
+ const Decl *D = cast<DeclRefExpr>(E)->getDecl();
if (const VarDecl *VD = dyn_cast<VarDecl>(D)) {
if (VD->hasGlobalStorage())
return true;
@@ -1583,11 +1599,11 @@ bool Expr::isOBJCGCCandidate(ASTContext &Ctx) const {
return false;
}
case MemberExprClass: {
- const MemberExpr *M = cast<MemberExpr>(this);
+ const MemberExpr *M = cast<MemberExpr>(E);
return M->getBase()->isOBJCGCCandidate(Ctx);
}
case ArraySubscriptExprClass:
- return cast<ArraySubscriptExpr>(this)->getBase()->isOBJCGCCandidate(Ctx);
+ return cast<ArraySubscriptExpr>(E)->getBase()->isOBJCGCCandidate(Ctx);
}
}
@@ -1597,6 +1613,30 @@ bool Expr::isBoundMemberFunction(ASTContext &Ctx) const {
return ClassifyLValue(Ctx) == Expr::LV_MemberFunction;
}
+QualType Expr::findBoundMemberType(const Expr *expr) {
+ assert(expr->getType()->isSpecificPlaceholderType(BuiltinType::BoundMember));
+
+ // Bound member expressions are always one of these possibilities:
+ // x->m x.m x->*y x.*y
+ // (possibly parenthesized)
+
+ expr = expr->IgnoreParens();
+ if (const MemberExpr *mem = dyn_cast<MemberExpr>(expr)) {
+ assert(isa<CXXMethodDecl>(mem->getMemberDecl()));
+ return mem->getMemberDecl()->getType();
+ }
+
+ if (const BinaryOperator *op = dyn_cast<BinaryOperator>(expr)) {
+ QualType type = op->getRHS()->getType()->castAs<MemberPointerType>()
+ ->getPointeeType();
+ assert(type->isFunctionType());
+ return type;
+ }
+
+ assert(isa<UnresolvedMemberExpr>(expr));
+ return QualType();
+}
+
static Expr::CanThrowResult MergeCanThrow(Expr::CanThrowResult CT1,
Expr::CanThrowResult CT2) {
// CanThrowResult constants are ordered so that the maximum is the correct
@@ -1613,7 +1653,7 @@ static Expr::CanThrowResult CanSubExprsThrow(ASTContext &C, const Expr *CE) {
return R;
}
-static Expr::CanThrowResult CanCalleeThrow(const Decl *D,
+static Expr::CanThrowResult CanCalleeThrow(ASTContext &Ctx, const Decl *D,
bool NullThrows = true) {
if (!D)
return NullThrows ? Expr::CT_Can : Expr::CT_Cannot;
@@ -1643,7 +1683,7 @@ static Expr::CanThrowResult CanCalleeThrow(const Decl *D,
if (!FT)
return Expr::CT_Can;
- return FT->hasEmptyExceptionSpec() ? Expr::CT_Cannot : Expr::CT_Can;
+ return FT->isNothrow(Ctx) ? Expr::CT_Cannot : Expr::CT_Can;
}
static Expr::CanThrowResult CanDynamicCastThrow(const CXXDynamicCastExpr *DC) {
@@ -1707,7 +1747,7 @@ Expr::CanThrowResult Expr::CanThrow(ASTContext &C) const {
case CallExprClass:
case CXXOperatorCallExprClass:
case CXXMemberCallExprClass: {
- CanThrowResult CT = CanCalleeThrow(cast<CallExpr>(this)->getCalleeDecl());
+ CanThrowResult CT = CanCalleeThrow(C,cast<CallExpr>(this)->getCalleeDecl());
if (CT == CT_Can)
return CT;
return MergeCanThrow(CT, CanSubExprsThrow(C, this));
@@ -1715,7 +1755,7 @@ Expr::CanThrowResult Expr::CanThrow(ASTContext &C) const {
case CXXConstructExprClass:
case CXXTemporaryObjectExprClass: {
- CanThrowResult CT = CanCalleeThrow(
+ CanThrowResult CT = CanCalleeThrow(C,
cast<CXXConstructExpr>(this)->getConstructor());
if (CT == CT_Can)
return CT;
@@ -1724,8 +1764,8 @@ Expr::CanThrowResult Expr::CanThrow(ASTContext &C) const {
case CXXNewExprClass: {
CanThrowResult CT = MergeCanThrow(
- CanCalleeThrow(cast<CXXNewExpr>(this)->getOperatorNew()),
- CanCalleeThrow(cast<CXXNewExpr>(this)->getConstructor(),
+ CanCalleeThrow(C, cast<CXXNewExpr>(this)->getOperatorNew()),
+ CanCalleeThrow(C, cast<CXXNewExpr>(this)->getConstructor(),
/*NullThrows*/false));
if (CT == CT_Can)
return CT;
@@ -1733,7 +1773,7 @@ Expr::CanThrowResult Expr::CanThrow(ASTContext &C) const {
}
case CXXDeleteExprClass: {
- CanThrowResult CT = CanCalleeThrow(
+ CanThrowResult CT = CanCalleeThrow(C,
cast<CXXDeleteExpr>(this)->getOperatorDelete());
if (CT == CT_Can)
return CT;
@@ -1743,7 +1783,7 @@ Expr::CanThrowResult Expr::CanThrow(ASTContext &C) const {
Arg = Cast->getSubExpr();
if (const PointerType *PT = Arg->getType()->getAs<PointerType>()) {
if (const RecordType *RT = PT->getPointeeType()->getAs<RecordType>()) {
- CanThrowResult CT2 = CanCalleeThrow(
+ CanThrowResult CT2 = CanCalleeThrow(C,
cast<CXXRecordDecl>(RT->getDecl())->getDestructor());
if (CT2 == CT_Can)
return CT2;
@@ -1755,7 +1795,7 @@ Expr::CanThrowResult Expr::CanThrow(ASTContext &C) const {
case CXXBindTemporaryExprClass: {
// The bound temporary has to be destroyed again, which might throw.
- CanThrowResult CT = CanCalleeThrow(
+ CanThrowResult CT = CanCalleeThrow(C,
cast<CXXBindTemporaryExpr>(this)->getTemporary()->getDestructor());
if (CT == CT_Can)
return CT;
@@ -1810,6 +1850,11 @@ Expr::CanThrowResult Expr::CanThrow(ASTContext &C) const {
return CT_Dependent;
return cast<ChooseExpr>(this)->getChosenSubExpr(C)->CanThrow(C);
+ case GenericSelectionExprClass:
+ if (cast<GenericSelectionExpr>(this)->isResultDependent())
+ return CT_Dependent;
+ return cast<GenericSelectionExpr>(this)->getResultExpr()->CanThrow(C);
+
// Some expressions are always dependent.
case DependentScopeDeclRefExprClass:
case CXXUnresolvedConstructExprClass:
@@ -1836,6 +1881,12 @@ Expr* Expr::IgnoreParens() {
continue;
}
}
+ if (GenericSelectionExpr* P = dyn_cast<GenericSelectionExpr>(E)) {
+ if (!P->isResultDependent()) {
+ E = P->getResultExpr();
+ continue;
+ }
+ }
return E;
}
}
@@ -1859,6 +1910,12 @@ Expr *Expr::IgnoreParenCasts() {
continue;
}
}
+ if (GenericSelectionExpr* P = dyn_cast<GenericSelectionExpr>(E)) {
+ if (!P->isResultDependent()) {
+ E = P->getResultExpr();
+ continue;
+ }
+ }
return E;
}
}
@@ -1883,6 +1940,11 @@ Expr *Expr::IgnoreParenLValueCasts() {
E = P->getSubExpr();
continue;
}
+ } else if (GenericSelectionExpr* P = dyn_cast<GenericSelectionExpr>(E)) {
+ if (!P->isResultDependent()) {
+ E = P->getResultExpr();
+ continue;
+ }
}
break;
}
@@ -1906,6 +1968,12 @@ Expr *Expr::IgnoreParenImpCasts() {
continue;
}
}
+ if (GenericSelectionExpr* P = dyn_cast<GenericSelectionExpr>(E)) {
+ if (!P->isResultDependent()) {
+ E = P->getResultExpr();
+ continue;
+ }
+ }
return E;
}
}
@@ -1948,6 +2016,13 @@ Expr *Expr::IgnoreParenNoopCasts(ASTContext &Ctx) {
}
}
+ if (GenericSelectionExpr* P = dyn_cast<GenericSelectionExpr>(E)) {
+ if (!P->isResultDependent()) {
+ E = P->getResultExpr();
+ continue;
+ }
+ }
+
return E;
}
}
@@ -2023,6 +2098,42 @@ bool Expr::isTemporaryObject(ASTContext &C, const CXXRecordDecl *TempTy) const {
return true;
}
+bool Expr::isImplicitCXXThis() const {
+ const Expr *E = this;
+
+ // Strip away parentheses and casts we don't care about.
+ while (true) {
+ if (const ParenExpr *Paren = dyn_cast<ParenExpr>(E)) {
+ E = Paren->getSubExpr();
+ continue;
+ }
+
+ if (const ImplicitCastExpr *ICE = dyn_cast<ImplicitCastExpr>(E)) {
+ if (ICE->getCastKind() == CK_NoOp ||
+ ICE->getCastKind() == CK_LValueToRValue ||
+ ICE->getCastKind() == CK_DerivedToBase ||
+ ICE->getCastKind() == CK_UncheckedDerivedToBase) {
+ E = ICE->getSubExpr();
+ continue;
+ }
+ }
+
+ if (const UnaryOperator* UnOp = dyn_cast<UnaryOperator>(E)) {
+ if (UnOp->getOpcode() == UO_Extension) {
+ E = UnOp->getSubExpr();
+ continue;
+ }
+ }
+
+ break;
+ }
+
+ if (const CXXThisExpr *This = dyn_cast<CXXThisExpr>(E))
+ return This->isImplicit();
+
+ return false;
+}
+
/// hasAnyTypeDependentArguments - Determines if any of the expressions
/// in Exprs is type-dependent.
bool Expr::hasAnyTypeDependentArguments(Expr** Exprs, unsigned NumExprs) {
@@ -2103,6 +2214,11 @@ bool Expr::isConstantInitializer(ASTContext &Ctx, bool IsForRef) const {
case ParenExprClass:
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)
->isConstantInitializer(Ctx, IsForRef);
@@ -2189,6 +2305,9 @@ Expr::isNullPointerConstant(ASTContext &Ctx,
// Accept ((void*)0) as a null pointer constant, as many other
// implementations do.
return PE->getSubExpr()->isNullPointerConstant(Ctx, NPC);
+ } else if (const GenericSelectionExpr *GE =
+ dyn_cast<GenericSelectionExpr>(this)) {
+ return GE->getResultExpr()->isNullPointerConstant(Ctx, NPC);
} else if (const CXXDefaultArgExpr *DefaultArg
= dyn_cast<CXXDefaultArgExpr>(this)) {
// See through default argument expressions
@@ -2587,6 +2706,51 @@ void ShuffleVectorExpr::setExprs(ASTContext &C, Expr ** Exprs,
memcpy(SubExprs, Exprs, sizeof(Expr *) * NumExprs);
}
+GenericSelectionExpr::GenericSelectionExpr(ASTContext &Context,
+ SourceLocation GenericLoc, Expr *ControllingExpr,
+ TypeSourceInfo **AssocTypes, Expr **AssocExprs,
+ unsigned NumAssocs, SourceLocation DefaultLoc,
+ SourceLocation RParenLoc,
+ bool ContainsUnexpandedParameterPack,
+ unsigned ResultIndex)
+ : Expr(GenericSelectionExprClass,
+ AssocExprs[ResultIndex]->getType(),
+ AssocExprs[ResultIndex]->getValueKind(),
+ AssocExprs[ResultIndex]->getObjectKind(),
+ AssocExprs[ResultIndex]->isTypeDependent(),
+ AssocExprs[ResultIndex]->isValueDependent(),
+ ContainsUnexpandedParameterPack),
+ AssocTypes(new (Context) TypeSourceInfo*[NumAssocs]),
+ SubExprs(new (Context) Stmt*[END_EXPR+NumAssocs]), NumAssocs(NumAssocs),
+ ResultIndex(ResultIndex), GenericLoc(GenericLoc), DefaultLoc(DefaultLoc),
+ RParenLoc(RParenLoc) {
+ SubExprs[CONTROLLING] = ControllingExpr;
+ std::copy(AssocTypes, AssocTypes+NumAssocs, this->AssocTypes);
+ std::copy(AssocExprs, AssocExprs+NumAssocs, SubExprs+END_EXPR);
+}
+
+GenericSelectionExpr::GenericSelectionExpr(ASTContext &Context,
+ SourceLocation GenericLoc, Expr *ControllingExpr,
+ TypeSourceInfo **AssocTypes, Expr **AssocExprs,
+ unsigned NumAssocs, SourceLocation DefaultLoc,
+ SourceLocation RParenLoc,
+ bool ContainsUnexpandedParameterPack)
+ : Expr(GenericSelectionExprClass,
+ Context.DependentTy,
+ VK_RValue,
+ OK_Ordinary,
+ /*isTypeDependent=*/ true,
+ /*isValueDependent=*/ true,
+ ContainsUnexpandedParameterPack),
+ AssocTypes(new (Context) TypeSourceInfo*[NumAssocs]),
+ SubExprs(new (Context) Stmt*[END_EXPR+NumAssocs]), NumAssocs(NumAssocs),
+ ResultIndex(-1U), GenericLoc(GenericLoc), DefaultLoc(DefaultLoc),
+ RParenLoc(RParenLoc) {
+ SubExprs[CONTROLLING] = ControllingExpr;
+ std::copy(AssocTypes, AssocTypes+NumAssocs, this->AssocTypes);
+ std::copy(AssocExprs, AssocExprs+NumAssocs, SubExprs+END_EXPR);
+}
+
//===----------------------------------------------------------------------===//
// DesignatedInitExpr
//===----------------------------------------------------------------------===//
@@ -2688,6 +2852,14 @@ void DesignatedInitExpr::setDesignators(ASTContext &C,
Designators[I] = Desigs[I];
}
+SourceRange DesignatedInitExpr::getDesignatorsSourceRange() const {
+ DesignatedInitExpr *DIE = const_cast<DesignatedInitExpr*>(this);
+ if (size() == 1)
+ return DIE->getDesignator(0)->getSourceRange();
+ return SourceRange(DIE->getDesignator(0)->getStartLocation(),
+ DIE->getDesignator(size()-1)->getEndLocation());
+}
+
SourceRange DesignatedInitExpr::getSourceRange() const {
SourceLocation StartLoc;
Designator &First =
@@ -2802,8 +2974,8 @@ const Expr* ConstExprIterator::operator->() const { return cast<Expr>(*I); }
// Child Iterators for iterating over subexpressions/substatements
//===----------------------------------------------------------------------===//
-// SizeOfAlignOfExpr
-Stmt::child_range SizeOfAlignOfExpr::children() {
+// UnaryExprOrTypeTraitExpr
+Stmt::child_range UnaryExprOrTypeTraitExpr::children() {
// If this is of a type and the type is a VLA type (and not a typedef), the
// size expression of the VLA needs to be treated as an executable expression.
// Why isn't this weirdness documented better in StmtIterator?
diff --git a/lib/AST/ExprCXX.cpp b/lib/AST/ExprCXX.cpp
index 4f4a6b4944d9..1a1a0a36a65b 100644
--- a/lib/AST/ExprCXX.cpp
+++ b/lib/AST/ExprCXX.cpp
@@ -100,6 +100,10 @@ void CXXNewExpr::AllocateArgsArray(ASTContext &C, bool isArray,
SubExprs = new (C) Stmt*[TotalSize];
}
+bool CXXNewExpr::shouldNullCheckAllocation(ASTContext &Ctx) const {
+ return getOperatorNew()->getType()->
+ castAs<FunctionProtoType>()->isNothrow(Ctx);
+}
// CXXDeleteExpr
QualType CXXDeleteExpr::getDestroyedType() const {
@@ -174,8 +178,7 @@ SourceRange CXXPseudoDestructorExpr::getSourceRange() const {
UnresolvedLookupExpr *
UnresolvedLookupExpr::Create(ASTContext &C,
CXXRecordDecl *NamingClass,
- NestedNameSpecifier *Qualifier,
- SourceRange QualifierRange,
+ NestedNameSpecifierLoc QualifierLoc,
const DeclarationNameInfo &NameInfo,
bool ADL,
const TemplateArgumentListInfo &Args,
@@ -184,10 +187,9 @@ UnresolvedLookupExpr::Create(ASTContext &C,
{
void *Mem = C.Allocate(sizeof(UnresolvedLookupExpr) +
ExplicitTemplateArgumentList::sizeFor(Args));
- return new (Mem) UnresolvedLookupExpr(C, NamingClass,
- Qualifier, QualifierRange, NameInfo,
+ return new (Mem) UnresolvedLookupExpr(C, NamingClass, QualifierLoc, NameInfo,
ADL, /*Overload*/ true, &Args,
- Begin, End);
+ Begin, End, /*StdIsAssociated=*/false);
}
UnresolvedLookupExpr *
@@ -204,7 +206,7 @@ UnresolvedLookupExpr::CreateEmpty(ASTContext &C, bool HasExplicitTemplateArgs,
}
OverloadExpr::OverloadExpr(StmtClass K, ASTContext &C,
- NestedNameSpecifier *Qualifier, SourceRange QRange,
+ NestedNameSpecifierLoc QualifierLoc,
const DeclarationNameInfo &NameInfo,
const TemplateArgumentListInfo *TemplateArgs,
UnresolvedSetIterator Begin,
@@ -215,10 +217,11 @@ OverloadExpr::OverloadExpr(StmtClass K, ASTContext &C,
KnownDependent,
(KnownContainsUnexpandedParameterPack ||
NameInfo.containsUnexpandedParameterPack() ||
- (Qualifier && Qualifier->containsUnexpandedParameterPack()))),
+ (QualifierLoc &&
+ QualifierLoc.getNestedNameSpecifier()
+ ->containsUnexpandedParameterPack()))),
Results(0), NumResults(End - Begin), NameInfo(NameInfo),
- Qualifier(Qualifier), QualifierRange(QRange),
- HasExplicitTemplateArgs(TemplateArgs != 0)
+ QualifierLoc(QualifierLoc), HasExplicitTemplateArgs(TemplateArgs != 0)
{
NumResults = End - Begin;
if (NumResults) {
@@ -365,8 +368,10 @@ SourceRange CXXOperatorCallExpr::getSourceRange() const {
getArg(0)->getSourceRange().getEnd());
else
// Postfix operator
- return SourceRange(getArg(0)->getSourceRange().getEnd(),
+ return SourceRange(getArg(0)->getSourceRange().getBegin(),
getOperatorLoc());
+ } else if (Kind == OO_Arrow) {
+ return getArg(0)->getSourceRange();
} else if (Kind == OO_Call) {
return SourceRange(getArg(0)->getSourceRange().getBegin(), getRParenLoc());
} else if (Kind == OO_Subscript) {
@@ -381,14 +386,25 @@ SourceRange CXXOperatorCallExpr::getSourceRange() const {
}
}
-Expr *CXXMemberCallExpr::getImplicitObjectArgument() {
- if (MemberExpr *MemExpr = dyn_cast<MemberExpr>(getCallee()->IgnoreParens()))
+Expr *CXXMemberCallExpr::getImplicitObjectArgument() const {
+ if (const MemberExpr *MemExpr =
+ dyn_cast<MemberExpr>(getCallee()->IgnoreParens()))
return MemExpr->getBase();
// FIXME: Will eventually need to cope with member pointers.
return 0;
}
+CXXMethodDecl *CXXMemberCallExpr::getMethodDecl() const {
+ if (const MemberExpr *MemExpr =
+ dyn_cast<MemberExpr>(getCallee()->IgnoreParens()))
+ return cast<CXXMethodDecl>(MemExpr->getMemberDecl());
+
+ // FIXME: Will eventually need to cope with member pointers.
+ return 0;
+}
+
+
CXXRecordDecl *CXXMemberCallExpr::getRecordDecl() {
Expr* ThisArg = getImplicitObjectArgument();
if (!ThisArg)
@@ -466,6 +482,36 @@ CXXDynamicCastExpr *CXXDynamicCastExpr::CreateEmpty(ASTContext &C,
return new (Buffer) CXXDynamicCastExpr(EmptyShell(), PathSize);
}
+/// isAlwaysNull - Return whether the result of the dynamic_cast is proven
+/// to always be null. For example:
+///
+/// struct A { };
+/// struct B final : A { };
+/// struct C { };
+///
+/// C *f(B* b) { return dynamic_cast<C*>(b); }
+bool CXXDynamicCastExpr::isAlwaysNull() const
+{
+ QualType SrcType = getSubExpr()->getType();
+ QualType DestType = getType();
+
+ if (const PointerType *SrcPTy = SrcType->getAs<PointerType>()) {
+ SrcType = SrcPTy->getPointeeType();
+ DestType = DestType->castAs<PointerType>()->getPointeeType();
+ }
+
+ const CXXRecordDecl *SrcRD =
+ cast<CXXRecordDecl>(SrcType->castAs<RecordType>()->getDecl());
+
+ if (!SrcRD->hasAttr<FinalAttr>())
+ return false;
+
+ const CXXRecordDecl *DestRD =
+ cast<CXXRecordDecl>(DestType->castAs<RecordType>()->getDecl());
+
+ return !DestRD->isDerivedFrom(SrcRD);
+}
+
CXXReinterpretCastExpr *
CXXReinterpretCastExpr::Create(ASTContext &C, QualType T, ExprValueKind VK,
CastKind K, Expr *Op,
@@ -689,20 +735,20 @@ CXXDependentScopeMemberExpr::CXXDependentScopeMemberExpr(ASTContext &C,
Expr *Base, QualType BaseType,
bool IsArrow,
SourceLocation OperatorLoc,
- NestedNameSpecifier *Qualifier,
- SourceRange QualifierRange,
+ NestedNameSpecifierLoc QualifierLoc,
NamedDecl *FirstQualifierFoundInScope,
DeclarationNameInfo MemberNameInfo,
const TemplateArgumentListInfo *TemplateArgs)
: Expr(CXXDependentScopeMemberExprClass, C.DependentTy,
VK_LValue, OK_Ordinary, true, true,
((Base && Base->containsUnexpandedParameterPack()) ||
- (Qualifier && Qualifier->containsUnexpandedParameterPack()) ||
+ (QualifierLoc &&
+ QualifierLoc.getNestedNameSpecifier()
+ ->containsUnexpandedParameterPack()) ||
MemberNameInfo.containsUnexpandedParameterPack())),
Base(Base), BaseType(BaseType), IsArrow(IsArrow),
HasExplicitTemplateArgs(TemplateArgs != 0),
- OperatorLoc(OperatorLoc),
- Qualifier(Qualifier), QualifierRange(QualifierRange),
+ OperatorLoc(OperatorLoc), QualifierLoc(QualifierLoc),
FirstQualifierFoundInScope(FirstQualifierFoundInScope),
MemberNameInfo(MemberNameInfo) {
if (TemplateArgs) {
@@ -719,18 +765,19 @@ CXXDependentScopeMemberExpr::CXXDependentScopeMemberExpr(ASTContext &C,
Expr *Base, QualType BaseType,
bool IsArrow,
SourceLocation OperatorLoc,
- NestedNameSpecifier *Qualifier,
- SourceRange QualifierRange,
+ NestedNameSpecifierLoc QualifierLoc,
NamedDecl *FirstQualifierFoundInScope,
DeclarationNameInfo MemberNameInfo)
: Expr(CXXDependentScopeMemberExprClass, C.DependentTy,
VK_LValue, OK_Ordinary, true, true,
((Base && Base->containsUnexpandedParameterPack()) ||
- (Qualifier && Qualifier->containsUnexpandedParameterPack()) ||
+ (QualifierLoc &&
+ QualifierLoc.getNestedNameSpecifier()->
+ containsUnexpandedParameterPack()) ||
MemberNameInfo.containsUnexpandedParameterPack())),
Base(Base), BaseType(BaseType), IsArrow(IsArrow),
HasExplicitTemplateArgs(false), OperatorLoc(OperatorLoc),
- Qualifier(Qualifier), QualifierRange(QualifierRange),
+ QualifierLoc(QualifierLoc),
FirstQualifierFoundInScope(FirstQualifierFoundInScope),
MemberNameInfo(MemberNameInfo) { }
@@ -738,15 +785,14 @@ CXXDependentScopeMemberExpr *
CXXDependentScopeMemberExpr::Create(ASTContext &C,
Expr *Base, QualType BaseType, bool IsArrow,
SourceLocation OperatorLoc,
- NestedNameSpecifier *Qualifier,
- SourceRange QualifierRange,
+ NestedNameSpecifierLoc QualifierLoc,
NamedDecl *FirstQualifierFoundInScope,
DeclarationNameInfo MemberNameInfo,
const TemplateArgumentListInfo *TemplateArgs) {
if (!TemplateArgs)
return new (C) CXXDependentScopeMemberExpr(C, Base, BaseType,
IsArrow, OperatorLoc,
- Qualifier, QualifierRange,
+ QualifierLoc,
FirstQualifierFoundInScope,
MemberNameInfo);
@@ -757,7 +803,7 @@ CXXDependentScopeMemberExpr::Create(ASTContext &C,
void *Mem = C.Allocate(size, llvm::alignOf<CXXDependentScopeMemberExpr>());
return new (Mem) CXXDependentScopeMemberExpr(C, Base, BaseType,
IsArrow, OperatorLoc,
- Qualifier, QualifierRange,
+ QualifierLoc,
FirstQualifierFoundInScope,
MemberNameInfo, TemplateArgs);
}
@@ -768,8 +814,8 @@ CXXDependentScopeMemberExpr::CreateEmpty(ASTContext &C,
unsigned NumTemplateArgs) {
if (!HasExplicitTemplateArgs)
return new (C) CXXDependentScopeMemberExpr(C, 0, QualType(),
- 0, SourceLocation(), 0,
- SourceRange(), 0,
+ 0, SourceLocation(),
+ NestedNameSpecifierLoc(), 0,
DeclarationNameInfo());
std::size_t size = sizeof(CXXDependentScopeMemberExpr) +
@@ -777,26 +823,53 @@ CXXDependentScopeMemberExpr::CreateEmpty(ASTContext &C,
void *Mem = C.Allocate(size, llvm::alignOf<CXXDependentScopeMemberExpr>());
CXXDependentScopeMemberExpr *E
= new (Mem) CXXDependentScopeMemberExpr(C, 0, QualType(),
- 0, SourceLocation(), 0,
- SourceRange(), 0,
+ 0, SourceLocation(),
+ NestedNameSpecifierLoc(), 0,
DeclarationNameInfo(), 0);
E->HasExplicitTemplateArgs = true;
return E;
}
+bool CXXDependentScopeMemberExpr::isImplicitAccess() const {
+ if (Base == 0)
+ return true;
+
+ return cast<Expr>(Base)->isImplicitCXXThis();
+}
+
+static bool hasOnlyNonStaticMemberFunctions(UnresolvedSetIterator begin,
+ UnresolvedSetIterator end) {
+ do {
+ NamedDecl *decl = *begin;
+ if (isa<UnresolvedUsingValueDecl>(decl))
+ return false;
+ if (isa<UsingShadowDecl>(decl))
+ decl = cast<UsingShadowDecl>(decl)->getUnderlyingDecl();
+
+ // Unresolved member expressions should only contain methods and
+ // method templates.
+ assert(isa<CXXMethodDecl>(decl) || isa<FunctionTemplateDecl>(decl));
+
+ if (isa<FunctionTemplateDecl>(decl))
+ decl = cast<FunctionTemplateDecl>(decl)->getTemplatedDecl();
+ if (cast<CXXMethodDecl>(decl)->isStatic())
+ return false;
+ } while (++begin != end);
+
+ return true;
+}
+
UnresolvedMemberExpr::UnresolvedMemberExpr(ASTContext &C,
bool HasUnresolvedUsing,
Expr *Base, QualType BaseType,
bool IsArrow,
SourceLocation OperatorLoc,
- NestedNameSpecifier *Qualifier,
- SourceRange QualifierRange,
+ NestedNameSpecifierLoc QualifierLoc,
const DeclarationNameInfo &MemberNameInfo,
const TemplateArgumentListInfo *TemplateArgs,
UnresolvedSetIterator Begin,
UnresolvedSetIterator End)
- : OverloadExpr(UnresolvedMemberExprClass, C,
- Qualifier, QualifierRange, MemberNameInfo,
+ : OverloadExpr(UnresolvedMemberExprClass, C, QualifierLoc, MemberNameInfo,
TemplateArgs, Begin, End,
// Dependent
((Base && Base->isTypeDependent()) ||
@@ -806,6 +879,18 @@ UnresolvedMemberExpr::UnresolvedMemberExpr(ASTContext &C,
BaseType->containsUnexpandedParameterPack())),
IsArrow(IsArrow), HasUnresolvedUsing(HasUnresolvedUsing),
Base(Base), BaseType(BaseType), OperatorLoc(OperatorLoc) {
+
+ // Check whether all of the members are non-static member functions,
+ // and if so, mark give this bound-member type instead of overload type.
+ if (hasOnlyNonStaticMemberFunctions(Begin, End))
+ setType(C.BoundMemberTy);
+}
+
+bool UnresolvedMemberExpr::isImplicitAccess() const {
+ if (Base == 0)
+ return true;
+
+ return cast<Expr>(Base)->isImplicitCXXThis();
}
UnresolvedMemberExpr *
@@ -813,8 +898,7 @@ UnresolvedMemberExpr::Create(ASTContext &C,
bool HasUnresolvedUsing,
Expr *Base, QualType BaseType, bool IsArrow,
SourceLocation OperatorLoc,
- NestedNameSpecifier *Qualifier,
- SourceRange QualifierRange,
+ NestedNameSpecifierLoc QualifierLoc,
const DeclarationNameInfo &MemberNameInfo,
const TemplateArgumentListInfo *TemplateArgs,
UnresolvedSetIterator Begin,
@@ -826,7 +910,7 @@ UnresolvedMemberExpr::Create(ASTContext &C,
void *Mem = C.Allocate(size, llvm::alignOf<UnresolvedMemberExpr>());
return new (Mem) UnresolvedMemberExpr(C,
HasUnresolvedUsing, Base, BaseType,
- IsArrow, OperatorLoc, Qualifier, QualifierRange,
+ IsArrow, OperatorLoc, QualifierLoc,
MemberNameInfo, TemplateArgs, Begin, End);
}
diff --git a/lib/AST/ExprClassification.cpp b/lib/AST/ExprClassification.cpp
index 890898a985e8..888a93c8aac0 100644
--- a/lib/AST/ExprClassification.cpp
+++ b/lib/AST/ExprClassification.cpp
@@ -61,8 +61,10 @@ Cl Expr::ClassifyImpl(ASTContext &Ctx, SourceLocation *Loc) const {
if (TR->isFunctionType() || TR == Ctx.OverloadTy)
kind = Cl::CL_Function;
// No void either, but qualified void is OK because it is "other than void".
- else if (TR->isVoidType() && !Ctx.getCanonicalType(TR).hasQualifiers())
- kind = Cl::CL_Void;
+ // Void "lvalues" are classified as addressable void values, which are void
+ // expressions whose address can be taken.
+ else if (TR->isVoidType() && !TR.hasQualifiers())
+ kind = (kind == Cl::CL_LValue ? Cl::CL_AddressableVoid : Cl::CL_Void);
}
// Enable this assertion for testing.
@@ -71,10 +73,12 @@ Cl Expr::ClassifyImpl(ASTContext &Ctx, SourceLocation *Loc) const {
case Cl::CL_XValue: assert(getValueKind() == VK_XValue); break;
case Cl::CL_Function:
case Cl::CL_Void:
+ case Cl::CL_AddressableVoid:
case Cl::CL_DuplicateVectorComponents:
case Cl::CL_MemberFunction:
case Cl::CL_SubObjCPropertySetting:
case Cl::CL_ClassTemporary:
+ case Cl::CL_ObjCMessageRValue:
case Cl::CL_PRValue: assert(getValueKind() == VK_RValue); break;
}
@@ -128,7 +132,7 @@ static Cl::Kinds ClassifyInternal(ASTContext &Ctx, const Expr *E) {
// Expressions that are prvalues.
case Expr::CXXBoolLiteralExprClass:
case Expr::CXXPseudoDestructorExprClass:
- case Expr::SizeOfAlignOfExprClass:
+ case Expr::UnaryExprOrTypeTraitExprClass:
case Expr::CXXNewExprClass:
case Expr::CXXThisExprClass:
case Expr::CXXNullPtrLiteralExprClass:
@@ -148,6 +152,8 @@ static Cl::Kinds ClassifyInternal(ASTContext &Ctx, const Expr *E) {
case Expr::CXXScalarValueInitExprClass:
case Expr::UnaryTypeTraitExprClass:
case Expr::BinaryTypeTraitExprClass:
+ case Expr::ArrayTypeTraitExprClass:
+ case Expr::ExpressionTraitExprClass:
case Expr::ObjCSelectorExprClass:
case Expr::ObjCProtocolExprClass:
case Expr::ObjCStringLiteralClass:
@@ -169,6 +175,9 @@ static Cl::Kinds ClassifyInternal(ASTContext &Ctx, const Expr *E) {
// C++ [expr.prim.general]p3: The result is an lvalue if the entity is a
// function or variable and a prvalue otherwise.
case Expr::DeclRefExprClass:
+ if (E->getType() == Ctx.UnknownAnyTy)
+ return isa<FunctionDecl>(cast<DeclRefExpr>(E)->getDecl())
+ ? Cl::CL_PRValue : Cl::CL_LValue;
return ClassifyDecl(Ctx, cast<DeclRefExpr>(E)->getDecl());
// We deal with names referenced from blocks the same way.
case Expr::BlockDeclRefExprClass:
@@ -229,6 +238,14 @@ static Cl::Kinds ClassifyInternal(ASTContext &Ctx, const Expr *E) {
case Expr::ParenExprClass:
return ClassifyInternal(Ctx, cast<ParenExpr>(E)->getSubExpr());
+ // C1X 6.5.1.1p4: [A generic selection] is an lvalue, a function designator,
+ // or a void expression if its result expression is, respectively, an
+ // lvalue, a function designator, or a void expression.
+ case Expr::GenericSelectionExprClass:
+ if (cast<GenericSelectionExpr>(E)->isResultDependent())
+ return Cl::CL_PRValue;
+ return ClassifyInternal(Ctx,cast<GenericSelectionExpr>(E)->getResultExpr());
+
case Expr::BinaryOperatorClass:
case Expr::CompoundAssignOperatorClass:
// C doesn't have any binary expressions that are lvalues.
@@ -293,7 +310,8 @@ static Cl::Kinds ClassifyInternal(ASTContext &Ctx, const Expr *E) {
case Expr::ObjCMessageExprClass:
if (const ObjCMethodDecl *Method =
cast<ObjCMessageExpr>(E)->getMethodDecl()) {
- return ClassifyUnnamed(Ctx, Method->getResultType());
+ Cl::Kinds kind = ClassifyUnnamed(Ctx, Method->getResultType());
+ return (kind == Cl::CL_PRValue) ? Cl::CL_ObjCMessageRValue : kind;
}
return Cl::CL_PRValue;
@@ -373,6 +391,10 @@ static Cl::Kinds ClassifyUnnamed(ASTContext &Ctx, QualType T) {
}
static Cl::Kinds ClassifyMemberExpr(ASTContext &Ctx, const MemberExpr *E) {
+ if (E->getType() == Ctx.UnknownAnyTy)
+ return (isa<FunctionDecl>(E->getMemberDecl())
+ ? Cl::CL_PRValue : Cl::CL_LValue);
+
// Handle C first, it's easier.
if (!Ctx.getLangOptions().CPlusPlus) {
// C99 6.5.2.3p3
@@ -546,11 +568,13 @@ Expr::LValueClassification Expr::ClassifyLValue(ASTContext &Ctx) const {
case Cl::CL_LValue: return LV_Valid;
case Cl::CL_XValue: return LV_InvalidExpression;
case Cl::CL_Function: return LV_NotObjectType;
- case Cl::CL_Void: return LV_IncompleteVoidType;
+ case Cl::CL_Void: return LV_InvalidExpression;
+ case Cl::CL_AddressableVoid: return LV_IncompleteVoidType;
case Cl::CL_DuplicateVectorComponents: return LV_DuplicateVectorComponents;
case Cl::CL_MemberFunction: return LV_MemberFunction;
case Cl::CL_SubObjCPropertySetting: return LV_SubObjCPropertySetting;
case Cl::CL_ClassTemporary: return LV_ClassTemporary;
+ case Cl::CL_ObjCMessageRValue: return LV_InvalidMessageExpression;
case Cl::CL_PRValue: return LV_InvalidExpression;
}
llvm_unreachable("Unhandled kind");
@@ -564,11 +588,13 @@ Expr::isModifiableLvalue(ASTContext &Ctx, SourceLocation *Loc) const {
case Cl::CL_LValue: break;
case Cl::CL_XValue: return MLV_InvalidExpression;
case Cl::CL_Function: return MLV_NotObjectType;
- case Cl::CL_Void: return MLV_IncompleteVoidType;
+ case Cl::CL_Void: return MLV_InvalidExpression;
+ case Cl::CL_AddressableVoid: return MLV_IncompleteVoidType;
case Cl::CL_DuplicateVectorComponents: return MLV_DuplicateVectorComponents;
case Cl::CL_MemberFunction: return MLV_MemberFunction;
case Cl::CL_SubObjCPropertySetting: return MLV_SubObjCPropertySetting;
case Cl::CL_ClassTemporary: return MLV_ClassTemporary;
+ case Cl::CL_ObjCMessageRValue: return MLV_InvalidMessageExpression;
case Cl::CL_PRValue:
return VC.getModifiable() == Cl::CM_LValueCast ?
MLV_LValueCast : MLV_InvalidExpression;
diff --git a/lib/AST/ExprConstant.cpp b/lib/AST/ExprConstant.cpp
index 3a5eb66ea18f..c2caf8d40b16 100644
--- a/lib/AST/ExprConstant.cpp
+++ b/lib/AST/ExprConstant.cpp
@@ -42,25 +42,25 @@ using llvm::APFloat;
/// rules. For example, the RHS of (0 && foo()) is not evaluated. We can
/// evaluate the expression regardless of what the RHS is, but C only allows
/// certain things in certain situations.
-struct EvalInfo {
- const ASTContext &Ctx;
-
- /// EvalResult - Contains information about the evaluation.
- Expr::EvalResult &EvalResult;
-
- llvm::DenseMap<const OpaqueValueExpr*, APValue> OpaqueValues;
- const APValue *getOpaqueValue(const OpaqueValueExpr *e) {
- llvm::DenseMap<const OpaqueValueExpr*, APValue>::iterator
- i = OpaqueValues.find(e);
- if (i == OpaqueValues.end()) return 0;
- return &i->second;
- }
+namespace {
+ struct EvalInfo {
+ const ASTContext &Ctx;
+
+ /// EvalResult - Contains information about the evaluation.
+ Expr::EvalResult &EvalResult;
+
+ typedef llvm::DenseMap<const OpaqueValueExpr*, APValue> MapTy;
+ MapTy OpaqueValues;
+ const APValue *getOpaqueValue(const OpaqueValueExpr *e) const {
+ MapTy::const_iterator i = OpaqueValues.find(e);
+ if (i == OpaqueValues.end()) return 0;
+ return &i->second;
+ }
- EvalInfo(const ASTContext &ctx, Expr::EvalResult& evalresult)
- : Ctx(ctx), EvalResult(evalresult) {}
-};
+ EvalInfo(const ASTContext &ctx, Expr::EvalResult &evalresult)
+ : Ctx(ctx), EvalResult(evalresult) {}
+ };
-namespace {
struct ComplexValue {
private:
bool IsInt;
@@ -175,7 +175,7 @@ static bool EvalPointerValueAsBool(LValue& Value, bool& Result) {
const ValueDecl* Decl = DeclRef->getDecl();
if (Decl->hasAttr<WeakAttr>() ||
Decl->hasAttr<WeakRefAttr>() ||
- Decl->hasAttr<WeakImportAttr>())
+ Decl->isWeakImported())
return false;
return true;
@@ -274,6 +274,9 @@ public:
}
bool VisitParenExpr(ParenExpr *E) { return Visit(E->getSubExpr()); }
+ bool VisitGenericSelectionExpr(GenericSelectionExpr *E) {
+ return Visit(E->getResultExpr());
+ }
bool VisitDeclRefExpr(DeclRefExpr *E) {
if (Info.Ctx.getCanonicalType(E->getType()).isVolatileQualified())
return true;
@@ -290,7 +293,8 @@ public:
bool VisitFloatingLiteral(FloatingLiteral *E) { return false; }
bool VisitStringLiteral(StringLiteral *E) { return false; }
bool VisitCharacterLiteral(CharacterLiteral *E) { return false; }
- bool VisitSizeOfAlignOfExpr(SizeOfAlignOfExpr *E) { return false; }
+ bool VisitUnaryExprOrTypeTraitExpr(UnaryExprOrTypeTraitExpr *E)
+ { return false; }
bool VisitArraySubscriptExpr(ArraySubscriptExpr *E)
{ return Visit(E->getLHS()) || Visit(E->getRHS()); }
bool VisitChooseExpr(ChooseExpr *E)
@@ -315,6 +319,8 @@ public:
bool VisitInitListExpr(InitListExpr *E) {
for (unsigned i = 0, e = E->getNumInits(); i != e; ++i)
if (Visit(E->getInit(i))) return true;
+ if (Expr *filler = E->getArrayFiller())
+ return Visit(filler);
return false;
}
@@ -371,6 +377,9 @@ public:
}
bool VisitParenExpr(ParenExpr *E) { return Visit(E->getSubExpr()); }
+ bool VisitGenericSelectionExpr(GenericSelectionExpr *E) {
+ return Visit(E->getResultExpr());
+ }
bool VisitDeclRefExpr(DeclRefExpr *E);
bool VisitPredefinedExpr(PredefinedExpr *E) { return Success(E); }
bool VisitCompoundLiteralExpr(CompoundLiteralExpr *E);
@@ -500,6 +509,9 @@ public:
}
bool VisitParenExpr(ParenExpr *E) { return Visit(E->getSubExpr()); }
+ bool VisitGenericSelectionExpr(GenericSelectionExpr *E) {
+ return Visit(E->getResultExpr());
+ }
bool VisitBinaryOperator(const BinaryOperator *E);
bool VisitCastExpr(CastExpr* E);
@@ -589,7 +601,6 @@ bool PointerExprEvaluator::VisitCastExpr(CastExpr* E) {
case CK_NoOp:
case CK_BitCast:
- case CK_LValueBitCast:
case CK_AnyPointerToObjCPointerCast:
case CK_AnyPointerToBlockPointerCast:
return Visit(SubExpr);
@@ -717,6 +728,8 @@ namespace {
APValue VisitParenExpr(ParenExpr *E)
{ return Visit(E->getSubExpr()); }
+ APValue VisitGenericSelectionExpr(GenericSelectionExpr *E)
+ { return Visit(E->getResultExpr()); }
APValue VisitUnaryExtension(const UnaryOperator *E)
{ return Visit(E->getSubExpr()); }
APValue VisitUnaryPlus(const UnaryOperator *E)
@@ -755,68 +768,61 @@ APValue VectorExprEvaluator::VisitCastExpr(const CastExpr* E) {
const Expr* SE = E->getSubExpr();
QualType SETy = SE->getType();
- APValue Result = APValue();
-
- // Check for vector->vector bitcast and scalar->vector splat.
- if (SETy->isVectorType()) {
- return this->Visit(const_cast<Expr*>(SE));
- } else if (SETy->isIntegerType()) {
- APSInt IntResult;
- if (!EvaluateInteger(SE, IntResult, Info))
- return APValue();
- Result = APValue(IntResult);
- } else if (SETy->isRealFloatingType()) {
- APFloat F(0.0);
- if (!EvaluateFloat(SE, F, Info))
- return APValue();
- Result = APValue(F);
- } else
- return APValue();
- // For casts of a scalar to ExtVector, convert the scalar to the element type
- // and splat it to all elements.
- if (E->getType()->isExtVectorType()) {
- if (EltTy->isIntegerType() && Result.isInt())
- Result = APValue(HandleIntToIntCast(EltTy, SETy, Result.getInt(),
- Info.Ctx));
- else if (EltTy->isIntegerType())
- Result = APValue(HandleFloatToIntCast(EltTy, SETy, Result.getFloat(),
- Info.Ctx));
- else if (EltTy->isRealFloatingType() && Result.isInt())
- Result = APValue(HandleIntToFloatCast(EltTy, SETy, Result.getInt(),
- Info.Ctx));
- else if (EltTy->isRealFloatingType())
- Result = APValue(HandleFloatToFloatCast(EltTy, SETy, Result.getFloat(),
- Info.Ctx));
- else
+ switch (E->getCastKind()) {
+ case CK_VectorSplat: {
+ APValue Result = APValue();
+ if (SETy->isIntegerType()) {
+ APSInt IntResult;
+ if (!EvaluateInteger(SE, IntResult, Info))
+ return APValue();
+ Result = APValue(IntResult);
+ } else if (SETy->isRealFloatingType()) {
+ APFloat F(0.0);
+ if (!EvaluateFloat(SE, F, Info))
+ return APValue();
+ Result = APValue(F);
+ } else {
return APValue();
+ }
// Splat and create vector APValue.
llvm::SmallVector<APValue, 4> Elts(NElts, Result);
return APValue(&Elts[0], Elts.size());
}
+ case CK_BitCast: {
+ if (SETy->isVectorType())
+ return Visit(const_cast<Expr*>(SE));
- // For casts of a scalar to regular gcc-style vector type, bitcast the scalar
- // to the vector. To construct the APValue vector initializer, bitcast the
- // initializing value to an APInt, and shift out the bits pertaining to each
- // element.
- APSInt Init;
- Init = Result.isInt() ? Result.getInt() : Result.getFloat().bitcastToAPInt();
-
- llvm::SmallVector<APValue, 4> Elts;
- for (unsigned i = 0; i != NElts; ++i) {
- APSInt Tmp = Init.extOrTrunc(EltWidth);
+ if (!SETy->isIntegerType())
+ return APValue();
- if (EltTy->isIntegerType())
- Elts.push_back(APValue(Tmp));
- else if (EltTy->isRealFloatingType())
- Elts.push_back(APValue(APFloat(Tmp)));
- else
+ APSInt Init;
+ if (!EvaluateInteger(SE, Init, Info))
return APValue();
- Init >>= EltWidth;
+ assert((EltTy->isIntegerType() || EltTy->isRealFloatingType()) &&
+ "Vectors must be composed of ints or floats");
+
+ llvm::SmallVector<APValue, 4> Elts;
+ for (unsigned i = 0; i != NElts; ++i) {
+ APSInt Tmp = Init.extOrTrunc(EltWidth);
+
+ if (EltTy->isIntegerType())
+ Elts.push_back(APValue(Tmp));
+ else
+ Elts.push_back(APValue(APFloat(Tmp)));
+
+ Init >>= EltWidth;
+ }
+ return APValue(&Elts[0], Elts.size());
+ }
+ case CK_LValueToRValue:
+ case CK_NoOp:
+ return Visit(const_cast<Expr*>(SE));
+ default:
+ return APValue();
}
- return APValue(&Elts[0], Elts.size());
}
APValue
@@ -837,6 +843,12 @@ VectorExprEvaluator::VisitInitListExpr(const InitListExpr *E) {
// becomes every element of the vector, not just the first.
// This is the behavior described in the IBM AltiVec documentation.
if (NumInits == 1) {
+
+ // Handle the case where the vector is initialized by a another
+ // vector (OpenCL 6.1.6).
+ if (E->getInit(0)->getType()->isVectorType())
+ return this->Visit(const_cast<Expr*>(E->getInit(0)));
+
APValue InitValue;
if (EltTy->isIntegerType()) {
llvm::APSInt sInt(32);
@@ -953,6 +965,11 @@ public:
return true;
}
+ bool Success(CharUnits Size, const Expr *E) {
+ return Success(Size.getQuantity(), E);
+ }
+
+
bool Error(SourceLocation L, diag::kind D, const Expr *E) {
// Take the first error.
if (Info.EvalResult.Diag == 0) {
@@ -977,6 +994,9 @@ public:
}
bool VisitParenExpr(ParenExpr *E) { return Visit(E->getSubExpr()); }
+ bool VisitGenericSelectionExpr(GenericSelectionExpr *E) {
+ return Visit(E->getResultExpr());
+ }
bool VisitIntegerLiteral(const IntegerLiteral *E) {
return Success(E->getValue(), E);
@@ -1015,7 +1035,7 @@ public:
bool VisitBinaryConditionalOperator(const BinaryConditionalOperator *E);
bool VisitCastExpr(CastExpr* E);
- bool VisitSizeOfAlignOfExpr(const SizeOfAlignOfExpr *E);
+ bool VisitUnaryExprOrTypeTraitExpr(const UnaryExprOrTypeTraitExpr *E);
bool VisitCXXBoolLiteralExpr(const CXXBoolLiteralExpr *E) {
return Success(E->getValue(), E);
@@ -1041,6 +1061,14 @@ public:
return Success(E->getValue(), E);
}
+ bool VisitArrayTypeTraitExpr(const ArrayTypeTraitExpr *E) {
+ return Success(E->getValue(), E);
+ }
+
+ bool VisitExpressionTraitExpr(const ExpressionTraitExpr *E) {
+ return Success(E->getValue(), E);
+ }
+
bool VisitChooseExpr(const ChooseExpr *E) {
return Visit(E->getChosenSubExpr(Info.Ctx));
}
@@ -1213,7 +1241,7 @@ bool IntExprEvaluator::TryEvaluateBuiltinObjectSize(CallExpr *E) {
Size -= Offset;
else
Size = CharUnits::Zero();
- return Success(Size.getQuantity(), E);
+ return Success(Size, E);
}
bool IntExprEvaluator::VisitCallExpr(CallExpr *E) {
@@ -1596,36 +1624,59 @@ CharUnits IntExprEvaluator::GetAlignOfExpr(const Expr *E) {
}
-/// VisitSizeAlignOfExpr - Evaluate a sizeof or alignof with a result as the
-/// expression's type.
-bool IntExprEvaluator::VisitSizeOfAlignOfExpr(const SizeOfAlignOfExpr *E) {
- // Handle alignof separately.
- if (!E->isSizeOf()) {
+/// VisitUnaryExprOrTypeTraitExpr - Evaluate a sizeof, alignof or vec_step with
+/// a result as the expression's type.
+bool IntExprEvaluator::VisitUnaryExprOrTypeTraitExpr(
+ const UnaryExprOrTypeTraitExpr *E) {
+ switch(E->getKind()) {
+ case UETT_AlignOf: {
if (E->isArgumentType())
- return Success(GetAlignOfType(E->getArgumentType()).getQuantity(), E);
+ return Success(GetAlignOfType(E->getArgumentType()), E);
else
- return Success(GetAlignOfExpr(E->getArgumentExpr()).getQuantity(), E);
+ return Success(GetAlignOfExpr(E->getArgumentExpr()), E);
}
- QualType SrcTy = E->getTypeOfArgument();
- // C++ [expr.sizeof]p2: "When applied to a reference or a reference type,
- // the result is the size of the referenced type."
- // C++ [expr.alignof]p3: "When alignof is applied to a reference type, the
- // result shall be the alignment of the referenced type."
- if (const ReferenceType *Ref = SrcTy->getAs<ReferenceType>())
- SrcTy = Ref->getPointeeType();
+ case UETT_VecStep: {
+ QualType Ty = E->getTypeOfArgument();
- // sizeof(void), __alignof__(void), sizeof(function) = 1 as a gcc
- // extension.
- if (SrcTy->isVoidType() || SrcTy->isFunctionType())
- return Success(1, E);
+ if (Ty->isVectorType()) {
+ unsigned n = Ty->getAs<VectorType>()->getNumElements();
- // sizeof(vla) is not a constantexpr: C99 6.5.3.4p2.
- if (!SrcTy->isConstantSizeType())
- return false;
+ // The vec_step built-in functions that take a 3-component
+ // vector return 4. (OpenCL 1.1 spec 6.11.12)
+ if (n == 3)
+ n = 4;
+
+ return Success(n, E);
+ } else
+ return Success(1, E);
+ }
+
+ case UETT_SizeOf: {
+ QualType SrcTy = E->getTypeOfArgument();
+ // C++ [expr.sizeof]p2: "When applied to a reference or a reference type,
+ // the result is the size of the referenced type."
+ // C++ [expr.alignof]p3: "When alignof is applied to a reference type, the
+ // result shall be the alignment of the referenced type."
+ if (const ReferenceType *Ref = SrcTy->getAs<ReferenceType>())
+ SrcTy = Ref->getPointeeType();
+
+ // sizeof(void), __alignof__(void), sizeof(function) = 1 as a gcc
+ // extension.
+ if (SrcTy->isVoidType() || SrcTy->isFunctionType())
+ return Success(1, E);
+
+ // sizeof(vla) is not a constantexpr: C99 6.5.3.4p2.
+ if (!SrcTy->isConstantSizeType())
+ return false;
+
+ // Get information about the size.
+ return Success(Info.Ctx.getTypeSizeInChars(SrcTy), E);
+ }
+ }
- // Get information about the size.
- return Success(Info.Ctx.getTypeSizeInChars(SrcTy).getQuantity(), E);
+ llvm_unreachable("unknown expr/type trait");
+ return false;
}
bool IntExprEvaluator::VisitOffsetOfExpr(const OffsetOfExpr *E) {
@@ -1694,7 +1745,7 @@ bool IntExprEvaluator::VisitOffsetOfExpr(const OffsetOfExpr *E) {
}
}
}
- return Success(Result.getQuantity(), E);
+ return Success(Result, E);
}
bool IntExprEvaluator::VisitUnaryOperator(const UnaryOperator *E) {
@@ -1742,15 +1793,60 @@ bool IntExprEvaluator::VisitCastExpr(CastExpr *E) {
QualType DestType = E->getType();
QualType SrcType = SubExpr->getType();
- if (DestType->isBooleanType()) {
+ switch (E->getCastKind()) {
+ case CK_BaseToDerived:
+ case CK_DerivedToBase:
+ case CK_UncheckedDerivedToBase:
+ case CK_Dynamic:
+ case CK_ToUnion:
+ case CK_ArrayToPointerDecay:
+ case CK_FunctionToPointerDecay:
+ case CK_NullToPointer:
+ case CK_NullToMemberPointer:
+ case CK_BaseToDerivedMemberPointer:
+ case CK_DerivedToBaseMemberPointer:
+ case CK_ConstructorConversion:
+ case CK_IntegralToPointer:
+ case CK_ToVoid:
+ case CK_VectorSplat:
+ case CK_IntegralToFloating:
+ case CK_FloatingCast:
+ case CK_AnyPointerToObjCPointerCast:
+ case CK_AnyPointerToBlockPointerCast:
+ case CK_ObjCObjectLValueCast:
+ case CK_FloatingRealToComplex:
+ case CK_FloatingComplexToReal:
+ case CK_FloatingComplexCast:
+ case CK_FloatingComplexToIntegralComplex:
+ case CK_IntegralRealToComplex:
+ case CK_IntegralComplexCast:
+ case CK_IntegralComplexToFloatingComplex:
+ llvm_unreachable("invalid cast kind for integral value");
+
+ case CK_BitCast:
+ case CK_Dependent:
+ case CK_GetObjCProperty:
+ case CK_LValueBitCast:
+ case CK_UserDefinedConversion:
+ return false;
+
+ case CK_LValueToRValue:
+ case CK_NoOp:
+ return Visit(E->getSubExpr());
+
+ case CK_MemberPointerToBoolean:
+ case CK_PointerToBoolean:
+ case CK_IntegralToBoolean:
+ case CK_FloatingToBoolean:
+ case CK_FloatingComplexToBoolean:
+ case CK_IntegralComplexToBoolean: {
bool BoolResult;
if (!HandleConversionToBool(SubExpr, BoolResult, Info))
return false;
return Success(BoolResult, E);
}
- // Handle simple integer->integer casts.
- if (SrcType->isIntegralOrEnumerationType()) {
+ case CK_IntegralCast: {
if (!Visit(SubExpr))
return false;
@@ -1763,8 +1859,7 @@ bool IntExprEvaluator::VisitCastExpr(CastExpr *E) {
Result.getInt(), Info.Ctx), E);
}
- // FIXME: Clean this up!
- if (SrcType->isPointerType()) {
+ case CK_PointerToIntegral: {
LValue LV;
if (!EvaluatePointer(SubExpr, LV, Info))
return false;
@@ -1783,42 +1878,24 @@ bool IntExprEvaluator::VisitCastExpr(CastExpr *E) {
return Success(HandleIntToIntCast(DestType, SrcType, AsInt, Info.Ctx), E);
}
- if (SrcType->isArrayType() || SrcType->isFunctionType()) {
- // This handles double-conversion cases, where there's both
- // an l-value promotion and an implicit conversion to int.
- LValue LV;
- if (!EvaluateLValue(SubExpr, LV, Info))
- return false;
-
- if (Info.Ctx.getTypeSize(DestType) != Info.Ctx.getTypeSize(Info.Ctx.VoidPtrTy))
- return false;
-
- LV.moveInto(Result);
- return true;
- }
-
- if (SrcType->isAnyComplexType()) {
+ case CK_IntegralComplexToReal: {
ComplexValue C;
if (!EvaluateComplex(SubExpr, C, Info))
return false;
- if (C.isComplexFloat())
- return Success(HandleFloatToIntCast(DestType, SrcType,
- C.getComplexFloatReal(), Info.Ctx),
- E);
- else
- return Success(HandleIntToIntCast(DestType, SrcType,
- C.getComplexIntReal(), Info.Ctx), E);
+ return Success(C.getComplexIntReal(), E);
}
- // FIXME: Handle vectors
- if (!SrcType->isRealFloatingType())
- return Error(E->getExprLoc(), diag::note_invalid_subexpr_in_ice, E);
+ case CK_FloatingToIntegral: {
+ APFloat F(0.0);
+ if (!EvaluateFloat(SubExpr, F, Info))
+ return false;
- APFloat F(0.0);
- if (!EvaluateFloat(SubExpr, F, Info))
- return Error(E->getExprLoc(), diag::note_invalid_subexpr_in_ice, E);
+ return Success(HandleFloatToIntCast(DestType, SrcType, F, Info.Ctx), E);
+ }
+ }
- return Success(HandleFloatToIntCast(DestType, SrcType, F, Info.Ctx), E);
+ llvm_unreachable("unknown cast resulting in integral value");
+ return false;
}
bool IntExprEvaluator::VisitUnaryReal(const UnaryOperator *E) {
@@ -1871,6 +1948,9 @@ public:
}
bool VisitParenExpr(ParenExpr *E) { return Visit(E->getSubExpr()); }
+ bool VisitGenericSelectionExpr(GenericSelectionExpr *E) {
+ return Visit(E->getResultExpr());
+ }
bool VisitCallExpr(const CallExpr *E);
bool VisitUnaryOperator(const UnaryOperator *E);
@@ -2119,7 +2199,15 @@ bool FloatExprEvaluator::VisitFloatingLiteral(const FloatingLiteral *E) {
bool FloatExprEvaluator::VisitCastExpr(CastExpr *E) {
Expr* SubExpr = E->getSubExpr();
- if (SubExpr->getType()->isIntegralOrEnumerationType()) {
+ switch (E->getCastKind()) {
+ default:
+ return false;
+
+ case CK_LValueToRValue:
+ case CK_NoOp:
+ return Visit(SubExpr);
+
+ case CK_IntegralToFloating: {
APSInt IntResult;
if (!EvaluateInteger(SubExpr, IntResult, Info))
return false;
@@ -2127,7 +2215,8 @@ bool FloatExprEvaluator::VisitCastExpr(CastExpr *E) {
IntResult, Info.Ctx);
return true;
}
- if (SubExpr->getType()->isRealFloatingType()) {
+
+ case CK_FloatingCast: {
if (!Visit(SubExpr))
return false;
Result = HandleFloatToFloatCast(E->getType(), SubExpr->getType(),
@@ -2135,13 +2224,14 @@ bool FloatExprEvaluator::VisitCastExpr(CastExpr *E) {
return true;
}
- if (E->getCastKind() == CK_FloatingComplexToReal) {
+ case CK_FloatingComplexToReal: {
ComplexValue V;
if (!EvaluateComplex(SubExpr, V, Info))
return false;
Result = V.getComplexFloatReal();
return true;
}
+ }
return false;
}
@@ -2194,6 +2284,9 @@ public:
}
bool VisitParenExpr(ParenExpr *E) { return Visit(E->getSubExpr()); }
+ bool VisitGenericSelectionExpr(GenericSelectionExpr *E) {
+ return Visit(E->getResultExpr());
+ }
bool VisitImaginaryLiteral(ImaginaryLiteral *E);
@@ -2253,7 +2346,6 @@ bool ComplexExprEvaluator::VisitCastExpr(CastExpr *E) {
switch (E->getCastKind()) {
case CK_BitCast:
- case CK_LValueBitCast:
case CK_BaseToDerived:
case CK_DerivedToBase:
case CK_UncheckedDerivedToBase:
@@ -2293,6 +2385,7 @@ bool ComplexExprEvaluator::VisitCastExpr(CastExpr *E) {
case CK_Dependent:
case CK_GetObjCProperty:
+ case CK_LValueBitCast:
case CK_UserDefinedConversion:
return false;
@@ -2782,12 +2875,16 @@ static ICEDiag CheckICE(const Expr* E, ASTContext &Ctx) {
case Expr::ParenExprClass:
return CheckICE(cast<ParenExpr>(E)->getSubExpr(), Ctx);
+ case Expr::GenericSelectionExprClass:
+ return CheckICE(cast<GenericSelectionExpr>(E)->getResultExpr(), Ctx);
case Expr::IntegerLiteralClass:
case Expr::CharacterLiteralClass:
case Expr::CXXBoolLiteralExprClass:
case Expr::CXXScalarValueInitExprClass:
case Expr::UnaryTypeTraitExprClass:
case Expr::BinaryTypeTraitExprClass:
+ case Expr::ArrayTypeTraitExprClass:
+ case Expr::ExpressionTraitExprClass:
case Expr::CXXNoexceptExprClass:
return NoDiag();
case Expr::CallExprClass:
@@ -2879,9 +2976,10 @@ static ICEDiag CheckICE(const Expr* E, ASTContext &Ctx) {
// are ICEs, the value of the offsetof must be an integer constant.
return CheckEvalInICE(E, Ctx);
}
- case Expr::SizeOfAlignOfExprClass: {
- const SizeOfAlignOfExpr *Exp = cast<SizeOfAlignOfExpr>(E);
- if (Exp->isSizeOf() && Exp->getTypeOfArgument()->isVariableArrayType())
+ case Expr::UnaryExprOrTypeTraitExprClass: {
+ const UnaryExprOrTypeTraitExpr *Exp = cast<UnaryExprOrTypeTraitExpr>(E);
+ if ((Exp->getKind() == UETT_SizeOf) &&
+ Exp->getTypeOfArgument()->isVariableArrayType())
return ICEDiag(2, E->getLocStart());
return NoDiag();
}
diff --git a/lib/AST/ExternalASTSource.cpp b/lib/AST/ExternalASTSource.cpp
new file mode 100644
index 000000000000..89bf56db1af7
--- /dev/null
+++ b/lib/AST/ExternalASTSource.cpp
@@ -0,0 +1,59 @@
+//===- ExternalASTSource.cpp - Abstract External AST Interface --*- C++ -*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+//
+// This file provides the default implementation of the ExternalASTSource
+// interface, which enables construction of AST nodes from some external
+// source.
+//
+//===----------------------------------------------------------------------===//
+
+#include "clang/AST/ExternalASTSource.h"
+#include "clang/AST/DeclarationName.h"
+
+using namespace clang;
+
+ExternalASTSource::~ExternalASTSource() { }
+
+void ExternalASTSource::PrintStats() { }
+
+Decl *ExternalASTSource::GetExternalDecl(uint32_t ID) {
+ return 0;
+}
+
+Selector ExternalASTSource::GetExternalSelector(uint32_t ID) {
+ return Selector();
+}
+
+uint32_t ExternalASTSource::GetNumExternalSelectors() {
+ return 0;
+}
+
+Stmt *ExternalASTSource::GetExternalDeclStmt(uint64_t Offset) {
+ return 0;
+}
+
+CXXBaseSpecifier *
+ExternalASTSource::GetExternalCXXBaseSpecifiers(uint64_t Offset) {
+ return 0;
+}
+
+DeclContextLookupResult
+ExternalASTSource::FindExternalVisibleDeclsByName(const DeclContext *DC,
+ DeclarationName Name) {
+ return DeclContext::lookup_result();
+}
+
+void ExternalASTSource::MaterializeVisibleDecls(const DeclContext *DC) { }
+
+bool
+ExternalASTSource::FindExternalLexicalDecls(const DeclContext *DC,
+ bool (*isKindWeWant)(Decl::Kind),
+ llvm::SmallVectorImpl<Decl*> &Result) {
+ return true;
+}
diff --git a/lib/AST/InheritViz.cpp b/lib/AST/InheritViz.cpp
index 533a2329c583..c47a9dadbadd 100644
--- a/lib/AST/InheritViz.cpp
+++ b/lib/AST/InheritViz.cpp
@@ -17,7 +17,6 @@
#include "clang/AST/Decl.h"
#include "clang/AST/DeclCXX.h"
#include "clang/AST/TypeOrdering.h"
-#include "llvm/Support/FileSystem.h"
#include "llvm/Support/GraphWriter.h"
#include "llvm/Support/raw_ostream.h"
#include <map>
@@ -136,28 +135,34 @@ InheritanceHierarchyWriter::WriteNodeReference(QualType Type,
/// class using GraphViz.
void CXXRecordDecl::viewInheritance(ASTContext& Context) const {
QualType Self = Context.getTypeDeclType(const_cast<CXXRecordDecl *>(this));
- // Create temp directory
- SmallString<128> Filename;
- int FileFD = 0;
- if (error_code ec = sys::fs::unique_file(
- "clang-class-inheritance-hierarchy-%%-%%-%%-%%-" +
- Self.getAsString() + ".dot",
- FileFD, Filename)) {
- errs() << "Error creating temporary output file: " << ec.message() << '\n';
+ std::string ErrMsg;
+ sys::Path Filename = sys::Path::GetTemporaryDirectory(&ErrMsg);
+ if (Filename.isEmpty()) {
+ llvm::errs() << "Error: " << ErrMsg << "\n";
+ return;
+ }
+ Filename.appendComponent(Self.getAsString() + ".dot");
+ if (Filename.makeUnique(true,&ErrMsg)) {
+ llvm::errs() << "Error: " << ErrMsg << "\n";
return;
}
- llvm::errs() << "Writing '" << Filename << "'... ";
+ llvm::errs() << "Writing '" << Filename.c_str() << "'... ";
- llvm::raw_fd_ostream O(FileFD, true);
- InheritanceHierarchyWriter Writer(Context, O);
- Writer.WriteGraph(Self);
+ llvm::raw_fd_ostream O(Filename.c_str(), ErrMsg);
- llvm::errs() << " done. \n";
- O.close();
+ if (ErrMsg.empty()) {
+ InheritanceHierarchyWriter Writer(Context, O);
+ Writer.WriteGraph(Self);
+ llvm::errs() << " done. \n";
- // Display the graph
- DisplayGraph(sys::Path(Filename));
+ O.close();
+
+ // Display the graph
+ DisplayGraph(Filename);
+ } else {
+ llvm::errs() << "error opening file for writing!\n";
+ }
}
}
diff --git a/lib/AST/ItaniumCXXABI.cpp b/lib/AST/ItaniumCXXABI.cpp
index bed02b4c0010..30aece3ee73b 100644
--- a/lib/AST/ItaniumCXXABI.cpp
+++ b/lib/AST/ItaniumCXXABI.cpp
@@ -7,7 +7,7 @@
//
//===----------------------------------------------------------------------===//
//
-// This provides C++ AST support targetting the Itanium C++ ABI, which is
+// This provides C++ AST support targeting the Itanium C++ ABI, which is
// documented at:
// http://www.codesourcery.com/public/cxx-abi/abi.html
// http://www.codesourcery.com/public/cxx-abi/abi-eh.html
diff --git a/lib/AST/ItaniumMangle.cpp b/lib/AST/ItaniumMangle.cpp
index 939ca7a924aa..c460929c461d 100644
--- a/lib/AST/ItaniumMangle.cpp
+++ b/lib/AST/ItaniumMangle.cpp
@@ -21,6 +21,7 @@
#include "clang/AST/DeclObjC.h"
#include "clang/AST/DeclTemplate.h"
#include "clang/AST/ExprCXX.h"
+#include "clang/AST/TypeLoc.h"
#include "clang/Basic/ABI.h"
#include "clang/Basic/SourceManager.h"
#include "clang/Basic/TargetInfo.h"
@@ -50,18 +51,16 @@ static const CXXRecordDecl *GetLocalClassDecl(const NamedDecl *ND) {
return 0;
}
-static const CXXMethodDecl *getStructor(const CXXMethodDecl *MD) {
- assert((isa<CXXConstructorDecl>(MD) || isa<CXXDestructorDecl>(MD)) &&
- "Passed in decl is not a ctor or dtor!");
+static const FunctionDecl *getStructor(const FunctionDecl *fn) {
+ if (const FunctionTemplateDecl *ftd = fn->getPrimaryTemplate())
+ return ftd->getTemplatedDecl();
- if (const TemplateDecl *TD = MD->getPrimaryTemplate()) {
- MD = cast<CXXMethodDecl>(TD->getTemplatedDecl());
-
- assert((isa<CXXConstructorDecl>(MD) || isa<CXXDestructorDecl>(MD)) &&
- "Templated decl is not a ctor or dtor!");
- }
+ return fn;
+}
- return MD;
+static const NamedDecl *getStructor(const NamedDecl *decl) {
+ const FunctionDecl *fn = dyn_cast_or_null<FunctionDecl>(decl);
+ return (fn ? getStructor(fn) : decl);
}
static const unsigned UnknownArity = ~0U;
@@ -138,27 +137,75 @@ class CXXNameMangler {
ItaniumMangleContext &Context;
llvm::raw_ostream &Out;
- const CXXMethodDecl *Structor;
+ /// The "structor" is the top-level declaration being mangled, if
+ /// that's not a template specialization; otherwise it's the pattern
+ /// for that specialization.
+ const NamedDecl *Structor;
unsigned StructorType;
/// SeqID - The next subsitution sequence number.
unsigned SeqID;
+ class FunctionTypeDepthState {
+ unsigned Bits;
+
+ enum { InResultTypeMask = 1 };
+
+ public:
+ FunctionTypeDepthState() : Bits(0) {}
+
+ /// The number of function types we're inside.
+ unsigned getDepth() const {
+ return Bits >> 1;
+ }
+
+ /// True if we're in the return type of the innermost function type.
+ bool isInResultType() const {
+ return Bits & InResultTypeMask;
+ }
+
+ FunctionTypeDepthState push() {
+ FunctionTypeDepthState tmp = *this;
+ Bits = (Bits & ~InResultTypeMask) + 2;
+ return tmp;
+ }
+
+ void enterResultType() {
+ Bits |= InResultTypeMask;
+ }
+
+ void leaveResultType() {
+ Bits &= ~InResultTypeMask;
+ }
+
+ void pop(FunctionTypeDepthState saved) {
+ assert(getDepth() == saved.getDepth() + 1);
+ Bits = saved.Bits;
+ }
+
+ } FunctionTypeDepth;
+
llvm::DenseMap<uintptr_t, unsigned> Substitutions;
ASTContext &getASTContext() const { return Context.getASTContext(); }
public:
- CXXNameMangler(ItaniumMangleContext &C, llvm::raw_ostream &Out_)
- : Context(C), Out(Out_), Structor(0), StructorType(0), SeqID(0) { }
+ CXXNameMangler(ItaniumMangleContext &C, llvm::raw_ostream &Out_,
+ const NamedDecl *D = 0)
+ : Context(C), Out(Out_), Structor(getStructor(D)), StructorType(0),
+ SeqID(0) {
+ // These can't be mangled without a ctor type or dtor type.
+ assert(!D || (!isa<CXXDestructorDecl>(D) &&
+ !isa<CXXConstructorDecl>(D)));
+ }
CXXNameMangler(ItaniumMangleContext &C, llvm::raw_ostream &Out_,
const CXXConstructorDecl *D, CXXCtorType Type)
: Context(C), Out(Out_), Structor(getStructor(D)), StructorType(Type),
- SeqID(0) { }
+ SeqID(0) { }
CXXNameMangler(ItaniumMangleContext &C, llvm::raw_ostream &Out_,
const CXXDestructorDecl *D, CXXDtorType Type)
: Context(C), Out(Out_), Structor(getStructor(D)), StructorType(Type),
- SeqID(0) { }
+ SeqID(0) { }
#if MANGLE_CHECKER
~CXXNameMangler() {
@@ -200,11 +247,16 @@ private:
void addSubstitution(TemplateName Template);
void addSubstitution(uintptr_t Ptr);
- void mangleUnresolvedScope(NestedNameSpecifier *Qualifier);
- void mangleUnresolvedName(NestedNameSpecifier *Qualifier,
- DeclarationName Name,
+ void mangleUnresolvedPrefix(NestedNameSpecifier *qualifier,
+ NamedDecl *firstQualifierLookup,
+ bool recursive = false);
+ void mangleUnresolvedName(NestedNameSpecifier *qualifier,
+ NamedDecl *firstQualifierLookup,
+ DeclarationName name,
unsigned KnownArity = UnknownArity);
+ void mangleUnresolvedType(QualType type);
+
void mangleName(const TemplateDecl *TD,
const TemplateArgument *TemplateArgs,
unsigned NumTemplateArgs);
@@ -223,6 +275,7 @@ private:
void mangleNestedName(const TemplateDecl *TD,
const TemplateArgument *TemplateArgs,
unsigned NumTemplateArgs);
+ void manglePrefix(NestedNameSpecifier *qualifier);
void manglePrefix(const DeclContext *DC, bool NoFunction=false);
void mangleTemplatePrefix(const TemplateDecl *ND);
void mangleTemplatePrefix(TemplateName Template);
@@ -245,10 +298,11 @@ private:
void mangleNeonVectorType(const VectorType *T);
void mangleIntegerLiteral(QualType T, const llvm::APSInt &Value);
- void mangleMemberExpr(const Expr *Base, bool IsArrow,
- NestedNameSpecifier *Qualifier,
- DeclarationName Name,
- unsigned KnownArity);
+ void mangleMemberExpr(const Expr *base, bool isArrow,
+ NestedNameSpecifier *qualifier,
+ NamedDecl *firstQualifierLookup,
+ DeclarationName name,
+ unsigned knownArity);
void mangleExpression(const Expr *E, unsigned Arity = UnknownArity);
void mangleCXXCtorType(CXXCtorType T);
void mangleCXXDtorType(CXXDtorType T);
@@ -265,6 +319,8 @@ private:
void mangleTemplateArg(const NamedDecl *P, const TemplateArgument &A);
void mangleTemplateParameter(unsigned Index);
+
+ void mangleFunctionParam(const ParmVarDecl *parm);
};
}
@@ -334,10 +390,11 @@ void CXXNameMangler::mangle(const NamedDecl *D, llvm::StringRef Prefix) {
// another has a "\01foo". That is known to happen on ELF with the
// tricks normally used for producing aliases (PR9177). Fortunately the
// llvm mangler on ELF is a nop, so we can just avoid adding the \01
- // marker.
+ // marker. We also avoid adding the marker if this is an alias for an
+ // LLVM intrinsic.
llvm::StringRef UserLabelPrefix =
getASTContext().Target.getUserLabelPrefix();
- if (!UserLabelPrefix.empty())
+ if (!UserLabelPrefix.empty() && !ALA->getLabel().startswith("llvm."))
Out << '\01'; // LLVM IR Marker for __asm("foo")
Out << ALA->getLabel();
@@ -552,11 +609,24 @@ void CXXNameMangler::mangleUnscopedTemplateName(TemplateName Template) {
addSubstitution(Template);
}
-void CXXNameMangler::mangleFloat(const llvm::APFloat &F) {
- // TODO: avoid this copy with careful stream management.
- llvm::SmallString<20> Buffer;
- F.bitcastToAPInt().toString(Buffer, 16, false);
- Out.write(Buffer.data(), Buffer.size());
+void CXXNameMangler::mangleFloat(const llvm::APFloat &f) {
+ // ABI:
+ // Floating-point literals are encoded using a fixed-length
+ // lowercase hexadecimal string corresponding to the internal
+ // representation (IEEE on Itanium), high-order bytes first,
+ // without leading zeroes. For example: "Lf bf800000 E" is -1.0f
+ // on Itanium.
+ // APInt::toString uses uppercase hexadecimal, and it's not really
+ // worth embellishing that interface for this use case, so we just
+ // do a second pass to lowercase things.
+ typedef llvm::SmallString<20> buffer_t;
+ buffer_t buffer;
+ f.bitcastToAPInt().toString(buffer, 16, false);
+
+ for (buffer_t::iterator i = buffer.begin(), e = buffer.end(); i != e; ++i)
+ if (isupper(*i)) *i = tolower(*i);
+
+ Out.write(buffer.data(), buffer.size());
}
void CXXNameMangler::mangleNumber(const llvm::APSInt &Value) {
@@ -597,59 +667,162 @@ void CXXNameMangler::mangleCallOffset(int64_t NonVirtual, int64_t Virtual) {
Out << '_';
}
-void CXXNameMangler::mangleUnresolvedScope(NestedNameSpecifier *Qualifier) {
- Qualifier = getASTContext().getCanonicalNestedNameSpecifier(Qualifier);
- switch (Qualifier->getKind()) {
+void CXXNameMangler::mangleUnresolvedType(QualType type) {
+ if (const TemplateSpecializationType *TST =
+ type->getAs<TemplateSpecializationType>()) {
+ if (!mangleSubstitution(QualType(TST, 0))) {
+ mangleTemplatePrefix(TST->getTemplateName());
+
+ // FIXME: GCC does not appear to mangle the template arguments when
+ // the template in question is a dependent template name. Should we
+ // emulate that badness?
+ mangleTemplateArgs(TST->getTemplateName(), TST->getArgs(),
+ TST->getNumArgs());
+ addSubstitution(QualType(TST, 0));
+ }
+ } else if (const DependentTemplateSpecializationType *DTST
+ = type->getAs<DependentTemplateSpecializationType>()) {
+ TemplateName Template
+ = getASTContext().getDependentTemplateName(DTST->getQualifier(),
+ DTST->getIdentifier());
+ mangleTemplatePrefix(Template);
+
+ // FIXME: GCC does not appear to mangle the template arguments when
+ // the template in question is a dependent template name. Should we
+ // emulate that badness?
+ mangleTemplateArgs(Template, DTST->getArgs(), DTST->getNumArgs());
+ } else {
+ // We use the QualType mangle type variant here because it handles
+ // substitutions.
+ mangleType(type);
+ }
+}
+
+/// Mangle everything prior to the base-unresolved-name in an unresolved-name.
+///
+/// \param firstQualifierLookup - the entity found by unqualified lookup
+/// for the first name in the qualifier, if this is for a member expression
+/// \param recursive - true if this is being called recursively,
+/// i.e. if there is more prefix "to the right".
+void CXXNameMangler::mangleUnresolvedPrefix(NestedNameSpecifier *qualifier,
+ NamedDecl *firstQualifierLookup,
+ bool recursive) {
+
+ // x, ::x
+ // <unresolved-name> ::= [gs] <base-unresolved-name>
+
+ // T::x / decltype(p)::x
+ // <unresolved-name> ::= sr <unresolved-type> <base-unresolved-name>
+
+ // T::N::x /decltype(p)::N::x
+ // <unresolved-name> ::= srN <unresolved-type> <unresolved-qualifier-level>+ E
+ // <base-unresolved-name>
+
+ // A::x, N::y, A<T>::z; "gs" means leading "::"
+ // <unresolved-name> ::= [gs] sr <unresolved-qualifier-level>+ E
+ // <base-unresolved-name>
+
+ switch (qualifier->getKind()) {
case NestedNameSpecifier::Global:
- // nothing
- break;
+ Out << "gs";
+
+ // We want an 'sr' unless this is the entire NNS.
+ if (recursive)
+ Out << "sr";
+
+ // We never want an 'E' here.
+ return;
+
case NestedNameSpecifier::Namespace:
- mangleName(Qualifier->getAsNamespace());
+ if (qualifier->getPrefix())
+ mangleUnresolvedPrefix(qualifier->getPrefix(), firstQualifierLookup,
+ /*recursive*/ true);
+ else
+ Out << "sr";
+ mangleSourceName(qualifier->getAsNamespace()->getIdentifier());
break;
case NestedNameSpecifier::NamespaceAlias:
- mangleName(Qualifier->getAsNamespaceAlias()->getNamespace());
+ if (qualifier->getPrefix())
+ mangleUnresolvedPrefix(qualifier->getPrefix(), firstQualifierLookup,
+ /*recursive*/ true);
+ else
+ Out << "sr";
+ mangleSourceName(qualifier->getAsNamespaceAlias()->getIdentifier());
break;
+
case NestedNameSpecifier::TypeSpec:
case NestedNameSpecifier::TypeSpecWithTemplate: {
- const Type *QTy = Qualifier->getAsType();
+ // Both cases want this.
+ Out << "sr";
- if (const TemplateSpecializationType *TST =
- dyn_cast<TemplateSpecializationType>(QTy)) {
- if (!mangleSubstitution(QualType(TST, 0))) {
- mangleTemplatePrefix(TST->getTemplateName());
-
- // FIXME: GCC does not appear to mangle the template arguments when
- // the template in question is a dependent template name. Should we
- // emulate that badness?
- mangleTemplateArgs(TST->getTemplateName(), TST->getArgs(),
- TST->getNumArgs());
- addSubstitution(QualType(TST, 0));
- }
- } else {
- // We use the QualType mangle type variant here because it handles
- // substitutions.
- mangleType(QualType(QTy, 0));
- }
+ // We only get here recursively if we're followed by identifiers.
+ if (recursive) Out << 'N';
+
+ mangleUnresolvedType(QualType(qualifier->getAsType(), 0));
+
+ // We never want to print 'E' directly after an unresolved-type,
+ // so we return directly.
+ return;
}
- break;
+
case NestedNameSpecifier::Identifier:
// Member expressions can have these without prefixes.
- if (Qualifier->getPrefix())
- mangleUnresolvedScope(Qualifier->getPrefix());
- mangleSourceName(Qualifier->getAsIdentifier());
+ if (qualifier->getPrefix()) {
+ mangleUnresolvedPrefix(qualifier->getPrefix(), firstQualifierLookup,
+ /*recursive*/ true);
+ } else if (firstQualifierLookup) {
+
+ // Try to make a proper qualifier out of the lookup result, and
+ // then just recurse on that.
+ NestedNameSpecifier *newQualifier;
+ if (TypeDecl *typeDecl = dyn_cast<TypeDecl>(firstQualifierLookup)) {
+ QualType type = getASTContext().getTypeDeclType(typeDecl);
+
+ // Pretend we had a different nested name specifier.
+ newQualifier = NestedNameSpecifier::Create(getASTContext(),
+ /*prefix*/ 0,
+ /*template*/ false,
+ type.getTypePtr());
+ } else if (NamespaceDecl *nspace =
+ dyn_cast<NamespaceDecl>(firstQualifierLookup)) {
+ newQualifier = NestedNameSpecifier::Create(getASTContext(),
+ /*prefix*/ 0,
+ nspace);
+ } else if (NamespaceAliasDecl *alias =
+ dyn_cast<NamespaceAliasDecl>(firstQualifierLookup)) {
+ newQualifier = NestedNameSpecifier::Create(getASTContext(),
+ /*prefix*/ 0,
+ alias);
+ } else {
+ // No sensible mangling to do here.
+ newQualifier = 0;
+ }
+
+ if (newQualifier)
+ return mangleUnresolvedPrefix(newQualifier, /*lookup*/ 0, recursive);
+
+ } else {
+ Out << "sr";
+ }
+
+ mangleSourceName(qualifier->getAsIdentifier());
break;
}
-}
-/// Mangles a name which was not resolved to a specific entity.
-void CXXNameMangler::mangleUnresolvedName(NestedNameSpecifier *Qualifier,
- DeclarationName Name,
- unsigned KnownArity) {
- if (Qualifier)
- mangleUnresolvedScope(Qualifier);
- // FIXME: ambiguity of unqualified lookup with ::
+ // If this was the innermost part of the NNS, and we fell out to
+ // here, append an 'E'.
+ if (!recursive)
+ Out << 'E';
+}
- mangleUnqualifiedName(0, Name, KnownArity);
+/// Mangle an unresolved-name, which is generally used for names which
+/// weren't resolved to specific entities.
+void CXXNameMangler::mangleUnresolvedName(NestedNameSpecifier *qualifier,
+ NamedDecl *firstQualifierLookup,
+ DeclarationName name,
+ unsigned knownArity) {
+ if (qualifier) mangleUnresolvedPrefix(qualifier, firstQualifierLookup);
+ mangleUnqualifiedName(0, name, knownArity);
}
static const FieldDecl *FindFirstNamedDataMember(const RecordDecl *RD) {
@@ -684,10 +857,12 @@ void CXXNameMangler::mangleUnqualifiedName(const NamedDecl *ND,
case DeclarationName::Identifier: {
if (const IdentifierInfo *II = Name.getAsIdentifierInfo()) {
// We must avoid conflicts between internally- and externally-
- // linked variable declaration names in the same TU.
- // This naming convention is the same as that followed by GCC, though it
- // shouldn't actually matter.
- if (ND && isa<VarDecl>(ND) && ND->getLinkage() == InternalLinkage &&
+ // linked variable and function declaration names in the same TU:
+ // void test() { extern void foo(); }
+ // static void foo();
+ // This naming convention is the same as that followed by GCC,
+ // though it shouldn't actually matter.
+ if (ND && ND->getLinkage() == InternalLinkage &&
ND->getDeclContext()->isFileContext())
Out << 'L';
@@ -734,7 +909,7 @@ void CXXNameMangler::mangleUnqualifiedName(const NamedDecl *ND,
// We must have an anonymous struct.
const TagDecl *TD = cast<TagDecl>(ND);
- if (const TypedefDecl *D = TD->getTypedefForAnonDecl()) {
+ if (const TypedefNameDecl *D = TD->getTypedefNameForAnonDecl()) {
assert(TD->getDeclContext() == D->getDeclContext() &&
"Typedef should not be in another decl context!");
assert(D->getDeclName().getAsIdentifierInfo() &&
@@ -906,6 +1081,38 @@ void CXXNameMangler::mangleLocalName(const NamedDecl *ND) {
mangleUnqualifiedName(ND);
}
+void CXXNameMangler::manglePrefix(NestedNameSpecifier *qualifier) {
+ switch (qualifier->getKind()) {
+ case NestedNameSpecifier::Global:
+ // nothing
+ return;
+
+ case NestedNameSpecifier::Namespace:
+ mangleName(qualifier->getAsNamespace());
+ return;
+
+ case NestedNameSpecifier::NamespaceAlias:
+ mangleName(qualifier->getAsNamespaceAlias()->getNamespace());
+ return;
+
+ case NestedNameSpecifier::TypeSpec:
+ case NestedNameSpecifier::TypeSpecWithTemplate:
+ mangleUnresolvedType(QualType(qualifier->getAsType(), 0));
+ return;
+
+ case NestedNameSpecifier::Identifier:
+ // Member expressions can have these without prefixes, but that
+ // should end up in mangleUnresolvedPrefix instead.
+ assert(qualifier->getPrefix());
+ manglePrefix(qualifier->getPrefix());
+
+ mangleSourceName(qualifier->getAsIdentifier());
+ return;
+ }
+
+ llvm_unreachable("unexpected nested name specifier");
+}
+
void CXXNameMangler::manglePrefix(const DeclContext *DC, bool NoFunction) {
// <prefix> ::= <prefix> <unqualified-name>
// ::= <template-prefix> <template-args>
@@ -959,7 +1166,7 @@ void CXXNameMangler::mangleTemplatePrefix(TemplateName Template) {
return mangleTemplatePrefix(TD);
if (QualifiedTemplateName *Qualified = Template.getAsQualifiedTemplateName())
- mangleUnresolvedScope(Qualified->getQualifier());
+ manglePrefix(Qualified->getQualifier());
if (OverloadedTemplateStorage *Overloaded
= Template.getAsOverloadedTemplate()) {
@@ -970,7 +1177,7 @@ void CXXNameMangler::mangleTemplatePrefix(TemplateName Template) {
DependentTemplateName *Dependent = Template.getAsDependentTemplateName();
assert(Dependent && "Unknown template name kind?");
- mangleUnresolvedScope(Dependent->getQualifier());
+ manglePrefix(Dependent->getQualifier());
mangleUnscopedTemplateName(Template);
}
@@ -1033,7 +1240,7 @@ void CXXNameMangler::mangleType(TemplateName TN) {
// <class-enum-type> ::= <name>
// <name> ::= <nested-name>
- mangleUnresolvedScope(Dependent->getQualifier());
+ mangleUnresolvedPrefix(Dependent->getQualifier(), 0);
mangleSourceName(Dependent->getIdentifier());
break;
}
@@ -1313,8 +1520,9 @@ void CXXNameMangler::mangleType(const BuiltinType *T) {
case BuiltinType::Overload:
case BuiltinType::Dependent:
- assert(false &&
- "Overloaded and dependent types shouldn't get to name mangling");
+ case BuiltinType::BoundMember:
+ case BuiltinType::UnknownAny:
+ llvm_unreachable("mangling a placeholder type");
break;
case BuiltinType::ObjCId: Out << "11objc_object"; break;
case BuiltinType::ObjCClass: Out << "10objc_class"; break;
@@ -1339,13 +1547,22 @@ void CXXNameMangler::mangleBareFunctionType(const FunctionType *T,
// We should never be mangling something without a prototype.
const FunctionProtoType *Proto = cast<FunctionProtoType>(T);
+ // Record that we're in a function type. See mangleFunctionParam
+ // for details on what we're trying to achieve here.
+ FunctionTypeDepthState saved = FunctionTypeDepth.push();
+
// <bare-function-type> ::= <signature type>+
- if (MangleReturnType)
+ if (MangleReturnType) {
+ FunctionTypeDepth.enterResultType();
mangleType(Proto->getResultType());
+ FunctionTypeDepth.leaveResultType();
+ }
if (Proto->getNumArgs() == 0 && !Proto->isVariadic()) {
// <builtin-type> ::= v # void
Out << 'v';
+
+ FunctionTypeDepth.pop(saved);
return;
}
@@ -1354,6 +1571,8 @@ void CXXNameMangler::mangleBareFunctionType(const FunctionType *T,
Arg != ArgEnd; ++Arg)
mangleType(*Arg);
+ FunctionTypeDepth.pop(saved);
+
// <builtin-type> ::= z # ellipsis
if (Proto->isVariadic())
Out << 'z';
@@ -1590,13 +1809,13 @@ void CXXNameMangler::mangleType(const TemplateSpecializationType *T) {
void CXXNameMangler::mangleType(const DependentNameType *T) {
// Typename types are always nested
Out << 'N';
- mangleUnresolvedScope(T->getQualifier());
+ manglePrefix(T->getQualifier());
mangleSourceName(T->getIdentifier());
Out << 'E';
}
void CXXNameMangler::mangleType(const DependentTemplateSpecializationType *T) {
- // Dependently-scoped template types are always nested
+ // Dependently-scoped template types are nested if they have a prefix.
Out << 'N';
// TODO: avoid making this TemplateName.
@@ -1676,23 +1895,54 @@ void CXXNameMangler::mangleIntegerLiteral(QualType T,
/// Mangles a member expression. Implicit accesses are not handled,
/// but that should be okay, because you shouldn't be able to
/// make an implicit access in a function template declaration.
-void CXXNameMangler::mangleMemberExpr(const Expr *Base,
- bool IsArrow,
- NestedNameSpecifier *Qualifier,
- DeclarationName Member,
- unsigned Arity) {
- // gcc-4.4 uses 'dt' for dot expressions, which is reasonable.
- // OTOH, gcc also mangles the name as an expression.
- Out << (IsArrow ? "pt" : "dt");
- mangleExpression(Base);
- mangleUnresolvedName(Qualifier, Member, Arity);
+void CXXNameMangler::mangleMemberExpr(const Expr *base,
+ bool isArrow,
+ NestedNameSpecifier *qualifier,
+ NamedDecl *firstQualifierLookup,
+ DeclarationName member,
+ unsigned arity) {
+ // <expression> ::= dt <expression> <unresolved-name>
+ // ::= pt <expression> <unresolved-name>
+ Out << (isArrow ? "pt" : "dt");
+ mangleExpression(base);
+ mangleUnresolvedName(qualifier, firstQualifierLookup, member, arity);
+}
+
+/// Look at the callee of the given call expression and determine if
+/// it's a parenthesized id-expression which would have triggered ADL
+/// otherwise.
+static bool isParenthesizedADLCallee(const CallExpr *call) {
+ const Expr *callee = call->getCallee();
+ const Expr *fn = callee->IgnoreParens();
+
+ // Must be parenthesized. IgnoreParens() skips __extension__ nodes,
+ // too, but for those to appear in the callee, it would have to be
+ // parenthesized.
+ if (callee == fn) return false;
+
+ // Must be an unresolved lookup.
+ const UnresolvedLookupExpr *lookup = dyn_cast<UnresolvedLookupExpr>(fn);
+ if (!lookup) return false;
+
+ assert(!lookup->requiresADL());
+
+ // Must be an unqualified lookup.
+ if (lookup->getQualifier()) return false;
+
+ // Must not have found a class member. Note that if one is a class
+ // member, they're all class members.
+ if (lookup->getNumDecls() > 0 &&
+ (*lookup->decls_begin())->isCXXClassMember())
+ return false;
+
+ // Otherwise, ADL would have been triggered.
+ return true;
}
void CXXNameMangler::mangleExpression(const Expr *E, unsigned Arity) {
// <expression> ::= <unary operator-name> <expression>
// ::= <binary operator-name> <expression> <expression>
// ::= <trinary operator-name> <expression> <expression> <expression>
- // ::= cl <expression>* E # call
// ::= cv <type> expression # conversion with one argument
// ::= cv <type> _ <expression>* E # conversion with a different number of arguments
// ::= st <type> # sizeof (a type)
@@ -1735,6 +1985,7 @@ void CXXNameMangler::mangleExpression(const Expr *E, unsigned Arity) {
case Expr::ChooseExprClass:
case Expr::CompoundLiteralExprClass:
case Expr::ExtVectorElementExprClass:
+ case Expr::GenericSelectionExprClass:
case Expr::ObjCEncodeExprClass:
case Expr::ObjCIsaExprClass:
case Expr::ObjCIvarRefExprClass:
@@ -1749,6 +2000,8 @@ void CXXNameMangler::mangleExpression(const Expr *E, unsigned Arity) {
case Expr::StmtExprClass:
case Expr::UnaryTypeTraitExprClass:
case Expr::BinaryTypeTraitExprClass:
+ case Expr::ArrayTypeTraitExprClass:
+ case Expr::ExpressionTraitExprClass:
case Expr::VAArgExprClass:
case Expr::CXXUuidofExprClass:
case Expr::CXXNoexceptExprClass:
@@ -1784,7 +2037,22 @@ void CXXNameMangler::mangleExpression(const Expr *E, unsigned Arity) {
case Expr::CXXMemberCallExprClass: // fallthrough
case Expr::CallExprClass: {
const CallExpr *CE = cast<CallExpr>(E);
- Out << "cl";
+
+ // <expression> ::= cp <simple-id> <expression>* E
+ // We use this mangling only when the call would use ADL except
+ // for being parenthesized. Per discussion with David
+ // Vandervoorde, 2011.04.25.
+ if (isParenthesizedADLCallee(CE)) {
+ Out << "cp";
+ // The callee here is a parenthesized UnresolvedLookupExpr with
+ // no qualifier and should always get mangled as a <simple-id>
+ // anyway.
+
+ // <expression> ::= cl <expression>* E
+ } else {
+ Out << "cl";
+ }
+
mangleExpression(CE->getCallee(), CE->getNumArgs());
for (unsigned I = 0, N = CE->getNumArgs(); I != N; ++I)
mangleExpression(CE->getArg(I));
@@ -1815,7 +2083,7 @@ void CXXNameMangler::mangleExpression(const Expr *E, unsigned Arity) {
case Expr::MemberExprClass: {
const MemberExpr *ME = cast<MemberExpr>(E);
mangleMemberExpr(ME->getBase(), ME->isArrow(),
- ME->getQualifier(), ME->getMemberDecl()->getDeclName(),
+ ME->getQualifier(), 0, ME->getMemberDecl()->getDeclName(),
Arity);
break;
}
@@ -1823,7 +2091,7 @@ void CXXNameMangler::mangleExpression(const Expr *E, unsigned Arity) {
case Expr::UnresolvedMemberExprClass: {
const UnresolvedMemberExpr *ME = cast<UnresolvedMemberExpr>(E);
mangleMemberExpr(ME->getBase(), ME->isArrow(),
- ME->getQualifier(), ME->getMemberName(),
+ ME->getQualifier(), 0, ME->getMemberName(),
Arity);
if (ME->hasExplicitTemplateArgs())
mangleTemplateArgs(ME->getExplicitTemplateArgs());
@@ -1834,19 +2102,16 @@ void CXXNameMangler::mangleExpression(const Expr *E, unsigned Arity) {
const CXXDependentScopeMemberExpr *ME
= cast<CXXDependentScopeMemberExpr>(E);
mangleMemberExpr(ME->getBase(), ME->isArrow(),
- ME->getQualifier(), ME->getMember(),
- Arity);
+ ME->getQualifier(), ME->getFirstQualifierFoundInScope(),
+ ME->getMember(), Arity);
if (ME->hasExplicitTemplateArgs())
mangleTemplateArgs(ME->getExplicitTemplateArgs());
break;
}
case Expr::UnresolvedLookupExprClass: {
- // The ABI doesn't cover how to mangle overload sets, so we mangle
- // using something as close as possible to the original lookup
- // expression.
const UnresolvedLookupExpr *ULE = cast<UnresolvedLookupExpr>(E);
- mangleUnresolvedName(ULE->getQualifier(), ULE->getName(), Arity);
+ mangleUnresolvedName(ULE->getQualifier(), 0, ULE->getName(), Arity);
if (ULE->hasExplicitTemplateArgs())
mangleTemplateArgs(ULE->getExplicitTemplateArgs());
break;
@@ -1877,10 +2142,22 @@ void CXXNameMangler::mangleExpression(const Expr *E, unsigned Arity) {
break;
}
- case Expr::SizeOfAlignOfExprClass: {
- const SizeOfAlignOfExpr *SAE = cast<SizeOfAlignOfExpr>(E);
- if (SAE->isSizeOf()) Out << 's';
- else Out << 'a';
+ case Expr::UnaryExprOrTypeTraitExprClass: {
+ const UnaryExprOrTypeTraitExpr *SAE = cast<UnaryExprOrTypeTraitExpr>(E);
+ switch(SAE->getKind()) {
+ case UETT_SizeOf:
+ Out << 's';
+ break;
+ case UETT_AlignOf:
+ Out << 'a';
+ break;
+ case UETT_VecStep:
+ Diagnostic &Diags = Context.getDiags();
+ unsigned DiagID = Diags.getCustomDiagID(Diagnostic::Error,
+ "cannot yet mangle vec_step expression");
+ Diags.Report(DiagID);
+ return;
+ }
if (SAE->isArgumentType()) {
Out << 't';
mangleType(SAE->getArgumentType());
@@ -1939,7 +2216,7 @@ void CXXNameMangler::mangleExpression(const Expr *E, unsigned Arity) {
case Expr::ArraySubscriptExprClass: {
const ArraySubscriptExpr *AE = cast<ArraySubscriptExpr>(E);
- // Array subscript is treated as a syntactically wierd form of
+ // Array subscript is treated as a syntactically weird form of
// binary operator.
Out << "ix";
mangleExpression(AE->getLHS());
@@ -2009,6 +2286,10 @@ void CXXNameMangler::mangleExpression(const Expr *E, unsigned Arity) {
Out << 'E';
break;
+ case Decl::ParmVar:
+ mangleFunctionParam(cast<ParmVarDecl>(D));
+ break;
+
case Decl::EnumConstant: {
const EnumConstantDecl *ED = cast<EnumConstantDecl>(D);
mangleIntegerLiteral(ED->getType(), ED->getInitVal());
@@ -2165,10 +2446,72 @@ void CXXNameMangler::mangleExpression(const Expr *E, unsigned Arity) {
Diags.Report(DiagID);
return;
}
+ break;
}
}
}
+/// Mangle an expression which refers to a parameter variable.
+///
+/// <expression> ::= <function-param>
+/// <function-param> ::= fp <top-level CV-qualifiers> _ # L == 0, I == 0
+/// <function-param> ::= fp <top-level CV-qualifiers>
+/// <parameter-2 non-negative number> _ # L == 0, I > 0
+/// <function-param> ::= fL <L-1 non-negative number>
+/// p <top-level CV-qualifiers> _ # L > 0, I == 0
+/// <function-param> ::= fL <L-1 non-negative number>
+/// p <top-level CV-qualifiers>
+/// <I-1 non-negative number> _ # L > 0, I > 0
+///
+/// L is the nesting depth of the parameter, defined as 1 if the
+/// parameter comes from the innermost function prototype scope
+/// enclosing the current context, 2 if from the next enclosing
+/// function prototype scope, and so on, with one special case: if
+/// we've processed the full parameter clause for the innermost
+/// function type, then L is one less. This definition conveniently
+/// makes it irrelevant whether a function's result type was written
+/// trailing or leading, but is otherwise overly complicated; the
+/// numbering was first designed without considering references to
+/// parameter in locations other than return types, and then the
+/// mangling had to be generalized without changing the existing
+/// manglings.
+///
+/// I is the zero-based index of the parameter within its parameter
+/// declaration clause. Note that the original ABI document describes
+/// this using 1-based ordinals.
+void CXXNameMangler::mangleFunctionParam(const ParmVarDecl *parm) {
+ unsigned parmDepth = parm->getFunctionScopeDepth();
+ unsigned parmIndex = parm->getFunctionScopeIndex();
+
+ // Compute 'L'.
+ // parmDepth does not include the declaring function prototype.
+ // FunctionTypeDepth does account for that.
+ assert(parmDepth < FunctionTypeDepth.getDepth());
+ unsigned nestingDepth = FunctionTypeDepth.getDepth() - parmDepth;
+ if (FunctionTypeDepth.isInResultType())
+ nestingDepth--;
+
+ if (nestingDepth == 0) {
+ Out << "fp";
+ } else {
+ Out << "fL" << (nestingDepth - 1) << 'p';
+ }
+
+ // Top-level qualifiers. We don't have to worry about arrays here,
+ // because parameters declared as arrays should already have been
+ // tranformed to have pointer type. FIXME: apparently these don't
+ // get mangled if used as an rvalue of a known non-class type?
+ assert(!parm->getType()->isArrayType()
+ && "parameter's type is still an array type?");
+ mangleQualifiers(parm->getType().getQualifiers());
+
+ // Parameter index.
+ if (parmIndex != 0) {
+ Out << (parmIndex - 1);
+ }
+ Out << '_';
+}
+
void CXXNameMangler::mangleCXXCtorType(CXXCtorType T) {
// <ctor-dtor-name> ::= C1 # complete object constructor
// ::= C2 # base object constructor
@@ -2287,8 +2630,7 @@ void CXXNameMangler::mangleTemplateArg(const NamedDecl *P,
// an expression. We compensate for it here to produce the correct mangling.
NamedDecl *D = cast<NamedDecl>(A.getAsDecl());
const NonTypeTemplateParmDecl *Parameter = cast<NonTypeTemplateParmDecl>(P);
- bool compensateMangling = D->isCXXClassMember() &&
- !Parameter->getType()->isReferenceType();
+ bool compensateMangling = !Parameter->getType()->isReferenceType();
if (compensateMangling) {
Out << 'X';
mangleOperatorName(OO_Amp, 1);
@@ -2576,7 +2918,7 @@ void ItaniumMangleContext::mangleName(const NamedDecl *D,
getASTContext().getSourceManager(),
"Mangling declaration");
- CXXNameMangler Mangler(*this, Out);
+ CXXNameMangler Mangler(*this, Out, D);
return Mangler.mangle(D);
}
diff --git a/lib/AST/MicrosoftCXXABI.cpp b/lib/AST/MicrosoftCXXABI.cpp
index 4de93bb4beab..206f6dd0c9eb 100644
--- a/lib/AST/MicrosoftCXXABI.cpp
+++ b/lib/AST/MicrosoftCXXABI.cpp
@@ -7,7 +7,7 @@
//
//===----------------------------------------------------------------------===//
//
-// This provides C++ AST support targetting the Microsoft Visual C++
+// This provides C++ AST support targeting the Microsoft Visual C++
// ABI.
//
//===----------------------------------------------------------------------===//
diff --git a/lib/AST/MicrosoftMangle.cpp b/lib/AST/MicrosoftMangle.cpp
index 4bf7f23a0a9d..5424bebc81b0 100644
--- a/lib/AST/MicrosoftMangle.cpp
+++ b/lib/AST/MicrosoftMangle.cpp
@@ -7,7 +7,7 @@
//
//===----------------------------------------------------------------------===//
//
-// This provides C++ name mangling targetting the Microsoft Visual C++ ABI.
+// This provides C++ name mangling targeting the Microsoft Visual C++ ABI.
//
//===----------------------------------------------------------------------===//
@@ -314,7 +314,7 @@ MicrosoftCXXNameMangler::mangleUnqualifiedName(const NamedDecl *ND,
// We must have an anonymous struct.
const TagDecl *TD = cast<TagDecl>(ND);
- if (const TypedefDecl *D = TD->getTypedefForAnonDecl()) {
+ if (const TypedefNameDecl *D = TD->getTypedefNameForAnonDecl()) {
assert(TD->getDeclContext() == D->getDeclContext() &&
"Typedef should not be in another decl context!");
assert(D->getDeclName().getAsIdentifierInfo() &&
@@ -676,12 +676,6 @@ void MicrosoftCXXNameMangler::mangleType(const BuiltinType *T) {
// ::= M # float
// ::= N # double
// ::= O # long double (__float80 is mangled differently)
- // ::= _D # __int8 (yup, it's a distinct type in MSVC)
- // ::= _E # unsigned __int8
- // ::= _F # __int16
- // ::= _G # unsigned __int16
- // ::= _H # __int32
- // ::= _I # unsigned __int32
// ::= _J # long long, __int64
// ::= _K # unsigned long long, __int64
// ::= _L # __int128
@@ -706,7 +700,6 @@ void MicrosoftCXXNameMangler::mangleType(const BuiltinType *T) {
case BuiltinType::Double: Out << 'N'; break;
// TODO: Determine size and mangle accordingly
case BuiltinType::LongDouble: Out << 'O'; break;
- // TODO: __int8 and friends
case BuiltinType::LongLong: Out << "_J"; break;
case BuiltinType::ULongLong: Out << "_K"; break;
case BuiltinType::Int128: Out << "_L"; break;
@@ -717,6 +710,8 @@ void MicrosoftCXXNameMangler::mangleType(const BuiltinType *T) {
case BuiltinType::Overload:
case BuiltinType::Dependent:
+ case BuiltinType::UnknownAny:
+ case BuiltinType::BoundMember:
assert(false &&
"Overloaded and dependent types shouldn't get to name mangling");
break;
@@ -873,6 +868,8 @@ void MicrosoftCXXNameMangler::mangleCallingConvention(const FunctionType *T,
if (CC == CC_Default)
CC = IsInstMethod ? getASTContext().getDefaultMethodCallConv() : CC_C;
switch (CC) {
+ default:
+ assert(0 && "Unsupported CC for mangling");
case CC_Default:
case CC_C: Out << 'A'; break;
case CC_X86Pascal: Out << 'C'; break;
diff --git a/lib/AST/NestedNameSpecifier.cpp b/lib/AST/NestedNameSpecifier.cpp
index 6f1ec058d74e..2878dff3edc4 100644
--- a/lib/AST/NestedNameSpecifier.cpp
+++ b/lib/AST/NestedNameSpecifier.cpp
@@ -371,3 +371,249 @@ TypeLoc NestedNameSpecifierLoc::getTypeLoc() const {
void *TypeData = LoadPointer(Data, Offset);
return TypeLoc(Qualifier->getAsType(), TypeData);
}
+
+namespace {
+ void Append(char *Start, char *End, char *&Buffer, unsigned &BufferSize,
+ unsigned &BufferCapacity) {
+ if (BufferSize + (End - Start) > BufferCapacity) {
+ // Reallocate the buffer.
+ unsigned NewCapacity
+ = std::max((unsigned)(BufferCapacity? BufferCapacity * 2
+ : sizeof(void*) * 2),
+ (unsigned)(BufferSize + (End - Start)));
+ char *NewBuffer = static_cast<char *>(malloc(NewCapacity));
+ memcpy(NewBuffer, Buffer, BufferSize);
+
+ if (BufferCapacity)
+ free(Buffer);
+ Buffer = NewBuffer;
+ BufferCapacity = NewCapacity;
+ }
+
+ memcpy(Buffer + BufferSize, Start, End - Start);
+ BufferSize += End-Start;
+ }
+
+ /// \brief Save a source location to the given buffer.
+ void SaveSourceLocation(SourceLocation Loc, char *&Buffer,
+ unsigned &BufferSize, unsigned &BufferCapacity) {
+ unsigned Raw = Loc.getRawEncoding();
+ Append(reinterpret_cast<char *>(&Raw),
+ reinterpret_cast<char *>(&Raw) + sizeof(unsigned),
+ Buffer, BufferSize, BufferCapacity);
+ }
+
+ /// \brief Save a pointer to the given buffer.
+ void SavePointer(void *Ptr, char *&Buffer, unsigned &BufferSize,
+ unsigned &BufferCapacity) {
+ Append(reinterpret_cast<char *>(&Ptr),
+ reinterpret_cast<char *>(&Ptr) + sizeof(void *),
+ Buffer, BufferSize, BufferCapacity);
+ }
+}
+
+NestedNameSpecifierLocBuilder::NestedNameSpecifierLocBuilder()
+ : Representation(0), Buffer(0), BufferSize(0), BufferCapacity(0) { }
+
+NestedNameSpecifierLocBuilder::
+NestedNameSpecifierLocBuilder(const NestedNameSpecifierLocBuilder &Other)
+ : Representation(Other.Representation), Buffer(0),
+ BufferSize(0), BufferCapacity(0)
+{
+ if (!Other.Buffer)
+ return;
+
+ if (Other.BufferCapacity == 0) {
+ // Shallow copy is okay.
+ Buffer = Other.Buffer;
+ BufferSize = Other.BufferSize;
+ return;
+ }
+
+ // Deep copy
+ BufferSize = Other.BufferSize;
+ BufferCapacity = Other.BufferSize;
+ Buffer = static_cast<char *>(malloc(BufferCapacity));
+ memcpy(Buffer, Other.Buffer, BufferSize);
+}
+
+NestedNameSpecifierLocBuilder &
+NestedNameSpecifierLocBuilder::
+operator=(const NestedNameSpecifierLocBuilder &Other) {
+ Representation = Other.Representation;
+
+ if (Buffer && Other.Buffer && BufferCapacity >= Other.BufferSize) {
+ // Re-use our storage.
+ BufferSize = Other.BufferSize;
+ memcpy(Buffer, Other.Buffer, BufferSize);
+ return *this;
+ }
+
+ // Free our storage, if we have any.
+ if (BufferCapacity) {
+ free(Buffer);
+ BufferCapacity = 0;
+ }
+
+ if (!Other.Buffer) {
+ // Empty.
+ Buffer = 0;
+ BufferSize = 0;
+ return *this;
+ }
+
+ if (Other.BufferCapacity == 0) {
+ // Shallow copy is okay.
+ Buffer = Other.Buffer;
+ BufferSize = Other.BufferSize;
+ return *this;
+ }
+
+ // Deep copy.
+ BufferSize = Other.BufferSize;
+ BufferCapacity = BufferSize;
+ Buffer = static_cast<char *>(malloc(BufferSize));
+ memcpy(Buffer, Other.Buffer, BufferSize);
+ return *this;
+}
+
+NestedNameSpecifierLocBuilder::~NestedNameSpecifierLocBuilder() {
+ if (BufferCapacity)
+ free(Buffer);
+}
+
+void NestedNameSpecifierLocBuilder::Extend(ASTContext &Context,
+ SourceLocation TemplateKWLoc,
+ TypeLoc TL,
+ SourceLocation ColonColonLoc) {
+ Representation = NestedNameSpecifier::Create(Context, Representation,
+ TemplateKWLoc.isValid(),
+ TL.getTypePtr());
+
+ // Push source-location info into the buffer.
+ SavePointer(TL.getOpaqueData(), Buffer, BufferSize, BufferCapacity);
+ SaveSourceLocation(ColonColonLoc, Buffer, BufferSize, BufferCapacity);
+}
+
+void NestedNameSpecifierLocBuilder::Extend(ASTContext &Context,
+ IdentifierInfo *Identifier,
+ SourceLocation IdentifierLoc,
+ SourceLocation ColonColonLoc) {
+ Representation = NestedNameSpecifier::Create(Context, Representation,
+ Identifier);
+
+ // Push source-location info into the buffer.
+ SaveSourceLocation(IdentifierLoc, Buffer, BufferSize, BufferCapacity);
+ SaveSourceLocation(ColonColonLoc, Buffer, BufferSize, BufferCapacity);
+}
+
+void NestedNameSpecifierLocBuilder::Extend(ASTContext &Context,
+ NamespaceDecl *Namespace,
+ SourceLocation NamespaceLoc,
+ SourceLocation ColonColonLoc) {
+ Representation = NestedNameSpecifier::Create(Context, Representation,
+ Namespace);
+
+ // Push source-location info into the buffer.
+ SaveSourceLocation(NamespaceLoc, Buffer, BufferSize, BufferCapacity);
+ SaveSourceLocation(ColonColonLoc, Buffer, BufferSize, BufferCapacity);
+}
+
+void NestedNameSpecifierLocBuilder::Extend(ASTContext &Context,
+ NamespaceAliasDecl *Alias,
+ SourceLocation AliasLoc,
+ SourceLocation ColonColonLoc) {
+ Representation = NestedNameSpecifier::Create(Context, Representation, Alias);
+
+ // Push source-location info into the buffer.
+ SaveSourceLocation(AliasLoc, Buffer, BufferSize, BufferCapacity);
+ SaveSourceLocation(ColonColonLoc, Buffer, BufferSize, BufferCapacity);
+}
+
+void NestedNameSpecifierLocBuilder::MakeGlobal(ASTContext &Context,
+ SourceLocation ColonColonLoc) {
+ assert(!Representation && "Already have a nested-name-specifier!?");
+ Representation = NestedNameSpecifier::GlobalSpecifier(Context);
+
+ // Push source-location info into the buffer.
+ SaveSourceLocation(ColonColonLoc, Buffer, BufferSize, BufferCapacity);
+}
+
+void NestedNameSpecifierLocBuilder::MakeTrivial(ASTContext &Context,
+ NestedNameSpecifier *Qualifier,
+ SourceRange R) {
+ Representation = Qualifier;
+
+ // Construct bogus (but well-formed) source information for the
+ // nested-name-specifier.
+ BufferSize = 0;
+ llvm::SmallVector<NestedNameSpecifier *, 4> Stack;
+ for (NestedNameSpecifier *NNS = Qualifier; NNS; NNS = NNS->getPrefix())
+ Stack.push_back(NNS);
+ while (!Stack.empty()) {
+ NestedNameSpecifier *NNS = Stack.back();
+ Stack.pop_back();
+ switch (NNS->getKind()) {
+ case NestedNameSpecifier::Identifier:
+ case NestedNameSpecifier::Namespace:
+ case NestedNameSpecifier::NamespaceAlias:
+ SaveSourceLocation(R.getBegin(), Buffer, BufferSize, BufferCapacity);
+ break;
+
+ case NestedNameSpecifier::TypeSpec:
+ case NestedNameSpecifier::TypeSpecWithTemplate: {
+ TypeSourceInfo *TSInfo
+ = Context.getTrivialTypeSourceInfo(QualType(NNS->getAsType(), 0),
+ R.getBegin());
+ SavePointer(TSInfo->getTypeLoc().getOpaqueData(), Buffer, BufferSize,
+ BufferCapacity);
+ break;
+ }
+
+ case NestedNameSpecifier::Global:
+ break;
+ }
+
+ // Save the location of the '::'.
+ SaveSourceLocation(Stack.empty()? R.getEnd() : R.getBegin(),
+ Buffer, BufferSize, BufferCapacity);
+ }
+}
+
+void NestedNameSpecifierLocBuilder::Adopt(NestedNameSpecifierLoc Other) {
+ if (BufferCapacity)
+ free(Buffer);
+
+ if (!Other) {
+ Representation = 0;
+ BufferSize = 0;
+ return;
+ }
+
+ // Rather than copying the data (which is wasteful), "adopt" the
+ // pointer (which points into the ASTContext) but set the capacity to zero to
+ // indicate that we don't own it.
+ Representation = Other.getNestedNameSpecifier();
+ Buffer = static_cast<char *>(Other.getOpaqueData());
+ BufferSize = Other.getDataLength();
+ BufferCapacity = 0;
+}
+
+NestedNameSpecifierLoc
+NestedNameSpecifierLocBuilder::getWithLocInContext(ASTContext &Context) const {
+ if (!Representation)
+ return NestedNameSpecifierLoc();
+
+ // If we adopted our data pointer from elsewhere in the AST context, there's
+ // no need to copy the memory.
+ if (BufferCapacity == 0)
+ return NestedNameSpecifierLoc(Representation, Buffer);
+
+ // FIXME: After copying the source-location information, should we free
+ // our (temporary) buffer and adopt the ASTContext-allocated memory?
+ // Doing so would optimize repeated calls to getWithLocInContext().
+ void *Mem = Context.Allocate(BufferSize, llvm::alignOf<void *>());
+ memcpy(Mem, Buffer, BufferSize);
+ return NestedNameSpecifierLoc(Representation, Mem);
+}
+
diff --git a/lib/AST/RecordLayoutBuilder.cpp b/lib/AST/RecordLayoutBuilder.cpp
index 4ed031f97499..0770e1f15143 100644
--- a/lib/AST/RecordLayoutBuilder.cpp
+++ b/lib/AST/RecordLayoutBuilder.cpp
@@ -19,7 +19,7 @@
#include "llvm/Support/Format.h"
#include "llvm/ADT/SmallSet.h"
#include "llvm/Support/MathExtras.h"
-#include <map>
+#include "llvm/Support/CrashRecoveryContext.h"
using namespace clang;
@@ -564,6 +564,8 @@ protected:
unsigned IsUnion : 1;
unsigned IsMac68kAlign : 1;
+
+ unsigned IsMsStruct : 1;
/// UnfilledBitsInLastByte - If the last field laid out was a bitfield,
/// this contains the number of bits in the last byte that can be used for
@@ -580,6 +582,8 @@ protected:
CharUnits NonVirtualSize;
CharUnits NonVirtualAlignment;
+ CharUnits ZeroLengthBitfieldAlignment;
+
/// PrimaryBase - the primary base class (if one exists) of the class
/// we're laying out.
const CXXRecordDecl *PrimaryBase;
@@ -612,10 +616,12 @@ protected:
*EmptySubobjects)
: Context(Context), EmptySubobjects(EmptySubobjects), Size(0),
Alignment(CharUnits::One()), UnpackedAlignment(Alignment),
- Packed(false), IsUnion(false), IsMac68kAlign(false),
+ Packed(false), IsUnion(false),
+ IsMac68kAlign(false), IsMsStruct(false),
UnfilledBitsInLastByte(0), MaxFieldAlignment(CharUnits::Zero()),
DataSize(0), NonVirtualSize(CharUnits::Zero()),
- NonVirtualAlignment(CharUnits::One()), PrimaryBase(0),
+ NonVirtualAlignment(CharUnits::One()),
+ ZeroLengthBitfieldAlignment(CharUnits::Zero()), PrimaryBase(0),
PrimaryBaseIsVirtual(false), FirstNearlyEmptyVBase(0) { }
void Layout(const RecordDecl *D);
@@ -657,7 +663,7 @@ protected:
void SelectPrimaryVBase(const CXXRecordDecl *RD);
- virtual uint64_t GetVirtualPointersSize(const CXXRecordDecl *RD) const;
+ virtual CharUnits GetVirtualPointersSize(const CXXRecordDecl *RD) const;
/// LayoutNonVirtualBases - Determines the primary base class (if any) and
/// lays it out. Will then proceed to lay out all non-virtual base clasess.
@@ -757,9 +763,9 @@ RecordLayoutBuilder::SelectPrimaryVBase(const CXXRecordDecl *RD) {
}
}
-uint64_t
+CharUnits
RecordLayoutBuilder::GetVirtualPointersSize(const CXXRecordDecl *RD) const {
- return Context.Target.getPointerWidth(0);
+ return Context.toCharUnitsFromBits(Context.Target.getPointerWidth(0));
}
/// DeterminePrimaryBase - Determine the primary base of the given class.
@@ -815,8 +821,8 @@ void RecordLayoutBuilder::DeterminePrimaryBase(const CXXRecordDecl *RD) {
assert(DataSize == 0 && "Vtable pointer must be at offset zero!");
// Update the size.
- setSize(getSizeInBits() + GetVirtualPointersSize(RD));
- setDataSize(getSizeInBits());
+ setSize(getSize() + GetVirtualPointersSize(RD));
+ setDataSize(getSize());
CharUnits UnpackedBaseAlign =
Context.toCharUnitsFromBits(Context.Target.getPointerAlign(0));
@@ -1108,8 +1114,7 @@ CharUnits RecordLayoutBuilder::LayoutBase(const BaseSubobjectInfo *Base) {
// If we have an empty base class, try to place it at offset 0.
if (Base->Class->isEmpty() &&
EmptySubobjects->CanPlaceBaseAtOffset(Base, CharUnits::Zero())) {
- uint64_t RecordSizeInBits = Context.toBits(Layout.getSize());
- setSize(std::max(getSizeInBits(), RecordSizeInBits));
+ setSize(std::max(getSize(), Layout.getSize()));
return CharUnits::Zero();
}
@@ -1124,27 +1129,24 @@ CharUnits RecordLayoutBuilder::LayoutBase(const BaseSubobjectInfo *Base) {
}
// Round up the current record size to the base's alignment boundary.
- uint64_t Offset =
- llvm::RoundUpToAlignment(getDataSizeInBits(), Context.toBits(BaseAlign));
+ CharUnits Offset = getDataSize().RoundUpToAlignment(BaseAlign);
// Try to place the base.
- while (!EmptySubobjects->CanPlaceBaseAtOffset(Base,
- Context.toCharUnitsFromBits(Offset)))
- Offset += Context.toBits(BaseAlign);
+ while (!EmptySubobjects->CanPlaceBaseAtOffset(Base, Offset))
+ Offset += BaseAlign;
if (!Base->Class->isEmpty()) {
// Update the data size.
- setDataSize(Offset + Context.toBits(Layout.getNonVirtualSize()));
+ setDataSize(Offset + Layout.getNonVirtualSize());
- setSize(std::max(getSizeInBits(), getDataSizeInBits()));
+ setSize(std::max(getSize(), getDataSize()));
} else
- setSize(std::max(getSizeInBits(),
- Offset + Context.toBits(Layout.getSize())));
+ setSize(std::max(getSize(), Offset + Layout.getSize()));
// Remember max struct/class alignment.
UpdateAlignment(BaseAlign, UnpackedBaseAlign);
- return Context.toCharUnitsFromBits(Offset);
+ return Offset;
}
void RecordLayoutBuilder::InitializeLayout(const Decl *D) {
@@ -1152,6 +1154,8 @@ void RecordLayoutBuilder::InitializeLayout(const Decl *D) {
IsUnion = RD->isUnion();
Packed = D->hasAttr<PackedAttr>();
+
+ IsMsStruct = D->hasAttr<MsStructAttr>();
// mac68k alignment supersedes maximum field alignment and attribute aligned,
// and forces all structures to have 2-byte alignment. The IBM docs on it
@@ -1187,8 +1191,9 @@ void RecordLayoutBuilder::Layout(const CXXRecordDecl *RD) {
LayoutFields(RD);
- // FIXME: Size isn't always an exact multiple of the char width. Round up?
- NonVirtualSize = Context.toCharUnitsFromBits(getSizeInBits());
+ NonVirtualSize = Context.toCharUnitsFromBits(
+ llvm::RoundUpToAlignment(getSizeInBits(),
+ Context.Target.getCharAlign()));
NonVirtualAlignment = Alignment;
// Lay out the virtual bases and add the primary virtual base offsets.
@@ -1233,7 +1238,7 @@ void RecordLayoutBuilder::Layout(const ObjCInterfaceDecl *D) {
// We start laying out ivars not at the end of the superclass
// structure, but at the next byte following the last field.
setSize(SL.getDataSize());
- setDataSize(getSizeInBits());
+ setDataSize(getSize());
}
InitializeLayout(D);
@@ -1252,9 +1257,28 @@ void RecordLayoutBuilder::Layout(const ObjCInterfaceDecl *D) {
void RecordLayoutBuilder::LayoutFields(const RecordDecl *D) {
// Layout each field, for now, just sequentially, respecting alignment. In
// the future, this will need to be tweakable by targets.
+ const FieldDecl *LastFD = 0;
for (RecordDecl::field_iterator Field = D->field_begin(),
- FieldEnd = D->field_end(); Field != FieldEnd; ++Field)
+ FieldEnd = D->field_end(); Field != FieldEnd; ++Field) {
+ if (IsMsStruct) {
+ const FieldDecl *FD = (*Field);
+ if (Context.ZeroBitfieldFollowsBitfield(FD, LastFD)) {
+ // FIXME. Multiple zero bitfields may follow a bitfield.
+ // set ZeroLengthBitfieldAlignment to max. of its
+ // currrent and alignment of 'FD'.
+ std::pair<CharUnits, CharUnits> FieldInfo =
+ Context.getTypeInfoInChars(FD->getType());
+ ZeroLengthBitfieldAlignment = FieldInfo.second;
+ continue;
+ }
+ // Zero-length bitfields following non-bitfield members are
+ // ignored:
+ if (Context.ZeroBitfieldFollowsNonBitfield(FD, LastFD))
+ continue;
+ LastFD = FD;
+ }
LayoutField(*Field);
+ }
}
void RecordLayoutBuilder::LayoutWideBitField(uint64_t FieldSize,
@@ -1285,7 +1309,7 @@ void RecordLayoutBuilder::LayoutWideBitField(uint64_t FieldSize,
}
assert(!Type.isNull() && "Did not find a type!");
- unsigned TypeAlign = Context.getTypeAlign(Type);
+ CharUnits TypeAlign = Context.getTypeAlignInChars(Type);
// We're not going to use any of the unfilled bits in the last byte.
UnfilledBitsInLastByte = 0;
@@ -1299,11 +1323,13 @@ void RecordLayoutBuilder::LayoutWideBitField(uint64_t FieldSize,
} else {
// The bitfield is allocated starting at the next offset aligned appropriately
// for T', with length n bits.
- FieldOffset = llvm::RoundUpToAlignment(getDataSizeInBits(), TypeAlign);
+ FieldOffset = llvm::RoundUpToAlignment(getDataSizeInBits(),
+ Context.toBits(TypeAlign));
uint64_t NewSizeInBits = FieldOffset + FieldSize;
- setDataSize(llvm::RoundUpToAlignment(NewSizeInBits, 8));
+ setDataSize(llvm::RoundUpToAlignment(NewSizeInBits,
+ Context.Target.getCharAlign()));
UnfilledBitsInLastByte = getDataSizeInBits() - NewSizeInBits;
}
@@ -1311,13 +1337,13 @@ void RecordLayoutBuilder::LayoutWideBitField(uint64_t FieldSize,
FieldOffsets.push_back(FieldOffset);
CheckFieldPadding(FieldOffset, UnpaddedFieldOffset, FieldOffset,
- TypeAlign, FieldPacked, D);
+ Context.toBits(TypeAlign), FieldPacked, D);
// Update the size.
setSize(std::max(getSizeInBits(), getDataSizeInBits()));
// Remember max struct/class alignment.
- UpdateAlignment(Context.toCharUnitsFromBits(TypeAlign));
+ UpdateAlignment(TypeAlign);
}
void RecordLayoutBuilder::LayoutBitField(const FieldDecl *D) {
@@ -1380,7 +1406,8 @@ void RecordLayoutBuilder::LayoutBitField(const FieldDecl *D) {
} else {
uint64_t NewSizeInBits = FieldOffset + FieldSize;
- setDataSize(llvm::RoundUpToAlignment(NewSizeInBits, 8));
+ setDataSize(llvm::RoundUpToAlignment(NewSizeInBits,
+ Context.Target.getCharAlign()));
UnfilledBitsInLastByte = getDataSizeInBits() - NewSizeInBits;
}
@@ -1428,6 +1455,9 @@ void RecordLayoutBuilder::LayoutField(const FieldDecl *D) {
Context.getTypeInfoInChars(D->getType());
FieldSize = FieldInfo.first;
FieldAlign = FieldInfo.second;
+ if (ZeroLengthBitfieldAlignment > FieldAlign)
+ FieldAlign = ZeroLengthBitfieldAlignment;
+ ZeroLengthBitfieldAlignment = CharUnits::Zero();
if (Context.getLangOptions().MSBitfields) {
// If MS bitfield layout is required, figure out what type is being
@@ -1487,7 +1517,7 @@ void RecordLayoutBuilder::LayoutField(const FieldDecl *D) {
if (IsUnion)
setSize(std::max(getSizeInBits(), FieldSizeInBits));
else
- setSize(Context.toBits(FieldOffset) + FieldSizeInBits);
+ setSize(FieldOffset + FieldSize);
// Update the data size.
setDataSize(getSizeInBits());
@@ -1504,17 +1534,18 @@ void RecordLayoutBuilder::FinishLayout(const NamedDecl *D) {
// which is not empty but of size 0; such as having fields of
// array of zero-length, remains of Size 0
if (RD->isEmpty())
- setSize(8);
+ setSize(CharUnits::One());
}
else
- setSize(8);
+ setSize(CharUnits::One());
}
// Finally, round the size of the record up to the alignment of the
// record itself.
uint64_t UnpaddedSize = getSizeInBits() - UnfilledBitsInLastByte;
- uint64_t UnpackedSize =
+ uint64_t UnpackedSizeInBits =
llvm::RoundUpToAlignment(getSizeInBits(),
Context.toBits(UnpackedAlignment));
+ CharUnits UnpackedSize = Context.toCharUnitsFromBits(UnpackedSizeInBits);
setSize(llvm::RoundUpToAlignment(getSizeInBits(), Context.toBits(Alignment)));
unsigned CharBitNum = Context.Target.getCharWidth();
@@ -1536,7 +1567,7 @@ void RecordLayoutBuilder::FinishLayout(const NamedDecl *D) {
// Warn if we packed it unnecessarily. If the alignment is 1 byte don't
// bother since there won't be alignment issues.
if (Packed && UnpackedAlignment > CharUnits::One() &&
- getSizeInBits() == UnpackedSize)
+ getSize() == UnpackedSize)
Diag(D->getLocation(), diag::warn_unnecessary_packed)
<< Context.getTypeDeclType(RD);
}
@@ -1664,17 +1695,19 @@ namespace {
EmptySubobjectMap *EmptySubobjects) :
RecordLayoutBuilder(Ctx, EmptySubobjects) {}
- virtual uint64_t GetVirtualPointersSize(const CXXRecordDecl *RD) const;
+ virtual CharUnits GetVirtualPointersSize(const CXXRecordDecl *RD) const;
};
}
-uint64_t
+CharUnits
MSRecordLayoutBuilder::GetVirtualPointersSize(const CXXRecordDecl *RD) const {
// We should reserve space for two pointers if the class has both
// virtual functions and virtual bases.
+ CharUnits PointerWidth =
+ Context.toCharUnitsFromBits(Context.Target.getPointerWidth(0));
if (RD->isPolymorphic() && RD->getNumVBases() > 0)
- return 2 * Context.Target.getPointerWidth(0);
- return Context.Target.getPointerWidth(0);
+ return 2 * PointerWidth;
+ return PointerWidth;
}
/// getASTRecordLayout - Get or compute information about the layout of the
@@ -1705,6 +1738,10 @@ ASTContext::getASTRecordLayout(const RecordDecl *D) const {
case CXXABI_Microsoft:
Builder.reset(new MSRecordLayoutBuilder(*this, &EmptySubobjects));
}
+ // Recover resources if we crash before exiting this method.
+ llvm::CrashRecoveryContextCleanupRegistrar<RecordLayoutBuilder>
+ RecordBuilderCleanup(Builder.get());
+
Builder->Layout(RD);
// FIXME: This is not always correct. See the part about bitfields at
@@ -1713,17 +1750,15 @@ ASTContext::getASTRecordLayout(const RecordDecl *D) const {
bool IsPODForThePurposeOfLayout = cast<CXXRecordDecl>(D)->isPOD();
// FIXME: This should be done in FinalizeLayout.
- uint64_t DataSize =
- IsPODForThePurposeOfLayout ? Builder->Size : Builder->DataSize;
- CharUnits NonVirtualSize =
- IsPODForThePurposeOfLayout ?
- toCharUnitsFromBits(DataSize) : Builder->NonVirtualSize;
+ CharUnits DataSize =
+ IsPODForThePurposeOfLayout ? Builder->getSize() : Builder->getDataSize();
+ CharUnits NonVirtualSize =
+ IsPODForThePurposeOfLayout ? DataSize : Builder->NonVirtualSize;
- CharUnits RecordSize = toCharUnitsFromBits(Builder->Size);
NewEntry =
- new (*this) ASTRecordLayout(*this, RecordSize,
+ new (*this) ASTRecordLayout(*this, Builder->getSize(),
Builder->Alignment,
- toCharUnitsFromBits(DataSize),
+ DataSize,
Builder->FieldOffsets.data(),
Builder->FieldOffsets.size(),
NonVirtualSize,
@@ -1736,12 +1771,10 @@ ASTContext::getASTRecordLayout(const RecordDecl *D) const {
RecordLayoutBuilder Builder(*this, /*EmptySubobjects=*/0);
Builder.Layout(D);
- CharUnits RecordSize = toCharUnitsFromBits(Builder.Size);
-
NewEntry =
- new (*this) ASTRecordLayout(*this, RecordSize,
+ new (*this) ASTRecordLayout(*this, Builder.getSize(),
Builder.Alignment,
- toCharUnitsFromBits(Builder.Size),
+ Builder.getSize(),
Builder.FieldOffsets.data(),
Builder.FieldOffsets.size());
}
@@ -1797,12 +1830,10 @@ ASTContext::getObjCLayout(const ObjCInterfaceDecl *D,
RecordLayoutBuilder Builder(*this, /*EmptySubobjects=*/0);
Builder.Layout(D);
- CharUnits RecordSize = toCharUnitsFromBits(Builder.Size);
-
const ASTRecordLayout *NewEntry =
- new (*this) ASTRecordLayout(*this, RecordSize,
+ new (*this) ASTRecordLayout(*this, Builder.getSize(),
Builder.Alignment,
- toCharUnitsFromBits(Builder.DataSize),
+ Builder.getDataSize(),
Builder.FieldOffsets.data(),
Builder.FieldOffsets.size());
diff --git a/lib/AST/Stmt.cpp b/lib/AST/Stmt.cpp
index 8a80275aa165..380ad94ca224 100644
--- a/lib/AST/Stmt.cpp
+++ b/lib/AST/Stmt.cpp
@@ -540,6 +540,40 @@ CXXTryStmt::CXXTryStmt(SourceLocation tryLoc, Stmt *tryBlock,
std::copy(handlers, handlers + NumHandlers, Stmts + 1);
}
+CXXForRangeStmt::CXXForRangeStmt(DeclStmt *Range, DeclStmt *BeginEndStmt,
+ Expr *Cond, Expr *Inc, DeclStmt *LoopVar,
+ Stmt *Body, SourceLocation FL,
+ SourceLocation CL, SourceLocation RPL)
+ : Stmt(CXXForRangeStmtClass), ForLoc(FL), ColonLoc(CL), RParenLoc(RPL) {
+ SubExprs[RANGE] = Range;
+ SubExprs[BEGINEND] = BeginEndStmt;
+ SubExprs[COND] = reinterpret_cast<Stmt*>(Cond);
+ SubExprs[INC] = reinterpret_cast<Stmt*>(Inc);
+ SubExprs[LOOPVAR] = LoopVar;
+ SubExprs[BODY] = Body;
+}
+
+Expr *CXXForRangeStmt::getRangeInit() {
+ DeclStmt *RangeStmt = getRangeStmt();
+ VarDecl *RangeDecl = dyn_cast_or_null<VarDecl>(RangeStmt->getSingleDecl());
+ assert(RangeDecl &&& "for-range should have a single var decl");
+ return RangeDecl->getInit();
+}
+
+const Expr *CXXForRangeStmt::getRangeInit() const {
+ return const_cast<CXXForRangeStmt*>(this)->getRangeInit();
+}
+
+VarDecl *CXXForRangeStmt::getLoopVariable() {
+ Decl *LV = cast<DeclStmt>(getLoopVarStmt())->getSingleDecl();
+ assert(LV && "No loop variable in CXXForRangeStmt");
+ return cast<VarDecl>(LV);
+}
+
+const VarDecl *CXXForRangeStmt::getLoopVariable() const {
+ return const_cast<CXXForRangeStmt*>(this)->getLoopVariable();
+}
+
IfStmt::IfStmt(ASTContext &C, SourceLocation IL, VarDecl *var, Expr *cond,
Stmt *then, SourceLocation EL, Stmt *elsev)
: Stmt(IfStmtClass), IfLoc(IL), ElseLoc(EL)
@@ -628,14 +662,14 @@ void SwitchStmt::setConditionVariable(ASTContext &C, VarDecl *V) {
}
Stmt *SwitchCase::getSubStmt() {
- if (isa<CaseStmt>(this)) return cast<CaseStmt>(this)->getSubStmt();
+ if (isa<CaseStmt>(this))
+ return cast<CaseStmt>(this)->getSubStmt();
return cast<DefaultStmt>(this)->getSubStmt();
}
WhileStmt::WhileStmt(ASTContext &C, VarDecl *Var, Expr *cond, Stmt *body,
SourceLocation WL)
-: Stmt(WhileStmtClass)
-{
+ : Stmt(WhileStmtClass) {
setConditionVariable(C, Var);
SubExprs[COND] = reinterpret_cast<Stmt*>(cond);
SubExprs[BODY] = body;
@@ -676,3 +710,61 @@ const Expr* ReturnStmt::getRetValue() const {
Expr* ReturnStmt::getRetValue() {
return cast_or_null<Expr>(RetExpr);
}
+
+SEHTryStmt::SEHTryStmt(bool IsCXXTry,
+ SourceLocation TryLoc,
+ Stmt *TryBlock,
+ Stmt *Handler)
+ : Stmt(SEHTryStmtClass),
+ IsCXXTry(IsCXXTry),
+ TryLoc(TryLoc)
+{
+ Children[TRY] = TryBlock;
+ Children[HANDLER] = Handler;
+}
+
+SEHTryStmt* SEHTryStmt::Create(ASTContext &C,
+ bool IsCXXTry,
+ SourceLocation TryLoc,
+ Stmt *TryBlock,
+ Stmt *Handler) {
+ return new(C) SEHTryStmt(IsCXXTry,TryLoc,TryBlock,Handler);
+}
+
+SEHExceptStmt* SEHTryStmt::getExceptHandler() const {
+ return dyn_cast<SEHExceptStmt>(getHandler());
+}
+
+SEHFinallyStmt* SEHTryStmt::getFinallyHandler() const {
+ return dyn_cast<SEHFinallyStmt>(getHandler());
+}
+
+SEHExceptStmt::SEHExceptStmt(SourceLocation Loc,
+ Expr *FilterExpr,
+ Stmt *Block)
+ : Stmt(SEHExceptStmtClass),
+ Loc(Loc)
+{
+ Children[FILTER_EXPR] = reinterpret_cast<Stmt*>(FilterExpr);
+ Children[BLOCK] = Block;
+}
+
+SEHExceptStmt* SEHExceptStmt::Create(ASTContext &C,
+ SourceLocation Loc,
+ Expr *FilterExpr,
+ Stmt *Block) {
+ return new(C) SEHExceptStmt(Loc,FilterExpr,Block);
+}
+
+SEHFinallyStmt::SEHFinallyStmt(SourceLocation Loc,
+ Stmt *Block)
+ : Stmt(SEHFinallyStmtClass),
+ Loc(Loc),
+ Block(Block)
+{}
+
+SEHFinallyStmt* SEHFinallyStmt::Create(ASTContext &C,
+ SourceLocation Loc,
+ Stmt *Block) {
+ return new(C)SEHFinallyStmt(Loc,Block);
+}
diff --git a/lib/AST/StmtDumper.cpp b/lib/AST/StmtDumper.cpp
index 5c7dbb3ed990..fb024f33ab30 100644
--- a/lib/AST/StmtDumper.cpp
+++ b/lib/AST/StmtDumper.cpp
@@ -141,7 +141,7 @@ namespace {
void VisitFloatingLiteral(FloatingLiteral *Node);
void VisitStringLiteral(StringLiteral *Str);
void VisitUnaryOperator(UnaryOperator *Node);
- void VisitSizeOfAlignOfExpr(SizeOfAlignOfExpr *Node);
+ void VisitUnaryExprOrTypeTraitExpr(UnaryExprOrTypeTraitExpr *Node);
void VisitMemberExpr(MemberExpr *Node);
void VisitExtVectorElementExpr(ExtVectorElementExpr *Node);
void VisitBinaryOperator(BinaryOperator *Node);
@@ -236,6 +236,9 @@ void StmtDumper::DumpDeclarator(Decl *D) {
if (TypedefDecl *localType = dyn_cast<TypedefDecl>(D)) {
OS << "\"typedef " << localType->getUnderlyingType().getAsString()
<< ' ' << localType << '"';
+ } else if (TypeAliasDecl *localType = dyn_cast<TypeAliasDecl>(D)) {
+ OS << "\"using " << localType << " = "
+ << localType->getUnderlyingType().getAsString() << '"';
} else if (ValueDecl *VD = dyn_cast<ValueDecl>(D)) {
OS << "\"";
// Emit storage class for vardecls.
@@ -284,6 +287,12 @@ void StmtDumper::DumpDeclarator(Decl *D) {
OS << ";\"";
} else if (LabelDecl *LD = dyn_cast<LabelDecl>(D)) {
OS << "label " << LD->getNameAsString();
+ } else if (StaticAssertDecl *SAD = dyn_cast<StaticAssertDecl>(D)) {
+ OS << "\"static_assert(\n";
+ DumpSubTree(SAD->getAssertExpr());
+ OS << ",\n";
+ DumpSubTree(SAD->getMessage());
+ OS << ");\"";
} else {
assert(0 && "Unexpected decl");
}
@@ -360,6 +369,11 @@ void StmtDumper::VisitDeclRefExpr(DeclRefExpr *Node) {
OS << " ";
DumpDeclRef(Node->getDecl());
+ if (Node->getDecl() != Node->getFoundDecl()) {
+ OS << " (";
+ DumpDeclRef(Node->getFoundDecl());
+ OS << ")";
+ }
}
void StmtDumper::DumpDeclRef(Decl *d) {
@@ -441,9 +455,19 @@ void StmtDumper::VisitUnaryOperator(UnaryOperator *Node) {
OS << " " << (Node->isPostfix() ? "postfix" : "prefix")
<< " '" << UnaryOperator::getOpcodeStr(Node->getOpcode()) << "'";
}
-void StmtDumper::VisitSizeOfAlignOfExpr(SizeOfAlignOfExpr *Node) {
+void StmtDumper::VisitUnaryExprOrTypeTraitExpr(UnaryExprOrTypeTraitExpr *Node) {
DumpExpr(Node);
- OS << " " << (Node->isSizeOf() ? "sizeof" : "alignof") << " ";
+ switch(Node->getKind()) {
+ case UETT_SizeOf:
+ OS << " sizeof ";
+ break;
+ case UETT_AlignOf:
+ OS << " __alignof ";
+ break;
+ case UETT_VecStep:
+ OS << " vec_step ";
+ break;
+ }
if (Node->isArgumentType())
DumpType(Node->getArgumentType());
}
diff --git a/lib/AST/StmtIterator.cpp b/lib/AST/StmtIterator.cpp
index 9a7265a043f2..9bf4aeaae83e 100644
--- a/lib/AST/StmtIterator.cpp
+++ b/lib/AST/StmtIterator.cpp
@@ -98,7 +98,7 @@ bool StmtIteratorBase::HandleDecl(Decl* D) {
if (VD->getInit())
return true;
}
- else if (TypedefDecl* TD = dyn_cast<TypedefDecl>(D)) {
+ else if (TypedefNameDecl* TD = dyn_cast<TypedefNameDecl>(D)) {
if (const VariableArrayType* VAPtr =
FindVA(TD->getUnderlyingType().getTypePtr())) {
setVAPtr(VAPtr);
diff --git a/lib/AST/StmtPrinter.cpp b/lib/AST/StmtPrinter.cpp
index 1cdd22088141..0d13502e8d58 100644
--- a/lib/AST/StmtPrinter.cpp
+++ b/lib/AST/StmtPrinter.cpp
@@ -66,6 +66,8 @@ namespace {
void PrintRawIfStmt(IfStmt *If);
void PrintRawCXXCatchStmt(CXXCatchStmt *Catch);
void PrintCallArgs(CallExpr *E);
+ void PrintRawSEHExceptHandler(SEHExceptStmt *S);
+ void PrintRawSEHFinallyStmt(SEHFinallyStmt *S);
void PrintExpr(Expr *E) {
if (E)
@@ -291,6 +293,18 @@ void StmtPrinter::VisitObjCForCollectionStmt(ObjCForCollectionStmt *Node) {
}
}
+void StmtPrinter::VisitCXXForRangeStmt(CXXForRangeStmt *Node) {
+ Indent() << "for (";
+ PrintingPolicy SubPolicy(Policy);
+ SubPolicy.SuppressInitializers = true;
+ Node->getLoopVariable()->print(OS, SubPolicy, IndentLevel);
+ OS << " : ";
+ PrintExpr(Node->getRangeInit());
+ OS << ") {\n";
+ PrintStmt(Node->getBody());
+ Indent() << "}\n";
+}
+
void StmtPrinter::VisitGotoStmt(GotoStmt *Node) {
Indent() << "goto " << Node->getLabel()->getName() << ";\n";
}
@@ -461,6 +475,46 @@ void StmtPrinter::VisitCXXTryStmt(CXXTryStmt *Node) {
OS << "\n";
}
+void StmtPrinter::VisitSEHTryStmt(SEHTryStmt *Node) {
+ Indent() << (Node->getIsCXXTry() ? "try " : "__try ");
+ PrintRawCompoundStmt(Node->getTryBlock());
+ SEHExceptStmt *E = Node->getExceptHandler();
+ SEHFinallyStmt *F = Node->getFinallyHandler();
+ if(E)
+ PrintRawSEHExceptHandler(E);
+ else {
+ assert(F && "Must have a finally block...");
+ PrintRawSEHFinallyStmt(F);
+ }
+ OS << "\n";
+}
+
+void StmtPrinter::PrintRawSEHFinallyStmt(SEHFinallyStmt *Node) {
+ OS << "__finally ";
+ PrintRawCompoundStmt(Node->getBlock());
+ OS << "\n";
+}
+
+void StmtPrinter::PrintRawSEHExceptHandler(SEHExceptStmt *Node) {
+ OS << "__except (";
+ VisitExpr(Node->getFilterExpr());
+ OS << ")\n";
+ PrintRawCompoundStmt(Node->getBlock());
+ OS << "\n";
+}
+
+void StmtPrinter::VisitSEHExceptStmt(SEHExceptStmt *Node) {
+ Indent();
+ PrintRawSEHExceptHandler(Node);
+ OS << "\n";
+}
+
+void StmtPrinter::VisitSEHFinallyStmt(SEHFinallyStmt *Node) {
+ Indent();
+ PrintRawSEHFinallyStmt(Node);
+ OS << "\n";
+}
+
//===----------------------------------------------------------------------===//
// Expr printing methods.
//===----------------------------------------------------------------------===//
@@ -706,8 +760,18 @@ void StmtPrinter::VisitOffsetOfExpr(OffsetOfExpr *Node) {
OS << ")";
}
-void StmtPrinter::VisitSizeOfAlignOfExpr(SizeOfAlignOfExpr *Node) {
- OS << (Node->isSizeOf() ? "sizeof" : "__alignof");
+void StmtPrinter::VisitUnaryExprOrTypeTraitExpr(UnaryExprOrTypeTraitExpr *Node){
+ switch(Node->getKind()) {
+ case UETT_SizeOf:
+ OS << "sizeof";
+ break;
+ case UETT_AlignOf:
+ OS << "__alignof";
+ break;
+ case UETT_VecStep:
+ OS << "vec_step";
+ break;
+ }
if (Node->isArgumentType())
OS << "(" << Node->getArgumentType().getAsString(Policy) << ")";
else {
@@ -715,6 +779,23 @@ void StmtPrinter::VisitSizeOfAlignOfExpr(SizeOfAlignOfExpr *Node) {
PrintExpr(Node->getArgumentExpr());
}
}
+
+void StmtPrinter::VisitGenericSelectionExpr(GenericSelectionExpr *Node) {
+ OS << "_Generic(";
+ PrintExpr(Node->getControllingExpr());
+ for (unsigned i = 0; i != Node->getNumAssocs(); ++i) {
+ OS << ", ";
+ QualType T = Node->getAssocType(i);
+ if (T.isNull())
+ OS << "default";
+ else
+ OS << T.getAsString(Policy);
+ OS << ": ";
+ PrintExpr(Node->getAssocExpr(i));
+ }
+ OS << ")";
+}
+
void StmtPrinter::VisitArraySubscriptExpr(ArraySubscriptExpr *Node) {
PrintExpr(Node->getLHS());
OS << "[";
@@ -1212,33 +1293,75 @@ void StmtPrinter::VisitUnresolvedMemberExpr(UnresolvedMemberExpr *Node) {
static const char *getTypeTraitName(UnaryTypeTrait UTT) {
switch (UTT) {
- default: llvm_unreachable("Unknown unary type trait");
case UTT_HasNothrowAssign: return "__has_nothrow_assign";
- case UTT_HasNothrowCopy: return "__has_nothrow_copy";
case UTT_HasNothrowConstructor: return "__has_nothrow_constructor";
+ case UTT_HasNothrowCopy: return "__has_nothrow_copy";
case UTT_HasTrivialAssign: return "__has_trivial_assign";
- case UTT_HasTrivialCopy: return "__has_trivial_copy";
case UTT_HasTrivialConstructor: return "__has_trivial_constructor";
+ case UTT_HasTrivialCopy: return "__has_trivial_copy";
case UTT_HasTrivialDestructor: return "__has_trivial_destructor";
case UTT_HasVirtualDestructor: return "__has_virtual_destructor";
case UTT_IsAbstract: return "__is_abstract";
+ case UTT_IsArithmetic: return "__is_arithmetic";
+ case UTT_IsArray: return "__is_array";
case UTT_IsClass: return "__is_class";
+ case UTT_IsCompleteType: return "__is_complete_type";
+ case UTT_IsCompound: return "__is_compound";
+ case UTT_IsConst: return "__is_const";
case UTT_IsEmpty: return "__is_empty";
case UTT_IsEnum: return "__is_enum";
+ case UTT_IsFloatingPoint: return "__is_floating_point";
+ case UTT_IsFunction: return "__is_function";
+ case UTT_IsFundamental: return "__is_fundamental";
+ case UTT_IsIntegral: return "__is_integral";
+ case UTT_IsLiteral: return "__is_literal";
+ case UTT_IsLvalueReference: return "__is_lvalue_reference";
+ case UTT_IsMemberFunctionPointer: return "__is_member_function_pointer";
+ case UTT_IsMemberObjectPointer: return "__is_member_object_pointer";
+ case UTT_IsMemberPointer: return "__is_member_pointer";
+ case UTT_IsObject: return "__is_object";
case UTT_IsPOD: return "__is_pod";
+ case UTT_IsPointer: return "__is_pointer";
case UTT_IsPolymorphic: return "__is_polymorphic";
+ case UTT_IsReference: return "__is_reference";
+ case UTT_IsRvalueReference: return "__is_rvalue_reference";
+ case UTT_IsScalar: return "__is_scalar";
+ case UTT_IsSigned: return "__is_signed";
+ case UTT_IsStandardLayout: return "__is_standard_layout";
+ case UTT_IsTrivial: return "__is_trivial";
case UTT_IsUnion: return "__is_union";
+ case UTT_IsUnsigned: return "__is_unsigned";
+ case UTT_IsVoid: return "__is_void";
+ case UTT_IsVolatile: return "__is_volatile";
}
- return "";
+ llvm_unreachable("Type trait not covered by switch statement");
}
static const char *getTypeTraitName(BinaryTypeTrait BTT) {
switch (BTT) {
case BTT_IsBaseOf: return "__is_base_of";
+ case BTT_IsConvertible: return "__is_convertible";
+ case BTT_IsSame: return "__is_same";
case BTT_TypeCompatible: return "__builtin_types_compatible_p";
case BTT_IsConvertibleTo: return "__is_convertible_to";
}
- return "";
+ llvm_unreachable("Binary type trait not covered by switch");
+}
+
+static const char *getTypeTraitName(ArrayTypeTrait ATT) {
+ switch (ATT) {
+ case ATT_ArrayRank: return "__array_rank";
+ case ATT_ArrayExtent: return "__array_extent";
+ }
+ llvm_unreachable("Array type trait not covered by switch");
+}
+
+static const char *getExpressionTraitName(ExpressionTrait ET) {
+ switch (ET) {
+ case ET_IsLValueExpr: return "__is_lvalue_expr";
+ case ET_IsRValueExpr: return "__is_rvalue_expr";
+ }
+ llvm_unreachable("Expression type trait not covered by switch");
}
void StmtPrinter::VisitUnaryTypeTraitExpr(UnaryTypeTraitExpr *E) {
@@ -1252,6 +1375,17 @@ void StmtPrinter::VisitBinaryTypeTraitExpr(BinaryTypeTraitExpr *E) {
<< E->getRhsType().getAsString(Policy) << ")";
}
+void StmtPrinter::VisitArrayTypeTraitExpr(ArrayTypeTraitExpr *E) {
+ OS << getTypeTraitName(E->getTrait()) << "("
+ << E->getQueriedType().getAsString(Policy) << ")";
+}
+
+void StmtPrinter::VisitExpressionTraitExpr(ExpressionTraitExpr *E) {
+ OS << getExpressionTraitName(E->getTrait()) << "(";
+ PrintExpr(E->getQueriedExpression());
+ OS << ")";
+}
+
void StmtPrinter::VisitCXXNoexceptExpr(CXXNoexceptExpr *E) {
OS << "noexcept(";
PrintExpr(E->getOperand());
diff --git a/lib/AST/StmtProfile.cpp b/lib/AST/StmtProfile.cpp
index b54001167b42..44818e8c0847 100644
--- a/lib/AST/StmtProfile.cpp
+++ b/lib/AST/StmtProfile.cpp
@@ -177,6 +177,22 @@ void StmtProfiler::VisitCXXTryStmt(CXXTryStmt *S) {
VisitStmt(S);
}
+void StmtProfiler::VisitCXXForRangeStmt(CXXForRangeStmt *S) {
+ VisitStmt(S);
+}
+
+void StmtProfiler::VisitSEHTryStmt(SEHTryStmt *S) {
+ VisitStmt(S);
+}
+
+void StmtProfiler::VisitSEHFinallyStmt(SEHFinallyStmt *S) {
+ VisitStmt(S);
+}
+
+void StmtProfiler::VisitSEHExceptStmt(SEHExceptStmt *S) {
+ VisitStmt(S);
+}
+
void StmtProfiler::VisitObjCForCollectionStmt(ObjCForCollectionStmt *S) {
VisitStmt(S);
}
@@ -290,9 +306,9 @@ void StmtProfiler::VisitOffsetOfExpr(OffsetOfExpr *S) {
VisitExpr(S);
}
-void StmtProfiler::VisitSizeOfAlignOfExpr(SizeOfAlignOfExpr *S) {
+void StmtProfiler::VisitUnaryExprOrTypeTraitExpr(UnaryExprOrTypeTraitExpr *S) {
VisitExpr(S);
- ID.AddBoolean(S->isSizeOf());
+ ID.AddInteger(S->getKind());
if (S->isArgumentType())
VisitType(S->getArgumentType());
}
@@ -430,6 +446,18 @@ void StmtProfiler::VisitBlockDeclRefExpr(BlockDeclRefExpr *S) {
ID.AddBoolean(S->isConstQualAdded());
}
+void StmtProfiler::VisitGenericSelectionExpr(GenericSelectionExpr *S) {
+ VisitExpr(S);
+ for (unsigned i = 0; i != S->getNumAssocs(); ++i) {
+ QualType T = S->getAssocType(i);
+ if (T.isNull())
+ ID.AddPointer(0);
+ else
+ VisitType(T);
+ VisitExpr(S->getAssocExpr(i));
+ }
+}
+
static Stmt::StmtClass DecodeOperatorCall(CXXOperatorCallExpr *S,
UnaryOperatorKind &UnaryOp,
BinaryOperatorKind &BinaryOp) {
@@ -786,6 +814,18 @@ void StmtProfiler::VisitBinaryTypeTraitExpr(BinaryTypeTraitExpr *S) {
VisitType(S->getRhsType());
}
+void StmtProfiler::VisitArrayTypeTraitExpr(ArrayTypeTraitExpr *S) {
+ VisitExpr(S);
+ ID.AddInteger(S->getTrait());
+ VisitType(S->getQueriedType());
+}
+
+void StmtProfiler::VisitExpressionTraitExpr(ExpressionTraitExpr *S) {
+ VisitExpr(S);
+ ID.AddInteger(S->getTrait());
+ VisitExpr(S->getQueriedExpression());
+}
+
void
StmtProfiler::VisitDependentScopeDeclRefExpr(DependentScopeDeclRefExpr *S) {
VisitExpr(S);
@@ -921,12 +961,16 @@ void StmtProfiler::VisitDecl(Decl *D) {
}
if (ParmVarDecl *Parm = dyn_cast<ParmVarDecl>(D)) {
- // The Itanium C++ ABI uses the type of a parameter when mangling
- // expressions that involve function parameters, so we will use the
- // parameter's type for establishing function parameter identity. That
- // way, our definition of "equivalent" (per C++ [temp.over.link])
- // matches the definition of "equivalent" used for name mangling.
+ // The Itanium C++ ABI uses the type, scope depth, and scope
+ // index of a parameter when mangling expressions that involve
+ // function parameters, so we will use the parameter's type for
+ // establishing function parameter identity. That way, our
+ // definition of "equivalent" (per C++ [temp.over.link]) is at
+ // least as strong as the definition of "equivalent" used for
+ // name mangling.
VisitType(Parm->getType());
+ ID.AddInteger(Parm->getFunctionScopeDepth());
+ ID.AddInteger(Parm->getFunctionScopeIndex());
return;
}
diff --git a/lib/AST/TemplateBase.cpp b/lib/AST/TemplateBase.cpp
index 1764f4ab1f03..6114a5a051be 100644
--- a/lib/AST/TemplateBase.cpp
+++ b/lib/AST/TemplateBase.cpp
@@ -338,7 +338,7 @@ void TemplateArgument::print(const PrintingPolicy &Policy,
//===----------------------------------------------------------------------===//
TemplateArgumentLocInfo::TemplateArgumentLocInfo() {
- memset(this, 0, sizeof(TemplateArgumentLocInfo));
+ memset((void*)this, 0, sizeof(TemplateArgumentLocInfo));
}
SourceRange TemplateArgumentLoc::getSourceRange() const {
@@ -356,14 +356,14 @@ SourceRange TemplateArgumentLoc::getSourceRange() const {
return SourceRange();
case TemplateArgument::Template:
- if (getTemplateQualifierRange().isValid())
- return SourceRange(getTemplateQualifierRange().getBegin(),
+ if (getTemplateQualifierLoc())
+ return SourceRange(getTemplateQualifierLoc().getBeginLoc(),
getTemplateNameLoc());
return SourceRange(getTemplateNameLoc());
case TemplateArgument::TemplateExpansion:
- if (getTemplateQualifierRange().isValid())
- return SourceRange(getTemplateQualifierRange().getBegin(),
+ if (getTemplateQualifierLoc())
+ return SourceRange(getTemplateQualifierLoc().getBeginLoc(),
getTemplateEllipsisLoc());
return SourceRange(getTemplateNameLoc(), getTemplateEllipsisLoc());
@@ -425,7 +425,7 @@ TemplateArgumentLoc::getPackExpansionPattern(SourceLocation &Ellipsis,
Ellipsis = getTemplateEllipsisLoc();
NumExpansions = Argument.getNumTemplateExpansions();
return TemplateArgumentLoc(Argument.getPackExpansionPattern(),
- getTemplateQualifierRange(),
+ getTemplateQualifierLoc(),
getTemplateNameLoc());
case TemplateArgument::Declaration:
diff --git a/lib/AST/TemplateName.cpp b/lib/AST/TemplateName.cpp
index 6b378a001101..ebd07f486783 100644
--- a/lib/AST/TemplateName.cpp
+++ b/lib/AST/TemplateName.cpp
@@ -118,6 +118,10 @@ TemplateName::print(llvm::raw_ostream &OS, const PrintingPolicy &Policy,
} else if (SubstTemplateTemplateParmPackStorage *SubstPack
= getAsSubstTemplateTemplateParmPack())
OS << SubstPack->getParameterPack()->getNameAsString();
+ else {
+ OverloadedTemplateStorage *OTS = getAsOverloadedTemplate();
+ (*OTS->begin())->printName(OS);
+ }
}
const DiagnosticBuilder &clang::operator<<(const DiagnosticBuilder &DB,
diff --git a/lib/AST/Type.cpp b/lib/AST/Type.cpp
index b03314e11d13..9eb497bea629 100644
--- a/lib/AST/Type.cpp
+++ b/lib/AST/Type.cpp
@@ -21,11 +21,24 @@
#include "clang/AST/PrettyPrinter.h"
#include "clang/AST/TypeVisitor.h"
#include "clang/Basic/Specifiers.h"
+#include "llvm/ADT/APSInt.h"
#include "llvm/ADT/StringExtras.h"
#include "llvm/Support/raw_ostream.h"
#include <algorithm>
using namespace clang;
+bool Qualifiers::isStrictSupersetOf(Qualifiers Other) const {
+ return (*this != Other) &&
+ // CVR qualifiers superset
+ (((Mask & CVRMask) | (Other.Mask & CVRMask)) == (Mask & CVRMask)) &&
+ // ObjC GC qualifiers superset
+ ((getObjCGCAttr() == Other.getObjCGCAttr()) ||
+ (hasObjCGCAttr() && !Other.hasObjCGCAttr())) &&
+ // Address space superset.
+ ((getAddressSpace() == Other.getAddressSpace()) ||
+ (hasAddressSpace()&& !Other.hasAddressSpace()));
+}
+
bool QualType::isConstant(QualType T, ASTContext &Ctx) {
if (T.isConstQualified())
return true;
@@ -407,6 +420,16 @@ const ObjCObjectPointerType *Type::getAsObjCQualifiedIdType() const {
return 0;
}
+const ObjCObjectPointerType *Type::getAsObjCQualifiedClassType() const {
+ // There is no sugar for ObjCQualifiedClassType's, just return the canonical
+ // type pointer if it is the right class.
+ if (const ObjCObjectPointerType *OPT = getAs<ObjCObjectPointerType>()) {
+ if (OPT->isObjCQualifiedClassType())
+ return OPT;
+ }
+ return 0;
+}
+
const ObjCObjectPointerType *Type::getAsObjCInterfacePointerType() const {
if (const ObjCObjectPointerType *OPT = getAs<ObjCObjectPointerType>()) {
if (OPT->getInterfaceType())
@@ -858,37 +881,178 @@ bool Type::isPODType() const {
}
bool Type::isLiteralType() const {
- if (isIncompleteType())
+ if (isDependentType())
return false;
// C++0x [basic.types]p10:
// A type is a literal type if it is:
- switch (CanonicalType->getTypeClass()) {
- // We're whitelisting
- default: return false;
+ // [...]
+ // -- an array of literal type
+ // Extension: variable arrays cannot be literal types, since they're
+ // runtime-sized.
+ if (isVariableArrayType())
+ return false;
+ const Type *BaseTy = getBaseElementTypeUnsafe();
+ assert(BaseTy && "NULL element type");
+
+ // Return false for incomplete types after skipping any incomplete array
+ // types; those are expressly allowed by the standard and thus our API.
+ if (BaseTy->isIncompleteType())
+ return false;
+
+ // C++0x [basic.types]p10:
+ // A type is a literal type if it is:
+ // -- a scalar type; or
+ // As an extension, Clang treats vector types as Scalar types.
+ if (BaseTy->isScalarType() || BaseTy->isVectorType()) return true;
+ // -- a reference type; or
+ if (BaseTy->isReferenceType()) return true;
+ // -- a class type that has all of the following properties:
+ if (const RecordType *RT = BaseTy->getAs<RecordType>()) {
+ if (const CXXRecordDecl *ClassDecl =
+ dyn_cast<CXXRecordDecl>(RT->getDecl())) {
+ // -- a trivial destructor,
+ if (!ClassDecl->hasTrivialDestructor()) return false;
+ // -- every constructor call and full-expression in the
+ // brace-or-equal-initializers for non-static data members (if any)
+ // is a constant expression,
+ // FIXME: C++0x: Clang doesn't yet support non-static data member
+ // declarations with initializers, or constexprs.
+ // -- it is an aggregate type or has at least one constexpr
+ // constructor or constructor template that is not a copy or move
+ // constructor, and
+ if (!ClassDecl->isAggregate() &&
+ !ClassDecl->hasConstExprNonCopyMoveConstructor())
+ return false;
+ // -- all non-static data members and base classes of literal types
+ if (ClassDecl->hasNonLiteralTypeFieldsOrBases()) return false;
+ }
- // -- a scalar type
- case Builtin:
- case Complex:
- case Pointer:
- case MemberPointer:
- case Vector:
- case ExtVector:
- case ObjCObjectPointer:
- case Enum:
return true;
+ }
+ return false;
+}
- // -- a class type with ...
- case Record:
- // FIXME: Do the tests
+bool Type::isTrivialType() const {
+ if (isDependentType())
return false;
- // -- an array of literal type
- // Extension: variable arrays cannot be literal types, since they're
- // runtime-sized.
- case ConstantArray:
- return cast<ArrayType>(CanonicalType)->getElementType()->isLiteralType();
+ // C++0x [basic.types]p9:
+ // Scalar types, trivial class types, arrays of such types, and
+ // cv-qualified versions of these types are collectively called trivial
+ // types.
+ const Type *BaseTy = getBaseElementTypeUnsafe();
+ assert(BaseTy && "NULL element type");
+
+ // Return false for incomplete types after skipping any incomplete array
+ // types which are expressly allowed by the standard and thus our API.
+ if (BaseTy->isIncompleteType())
+ return false;
+
+ // As an extension, Clang treats vector types as Scalar types.
+ if (BaseTy->isScalarType() || BaseTy->isVectorType()) return true;
+ if (const RecordType *RT = BaseTy->getAs<RecordType>()) {
+ if (const CXXRecordDecl *ClassDecl =
+ dyn_cast<CXXRecordDecl>(RT->getDecl())) {
+ // C++0x [class]p5:
+ // A trivial class is a class that has a trivial default constructor
+ if (!ClassDecl->hasTrivialConstructor()) return false;
+ // and is trivially copyable.
+ if (!ClassDecl->isTriviallyCopyable()) return false;
+ }
+
+ return true;
+ }
+
+ // No other types can match.
+ return false;
+}
+
+bool Type::isStandardLayoutType() const {
+ if (isDependentType())
+ return false;
+
+ // C++0x [basic.types]p9:
+ // Scalar types, standard-layout class types, arrays of such types, and
+ // cv-qualified versions of these types are collectively called
+ // standard-layout types.
+ const Type *BaseTy = getBaseElementTypeUnsafe();
+ assert(BaseTy && "NULL element type");
+
+ // Return false for incomplete types after skipping any incomplete array
+ // types which are expressly allowed by the standard and thus our API.
+ if (BaseTy->isIncompleteType())
+ return false;
+
+ // As an extension, Clang treats vector types as Scalar types.
+ if (BaseTy->isScalarType() || BaseTy->isVectorType()) return true;
+ if (const RecordType *RT = BaseTy->getAs<RecordType>()) {
+ if (const CXXRecordDecl *ClassDecl =
+ dyn_cast<CXXRecordDecl>(RT->getDecl()))
+ if (!ClassDecl->isStandardLayout())
+ return false;
+
+ // Default to 'true' for non-C++ class types.
+ // FIXME: This is a bit dubious, but plain C structs should trivially meet
+ // all the requirements of standard layout classes.
+ return true;
+ }
+
+ // No other types can match.
+ return false;
+}
+
+// This is effectively the intersection of isTrivialType and
+// isStandardLayoutType. We implement it dircetly to avoid redundant
+// conversions from a type to a CXXRecordDecl.
+bool Type::isCXX11PODType() const {
+ if (isDependentType())
+ return false;
+
+ // C++11 [basic.types]p9:
+ // Scalar types, POD classes, arrays of such types, and cv-qualified
+ // versions of these types are collectively called trivial types.
+ const Type *BaseTy = getBaseElementTypeUnsafe();
+ assert(BaseTy && "NULL element type");
+
+ // Return false for incomplete types after skipping any incomplete array
+ // types which are expressly allowed by the standard and thus our API.
+ if (BaseTy->isIncompleteType())
+ return false;
+
+ // As an extension, Clang treats vector types as Scalar types.
+ if (BaseTy->isScalarType() || BaseTy->isVectorType()) return true;
+ if (const RecordType *RT = BaseTy->getAs<RecordType>()) {
+ if (const CXXRecordDecl *ClassDecl =
+ dyn_cast<CXXRecordDecl>(RT->getDecl())) {
+ // C++11 [class]p10:
+ // A POD struct is a non-union class that is both a trivial class [...]
+ // C++11 [class]p5:
+ // A trivial class is a class that has a trivial default constructor
+ if (!ClassDecl->hasTrivialConstructor()) return false;
+ // and is trivially copyable.
+ if (!ClassDecl->isTriviallyCopyable()) return false;
+
+ // C++11 [class]p10:
+ // A POD struct is a non-union class that is both a trivial class and
+ // a standard-layout class [...]
+ if (!ClassDecl->isStandardLayout()) return false;
+
+ // C++11 [class]p10:
+ // A POD struct is a non-union class that is both a trivial class and
+ // a standard-layout class, and has no non-static data members of type
+ // non-POD struct, non-POD union (or array of such types). [...]
+ //
+ // We don't directly query the recursive aspect as the requiremets for
+ // both standard-layout classes and trivial classes apply recursively
+ // already.
+ }
+
+ return true;
}
+
+ // No other types can match.
+ return false;
}
bool Type::isPromotableIntegerType() const {
@@ -1040,9 +1204,9 @@ DependentTemplateSpecializationType::DependentTemplateSpecializationType(
QualType Canon)
: TypeWithKeyword(Keyword, DependentTemplateSpecialization, Canon, true,
/*VariablyModified=*/false,
- NNS->containsUnexpandedParameterPack()),
+ NNS && NNS->containsUnexpandedParameterPack()),
NNS(NNS), Name(Name), NumArgs(NumArgs) {
- assert(NNS && NNS->isDependent() &&
+ assert((!NNS || NNS->isDependent()) &&
"DependentTemplateSpecializatonType requires dependent qualifier");
for (unsigned I = 0; I != NumArgs; ++I) {
if (Args[I].containsUnexpandedParameterPack())
@@ -1120,7 +1284,9 @@ const char *BuiltinType::getName(const LangOptions &LO) const {
case Char32: return "char32_t";
case NullPtr: return "nullptr_t";
case Overload: return "<overloaded function type>";
+ case BoundMember: return "<bound member function type>";
case Dependent: return "<dependent type>";
+ case UnknownAny: return "<unknown type>";
case ObjCId: return "id";
case ObjCClass: return "Class";
case ObjCSel: return "SEL";
@@ -1157,6 +1323,8 @@ llvm::StringRef FunctionType::getNameForCallConv(CallingConv CC) {
case CC_X86FastCall: return "fastcall";
case CC_X86ThisCall: return "thiscall";
case CC_X86Pascal: return "pascal";
+ case CC_AAPCS: return "aapcs";
+ case CC_AAPCS_VFP: return "aapcs-vfp";
}
llvm_unreachable("Invalid calling convention.");
@@ -1173,8 +1341,7 @@ FunctionProtoType::FunctionProtoType(QualType result, const QualType *args,
result->containsUnexpandedParameterPack(),
epi.ExtInfo),
NumArgs(numArgs), NumExceptions(epi.NumExceptions),
- HasExceptionSpec(epi.HasExceptionSpec),
- HasAnyExceptionSpec(epi.HasAnyExceptionSpec)
+ ExceptionSpecType(epi.ExceptionSpecType)
{
// Fill in the trailing argument array.
QualType *argSlot = reinterpret_cast<QualType*>(this+1);
@@ -1187,20 +1354,50 @@ FunctionProtoType::FunctionProtoType(QualType result, const QualType *args,
argSlot[i] = args[i];
}
-
- // Fill in the exception array.
- QualType *exnSlot = argSlot + numArgs;
- for (unsigned i = 0, e = epi.NumExceptions; i != e; ++i) {
- if (epi.Exceptions[i]->isDependentType())
- setDependent();
- if (epi.Exceptions[i]->containsUnexpandedParameterPack())
- setContainsUnexpandedParameterPack();
+ if (getExceptionSpecType() == EST_Dynamic) {
+ // Fill in the exception array.
+ QualType *exnSlot = argSlot + numArgs;
+ for (unsigned i = 0, e = epi.NumExceptions; i != e; ++i) {
+ if (epi.Exceptions[i]->isDependentType())
+ setDependent();
- exnSlot[i] = epi.Exceptions[i];
+ if (epi.Exceptions[i]->containsUnexpandedParameterPack())
+ setContainsUnexpandedParameterPack();
+
+ exnSlot[i] = epi.Exceptions[i];
+ }
+ } else if (getExceptionSpecType() == EST_ComputedNoexcept) {
+ // Store the noexcept expression and context.
+ Expr **noexSlot = reinterpret_cast<Expr**>(argSlot + numArgs);
+ *noexSlot = epi.NoexceptExpr;
}
}
+FunctionProtoType::NoexceptResult
+FunctionProtoType::getNoexceptSpec(ASTContext &ctx) const {
+ ExceptionSpecificationType est = getExceptionSpecType();
+ if (est == EST_BasicNoexcept)
+ return NR_Nothrow;
+
+ if (est != EST_ComputedNoexcept)
+ return NR_NoNoexcept;
+
+ Expr *noexceptExpr = getNoexceptExpr();
+ if (!noexceptExpr)
+ return NR_BadNoexcept;
+ if (noexceptExpr->isValueDependent())
+ return NR_Dependent;
+
+ llvm::APSInt value;
+ bool isICE = noexceptExpr->isIntegerConstantExpr(value, ctx, 0,
+ /*evaluated*/false);
+ (void)isICE;
+ assert(isICE && "AST should not contain bad noexcept expressions.");
+
+ return value.getBoolValue() ? NR_Nothrow : NR_Throw;
+}
+
bool FunctionProtoType::isTemplateVariadic() const {
for (unsigned ArgIdx = getNumArgs(); ArgIdx; --ArgIdx)
if (isa<PackExpansionType>(getArgType(ArgIdx - 1)))
@@ -1211,23 +1408,28 @@ bool FunctionProtoType::isTemplateVariadic() const {
void FunctionProtoType::Profile(llvm::FoldingSetNodeID &ID, QualType Result,
const QualType *ArgTys, unsigned NumArgs,
- const ExtProtoInfo &epi) {
+ const ExtProtoInfo &epi,
+ const ASTContext &Context) {
ID.AddPointer(Result.getAsOpaquePtr());
for (unsigned i = 0; i != NumArgs; ++i)
ID.AddPointer(ArgTys[i].getAsOpaquePtr());
ID.AddBoolean(epi.Variadic);
ID.AddInteger(epi.TypeQuals);
ID.AddInteger(epi.RefQualifier);
- if (epi.HasExceptionSpec) {
- ID.AddBoolean(epi.HasAnyExceptionSpec);
+ ID.AddInteger(epi.ExceptionSpecType);
+ if (epi.ExceptionSpecType == EST_Dynamic) {
for (unsigned i = 0; i != epi.NumExceptions; ++i)
ID.AddPointer(epi.Exceptions[i].getAsOpaquePtr());
+ } else if (epi.ExceptionSpecType == EST_ComputedNoexcept && epi.NoexceptExpr){
+ epi.NoexceptExpr->Profile(ID, Context, true);
}
epi.ExtInfo.Profile(ID);
}
-void FunctionProtoType::Profile(llvm::FoldingSetNodeID &ID) {
- Profile(ID, getResultType(), arg_type_begin(), NumArgs, getExtProtoInfo());
+void FunctionProtoType::Profile(llvm::FoldingSetNodeID &ID,
+ const ASTContext &Ctx) {
+ Profile(ID, getResultType(), arg_type_begin(), NumArgs, getExtProtoInfo(),
+ Ctx);
}
QualType TypedefType::desugar() const {
@@ -1302,6 +1504,10 @@ bool EnumType::classof(const TagType *TT) {
return isa<EnumDecl>(TT->getDecl());
}
+IdentifierInfo *TemplateTypeParmType::getIdentifier() const {
+ return isCanonicalUnqualified() ? 0 : getDecl()->getIdentifier();
+}
+
SubstTemplateTypeParmPackType::
SubstTemplateTypeParmPackType(const TemplateTypeParmType *Param,
QualType Canon,
@@ -1357,10 +1563,11 @@ TemplateSpecializationType(TemplateName T,
unsigned NumArgs, QualType Canon)
: Type(TemplateSpecialization,
Canon.isNull()? QualType(this, 0) : Canon,
- T.isDependent(), false,
- T.containsUnexpandedParameterPack()),
+ T.isDependent(), false, T.containsUnexpandedParameterPack()),
Template(T), NumArgs(NumArgs)
{
+ assert(!T.getAsDependentTemplateName() &&
+ "Use DependentTemplateSpecializationType for dependent template-name");
assert((!Canon.isNull() ||
T.isDependent() || anyDependentTemplateArguments(Args, NumArgs)) &&
"No canonical type for non-dependent class template specialization");
@@ -1529,7 +1736,7 @@ static CachedProperties computeCachedProperties(const Type *T) {
NamedDecl::LinkageInfo LV = Tag->getLinkageAndVisibility();
bool IsLocalOrUnnamed =
Tag->getDeclContext()->isFunctionOrMethod() ||
- (!Tag->getIdentifier() && !Tag->getTypedefForAnonDecl());
+ (!Tag->getIdentifier() && !Tag->getTypedefNameForAnonDecl());
return CachedProperties(LV.linkage(), LV.visibility(), IsLocalOrUnnamed);
}
diff --git a/lib/AST/TypeLoc.cpp b/lib/AST/TypeLoc.cpp
index 14db7f83c2d0..34e7693e3075 100644
--- a/lib/AST/TypeLoc.cpp
+++ b/lib/AST/TypeLoc.cpp
@@ -102,6 +102,8 @@ SourceLocation TypeLoc::getBeginLoc() const {
// FIXME: Currently QualifiedTypeLoc does not have a source range
// case Qualified:
case Elaborated:
+ case DependentName:
+ case DependentTemplateSpecialization:
break;
default:
TypeLoc Next = Cur.getNextTypeLoc();
@@ -116,18 +118,37 @@ SourceLocation TypeLoc::getBeginLoc() const {
SourceLocation TypeLoc::getEndLoc() const {
TypeLoc Cur = *this;
+ TypeLoc Last;
while (true) {
switch (Cur.getTypeLocClass()) {
default:
+ if (!Last)
+ Last = Cur;
+ return Last.getLocalSourceRange().getEnd();
+ case Paren:
+ case ConstantArray:
+ case DependentSizedArray:
+ case IncompleteArray:
+ case VariableArray:
+ case FunctionProto:
+ case FunctionNoProto:
+ Last = Cur;
+ break;
+ case Pointer:
+ case BlockPointer:
+ case MemberPointer:
+ case LValueReference:
+ case RValueReference:
+ case PackExpansion:
+ if (!Last)
+ Last = Cur;
break;
case Qualified:
case Elaborated:
- Cur = Cur.getNextTypeLoc();
- continue;
+ break;
}
- break;
+ Cur = Cur.getNextTypeLoc();
}
- return Cur.getLocalSourceRange().getEnd();
}
@@ -213,6 +234,8 @@ TypeSpecifierType BuiltinTypeLoc::getWrittenTypeSpec() const {
case BuiltinType::NullPtr:
case BuiltinType::Overload:
case BuiltinType::Dependent:
+ case BuiltinType::BoundMember:
+ case BuiltinType::UnknownAny:
case BuiltinType::ObjCId:
case BuiltinType::ObjCClass:
case BuiltinType::ObjCSel:
@@ -229,6 +252,43 @@ TypeLoc TypeLoc::IgnoreParensImpl(TypeLoc TL) {
return TL;
}
+void ElaboratedTypeLoc::initializeLocal(ASTContext &Context,
+ SourceLocation Loc) {
+ setKeywordLoc(Loc);
+ NestedNameSpecifierLocBuilder Builder;
+ Builder.MakeTrivial(Context, getTypePtr()->getQualifier(), Loc);
+ setQualifierLoc(Builder.getWithLocInContext(Context));
+}
+
+void DependentNameTypeLoc::initializeLocal(ASTContext &Context,
+ SourceLocation Loc) {
+ setKeywordLoc(Loc);
+ NestedNameSpecifierLocBuilder Builder;
+ Builder.MakeTrivial(Context, getTypePtr()->getQualifier(), Loc);
+ setQualifierLoc(Builder.getWithLocInContext(Context));
+ setNameLoc(Loc);
+}
+
+void
+DependentTemplateSpecializationTypeLoc::initializeLocal(ASTContext &Context,
+ SourceLocation Loc) {
+ setKeywordLoc(Loc);
+ if (getTypePtr()->getQualifier()) {
+ NestedNameSpecifierLocBuilder Builder;
+ Builder.MakeTrivial(Context, getTypePtr()->getQualifier(), Loc);
+ setQualifierLoc(Builder.getWithLocInContext(Context));
+ } else {
+ setQualifierLoc(NestedNameSpecifierLoc());
+ }
+
+ setNameLoc(Loc);
+ setLAngleLoc(Loc);
+ setRAngleLoc(Loc);
+ TemplateSpecializationTypeLoc::initializeArgLocs(Context, getNumArgs(),
+ getTypePtr()->getArgs(),
+ getArgInfos(), Loc);
+}
+
void TemplateSpecializationTypeLoc::initializeArgLocs(ASTContext &Context,
unsigned NumArgs,
const TemplateArgument *Args,
@@ -252,13 +312,22 @@ void TemplateSpecializationTypeLoc::initializeArgLocs(ASTContext &Context,
break;
case TemplateArgument::Template:
- ArgInfos[i] = TemplateArgumentLocInfo(SourceRange(Loc), Loc,
- SourceLocation());
- break;
+ case TemplateArgument::TemplateExpansion: {
+ NestedNameSpecifierLocBuilder Builder;
+ TemplateName Template = Args[i].getAsTemplate();
+ if (DependentTemplateName *DTN = Template.getAsDependentTemplateName())
+ Builder.MakeTrivial(Context, DTN->getQualifier(), Loc);
+ else if (QualifiedTemplateName *QTN = Template.getAsQualifiedTemplateName())
+ Builder.MakeTrivial(Context, QTN->getQualifier(), Loc);
- case TemplateArgument::TemplateExpansion:
- ArgInfos[i] = TemplateArgumentLocInfo(SourceRange(Loc), Loc, Loc);
+ ArgInfos[i] = TemplateArgumentLocInfo(
+ Builder.getWithLocInContext(Context),
+ Loc,
+ Args[i].getKind() == TemplateArgument::Template
+ ? SourceLocation()
+ : Loc);
break;
+ }
}
}
}
diff --git a/lib/AST/TypePrinter.cpp b/lib/AST/TypePrinter.cpp
index 139073987a0e..0c5df7fae671 100644
--- a/lib/AST/TypePrinter.cpp
+++ b/lib/AST/TypePrinter.cpp
@@ -400,6 +400,12 @@ void TypePrinter::printFunctionProto(const FunctionProtoType *T,
case CC_X86Pascal:
S += " __attribute__((pascal))";
break;
+ case CC_AAPCS:
+ S += " __attribute__((pcs(\"aapcs\")))";
+ break;
+ case CC_AAPCS_VFP:
+ S += " __attribute__((pcs(\"aapcs-vfp\")))";
+ break;
}
if (Info.getNoReturn())
S += " __attribute__((noreturn))";
@@ -421,12 +427,12 @@ void TypePrinter::printFunctionProto(const FunctionProtoType *T,
S += " &&";
break;
}
-
- if (T->hasExceptionSpec()) {
+
+ if (T->hasDynamicExceptionSpec()) {
S += " throw(";
- if (T->hasAnyExceptionSpec())
+ if (T->getExceptionSpecType() == EST_MSAny)
S += "...";
- else
+ else
for (unsigned I = 0, N = T->getNumExceptions(); I != N; ++I) {
if (I)
S += ", ";
@@ -436,6 +442,16 @@ void TypePrinter::printFunctionProto(const FunctionProtoType *T,
S += ExceptionType;
}
S += ")";
+ } else if (isNoexceptExceptionSpec(T->getExceptionSpecType())) {
+ S += " noexcept";
+ if (T->getExceptionSpecType() == EST_ComputedNoexcept) {
+ S += "(";
+ llvm::raw_string_ostream EOut(S);
+ T->getNoexceptExpr()->printPretty(EOut, 0, Policy);
+ EOut.flush();
+ S += EOut.str();
+ S += ")";
+ }
}
print(T->getResultType(), S);
@@ -530,7 +546,7 @@ void TypePrinter::AppendScope(DeclContext *DC, std::string &Buffer) {
Buffer += Spec->getIdentifier()->getName();
Buffer += TemplateArgsStr;
} else if (TagDecl *Tag = dyn_cast<TagDecl>(DC)) {
- if (TypedefDecl *Typedef = Tag->getTypedefForAnonDecl())
+ if (TypedefNameDecl *Typedef = Tag->getTypedefNameForAnonDecl())
Buffer += Typedef->getIdentifier()->getName();
else if (Tag->getIdentifier())
Buffer += Tag->getIdentifier()->getName();
@@ -547,9 +563,13 @@ void TypePrinter::printTag(TagDecl *D, std::string &InnerString) {
std::string Buffer;
bool HasKindDecoration = false;
+ // bool SuppressTagKeyword
+ // = Policy.LangOpts.CPlusPlus || Policy.SuppressTagKeyword;
+
// We don't print tags unless this is an elaborated type.
// In C, we just assume every RecordType is an elaborated type.
- if (!Policy.LangOpts.CPlusPlus && !D->getTypedefForAnonDecl()) {
+ if (!(Policy.LangOpts.CPlusPlus || Policy.SuppressTagKeyword ||
+ D->getTypedefNameForAnonDecl())) {
HasKindDecoration = true;
Buffer += D->getKindName();
Buffer += ' ';
@@ -563,7 +583,7 @@ void TypePrinter::printTag(TagDecl *D, std::string &InnerString) {
if (const IdentifierInfo *II = D->getIdentifier())
Buffer += II->getNameStart();
- else if (TypedefDecl *Typedef = D->getTypedefForAnonDecl()) {
+ else if (TypedefNameDecl *Typedef = D->getTypedefNameForAnonDecl()) {
assert(Typedef->getIdentifier() && "Typedef without identifier?");
Buffer += Typedef->getIdentifier()->getNameStart();
} else {
@@ -632,12 +652,12 @@ void TypePrinter::printTemplateTypeParm(const TemplateTypeParmType *T,
std::string &S) {
if (!S.empty()) // Prefix the basic type, e.g. 'parmname X'.
S = ' ' + S;
-
- if (!T->getName())
+
+ if (IdentifierInfo *Id = T->getIdentifier())
+ S = Id->getName().str() + S;
+ else
S = "type-parameter-" + llvm::utostr_32(T->getDepth()) + '-' +
llvm::utostr_32(T->getIndex()) + S;
- else
- S = T->getName()->getName().str() + S;
}
void TypePrinter::printSubstTemplateTypeParm(const SubstTemplateTypeParmType *T,
@@ -691,6 +711,7 @@ void TypePrinter::printElaborated(const ElaboratedType *T, std::string &S) {
std::string TypeStr;
PrintingPolicy InnerPolicy(Policy);
+ InnerPolicy.SuppressTagKeyword = true;
InnerPolicy.SuppressScope = true;
TypePrinter(InnerPolicy).print(T->getNamedType(), TypeStr);
@@ -737,7 +758,8 @@ void TypePrinter::printDependentTemplateSpecialization(
if (T->getKeyword() != ETK_None)
OS << " ";
- T->getQualifier()->print(OS, Policy);
+ if (T->getQualifier())
+ T->getQualifier()->print(OS, Policy);
OS << T->getIdentifier()->getName();
OS << TemplateSpecializationType::PrintTemplateArgumentList(
T->getArgs(),
@@ -759,10 +781,14 @@ void TypePrinter::printPackExpansion(const PackExpansionType *T,
void TypePrinter::printAttributed(const AttributedType *T,
std::string &S) {
+ // Prefer the macro forms of the GC qualifiers.
+ if (T->getAttrKind() == AttributedType::attr_objc_gc)
+ return print(T->getEquivalentType(), S);
+
print(T->getModifiedType(), S);
// TODO: not all attributes are GCC-style attributes.
- S += "__attribute__((";
+ S += " __attribute__((";
switch (T->getAttrKind()) {
case AttributedType::attr_address_space:
S += "address_space(";
@@ -831,6 +857,16 @@ void TypePrinter::printAttributed(const AttributedType *T,
case AttributedType::attr_stdcall: S += "stdcall"; break;
case AttributedType::attr_thiscall: S += "thiscall"; break;
case AttributedType::attr_pascal: S += "pascal"; break;
+ case AttributedType::attr_pcs: {
+ S += "pcs(";
+ QualType t = T->getEquivalentType();
+ while (!t->isFunctionType())
+ t = t->getPointeeType();
+ S += (t->getAs<FunctionType>()->getCallConv() == CC_AAPCS ?
+ "\"aapcs\"" : "\"aapcs-vfp\"");
+ S += ")";
+ break;
+ }
}
S += "))";
}
@@ -1031,20 +1067,18 @@ std::string Qualifiers::getAsString() const {
void Qualifiers::getAsStringInternal(std::string &S,
const PrintingPolicy&) const {
AppendTypeQualList(S, getCVRQualifiers());
- if (unsigned AddressSpace = getAddressSpace()) {
+ if (unsigned addrspace = getAddressSpace()) {
if (!S.empty()) S += ' ';
S += "__attribute__((address_space(";
- S += llvm::utostr_32(AddressSpace);
+ S += llvm::utostr_32(addrspace);
S += ")))";
}
- if (Qualifiers::GC GCAttrType = getObjCGCAttr()) {
+ if (Qualifiers::GC gc = getObjCGCAttr()) {
if (!S.empty()) S += ' ';
- S += "__attribute__((objc_gc(";
- if (GCAttrType == Qualifiers::Weak)
- S += "weak";
+ if (gc == Qualifiers::Weak)
+ S += "__weak";
else
- S += "strong";
- S += ")))";
+ S += "__strong";
}
}
diff --git a/lib/Analysis/AnalysisContext.cpp b/lib/Analysis/AnalysisContext.cpp
index 62097ef20dd9..ddc5e887031b 100644
--- a/lib/Analysis/AnalysisContext.cpp
+++ b/lib/Analysis/AnalysisContext.cpp
@@ -29,6 +29,24 @@
using namespace clang;
+AnalysisContext::AnalysisContext(const Decl *d,
+ idx::TranslationUnit *tu,
+ bool useUnoptimizedCFG,
+ bool addehedges,
+ bool addImplicitDtors,
+ bool addInitializers)
+ : D(d), TU(tu),
+ forcedBlkExprs(0),
+ builtCFG(false), builtCompleteCFG(false),
+ useUnoptimizedCFG(useUnoptimizedCFG),
+ ReferencedBlockVars(0)
+{
+ cfgBuildOptions.forcedBlkExprs = &forcedBlkExprs;
+ cfgBuildOptions.AddEHEdges = addehedges;
+ cfgBuildOptions.AddImplicitDtors = addImplicitDtors;
+ cfgBuildOptions.AddInitializers = addInitializers;
+}
+
void AnalysisContextManager::clear() {
for (ContextMap::iterator I = Contexts.begin(), E = Contexts.end(); I!=E; ++I)
delete I->second;
@@ -56,57 +74,71 @@ const ImplicitParamDecl *AnalysisContext::getSelfDecl() const {
return NULL;
}
+void AnalysisContext::registerForcedBlockExpression(const Stmt *stmt) {
+ if (!forcedBlkExprs)
+ forcedBlkExprs = new CFG::BuildOptions::ForcedBlkExprs();
+ // Default construct an entry for 'stmt'.
+ if (const ParenExpr *pe = dyn_cast<ParenExpr>(stmt))
+ stmt = pe->IgnoreParens();
+ (void) (*forcedBlkExprs)[stmt];
+}
+
+const CFGBlock *
+AnalysisContext::getBlockForRegisteredExpression(const Stmt *stmt) {
+ assert(forcedBlkExprs);
+ if (const ParenExpr *pe = dyn_cast<ParenExpr>(stmt))
+ stmt = pe->IgnoreParens();
+ CFG::BuildOptions::ForcedBlkExprs::const_iterator itr =
+ forcedBlkExprs->find(stmt);
+ assert(itr != forcedBlkExprs->end());
+ return itr->second;
+}
+
CFG *AnalysisContext::getCFG() {
- if (UseUnoptimizedCFG)
+ if (useUnoptimizedCFG)
return getUnoptimizedCFG();
if (!builtCFG) {
- CFG::BuildOptions B;
- B.AddEHEdges = AddEHEdges;
- B.AddImplicitDtors = AddImplicitDtors;
- B.AddInitializers = AddInitializers;
- cfg = CFG::buildCFG(D, getBody(), &D->getASTContext(), B);
+ cfg.reset(CFG::buildCFG(D, getBody(),
+ &D->getASTContext(), cfgBuildOptions));
// Even when the cfg is not successfully built, we don't
// want to try building it again.
builtCFG = true;
}
- return cfg;
+ return cfg.get();
}
CFG *AnalysisContext::getUnoptimizedCFG() {
if (!builtCompleteCFG) {
- CFG::BuildOptions B;
+ CFG::BuildOptions B = cfgBuildOptions;
B.PruneTriviallyFalseEdges = false;
- B.AddEHEdges = AddEHEdges;
- B.AddImplicitDtors = AddImplicitDtors;
- B.AddInitializers = AddInitializers;
- completeCFG = CFG::buildCFG(D, getBody(), &D->getASTContext(), B);
+ completeCFG.reset(CFG::buildCFG(D, getBody(), &D->getASTContext(), B));
// Even when the cfg is not successfully built, we don't
// want to try building it again.
builtCompleteCFG = true;
}
- return completeCFG;
+ return completeCFG.get();
}
CFGStmtMap *AnalysisContext::getCFGStmtMap() {
if (cfgStmtMap)
- return cfgStmtMap;
+ return cfgStmtMap.get();
if (CFG *c = getCFG()) {
- cfgStmtMap = CFGStmtMap::Build(c, &getParentMap());
- return cfgStmtMap;
+ cfgStmtMap.reset(CFGStmtMap::Build(c, &getParentMap()));
+ return cfgStmtMap.get();
}
return 0;
}
-CFGReachabilityAnalysis *AnalysisContext::getCFGReachablityAnalysis() {
+CFGReverseBlockReachabilityAnalysis *AnalysisContext::getCFGReachablityAnalysis() {
if (CFA)
- return CFA;
+ return CFA.get();
if (CFG *c = getCFG()) {
- CFA = new CFGReachabilityAnalysis(*c);
- return CFA;
+ CFA.reset(new CFGReverseBlockReachabilityAnalysis(*c));
+ return CFA.get();
}
return 0;
@@ -118,42 +150,37 @@ void AnalysisContext::dumpCFG() {
ParentMap &AnalysisContext::getParentMap() {
if (!PM)
- PM = new ParentMap(getBody());
+ PM.reset(new ParentMap(getBody()));
return *PM;
}
PseudoConstantAnalysis *AnalysisContext::getPseudoConstantAnalysis() {
if (!PCA)
- PCA = new PseudoConstantAnalysis(getBody());
- return PCA;
+ PCA.reset(new PseudoConstantAnalysis(getBody()));
+ return PCA.get();
}
LiveVariables *AnalysisContext::getLiveVariables() {
if (!liveness) {
- CFG *c = getCFG();
- if (!c)
- return 0;
-
- liveness = new LiveVariables(*this);
- liveness->runOnCFG(*c);
- liveness->runOnAllBlocks(*c, 0, true);
+ if (CFG *c = getCFG()) {
+ liveness.reset(new LiveVariables(*this));
+ liveness->runOnCFG(*c);
+ liveness->runOnAllBlocks(*c, 0, true);
+ }
}
- return liveness;
+ return liveness.get();
}
LiveVariables *AnalysisContext::getRelaxedLiveVariables() {
- if (!relaxedLiveness) {
- CFG *c = getCFG();
- if (!c)
- return 0;
-
- relaxedLiveness = new LiveVariables(*this, false);
- relaxedLiveness->runOnCFG(*c);
- relaxedLiveness->runOnAllBlocks(*c, 0, true);
- }
+ if (!relaxedLiveness)
+ if (CFG *c = getCFG()) {
+ relaxedLiveness.reset(new LiveVariables(*this, false));
+ relaxedLiveness->runOnCFG(*c);
+ relaxedLiveness->runOnAllBlocks(*c, 0, true);
+ }
- return relaxedLiveness;
+ return relaxedLiveness.get();
}
AnalysisContext *AnalysisContextManager::getContext(const Decl *D,
@@ -370,14 +397,7 @@ AnalysisContext::getReferencedBlockVars(const BlockDecl *BD) {
//===----------------------------------------------------------------------===//
AnalysisContext::~AnalysisContext() {
- delete cfg;
- delete completeCFG;
- delete cfgStmtMap;
- delete liveness;
- delete relaxedLiveness;
- delete PM;
- delete PCA;
- delete CFA;
+ delete forcedBlkExprs;
delete ReferencedBlockVars;
}
diff --git a/lib/Analysis/CFG.cpp b/lib/Analysis/CFG.cpp
index cc6e9c592a1e..de16334ce137 100644
--- a/lib/Analysis/CFG.cpp
+++ b/lib/Analysis/CFG.cpp
@@ -36,6 +36,8 @@ static SourceLocation GetEndLoc(Decl* D) {
return D->getLocation();
}
+class CFGBuilder;
+
/// The CFG builder uses a recursive algorithm to build the CFG. When
/// we process an expression, sometimes we know that we must add the
/// subexpressions as block-level expressions. For example:
@@ -55,13 +57,13 @@ public:
AddStmtChoice(Kind a_kind = NotAlwaysAdd) : kind(a_kind) {}
- bool alwaysAdd() const { return kind & AlwaysAdd; }
+ bool alwaysAdd(CFGBuilder &builder,
+ const Stmt *stmt) const;
/// Return a copy of this object, except with the 'always-add' bit
/// set as specified.
AddStmtChoice withAlwaysAdd(bool alwaysAdd) const {
- return AddStmtChoice(alwaysAdd ? Kind(kind | AlwaysAdd) :
- Kind(kind & ~AlwaysAdd));
+ return AddStmtChoice(alwaysAdd ? AlwaysAdd : NotAlwaysAdd);
}
private:
@@ -210,6 +212,25 @@ struct BlockScopePosPair {
LocalScope::const_iterator scopePosition;
};
+/// TryResult - a class representing a variant over the values
+/// 'true', 'false', or 'unknown'. This is returned by tryEvaluateBool,
+/// and is used by the CFGBuilder to decide if a branch condition
+/// can be decided up front during CFG construction.
+class TryResult {
+ int X;
+public:
+ TryResult(bool b) : X(b ? 1 : 0) {}
+ TryResult() : X(-1) {}
+
+ bool isTrue() const { return X == 1; }
+ bool isFalse() const { return X == 0; }
+ bool isKnown() const { return X >= 0; }
+ void negate() {
+ assert(isKnown());
+ X ^= 0x1;
+ }
+};
+
/// CFGBuilder - This class implements CFG construction from an AST.
/// The builder is stateful: an instance of the builder should be used to only
/// construct a single CFG.
@@ -238,7 +259,7 @@ class CFGBuilder {
CFGBlock* SwitchTerminatedBlock;
CFGBlock* DefaultCaseBlock;
CFGBlock* TryTerminatedBlock;
-
+
// Current position in local scope.
LocalScope::const_iterator ScopePos;
@@ -256,18 +277,30 @@ class CFGBuilder {
LabelSetTy AddressTakenLabels;
bool badCFG;
- CFG::BuildOptions BuildOpts;
+ const CFG::BuildOptions &BuildOpts;
+
+ // State to track for building switch statements.
+ bool switchExclusivelyCovered;
+ Expr::EvalResult *switchCond;
+
+ CFG::BuildOptions::ForcedBlkExprs::value_type *cachedEntry;
+ const Stmt *lastLookup;
public:
- explicit CFGBuilder() : cfg(new CFG()), // crew a new CFG
- Block(NULL), Succ(NULL),
- SwitchTerminatedBlock(NULL), DefaultCaseBlock(NULL),
- TryTerminatedBlock(NULL), badCFG(false) {}
+ explicit CFGBuilder(ASTContext *astContext,
+ const CFG::BuildOptions &buildOpts)
+ : Context(astContext), cfg(new CFG()), // crew a new CFG
+ Block(NULL), Succ(NULL),
+ SwitchTerminatedBlock(NULL), DefaultCaseBlock(NULL),
+ TryTerminatedBlock(NULL), badCFG(false), BuildOpts(buildOpts),
+ switchExclusivelyCovered(false), switchCond(0),
+ cachedEntry(0), lastLookup(0) {}
// buildCFG - Used by external clients to construct the CFG.
- CFG* buildCFG(const Decl *D, Stmt *Statement, ASTContext *C,
- CFG::BuildOptions BO);
+ CFG* buildCFG(const Decl *D, Stmt *Statement);
+ bool alwaysAdd(const Stmt *stmt);
+
private:
// Visitors to walk an AST and construct the CFG.
CFGBlock *VisitAddrLabelExpr(AddrLabelExpr *A, AddStmtChoice asc);
@@ -279,6 +312,7 @@ private:
AddStmtChoice asc);
CFGBlock *VisitCXXThrowExpr(CXXThrowExpr *T);
CFGBlock *VisitCXXTryStmt(CXXTryStmt *S);
+ CFGBlock *VisitCXXForRangeStmt(CXXForRangeStmt *S);
CFGBlock *VisitCXXBindTemporaryExpr(CXXBindTemporaryExpr *E,
AddStmtChoice asc);
CFGBlock *VisitCXXConstructExpr(CXXConstructExpr *C, AddStmtChoice asc);
@@ -311,7 +345,8 @@ private:
CFGBlock *VisitObjCAtTryStmt(ObjCAtTryStmt *S);
CFGBlock *VisitObjCForCollectionStmt(ObjCForCollectionStmt *S);
CFGBlock *VisitReturnStmt(ReturnStmt* R);
- CFGBlock *VisitSizeOfAlignOfExpr(SizeOfAlignOfExpr *E, AddStmtChoice asc);
+ CFGBlock *VisitUnaryExprOrTypeTraitExpr(UnaryExprOrTypeTraitExpr *E,
+ AddStmtChoice asc);
CFGBlock *VisitStmtExpr(StmtExpr *S, AddStmtChoice asc);
CFGBlock *VisitSwitchStmt(SwitchStmt *S);
CFGBlock *VisitUnaryOperator(UnaryOperator *U, AddStmtChoice asc);
@@ -359,9 +394,11 @@ private:
void addLocalScopeAndDtors(Stmt* S);
// Interface to CFGBlock - adding CFGElements.
- void appendStmt(CFGBlock *B, Stmt *S,
- AddStmtChoice asc = AddStmtChoice::AlwaysAdd) {
- B->appendStmt(S, cfg->getBumpVectorContext());
+ void appendStmt(CFGBlock *B, const Stmt *S) {
+ if (alwaysAdd(S))
+ cachedEntry->second = B;
+
+ B->appendStmt(const_cast<Stmt*>(S), cfg->getBumpVectorContext());
}
void appendInitializer(CFGBlock *B, CXXCtorInitializer *I) {
B->appendInitializer(I, cfg->getBumpVectorContext());
@@ -387,47 +424,74 @@ private:
B->addSuccessor(S, cfg->getBumpVectorContext());
}
- /// TryResult - a class representing a variant over the values
- /// 'true', 'false', or 'unknown'. This is returned by tryEvaluateBool,
- /// and is used by the CFGBuilder to decide if a branch condition
- /// can be decided up front during CFG construction.
- class TryResult {
- int X;
- public:
- TryResult(bool b) : X(b ? 1 : 0) {}
- TryResult() : X(-1) {}
-
- bool isTrue() const { return X == 1; }
- bool isFalse() const { return X == 0; }
- bool isKnown() const { return X >= 0; }
- void negate() {
- assert(isKnown());
- X ^= 0x1;
- }
- };
+ /// Try and evaluate an expression to an integer constant.
+ bool tryEvaluate(Expr *S, Expr::EvalResult &outResult) {
+ if (!BuildOpts.PruneTriviallyFalseEdges)
+ return false;
+ return !S->isTypeDependent() &&
+ !S->isValueDependent() &&
+ S->Evaluate(outResult, *Context);
+ }
/// tryEvaluateBool - Try and evaluate the Stmt and return 0 or 1
/// if we can evaluate to a known value, otherwise return -1.
TryResult tryEvaluateBool(Expr *S) {
- if (!BuildOpts.PruneTriviallyFalseEdges)
- return TryResult();
-
Expr::EvalResult Result;
- if (!S->isTypeDependent() && !S->isValueDependent() &&
- S->Evaluate(Result, *Context)) {
- if (Result.Val.isInt())
- return Result.Val.getInt().getBoolValue();
- if (Result.Val.isLValue()) {
- Expr *e = Result.Val.getLValueBase();
- const CharUnits &c = Result.Val.getLValueOffset();
- if (!e && c.isZero())
- return false;
- }
+ if (!tryEvaluate(S, Result))
+ return TryResult();
+
+ if (Result.Val.isInt())
+ return Result.Val.getInt().getBoolValue();
+
+ if (Result.Val.isLValue()) {
+ Expr *e = Result.Val.getLValueBase();
+ const CharUnits &c = Result.Val.getLValueOffset();
+ if (!e && c.isZero())
+ return false;
}
return TryResult();
}
+
};
+inline bool AddStmtChoice::alwaysAdd(CFGBuilder &builder,
+ const Stmt *stmt) const {
+ return builder.alwaysAdd(stmt) || kind == AlwaysAdd;
+}
+
+bool CFGBuilder::alwaysAdd(const Stmt *stmt) {
+ if (!BuildOpts.forcedBlkExprs)
+ return false;
+
+ if (lastLookup == stmt) {
+ if (cachedEntry) {
+ assert(cachedEntry->first == stmt);
+ return true;
+ }
+ return false;
+ }
+
+ lastLookup = stmt;
+
+ // Perform the lookup!
+ CFG::BuildOptions::ForcedBlkExprs *fb = *BuildOpts.forcedBlkExprs;
+
+ if (!fb) {
+ // No need to update 'cachedEntry', since it will always be null.
+ assert(cachedEntry == 0);
+ return false;
+ }
+
+ CFG::BuildOptions::ForcedBlkExprs::iterator itr = fb->find(stmt);
+ if (itr == fb->end()) {
+ cachedEntry = 0;
+ return false;
+ }
+
+ cachedEntry = &*itr;
+ return true;
+}
+
// FIXME: Add support for dependent-sized array types in C++?
// Does it even make sense to build a CFG for an uninstantiated template?
static const VariableArrayType *FindVA(const Type *t) {
@@ -447,16 +511,11 @@ static const VariableArrayType *FindVA(const Type *t) {
/// body (compound statement). The ownership of the returned CFG is
/// transferred to the caller. If CFG construction fails, this method returns
/// NULL.
-CFG* CFGBuilder::buildCFG(const Decl *D, Stmt* Statement, ASTContext* C,
- CFG::BuildOptions BO) {
-
- Context = C;
+CFG* CFGBuilder::buildCFG(const Decl *D, Stmt* Statement) {
assert(cfg.get());
if (!Statement)
return NULL;
- BuildOpts = BO;
-
// Create an empty block that will serve as the exit block for the CFG. Since
// this is the first block added to the CFG, it will be implicitly registered
// as the exit block.
@@ -853,6 +912,9 @@ tryAgain:
case Stmt::CXXTryStmtClass:
return VisitCXXTryStmt(cast<CXXTryStmt>(S));
+ case Stmt::CXXForRangeStmtClass:
+ return VisitCXXForRangeStmt(cast<CXXForRangeStmt>(S));
+
case Stmt::DeclStmtClass:
return VisitDeclStmt(cast<DeclStmt>(S));
@@ -908,8 +970,9 @@ tryAgain:
case Stmt::ReturnStmtClass:
return VisitReturnStmt(cast<ReturnStmt>(S));
- case Stmt::SizeOfAlignOfExprClass:
- return VisitSizeOfAlignOfExpr(cast<SizeOfAlignOfExpr>(S), asc);
+ case Stmt::UnaryExprOrTypeTraitExprClass:
+ return VisitUnaryExprOrTypeTraitExpr(cast<UnaryExprOrTypeTraitExpr>(S),
+ asc);
case Stmt::StmtExprClass:
return VisitStmtExpr(cast<StmtExpr>(S), asc);
@@ -926,9 +989,9 @@ tryAgain:
}
CFGBlock *CFGBuilder::VisitStmt(Stmt *S, AddStmtChoice asc) {
- if (asc.alwaysAdd()) {
+ if (asc.alwaysAdd(*this, S)) {
autoCreateBlock();
- appendStmt(Block, S, asc);
+ appendStmt(Block, S);
}
return VisitChildren(S);
@@ -949,9 +1012,9 @@ CFGBlock *CFGBuilder::VisitAddrLabelExpr(AddrLabelExpr *A,
AddStmtChoice asc) {
AddressTakenLabels.insert(A->getLabel());
- if (asc.alwaysAdd()) {
+ if (asc.alwaysAdd(*this, A)) {
autoCreateBlock();
- appendStmt(Block, A, asc);
+ appendStmt(Block, A);
}
return Block;
@@ -959,9 +1022,9 @@ CFGBlock *CFGBuilder::VisitAddrLabelExpr(AddrLabelExpr *A,
CFGBlock *CFGBuilder::VisitUnaryOperator(UnaryOperator *U,
AddStmtChoice asc) {
- if (asc.alwaysAdd()) {
+ if (asc.alwaysAdd(*this, U)) {
autoCreateBlock();
- appendStmt(Block, U, asc);
+ appendStmt(Block, U);
}
return Visit(U->getSubExpr(), AddStmtChoice());
@@ -971,7 +1034,7 @@ CFGBlock *CFGBuilder::VisitBinaryOperator(BinaryOperator *B,
AddStmtChoice asc) {
if (B->isLogicalOp()) { // && or ||
CFGBlock* ConfluenceBlock = Block ? Block : createBlock();
- appendStmt(ConfluenceBlock, B, asc);
+ appendStmt(ConfluenceBlock, B);
if (badCFG)
return 0;
@@ -1016,23 +1079,23 @@ CFGBlock *CFGBuilder::VisitBinaryOperator(BinaryOperator *B,
if (B->getOpcode() == BO_Comma) { // ,
autoCreateBlock();
- appendStmt(Block, B, asc);
+ appendStmt(Block, B);
addStmt(B->getRHS());
return addStmt(B->getLHS());
}
if (B->isAssignmentOp()) {
- if (asc.alwaysAdd()) {
+ if (asc.alwaysAdd(*this, B)) {
autoCreateBlock();
- appendStmt(Block, B, asc);
+ appendStmt(Block, B);
}
Visit(B->getLHS());
return Visit(B->getRHS());
}
- if (asc.alwaysAdd()) {
+ if (asc.alwaysAdd(*this, B)) {
autoCreateBlock();
- appendStmt(Block, B, asc);
+ appendStmt(Block, B);
}
CFGBlock *RBlock = Visit(B->getRHS());
@@ -1044,9 +1107,9 @@ CFGBlock *CFGBuilder::VisitBinaryOperator(BinaryOperator *B,
}
CFGBlock *CFGBuilder::VisitBlockExpr(BlockExpr *E, AddStmtChoice asc) {
- if (asc.alwaysAdd()) {
+ if (asc.alwaysAdd(*this, E)) {
autoCreateBlock();
- appendStmt(Block, E, asc);
+ appendStmt(Block, E);
}
return Block;
}
@@ -1073,7 +1136,7 @@ CFGBlock *CFGBuilder::VisitBreakStmt(BreakStmt *B) {
return Block;
}
-static bool CanThrow(Expr *E) {
+static bool CanThrow(Expr *E, ASTContext &Ctx) {
QualType Ty = E->getType();
if (Ty->isFunctionPointerType())
Ty = Ty->getAs<PointerType>()->getPointeeType();
@@ -1083,7 +1146,7 @@ static bool CanThrow(Expr *E) {
const FunctionType *FT = Ty->getAs<FunctionType>();
if (FT) {
if (const FunctionProtoType *Proto = dyn_cast<FunctionProtoType>(FT))
- if (Proto->hasEmptyExceptionSpec())
+ if (Proto->isNothrow(Ctx))
return false;
}
return true;
@@ -1099,7 +1162,7 @@ CFGBlock *CFGBuilder::VisitCallExpr(CallExpr *C, AddStmtChoice asc) {
bool AddEHEdge = false;
// Languages without exceptions are assumed to not throw.
- if (Context->getLangOptions().areExceptionsEnabled()) {
+ if (Context->getLangOptions().Exceptions) {
if (BuildOpts.AddEHEdges)
AddEHEdge = true;
}
@@ -1111,7 +1174,7 @@ CFGBlock *CFGBuilder::VisitCallExpr(CallExpr *C, AddStmtChoice asc) {
AddEHEdge = false;
}
- if (!CanThrow(C->getCallee()))
+ if (!CanThrow(C->getCallee(), *Context))
AddEHEdge = false;
if (!NoReturn && !AddEHEdge)
@@ -1124,7 +1187,7 @@ CFGBlock *CFGBuilder::VisitCallExpr(CallExpr *C, AddStmtChoice asc) {
}
Block = createBlock(!NoReturn);
- appendStmt(Block, C, asc);
+ appendStmt(Block, C);
if (NoReturn) {
// Wire this to the exit block directly.
@@ -1144,7 +1207,7 @@ CFGBlock *CFGBuilder::VisitCallExpr(CallExpr *C, AddStmtChoice asc) {
CFGBlock *CFGBuilder::VisitChooseExpr(ChooseExpr *C,
AddStmtChoice asc) {
CFGBlock* ConfluenceBlock = Block ? Block : createBlock();
- appendStmt(ConfluenceBlock, C, asc);
+ appendStmt(ConfluenceBlock, C);
if (badCFG)
return 0;
@@ -1197,7 +1260,7 @@ CFGBlock *CFGBuilder::VisitConditionalOperator(AbstractConditionalOperator *C,
// Create the confluence block that will "merge" the results of the ternary
// expression.
CFGBlock* ConfluenceBlock = Block ? Block : createBlock();
- appendStmt(ConfluenceBlock, C, asc);
+ appendStmt(ConfluenceBlock, C);
if (badCFG)
return 0;
@@ -1353,7 +1416,7 @@ CFGBlock* CFGBuilder::VisitIfStmt(IfStmt* I) {
addAutomaticObjDtors(ScopePos, BeginScopePos, I);
}
- // The block we were proccessing is now finished. Make it the successor
+ // The block we were processing is now finished. Make it the successor
// block.
if (Block) {
Succ = Block;
@@ -1436,7 +1499,7 @@ CFGBlock* CFGBuilder::VisitIfStmt(IfStmt* I) {
if (VarDecl *VD = I->getConditionVariable()) {
if (Expr *Init = VD->getInit()) {
autoCreateBlock();
- appendStmt(Block, I, AddStmtChoice::AlwaysAdd);
+ appendStmt(Block, I->getConditionVariableDeclStmt());
addStmt(Init);
}
}
@@ -1574,7 +1637,7 @@ CFGBlock* CFGBuilder::VisitForStmt(ForStmt* F) {
if (VarDecl *VD = F->getConditionVariable()) {
if (Expr *Init = VD->getInit()) {
autoCreateBlock();
- appendStmt(Block, F, AddStmtChoice::AlwaysAdd);
+ appendStmt(Block, F->getConditionVariableDeclStmt());
EntryConditionBlock = addStmt(Init);
assert(Block == EntryConditionBlock);
}
@@ -1672,9 +1735,9 @@ CFGBlock* CFGBuilder::VisitForStmt(ForStmt* F) {
}
CFGBlock *CFGBuilder::VisitMemberExpr(MemberExpr *M, AddStmtChoice asc) {
- if (asc.alwaysAdd()) {
+ if (asc.alwaysAdd(*this, M)) {
autoCreateBlock();
- appendStmt(Block, M, asc);
+ appendStmt(Block, M);
}
return Visit(M->getBase());
}
@@ -1736,7 +1799,7 @@ CFGBlock* CFGBuilder::VisitObjCForCollectionStmt(ObjCForCollectionStmt* S) {
Block = ExitConditionBlock;
// Walk the 'element' expression to see if there are any side-effects. We
- // generate new blocks as necesary. We DON'T add the statement by default to
+ // generate new blocks as necessary. We DON'T add the statement by default to
// the CFG unless it contains control-flow.
EntryConditionBlock = Visit(S->getElement(), AddStmtChoice::NotAlwaysAdd);
if (Block) {
@@ -1799,7 +1862,7 @@ CFGBlock* CFGBuilder::VisitObjCAtSynchronizedStmt(ObjCAtSynchronizedStmt* S) {
// Add the @synchronized to the CFG.
autoCreateBlock();
- appendStmt(Block, S, AddStmtChoice::AlwaysAdd);
+ appendStmt(Block, S);
// Inline the sync expression.
return addStmt(S->getSynchExpr());
@@ -1858,7 +1921,7 @@ CFGBlock* CFGBuilder::VisitWhileStmt(WhileStmt* W) {
if (VarDecl *VD = W->getConditionVariable()) {
if (Expr *Init = VD->getInit()) {
autoCreateBlock();
- appendStmt(Block, W, AddStmtChoice::AlwaysAdd);
+ appendStmt(Block, W->getConditionVariableDeclStmt());
EntryConditionBlock = addStmt(Init);
assert(Block == EntryConditionBlock);
}
@@ -2105,28 +2168,30 @@ CFGBlock* CFGBuilder::VisitContinueStmt(ContinueStmt* C) {
return Block;
}
-CFGBlock *CFGBuilder::VisitSizeOfAlignOfExpr(SizeOfAlignOfExpr *E,
- AddStmtChoice asc) {
+CFGBlock *CFGBuilder::VisitUnaryExprOrTypeTraitExpr(UnaryExprOrTypeTraitExpr *E,
+ AddStmtChoice asc) {
- if (asc.alwaysAdd()) {
+ if (asc.alwaysAdd(*this, E)) {
autoCreateBlock();
appendStmt(Block, E);
}
// VLA types have expressions that must be evaluated.
+ CFGBlock *lastBlock = Block;
+
if (E->isArgumentType()) {
for (const VariableArrayType *VA =FindVA(E->getArgumentType().getTypePtr());
VA != 0; VA = FindVA(VA->getElementType().getTypePtr()))
- addStmt(VA->getSizeExpr());
+ lastBlock = addStmt(VA->getSizeExpr());
}
- return Block;
+ return lastBlock;
}
/// VisitStmtExpr - Utility method to handle (nested) statement
/// expressions (a GCC extension).
CFGBlock* CFGBuilder::VisitStmtExpr(StmtExpr *SE, AddStmtChoice asc) {
- if (asc.alwaysAdd()) {
+ if (asc.alwaysAdd(*this, SE)) {
autoCreateBlock();
appendStmt(Block, SE);
}
@@ -2180,6 +2245,18 @@ CFGBlock* CFGBuilder::VisitSwitchStmt(SwitchStmt* Terminator) {
assert(Terminator->getBody() && "switch must contain a non-NULL body");
Block = NULL;
+ // For pruning unreachable case statements, save the current state
+ // for tracking the condition value.
+ SaveAndRestore<bool> save_switchExclusivelyCovered(switchExclusivelyCovered,
+ false);
+
+ // Determine if the switch condition can be explicitly evaluated.
+ assert(Terminator->getCond() && "switch condition must be non-NULL");
+ Expr::EvalResult result;
+ bool b = tryEvaluate(Terminator->getCond(), result);
+ SaveAndRestore<Expr::EvalResult*> save_switchCond(switchCond,
+ b ? &result : 0);
+
// If body is not a compound statement create implicit scope
// and add destructors.
if (!isa<CompoundStmt>(Terminator->getBody()))
@@ -2192,12 +2269,14 @@ CFGBlock* CFGBuilder::VisitSwitchStmt(SwitchStmt* Terminator) {
}
// If we have no "default:" case, the default transition is to the code
- // following the switch body.
- addSuccessor(SwitchTerminatedBlock, DefaultCaseBlock);
+ // following the switch body. Moreover, take into account if all the
+ // cases of a switch are covered (e.g., switching on an enum value).
+ addSuccessor(SwitchTerminatedBlock,
+ switchExclusivelyCovered || Terminator->isAllEnumCasesCovered()
+ ? 0 : DefaultCaseBlock);
// Add the terminator and condition in the switch block.
SwitchTerminatedBlock->setTerminator(Terminator);
- assert(Terminator->getCond() && "switch condition must be non-NULL");
Block = SwitchTerminatedBlock;
Block = addStmt(Terminator->getCond());
@@ -2206,19 +2285,60 @@ CFGBlock* CFGBuilder::VisitSwitchStmt(SwitchStmt* Terminator) {
if (VarDecl *VD = Terminator->getConditionVariable()) {
if (Expr *Init = VD->getInit()) {
autoCreateBlock();
- appendStmt(Block, Terminator, AddStmtChoice::AlwaysAdd);
+ appendStmt(Block, Terminator->getConditionVariableDeclStmt());
addStmt(Init);
}
}
return Block;
}
+
+static bool shouldAddCase(bool &switchExclusivelyCovered,
+ const Expr::EvalResult *switchCond,
+ const CaseStmt *CS,
+ ASTContext &Ctx) {
+ if (!switchCond)
+ return true;
+
+ bool addCase = false;
+
+ if (!switchExclusivelyCovered) {
+ if (switchCond->Val.isInt()) {
+ // Evaluate the LHS of the case value.
+ Expr::EvalResult V1;
+ CS->getLHS()->Evaluate(V1, Ctx);
+ assert(V1.Val.isInt());
+ const llvm::APSInt &condInt = switchCond->Val.getInt();
+ const llvm::APSInt &lhsInt = V1.Val.getInt();
+
+ if (condInt == lhsInt) {
+ addCase = true;
+ switchExclusivelyCovered = true;
+ }
+ else if (condInt < lhsInt) {
+ if (const Expr *RHS = CS->getRHS()) {
+ // Evaluate the RHS of the case value.
+ Expr::EvalResult V2;
+ RHS->Evaluate(V2, Ctx);
+ assert(V2.Val.isInt());
+ if (V2.Val.getInt() <= condInt) {
+ addCase = true;
+ switchExclusivelyCovered = true;
+ }
+ }
+ }
+ }
+ else
+ addCase = true;
+ }
+ return addCase;
+}
CFGBlock* CFGBuilder::VisitCaseStmt(CaseStmt* CS) {
// CaseStmts are essentially labels, so they are the first statement in a
// block.
CFGBlock *TopBlock = 0, *LastBlock = 0;
-
+
if (Stmt *Sub = CS->getSubStmt()) {
// For deeply nested chains of CaseStmts, instead of doing a recursion
// (which can blow out the stack), manually unroll and create blocks
@@ -2232,9 +2352,12 @@ CFGBlock* CFGBuilder::VisitCaseStmt(CaseStmt* CS) {
else
TopBlock = currentBlock;
- addSuccessor(SwitchTerminatedBlock, currentBlock);
- LastBlock = currentBlock;
+ addSuccessor(SwitchTerminatedBlock,
+ shouldAddCase(switchExclusivelyCovered, switchCond,
+ CS, *Context)
+ ? currentBlock : 0);
+ LastBlock = currentBlock;
CS = cast<CaseStmt>(Sub);
Sub = CS->getSubStmt();
}
@@ -2256,7 +2379,10 @@ CFGBlock* CFGBuilder::VisitCaseStmt(CaseStmt* CS) {
// Add this block to the list of successors for the block with the switch
// statement.
assert(SwitchTerminatedBlock);
- addSuccessor(SwitchTerminatedBlock, CaseBlock);
+ addSuccessor(SwitchTerminatedBlock,
+ shouldAddCase(switchExclusivelyCovered, switchCond,
+ CS, *Context)
+ ? CaseBlock : 0);
// We set Block to NULL to allow lazy creation of a new block (if necessary)
Block = NULL;
@@ -2391,6 +2517,122 @@ CFGBlock* CFGBuilder::VisitCXXCatchStmt(CXXCatchStmt* CS) {
return CatchBlock;
}
+CFGBlock* CFGBuilder::VisitCXXForRangeStmt(CXXForRangeStmt* S) {
+ // C++0x for-range statements are specified as [stmt.ranged]:
+ //
+ // {
+ // auto && __range = range-init;
+ // for ( auto __begin = begin-expr,
+ // __end = end-expr;
+ // __begin != __end;
+ // ++__begin ) {
+ // for-range-declaration = *__begin;
+ // statement
+ // }
+ // }
+
+ // Save local scope position before the addition of the implicit variables.
+ SaveAndRestore<LocalScope::const_iterator> save_scope_pos(ScopePos);
+
+ // Create local scopes and destructors for range, begin and end variables.
+ if (Stmt *Range = S->getRangeStmt())
+ addLocalScopeForStmt(Range);
+ if (Stmt *BeginEnd = S->getBeginEndStmt())
+ addLocalScopeForStmt(BeginEnd);
+ addAutomaticObjDtors(ScopePos, save_scope_pos.get(), S);
+
+ LocalScope::const_iterator ContinueScopePos = ScopePos;
+
+ // "for" is a control-flow statement. Thus we stop processing the current
+ // block.
+ CFGBlock* LoopSuccessor = NULL;
+ if (Block) {
+ if (badCFG)
+ return 0;
+ LoopSuccessor = Block;
+ } else
+ LoopSuccessor = Succ;
+
+ // Save the current value for the break targets.
+ // All breaks should go to the code following the loop.
+ SaveAndRestore<JumpTarget> save_break(BreakJumpTarget);
+ BreakJumpTarget = JumpTarget(LoopSuccessor, ScopePos);
+
+ // The block for the __begin != __end expression.
+ CFGBlock* ConditionBlock = createBlock(false);
+ ConditionBlock->setTerminator(S);
+
+ // Now add the actual condition to the condition block.
+ if (Expr *C = S->getCond()) {
+ Block = ConditionBlock;
+ CFGBlock *BeginConditionBlock = addStmt(C);
+ if (badCFG)
+ return 0;
+ assert(BeginConditionBlock == ConditionBlock &&
+ "condition block in for-range was unexpectedly complex");
+ (void)BeginConditionBlock;
+ }
+
+ // The condition block is the implicit successor for the loop body as well as
+ // any code above the loop.
+ Succ = ConditionBlock;
+
+ // See if this is a known constant.
+ TryResult KnownVal(true);
+
+ if (S->getCond())
+ KnownVal = tryEvaluateBool(S->getCond());
+
+ // Now create the loop body.
+ {
+ assert(S->getBody());
+
+ // Save the current values for Block, Succ, and continue targets.
+ SaveAndRestore<CFGBlock*> save_Block(Block), save_Succ(Succ);
+ SaveAndRestore<JumpTarget> save_continue(ContinueJumpTarget);
+
+ // Generate increment code in its own basic block. This is the target of
+ // continue statements.
+ Block = 0;
+ Succ = addStmt(S->getInc());
+ ContinueJumpTarget = JumpTarget(Succ, ContinueScopePos);
+
+ // The starting block for the loop increment is the block that should
+ // represent the 'loop target' for looping back to the start of the loop.
+ ContinueJumpTarget.block->setLoopTarget(S);
+
+ // Finish up the increment block and prepare to start the loop body.
+ assert(Block);
+ if (badCFG)
+ return 0;
+ Block = 0;
+
+
+ // Add implicit scope and dtors for loop variable.
+ addLocalScopeAndDtors(S->getLoopVarStmt());
+
+ // Populate a new block to contain the loop body and loop variable.
+ Block = addStmt(S->getBody());
+ if (badCFG)
+ return 0;
+ Block = addStmt(S->getLoopVarStmt());
+ if (badCFG)
+ return 0;
+
+ // This new body block is a successor to our condition block.
+ addSuccessor(ConditionBlock, KnownVal.isFalse() ? 0 : Block);
+ }
+
+ // Link up the condition block with the code that follows the loop (the
+ // false branch).
+ addSuccessor(ConditionBlock, KnownVal.isTrue() ? 0 : LoopSuccessor);
+
+ // Add the initialization statements.
+ Block = createBlock();
+ addStmt(S->getBeginEndStmt());
+ return addStmt(S->getRangeStmt());
+}
+
CFGBlock *CFGBuilder::VisitExprWithCleanups(ExprWithCleanups *E,
AddStmtChoice asc) {
if (BuildOpts.AddImplicitDtors) {
@@ -2407,9 +2649,9 @@ CFGBlock *CFGBuilder::VisitExprWithCleanups(ExprWithCleanups *E,
CFGBlock *CFGBuilder::VisitCXXBindTemporaryExpr(CXXBindTemporaryExpr *E,
AddStmtChoice asc) {
- if (asc.alwaysAdd()) {
+ if (asc.alwaysAdd(*this, E)) {
autoCreateBlock();
- appendStmt(Block, E, asc);
+ appendStmt(Block, E);
// We do not want to propagate the AlwaysAdd property.
asc = asc.withAlwaysAdd(false);
@@ -2421,16 +2663,16 @@ CFGBlock *CFGBuilder::VisitCXXConstructExpr(CXXConstructExpr *C,
AddStmtChoice asc) {
autoCreateBlock();
if (!C->isElidable())
- appendStmt(Block, C, asc.withAlwaysAdd(true));
+ appendStmt(Block, C);
return VisitChildren(C);
}
CFGBlock *CFGBuilder::VisitCXXFunctionalCastExpr(CXXFunctionalCastExpr *E,
AddStmtChoice asc) {
- if (asc.alwaysAdd()) {
+ if (asc.alwaysAdd(*this, E)) {
autoCreateBlock();
- appendStmt(Block, E, asc);
+ appendStmt(Block, E);
// We do not want to propagate the AlwaysAdd property.
asc = asc.withAlwaysAdd(false);
}
@@ -2440,22 +2682,22 @@ CFGBlock *CFGBuilder::VisitCXXFunctionalCastExpr(CXXFunctionalCastExpr *E,
CFGBlock *CFGBuilder::VisitCXXTemporaryObjectExpr(CXXTemporaryObjectExpr *C,
AddStmtChoice asc) {
autoCreateBlock();
- appendStmt(Block, C, asc.withAlwaysAdd(true));
+ appendStmt(Block, C);
return VisitChildren(C);
}
CFGBlock *CFGBuilder::VisitCXXMemberCallExpr(CXXMemberCallExpr *C,
AddStmtChoice asc) {
autoCreateBlock();
- appendStmt(Block, C, asc.withAlwaysAdd(true));
+ appendStmt(Block, C);
return VisitChildren(C);
}
CFGBlock *CFGBuilder::VisitImplicitCastExpr(ImplicitCastExpr *E,
AddStmtChoice asc) {
- if (asc.alwaysAdd()) {
+ if (asc.alwaysAdd(*this, E)) {
autoCreateBlock();
- appendStmt(Block, E, asc);
+ appendStmt(Block, E);
}
return Visit(E->getSubExpr(), AddStmtChoice());
}
@@ -2699,9 +2941,53 @@ CFGBlock* CFG::createBlock() {
/// buildCFG - Constructs a CFG from an AST. Ownership of the returned
/// CFG is returned to the caller.
CFG* CFG::buildCFG(const Decl *D, Stmt* Statement, ASTContext *C,
- BuildOptions BO) {
- CFGBuilder Builder;
- return Builder.buildCFG(D, Statement, C, BO);
+ const BuildOptions &BO) {
+ CFGBuilder Builder(C, BO);
+ return Builder.buildCFG(D, Statement);
+}
+
+const CXXDestructorDecl *
+CFGImplicitDtor::getDestructorDecl(ASTContext &astContext) const {
+ switch (getKind()) {
+ case CFGElement::Invalid:
+ case CFGElement::Statement:
+ case CFGElement::Initializer:
+ llvm_unreachable("getDestructorDecl should only be used with "
+ "ImplicitDtors");
+ case CFGElement::AutomaticObjectDtor: {
+ const VarDecl *var = cast<CFGAutomaticObjDtor>(this)->getVarDecl();
+ QualType ty = var->getType();
+ ty = ty.getNonReferenceType();
+ if (const ArrayType *arrayType = astContext.getAsArrayType(ty)) {
+ ty = arrayType->getElementType();
+ }
+ const RecordType *recordType = ty->getAs<RecordType>();
+ const CXXRecordDecl *classDecl =
+ cast<CXXRecordDecl>(recordType->getDecl());
+ return classDecl->getDestructor();
+ }
+ case CFGElement::TemporaryDtor: {
+ const CXXBindTemporaryExpr *bindExpr =
+ cast<CFGTemporaryDtor>(this)->getBindTemporaryExpr();
+ const CXXTemporary *temp = bindExpr->getTemporary();
+ return temp->getDestructor();
+ }
+ case CFGElement::BaseDtor:
+ case CFGElement::MemberDtor:
+
+ // Not yet supported.
+ return 0;
+ }
+ llvm_unreachable("getKind() returned bogus value");
+ return 0;
+}
+
+bool CFGImplicitDtor::isNoReturn(ASTContext &astContext) const {
+ if (const CXXDestructorDecl *cdecl = getDestructorDecl(astContext)) {
+ QualType ty = cdecl->getType();
+ return cast<FunctionType>(ty)->getNoReturnAttr();
+ }
+ return false;
}
//===----------------------------------------------------------------------===//
@@ -2740,8 +3026,8 @@ static BlkExprMapTy* PopulateBlkExprMap(CFG& cfg) {
for (CFG::iterator I=cfg.begin(), E=cfg.end(); I != E; ++I)
for (CFGBlock::iterator BI=(*I)->begin(), EI=(*I)->end(); BI != EI; ++BI)
- if (CFGStmt S = BI->getAs<CFGStmt>())
- FindSubExprAssignments(S, SubExprAssignments);
+ if (const CFGStmt *S = BI->getAs<CFGStmt>())
+ FindSubExprAssignments(S->getStmt(), SubExprAssignments);
for (CFG::iterator I=cfg.begin(), E=cfg.end(); I != E; ++I) {
@@ -2749,10 +3035,10 @@ static BlkExprMapTy* PopulateBlkExprMap(CFG& cfg) {
// block-level that are block-level expressions.
for (CFGBlock::iterator BI=(*I)->begin(), EI=(*I)->end(); BI != EI; ++BI) {
- CFGStmt CS = BI->getAs<CFGStmt>();
- if (!CS.isValid())
+ const CFGStmt *CS = BI->getAs<CFGStmt>();
+ if (!CS)
continue;
- if (Expr* Exp = dyn_cast<Expr>(CS.getStmt())) {
+ if (Expr* Exp = dyn_cast<Expr>(CS->getStmt())) {
if (BinaryOperator* B = dyn_cast<BinaryOperator>(Exp)) {
// Assignment expressions that are not nested within another
@@ -2814,15 +3100,15 @@ unsigned CFG::getNumBlkExprs() {
bool CFGBlock::FilterEdge(const CFGBlock::FilterOptions &F,
const CFGBlock *From, const CFGBlock *To) {
- if (F.IgnoreDefaultsWithCoveredEnums) {
+ if (To && F.IgnoreDefaultsWithCoveredEnums) {
// If the 'To' has no label or is labeled but the label isn't a
// CaseStmt then filter this edge.
if (const SwitchStmt *S =
- dyn_cast_or_null<SwitchStmt>(From->getTerminator().getStmt())) {
+ dyn_cast_or_null<SwitchStmt>(From->getTerminator().getStmt())) {
if (S->isAllEnumCasesCovered()) {
- const Stmt *L = To->getLabel();
- if (!L || !isa<CaseStmt>(L))
- return true;
+ const Stmt *L = To->getLabel();
+ if (!L || !isa<CaseStmt>(L))
+ return true;
}
}
}
@@ -2845,8 +3131,8 @@ CFG::~CFG() {
namespace {
class StmtPrinterHelper : public PrinterHelper {
- typedef llvm::DenseMap<Stmt*,std::pair<unsigned,unsigned> > StmtMapTy;
- typedef llvm::DenseMap<Decl*,std::pair<unsigned,unsigned> > DeclMapTy;
+ typedef llvm::DenseMap<const Stmt*,std::pair<unsigned,unsigned> > StmtMapTy;
+ typedef llvm::DenseMap<const Decl*,std::pair<unsigned,unsigned> > DeclMapTy;
StmtMapTy StmtMap;
DeclMapTy DeclMap;
signed currentBlock;
@@ -2855,42 +3141,62 @@ class StmtPrinterHelper : public PrinterHelper {
public:
StmtPrinterHelper(const CFG* cfg, const LangOptions &LO)
- : currentBlock(0), currentStmt(0), LangOpts(LO) {
+ : currentBlock(0), currentStmt(0), LangOpts(LO)
+ {
for (CFG::const_iterator I = cfg->begin(), E = cfg->end(); I != E; ++I ) {
unsigned j = 1;
for (CFGBlock::const_iterator BI = (*I)->begin(), BEnd = (*I)->end() ;
BI != BEnd; ++BI, ++j ) {
- if (CFGStmt SE = BI->getAs<CFGStmt>()) {
+ if (const CFGStmt *SE = BI->getAs<CFGStmt>()) {
+ const Stmt *stmt= SE->getStmt();
std::pair<unsigned, unsigned> P((*I)->getBlockID(), j);
- StmtMap[SE] = P;
-
- if (DeclStmt* DS = dyn_cast<DeclStmt>(SE.getStmt())) {
- DeclMap[DS->getSingleDecl()] = P;
-
- } else if (IfStmt* IS = dyn_cast<IfStmt>(SE.getStmt())) {
- if (VarDecl* VD = IS->getConditionVariable())
- DeclMap[VD] = P;
-
- } else if (ForStmt* FS = dyn_cast<ForStmt>(SE.getStmt())) {
- if (VarDecl* VD = FS->getConditionVariable())
- DeclMap[VD] = P;
-
- } else if (WhileStmt* WS = dyn_cast<WhileStmt>(SE.getStmt())) {
- if (VarDecl* VD = WS->getConditionVariable())
- DeclMap[VD] = P;
-
- } else if (SwitchStmt* SS = dyn_cast<SwitchStmt>(SE.getStmt())) {
- if (VarDecl* VD = SS->getConditionVariable())
- DeclMap[VD] = P;
-
- } else if (CXXCatchStmt* CS = dyn_cast<CXXCatchStmt>(SE.getStmt())) {
- if (VarDecl* VD = CS->getExceptionDecl())
- DeclMap[VD] = P;
+ StmtMap[stmt] = P;
+
+ switch (stmt->getStmtClass()) {
+ case Stmt::DeclStmtClass:
+ DeclMap[cast<DeclStmt>(stmt)->getSingleDecl()] = P;
+ break;
+ case Stmt::IfStmtClass: {
+ const VarDecl *var = cast<IfStmt>(stmt)->getConditionVariable();
+ if (var)
+ DeclMap[var] = P;
+ break;
+ }
+ case Stmt::ForStmtClass: {
+ const VarDecl *var = cast<ForStmt>(stmt)->getConditionVariable();
+ if (var)
+ DeclMap[var] = P;
+ break;
+ }
+ case Stmt::WhileStmtClass: {
+ const VarDecl *var =
+ cast<WhileStmt>(stmt)->getConditionVariable();
+ if (var)
+ DeclMap[var] = P;
+ break;
+ }
+ case Stmt::SwitchStmtClass: {
+ const VarDecl *var =
+ cast<SwitchStmt>(stmt)->getConditionVariable();
+ if (var)
+ DeclMap[var] = P;
+ break;
+ }
+ case Stmt::CXXCatchStmtClass: {
+ const VarDecl *var =
+ cast<CXXCatchStmt>(stmt)->getExceptionDecl();
+ if (var)
+ DeclMap[var] = P;
+ break;
+ }
+ default:
+ break;
}
}
}
}
}
+
virtual ~StmtPrinterHelper() {}
@@ -2913,7 +3219,7 @@ public:
return true;
}
- bool handleDecl(Decl* D, llvm::raw_ostream& OS) {
+ bool handleDecl(const Decl* D, llvm::raw_ostream& OS) {
DeclMapTy::iterator I = DeclMap.find(D);
if (I == DeclMap.end())
@@ -3031,8 +3337,8 @@ public:
static void print_elem(llvm::raw_ostream &OS, StmtPrinterHelper* Helper,
const CFGElement &E) {
- if (CFGStmt CS = E.getAs<CFGStmt>()) {
- Stmt *S = CS;
+ if (const CFGStmt *CS = E.getAs<CFGStmt>()) {
+ Stmt *S = CS->getStmt();
if (Helper) {
@@ -3069,8 +3375,8 @@ static void print_elem(llvm::raw_ostream &OS, StmtPrinterHelper* Helper,
if (isa<Expr>(S))
OS << '\n';
- } else if (CFGInitializer IE = E.getAs<CFGInitializer>()) {
- CXXCtorInitializer* I = IE;
+ } else if (const CFGInitializer *IE = E.getAs<CFGInitializer>()) {
+ const CXXCtorInitializer *I = IE->getInitializer();
if (I->isBaseInitializer())
OS << I->getBaseClass()->getAsCXXRecordDecl()->getName();
else OS << I->getAnyMember()->getName();
@@ -3084,8 +3390,8 @@ static void print_elem(llvm::raw_ostream &OS, StmtPrinterHelper* Helper,
OS << " (Base initializer)\n";
else OS << " (Member initializer)\n";
- } else if (CFGAutomaticObjDtor DE = E.getAs<CFGAutomaticObjDtor>()){
- VarDecl* VD = DE.getVarDecl();
+ } else if (const CFGAutomaticObjDtor *DE = E.getAs<CFGAutomaticObjDtor>()){
+ const VarDecl* VD = DE->getVarDecl();
Helper->handleDecl(VD, OS);
const Type* T = VD->getType().getTypePtr();
@@ -3097,13 +3403,13 @@ static void print_elem(llvm::raw_ostream &OS, StmtPrinterHelper* Helper,
OS << ".~" << T->getAsCXXRecordDecl()->getName().str() << "()";
OS << " (Implicit destructor)\n";
- } else if (CFGBaseDtor BE = E.getAs<CFGBaseDtor>()) {
- const CXXBaseSpecifier *BS = BE.getBaseSpecifier();
+ } else if (const CFGBaseDtor *BE = E.getAs<CFGBaseDtor>()) {
+ const CXXBaseSpecifier *BS = BE->getBaseSpecifier();
OS << "~" << BS->getType()->getAsCXXRecordDecl()->getName() << "()";
OS << " (Base object destructor)\n";
- } else if (CFGMemberDtor ME = E.getAs<CFGMemberDtor>()) {
- FieldDecl *FD = ME.getFieldDecl();
+ } else if (const CFGMemberDtor *ME = E.getAs<CFGMemberDtor>()) {
+ const FieldDecl *FD = ME->getFieldDecl();
const Type *T = FD->getType().getTypePtr();
if (const Type *ET = T->getArrayElementTypeNoTypeQual())
@@ -3113,8 +3419,8 @@ static void print_elem(llvm::raw_ostream &OS, StmtPrinterHelper* Helper,
OS << ".~" << T->getAsCXXRecordDecl()->getName() << "()";
OS << " (Member object destructor)\n";
- } else if (CFGTemporaryDtor TE = E.getAs<CFGTemporaryDtor>()) {
- CXXBindTemporaryExpr *BT = TE.getBindTemporaryExpr();
+ } else if (const CFGTemporaryDtor *TE = E.getAs<CFGTemporaryDtor>()) {
+ const CXXBindTemporaryExpr *BT = TE->getBindTemporaryExpr();
OS << "~" << BT->getType()->getAsCXXRecordDecl()->getName() << "()";
OS << " (Temporary object destructor)\n";
}
@@ -3344,32 +3650,6 @@ Stmt* CFGBlock::getTerminatorCondition() {
return E ? E->IgnoreParens() : NULL;
}
-bool CFGBlock::hasBinaryBranchTerminator() const {
- const Stmt *Terminator = this->Terminator;
- if (!Terminator)
- return false;
-
- Expr* E = NULL;
-
- switch (Terminator->getStmtClass()) {
- default:
- return false;
-
- case Stmt::ForStmtClass:
- case Stmt::WhileStmtClass:
- case Stmt::DoStmtClass:
- case Stmt::IfStmtClass:
- case Stmt::ChooseExprClass:
- case Stmt::BinaryConditionalOperatorClass:
- case Stmt::ConditionalOperatorClass:
- case Stmt::BinaryOperatorClass:
- return true;
- }
-
- return E ? E->IgnoreParens() : NULL;
-}
-
-
//===----------------------------------------------------------------------===//
// CFG Graphviz Visualization
//===----------------------------------------------------------------------===//
diff --git a/lib/Analysis/CFGReachabilityAnalysis.cpp b/lib/Analysis/CFGReachabilityAnalysis.cpp
index 77865849014a..65cd0898573c 100644
--- a/lib/Analysis/CFGReachabilityAnalysis.cpp
+++ b/lib/Analysis/CFGReachabilityAnalysis.cpp
@@ -19,10 +19,10 @@
using namespace clang;
-CFGReachabilityAnalysis::CFGReachabilityAnalysis(const CFG &cfg)
+CFGReverseBlockReachabilityAnalysis::CFGReverseBlockReachabilityAnalysis(const CFG &cfg)
: analyzed(cfg.getNumBlockIDs(), false) {}
-bool CFGReachabilityAnalysis::isReachable(const CFGBlock *Src,
+bool CFGReverseBlockReachabilityAnalysis::isReachable(const CFGBlock *Src,
const CFGBlock *Dst) {
const unsigned DstBlockID = Dst->getBlockID();
@@ -39,7 +39,7 @@ bool CFGReachabilityAnalysis::isReachable(const CFGBlock *Src,
// Maps reachability to a common node by walking the predecessors of the
// destination node.
-void CFGReachabilityAnalysis::mapReachability(const CFGBlock *Dst) {
+void CFGReverseBlockReachabilityAnalysis::mapReachability(const CFGBlock *Dst) {
llvm::SmallVector<const CFGBlock *, 11> worklist;
llvm::BitVector visited(analyzed.size());
diff --git a/lib/Analysis/CFGStmtMap.cpp b/lib/Analysis/CFGStmtMap.cpp
index 3a030f9bdd1e..1fd5eedfeb86 100644
--- a/lib/Analysis/CFGStmtMap.cpp
+++ b/lib/Analysis/CFGStmtMap.cpp
@@ -50,11 +50,11 @@ static void Accumulate(SMap &SM, CFGBlock *B) {
// First walk the block-level expressions.
for (CFGBlock::iterator I = B->begin(), E = B->end(); I != E; ++I) {
const CFGElement &CE = *I;
- CFGStmt CS = CE.getAs<CFGStmt>();
- if (!CS.isValid())
+ const CFGStmt *CS = CE.getAs<CFGStmt>();
+ if (!CS)
continue;
- CFGBlock *&Entry = SM[CS];
+ CFGBlock *&Entry = SM[CS->getStmt()];
// If 'Entry' is already initialized (e.g., a terminator was already),
// skip.
if (Entry)
diff --git a/lib/Analysis/CMakeLists.txt b/lib/Analysis/CMakeLists.txt
index 84b211f2cfca..967fc2930f42 100644
--- a/lib/Analysis/CMakeLists.txt
+++ b/lib/Analysis/CMakeLists.txt
@@ -13,7 +13,6 @@ add_clang_library(clangAnalysis
ReachableCode.cpp
ScanfFormatString.cpp
UninitializedValues.cpp
- UninitializedValuesV2.cpp
)
add_dependencies(clangAnalysis ClangAttrClasses ClangAttrList
diff --git a/lib/Analysis/CocoaConventions.cpp b/lib/Analysis/CocoaConventions.cpp
index 22b6c1aaf021..4c62f36e6c92 100644
--- a/lib/Analysis/CocoaConventions.cpp
+++ b/lib/Analysis/CocoaConventions.cpp
@@ -16,6 +16,7 @@
#include "clang/AST/Decl.h"
#include "clang/AST/DeclObjC.h"
#include "llvm/ADT/StringExtras.h"
+#include "llvm/Support/ErrorHandling.h"
using namespace clang;
using namespace ento;
@@ -35,84 +36,27 @@ using llvm::StringRef;
// not release it."
//
-static bool isWordEnd(char ch, char prev, char next) {
- return ch == '\0'
- || (islower(prev) && isupper(ch)) // xxxC
- || (isupper(prev) && isupper(ch) && islower(next)) // XXCreate
- || !isalpha(ch);
-}
-
-static const char* parseWord(const char* s) {
- char ch = *s, prev = '\0';
- assert(ch != '\0');
- char next = *(s+1);
- while (!isWordEnd(ch, prev, next)) {
- prev = ch;
- ch = next;
- next = *((++s)+1);
- }
- return s;
-}
-
-cocoa::NamingConvention cocoa::deriveNamingConvention(Selector S,
- bool ignorePrefix) {
- IdentifierInfo *II = S.getIdentifierInfoForSlot(0);
-
- if (!II)
- return NoConvention;
-
- const char *s = II->getNameStart();
-
- const char *orig = s;
- // A method/function name may contain a prefix. We don't know it is there,
- // however, until we encounter the first '_'.
- while (*s != '\0') {
- // Skip '_', numbers, ':', etc.
- if (*s == '_' || !isalpha(*s)) {
- ++s;
- continue;
- }
- break;
- }
-
- if (!ignorePrefix && s != orig)
+cocoa::NamingConvention cocoa::deriveNamingConvention(Selector S) {
+ switch (S.getMethodFamily()) {
+ case OMF_None:
+ case OMF_autorelease:
+ case OMF_dealloc:
+ case OMF_release:
+ case OMF_retain:
+ case OMF_retainCount:
return NoConvention;
- // Parse the first word, and look for specific keywords.
- const char *wordEnd = parseWord(s);
- assert(wordEnd > s);
- unsigned len = wordEnd - s;
+ case OMF_init:
+ return InitRule;
- switch (len) {
- default:
- return NoConvention;
- case 3:
- // Methods starting with 'new' follow the create rule.
- return (memcmp(s, "new", 3) == 0) ? CreateRule : NoConvention;
- case 4:
- // Methods starting with 'copy' follow the create rule.
- if (memcmp(s, "copy", 4) == 0)
- return CreateRule;
- // Methods starting with 'init' follow the init rule.
- if (memcmp(s, "init", 4) == 0)
- return InitRule;
- return NoConvention;
- case 5:
- return (memcmp(s, "alloc", 5) == 0) ? CreateRule : NoConvention;
- case 7:
- // Methods starting with 'mutableCopy' follow the create rule.
- if (memcmp(s, "mutable", 7) == 0) {
- // Look at the next word to see if it is "Copy".
- s = wordEnd;
- if (*s != '\0') {
- wordEnd = parseWord(s);
- len = wordEnd - s;
- if (len == 4 && memcmp(s, "Copy", 4) == 0)
- return CreateRule;
- }
- }
- return NoConvention;
+ case OMF_alloc:
+ case OMF_copy:
+ case OMF_mutableCopy:
+ case OMF_new:
+ return CreateRule;
}
+ llvm_unreachable("unexpected naming convention");
+ return NoConvention;
}
bool cocoa::isRefType(QualType RetTy, llvm::StringRef Prefix,
diff --git a/lib/Analysis/PrintfFormatString.cpp b/lib/Analysis/PrintfFormatString.cpp
index db9f7f2c834e..00b0b279e4a0 100644
--- a/lib/Analysis/PrintfFormatString.cpp
+++ b/lib/Analysis/PrintfFormatString.cpp
@@ -381,8 +381,32 @@ bool PrintfSpecifier::fixType(QualType QT) {
// Set length modifier
switch (BT->getKind()) {
- default:
- // The rest of the conversions are either optional or for non-builtin types
+ case BuiltinType::Bool:
+ case BuiltinType::WChar_U:
+ case BuiltinType::WChar_S:
+ case BuiltinType::Char16:
+ case BuiltinType::Char32:
+ case BuiltinType::UInt128:
+ case BuiltinType::Int128:
+ // Integral types which are non-trivial to correct.
+ return false;
+
+ case BuiltinType::Void:
+ case BuiltinType::NullPtr:
+ case BuiltinType::ObjCId:
+ case BuiltinType::ObjCClass:
+ case BuiltinType::ObjCSel:
+ case BuiltinType::Dependent:
+ case BuiltinType::Overload:
+ case BuiltinType::BoundMember:
+ case BuiltinType::UnknownAny:
+ // Misc other stuff which doesn't make sense here.
+ return false;
+
+ case BuiltinType::UInt:
+ case BuiltinType::Int:
+ case BuiltinType::Float:
+ case BuiltinType::Double:
LM.setKind(LengthModifier::None);
break;
@@ -398,8 +422,6 @@ bool PrintfSpecifier::fixType(QualType QT) {
LM.setKind(LengthModifier::AsShort);
break;
- case BuiltinType::WChar_S:
- case BuiltinType::WChar_U:
case BuiltinType::Long:
case BuiltinType::ULong:
LM.setKind(LengthModifier::AsLong);
@@ -429,24 +451,19 @@ bool PrintfSpecifier::fixType(QualType QT) {
else if (QT->isRealFloatingType()) {
CS.setKind(ConversionSpecifier::fArg);
}
- else if (QT->isPointerType()) {
- CS.setKind(ConversionSpecifier::pArg);
- Precision.setHowSpecified(OptionalAmount::NotSpecified);
- HasAlternativeForm = 0;
- HasLeadingZeroes = 0;
- HasPlusPrefix = 0;
- }
else if (QT->isSignedIntegerType()) {
CS.setKind(ConversionSpecifier::dArg);
HasAlternativeForm = 0;
}
else if (QT->isUnsignedIntegerType()) {
- CS.setKind(ConversionSpecifier::uArg);
+ // Preserve the original formatting, e.g. 'X', 'o'.
+ if (!cast<PrintfConversionSpecifier>(CS).isUIntArg())
+ CS.setKind(ConversionSpecifier::uArg);
HasAlternativeForm = 0;
HasPlusPrefix = 0;
}
else {
- return false;
+ assert(0 && "Unexpected type");
}
return true;
diff --git a/lib/Analysis/ReachableCode.cpp b/lib/Analysis/ReachableCode.cpp
index 7afa586479b3..9ac456f53a67 100644
--- a/lib/Analysis/ReachableCode.cpp
+++ b/lib/Analysis/ReachableCode.cpp
@@ -31,11 +31,11 @@ static SourceLocation GetUnreachableLoc(const CFGBlock &b, SourceRange &R1,
R1 = R2 = SourceRange();
if (sn < b.size()) {
- CFGStmt CS = b[sn].getAs<CFGStmt>();
+ const CFGStmt *CS = b[sn].getAs<CFGStmt>();
if (!CS)
return SourceLocation();
- S = CS.getStmt();
+ S = CS->getStmt();
} else if (b.getTerminator())
S = b.getTerminator();
else
@@ -49,7 +49,7 @@ static SourceLocation GetUnreachableLoc(const CFGBlock &b, SourceRange &R1,
const BinaryOperator *BO = cast<BinaryOperator>(S);
if (BO->getOpcode() == BO_Comma) {
if (sn+1 < b.size())
- return b[sn+1].getAs<CFGStmt>().getStmt()->getLocStart();
+ return b[sn+1].getAs<CFGStmt>()->getStmt()->getLocStart();
const CFGBlock *n = &b;
while (1) {
if (n->getTerminator())
@@ -60,7 +60,7 @@ static SourceLocation GetUnreachableLoc(const CFGBlock &b, SourceRange &R1,
if (n->pred_size() != 1)
return SourceLocation();
if (!n->empty())
- return n[0][0].getAs<CFGStmt>().getStmt()->getLocStart();
+ return n[0][0].getAs<CFGStmt>()->getStmt()->getLocStart();
}
}
R1 = BO->getLHS()->getSourceRange();
@@ -193,7 +193,7 @@ unsigned ScanReachableFromBlock(const CFGBlock &Start,
unsigned count = 0;
llvm::SmallVector<const CFGBlock*, 32> WL;
- // Prep work queue
+ // Prep work queue
Reachable.set(Start.getBlockID());
++count;
WL.push_back(&Start);
diff --git a/lib/Analysis/UninitializedValues.cpp b/lib/Analysis/UninitializedValues.cpp
index c08cbedf4b94..88a2db751a43 100644
--- a/lib/Analysis/UninitializedValues.cpp
+++ b/lib/Analysis/UninitializedValues.cpp
@@ -7,311 +7,723 @@
//
//===----------------------------------------------------------------------===//
//
-// This file implements Uninitialized Values analysis for source-level CFGs.
+// This file implements uninitialized values analysis for source-level CFGs.
//
//===----------------------------------------------------------------------===//
-#include "clang/Analysis/Analyses/UninitializedValues.h"
+#include <utility>
+#include "llvm/ADT/Optional.h"
+#include "llvm/ADT/SmallVector.h"
+#include "llvm/ADT/BitVector.h"
+#include "llvm/ADT/DenseMap.h"
+#include "clang/AST/Decl.h"
+#include "clang/Analysis/CFG.h"
+#include "clang/Analysis/AnalysisContext.h"
#include "clang/Analysis/Visitors/CFGRecStmtDeclVisitor.h"
-#include "clang/Analysis/AnalysisDiagnostic.h"
-#include "clang/AST/ASTContext.h"
-#include "clang/Analysis/FlowSensitive/DataflowSolver.h"
-
-#include "llvm/ADT/SmallPtrSet.h"
+#include "clang/Analysis/Analyses/UninitializedValues.h"
+#include "clang/Analysis/Support/SaveAndRestore.h"
using namespace clang;
-//===----------------------------------------------------------------------===//
-// Dataflow initialization logic.
-//===----------------------------------------------------------------------===//
-
-namespace {
+static bool isTrackedVar(const VarDecl *vd, const DeclContext *dc) {
+ if (vd->isLocalVarDecl() && !vd->hasGlobalStorage() &&
+ !vd->isExceptionVariable() &&
+ vd->getDeclContext() == dc) {
+ QualType ty = vd->getType();
+ return ty->isScalarType() || ty->isVectorType();
+ }
+ return false;
+}
-class RegisterDecls
- : public CFGRecStmtDeclVisitor<RegisterDecls> {
+//------------------------------------------------------------------------====//
+// DeclToIndex: a mapping from Decls we track to value indices.
+//====------------------------------------------------------------------------//
- UninitializedValues::AnalysisDataTy& AD;
+namespace {
+class DeclToIndex {
+ llvm::DenseMap<const VarDecl *, unsigned> map;
public:
- RegisterDecls(UninitializedValues::AnalysisDataTy& ad) : AD(ad) {}
-
- void VisitVarDecl(VarDecl* VD) { AD.Register(VD); }
- CFG& getCFG() { return AD.getCFG(); }
+ DeclToIndex() {}
+
+ /// Compute the actual mapping from declarations to bits.
+ void computeMap(const DeclContext &dc);
+
+ /// Return the number of declarations in the map.
+ unsigned size() const { return map.size(); }
+
+ /// Returns the bit vector index for a given declaration.
+ llvm::Optional<unsigned> getValueIndex(const VarDecl *d) const;
};
+}
-} // end anonymous namespace
+void DeclToIndex::computeMap(const DeclContext &dc) {
+ unsigned count = 0;
+ DeclContext::specific_decl_iterator<VarDecl> I(dc.decls_begin()),
+ E(dc.decls_end());
+ for ( ; I != E; ++I) {
+ const VarDecl *vd = *I;
+ if (isTrackedVar(vd, &dc))
+ map[vd] = count++;
+ }
+}
-void UninitializedValues::InitializeValues(const CFG& cfg) {
- RegisterDecls R(getAnalysisData());
- cfg.VisitBlockStmts(R);
+llvm::Optional<unsigned> DeclToIndex::getValueIndex(const VarDecl *d) const {
+ llvm::DenseMap<const VarDecl *, unsigned>::const_iterator I = map.find(d);
+ if (I == map.end())
+ return llvm::Optional<unsigned>();
+ return I->second;
}
-//===----------------------------------------------------------------------===//
-// Transfer functions.
-//===----------------------------------------------------------------------===//
+//------------------------------------------------------------------------====//
+// CFGBlockValues: dataflow values for CFG blocks.
+//====------------------------------------------------------------------------//
-namespace {
-class TransferFuncs
- : public CFGStmtVisitor<TransferFuncs,bool> {
+// These values are defined in such a way that a merge can be done using
+// a bitwise OR.
+enum Value { Unknown = 0x0, /* 00 */
+ Initialized = 0x1, /* 01 */
+ Uninitialized = 0x2, /* 10 */
+ MayUninitialized = 0x3 /* 11 */ };
- UninitializedValues::ValTy V;
- UninitializedValues::AnalysisDataTy& AD;
+static bool isUninitialized(const Value v) {
+ return v >= Uninitialized;
+}
+static bool isAlwaysUninit(const Value v) {
+ return v == Uninitialized;
+}
+
+namespace {
+class ValueVector {
+ llvm::BitVector vec;
public:
- TransferFuncs(UninitializedValues::AnalysisDataTy& ad) : AD(ad) {}
+ ValueVector() {}
+ ValueVector(unsigned size) : vec(size << 1) {}
+ void resize(unsigned n) { vec.resize(n << 1); }
+ void merge(const ValueVector &rhs) { vec |= rhs.vec; }
+ bool operator!=(const ValueVector &rhs) const { return vec != rhs.vec; }
+ void reset() { vec.reset(); }
+
+ class reference {
+ ValueVector &vv;
+ const unsigned idx;
+
+ reference(); // Undefined
+ public:
+ reference(ValueVector &vv, unsigned idx) : vv(vv), idx(idx) {}
+ ~reference() {}
+
+ reference &operator=(Value v) {
+ vv.vec[idx << 1] = (((unsigned) v) & 0x1) ? true : false;
+ vv.vec[(idx << 1) | 1] = (((unsigned) v) & 0x2) ? true : false;
+ return *this;
+ }
+ operator Value() {
+ unsigned x = (vv.vec[idx << 1] ? 1 : 0) | (vv.vec[(idx << 1) | 1] ? 2 :0);
+ return (Value) x;
+ }
+ };
+
+ reference operator[](unsigned idx) { return reference(*this, idx); }
+};
- UninitializedValues::ValTy& getVal() { return V; }
- CFG& getCFG() { return AD.getCFG(); }
+typedef std::pair<ValueVector *, ValueVector *> BVPair;
- void SetTopValue(UninitializedValues::ValTy& X) {
- X.setDeclValues(AD);
- X.resetBlkExprValues(AD);
+class CFGBlockValues {
+ const CFG &cfg;
+ BVPair *vals;
+ ValueVector scratch;
+ DeclToIndex declToIndex;
+
+ ValueVector &lazyCreate(ValueVector *&bv);
+public:
+ CFGBlockValues(const CFG &cfg);
+ ~CFGBlockValues();
+
+ unsigned getNumEntries() const { return declToIndex.size(); }
+
+ void computeSetOfDeclarations(const DeclContext &dc);
+ ValueVector &getValueVector(const CFGBlock *block,
+ const CFGBlock *dstBlock);
+
+ BVPair &getValueVectors(const CFGBlock *block, bool shouldLazyCreate);
+
+ void mergeIntoScratch(ValueVector const &source, bool isFirst);
+ bool updateValueVectorWithScratch(const CFGBlock *block);
+ bool updateValueVectors(const CFGBlock *block, const BVPair &newVals);
+
+ bool hasNoDeclarations() const {
+ return declToIndex.size() == 0;
}
+
+ bool hasEntry(const VarDecl *vd) const {
+ return declToIndex.getValueIndex(vd).hasValue();
+ }
+
+ bool hasValues(const CFGBlock *block);
+
+ void resetScratch();
+ ValueVector &getScratch() { return scratch; }
+
+ ValueVector::reference operator[](const VarDecl *vd);
+};
+} // end anonymous namespace
- bool VisitDeclRefExpr(DeclRefExpr* DR);
- bool VisitBinaryOperator(BinaryOperator* B);
- bool VisitUnaryOperator(UnaryOperator* U);
- bool VisitStmt(Stmt* S);
- bool VisitCallExpr(CallExpr* C);
- bool VisitDeclStmt(DeclStmt* D);
- bool VisitAbstractConditionalOperator(AbstractConditionalOperator* C);
- bool BlockStmt_VisitObjCForCollectionStmt(ObjCForCollectionStmt* S);
-
- bool Visit(Stmt *S);
- bool BlockStmt_VisitExpr(Expr* E);
+CFGBlockValues::CFGBlockValues(const CFG &c) : cfg(c), vals(0) {
+ unsigned n = cfg.getNumBlockIDs();
+ if (!n)
+ return;
+ vals = new std::pair<ValueVector*, ValueVector*>[n];
+ memset((void*)vals, 0, sizeof(*vals) * n);
+}
- void VisitTerminator(CFGBlock* B) { }
-
- void setCurrentBlock(const CFGBlock *block) {}
-};
+CFGBlockValues::~CFGBlockValues() {
+ unsigned n = cfg.getNumBlockIDs();
+ if (n == 0)
+ return;
+ for (unsigned i = 0; i < n; ++i) {
+ delete vals[i].first;
+ delete vals[i].second;
+ }
+ delete [] vals;
+}
-static const bool Initialized = false;
-static const bool Uninitialized = true;
+void CFGBlockValues::computeSetOfDeclarations(const DeclContext &dc) {
+ declToIndex.computeMap(dc);
+ scratch.resize(declToIndex.size());
+}
-bool TransferFuncs::VisitDeclRefExpr(DeclRefExpr* DR) {
+ValueVector &CFGBlockValues::lazyCreate(ValueVector *&bv) {
+ if (!bv)
+ bv = new ValueVector(declToIndex.size());
+ return *bv;
+}
- if (VarDecl* VD = dyn_cast<VarDecl>(DR->getDecl()))
- if (VD->isLocalVarDecl()) {
+/// This function pattern matches for a '&&' or '||' that appears at
+/// the beginning of a CFGBlock that also (1) has a terminator and
+/// (2) has no other elements. If such an expression is found, it is returned.
+static BinaryOperator *getLogicalOperatorInChain(const CFGBlock *block) {
+ if (block->empty())
+ return 0;
+
+ const CFGStmt *cstmt = block->front().getAs<CFGStmt>();
+ if (!cstmt)
+ return 0;
+
+ BinaryOperator *b = llvm::dyn_cast_or_null<BinaryOperator>(cstmt->getStmt());
+
+ if (!b || !b->isLogicalOp())
+ return 0;
+
+ if (block->pred_size() == 2 &&
+ ((block->succ_size() == 2 && block->getTerminatorCondition() == b) ||
+ block->size() == 1))
+ return b;
+
+ return 0;
+}
- if (AD.Observer)
- AD.Observer->ObserveDeclRefExpr(V, AD, DR, VD);
+ValueVector &CFGBlockValues::getValueVector(const CFGBlock *block,
+ const CFGBlock *dstBlock) {
+ unsigned idx = block->getBlockID();
+ if (dstBlock && getLogicalOperatorInChain(block)) {
+ if (*block->succ_begin() == dstBlock)
+ return lazyCreate(vals[idx].first);
+ assert(*(block->succ_begin()+1) == dstBlock);
+ return lazyCreate(vals[idx].second);
+ }
- // Pseudo-hack to prevent cascade of warnings. If an accessed variable
- // is uninitialized, then we are already going to flag a warning for
- // this variable, which a "source" of uninitialized values.
- // We can otherwise do a full "taint" of uninitialized values. The
- // client has both options by toggling AD.FullUninitTaint.
+ assert(vals[idx].second == 0);
+ return lazyCreate(vals[idx].first);
+}
- if (AD.FullUninitTaint)
- return V(VD,AD);
- }
+bool CFGBlockValues::hasValues(const CFGBlock *block) {
+ unsigned idx = block->getBlockID();
+ return vals[idx].second != 0;
+}
- return Initialized;
+BVPair &CFGBlockValues::getValueVectors(const clang::CFGBlock *block,
+ bool shouldLazyCreate) {
+ unsigned idx = block->getBlockID();
+ lazyCreate(vals[idx].first);
+ if (shouldLazyCreate)
+ lazyCreate(vals[idx].second);
+ return vals[idx];
}
-static VarDecl* FindBlockVarDecl(Expr* E) {
+void CFGBlockValues::mergeIntoScratch(ValueVector const &source,
+ bool isFirst) {
+ if (isFirst)
+ scratch = source;
+ else
+ scratch.merge(source);
+}
+#if 0
+static void printVector(const CFGBlock *block, ValueVector &bv,
+ unsigned num) {
+
+ llvm::errs() << block->getBlockID() << " :";
+ for (unsigned i = 0; i < bv.size(); ++i) {
+ llvm::errs() << ' ' << bv[i];
+ }
+ llvm::errs() << " : " << num << '\n';
+}
+#endif
+
+bool CFGBlockValues::updateValueVectorWithScratch(const CFGBlock *block) {
+ ValueVector &dst = getValueVector(block, 0);
+ bool changed = (dst != scratch);
+ if (changed)
+ dst = scratch;
+#if 0
+ printVector(block, scratch, 0);
+#endif
+ return changed;
+}
- // Blast through casts and parentheses to find any DeclRefExprs that
- // refer to a block VarDecl.
+bool CFGBlockValues::updateValueVectors(const CFGBlock *block,
+ const BVPair &newVals) {
+ BVPair &vals = getValueVectors(block, true);
+ bool changed = *newVals.first != *vals.first ||
+ *newVals.second != *vals.second;
+ *vals.first = *newVals.first;
+ *vals.second = *newVals.second;
+#if 0
+ printVector(block, *vals.first, 1);
+ printVector(block, *vals.second, 2);
+#endif
+ return changed;
+}
- if (DeclRefExpr* DR = dyn_cast<DeclRefExpr>(E->IgnoreParenCasts()))
- if (VarDecl* VD = dyn_cast<VarDecl>(DR->getDecl()))
- if (VD->isLocalVarDecl()) return VD;
+void CFGBlockValues::resetScratch() {
+ scratch.reset();
+}
- return NULL;
+ValueVector::reference CFGBlockValues::operator[](const VarDecl *vd) {
+ const llvm::Optional<unsigned> &idx = declToIndex.getValueIndex(vd);
+ assert(idx.hasValue());
+ return scratch[idx.getValue()];
}
-bool TransferFuncs::VisitBinaryOperator(BinaryOperator* B) {
+//------------------------------------------------------------------------====//
+// Worklist: worklist for dataflow analysis.
+//====------------------------------------------------------------------------//
- if (VarDecl* VD = FindBlockVarDecl(B->getLHS()))
- if (B->isAssignmentOp()) {
- if (B->getOpcode() == BO_Assign)
- return V(VD,AD) = Visit(B->getRHS());
- else // Handle +=, -=, *=, etc. We do want '&', not '&&'.
- return V(VD,AD) = Visit(B->getLHS()) & Visit(B->getRHS());
- }
+namespace {
+class DataflowWorklist {
+ llvm::SmallVector<const CFGBlock *, 20> worklist;
+ llvm::BitVector enqueuedBlocks;
+public:
+ DataflowWorklist(const CFG &cfg) : enqueuedBlocks(cfg.getNumBlockIDs()) {}
+
+ void enqueue(const CFGBlock *block);
+ void enqueueSuccessors(const CFGBlock *block);
+ const CFGBlock *dequeue();
+
+};
+}
- return VisitStmt(B);
+void DataflowWorklist::enqueue(const CFGBlock *block) {
+ if (!block)
+ return;
+ unsigned idx = block->getBlockID();
+ if (enqueuedBlocks[idx])
+ return;
+ worklist.push_back(block);
+ enqueuedBlocks[idx] = true;
}
-bool TransferFuncs::VisitDeclStmt(DeclStmt* S) {
- for (DeclStmt::decl_iterator I=S->decl_begin(), E=S->decl_end(); I!=E; ++I) {
- VarDecl *VD = dyn_cast<VarDecl>(*I);
- if (VD && VD->isLocalVarDecl()) {
- if (Stmt* I = VD->getInit()) {
- // Visit the subexpression to check for uses of uninitialized values,
- // even if we don't propagate that value.
- bool isSubExprUninit = Visit(I);
- V(VD,AD) = AD.FullUninitTaint ? isSubExprUninit : Initialized;
- }
- else {
- // Special case for declarations of array types. For things like:
- //
- // char x[10];
- //
- // we should treat "x" as being initialized, because the variable
- // "x" really refers to the memory block. Clearly x[1] is
- // uninitialized, but expressions like "(char *) x" really do refer to
- // an initialized value. This simple dataflow analysis does not reason
- // about the contents of arrays, although it could be potentially
- // extended to do so if the array were of constant size.
- if (VD->getType()->isArrayType())
- V(VD,AD) = Initialized;
- else
- V(VD,AD) = Uninitialized;
- }
- }
+void DataflowWorklist::enqueueSuccessors(const clang::CFGBlock *block) {
+ for (CFGBlock::const_succ_iterator I = block->succ_begin(),
+ E = block->succ_end(); I != E; ++I) {
+ enqueue(*I);
}
- return Uninitialized; // Value is never consumed.
}
-bool TransferFuncs::VisitCallExpr(CallExpr* C) {
- VisitChildren(C);
- return Initialized;
+const CFGBlock *DataflowWorklist::dequeue() {
+ if (worklist.empty())
+ return 0;
+ const CFGBlock *b = worklist.back();
+ worklist.pop_back();
+ enqueuedBlocks[b->getBlockID()] = false;
+ return b;
}
-bool TransferFuncs::VisitUnaryOperator(UnaryOperator* U) {
- switch (U->getOpcode()) {
- case UO_AddrOf: {
- VarDecl* VD = FindBlockVarDecl(U->getSubExpr());
- if (VD && VD->isLocalVarDecl())
- return V(VD,AD) = Initialized;
- break;
- }
+//------------------------------------------------------------------------====//
+// Transfer function for uninitialized values analysis.
+//====------------------------------------------------------------------------//
- default:
- break;
+namespace {
+class FindVarResult {
+ const VarDecl *vd;
+ const DeclRefExpr *dr;
+public:
+ FindVarResult(VarDecl *vd, DeclRefExpr *dr) : vd(vd), dr(dr) {}
+
+ const DeclRefExpr *getDeclRefExpr() const { return dr; }
+ const VarDecl *getDecl() const { return vd; }
+};
+
+class TransferFunctions : public CFGRecStmtVisitor<TransferFunctions> {
+ CFGBlockValues &vals;
+ const CFG &cfg;
+ AnalysisContext &ac;
+ UninitVariablesHandler *handler;
+ const DeclRefExpr *currentDR;
+ const Expr *currentVoidCast;
+ const bool flagBlockUses;
+public:
+ TransferFunctions(CFGBlockValues &vals, const CFG &cfg,
+ AnalysisContext &ac,
+ UninitVariablesHandler *handler,
+ bool flagBlockUses)
+ : vals(vals), cfg(cfg), ac(ac), handler(handler), currentDR(0),
+ currentVoidCast(0), flagBlockUses(flagBlockUses) {}
+
+ const CFG &getCFG() { return cfg; }
+ void reportUninit(const DeclRefExpr *ex, const VarDecl *vd,
+ bool isAlwaysUninit);
+
+ void VisitBlockExpr(BlockExpr *be);
+ void VisitDeclStmt(DeclStmt *ds);
+ void VisitDeclRefExpr(DeclRefExpr *dr);
+ void VisitUnaryOperator(UnaryOperator *uo);
+ void VisitBinaryOperator(BinaryOperator *bo);
+ void VisitCastExpr(CastExpr *ce);
+ void VisitUnaryExprOrTypeTraitExpr(UnaryExprOrTypeTraitExpr *se);
+ void VisitCXXTypeidExpr(CXXTypeidExpr *E);
+ void BlockStmt_VisitObjCForCollectionStmt(ObjCForCollectionStmt *fs);
+
+ bool isTrackedVar(const VarDecl *vd) {
+ return ::isTrackedVar(vd, cast<DeclContext>(ac.getDecl()));
}
-
- return Visit(U->getSubExpr());
+
+ FindVarResult findBlockVarDecl(Expr *ex);
+};
}
-bool
-TransferFuncs::BlockStmt_VisitObjCForCollectionStmt(ObjCForCollectionStmt* S) {
- // This represents a use of the 'collection'
- bool x = Visit(S->getCollection());
+void TransferFunctions::reportUninit(const DeclRefExpr *ex,
+ const VarDecl *vd, bool isAlwaysUnit) {
+ if (handler) handler->handleUseOfUninitVariable(ex, vd, isAlwaysUnit);
+}
- if (x == Uninitialized)
- return Uninitialized;
+FindVarResult TransferFunctions::findBlockVarDecl(Expr* ex) {
+ if (DeclRefExpr* dr = dyn_cast<DeclRefExpr>(ex->IgnoreParenCasts()))
+ if (VarDecl *vd = dyn_cast<VarDecl>(dr->getDecl()))
+ if (isTrackedVar(vd))
+ return FindVarResult(vd, dr);
+ return FindVarResult(0, 0);
+}
+void TransferFunctions::BlockStmt_VisitObjCForCollectionStmt(
+ ObjCForCollectionStmt *fs) {
+
+ Visit(fs->getCollection());
+
// This represents an initialization of the 'element' value.
- Stmt* Element = S->getElement();
- VarDecl* VD = 0;
-
- if (DeclStmt* DS = dyn_cast<DeclStmt>(Element))
- VD = cast<VarDecl>(DS->getSingleDecl());
+ Stmt *element = fs->getElement();
+ const VarDecl* vd = 0;
+
+ if (DeclStmt* ds = dyn_cast<DeclStmt>(element)) {
+ vd = cast<VarDecl>(ds->getSingleDecl());
+ if (!isTrackedVar(vd))
+ vd = 0;
+ }
else {
- Expr* ElemExpr = cast<Expr>(Element)->IgnoreParens();
-
// Initialize the value of the reference variable.
- if (DeclRefExpr* DR = dyn_cast<DeclRefExpr>(ElemExpr))
- VD = cast<VarDecl>(DR->getDecl());
- else
- return Visit(ElemExpr);
+ const FindVarResult &res = findBlockVarDecl(cast<Expr>(element));
+ vd = res.getDecl();
+ if (!vd) {
+ Visit(element);
+ return;
+ }
}
-
- V(VD,AD) = Initialized;
- return Initialized;
+
+ if (vd)
+ vals[vd] = Initialized;
}
-
-bool TransferFuncs::
-VisitAbstractConditionalOperator(AbstractConditionalOperator* C) {
- Visit(C->getCond());
-
- bool rhsResult = Visit(C->getFalseExpr());
- // Handle the GNU extension for missing LHS.
- if (isa<ConditionalOperator>(C))
- return Visit(C->getTrueExpr()) & rhsResult; // Yes: we want &, not &&.
- else
- return rhsResult;
+void TransferFunctions::VisitBlockExpr(BlockExpr *be) {
+ if (!flagBlockUses || !handler)
+ return;
+ const BlockDecl *bd = be->getBlockDecl();
+ for (BlockDecl::capture_const_iterator i = bd->capture_begin(),
+ e = bd->capture_end() ; i != e; ++i) {
+ const VarDecl *vd = i->getVariable();
+ if (!vd->hasLocalStorage())
+ continue;
+ if (!isTrackedVar(vd))
+ continue;
+ if (i->isByRef()) {
+ vals[vd] = Initialized;
+ continue;
+ }
+ Value v = vals[vd];
+ if (isUninitialized(v))
+ handler->handleUseOfUninitVariable(be, vd, isAlwaysUninit(v));
+ }
}
-bool TransferFuncs::VisitStmt(Stmt* S) {
- bool x = Initialized;
-
- // We don't stop at the first subexpression that is Uninitialized because
- // evaluating some subexpressions may result in propogating "Uninitialized"
- // or "Initialized" to variables referenced in the other subexpressions.
- for (Stmt::child_range I = S->children(); I; ++I)
- if (*I && Visit(*I) == Uninitialized) x = Uninitialized;
-
- return x;
+void TransferFunctions::VisitDeclStmt(DeclStmt *ds) {
+ for (DeclStmt::decl_iterator DI = ds->decl_begin(), DE = ds->decl_end();
+ DI != DE; ++DI) {
+ if (VarDecl *vd = dyn_cast<VarDecl>(*DI)) {
+ if (isTrackedVar(vd)) {
+ if (Expr *init = vd->getInit()) {
+ Visit(init);
+
+ // If the initializer consists solely of a reference to itself, we
+ // explicitly mark the variable as uninitialized. This allows code
+ // like the following:
+ //
+ // int x = x;
+ //
+ // to deliberately leave a variable uninitialized. Different analysis
+ // clients can detect this pattern and adjust their reporting
+ // appropriately, but we need to continue to analyze subsequent uses
+ // of the variable.
+ DeclRefExpr *DRE = dyn_cast<DeclRefExpr>(init->IgnoreParenImpCasts());
+ vals[vd] = (DRE && DRE->getDecl() == vd) ? Uninitialized
+ : Initialized;
+ }
+ } else if (Stmt *init = vd->getInit()) {
+ Visit(init);
+ }
+ }
+ }
}
-bool TransferFuncs::Visit(Stmt *S) {
- if (AD.isTracked(static_cast<Expr*>(S))) return V(static_cast<Expr*>(S),AD);
- else return static_cast<CFGStmtVisitor<TransferFuncs,bool>*>(this)->Visit(S);
+void TransferFunctions::VisitDeclRefExpr(DeclRefExpr *dr) {
+ // We assume that DeclRefExprs wrapped in an lvalue-to-rvalue cast
+ // cannot be block-level expressions. Therefore, we determine if
+ // a DeclRefExpr is involved in a "load" by comparing it to the current
+ // DeclRefExpr found when analyzing the last lvalue-to-rvalue CastExpr.
+ // If a DeclRefExpr is not involved in a load, we are essentially computing
+ // its address, either for assignment to a reference or via the '&' operator.
+ // In such cases, treat the variable as being initialized, since this
+ // analysis isn't powerful enough to do alias tracking.
+ if (dr != currentDR)
+ if (const VarDecl *vd = dyn_cast<VarDecl>(dr->getDecl()))
+ if (isTrackedVar(vd))
+ vals[vd] = Initialized;
}
-bool TransferFuncs::BlockStmt_VisitExpr(Expr* E) {
- bool x = static_cast<CFGStmtVisitor<TransferFuncs,bool>*>(this)->Visit(E);
- if (AD.isTracked(E)) V(E,AD) = x;
- return x;
+void TransferFunctions::VisitBinaryOperator(clang::BinaryOperator *bo) {
+ if (bo->isAssignmentOp()) {
+ const FindVarResult &res = findBlockVarDecl(bo->getLHS());
+ if (const VarDecl* vd = res.getDecl()) {
+ // We assume that DeclRefExprs wrapped in a BinaryOperator "assignment"
+ // cannot be block-level expressions. Therefore, we determine if
+ // a DeclRefExpr is involved in a "load" by comparing it to the current
+ // DeclRefExpr found when analyzing the last lvalue-to-rvalue CastExpr.
+ SaveAndRestore<const DeclRefExpr*> lastDR(currentDR,
+ res.getDeclRefExpr());
+ Visit(bo->getRHS());
+ Visit(bo->getLHS());
+
+ ValueVector::reference val = vals[vd];
+ if (isUninitialized(val)) {
+ if (bo->getOpcode() != BO_Assign)
+ reportUninit(res.getDeclRefExpr(), vd, isAlwaysUninit(val));
+ val = Initialized;
+ }
+ return;
+ }
+ }
+ Visit(bo->getRHS());
+ Visit(bo->getLHS());
}
-} // end anonymous namespace
-
-//===----------------------------------------------------------------------===//
-// Merge operator.
-//
-// In our transfer functions we take the approach that any
-// combination of uninitialized values, e.g.
-// Uninitialized + ___ = Uninitialized.
-//
-// Merges take the same approach, preferring soundness. At a confluence point,
-// if any predecessor has a variable marked uninitialized, the value is
-// uninitialized at the confluence point.
-//===----------------------------------------------------------------------===//
-
-namespace {
- typedef StmtDeclBitVector_Types::Union Merge;
- typedef DataflowSolver<UninitializedValues,TransferFuncs,Merge> Solver;
+void TransferFunctions::VisitUnaryOperator(clang::UnaryOperator *uo) {
+ switch (uo->getOpcode()) {
+ case clang::UO_PostDec:
+ case clang::UO_PostInc:
+ case clang::UO_PreDec:
+ case clang::UO_PreInc: {
+ const FindVarResult &res = findBlockVarDecl(uo->getSubExpr());
+ if (const VarDecl *vd = res.getDecl()) {
+ // We assume that DeclRefExprs wrapped in a unary operator ++/--
+ // cannot be block-level expressions. Therefore, we determine if
+ // a DeclRefExpr is involved in a "load" by comparing it to the current
+ // DeclRefExpr found when analyzing the last lvalue-to-rvalue CastExpr.
+ SaveAndRestore<const DeclRefExpr*> lastDR(currentDR,
+ res.getDeclRefExpr());
+ Visit(uo->getSubExpr());
+
+ ValueVector::reference val = vals[vd];
+ if (isUninitialized(val)) {
+ reportUninit(res.getDeclRefExpr(), vd, isAlwaysUninit(val));
+ // Don't cascade warnings.
+ val = Initialized;
+ }
+ return;
+ }
+ break;
+ }
+ default:
+ break;
+ }
+ Visit(uo->getSubExpr());
}
-//===----------------------------------------------------------------------===//
-// Uninitialized values checker. Scan an AST and flag variable uses
-//===----------------------------------------------------------------------===//
-
-UninitializedValues_ValueTypes::ObserverTy::~ObserverTy() {}
-
-namespace {
-class UninitializedValuesChecker
- : public UninitializedValues::ObserverTy {
+void TransferFunctions::VisitCastExpr(clang::CastExpr *ce) {
+ if (ce->getCastKind() == CK_LValueToRValue) {
+ const FindVarResult &res = findBlockVarDecl(ce->getSubExpr());
+ if (const VarDecl *vd = res.getDecl()) {
+ // We assume that DeclRefExprs wrapped in an lvalue-to-rvalue cast
+ // cannot be block-level expressions. Therefore, we determine if
+ // a DeclRefExpr is involved in a "load" by comparing it to the current
+ // DeclRefExpr found when analyzing the last lvalue-to-rvalue CastExpr.
+ // Here we update 'currentDR' to be the one associated with this
+ // lvalue-to-rvalue cast. Then, when we analyze the DeclRefExpr, we
+ // will know that we are not computing its lvalue for other purposes
+ // than to perform a load.
+ SaveAndRestore<const DeclRefExpr*> lastDR(currentDR,
+ res.getDeclRefExpr());
+ Visit(ce->getSubExpr());
+ if (currentVoidCast != ce) {
+ Value val = vals[vd];
+ if (isUninitialized(val)) {
+ reportUninit(res.getDeclRefExpr(), vd, isAlwaysUninit(val));
+ // Don't cascade warnings.
+ vals[vd] = Initialized;
+ }
+ }
+ return;
+ }
+ }
+ else if (CStyleCastExpr *cse = dyn_cast<CStyleCastExpr>(ce)) {
+ if (cse->getType()->isVoidType()) {
+ // e.g. (void) x;
+ SaveAndRestore<const Expr *>
+ lastVoidCast(currentVoidCast, cse->getSubExpr()->IgnoreParens());
+ Visit(cse->getSubExpr());
+ return;
+ }
+ }
+ Visit(ce->getSubExpr());
+}
- ASTContext &Ctx;
- Diagnostic &Diags;
- llvm::SmallPtrSet<VarDecl*,10> AlreadyWarned;
+void TransferFunctions::VisitUnaryExprOrTypeTraitExpr(
+ UnaryExprOrTypeTraitExpr *se) {
+ if (se->getKind() == UETT_SizeOf) {
+ if (se->getType()->isConstantSizeType())
+ return;
+ // Handle VLAs.
+ Visit(se->getArgumentExpr());
+ }
+}
-public:
- UninitializedValuesChecker(ASTContext &ctx, Diagnostic &diags)
- : Ctx(ctx), Diags(diags) {}
+void TransferFunctions::VisitCXXTypeidExpr(CXXTypeidExpr *E) {
+ // typeid(expression) is potentially evaluated when the argument is
+ // a glvalue of polymorphic type. (C++ 5.2.8p2-3)
+ if (!E->isTypeOperand() && E->Classify(ac.getASTContext()).isGLValue()) {
+ QualType SubExprTy = E->getExprOperand()->getType();
+ if (const RecordType *Record = SubExprTy->getAs<RecordType>())
+ if (cast<CXXRecordDecl>(Record->getDecl())->isPolymorphic())
+ Visit(E->getExprOperand());
+ }
+}
- virtual void ObserveDeclRefExpr(UninitializedValues::ValTy& V,
- UninitializedValues::AnalysisDataTy& AD,
- DeclRefExpr* DR, VarDecl* VD) {
+//------------------------------------------------------------------------====//
+// High-level "driver" logic for uninitialized values analysis.
+//====------------------------------------------------------------------------//
+
+static bool runOnBlock(const CFGBlock *block, const CFG &cfg,
+ AnalysisContext &ac, CFGBlockValues &vals,
+ llvm::BitVector &wasAnalyzed,
+ UninitVariablesHandler *handler = 0,
+ bool flagBlockUses = false) {
+
+ wasAnalyzed[block->getBlockID()] = true;
+
+ if (const BinaryOperator *b = getLogicalOperatorInChain(block)) {
+ CFGBlock::const_pred_iterator itr = block->pred_begin();
+ BVPair vA = vals.getValueVectors(*itr, false);
+ ++itr;
+ BVPair vB = vals.getValueVectors(*itr, false);
+
+ BVPair valsAB;
+
+ if (b->getOpcode() == BO_LAnd) {
+ // Merge the 'F' bits from the first and second.
+ vals.mergeIntoScratch(*(vA.second ? vA.second : vA.first), true);
+ vals.mergeIntoScratch(*(vB.second ? vB.second : vB.first), false);
+ valsAB.first = vA.first;
+ valsAB.second = &vals.getScratch();
+ }
+ else {
+ // Merge the 'T' bits from the first and second.
+ assert(b->getOpcode() == BO_LOr);
+ vals.mergeIntoScratch(*vA.first, true);
+ vals.mergeIntoScratch(*vB.first, false);
+ valsAB.first = &vals.getScratch();
+ valsAB.second = vA.second ? vA.second : vA.first;
+ }
+ return vals.updateValueVectors(block, valsAB);
+ }
- assert ( AD.isTracked(VD) && "Unknown VarDecl.");
+ // Default behavior: merge in values of predecessor blocks.
+ vals.resetScratch();
+ bool isFirst = true;
+ for (CFGBlock::const_pred_iterator I = block->pred_begin(),
+ E = block->pred_end(); I != E; ++I) {
+ vals.mergeIntoScratch(vals.getValueVector(*I, block), isFirst);
+ isFirst = false;
+ }
+ // Apply the transfer function.
+ TransferFunctions tf(vals, cfg, ac, handler, flagBlockUses);
+ for (CFGBlock::const_iterator I = block->begin(), E = block->end();
+ I != E; ++I) {
+ if (const CFGStmt *cs = dyn_cast<CFGStmt>(&*I)) {
+ tf.BlockStmt_Visit(cs->getStmt());
+ }
+ }
+ return vals.updateValueVectorWithScratch(block);
+}
- if (V(VD,AD) == Uninitialized)
- if (AlreadyWarned.insert(VD))
- Diags.Report(Ctx.getFullLoc(DR->getSourceRange().getBegin()),
- diag::warn_uninit_val);
+void clang::runUninitializedVariablesAnalysis(const DeclContext &dc,
+ const CFG &cfg,
+ AnalysisContext &ac,
+ UninitVariablesHandler &handler) {
+ CFGBlockValues vals(cfg);
+ vals.computeSetOfDeclarations(dc);
+ if (vals.hasNoDeclarations())
+ return;
+
+ // Mark all variables uninitialized at the entry.
+ const CFGBlock &entry = cfg.getEntry();
+ for (CFGBlock::const_succ_iterator i = entry.succ_begin(),
+ e = entry.succ_end(); i != e; ++i) {
+ if (const CFGBlock *succ = *i) {
+ ValueVector &vec = vals.getValueVector(&entry, succ);
+ const unsigned n = vals.getNumEntries();
+ for (unsigned j = 0; j < n ; ++j) {
+ vec[j] = Uninitialized;
+ }
+ }
}
-};
-} // end anonymous namespace
-namespace clang {
-void CheckUninitializedValues(CFG& cfg, ASTContext &Ctx, Diagnostic &Diags,
- bool FullUninitTaint) {
+ // Proceed with the workist.
+ DataflowWorklist worklist(cfg);
+ llvm::BitVector previouslyVisited(cfg.getNumBlockIDs());
+ worklist.enqueueSuccessors(&cfg.getEntry());
+ llvm::BitVector wasAnalyzed(cfg.getNumBlockIDs(), false);
+
+ while (const CFGBlock *block = worklist.dequeue()) {
+ // Did the block change?
+ bool changed = runOnBlock(block, cfg, ac, vals, wasAnalyzed);
+ if (changed || !previouslyVisited[block->getBlockID()])
+ worklist.enqueueSuccessors(block);
+ previouslyVisited[block->getBlockID()] = true;
+ }
+
+ // Run through the blocks one more time, and report uninitialized variabes.
+ for (CFG::const_iterator BI = cfg.begin(), BE = cfg.end(); BI != BE; ++BI) {
+ if (wasAnalyzed[(*BI)->getBlockID()])
+ runOnBlock(*BI, cfg, ac, vals, wasAnalyzed, &handler,
+ /* flagBlockUses */ true);
+ }
+}
- // Compute the uninitialized values information.
- UninitializedValues U(cfg);
- U.getAnalysisData().FullUninitTaint = FullUninitTaint;
- Solver S(U);
- S.runOnCFG(cfg);
+UninitVariablesHandler::~UninitVariablesHandler() {}
- // Scan for DeclRefExprs that use uninitialized values.
- UninitializedValuesChecker Observer(Ctx,Diags);
- U.getAnalysisData().Observer = &Observer;
- S.runOnAllBlocks(cfg);
-}
-} // end namespace clang
diff --git a/lib/Analysis/UninitializedValuesV2.cpp b/lib/Analysis/UninitializedValuesV2.cpp
deleted file mode 100644
index 75eccbf7a3c8..000000000000
--- a/lib/Analysis/UninitializedValuesV2.cpp
+++ /dev/null
@@ -1,610 +0,0 @@
-//==- UninitializedValuesV2.cpp - Find Uninitialized Values -----*- C++ --*-==//
-//
-// The LLVM Compiler Infrastructure
-//
-// This file is distributed under the University of Illinois Open Source
-// License. See LICENSE.TXT for details.
-//
-//===----------------------------------------------------------------------===//
-//
-// This file implements uninitialized values analysis for source-level CFGs.
-//
-//===----------------------------------------------------------------------===//
-
-#include <utility>
-#include "llvm/ADT/Optional.h"
-#include "llvm/ADT/SmallVector.h"
-#include "llvm/ADT/BitVector.h"
-#include "llvm/ADT/DenseMap.h"
-#include "clang/AST/Decl.h"
-#include "clang/Analysis/CFG.h"
-#include "clang/Analysis/AnalysisContext.h"
-#include "clang/Analysis/Visitors/CFGRecStmtDeclVisitor.h"
-#include "clang/Analysis/Analyses/UninitializedValuesV2.h"
-#include "clang/Analysis/Support/SaveAndRestore.h"
-
-using namespace clang;
-
-static bool isTrackedVar(const VarDecl *vd, const DeclContext *dc) {
- return vd->isLocalVarDecl() && !vd->hasGlobalStorage() &&
- vd->getType()->isScalarType() &&
- vd->getDeclContext() == dc;
-}
-
-//------------------------------------------------------------------------====//
-// DeclToBit: a mapping from Decls we track to bitvector indices.
-//====------------------------------------------------------------------------//
-
-namespace {
-class DeclToBit {
- llvm::DenseMap<const VarDecl *, unsigned> map;
-public:
- DeclToBit() {}
-
- /// Compute the actual mapping from declarations to bits.
- void computeMap(const DeclContext &dc);
-
- /// Return the number of declarations in the map.
- unsigned size() const { return map.size(); }
-
- /// Returns the bit vector index for a given declaration.
- llvm::Optional<unsigned> getBitVectorIndex(const VarDecl *d);
-};
-}
-
-void DeclToBit::computeMap(const DeclContext &dc) {
- unsigned count = 0;
- DeclContext::specific_decl_iterator<VarDecl> I(dc.decls_begin()),
- E(dc.decls_end());
- for ( ; I != E; ++I) {
- const VarDecl *vd = *I;
- if (isTrackedVar(vd, &dc))
- map[vd] = count++;
- }
-}
-
-llvm::Optional<unsigned> DeclToBit::getBitVectorIndex(const VarDecl *d) {
- llvm::DenseMap<const VarDecl *, unsigned>::iterator I = map.find(d);
- if (I == map.end())
- return llvm::Optional<unsigned>();
- return I->second;
-}
-
-//------------------------------------------------------------------------====//
-// CFGBlockValues: dataflow values for CFG blocks.
-//====------------------------------------------------------------------------//
-
-typedef std::pair<llvm::BitVector *, llvm::BitVector *> BVPair;
-
-namespace {
-class CFGBlockValues {
- const CFG &cfg;
- BVPair *vals;
- llvm::BitVector scratch;
- DeclToBit declToBit;
-
- llvm::BitVector &lazyCreate(llvm::BitVector *&bv);
-public:
- CFGBlockValues(const CFG &cfg);
- ~CFGBlockValues();
-
- void computeSetOfDeclarations(const DeclContext &dc);
- llvm::BitVector &getBitVector(const CFGBlock *block,
- const CFGBlock *dstBlock);
-
- BVPair &getBitVectors(const CFGBlock *block, bool shouldLazyCreate);
-
- void mergeIntoScratch(llvm::BitVector const &source, bool isFirst);
- bool updateBitVectorWithScratch(const CFGBlock *block);
- bool updateBitVectors(const CFGBlock *block, const BVPair &newVals);
-
- bool hasNoDeclarations() const {
- return declToBit.size() == 0;
- }
-
- void resetScratch();
- llvm::BitVector &getScratch() { return scratch; }
-
- llvm::BitVector::reference operator[](const VarDecl *vd);
-};
-}
-
-CFGBlockValues::CFGBlockValues(const CFG &c) : cfg(c), vals(0) {
- unsigned n = cfg.getNumBlockIDs();
- if (!n)
- return;
- vals = new std::pair<llvm::BitVector*, llvm::BitVector*>[n];
- memset(vals, 0, sizeof(*vals) * n);
-}
-
-CFGBlockValues::~CFGBlockValues() {
- unsigned n = cfg.getNumBlockIDs();
- if (n == 0)
- return;
- for (unsigned i = 0; i < n; ++i) {
- delete vals[i].first;
- delete vals[i].second;
- }
- delete [] vals;
-}
-
-void CFGBlockValues::computeSetOfDeclarations(const DeclContext &dc) {
- declToBit.computeMap(dc);
- scratch.resize(declToBit.size());
-}
-
-llvm::BitVector &CFGBlockValues::lazyCreate(llvm::BitVector *&bv) {
- if (!bv)
- bv = new llvm::BitVector(declToBit.size());
- return *bv;
-}
-
-/// This function pattern matches for a '&&' or '||' that appears at
-/// the beginning of a CFGBlock that also (1) has a terminator and
-/// (2) has no other elements. If such an expression is found, it is returned.
-static BinaryOperator *getLogicalOperatorInChain(const CFGBlock *block) {
- if (block->empty())
- return 0;
-
- CFGStmt cstmt = block->front().getAs<CFGStmt>();
- BinaryOperator *b = llvm::dyn_cast_or_null<BinaryOperator>(cstmt.getStmt());
-
- if (!b || !b->isLogicalOp())
- return 0;
-
- if (block->pred_size() == 2 &&
- ((block->succ_size() == 2 && block->getTerminatorCondition() == b) ||
- block->size() == 1))
- return b;
-
- return 0;
-}
-
-llvm::BitVector &CFGBlockValues::getBitVector(const CFGBlock *block,
- const CFGBlock *dstBlock) {
- unsigned idx = block->getBlockID();
- if (dstBlock && getLogicalOperatorInChain(block)) {
- if (*block->succ_begin() == dstBlock)
- return lazyCreate(vals[idx].first);
- assert(*(block->succ_begin()+1) == dstBlock);
- return lazyCreate(vals[idx].second);
- }
-
- assert(vals[idx].second == 0);
- return lazyCreate(vals[idx].first);
-}
-
-BVPair &CFGBlockValues::getBitVectors(const clang::CFGBlock *block,
- bool shouldLazyCreate) {
- unsigned idx = block->getBlockID();
- lazyCreate(vals[idx].first);
- if (shouldLazyCreate)
- lazyCreate(vals[idx].second);
- return vals[idx];
-}
-
-void CFGBlockValues::mergeIntoScratch(llvm::BitVector const &source,
- bool isFirst) {
- if (isFirst)
- scratch = source;
- else
- scratch |= source;
-}
-#if 0
-static void printVector(const CFGBlock *block, llvm::BitVector &bv,
- unsigned num) {
-
- llvm::errs() << block->getBlockID() << " :";
- for (unsigned i = 0; i < bv.size(); ++i) {
- llvm::errs() << ' ' << bv[i];
- }
- llvm::errs() << " : " << num << '\n';
-}
-#endif
-
-bool CFGBlockValues::updateBitVectorWithScratch(const CFGBlock *block) {
- llvm::BitVector &dst = getBitVector(block, 0);
- bool changed = (dst != scratch);
- if (changed)
- dst = scratch;
-#if 0
- printVector(block, scratch, 0);
-#endif
- return changed;
-}
-
-bool CFGBlockValues::updateBitVectors(const CFGBlock *block,
- const BVPair &newVals) {
- BVPair &vals = getBitVectors(block, true);
- bool changed = *newVals.first != *vals.first ||
- *newVals.second != *vals.second;
- *vals.first = *newVals.first;
- *vals.second = *newVals.second;
-#if 0
- printVector(block, *vals.first, 1);
- printVector(block, *vals.second, 2);
-#endif
- return changed;
-}
-
-void CFGBlockValues::resetScratch() {
- scratch.reset();
-}
-
-llvm::BitVector::reference CFGBlockValues::operator[](const VarDecl *vd) {
- const llvm::Optional<unsigned> &idx = declToBit.getBitVectorIndex(vd);
- assert(idx.hasValue());
- return scratch[idx.getValue()];
-}
-
-//------------------------------------------------------------------------====//
-// Worklist: worklist for dataflow analysis.
-//====------------------------------------------------------------------------//
-
-namespace {
-class DataflowWorklist {
- llvm::SmallVector<const CFGBlock *, 20> worklist;
- llvm::BitVector enqueuedBlocks;
-public:
- DataflowWorklist(const CFG &cfg) : enqueuedBlocks(cfg.getNumBlockIDs()) {}
-
- void enqueue(const CFGBlock *block);
- void enqueueSuccessors(const CFGBlock *block);
- const CFGBlock *dequeue();
-
-};
-}
-
-void DataflowWorklist::enqueue(const CFGBlock *block) {
- if (!block)
- return;
- unsigned idx = block->getBlockID();
- if (enqueuedBlocks[idx])
- return;
- worklist.push_back(block);
- enqueuedBlocks[idx] = true;
-}
-
-void DataflowWorklist::enqueueSuccessors(const clang::CFGBlock *block) {
- for (CFGBlock::const_succ_iterator I = block->succ_begin(),
- E = block->succ_end(); I != E; ++I) {
- enqueue(*I);
- }
-}
-
-const CFGBlock *DataflowWorklist::dequeue() {
- if (worklist.empty())
- return 0;
- const CFGBlock *b = worklist.back();
- worklist.pop_back();
- enqueuedBlocks[b->getBlockID()] = false;
- return b;
-}
-
-//------------------------------------------------------------------------====//
-// Transfer function for uninitialized values analysis.
-//====------------------------------------------------------------------------//
-
-static const bool Initialized = false;
-static const bool Uninitialized = true;
-
-namespace {
-class FindVarResult {
- const VarDecl *vd;
- const DeclRefExpr *dr;
-public:
- FindVarResult(VarDecl *vd, DeclRefExpr *dr) : vd(vd), dr(dr) {}
-
- const DeclRefExpr *getDeclRefExpr() const { return dr; }
- const VarDecl *getDecl() const { return vd; }
-};
-
-class TransferFunctions : public CFGRecStmtVisitor<TransferFunctions> {
- CFGBlockValues &vals;
- const CFG &cfg;
- AnalysisContext &ac;
- UninitVariablesHandler *handler;
- const DeclRefExpr *currentDR;
- const Expr *currentVoidCast;
- const bool flagBlockUses;
-public:
- TransferFunctions(CFGBlockValues &vals, const CFG &cfg,
- AnalysisContext &ac,
- UninitVariablesHandler *handler,
- bool flagBlockUses)
- : vals(vals), cfg(cfg), ac(ac), handler(handler), currentDR(0),
- currentVoidCast(0), flagBlockUses(flagBlockUses) {}
-
- const CFG &getCFG() { return cfg; }
- void reportUninit(const DeclRefExpr *ex, const VarDecl *vd);
-
- void VisitBlockExpr(BlockExpr *be);
- void VisitDeclStmt(DeclStmt *ds);
- void VisitDeclRefExpr(DeclRefExpr *dr);
- void VisitUnaryOperator(UnaryOperator *uo);
- void VisitBinaryOperator(BinaryOperator *bo);
- void VisitCastExpr(CastExpr *ce);
- void VisitSizeOfAlignOfExpr(SizeOfAlignOfExpr *se);
- void BlockStmt_VisitObjCForCollectionStmt(ObjCForCollectionStmt *fs);
-
- bool isTrackedVar(const VarDecl *vd) {
- return ::isTrackedVar(vd, cast<DeclContext>(ac.getDecl()));
- }
-
- FindVarResult findBlockVarDecl(Expr *ex);
-};
-}
-
-void TransferFunctions::reportUninit(const DeclRefExpr *ex,
- const VarDecl *vd) {
- if (handler) handler->handleUseOfUninitVariable(ex, vd);
-}
-
-FindVarResult TransferFunctions::findBlockVarDecl(Expr* ex) {
- if (DeclRefExpr* dr = dyn_cast<DeclRefExpr>(ex->IgnoreParenCasts()))
- if (VarDecl *vd = dyn_cast<VarDecl>(dr->getDecl()))
- if (isTrackedVar(vd))
- return FindVarResult(vd, dr);
- return FindVarResult(0, 0);
-}
-
-void TransferFunctions::BlockStmt_VisitObjCForCollectionStmt(
- ObjCForCollectionStmt *fs) {
-
- Visit(fs->getCollection());
-
- // This represents an initialization of the 'element' value.
- Stmt *element = fs->getElement();
- const VarDecl* vd = 0;
-
- if (DeclStmt* ds = dyn_cast<DeclStmt>(element)) {
- vd = cast<VarDecl>(ds->getSingleDecl());
- if (!isTrackedVar(vd))
- vd = 0;
- }
- else {
- // Initialize the value of the reference variable.
- const FindVarResult &res = findBlockVarDecl(cast<Expr>(element));
- vd = res.getDecl();
- if (!vd) {
- Visit(element);
- return;
- }
- }
-
- if (vd)
- vals[vd] = Initialized;
-}
-
-void TransferFunctions::VisitBlockExpr(BlockExpr *be) {
- if (!flagBlockUses || !handler)
- return;
- AnalysisContext::referenced_decls_iterator i, e;
- llvm::tie(i, e) = ac.getReferencedBlockVars(be->getBlockDecl());
- for ( ; i != e; ++i) {
- const VarDecl *vd = *i;
- if (vd->getAttr<BlocksAttr>() || !vd->hasLocalStorage() ||
- !isTrackedVar(vd))
- continue;
- if (vals[vd] == Uninitialized)
- handler->handleUseOfUninitVariable(be, vd);
- }
-}
-
-void TransferFunctions::VisitDeclStmt(DeclStmt *ds) {
- for (DeclStmt::decl_iterator DI = ds->decl_begin(), DE = ds->decl_end();
- DI != DE; ++DI) {
- if (VarDecl *vd = dyn_cast<VarDecl>(*DI)) {
- if (isTrackedVar(vd)) {
- vals[vd] = Uninitialized;
- if (Stmt *init = vd->getInit()) {
- Visit(init);
- vals[vd] = Initialized;
- }
- }
- else if (Stmt *init = vd->getInit()) {
- Visit(init);
- }
- }
- }
-}
-
-void TransferFunctions::VisitDeclRefExpr(DeclRefExpr *dr) {
- // We assume that DeclRefExprs wrapped in an lvalue-to-rvalue cast
- // cannot be block-level expressions. Therefore, we determine if
- // a DeclRefExpr is involved in a "load" by comparing it to the current
- // DeclRefExpr found when analyzing the last lvalue-to-rvalue CastExpr.
- // If a DeclRefExpr is not involved in a load, we are essentially computing
- // its address, either for assignment to a reference or via the '&' operator.
- // In such cases, treat the variable as being initialized, since this
- // analysis isn't powerful enough to do alias tracking.
- if (dr != currentDR)
- if (const VarDecl *vd = dyn_cast<VarDecl>(dr->getDecl()))
- if (isTrackedVar(vd))
- vals[vd] = Initialized;
-}
-
-void TransferFunctions::VisitBinaryOperator(clang::BinaryOperator *bo) {
- if (bo->isAssignmentOp()) {
- const FindVarResult &res = findBlockVarDecl(bo->getLHS());
- if (const VarDecl* vd = res.getDecl()) {
- // We assume that DeclRefExprs wrapped in a BinaryOperator "assignment"
- // cannot be block-level expressions. Therefore, we determine if
- // a DeclRefExpr is involved in a "load" by comparing it to the current
- // DeclRefExpr found when analyzing the last lvalue-to-rvalue CastExpr.
- SaveAndRestore<const DeclRefExpr*> lastDR(currentDR,
- res.getDeclRefExpr());
- Visit(bo->getRHS());
- Visit(bo->getLHS());
-
- llvm::BitVector::reference bit = vals[vd];
- if (bit == Uninitialized) {
- if (bo->getOpcode() != BO_Assign)
- reportUninit(res.getDeclRefExpr(), vd);
- bit = Initialized;
- }
- return;
- }
- }
- Visit(bo->getRHS());
- Visit(bo->getLHS());
-}
-
-void TransferFunctions::VisitUnaryOperator(clang::UnaryOperator *uo) {
- switch (uo->getOpcode()) {
- case clang::UO_PostDec:
- case clang::UO_PostInc:
- case clang::UO_PreDec:
- case clang::UO_PreInc: {
- const FindVarResult &res = findBlockVarDecl(uo->getSubExpr());
- if (const VarDecl *vd = res.getDecl()) {
- // We assume that DeclRefExprs wrapped in a unary operator ++/--
- // cannot be block-level expressions. Therefore, we determine if
- // a DeclRefExpr is involved in a "load" by comparing it to the current
- // DeclRefExpr found when analyzing the last lvalue-to-rvalue CastExpr.
- SaveAndRestore<const DeclRefExpr*> lastDR(currentDR,
- res.getDeclRefExpr());
- Visit(uo->getSubExpr());
-
- llvm::BitVector::reference bit = vals[vd];
- if (bit == Uninitialized) {
- reportUninit(res.getDeclRefExpr(), vd);
- bit = Initialized;
- }
- return;
- }
- break;
- }
- default:
- break;
- }
- Visit(uo->getSubExpr());
-}
-
-void TransferFunctions::VisitCastExpr(clang::CastExpr *ce) {
- if (ce->getCastKind() == CK_LValueToRValue) {
- const FindVarResult &res = findBlockVarDecl(ce->getSubExpr());
- if (const VarDecl *vd = res.getDecl()) {
- // We assume that DeclRefExprs wrapped in an lvalue-to-rvalue cast
- // cannot be block-level expressions. Therefore, we determine if
- // a DeclRefExpr is involved in a "load" by comparing it to the current
- // DeclRefExpr found when analyzing the last lvalue-to-rvalue CastExpr.
- // Here we update 'currentDR' to be the one associated with this
- // lvalue-to-rvalue cast. Then, when we analyze the DeclRefExpr, we
- // will know that we are not computing its lvalue for other purposes
- // than to perform a load.
- SaveAndRestore<const DeclRefExpr*> lastDR(currentDR,
- res.getDeclRefExpr());
- Visit(ce->getSubExpr());
- if (currentVoidCast != ce && vals[vd] == Uninitialized) {
- reportUninit(res.getDeclRefExpr(), vd);
- // Don't cascade warnings.
- vals[vd] = Initialized;
- }
- return;
- }
- }
- else if (CStyleCastExpr *cse = dyn_cast<CStyleCastExpr>(ce)) {
- if (cse->getType()->isVoidType()) {
- // e.g. (void) x;
- SaveAndRestore<const Expr *>
- lastVoidCast(currentVoidCast, cse->getSubExpr()->IgnoreParens());
- Visit(cse->getSubExpr());
- return;
- }
- }
- Visit(ce->getSubExpr());
-}
-
-void TransferFunctions::VisitSizeOfAlignOfExpr(SizeOfAlignOfExpr *se) {
- if (se->isSizeOf()) {
- if (se->getType()->isConstantSizeType())
- return;
- // Handle VLAs.
- Visit(se->getArgumentExpr());
- }
-}
-
-//------------------------------------------------------------------------====//
-// High-level "driver" logic for uninitialized values analysis.
-//====------------------------------------------------------------------------//
-
-static bool runOnBlock(const CFGBlock *block, const CFG &cfg,
- AnalysisContext &ac, CFGBlockValues &vals,
- UninitVariablesHandler *handler = 0,
- bool flagBlockUses = false) {
-
- if (const BinaryOperator *b = getLogicalOperatorInChain(block)) {
- CFGBlock::const_pred_iterator itr = block->pred_begin();
- BVPair vA = vals.getBitVectors(*itr, false);
- ++itr;
- BVPair vB = vals.getBitVectors(*itr, false);
-
- BVPair valsAB;
-
- if (b->getOpcode() == BO_LAnd) {
- // Merge the 'F' bits from the first and second.
- vals.mergeIntoScratch(*(vA.second ? vA.second : vA.first), true);
- vals.mergeIntoScratch(*(vB.second ? vB.second : vB.first), false);
- valsAB.first = vA.first;
- valsAB.second = &vals.getScratch();
- }
- else {
- // Merge the 'T' bits from the first and second.
- assert(b->getOpcode() == BO_LOr);
- vals.mergeIntoScratch(*vA.first, true);
- vals.mergeIntoScratch(*vB.first, false);
- valsAB.first = &vals.getScratch();
- valsAB.second = vA.second ? vA.second : vA.first;
- }
- return vals.updateBitVectors(block, valsAB);
- }
-
- // Default behavior: merge in values of predecessor blocks.
- vals.resetScratch();
- bool isFirst = true;
- for (CFGBlock::const_pred_iterator I = block->pred_begin(),
- E = block->pred_end(); I != E; ++I) {
- vals.mergeIntoScratch(vals.getBitVector(*I, block), isFirst);
- isFirst = false;
- }
- // Apply the transfer function.
- TransferFunctions tf(vals, cfg, ac, handler, flagBlockUses);
- for (CFGBlock::const_iterator I = block->begin(), E = block->end();
- I != E; ++I) {
- if (const CFGStmt *cs = dyn_cast<CFGStmt>(&*I)) {
- tf.BlockStmt_Visit(cs->getStmt());
- }
- }
- return vals.updateBitVectorWithScratch(block);
-}
-
-void clang::runUninitializedVariablesAnalysis(const DeclContext &dc,
- const CFG &cfg,
- AnalysisContext &ac,
- UninitVariablesHandler &handler) {
- CFGBlockValues vals(cfg);
- vals.computeSetOfDeclarations(dc);
- if (vals.hasNoDeclarations())
- return;
- DataflowWorklist worklist(cfg);
- llvm::BitVector previouslyVisited(cfg.getNumBlockIDs());
-
- worklist.enqueueSuccessors(&cfg.getEntry());
-
- while (const CFGBlock *block = worklist.dequeue()) {
- // Did the block change?
- bool changed = runOnBlock(block, cfg, ac, vals);
- if (changed || !previouslyVisited[block->getBlockID()])
- worklist.enqueueSuccessors(block);
- previouslyVisited[block->getBlockID()] = true;
- }
-
- // Run through the blocks one more time, and report uninitialized variabes.
- for (CFG::const_iterator BI = cfg.begin(), BE = cfg.end(); BI != BE; ++BI) {
- runOnBlock(*BI, cfg, ac, vals, &handler, /* flagBlockUses */ true);
- }
-}
-
-UninitVariablesHandler::~UninitVariablesHandler() {}
-
diff --git a/lib/Basic/CMakeLists.txt b/lib/Basic/CMakeLists.txt
index 91e7deb078ad..c1e7cf6bf971 100644
--- a/lib/Basic/CMakeLists.txt
+++ b/lib/Basic/CMakeLists.txt
@@ -14,6 +14,7 @@ add_clang_library(clangBasic
Targets.cpp
TokenKinds.cpp
Version.cpp
+ VersionTuple.cpp
)
# Determine Subversion revision.
@@ -39,5 +40,6 @@ add_dependencies(clangBasic
ClangDiagnosticGroups
ClangDiagnosticLex
ClangDiagnosticParse
- ClangDiagnosticSema)
+ ClangDiagnosticSema
+ ClangDiagnosticIndexName)
diff --git a/lib/Basic/Diagnostic.cpp b/lib/Basic/Diagnostic.cpp
index 31e33315cce2..e8cd21885d22 100644
--- a/lib/Basic/Diagnostic.cpp
+++ b/lib/Basic/Diagnostic.cpp
@@ -16,6 +16,8 @@
#include "clang/Basic/PartialDiagnostic.h"
#include "llvm/ADT/SmallVector.h"
#include "llvm/Support/raw_ostream.h"
+#include "llvm/Support/CrashRecoveryContext.h"
+
using namespace clang;
static void DummyArgToStringFn(Diagnostic::ArgumentKind AK, intptr_t QT,
@@ -49,11 +51,6 @@ Diagnostic::Diagnostic(const llvm::IntrusiveRefCntPtr<DiagnosticIDs> &diags,
ErrorLimit = 0;
TemplateBacktraceLimit = 0;
- // Create a DiagState and DiagStatePoint representing diagnostic changes
- // through command-line.
- DiagStates.push_back(DiagState());
- PushDiagStatePoint(&DiagStates.back(), SourceLocation());
-
Reset();
}
@@ -100,6 +97,16 @@ void Diagnostic::Reset() {
// displayed.
LastDiagLevel = (DiagnosticIDs::Level)-1;
DelayedDiagID = 0;
+
+ // Clear state related to #pragma diagnostic.
+ DiagStates.clear();
+ DiagStatePoints.clear();
+ DiagStateOnPushStack.clear();
+
+ // Create a DiagState and DiagStatePoint representing diagnostic changes
+ // through command-line.
+ DiagStates.push_back(DiagState());
+ PushDiagStatePoint(&DiagStates.back(), SourceLocation());
}
void Diagnostic::SetDelayedDiagnostic(unsigned DiagID, llvm::StringRef Arg1,
@@ -168,7 +175,7 @@ void Diagnostic::setDiagnosticMapping(diag::kind Diag, diag::Mapping Map,
// after the previous one.
if ((Loc.isValid() && LastStateChangePos.isInvalid()) ||
LastStateChangePos.isBeforeInTranslationUnitThan(Loc)) {
- // A diagnostic pragma occured, create a new DiagState initialized with
+ // A diagnostic pragma occurred, create a new DiagState initialized with
// the current one and a new DiagStatePoint to record at which location
// the new state became active.
DiagStates.push_back(*GetCurDiagState());
@@ -683,5 +690,7 @@ PartialDiagnostic::StorageAllocator::StorageAllocator() {
}
PartialDiagnostic::StorageAllocator::~StorageAllocator() {
- assert(NumFreeListEntries == NumCached && "A partial is on the lamb");
+ // Don't assert if we are in a CrashRecovery context, as this
+ // invariant may be invalidated during a crash.
+ assert((NumFreeListEntries == NumCached || llvm::CrashRecoveryContext::isRecoveringFromCrash()) && "A partial is on the lamb");
}
diff --git a/lib/Basic/DiagnosticIDs.cpp b/lib/Basic/DiagnosticIDs.cpp
index 553e4c929454..b4dd575a9684 100644
--- a/lib/Basic/DiagnosticIDs.cpp
+++ b/lib/Basic/DiagnosticIDs.cpp
@@ -46,19 +46,41 @@ struct StaticDiagInfoRec {
unsigned AccessControl : 1;
unsigned Category : 5;
+ const char *Name;
+
const char *Description;
const char *OptionGroup;
+ const char *BriefExplanation;
+ const char *FullExplanation;
+
bool operator<(const StaticDiagInfoRec &RHS) const {
return DiagID < RHS.DiagID;
}
};
+struct StaticDiagNameIndexRec {
+ const char *Name;
+ unsigned short DiagID;
+
+ bool operator<(const StaticDiagNameIndexRec &RHS) const {
+ assert(Name && RHS.Name && "Null Diagnostic Name");
+ return strcmp(Name, RHS.Name) == -1;
+ }
+
+ bool operator==(const StaticDiagNameIndexRec &RHS) const {
+ assert(Name && RHS.Name && "Null Diagnostic Name");
+ return strcmp(Name, RHS.Name) == 0;
+ }
+};
+
}
static const StaticDiagInfoRec StaticDiagInfo[] = {
-#define DIAG(ENUM,CLASS,DEFAULT_MAPPING,DESC,GROUP,SFINAE,ACCESS,CATEGORY) \
- { diag::ENUM, DEFAULT_MAPPING, CLASS, SFINAE, ACCESS, CATEGORY, DESC, GROUP },
+#define DIAG(ENUM,CLASS,DEFAULT_MAPPING,DESC,GROUP, \
+ SFINAE,ACCESS,CATEGORY,BRIEF,FULL) \
+ { diag::ENUM, DEFAULT_MAPPING, CLASS, SFINAE, \
+ ACCESS, CATEGORY, #ENUM, DESC, GROUP, BRIEF, FULL },
#include "clang/Basic/DiagnosticCommonKinds.inc"
#include "clang/Basic/DiagnosticDriverKinds.inc"
#include "clang/Basic/DiagnosticFrontendKinds.inc"
@@ -67,20 +89,32 @@ static const StaticDiagInfoRec StaticDiagInfo[] = {
#include "clang/Basic/DiagnosticASTKinds.inc"
#include "clang/Basic/DiagnosticSemaKinds.inc"
#include "clang/Basic/DiagnosticAnalysisKinds.inc"
- { 0, 0, 0, 0, 0, 0, 0, 0}
-};
#undef DIAG
+ { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}
+};
+
+static const unsigned StaticDiagInfoSize =
+ sizeof(StaticDiagInfo)/sizeof(StaticDiagInfo[0])-1;
+
+/// To be sorted before first use (since it's splitted among multiple files)
+static StaticDiagNameIndexRec StaticDiagNameIndex[] = {
+#define DIAG_NAME_INDEX(ENUM) { #ENUM, diag::ENUM },
+#include "clang/Basic/DiagnosticIndexName.inc"
+#undef DIAG_NAME_INDEX
+ { 0, 0 }
+};
+
+static const unsigned StaticDiagNameIndexSize =
+ sizeof(StaticDiagNameIndex)/sizeof(StaticDiagNameIndex[0])-1;
/// GetDiagInfo - Return the StaticDiagInfoRec entry for the specified DiagID,
/// or null if the ID is invalid.
static const StaticDiagInfoRec *GetDiagInfo(unsigned DiagID) {
- unsigned NumDiagEntries = sizeof(StaticDiagInfo)/sizeof(StaticDiagInfo[0])-1;
-
// If assertions are enabled, verify that the StaticDiagInfo array is sorted.
#ifndef NDEBUG
static bool IsFirst = true;
if (IsFirst) {
- for (unsigned i = 1; i != NumDiagEntries; ++i) {
+ for (unsigned i = 1; i != StaticDiagInfoSize; ++i) {
assert(StaticDiagInfo[i-1].DiagID != StaticDiagInfo[i].DiagID &&
"Diag ID conflict, the enums at the start of clang::diag (in "
"DiagnosticIDs.h) probably need to be increased");
@@ -93,11 +127,11 @@ static const StaticDiagInfoRec *GetDiagInfo(unsigned DiagID) {
#endif
// Search the diagnostic table with a binary search.
- StaticDiagInfoRec Find = { DiagID, 0, 0, 0, 0, 0, 0, 0 };
+ StaticDiagInfoRec Find = { DiagID, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 };
const StaticDiagInfoRec *Found =
- std::lower_bound(StaticDiagInfo, StaticDiagInfo + NumDiagEntries, Find);
- if (Found == StaticDiagInfo + NumDiagEntries ||
+ std::lower_bound(StaticDiagInfo, StaticDiagInfo + StaticDiagInfoSize, Find);
+ if (Found == StaticDiagInfo + StaticDiagInfoSize ||
Found->DiagID != DiagID)
return 0;
@@ -119,7 +153,7 @@ const char *DiagnosticIDs::getWarningOptionForDiag(unsigned DiagID) {
return 0;
}
-/// getWarningOptionForDiag - Return the category number that a specified
+/// getCategoryNumberForDiag - Return the category number that a specified
/// DiagID belongs to, or 0 if no category.
unsigned DiagnosticIDs::getCategoryNumberForDiag(unsigned DiagID) {
if (const StaticDiagInfoRec *Info = GetDiagInfo(DiagID))
@@ -167,7 +201,48 @@ DiagnosticIDs::getDiagnosticSFINAEResponse(unsigned DiagID) {
return SFINAE_Report;
}
-/// getDiagClass - Return the class field of the diagnostic.
+/// getName - Given a diagnostic ID, return its name
+const char *DiagnosticIDs::getName(unsigned DiagID) {
+ if (const StaticDiagInfoRec *Info = GetDiagInfo(DiagID))
+ return Info->Name;
+ return 0;
+}
+
+/// getIdFromName - Given a diagnostic name, return its ID, or 0
+unsigned DiagnosticIDs::getIdFromName(char const *Name) {
+ StaticDiagNameIndexRec *StaticDiagNameIndexEnd =
+ StaticDiagNameIndex + StaticDiagNameIndexSize;
+
+ if (Name == 0) { return diag::DIAG_UPPER_LIMIT; }
+
+ StaticDiagNameIndexRec Find = { Name, 0 };
+
+ const StaticDiagNameIndexRec *Found =
+ std::lower_bound( StaticDiagNameIndex, StaticDiagNameIndexEnd, Find);
+ if (Found == StaticDiagNameIndexEnd ||
+ strcmp(Found->Name, Name) != 0)
+ return diag::DIAG_UPPER_LIMIT;
+
+ return Found->DiagID;
+}
+
+/// getBriefExplanation - Given a diagnostic ID, return a brief explanation
+/// of the issue
+const char *DiagnosticIDs::getBriefExplanation(unsigned DiagID) {
+ if (const StaticDiagInfoRec *Info = GetDiagInfo(DiagID))
+ return Info->BriefExplanation;
+ return 0;
+}
+
+/// getFullExplanation - Given a diagnostic ID, return a full explanation
+/// of the issue
+const char *DiagnosticIDs::getFullExplanation(unsigned DiagID) {
+ if (const StaticDiagInfoRec *Info = GetDiagInfo(DiagID))
+ return Info->FullExplanation;
+ return 0;
+}
+
+/// getBuiltinDiagClass - Return the class field of the diagnostic.
///
static unsigned getBuiltinDiagClass(unsigned DiagID) {
if (const StaticDiagInfoRec *Info = GetDiagInfo(DiagID))
@@ -329,6 +404,8 @@ DiagnosticIDs::getDiagnosticLevel(unsigned DiagID, unsigned DiagClass,
if (mapping)
*mapping = (diag::Mapping) (MappingInfo & 7);
+ bool ShouldEmitInSystemHeader = false;
+
switch (MappingInfo & 7) {
default: assert(0 && "Unknown mapping!");
case diag::MAP_IGNORE:
@@ -351,6 +428,9 @@ DiagnosticIDs::getDiagnosticLevel(unsigned DiagID, unsigned DiagClass,
case diag::MAP_FATAL:
Result = DiagnosticIDs::Fatal;
break;
+ case diag::MAP_WARNING_SHOW_IN_SYSTEM_HEADER:
+ ShouldEmitInSystemHeader = true;
+ // continue as MAP_WARNING.
case diag::MAP_WARNING:
// If warnings are globally mapped to ignore or error, do it.
if (Diag.IgnoreAllWarnings)
@@ -395,6 +475,20 @@ DiagnosticIDs::getDiagnosticLevel(unsigned DiagID, unsigned DiagClass,
if (Diag.AllExtensionsSilenced && isBuiltinExtensionDiag(DiagID))
return DiagnosticIDs::Ignored;
+ // If we are in a system header, we ignore it.
+ // We also want to ignore extensions and warnings in -Werror and
+ // -pedantic-errors modes, which *map* warnings/extensions to errors.
+ if (Result >= DiagnosticIDs::Warning &&
+ DiagClass != CLASS_ERROR &&
+ // Custom diagnostics always are emitted in system headers.
+ DiagID < diag::DIAG_UPPER_LIMIT &&
+ !ShouldEmitInSystemHeader &&
+ Diag.SuppressSystemWarnings &&
+ Loc.isValid() &&
+ Diag.getSourceManager().isInSystemHeader(
+ Diag.getSourceManager().getInstantiationLoc(Loc)))
+ return DiagnosticIDs::Ignored;
+
return Result;
}
@@ -480,16 +574,9 @@ bool DiagnosticIDs::ProcessDiag(Diagnostic &Diag) const {
DiagnosticIDs::Level DiagLevel;
unsigned DiagID = Info.getID();
- // ShouldEmitInSystemHeader - True if this diagnostic should be produced even
- // in a system header.
- bool ShouldEmitInSystemHeader;
-
if (DiagID >= diag::DIAG_UPPER_LIMIT) {
// Handle custom diagnostics, which cannot be mapped.
DiagLevel = CustomDiagInfo->getLevel(DiagID);
-
- // Custom diagnostics always are emitted in system headers.
- ShouldEmitInSystemHeader = true;
} else {
// Get the class of the diagnostic. If this is a NOTE, map it onto whatever
// the diagnostic level was for the previous diagnostic so that it is
@@ -497,14 +584,7 @@ bool DiagnosticIDs::ProcessDiag(Diagnostic &Diag) const {
unsigned DiagClass = getBuiltinDiagClass(DiagID);
if (DiagClass == CLASS_NOTE) {
DiagLevel = DiagnosticIDs::Note;
- ShouldEmitInSystemHeader = false; // extra consideration is needed
} else {
- // If this is not an error and we are in a system header, we ignore it.
- // Check the original Diag ID here, because we also want to ignore
- // extensions and warnings in -Werror and -pedantic-errors modes, which
- // *map* warnings/extensions to errors.
- ShouldEmitInSystemHeader = DiagClass == CLASS_ERROR;
-
DiagLevel = getDiagnosticLevel(DiagID, DiagClass, Info.getLocation(),
Diag);
}
@@ -540,18 +620,6 @@ bool DiagnosticIDs::ProcessDiag(Diagnostic &Diag) const {
Diag.LastDiagLevel == DiagnosticIDs::Ignored))
return false;
- // If this diagnostic is in a system header and is not a clang error, suppress
- // it.
- if (Diag.SuppressSystemWarnings && !ShouldEmitInSystemHeader &&
- Info.getLocation().isValid() &&
- Diag.getSourceManager().isInSystemHeader(
- Diag.getSourceManager().getInstantiationLoc(Info.getLocation())) &&
- (DiagLevel != DiagnosticIDs::Note ||
- Diag.LastDiagLevel == DiagnosticIDs::Ignored)) {
- Diag.LastDiagLevel = DiagnosticIDs::Ignored;
- return false;
- }
-
if (DiagLevel >= DiagnosticIDs::Error) {
if (Diag.Client->IncludeInDiagnosticCounts()) {
Diag.ErrorOccurred = true;
diff --git a/lib/Basic/FileManager.cpp b/lib/Basic/FileManager.cpp
index 342413d7da52..4e5a129082f4 100644
--- a/lib/Basic/FileManager.cpp
+++ b/lib/Basic/FileManager.cpp
@@ -313,7 +313,7 @@ const DirectoryEntry *FileManager::getDirectory(llvm::StringRef DirName) {
/// getFile - Lookup, cache, and verify the specified file (real or
/// virtual). This returns NULL if the file doesn't exist.
///
-const FileEntry *FileManager::getFile(llvm::StringRef Filename) {
+const FileEntry *FileManager::getFile(llvm::StringRef Filename, bool openFile) {
++NumFileLookups;
// See if there is already an entry in the map.
@@ -354,6 +354,11 @@ const FileEntry *FileManager::getFile(llvm::StringRef Filename) {
return 0;
}
+ if (FileDescriptor != -1 && !openFile) {
+ close(FileDescriptor);
+ FileDescriptor = -1;
+ }
+
// It exists. See if we have already opened a file with the same inode.
// This occurs when one dir is symlinked to another, for example.
FileEntry &UFE = UniqueRealFiles.getFile(InterndFileName, StatBuf);
@@ -450,13 +455,15 @@ FileManager::getVirtualFile(llvm::StringRef Filename, off_t Size,
return UFE;
}
-void FileManager::FixupRelativePath(llvm::sys::Path &path,
- const FileSystemOptions &FSOpts) {
- if (FSOpts.WorkingDir.empty() || llvm::sys::path::is_absolute(path.str()))
+void FileManager::FixupRelativePath(llvm::SmallVectorImpl<char> &path) const {
+ llvm::StringRef pathRef(path.data(), path.size());
+
+ if (FileSystemOpts.WorkingDir.empty()
+ || llvm::sys::path::is_absolute(pathRef))
return;
- llvm::SmallString<128> NewPath(FSOpts.WorkingDir);
- llvm::sys::path::append(NewPath, path.str());
+ llvm::SmallString<128> NewPath(FileSystemOpts.WorkingDir);
+ llvm::sys::path::append(NewPath, pathRef);
path = NewPath;
}
@@ -464,30 +471,32 @@ llvm::MemoryBuffer *FileManager::
getBufferForFile(const FileEntry *Entry, std::string *ErrorStr) {
llvm::OwningPtr<llvm::MemoryBuffer> Result;
llvm::error_code ec;
- if (FileSystemOpts.WorkingDir.empty()) {
- const char *Filename = Entry->getName();
- // If the file is already open, use the open file descriptor.
- if (Entry->FD != -1) {
- ec = llvm::MemoryBuffer::getOpenFile(Entry->FD, Filename, Result,
- Entry->getSize());
- if (ErrorStr)
- *ErrorStr = ec.message();
-
- close(Entry->FD);
- Entry->FD = -1;
- return Result.take();
- }
- // Otherwise, open the file.
+ const char *Filename = Entry->getName();
+ // If the file is already open, use the open file descriptor.
+ if (Entry->FD != -1) {
+ ec = llvm::MemoryBuffer::getOpenFile(Entry->FD, Filename, Result,
+ Entry->getSize());
+ if (ErrorStr)
+ *ErrorStr = ec.message();
+
+ close(Entry->FD);
+ Entry->FD = -1;
+ return Result.take();
+ }
+
+ // Otherwise, open the file.
+
+ if (FileSystemOpts.WorkingDir.empty()) {
ec = llvm::MemoryBuffer::getFile(Filename, Result, Entry->getSize());
if (ec && ErrorStr)
*ErrorStr = ec.message();
return Result.take();
}
-
- llvm::sys::Path FilePath(Entry->getName());
- FixupRelativePath(FilePath, FileSystemOpts);
- ec = llvm::MemoryBuffer::getFile(FilePath.c_str(), Result, Entry->getSize());
+
+ llvm::SmallString<128> FilePath(Entry->getName());
+ FixupRelativePath(FilePath);
+ ec = llvm::MemoryBuffer::getFile(FilePath.str(), Result, Entry->getSize());
if (ec && ErrorStr)
*ErrorStr = ec.message();
return Result.take();
@@ -504,8 +513,8 @@ getBufferForFile(llvm::StringRef Filename, std::string *ErrorStr) {
return Result.take();
}
- llvm::sys::Path FilePath(Filename);
- FixupRelativePath(FilePath, FileSystemOpts);
+ llvm::SmallString<128> FilePath(Filename);
+ FixupRelativePath(FilePath);
ec = llvm::MemoryBuffer::getFile(FilePath.c_str(), Result);
if (ec && ErrorStr)
*ErrorStr = ec.message();
@@ -525,13 +534,21 @@ bool FileManager::getStatValue(const char *Path, struct stat &StatBuf,
return FileSystemStatCache::get(Path, StatBuf, FileDescriptor,
StatCache.get());
- llvm::sys::Path FilePath(Path);
- FixupRelativePath(FilePath, FileSystemOpts);
+ llvm::SmallString<128> FilePath(Path);
+ FixupRelativePath(FilePath);
return FileSystemStatCache::get(FilePath.c_str(), StatBuf, FileDescriptor,
StatCache.get());
}
+bool FileManager::getNoncachedStatValue(llvm::StringRef Path,
+ struct stat &StatBuf) {
+ llvm::SmallString<128> FilePath(Path);
+ FixupRelativePath(FilePath);
+
+ return ::stat(FilePath.c_str(), &StatBuf) != 0;
+}
+
void FileManager::GetUniqueIDMapping(
llvm::SmallVectorImpl<const FileEntry *> &UIDToFiles) const {
UIDToFiles.clear();
diff --git a/lib/Basic/IdentifierTable.cpp b/lib/Basic/IdentifierTable.cpp
index ef11d658ed9e..cb1f55b75773 100644
--- a/lib/Basic/IdentifierTable.cpp
+++ b/lib/Basic/IdentifierTable.cpp
@@ -81,17 +81,18 @@ IdentifierTable::IdentifierTable(const LangOptions &LangOpts,
// Constants for TokenKinds.def
namespace {
enum {
- KEYALL = 1,
- KEYC99 = 2,
- KEYCXX = 4,
- KEYCXX0X = 8,
- KEYGNU = 16,
- KEYMS = 32,
- BOOLSUPPORT = 64,
- KEYALTIVEC = 128,
- KEYNOCXX = 256,
- KEYBORLAND = 512,
- KEYOPENCL = 1024
+ KEYC99 = 0x1,
+ KEYCXX = 0x2,
+ KEYCXX0X = 0x4,
+ KEYGNU = 0x8,
+ KEYMS = 0x10,
+ BOOLSUPPORT = 0x20,
+ KEYALTIVEC = 0x40,
+ KEYNOCXX = 0x80,
+ KEYBORLAND = 0x100,
+ KEYOPENCL = 0x200,
+ KEYC1X = 0x400,
+ KEYALL = 0x7ff
};
}
@@ -107,7 +108,7 @@ static void AddKeyword(llvm::StringRef Keyword,
tok::TokenKind TokenCode, unsigned Flags,
const LangOptions &LangOpts, IdentifierTable &Table) {
unsigned AddResult = 0;
- if (Flags & KEYALL) AddResult = 2;
+ if (Flags == KEYALL) AddResult = 2;
else if (LangOpts.CPlusPlus && (Flags & KEYCXX)) AddResult = 2;
else if (LangOpts.CPlusPlus0x && (Flags & KEYCXX0X)) AddResult = 2;
else if (LangOpts.C99 && (Flags & KEYC99)) AddResult = 2;
@@ -118,6 +119,7 @@ static void AddKeyword(llvm::StringRef Keyword,
else if (LangOpts.AltiVec && (Flags & KEYALTIVEC)) AddResult = 2;
else if (LangOpts.OpenCL && (Flags & KEYOPENCL)) AddResult = 2;
else if (!LangOpts.CPlusPlus && (Flags & KEYNOCXX)) AddResult = 2;
+ else if (LangOpts.C1X && (Flags & KEYC1X)) AddResult = 2;
// Don't add this keyword if disabled in this language.
if (AddResult == 0) return;
@@ -162,7 +164,12 @@ void IdentifierTable::AddKeywords(const LangOptions &LangOpts) {
#define OBJC2_AT_KEYWORD(NAME) \
if (LangOpts.ObjC2) \
AddObjCKeyword(llvm::StringRef(#NAME), tok::objc_##NAME, *this);
+#define TESTING_KEYWORD(NAME, FLAGS)
#include "clang/Basic/TokenKinds.def"
+
+ if (LangOpts.ParseUnknownAnytype)
+ AddKeyword("__unknown_anytype", tok::kw___unknown_anytype, KEYALL,
+ LangOpts, *this);
}
tok::PPKeywordKind IdentifierInfo::getPPKeywordID() const {
@@ -364,6 +371,56 @@ std::string Selector::getAsString() const {
return reinterpret_cast<MultiKeywordSelector *>(InfoPtr)->getName();
}
+/// Interpreting the given string using the normal CamelCase
+/// conventions, determine whether the given string starts with the
+/// given "word", which is assumed to end in a lowercase letter.
+static bool startsWithWord(llvm::StringRef name, llvm::StringRef word) {
+ if (name.size() < word.size()) return false;
+ return ((name.size() == word.size() ||
+ !islower(name[word.size()]))
+ && name.startswith(word));
+}
+
+ObjCMethodFamily Selector::getMethodFamilyImpl(Selector sel) {
+ IdentifierInfo *first = sel.getIdentifierInfoForSlot(0);
+ if (!first) return OMF_None;
+
+ llvm::StringRef name = first->getName();
+ if (sel.isUnarySelector()) {
+ if (name == "autorelease") return OMF_autorelease;
+ if (name == "dealloc") return OMF_dealloc;
+ if (name == "release") return OMF_release;
+ if (name == "retain") return OMF_retain;
+ if (name == "retainCount") return OMF_retainCount;
+ }
+
+ // The other method families may begin with a prefix of underscores.
+ while (!name.empty() && name.front() == '_')
+ name = name.substr(1);
+
+ if (name.empty()) return OMF_None;
+ switch (name.front()) {
+ case 'a':
+ if (startsWithWord(name, "alloc")) return OMF_alloc;
+ break;
+ case 'c':
+ if (startsWithWord(name, "copy")) return OMF_copy;
+ break;
+ case 'i':
+ if (startsWithWord(name, "init")) return OMF_init;
+ break;
+ case 'm':
+ if (startsWithWord(name, "mutableCopy")) return OMF_mutableCopy;
+ break;
+ case 'n':
+ if (startsWithWord(name, "new")) return OMF_new;
+ break;
+ default:
+ break;
+ }
+
+ return OMF_None;
+}
namespace {
struct SelectorTableImpl {
@@ -376,6 +433,10 @@ static SelectorTableImpl &getSelectorTableImpl(void *P) {
return *static_cast<SelectorTableImpl*>(P);
}
+size_t SelectorTable::getTotalMemory() const {
+ SelectorTableImpl &SelTabImpl = getSelectorTableImpl(Impl);
+ return SelTabImpl.Allocator.getTotalMemory();
+}
Selector SelectorTable::getSelector(unsigned nKeys, IdentifierInfo **IIV) {
if (nKeys < 2)
diff --git a/lib/Basic/SourceManager.cpp b/lib/Basic/SourceManager.cpp
index e2783ba6fda2..c3e03933e5e5 100644
--- a/lib/Basic/SourceManager.cpp
+++ b/lib/Basic/SourceManager.cpp
@@ -46,13 +46,26 @@ unsigned ContentCache::getSizeBytesMapped() const {
return Buffer.getPointer() ? Buffer.getPointer()->getBufferSize() : 0;
}
+/// Returns the kind of memory used to back the memory buffer for
+/// this content cache. This is used for performance analysis.
+llvm::MemoryBuffer::BufferKind ContentCache::getMemoryBufferKind() const {
+ assert(Buffer.getPointer());
+
+ // Should be unreachable, but keep for sanity.
+ if (!Buffer.getPointer())
+ return llvm::MemoryBuffer::MemoryBuffer_Malloc;
+
+ const llvm::MemoryBuffer *buf = Buffer.getPointer();
+ return buf->getBufferKind();
+}
+
/// getSize - Returns the size of the content encapsulated by this ContentCache.
/// This can be the size of the source file or the size of an arbitrary
/// scratch buffer. If the ContentCache encapsulates a source file, that
/// file is not lazily brought in from disk to satisfy this query.
unsigned ContentCache::getSize() const {
return Buffer.getPointer() ? (unsigned) Buffer.getPointer()->getBufferSize()
- : (unsigned) Entry->getSize();
+ : (unsigned) ContentsEntry->getSize();
}
void ContentCache::replaceBuffer(const llvm::MemoryBuffer *B,
@@ -70,8 +83,8 @@ const llvm::MemoryBuffer *ContentCache::getBuffer(Diagnostic &Diag,
SourceLocation Loc,
bool *Invalid) const {
// Lazily create the Buffer for ContentCaches that wrap files. If we already
- // computed it, jsut return what we have.
- if (Buffer.getPointer() || Entry == 0) {
+ // computed it, just return what we have.
+ if (Buffer.getPointer() || ContentsEntry == 0) {
if (Invalid)
*Invalid = isBufferInvalid();
@@ -79,7 +92,7 @@ const llvm::MemoryBuffer *ContentCache::getBuffer(Diagnostic &Diag,
}
std::string ErrorStr;
- Buffer.setPointer(SM.getFileManager().getBufferForFile(Entry, &ErrorStr));
+ Buffer.setPointer(SM.getFileManager().getBufferForFile(ContentsEntry, &ErrorStr));
// If we were unable to open the file, then we are in an inconsistent
// situation where the content cache referenced a file which no longer
@@ -93,18 +106,18 @@ const llvm::MemoryBuffer *ContentCache::getBuffer(Diagnostic &Diag,
// possible.
if (!Buffer.getPointer()) {
const llvm::StringRef FillStr("<<<MISSING SOURCE FILE>>>\n");
- Buffer.setPointer(MemoryBuffer::getNewMemBuffer(Entry->getSize(),
+ Buffer.setPointer(MemoryBuffer::getNewMemBuffer(ContentsEntry->getSize(),
"<invalid>"));
char *Ptr = const_cast<char*>(Buffer.getPointer()->getBufferStart());
- for (unsigned i = 0, e = Entry->getSize(); i != e; ++i)
+ for (unsigned i = 0, e = ContentsEntry->getSize(); i != e; ++i)
Ptr[i] = FillStr[i % FillStr.size()];
if (Diag.isDiagnosticInFlight())
Diag.SetDelayedDiagnostic(diag::err_cannot_open_file,
- Entry->getName(), ErrorStr);
+ ContentsEntry->getName(), ErrorStr);
else
Diag.Report(Loc, diag::err_cannot_open_file)
- << Entry->getName() << ErrorStr;
+ << ContentsEntry->getName() << ErrorStr;
Buffer.setInt(Buffer.getInt() | InvalidFlag);
@@ -114,25 +127,24 @@ const llvm::MemoryBuffer *ContentCache::getBuffer(Diagnostic &Diag,
// Check that the file's size is the same as in the file entry (which may
// have come from a stat cache).
- if (getRawBuffer()->getBufferSize() != (size_t)Entry->getSize()) {
+ if (getRawBuffer()->getBufferSize() != (size_t)ContentsEntry->getSize()) {
if (Diag.isDiagnosticInFlight())
Diag.SetDelayedDiagnostic(diag::err_file_modified,
- Entry->getName());
+ ContentsEntry->getName());
else
Diag.Report(Loc, diag::err_file_modified)
- << Entry->getName();
+ << ContentsEntry->getName();
Buffer.setInt(Buffer.getInt() | InvalidFlag);
if (Invalid) *Invalid = true;
return Buffer.getPointer();
}
-
+
// If the buffer is valid, check to see if it has a UTF Byte Order Mark
- // (BOM). We only support UTF-8 without a BOM right now. See
+ // (BOM). We only support UTF-8 with and without a BOM right now. See
// http://en.wikipedia.org/wiki/Byte_order_mark for more information.
llvm::StringRef BufStr = Buffer.getPointer()->getBuffer();
- const char *BOM = llvm::StringSwitch<const char *>(BufStr)
- .StartsWith("\xEF\xBB\xBF", "UTF-8")
+ const char *InvalidBOM = llvm::StringSwitch<const char *>(BufStr)
.StartsWith("\xFE\xFF", "UTF-16 (BE)")
.StartsWith("\xFF\xFE", "UTF-16 (LE)")
.StartsWith("\x00\x00\xFE\xFF", "UTF-32 (BE)")
@@ -145,9 +157,9 @@ const llvm::MemoryBuffer *ContentCache::getBuffer(Diagnostic &Diag,
.StartsWith("\x84\x31\x95\x33", "GB-18030")
.Default(0);
- if (BOM) {
+ if (InvalidBOM) {
Diag.Report(Loc, diag::err_unsupported_bom)
- << BOM << Entry->getName();
+ << InvalidBOM << ContentsEntry->getName();
Buffer.setInt(Buffer.getInt() | InvalidFlag);
}
@@ -279,7 +291,12 @@ void SourceManager::AddLineNote(SourceLocation Loc, unsigned LineNo,
int FilenameID) {
std::pair<FileID, unsigned> LocInfo = getDecomposedInstantiationLoc(Loc);
- const SrcMgr::FileInfo &FileInfo = getSLocEntry(LocInfo.first).getFile();
+ bool Invalid = false;
+ const SLocEntry &Entry = getSLocEntry(LocInfo.first, &Invalid);
+ if (!Entry.isFile() || Invalid)
+ return;
+
+ const SrcMgr::FileInfo &FileInfo = Entry.getFile();
// Remember that this file has #line directives now if it doesn't already.
const_cast<SrcMgr::FileInfo&>(FileInfo).setHasLineDirectives();
@@ -303,7 +320,13 @@ void SourceManager::AddLineNote(SourceLocation Loc, unsigned LineNo,
}
std::pair<FileID, unsigned> LocInfo = getDecomposedInstantiationLoc(Loc);
- const SrcMgr::FileInfo &FileInfo = getSLocEntry(LocInfo.first).getFile();
+
+ bool Invalid = false;
+ const SLocEntry &Entry = getSLocEntry(LocInfo.first, &Invalid);
+ if (!Entry.isFile() || Invalid)
+ return;
+
+ const SrcMgr::FileInfo &FileInfo = Entry.getFile();
// Remember that this file has #line directives now if it doesn't already.
const_cast<SrcMgr::FileInfo&>(FileInfo).setHasLineDirectives();
@@ -340,9 +363,9 @@ LineTableInfo &SourceManager::getLineTable() {
//===----------------------------------------------------------------------===//
SourceManager::SourceManager(Diagnostic &Diag, FileManager &FileMgr)
- : Diag(Diag), FileMgr(FileMgr),
+ : Diag(Diag), FileMgr(FileMgr), OverridenFilesKeepOriginalName(true),
ExternalSLocEntries(0), LineTable(0), NumLinearScans(0),
- NumBinaryProbes(0) {
+ NumBinaryProbes(0), FakeBufferForRecovery(0) {
clearIDTables();
Diag.setSourceManager(this);
}
@@ -362,6 +385,8 @@ SourceManager::~SourceManager() {
I->second->~ContentCache();
ContentCacheAlloc.Deallocate(I->second);
}
+
+ delete FakeBufferForRecovery;
}
void SourceManager::clearIDTables() {
@@ -395,7 +420,18 @@ SourceManager::getOrCreateContentCache(const FileEntry *FileEnt) {
unsigned EntryAlign = llvm::AlignOf<ContentCache>::Alignment;
EntryAlign = std::max(8U, EntryAlign);
Entry = ContentCacheAlloc.Allocate<ContentCache>(1, EntryAlign);
- new (Entry) ContentCache(FileEnt);
+
+ // If the file contents are overridden with contents from another file,
+ // pass that file to ContentCache.
+ llvm::DenseMap<const FileEntry *, const FileEntry *>::iterator
+ overI = OverriddenFiles.find(FileEnt);
+ if (overI == OverriddenFiles.end())
+ new (Entry) ContentCache(FileEnt);
+ else
+ new (Entry) ContentCache(OverridenFilesKeepOriginalName ? FileEnt
+ : overI->second,
+ overI->second);
+
return Entry;
}
@@ -445,6 +481,15 @@ void SourceManager::ClearPreallocatedSLocEntries() {
ExternalSLocEntries = 0;
}
+/// \brief As part of recovering from missing or changed content, produce a
+/// fake, non-empty buffer.
+const llvm::MemoryBuffer *SourceManager::getFakeBufferForRecovery() const {
+ if (!FakeBufferForRecovery)
+ FakeBufferForRecovery
+ = llvm::MemoryBuffer::getMemBuffer("<<<INVALID BUFFER>>");
+
+ return FakeBufferForRecovery;
+}
//===----------------------------------------------------------------------===//
// Methods to create new FileID's and instantiations.
@@ -531,10 +576,21 @@ void SourceManager::overrideFileContents(const FileEntry *SourceFile,
const_cast<SrcMgr::ContentCache *>(IR)->replaceBuffer(Buffer, DoNotFree);
}
+void SourceManager::overrideFileContents(const FileEntry *SourceFile,
+ const FileEntry *NewFile) {
+ assert(SourceFile->getSize() == NewFile->getSize() &&
+ "Different sizes, use the FileManager to create a virtual file with "
+ "the correct size");
+ assert(FileInfos.count(SourceFile) == 0 &&
+ "This function should be called at the initialization stage, before "
+ "any parsing occurs.");
+ OverriddenFiles[SourceFile] = NewFile;
+}
+
llvm::StringRef SourceManager::getBufferData(FileID FID, bool *Invalid) const {
bool MyInvalid = false;
- const SLocEntry &SLoc = getSLocEntry(FID.ID);
- if (!SLoc.isFile()) {
+ const SLocEntry &SLoc = getSLocEntry(FID.ID, &MyInvalid);
+ if (!SLoc.isFile() || MyInvalid) {
if (Invalid)
*Invalid = true;
return "<<<<<INVALID SOURCE LOCATION>>>>>";
@@ -562,7 +618,8 @@ llvm::StringRef SourceManager::getBufferData(FileID FID, bool *Invalid) const {
/// SLocEntryTable which contains the specified location.
///
FileID SourceManager::getFileIDSlow(unsigned SLocOffset) const {
- assert(SLocOffset && "Invalid FileID");
+ if (!SLocOffset)
+ return FileID::get(0);
// After the first and second level caches, I see two common sorts of
// behavior: 1) a lot of searched FileID's are "near" the cached file location
@@ -590,8 +647,13 @@ FileID SourceManager::getFileIDSlow(unsigned SLocOffset) const {
unsigned NumProbes = 0;
while (1) {
--I;
- if (ExternalSLocEntries)
- getSLocEntry(FileID::get(I - SLocEntryTable.begin()));
+ if (ExternalSLocEntries) {
+ bool Invalid = false;
+ getSLocEntry(FileID::get(I - SLocEntryTable.begin()), &Invalid);
+ if (Invalid)
+ return FileID::get(0);
+ }
+
if (I->getOffset() <= SLocOffset) {
#if 0
printf("lin %d -> %d [%s] %d %d\n", SLocOffset,
@@ -621,9 +683,13 @@ FileID SourceManager::getFileIDSlow(unsigned SLocOffset) const {
unsigned LessIndex = 0;
NumProbes = 0;
while (1) {
+ bool Invalid = false;
unsigned MiddleIndex = (GreaterIndex-LessIndex)/2+LessIndex;
- unsigned MidOffset = getSLocEntry(FileID::get(MiddleIndex)).getOffset();
-
+ unsigned MidOffset = getSLocEntry(FileID::get(MiddleIndex), &Invalid)
+ .getOffset();
+ if (Invalid)
+ return FileID::get(0);
+
++NumProbes;
// If the offset of the midpoint is too large, chop the high side of the
@@ -773,9 +839,16 @@ const char *SourceManager::getCharacterData(SourceLocation SL,
// Note that calling 'getBuffer()' may lazily page in a source file.
bool CharDataInvalid = false;
+ const SLocEntry &Entry = getSLocEntry(LocInfo.first, &CharDataInvalid);
+ if (CharDataInvalid || !Entry.isFile()) {
+ if (Invalid)
+ *Invalid = true;
+
+ return "<<<<INVALID BUFFER>>>>";
+ }
const llvm::MemoryBuffer *Buffer
- = getSLocEntry(LocInfo.first).getFile().getContentCache()
- ->getBuffer(Diag, *this, SourceLocation(), &CharDataInvalid);
+ = Entry.getFile().getContentCache()
+ ->getBuffer(Diag, *this, SourceLocation(), &CharDataInvalid);
if (Invalid)
*Invalid = CharDataInvalid;
return Buffer->getBufferStart() + (CharDataInvalid? 0 : LocInfo.second);
@@ -891,10 +964,18 @@ unsigned SourceManager::getLineNumber(FileID FID, unsigned FilePos,
ContentCache *Content;
if (LastLineNoFileIDQuery == FID)
Content = LastLineNoContentCache;
- else
- Content = const_cast<ContentCache*>(getSLocEntry(FID)
- .getFile().getContentCache());
-
+ else {
+ bool MyInvalid = false;
+ const SLocEntry &Entry = getSLocEntry(FID, &MyInvalid);
+ if (MyInvalid || !Entry.isFile()) {
+ if (Invalid)
+ *Invalid = true;
+ return 1;
+ }
+
+ Content = const_cast<ContentCache*>(Entry.getFile().getContentCache());
+ }
+
// If this is the first use of line information for this buffer, compute the
/// SourceLineCache for it on demand.
if (Content->SourceLineCache == 0) {
@@ -1021,7 +1102,12 @@ SrcMgr::CharacteristicKind
SourceManager::getFileCharacteristic(SourceLocation Loc) const {
assert(!Loc.isInvalid() && "Can't get file characteristic of invalid loc!");
std::pair<FileID, unsigned> LocInfo = getDecomposedInstantiationLoc(Loc);
- const SrcMgr::FileInfo &FI = getSLocEntry(LocInfo.first).getFile();
+ bool Invalid = false;
+ const SLocEntry &SEntry = getSLocEntry(LocInfo.first, &Invalid);
+ if (Invalid || !SEntry.isFile())
+ return C_User;
+
+ const SrcMgr::FileInfo &FI = SEntry.getFile();
// If there are no #line directives in this file, just return the whole-file
// state.
@@ -1064,18 +1150,23 @@ PresumedLoc SourceManager::getPresumedLoc(SourceLocation Loc) const {
// Presumed locations are always for instantiation points.
std::pair<FileID, unsigned> LocInfo = getDecomposedInstantiationLoc(Loc);
- const SrcMgr::FileInfo &FI = getSLocEntry(LocInfo.first).getFile();
+ bool Invalid = false;
+ const SLocEntry &Entry = getSLocEntry(LocInfo.first, &Invalid);
+ if (Invalid || !Entry.isFile())
+ return PresumedLoc();
+
+ const SrcMgr::FileInfo &FI = Entry.getFile();
const SrcMgr::ContentCache *C = FI.getContentCache();
// To get the source name, first consult the FileEntry (if one exists)
// before the MemBuffer as this will avoid unnecessarily paging in the
// MemBuffer.
const char *Filename;
- if (C->Entry)
- Filename = C->Entry->getName();
+ if (C->OrigEntry)
+ Filename = C->OrigEntry->getName();
else
Filename = C->getBuffer(Diag, *this)->getBufferIdentifier();
- bool Invalid = false;
+
unsigned LineNo = getLineNumber(LocInfo.first, LocInfo.second, &Invalid);
if (Invalid)
return PresumedLoc();
@@ -1152,18 +1243,22 @@ SourceLocation SourceManager::getLocation(const FileEntry *SourceFile,
llvm::Optional<ino_t> SourceFileInode;
llvm::Optional<llvm::StringRef> SourceFileName;
if (!MainFileID.isInvalid()) {
- const SLocEntry &MainSLoc = getSLocEntry(MainFileID);
+ bool Invalid = false;
+ const SLocEntry &MainSLoc = getSLocEntry(MainFileID, &Invalid);
+ if (Invalid)
+ return SourceLocation();
+
if (MainSLoc.isFile()) {
const ContentCache *MainContentCache
= MainSLoc.getFile().getContentCache();
if (!MainContentCache) {
// Can't do anything
- } else if (MainContentCache->Entry == SourceFile) {
+ } else if (MainContentCache->OrigEntry == SourceFile) {
FirstFID = MainFileID;
} else {
// Fall back: check whether we have the same base name and inode
// as the main file.
- const FileEntry *MainFile = MainContentCache->Entry;
+ const FileEntry *MainFile = MainContentCache->OrigEntry;
SourceFileName = llvm::sys::path::filename(SourceFile->getName());
if (*SourceFileName == llvm::sys::path::filename(MainFile->getName())) {
SourceFileInode = getActualFileInode(SourceFile);
@@ -1185,10 +1280,14 @@ SourceLocation SourceManager::getLocation(const FileEntry *SourceFile,
// The location we're looking for isn't in the main file; look
// through all of the source locations.
for (unsigned I = 0, N = sloc_entry_size(); I != N; ++I) {
- const SLocEntry &SLoc = getSLocEntry(I);
+ bool Invalid = false;
+ const SLocEntry &SLoc = getSLocEntry(I, &Invalid);
+ if (Invalid)
+ return SourceLocation();
+
if (SLoc.isFile() &&
SLoc.getFile().getContentCache() &&
- SLoc.getFile().getContentCache()->Entry == SourceFile) {
+ SLoc.getFile().getContentCache()->OrigEntry == SourceFile) {
FirstFID = FileID::get(I);
break;
}
@@ -1203,12 +1302,16 @@ SourceLocation SourceManager::getLocation(const FileEntry *SourceFile,
(SourceFileName = llvm::sys::path::filename(SourceFile->getName()))) &&
(SourceFileInode ||
(SourceFileInode = getActualFileInode(SourceFile)))) {
+ bool Invalid = false;
for (unsigned I = 0, N = sloc_entry_size(); I != N; ++I) {
- const SLocEntry &SLoc = getSLocEntry(I);
+ const SLocEntry &SLoc = getSLocEntry(I, &Invalid);
+ if (Invalid)
+ return SourceLocation();
+
if (SLoc.isFile()) {
const ContentCache *FileContentCache
= SLoc.getFile().getContentCache();
- const FileEntry *Entry =FileContentCache? FileContentCache->Entry : 0;
+ const FileEntry *Entry =FileContentCache? FileContentCache->OrigEntry : 0;
if (Entry &&
*SourceFileName == llvm::sys::path::filename(Entry->getName())) {
if (llvm::Optional<ino_t> EntryInode = getActualFileInode(Entry)) {
@@ -1367,7 +1470,7 @@ bool SourceManager::isBeforeInTranslationUnit(SourceLocation LHS,
while (!MoveUpIncludeHierarchy(LOffs, *this)) /*empty*/;
while (!MoveUpIncludeHierarchy(ROffs, *this)) /*empty*/;
- // If exactly one location is a memory buffer, assume it preceeds the other.
+ // If exactly one location is a memory buffer, assume it precedes the other.
// Strip off macro instantation locations, going up to the top-level File
// SLocEntry.
@@ -1403,3 +1506,24 @@ void SourceManager::PrintStats() const {
}
ExternalSLocEntrySource::~ExternalSLocEntrySource() { }
+
+/// Return the amount of memory used by memory buffers, breaking down
+/// by heap-backed versus mmap'ed memory.
+SourceManager::MemoryBufferSizes SourceManager::getMemoryBufferSizes() const {
+ size_t malloc_bytes = 0;
+ size_t mmap_bytes = 0;
+
+ for (unsigned i = 0, e = MemBufferInfos.size(); i != e; ++i)
+ if (size_t sized_mapped = MemBufferInfos[i]->getSizeBytesMapped())
+ switch (MemBufferInfos[i]->getMemoryBufferKind()) {
+ case llvm::MemoryBuffer::MemoryBuffer_MMap:
+ mmap_bytes += sized_mapped;
+ break;
+ case llvm::MemoryBuffer::MemoryBuffer_Malloc:
+ malloc_bytes += sized_mapped;
+ break;
+ }
+
+ return MemoryBufferSizes(malloc_bytes, mmap_bytes);
+}
+
diff --git a/lib/Basic/TargetInfo.cpp b/lib/Basic/TargetInfo.cpp
index a9eeb8b4cc4e..dcf0cb4237a9 100644
--- a/lib/Basic/TargetInfo.cpp
+++ b/lib/Basic/TargetInfo.cpp
@@ -11,6 +11,7 @@
//
//===----------------------------------------------------------------------===//
+#include "clang/Basic/AddressSpaces.h"
#include "clang/Basic/TargetInfo.h"
#include "clang/Basic/LangOptions.h"
#include "llvm/ADT/APFloat.h"
@@ -19,6 +20,8 @@
#include <cstdlib>
using namespace clang;
+static const LangAS::Map DefaultAddrSpaceMap = { 0 };
+
// TargetInfo Constructor.
TargetInfo::TargetInfo(const std::string &T) : Triple(T) {
// Set defaults. Defaults are set for a 32-bit RISC platform, like PPC or
@@ -64,6 +67,13 @@ TargetInfo::TargetInfo(const std::string &T) : Triple(T) {
// Default to using the Itanium ABI.
CXXABI = CXXABI_Itanium;
+
+ // Default to an empty address space map.
+ AddrSpaceMap = &DefaultAddrSpaceMap;
+
+ // Default to an unknown platform name.
+ PlatformName = "unknown";
+ PlatformMinVersion = VersionTuple();
}
// Out of line virtual dtor for TargetInfo.
@@ -422,7 +432,7 @@ bool TargetInfo::validateInputConstraint(ConstraintInfo *OutputConstraints,
case ',': // multiple alternative constraint. Ignore comma.
break;
case '?': // Disparage slightly code.
- case '!': // Disparage severly.
+ case '!': // Disparage severely.
break; // Pass them.
}
diff --git a/lib/Basic/Targets.cpp b/lib/Basic/Targets.cpp
index 55321f2498ef..97109caf1237 100644
--- a/lib/Basic/Targets.cpp
+++ b/lib/Basic/Targets.cpp
@@ -76,7 +76,9 @@ public:
static void getDarwinDefines(MacroBuilder &Builder, const LangOptions &Opts,
- const llvm::Triple &Triple) {
+ const llvm::Triple &Triple,
+ llvm::StringRef &PlatformName,
+ VersionTuple &PlatformMinVersion) {
Builder.defineMacro("__APPLE_CC__", "5621");
Builder.defineMacro("__APPLE__");
Builder.defineMacro("__MACH__");
@@ -99,19 +101,40 @@ static void getDarwinDefines(MacroBuilder &Builder, const LangOptions &Opts,
if (Opts.POSIXThreads)
Builder.defineMacro("_REENTRANT");
- // Get the OS version number from the triple.
+ // Get the platform type and version number from the triple.
unsigned Maj, Min, Rev;
// If no version was given, default to to 10.4.0, for simplifying tests.
- if (Triple.getOSName() == "darwin") {
+ if (Triple.getOSName() == "darwin" || Triple.getOSName() == "osx") {
+ PlatformName = "macosx";
Min = Rev = 0;
Maj = 8;
- } else
- Triple.getDarwinNumber(Maj, Min, Rev);
+ } else {
+ // Otherwise, honor all three triple forms ("-darwinNNN[-iphoneos]",
+ // "-osxNNN", and "-iosNNN").
+
+ if (Triple.getOS() == llvm::Triple::Darwin) {
+ // For historical reasons that make little sense, the version passed here
+ // is the "darwin" version, which drops the 10 and offsets by 4.
+ Triple.getOSVersion(Maj, Min, Rev);
+
+ if (Triple.getEnvironmentName() == "iphoneos") {
+ PlatformName = "ios";
+ } else {
+ PlatformName = "macosx";
+ Rev = Min;
+ Min = Maj - 4;
+ Maj = 10;
+ }
+ } else {
+ Triple.getOSVersion(Maj, Min, Rev);
+ PlatformName = llvm::Triple::getOSTypeName(Triple.getOS());
+ }
+ }
// Set the appropriate OS version define.
- if (Triple.getEnvironmentName() == "iphoneos") {
- assert(Maj < 10 && Min < 99 && Rev < 99 && "Invalid version!");
+ if (PlatformName == "ios") {
+ assert(Maj < 10 && Min < 100 && Rev < 100 && "Invalid version!");
char Str[6];
Str[0] = '0' + Maj;
Str[1] = '0' + (Min / 10);
@@ -121,22 +144,22 @@ static void getDarwinDefines(MacroBuilder &Builder, const LangOptions &Opts,
Str[5] = '\0';
Builder.defineMacro("__ENVIRONMENT_IPHONE_OS_VERSION_MIN_REQUIRED__", Str);
} else {
- // For historical reasons that make little sense, the version passed here is
- // the "darwin" version, which drops the 10 and offsets by 4.
- Rev = Min;
- Min = Maj - 4;
- Maj = 10;
-
+ // Note that the Driver allows versions which aren't representable in the
+ // define (because we only get a single digit for the minor and micro
+ // revision numbers). So, we limit them to the maximum representable
+ // version.
assert(Triple.getEnvironmentName().empty() && "Invalid environment!");
- assert(Maj < 99 && Min < 10 && Rev < 10 && "Invalid version!");
+ assert(Maj < 100 && Min < 100 && Rev < 100 && "Invalid version!");
char Str[5];
Str[0] = '0' + (Maj / 10);
Str[1] = '0' + (Maj % 10);
- Str[2] = '0' + Min;
- Str[3] = '0' + Rev;
+ Str[2] = '0' + std::min(Min, 9U);
+ Str[3] = '0' + std::min(Rev, 9U);
Str[4] = '\0';
Builder.defineMacro("__ENVIRONMENT_MAC_OS_X_VERSION_MIN_REQUIRED__", Str);
}
+
+ PlatformMinVersion = VersionTuple(Maj, Min, Rev);
}
namespace {
@@ -145,7 +168,8 @@ class DarwinTargetInfo : public OSTargetInfo<Target> {
protected:
virtual void getOSDefines(const LangOptions &Opts, const llvm::Triple &Triple,
MacroBuilder &Builder) const {
- getDarwinDefines(Builder, Opts, Triple);
+ getDarwinDefines(Builder, Opts, Triple, this->PlatformName,
+ this->PlatformMinVersion);
}
public:
@@ -159,8 +183,9 @@ public:
// Let MCSectionMachO validate this.
llvm::StringRef Segment, Section;
unsigned TAA, StubSize;
+ bool HasTAA;
return llvm::MCSectionMachO::ParseSectionSpecifier(SR, Segment, Section,
- TAA, StubSize);
+ TAA, HasTAA, StubSize);
}
virtual const char *getStaticInitSectionSpecifier() const {
@@ -823,6 +848,87 @@ public:
} // end anonymous namespace.
namespace {
+ class PTXTargetInfo : public TargetInfo {
+ static const char * const GCCRegNames[];
+ static const Builtin::Info BuiltinInfo[];
+ public:
+ PTXTargetInfo(const std::string& triple) : TargetInfo(triple) {
+ TLSSupported = false;
+ LongWidth = LongAlign = 64;
+ }
+ virtual void getTargetDefines(const LangOptions &Opts,
+ MacroBuilder &Builder) const {
+ Builder.defineMacro("__PTX__");
+ }
+ virtual void getTargetBuiltins(const Builtin::Info *&Records,
+ unsigned &NumRecords) const {
+ Records = BuiltinInfo;
+ NumRecords = clang::PTX::LastTSBuiltin-Builtin::FirstTSBuiltin;
+ }
+
+ virtual void getGCCRegNames(const char * const *&Names,
+ unsigned &NumNames) const;
+ virtual void getGCCRegAliases(const GCCRegAlias *&Aliases,
+ unsigned &NumAliases) const {
+ // No aliases.
+ Aliases = 0;
+ NumAliases = 0;
+ }
+ virtual bool validateAsmConstraint(const char *&Name,
+ TargetInfo::ConstraintInfo &info) const {
+ // FIXME: implement
+ return true;
+ }
+ virtual const char *getClobbers() const {
+ // FIXME: Is this really right?
+ return "";
+ }
+ virtual const char *getVAListDeclaration() const {
+ // FIXME: implement
+ return "typedef char* __builtin_va_list;";
+ }
+ };
+
+ const Builtin::Info PTXTargetInfo::BuiltinInfo[] = {
+#define BUILTIN(ID, TYPE, ATTRS) { #ID, TYPE, ATTRS, 0, ALL_LANGUAGES, false },
+#define LIBBUILTIN(ID, TYPE, ATTRS, HEADER) { #ID, TYPE, ATTRS, HEADER,\
+ ALL_LANGUAGES, false },
+#include "clang/Basic/BuiltinsPTX.def"
+ };
+
+ const char * const PTXTargetInfo::GCCRegNames[] = {
+ "r0"
+ };
+
+ void PTXTargetInfo::getGCCRegNames(const char * const *&Names,
+ unsigned &NumNames) const {
+ Names = GCCRegNames;
+ NumNames = llvm::array_lengthof(GCCRegNames);
+ }
+
+
+ class PTX32TargetInfo : public PTXTargetInfo {
+ public:
+ PTX32TargetInfo(const std::string& triple) : PTXTargetInfo(triple) {
+ PointerWidth = PointerAlign = 32;
+ SizeType = PtrDiffType = IntPtrType = TargetInfo::UnsignedInt;
+ DescriptionString
+ = "e-p:32:32-i64:64:64-f64:64:64-n1:8:16:32:64";
+ }
+ };
+
+ class PTX64TargetInfo : public PTXTargetInfo {
+ public:
+ PTX64TargetInfo(const std::string& triple) : PTXTargetInfo(triple) {
+ PointerWidth = PointerAlign = 64;
+ SizeType = PtrDiffType = IntPtrType = TargetInfo::UnsignedLongLong;
+ DescriptionString
+ = "e-p:64:64-i64:64:64-f64:64:64-n1:8:16:32:64";
+ }
+ };
+}
+
+namespace {
// MBlaze abstract base class
class MBlazeTargetInfo : public TargetInfo {
static const char * const GCCRegNames[];
@@ -1074,8 +1180,11 @@ void X86TargetInfo::getDefaultFeatures(const std::string &CPU,
else if (CPU == "corei7") {
setFeatureEnabled(Features, "sse4", true);
setFeatureEnabled(Features, "aes", true);
- }
- else if (CPU == "k6" || CPU == "winchip-c6")
+ } else if (CPU == "sandybridge") {
+ setFeatureEnabled(Features, "sse4", true);
+ setFeatureEnabled(Features, "aes", true);
+// setFeatureEnabled(Features, "avx", true);
+ } else if (CPU == "k6" || CPU == "winchip-c6")
setFeatureEnabled(Features, "mmx", true);
else if (CPU == "k6-2" || CPU == "k6-3" || CPU == "athlon" ||
CPU == "athlon-tbird" || CPU == "winchip2" || CPU == "c3") {
@@ -1133,7 +1242,8 @@ bool X86TargetInfo::setFeatureEnabled(llvm::StringMap<bool> &Features,
Features["avx"] = true;
} else {
if (Name == "mmx")
- Features["mmx"] = Features["sse"] = Features["sse2"] = Features["sse3"] =
+ Features["mmx"] = Features["3dnow"] = Features["3dnowa"] =
+ Features["sse"] = Features["sse2"] = Features["sse3"] =
Features["ssse3"] = Features["sse41"] = Features["sse42"] = false;
else if (Name == "sse")
Features["sse"] = Features["sse2"] = Features["sse3"] =
@@ -1146,12 +1256,10 @@ bool X86TargetInfo::setFeatureEnabled(llvm::StringMap<bool> &Features,
Features["sse42"] = false;
else if (Name == "ssse3")
Features["ssse3"] = Features["sse41"] = Features["sse42"] = false;
- else if (Name == "sse4")
+ else if (Name == "sse4" || Name == "sse4.1")
Features["sse41"] = Features["sse42"] = false;
else if (Name == "sse4.2")
Features["sse42"] = false;
- else if (Name == "sse4.1")
- Features["sse41"] = Features["sse42"] = false;
else if (Name == "3dnow")
Features["3dnow"] = Features["3dnowa"] = false;
else if (Name == "3dnowa")
@@ -1451,7 +1559,7 @@ class VisualStudioWindowsX86_32TargetInfo : public WindowsX86_32TargetInfo {
public:
VisualStudioWindowsX86_32TargetInfo(const std::string& triple)
: WindowsX86_32TargetInfo(triple) {
- LongDoubleWidth = 64;
+ LongDoubleWidth = LongDoubleAlign = 64;
LongDoubleFormat = &llvm::APFloat::IEEEdouble;
}
virtual void getTargetDefines(const LangOptions &Opts,
@@ -1481,7 +1589,15 @@ public:
Builder.defineMacro("_X86_");
Builder.defineMacro("__MSVCRT__");
Builder.defineMacro("__MINGW32__");
- Builder.defineMacro("__declspec", "__declspec");
+
+ // mingw32-gcc provides __declspec(a) as alias of __attribute__((a)).
+ // In contrast, clang-cc1 provides __declspec(a) with -fms-extensions.
+ if (Opts.Microsoft)
+ // Provide "as-is" __declspec.
+ Builder.defineMacro("__declspec", "__declspec");
+ else
+ // Provide alias of __attribute__ like mingw32-gcc.
+ Builder.defineMacro("__declspec(a)", "__attribute__((a))");
}
};
} // end anonymous namespace
@@ -1606,6 +1722,8 @@ class VisualStudioWindowsX86_64TargetInfo : public WindowsX86_64TargetInfo {
public:
VisualStudioWindowsX86_64TargetInfo(const std::string& triple)
: WindowsX86_64TargetInfo(triple) {
+ LongDoubleWidth = LongDoubleAlign = 64;
+ LongDoubleFormat = &llvm::APFloat::IEEEdouble;
}
virtual void getTargetDefines(const LangOptions &Opts,
MacroBuilder &Builder) const {
@@ -1629,8 +1747,17 @@ public:
WindowsX86_64TargetInfo::getTargetDefines(Opts, Builder);
DefineStd(Builder, "WIN64", Opts);
Builder.defineMacro("__MSVCRT__");
+ Builder.defineMacro("__MINGW32__");
Builder.defineMacro("__MINGW64__");
- Builder.defineMacro("__declspec", "__declspec");
+
+ // mingw32-gcc provides __declspec(a) as alias of __attribute__((a)).
+ // In contrast, clang-cc1 provides __declspec(a) with -fms-extensions.
+ if (Opts.Microsoft)
+ // Provide "as-is" __declspec.
+ Builder.defineMacro("__declspec", "__declspec");
+ else
+ // Provide alias of __attribute__ like mingw32-gcc.
+ Builder.defineMacro("__declspec(a)", "__attribute__((a))");
}
};
} // end anonymous namespace
@@ -1700,13 +1827,15 @@ public:
// FIXME: Should we just treat this as a feature?
IsThumb = getTriple().getArchName().startswith("thumb");
if (IsThumb) {
+ // Thumb1 add sp, #imm requires the immediate value be multiple of 4,
+ // so set preferred for small types to 32.
DescriptionString = ("e-p:32:32:32-i1:8:32-i8:8:32-i16:16:32-i32:32:32-"
"i64:64:64-f32:32:32-f64:64:64-"
- "v64:64:64-v128:128:128-a0:0:32-n32");
+ "v64:64:64-v128:64:128-a0:0:32-n32");
} else {
DescriptionString = ("e-p:32:32:32-i1:8:8-i8:8:8-i16:16:16-i32:32:32-"
"i64:64:64-f32:32:32-f64:64:64-"
- "v64:64:64-v128:128:128-a0:0:64-n32");
+ "v64:64:64-v128:64:128-a0:0:64-n32");
}
// ARM targets default to using the ARM C++ ABI.
@@ -1729,13 +1858,15 @@ public:
UseBitFieldTypeAlignment = false;
if (IsThumb) {
+ // Thumb1 add sp, #imm requires the immediate value be multiple of 4,
+ // so set preferred for small types to 32.
DescriptionString = ("e-p:32:32:32-i1:8:32-i8:8:32-i16:16:32-i32:32:32-"
"i64:32:32-f32:32:32-f64:32:32-"
- "v64:64:64-v128:128:128-a0:0:32-n32");
+ "v64:32:64-v128:32:128-a0:0:32-n32");
} else {
DescriptionString = ("e-p:32:32:32-i1:8:8-i8:8:8-i16:16:16-i32:32:32-"
- "i64:32:32-f32:32:32-f64:32:32-"
- "v64:64:64-v128:128:128-a0:0:64-n32");
+ "i64:32:64-f32:32:32-f64:32:64-"
+ "v64:32:64-v128:32:128-a0:0:32-n32");
}
// FIXME: Override "preferred align" for double and long long.
@@ -1822,6 +1953,7 @@ public:
.Cases("arm1156t2-s", "arm1156t2f-s", "6T2")
.Cases("cortex-a8", "cortex-a9", "7A")
.Case("cortex-m3", "7M")
+ .Case("cortex-m0", "6M")
.Default(0);
}
virtual bool setCPU(const std::string &Name) {
@@ -1984,7 +2116,7 @@ class DarwinARMTargetInfo :
protected:
virtual void getOSDefines(const LangOptions &Opts, const llvm::Triple &Triple,
MacroBuilder &Builder) const {
- getDarwinDefines(Builder, Opts, Triple);
+ getDarwinDefines(Builder, Opts, Triple, PlatformName, PlatformMinVersion);
}
public:
@@ -2563,11 +2695,12 @@ static TargetInfo *AllocateTarget(const std::string &T) {
case llvm::Triple::arm:
case llvm::Triple::thumb:
+ if (Triple.isOSDarwin())
+ return new DarwinARMTargetInfo(T);
+
switch (os) {
case llvm::Triple::Linux:
return new LinuxTargetInfo<ARMTargetInfo>(T);
- case llvm::Triple::Darwin:
- return new DarwinARMTargetInfo(T);
case llvm::Triple::FreeBSD:
return new FreeBSDTargetInfo<ARMTargetInfo>(T);
default:
@@ -2595,14 +2728,14 @@ static TargetInfo *AllocateTarget(const std::string &T) {
return new MipselTargetInfo(T);
case llvm::Triple::ppc:
- if (os == llvm::Triple::Darwin)
+ if (Triple.isOSDarwin())
return new DarwinPPC32TargetInfo(T);
else if (os == llvm::Triple::FreeBSD)
return new FreeBSDTargetInfo<PPC32TargetInfo>(T);
return new PPC32TargetInfo(T);
case llvm::Triple::ppc64:
- if (os == llvm::Triple::Darwin)
+ if (Triple.isOSDarwin())
return new DarwinPPC64TargetInfo(T);
else if (os == llvm::Triple::Lv2)
return new PS3PPUTargetInfo<PPC64TargetInfo>(T);
@@ -2610,6 +2743,11 @@ static TargetInfo *AllocateTarget(const std::string &T) {
return new FreeBSDTargetInfo<PPC64TargetInfo>(T);
return new PPC64TargetInfo(T);
+ case llvm::Triple::ptx32:
+ return new PTX32TargetInfo(T);
+ case llvm::Triple::ptx64:
+ return new PTX64TargetInfo(T);
+
case llvm::Triple::mblaze:
return new MBlazeTargetInfo(T);
@@ -2631,11 +2769,12 @@ static TargetInfo *AllocateTarget(const std::string &T) {
return new TCETargetInfo(T);
case llvm::Triple::x86:
+ if (Triple.isOSDarwin())
+ return new DarwinI386TargetInfo(T);
+
switch (os) {
case llvm::Triple::AuroraUX:
return new AuroraUXTargetInfo<X86_32TargetInfo>(T);
- case llvm::Triple::Darwin:
- return new DarwinI386TargetInfo(T);
case llvm::Triple::Linux:
return new LinuxTargetInfo<X86_32TargetInfo>(T);
case llvm::Triple::DragonFly:
@@ -2663,11 +2802,12 @@ static TargetInfo *AllocateTarget(const std::string &T) {
}
case llvm::Triple::x86_64:
+ if (Triple.isOSDarwin() || Triple.getEnvironment() == llvm::Triple::MachO)
+ return new DarwinX86_64TargetInfo(T);
+
switch (os) {
case llvm::Triple::AuroraUX:
return new AuroraUXTargetInfo<X86_64TargetInfo>(T);
- case llvm::Triple::Darwin:
- return new DarwinX86_64TargetInfo(T);
case llvm::Triple::Linux:
return new LinuxTargetInfo<X86_64TargetInfo>(T);
case llvm::Triple::DragonFly:
@@ -2683,10 +2823,7 @@ static TargetInfo *AllocateTarget(const std::string &T) {
case llvm::Triple::MinGW32:
return new MinGWX86_64TargetInfo(T);
case llvm::Triple::Win32: // This is what Triple.h supports now.
- if (Triple.getEnvironment() == llvm::Triple::MachO)
- return new DarwinX86_64TargetInfo(T);
- else
- return new VisualStudioWindowsX86_64TargetInfo(T);
+ return new VisualStudioWindowsX86_64TargetInfo(T);
default:
return new X86_64TargetInfo(T);
}
diff --git a/lib/Basic/Version.cpp b/lib/Basic/Version.cpp
index 6573eb96e3f3..8f713524629c 100644
--- a/lib/Basic/Version.cpp
+++ b/lib/Basic/Version.cpp
@@ -17,11 +17,12 @@
#include <cstring>
#include <cstdlib>
-using namespace std;
-
namespace clang {
std::string getClangRepositoryPath() {
+#if defined(CLANG_REPOSITORY_STRING)
+ return CLANG_REPOSITORY_STRING;
+#else
#ifdef SVN_REPOSITORY
llvm::StringRef URL(SVN_REPOSITORY);
#else
@@ -45,6 +46,7 @@ std::string getClangRepositoryPath() {
URL = URL.substr(Start + 4);
return URL;
+#endif
}
std::string getClangRevision() {
@@ -87,4 +89,17 @@ std::string getClangFullVersion() {
return OS.str();
}
+std::string getClangFullCPPVersion() {
+ // The version string we report in __VERSION__ is just a compacted version of
+ // the one we report on the command line.
+ std::string buf;
+ llvm::raw_string_ostream OS(buf);
+#ifdef CLANG_VENDOR
+ OS << CLANG_VENDOR;
+#endif
+ OS << "Clang " CLANG_VERSION_STRING " ("
+ << getClangFullRepositoryVersion() << ')';
+ return OS.str();
+}
+
} // end namespace clang
diff --git a/lib/Basic/VersionTuple.cpp b/lib/Basic/VersionTuple.cpp
new file mode 100644
index 000000000000..d5cf126ff487
--- /dev/null
+++ b/lib/Basic/VersionTuple.cpp
@@ -0,0 +1,36 @@
+//===- VersionTuple.cpp - Version Number Handling ---------------*- C++ -*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+//
+// This file implements the VersionTuple class, which represents a version in
+// the form major[.minor[.subminor]].
+//
+//===----------------------------------------------------------------------===//
+#include "clang/Basic/VersionTuple.h"
+#include "llvm/Support/raw_ostream.h"
+
+using namespace clang;
+
+std::string VersionTuple::getAsString() const {
+ std::string Result;
+ {
+ llvm::raw_string_ostream Out(Result);
+ Out << *this;
+ }
+ return Result;
+}
+
+llvm::raw_ostream& clang::operator<<(llvm::raw_ostream &Out,
+ const VersionTuple &V) {
+ Out << V.getMajor();
+ if (llvm::Optional<unsigned> Minor = V.getMinor())
+ Out << '.' << *Minor;
+ if (llvm::Optional<unsigned> Subminor = V.getSubminor())
+ Out << '.' << *Subminor;
+ return Out;
+}
diff --git a/lib/CMakeLists.txt b/lib/CMakeLists.txt
index b4574344bc5f..0943e2b1c785 100644
--- a/lib/CMakeLists.txt
+++ b/lib/CMakeLists.txt
@@ -13,3 +13,4 @@ add_subdirectory(Frontend)
add_subdirectory(FrontendTool)
add_subdirectory(Index)
add_subdirectory(StaticAnalyzer)
+add_subdirectory(Tooling)
diff --git a/lib/CodeGen/BackendUtil.cpp b/lib/CodeGen/BackendUtil.cpp
index 9897b1b1a028..1264473dabce 100644
--- a/lib/CodeGen/BackendUtil.cpp
+++ b/lib/CodeGen/BackendUtil.cpp
@@ -30,6 +30,7 @@
#include "llvm/Target/TargetMachine.h"
#include "llvm/Target/TargetOptions.h"
#include "llvm/Target/TargetRegistry.h"
+#include "llvm/Transforms/Instrumentation.h"
using namespace clang;
using namespace llvm;
@@ -108,9 +109,9 @@ void EmitAssemblyHelper::CreatePasses() {
OptLevel = 0;
Inlining = CodeGenOpts.NoInlining;
}
-
+
FunctionPassManager *FPM = getPerFunctionPasses();
-
+
TargetLibraryInfo *TLI =
new TargetLibraryInfo(Triple(TheModule->getTargetTriple()));
if (!CodeGenOpts.SimplifyLibCalls)
@@ -133,8 +134,10 @@ void EmitAssemblyHelper::CreatePasses() {
//
// FIXME: Derive these constants in a principled fashion.
unsigned Threshold = 225;
- if (CodeGenOpts.OptimizeSize)
+ if (CodeGenOpts.OptimizeSize == 1) //-Os
Threshold = 75;
+ else if (CodeGenOpts.OptimizeSize == 2) //-Oz
+ Threshold = 25;
else if (OptLevel > 2)
Threshold = 275;
InliningPass = createFunctionInliningPass(Threshold);
@@ -146,12 +149,19 @@ void EmitAssemblyHelper::CreatePasses() {
}
PassManager *MPM = getPerModulePasses();
-
+
TLI = new TargetLibraryInfo(Triple(TheModule->getTargetTriple()));
if (!CodeGenOpts.SimplifyLibCalls)
TLI->disableAllFunctions();
MPM->add(TLI);
+ if (CodeGenOpts.EmitGcovArcs || CodeGenOpts.EmitGcovNotes) {
+ MPM->add(createGCOVProfilerPass(CodeGenOpts.EmitGcovNotes,
+ CodeGenOpts.EmitGcovArcs));
+ if (!CodeGenOpts.DebugInfo)
+ MPM->add(createStripSymbolsPass(true));
+ }
+
// For now we always create per module passes.
llvm::createStandardModulePasses(MPM, OptLevel,
CodeGenOpts.OptimizeSize,
@@ -190,7 +200,7 @@ bool EmitAssemblyHelper::AddEmitPasses(BackendAction Action,
}
// Set float ABI type.
- if (CodeGenOpts.FloatABI == "soft")
+ if (CodeGenOpts.FloatABI == "soft" || CodeGenOpts.FloatABI == "softfp")
llvm::FloatABIType = llvm::FloatABI::Soft;
else if (CodeGenOpts.FloatABI == "hard")
llvm::FloatABIType = llvm::FloatABI::Hard;
@@ -248,6 +258,8 @@ bool EmitAssemblyHelper::AddEmitPasses(BackendAction Action,
}
if (llvm::TimePassesIsEnabled)
BackendArgs.push_back("-time-passes");
+ for (unsigned i = 0, e = CodeGenOpts.BackendOptions.size(); i != e; ++i)
+ BackendArgs.push_back(CodeGenOpts.BackendOptions[i].c_str());
BackendArgs.push_back(0);
llvm::cl::ParseCommandLineOptions(BackendArgs.size() - 1,
const_cast<char **>(&BackendArgs[0]));
@@ -266,6 +278,10 @@ bool EmitAssemblyHelper::AddEmitPasses(BackendAction Action,
if (CodeGenOpts.RelaxAll)
TM->setMCRelaxAll(true);
+ if (CodeGenOpts.SaveTempLabels)
+ TM->setMCSaveTempLabels(true);
+ if (CodeGenOpts.NoDwarf2CFIAsm)
+ TM->setMCUseCFI(false);
// Create the code generator passes.
PassManager *PM = getCodeGenPasses();
@@ -319,6 +335,9 @@ void EmitAssemblyHelper::EmitAssembly(BackendAction Action, raw_ostream *OS) {
return;
}
+ // Before executing passes, print the final values of the LLVM options.
+ cl::PrintOptionValues();
+
// Run passes. For now we do all passes at once, but eventually we
// would like to have the option of streaming code generation.
diff --git a/lib/CodeGen/CGBlocks.cpp b/lib/CodeGen/CGBlocks.cpp
index 9587de223aa7..99a69a4f4a93 100644
--- a/lib/CodeGen/CGBlocks.cpp
+++ b/lib/CodeGen/CGBlocks.cpp
@@ -27,13 +27,16 @@ using namespace CodeGen;
CGBlockInfo::CGBlockInfo(const BlockExpr *blockExpr, const char *N)
: Name(N), CXXThisIndex(0), CanBeGlobal(false), NeedsCopyDispose(false),
- HasCXXObject(false), StructureType(0), Block(blockExpr) {
+ HasCXXObject(false), UsesStret(false), StructureType(0), Block(blockExpr) {
// Skip asm prefix, if any.
if (Name && Name[0] == '\01')
++Name;
}
+// Anchor the vtable to this translation unit.
+CodeGenModule::ByrefHelpers::~ByrefHelpers() {}
+
/// Build the given block as a global block.
static llvm::Constant *buildGlobalBlock(CodeGenModule &CGM,
const CGBlockInfo &blockInfo,
@@ -104,23 +107,6 @@ static llvm::Constant *buildBlockDescriptor(CodeGenModule &CGM,
return llvm::ConstantExpr::getBitCast(global, CGM.getBlockDescriptorType());
}
-static BlockFlags computeBlockFlag(CodeGenModule &CGM,
- const BlockExpr *BE,
- BlockFlags flags) {
- const FunctionType *ftype = BE->getFunctionType();
-
- // This is a bit overboard.
- CallArgList args;
- const CGFunctionInfo &fnInfo =
- CGM.getTypes().getFunctionInfo(ftype->getResultType(), args,
- ftype->getExtInfo());
-
- if (CGM.ReturnTypeUsesSRet(fnInfo))
- flags |= BLOCK_USE_STRET;
-
- return flags;
-}
-
/*
Purely notional variadic template describing the layout of a block.
@@ -536,7 +522,7 @@ llvm::Value *CodeGenFunction::EmitBlockLiteral(const BlockExpr *blockExpr) {
BlockFlags flags = BLOCK_HAS_SIGNATURE;
if (blockInfo.NeedsCopyDispose) flags |= BLOCK_HAS_COPY_DISPOSE;
if (blockInfo.HasCXXObject) flags |= BLOCK_HAS_CXX_OBJ;
- flags = computeBlockFlag(CGM, blockInfo.getBlockExpr(), flags);
+ if (blockInfo.UsesStret) flags |= BLOCK_USE_STRET;
// Initialize the block literal.
Builder.CreateStore(isa, Builder.CreateStructGEP(blockAddr, 0, "block.isa"));
@@ -630,7 +616,9 @@ llvm::Value *CodeGenFunction::EmitBlockLiteral(const BlockExpr *blockExpr) {
ImplicitCastExpr l2r(ImplicitCastExpr::OnStack, type, CK_LValueToRValue,
declRef, VK_RValue);
- EmitAnyExprToMem(&l2r, blockField, /*volatile*/ false, /*init*/ true);
+ EmitExprAsInit(&l2r, variable, blockField,
+ getContext().getDeclAlign(variable),
+ /*captured by init*/ false);
}
// Push a destructor if necessary. The semantics for when this
@@ -734,7 +722,7 @@ RValue CodeGenFunction::EmitBlockCallExpr(const CallExpr* E,
// Add the block literal.
QualType VoidPtrTy = getContext().getPointerType(getContext().VoidTy);
CallArgList Args;
- Args.push_back(std::make_pair(RValue::get(BlockLiteral), VoidPtrTy));
+ Args.add(RValue::get(BlockLiteral), VoidPtrTy);
QualType FnType = BPT->getPointeeType();
@@ -745,7 +733,7 @@ RValue CodeGenFunction::EmitBlockCallExpr(const CallExpr* E,
// Load the function.
llvm::Value *Func = Builder.CreateLoad(FuncPtr, "tmp");
- const FunctionType *FuncTy = FnType->getAs<FunctionType>();
+ const FunctionType *FuncTy = FnType->castAs<FunctionType>();
QualType ResultType = FuncTy->getResultType();
const CGFunctionInfo &FnInfo =
@@ -834,8 +822,9 @@ static llvm::Constant *buildGlobalBlock(CodeGenModule &CGM,
fields[0] = CGM.getNSConcreteGlobalBlock();
// __flags
- BlockFlags flags = computeBlockFlag(CGM, blockInfo.getBlockExpr(),
- BLOCK_IS_GLOBAL | BLOCK_HAS_SIGNATURE);
+ BlockFlags flags = BLOCK_IS_GLOBAL | BLOCK_HAS_SIGNATURE;
+ if (blockInfo.UsesStret) flags |= BLOCK_USE_STRET;
+
fields[1] = llvm::ConstantInt::get(CGM.IntTy, flags.getBitMask());
// Reserved
@@ -873,7 +862,10 @@ CodeGenFunction::GenerateBlockFunction(GlobalDecl GD,
const DeclMapTy &ldm) {
const BlockDecl *blockDecl = blockInfo.getBlockDecl();
- DebugInfo = CGM.getDebugInfo();
+ // Check if we should generate debug info for this block function.
+ if (CGM.getModuleDebugInfo())
+ DebugInfo = CGM.getModuleDebugInfo();
+
BlockInfo = &blockInfo;
// Arrange for local static and local extern declarations to appear
@@ -897,12 +889,12 @@ CodeGenFunction::GenerateBlockFunction(GlobalDecl GD,
ImplicitParamDecl selfDecl(const_cast<BlockDecl*>(blockDecl),
SourceLocation(), II, selfTy);
- args.push_back(std::make_pair(&selfDecl, selfTy));
+ args.push_back(&selfDecl);
// Now add the rest of the parameters.
for (BlockDecl::param_const_iterator i = blockDecl->param_begin(),
e = blockDecl->param_end(); i != e; ++i)
- args.push_back(std::make_pair(*i, (*i)->getType()));
+ args.push_back(*i);
// Create the function declaration.
const FunctionProtoType *fnType =
@@ -910,6 +902,9 @@ CodeGenFunction::GenerateBlockFunction(GlobalDecl GD,
const CGFunctionInfo &fnInfo =
CGM.getTypes().getFunctionInfo(fnType->getResultType(), args,
fnType->getExtInfo());
+ if (CGM.ReturnTypeUsesSRet(fnInfo))
+ blockInfo.UsesStret = true;
+
const llvm::FunctionType *fnLLVMType =
CGM.getTypes().GetFunctionType(fnInfo, fnType->isVariadic());
@@ -921,8 +916,8 @@ CodeGenFunction::GenerateBlockFunction(GlobalDecl GD,
CGM.SetInternalFunctionAttributes(blockDecl, fn, fnInfo);
// Begin generating the function.
- StartFunction(blockDecl, fnType->getResultType(), fn, args,
- blockInfo.getBlockExpr()->getBody()->getLocEnd());
+ StartFunction(blockDecl, fnType->getResultType(), fn, fnInfo, args,
+ blockInfo.getBlockExpr()->getBody()->getLocStart());
CurFuncDecl = outerFnDecl; // StartFunction sets this to blockDecl
// Okay. Undo some of what StartFunction did.
@@ -1049,13 +1044,10 @@ CodeGenFunction::GenerateCopyHelperFunction(const CGBlockInfo &blockInfo) {
ASTContext &C = getContext();
FunctionArgList args;
- // FIXME: This leaks
- ImplicitParamDecl *dstDecl =
- ImplicitParamDecl::Create(C, 0, SourceLocation(), 0, C.VoidPtrTy);
- args.push_back(std::make_pair(dstDecl, dstDecl->getType()));
- ImplicitParamDecl *srcDecl =
- ImplicitParamDecl::Create(C, 0, SourceLocation(), 0, C.VoidPtrTy);
- args.push_back(std::make_pair(srcDecl, srcDecl->getType()));
+ ImplicitParamDecl dstDecl(0, SourceLocation(), 0, C.VoidPtrTy);
+ args.push_back(&dstDecl);
+ ImplicitParamDecl srcDecl(0, SourceLocation(), 0, C.VoidPtrTy);
+ args.push_back(&srcDecl);
const CGFunctionInfo &FI =
CGM.getTypes().getFunctionInfo(C.VoidTy, args, FunctionType::ExtInfo());
@@ -1073,20 +1065,21 @@ CodeGenFunction::GenerateCopyHelperFunction(const CGBlockInfo &blockInfo) {
FunctionDecl *FD = FunctionDecl::Create(C,
C.getTranslationUnitDecl(),
+ SourceLocation(),
SourceLocation(), II, C.VoidTy, 0,
SC_Static,
SC_None,
false,
true);
- StartFunction(FD, C.VoidTy, Fn, args, SourceLocation());
+ StartFunction(FD, C.VoidTy, Fn, FI, args, SourceLocation());
const llvm::Type *structPtrTy = blockInfo.StructureType->getPointerTo();
- llvm::Value *src = GetAddrOfLocalVar(srcDecl);
+ llvm::Value *src = GetAddrOfLocalVar(&srcDecl);
src = Builder.CreateLoad(src);
src = Builder.CreateBitCast(src, structPtrTy, "block.source");
- llvm::Value *dst = GetAddrOfLocalVar(dstDecl);
+ llvm::Value *dst = GetAddrOfLocalVar(&dstDecl);
dst = Builder.CreateLoad(dst);
dst = Builder.CreateBitCast(dst, structPtrTy, "block.dest");
@@ -1143,10 +1136,8 @@ CodeGenFunction::GenerateDestroyHelperFunction(const CGBlockInfo &blockInfo) {
ASTContext &C = getContext();
FunctionArgList args;
- // FIXME: This leaks
- ImplicitParamDecl *srcDecl =
- ImplicitParamDecl::Create(C, 0, SourceLocation(), 0, C.VoidPtrTy);
- args.push_back(std::make_pair(srcDecl, srcDecl->getType()));
+ ImplicitParamDecl srcDecl(0, SourceLocation(), 0, C.VoidPtrTy);
+ args.push_back(&srcDecl);
const CGFunctionInfo &FI =
CGM.getTypes().getFunctionInfo(C.VoidTy, args, FunctionType::ExtInfo());
@@ -1163,15 +1154,16 @@ CodeGenFunction::GenerateDestroyHelperFunction(const CGBlockInfo &blockInfo) {
= &CGM.getContext().Idents.get("__destroy_helper_block_");
FunctionDecl *FD = FunctionDecl::Create(C, C.getTranslationUnitDecl(),
+ SourceLocation(),
SourceLocation(), II, C.VoidTy, 0,
SC_Static,
SC_None,
false, true);
- StartFunction(FD, C.VoidTy, Fn, args, SourceLocation());
+ StartFunction(FD, C.VoidTy, Fn, FI, args, SourceLocation());
const llvm::Type *structPtrTy = blockInfo.StructureType->getPointerTo();
- llvm::Value *src = GetAddrOfLocalVar(srcDecl);
+ llvm::Value *src = GetAddrOfLocalVar(&srcDecl);
src = Builder.CreateLoad(src);
src = Builder.CreateBitCast(src, structPtrTy, "block");
@@ -1229,99 +1221,158 @@ CodeGenFunction::GenerateDestroyHelperFunction(const CGBlockInfo &blockInfo) {
return llvm::ConstantExpr::getBitCast(Fn, VoidPtrTy);
}
-llvm::Constant *CodeGenFunction::
-GeneratebyrefCopyHelperFunction(const llvm::Type *T, BlockFieldFlags flags,
- const VarDecl *variable) {
- QualType R = getContext().VoidTy;
-
- FunctionArgList Args;
- // FIXME: This leaks
- ImplicitParamDecl *Dst =
- ImplicitParamDecl::Create(getContext(), 0,
- SourceLocation(), 0,
- getContext().getPointerType(getContext().VoidTy));
- Args.push_back(std::make_pair(Dst, Dst->getType()));
-
- // FIXME: This leaks
- ImplicitParamDecl *Src =
- ImplicitParamDecl::Create(getContext(), 0,
- SourceLocation(), 0,
- getContext().getPointerType(getContext().VoidTy));
- Args.push_back(std::make_pair(Src, Src->getType()));
+namespace {
+
+/// Emits the copy/dispose helper functions for a __block object of id type.
+class ObjectByrefHelpers : public CodeGenModule::ByrefHelpers {
+ BlockFieldFlags Flags;
+
+public:
+ ObjectByrefHelpers(CharUnits alignment, BlockFieldFlags flags)
+ : ByrefHelpers(alignment), Flags(flags) {}
+
+ void emitCopy(CodeGenFunction &CGF, llvm::Value *destField,
+ llvm::Value *srcField) {
+ destField = CGF.Builder.CreateBitCast(destField, CGF.VoidPtrTy);
+
+ srcField = CGF.Builder.CreateBitCast(srcField, CGF.VoidPtrPtrTy);
+ llvm::Value *srcValue = CGF.Builder.CreateLoad(srcField);
+
+ unsigned flags = (Flags | BLOCK_BYREF_CALLER).getBitMask();
+
+ llvm::Value *flagsVal = llvm::ConstantInt::get(CGF.Int32Ty, flags);
+ llvm::Value *fn = CGF.CGM.getBlockObjectAssign();
+ CGF.Builder.CreateCall3(fn, destField, srcValue, flagsVal);
+ }
+
+ void emitDispose(CodeGenFunction &CGF, llvm::Value *field) {
+ field = CGF.Builder.CreateBitCast(field, CGF.Int8PtrTy->getPointerTo(0));
+ llvm::Value *value = CGF.Builder.CreateLoad(field);
+
+ CGF.BuildBlockRelease(value, Flags | BLOCK_BYREF_CALLER);
+ }
+
+ void profileImpl(llvm::FoldingSetNodeID &id) const {
+ id.AddInteger(Flags.getBitMask());
+ }
+};
+
+/// Emits the copy/dispose helpers for a __block variable with a
+/// nontrivial copy constructor or destructor.
+class CXXByrefHelpers : public CodeGenModule::ByrefHelpers {
+ QualType VarType;
+ const Expr *CopyExpr;
+
+public:
+ CXXByrefHelpers(CharUnits alignment, QualType type,
+ const Expr *copyExpr)
+ : ByrefHelpers(alignment), VarType(type), CopyExpr(copyExpr) {}
+
+ bool needsCopy() const { return CopyExpr != 0; }
+ void emitCopy(CodeGenFunction &CGF, llvm::Value *destField,
+ llvm::Value *srcField) {
+ if (!CopyExpr) return;
+ CGF.EmitSynthesizedCXXCopyCtor(destField, srcField, CopyExpr);
+ }
+
+ void emitDispose(CodeGenFunction &CGF, llvm::Value *field) {
+ EHScopeStack::stable_iterator cleanupDepth = CGF.EHStack.stable_begin();
+ CGF.PushDestructorCleanup(VarType, field);
+ CGF.PopCleanupBlocks(cleanupDepth);
+ }
+
+ void profileImpl(llvm::FoldingSetNodeID &id) const {
+ id.AddPointer(VarType.getCanonicalType().getAsOpaquePtr());
+ }
+};
+} // end anonymous namespace
+
+static llvm::Constant *
+generateByrefCopyHelper(CodeGenFunction &CGF,
+ const llvm::StructType &byrefType,
+ CodeGenModule::ByrefHelpers &byrefInfo) {
+ ASTContext &Context = CGF.getContext();
+
+ QualType R = Context.VoidTy;
+
+ FunctionArgList args;
+ ImplicitParamDecl dst(0, SourceLocation(), 0, Context.VoidPtrTy);
+ args.push_back(&dst);
+
+ ImplicitParamDecl src(0, SourceLocation(), 0, Context.VoidPtrTy);
+ args.push_back(&src);
const CGFunctionInfo &FI =
- CGM.getTypes().getFunctionInfo(R, Args, FunctionType::ExtInfo());
+ CGF.CGM.getTypes().getFunctionInfo(R, args, FunctionType::ExtInfo());
- CodeGenTypes &Types = CGM.getTypes();
+ CodeGenTypes &Types = CGF.CGM.getTypes();
const llvm::FunctionType *LTy = Types.GetFunctionType(FI, false);
// FIXME: We'd like to put these into a mergable by content, with
// internal linkage.
llvm::Function *Fn =
llvm::Function::Create(LTy, llvm::GlobalValue::InternalLinkage,
- "__Block_byref_object_copy_", &CGM.getModule());
+ "__Block_byref_object_copy_", &CGF.CGM.getModule());
IdentifierInfo *II
- = &CGM.getContext().Idents.get("__Block_byref_object_copy_");
+ = &Context.Idents.get("__Block_byref_object_copy_");
- FunctionDecl *FD = FunctionDecl::Create(getContext(),
- getContext().getTranslationUnitDecl(),
+ FunctionDecl *FD = FunctionDecl::Create(Context,
+ Context.getTranslationUnitDecl(),
+ SourceLocation(),
SourceLocation(), II, R, 0,
SC_Static,
SC_None,
false, true);
- StartFunction(FD, R, Fn, Args, SourceLocation());
-
- // dst->x
- llvm::Value *V = GetAddrOfLocalVar(Dst);
- V = Builder.CreateBitCast(V, llvm::PointerType::get(T, 0));
- V = Builder.CreateLoad(V);
- V = Builder.CreateStructGEP(V, 6, "x");
- llvm::Value *DstObj = V;
-
- // src->x
- V = GetAddrOfLocalVar(Src);
- V = Builder.CreateLoad(V);
- V = Builder.CreateBitCast(V, T);
- V = Builder.CreateStructGEP(V, 6, "x");
-
- if (Expr *copyExpr = getContext().getBlockVarCopyInits(variable)) {
- llvm::Value *SrcObj = V;
- EmitSynthesizedCXXCopyCtor(DstObj, SrcObj, copyExpr);
- } else {
- DstObj = Builder.CreateBitCast(DstObj, VoidPtrTy);
- V = Builder.CreateBitCast(V, VoidPtrPtrTy);
- llvm::Value *SrcObj = Builder.CreateLoad(V);
- flags |= BLOCK_BYREF_CALLER;
- llvm::Value *N = llvm::ConstantInt::get(Int32Ty, flags.getBitMask());
- llvm::Value *F = CGM.getBlockObjectAssign();
- Builder.CreateCall3(F, DstObj, SrcObj, N);
- }
-
- FinishFunction();
+ CGF.StartFunction(FD, R, Fn, FI, args, SourceLocation());
- return llvm::ConstantExpr::getBitCast(Fn, Int8PtrTy);
+ if (byrefInfo.needsCopy()) {
+ const llvm::Type *byrefPtrType = byrefType.getPointerTo(0);
+
+ // dst->x
+ llvm::Value *destField = CGF.GetAddrOfLocalVar(&dst);
+ destField = CGF.Builder.CreateLoad(destField);
+ destField = CGF.Builder.CreateBitCast(destField, byrefPtrType);
+ destField = CGF.Builder.CreateStructGEP(destField, 6, "x");
+
+ // src->x
+ llvm::Value *srcField = CGF.GetAddrOfLocalVar(&src);
+ srcField = CGF.Builder.CreateLoad(srcField);
+ srcField = CGF.Builder.CreateBitCast(srcField, byrefPtrType);
+ srcField = CGF.Builder.CreateStructGEP(srcField, 6, "x");
+
+ byrefInfo.emitCopy(CGF, destField, srcField);
+ }
+
+ CGF.FinishFunction();
+
+ return llvm::ConstantExpr::getBitCast(Fn, CGF.Int8PtrTy);
}
-llvm::Constant *
-CodeGenFunction::GeneratebyrefDestroyHelperFunction(const llvm::Type *T,
- BlockFieldFlags flags,
- const VarDecl *variable) {
- QualType R = getContext().VoidTy;
+/// Build the copy helper for a __block variable.
+static llvm::Constant *buildByrefCopyHelper(CodeGenModule &CGM,
+ const llvm::StructType &byrefType,
+ CodeGenModule::ByrefHelpers &info) {
+ CodeGenFunction CGF(CGM);
+ return generateByrefCopyHelper(CGF, byrefType, info);
+}
- FunctionArgList Args;
- // FIXME: This leaks
- ImplicitParamDecl *Src =
- ImplicitParamDecl::Create(getContext(), 0,
- SourceLocation(), 0,
- getContext().getPointerType(getContext().VoidTy));
+/// Generate code for a __block variable's dispose helper.
+static llvm::Constant *
+generateByrefDisposeHelper(CodeGenFunction &CGF,
+ const llvm::StructType &byrefType,
+ CodeGenModule::ByrefHelpers &byrefInfo) {
+ ASTContext &Context = CGF.getContext();
+ QualType R = Context.VoidTy;
- Args.push_back(std::make_pair(Src, Src->getType()));
+ FunctionArgList args;
+ ImplicitParamDecl src(0, SourceLocation(), 0, Context.VoidPtrTy);
+ args.push_back(&src);
const CGFunctionInfo &FI =
- CGM.getTypes().getFunctionInfo(R, Args, FunctionType::ExtInfo());
+ CGF.CGM.getTypes().getFunctionInfo(R, args, FunctionType::ExtInfo());
- CodeGenTypes &Types = CGM.getTypes();
+ CodeGenTypes &Types = CGF.CGM.getTypes();
const llvm::FunctionType *LTy = Types.GetFunctionType(FI, false);
// FIXME: We'd like to put these into a mergable by content, with
@@ -1329,81 +1380,255 @@ CodeGenFunction::GeneratebyrefDestroyHelperFunction(const llvm::Type *T,
llvm::Function *Fn =
llvm::Function::Create(LTy, llvm::GlobalValue::InternalLinkage,
"__Block_byref_object_dispose_",
- &CGM.getModule());
+ &CGF.CGM.getModule());
IdentifierInfo *II
- = &CGM.getContext().Idents.get("__Block_byref_object_dispose_");
+ = &Context.Idents.get("__Block_byref_object_dispose_");
- FunctionDecl *FD = FunctionDecl::Create(getContext(),
- getContext().getTranslationUnitDecl(),
+ FunctionDecl *FD = FunctionDecl::Create(Context,
+ Context.getTranslationUnitDecl(),
+ SourceLocation(),
SourceLocation(), II, R, 0,
SC_Static,
SC_None,
false, true);
- StartFunction(FD, R, Fn, Args, SourceLocation());
+ CGF.StartFunction(FD, R, Fn, FI, args, SourceLocation());
+
+ if (byrefInfo.needsDispose()) {
+ llvm::Value *V = CGF.GetAddrOfLocalVar(&src);
+ V = CGF.Builder.CreateLoad(V);
+ V = CGF.Builder.CreateBitCast(V, byrefType.getPointerTo(0));
+ V = CGF.Builder.CreateStructGEP(V, 6, "x");
- llvm::Value *V = GetAddrOfLocalVar(Src);
- V = Builder.CreateBitCast(V, llvm::PointerType::get(T, 0));
- V = Builder.CreateLoad(V);
- V = Builder.CreateStructGEP(V, 6, "x");
+ byrefInfo.emitDispose(CGF, V);
+ }
- // If it's not any kind of special object, it must have a destructor
- // or something.
- if (!flags.isSpecialPointer()) {
- EHScopeStack::stable_iterator CleanupDepth = EHStack.stable_begin();
- PushDestructorCleanup(variable->getType(), V);
- PopCleanupBlocks(CleanupDepth);
+ CGF.FinishFunction();
- // Otherwise, call _Block_object_dispose.
- } else {
- V = Builder.CreateBitCast(V, llvm::PointerType::get(Int8PtrTy, 0));
- V = Builder.CreateLoad(V);
+ return llvm::ConstantExpr::getBitCast(Fn, CGF.Int8PtrTy);
+}
- flags |= BLOCK_BYREF_CALLER;
- BuildBlockRelease(V, flags);
+/// Build the dispose helper for a __block variable.
+static llvm::Constant *buildByrefDisposeHelper(CodeGenModule &CGM,
+ const llvm::StructType &byrefType,
+ CodeGenModule::ByrefHelpers &info) {
+ CodeGenFunction CGF(CGM);
+ return generateByrefDisposeHelper(CGF, byrefType, info);
+}
+
+///
+template <class T> static T *buildByrefHelpers(CodeGenModule &CGM,
+ const llvm::StructType &byrefTy,
+ T &byrefInfo) {
+ // Increase the field's alignment to be at least pointer alignment,
+ // since the layout of the byref struct will guarantee at least that.
+ byrefInfo.Alignment = std::max(byrefInfo.Alignment,
+ CharUnits::fromQuantity(CGM.PointerAlignInBytes));
+
+ llvm::FoldingSetNodeID id;
+ byrefInfo.Profile(id);
+
+ void *insertPos;
+ CodeGenModule::ByrefHelpers *node
+ = CGM.ByrefHelpersCache.FindNodeOrInsertPos(id, insertPos);
+ if (node) return static_cast<T*>(node);
+
+ byrefInfo.CopyHelper = buildByrefCopyHelper(CGM, byrefTy, byrefInfo);
+ byrefInfo.DisposeHelper = buildByrefDisposeHelper(CGM, byrefTy, byrefInfo);
+
+ T *copy = new (CGM.getContext()) T(byrefInfo);
+ CGM.ByrefHelpersCache.InsertNode(copy, insertPos);
+ return copy;
+}
+
+CodeGenModule::ByrefHelpers *
+CodeGenFunction::buildByrefHelpers(const llvm::StructType &byrefType,
+ const AutoVarEmission &emission) {
+ const VarDecl &var = *emission.Variable;
+ QualType type = var.getType();
+
+ if (const CXXRecordDecl *record = type->getAsCXXRecordDecl()) {
+ const Expr *copyExpr = CGM.getContext().getBlockVarCopyInits(&var);
+ if (!copyExpr && record->hasTrivialDestructor()) return 0;
+
+ CXXByrefHelpers byrefInfo(emission.Alignment, type, copyExpr);
+ return ::buildByrefHelpers(CGM, byrefType, byrefInfo);
}
- FinishFunction();
+ BlockFieldFlags flags;
+ if (type->isBlockPointerType()) {
+ flags |= BLOCK_FIELD_IS_BLOCK;
+ } else if (CGM.getContext().isObjCNSObjectType(type) ||
+ type->isObjCObjectPointerType()) {
+ flags |= BLOCK_FIELD_IS_OBJECT;
+ } else {
+ return 0;
+ }
- return llvm::ConstantExpr::getBitCast(Fn, Int8PtrTy);
+ if (type.isObjCGCWeak())
+ flags |= BLOCK_FIELD_IS_WEAK;
+
+ ObjectByrefHelpers byrefInfo(emission.Alignment, flags);
+ return ::buildByrefHelpers(CGM, byrefType, byrefInfo);
}
-llvm::Constant *CodeGenModule::BuildbyrefCopyHelper(const llvm::Type *T,
- BlockFieldFlags flags,
- unsigned align,
- const VarDecl *var) {
- // All alignments below pointer alignment are bumped up, as we
- // always have at least that much alignment to begin with.
- if (align < PointerAlignInBytes) align = PointerAlignInBytes;
+unsigned CodeGenFunction::getByRefValueLLVMField(const ValueDecl *VD) const {
+ assert(ByRefVal