Update clang to r100181.
This commit is contained in:
parent
c0c7bca4e5
commit
11d2b2d2bb
@ -92,6 +92,12 @@ install(DIRECTORY include/
|
||||
PATTERN ".svn" EXCLUDE
|
||||
)
|
||||
|
||||
install(DIRECTORY ${CMAKE_CURRENT_BINARY_DIR}/include/
|
||||
DESTINATION include
|
||||
FILES_MATCHING
|
||||
PATTERN "*.inc"
|
||||
)
|
||||
|
||||
add_definitions( -D_GNU_SOURCE )
|
||||
|
||||
option(CLANG_BUILD_EXAMPLES "Build CLANG example programs." OFF)
|
||||
|
@ -12,7 +12,6 @@
|
||||
1A2193CE0F45EEB700C0713D /* Mangle.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 1A2193CC0F45EEB700C0713D /* Mangle.cpp */; };
|
||||
1A2A54B50FD1DD1C00F4CE45 /* AnalysisConsumer.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 1A2A54A40FD1DD1C00F4CE45 /* AnalysisConsumer.cpp */; };
|
||||
1A2A54B60FD1DD1C00F4CE45 /* ASTConsumers.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 1A2A54A50FD1DD1C00F4CE45 /* ASTConsumers.cpp */; };
|
||||
1A2A54B70FD1DD1C00F4CE45 /* Backend.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 1A2A54A60FD1DD1C00F4CE45 /* Backend.cpp */; };
|
||||
1A2A54B80FD1DD1C00F4CE45 /* CacheTokens.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 1A2A54A70FD1DD1C00F4CE45 /* CacheTokens.cpp */; };
|
||||
1A2A54B90FD1DD1C00F4CE45 /* DependencyFile.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 1A2A54A80FD1DD1C00F4CE45 /* DependencyFile.cpp */; };
|
||||
1A2A54BA0FD1DD1C00F4CE45 /* DiagChecker.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 1A2A54A90FD1DD1C00F4CE45 /* DiagChecker.cpp */; };
|
||||
@ -70,6 +69,8 @@
|
||||
1ADF47AF0F782C3200E48A8A /* SemaTemplateInstantiateDecl.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 1ADF47AE0F782C3200E48A8A /* SemaTemplateInstantiateDecl.cpp */; };
|
||||
1AE4EE3E103B89ED00888A23 /* StmtProfile.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 1AE4EE3D103B89ED00888A23 /* StmtProfile.cpp */; };
|
||||
1AF1B50F109A4FB800AFAFAC /* CGException.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 1AF1B50E109A4FB800AFAFAC /* CGException.cpp */; };
|
||||
1AFDD8721161085D00AE030A /* ASTMerge.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 1AFDD8701161085D00AE030A /* ASTMerge.cpp */; };
|
||||
1AFDD8731161085D00AE030A /* CodeGenAction.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 1AFDD8711161085D00AE030A /* CodeGenAction.cpp */; };
|
||||
1AFF8AE31012BFC900D248DA /* CGRecordLayoutBuilder.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 1AFF8AE11012BFC900D248DA /* CGRecordLayoutBuilder.cpp */; };
|
||||
3507E4C20E27FE2D00FB7B57 /* CheckObjCInstMethSignature.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 3507E4C10E27FE2D00FB7B57 /* CheckObjCInstMethSignature.cpp */; };
|
||||
352246E70F5C6BE000D0D279 /* HTMLDiagnostics.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 352246E10F5C6BE000D0D279 /* HTMLDiagnostics.cpp */; };
|
||||
@ -149,6 +150,11 @@
|
||||
90FD6D85103C3D49005F5B73 /* SelectorMap.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 90FD6D7A103C3D49005F5B73 /* SelectorMap.cpp */; };
|
||||
90FD6DB6103D977E005F5B73 /* index-test.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 90FD6DB5103D977E005F5B73 /* index-test.cpp */; };
|
||||
BDF87CF70FD746F300BBF872 /* SemaTemplateDeduction.cpp in Sources */ = {isa = PBXBuildFile; fileRef = BDF87CF60FD746F300BBF872 /* SemaTemplateDeduction.cpp */; };
|
||||
BF89C3E211595818001C2D68 /* AnalysisBasedWarnings.cpp in Sources */ = {isa = PBXBuildFile; fileRef = BF89C3E111595818001C2D68 /* AnalysisBasedWarnings.cpp */; };
|
||||
BF89C3E91159594A001C2D68 /* SemaObjCProperty.cpp in Sources */ = {isa = PBXBuildFile; fileRef = BF89C3E81159594A001C2D68 /* SemaObjCProperty.cpp */; };
|
||||
BF89C3F911595A01001C2D68 /* SemaType.cpp in Sources */ = {isa = PBXBuildFile; fileRef = BF89C3F811595A01001C2D68 /* SemaType.cpp */; };
|
||||
BF89C3FB11595A37001C2D68 /* SemaCodeComplete.cpp in Sources */ = {isa = PBXBuildFile; fileRef = BF89C3FA11595A37001C2D68 /* SemaCodeComplete.cpp */; };
|
||||
BF89C3FD11595A5D001C2D68 /* SemaExceptionSpec.cpp in Sources */ = {isa = PBXBuildFile; fileRef = BF89C3FC11595A5D001C2D68 /* SemaExceptionSpec.cpp */; };
|
||||
DE01DA490B12ADA300AC22CE /* PPCallbacks.h in CopyFiles */ = {isa = PBXBuildFile; fileRef = DE01DA480B12ADA300AC22CE /* PPCallbacks.h */; };
|
||||
DE06756C0C051CFE00EBBFD8 /* ParseExprCXX.cpp in Sources */ = {isa = PBXBuildFile; fileRef = DE06756B0C051CFE00EBBFD8 /* ParseExprCXX.cpp */; };
|
||||
DE06B73E0A8307640050E87E /* LangOptions.h in CopyFiles */ = {isa = PBXBuildFile; fileRef = DE06B73D0A8307640050E87E /* LangOptions.h */; };
|
||||
@ -365,7 +371,6 @@
|
||||
1A2193CD0F45EEB700C0713D /* Mangle.h */ = {isa = PBXFileReference; fileEncoding = 4; indentWidth = 2; lastKnownFileType = sourcecode.c.h; name = Mangle.h; path = lib/CodeGen/Mangle.h; sourceTree = "<group>"; tabWidth = 2; };
|
||||
1A2A54A40FD1DD1C00F4CE45 /* AnalysisConsumer.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = AnalysisConsumer.cpp; path = lib/Frontend/AnalysisConsumer.cpp; sourceTree = "<group>"; };
|
||||
1A2A54A50FD1DD1C00F4CE45 /* ASTConsumers.cpp */ = {isa = PBXFileReference; fileEncoding = 4; indentWidth = 2; lastKnownFileType = sourcecode.cpp.cpp; name = ASTConsumers.cpp; path = lib/Frontend/ASTConsumers.cpp; sourceTree = "<group>"; tabWidth = 2; };
|
||||
1A2A54A60FD1DD1C00F4CE45 /* Backend.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = Backend.cpp; path = lib/Frontend/Backend.cpp; sourceTree = "<group>"; };
|
||||
1A2A54A70FD1DD1C00F4CE45 /* CacheTokens.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = CacheTokens.cpp; path = lib/Frontend/CacheTokens.cpp; sourceTree = "<group>"; };
|
||||
1A2A54A80FD1DD1C00F4CE45 /* DependencyFile.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = DependencyFile.cpp; path = lib/Frontend/DependencyFile.cpp; sourceTree = "<group>"; };
|
||||
1A2A54A90FD1DD1C00F4CE45 /* DiagChecker.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = DiagChecker.cpp; path = lib/Frontend/DiagChecker.cpp; sourceTree = "<group>"; };
|
||||
@ -446,8 +451,9 @@
|
||||
1AE4EE3B103B89CA00888A23 /* TreeTransform.h */ = {isa = PBXFileReference; fileEncoding = 4; indentWidth = 2; lastKnownFileType = sourcecode.c.h; name = TreeTransform.h; path = lib/Sema/TreeTransform.h; sourceTree = "<group>"; tabWidth = 2; };
|
||||
1AE4EE3D103B89ED00888A23 /* StmtProfile.cpp */ = {isa = PBXFileReference; fileEncoding = 4; indentWidth = 2; lastKnownFileType = sourcecode.cpp.cpp; name = StmtProfile.cpp; path = lib/AST/StmtProfile.cpp; sourceTree = "<group>"; tabWidth = 2; };
|
||||
1AF1B50E109A4FB800AFAFAC /* CGException.cpp */ = {isa = PBXFileReference; fileEncoding = 4; indentWidth = 2; lastKnownFileType = sourcecode.cpp.cpp; name = CGException.cpp; path = lib/CodeGen/CGException.cpp; sourceTree = "<group>"; tabWidth = 2; };
|
||||
1AFDD8701161085D00AE030A /* ASTMerge.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = ASTMerge.cpp; path = lib/Frontend/ASTMerge.cpp; sourceTree = "<group>"; };
|
||||
1AFDD8711161085D00AE030A /* CodeGenAction.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = CodeGenAction.cpp; path = lib/Frontend/CodeGenAction.cpp; sourceTree = "<group>"; };
|
||||
1AFF8AE11012BFC900D248DA /* CGRecordLayoutBuilder.cpp */ = {isa = PBXFileReference; fileEncoding = 4; indentWidth = 2; lastKnownFileType = sourcecode.cpp.cpp; name = CGRecordLayoutBuilder.cpp; path = lib/CodeGen/CGRecordLayoutBuilder.cpp; sourceTree = "<group>"; tabWidth = 2; };
|
||||
1AFF8AE21012BFC900D248DA /* CGRecordLayoutBuilder.h */ = {isa = PBXFileReference; fileEncoding = 4; indentWidth = 2; lastKnownFileType = sourcecode.c.h; name = CGRecordLayoutBuilder.h; path = lib/CodeGen/CGRecordLayoutBuilder.h; sourceTree = "<group>"; tabWidth = 2; };
|
||||
3507E4C10E27FE2D00FB7B57 /* CheckObjCInstMethSignature.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = CheckObjCInstMethSignature.cpp; path = lib/Analysis/CheckObjCInstMethSignature.cpp; sourceTree = "<group>"; };
|
||||
352246E10F5C6BE000D0D279 /* HTMLDiagnostics.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = HTMLDiagnostics.cpp; path = lib/Frontend/HTMLDiagnostics.cpp; sourceTree = "<group>"; };
|
||||
352246E20F5C6BE000D0D279 /* InitHeaderSearch.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = InitHeaderSearch.cpp; path = lib/Frontend/InitHeaderSearch.cpp; sourceTree = "<group>"; };
|
||||
@ -618,6 +624,15 @@
|
||||
90FD6D91103C3D80005F5B73 /* Utils.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = Utils.h; path = clang/Frontend/Utils.h; sourceTree = "<group>"; };
|
||||
90FD6DB5103D977E005F5B73 /* index-test.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = "index-test.cpp"; path = "tools/index-test/index-test.cpp"; sourceTree = "<group>"; };
|
||||
BDF87CF60FD746F300BBF872 /* SemaTemplateDeduction.cpp */ = {isa = PBXFileReference; fileEncoding = 4; indentWidth = 2; lastKnownFileType = sourcecode.cpp.cpp; name = SemaTemplateDeduction.cpp; path = lib/Sema/SemaTemplateDeduction.cpp; sourceTree = "<group>"; tabWidth = 2; };
|
||||
BF89C3E0115957FF001C2D68 /* AnalysisBasedWarnings.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = AnalysisBasedWarnings.h; path = lib/Sema/AnalysisBasedWarnings.h; sourceTree = "<group>"; };
|
||||
BF89C3E111595818001C2D68 /* AnalysisBasedWarnings.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = AnalysisBasedWarnings.cpp; path = lib/Sema/AnalysisBasedWarnings.cpp; sourceTree = "<group>"; };
|
||||
BF89C3E311595835001C2D68 /* Lookup.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = Lookup.h; path = lib/Sema/Lookup.h; sourceTree = "<group>"; };
|
||||
BF89C3E411595855001C2D68 /* SemaInit.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = SemaInit.h; path = lib/Sema/SemaInit.h; sourceTree = "<group>"; };
|
||||
BF89C3E5115958A1001C2D68 /* TargetAttributesSema.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = TargetAttributesSema.h; path = lib/Sema/TargetAttributesSema.h; sourceTree = "<group>"; };
|
||||
BF89C3E81159594A001C2D68 /* SemaObjCProperty.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = SemaObjCProperty.cpp; path = lib/Sema/SemaObjCProperty.cpp; sourceTree = "<group>"; };
|
||||
BF89C3F811595A01001C2D68 /* SemaType.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = SemaType.cpp; path = lib/Sema/SemaType.cpp; sourceTree = "<group>"; };
|
||||
BF89C3FA11595A37001C2D68 /* SemaCodeComplete.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = SemaCodeComplete.cpp; path = lib/Sema/SemaCodeComplete.cpp; sourceTree = "<group>"; };
|
||||
BF89C3FC11595A5D001C2D68 /* SemaExceptionSpec.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = SemaExceptionSpec.cpp; path = lib/Sema/SemaExceptionSpec.cpp; sourceTree = "<group>"; };
|
||||
DE01DA480B12ADA300AC22CE /* PPCallbacks.h */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.c.h; path = PPCallbacks.h; sourceTree = "<group>"; };
|
||||
DE06756B0C051CFE00EBBFD8 /* ParseExprCXX.cpp */ = {isa = PBXFileReference; fileEncoding = 30; indentWidth = 2; lastKnownFileType = sourcecode.cpp.cpp; name = ParseExprCXX.cpp; path = lib/Parse/ParseExprCXX.cpp; sourceTree = "<group>"; tabWidth = 2; };
|
||||
DE06B73D0A8307640050E87E /* LangOptions.h */ = {isa = PBXFileReference; fileEncoding = 30; indentWidth = 2; lastKnownFileType = sourcecode.c.h; path = LangOptions.h; sourceTree = "<group>"; tabWidth = 2; };
|
||||
@ -948,10 +963,11 @@
|
||||
352246E00F5C6BC000D0D279 /* Frontend */ = {
|
||||
isa = PBXGroup;
|
||||
children = (
|
||||
1AFDD8701161085D00AE030A /* ASTMerge.cpp */,
|
||||
9012911C1048068D0083456D /* ASTUnit.cpp */,
|
||||
1A2A54A40FD1DD1C00F4CE45 /* AnalysisConsumer.cpp */,
|
||||
1A2A54A50FD1DD1C00F4CE45 /* ASTConsumers.cpp */,
|
||||
1A2A54A60FD1DD1C00F4CE45 /* Backend.cpp */,
|
||||
1AFDD8711161085D00AE030A /* CodeGenAction.cpp */,
|
||||
1A2A54A70FD1DD1C00F4CE45 /* CacheTokens.cpp */,
|
||||
1ACB57DB1105820D0047B991 /* CompilerInstance.cpp */,
|
||||
1ACB57DC1105820D0047B991 /* CompilerInvocation.cpp */,
|
||||
@ -1257,29 +1273,36 @@
|
||||
DE67E7070C020EAB00F66BC5 /* Sema */ = {
|
||||
isa = PBXGroup;
|
||||
children = (
|
||||
BF89C3E111595818001C2D68 /* AnalysisBasedWarnings.cpp */,
|
||||
BF89C3E0115957FF001C2D68 /* AnalysisBasedWarnings.h */,
|
||||
35585DBD0EAFBC4500D0A97A /* CXXFieldCollector.h */,
|
||||
1A6B6CD110693FC900BB4A8F /* CodeCompleteConsumer.cpp */,
|
||||
3527124F0DAFE54700C76352 /* IdentifierResolver.h */,
|
||||
352712500DAFE54700C76352 /* IdentifierResolver.cpp */,
|
||||
DECB6D640F9AE26600F5FBC7 /* JumpDiagnostics.cpp */,
|
||||
BF89C3E311595835001C2D68 /* Lookup.h */,
|
||||
DE67E7190C020F4F00F66BC5 /* ParseAST.cpp */,
|
||||
DE67E7140C020EDF00F66BC5 /* Sema.h */,
|
||||
DE67E7160C020EE400F66BC5 /* Sema.cpp */,
|
||||
1A701B630F7C8FE400FEC4D1 /* SemaAccess.cpp */,
|
||||
DEB07AC70F4A427E00F5A2BE /* SemaAttr.cpp */,
|
||||
DEF2F00F0C6CFED5000C4259 /* SemaChecking.cpp */,
|
||||
BF89C3FA11595A37001C2D68 /* SemaCodeComplete.cpp */,
|
||||
35E194670ECB82FB00F21733 /* SemaCXXScopeSpec.cpp */,
|
||||
DE67E7120C020ED900F66BC5 /* SemaDecl.cpp */,
|
||||
DE22BCF10E14197E0094DC60 /* SemaDeclAttr.cpp */,
|
||||
35EF676F0DAD1D2C00B19414 /* SemaDeclCXX.cpp */,
|
||||
DE704B250D0FBEBE009C7762 /* SemaDeclObjC.cpp */,
|
||||
BF89C3FC11595A5D001C2D68 /* SemaExceptionSpec.cpp */,
|
||||
DE67E7100C020ED400F66BC5 /* SemaExpr.cpp */,
|
||||
DE47999B0D2EBE1A00706D2D /* SemaExprObjC.cpp */,
|
||||
DE67E70E0C020ECF00F66BC5 /* SemaExprCXX.cpp */,
|
||||
BF89C3E411595855001C2D68 /* SemaInit.h */,
|
||||
3599299A0DE2425300A8A33E /* SemaInit.cpp */,
|
||||
357EA27C0F2526F300439B60 /* SemaLookup.cpp */,
|
||||
1A6B6CD210693FC900BB4A8F /* SemaCodeComplete.cpp */,
|
||||
35E194680ECB82FB00F21733 /* SemaCXXCast.cpp */,
|
||||
BF89C3E81159594A001C2D68 /* SemaObjCProperty.cpp */,
|
||||
35585DBE0EAFBC4500D0A97A /* SemaOverload.cpp */,
|
||||
35585DBF0EAFBC4500D0A97A /* SemaOverload.h */,
|
||||
DE67E70C0C020ECA00F66BC5 /* SemaStmt.cpp */,
|
||||
@ -1288,7 +1311,9 @@
|
||||
BDF87CF60FD746F300BBF872 /* SemaTemplateDeduction.cpp */,
|
||||
35544B8B0F5C803200D92AA9 /* SemaTemplateInstantiate.cpp */,
|
||||
1ADF47AE0F782C3200E48A8A /* SemaTemplateInstantiateDecl.cpp */,
|
||||
BF89C3F811595A01001C2D68 /* SemaType.cpp */,
|
||||
1AE4EE3B103B89CA00888A23 /* TreeTransform.h */,
|
||||
BF89C3E5115958A1001C2D68 /* TargetAttributesSema.h */,
|
||||
);
|
||||
name = Sema;
|
||||
sourceTree = "<group>";
|
||||
@ -1334,7 +1359,6 @@
|
||||
DE38CD4F0D794D0100A273B6 /* CGObjCGNU.cpp */,
|
||||
3552E7580E520DD7003A8CA5 /* CGObjCMac.cpp */,
|
||||
1AFF8AE11012BFC900D248DA /* CGRecordLayoutBuilder.cpp */,
|
||||
1AFF8AE21012BFC900D248DA /* CGRecordLayoutBuilder.h */,
|
||||
1A6C01F6108128710072DEE4 /* CGRTTI.cpp */,
|
||||
DE4772F90C10EAE5002239E8 /* CGStmt.cpp */,
|
||||
1A6FE7080FD6F85800E00CA9 /* CGTemporaries.cpp */,
|
||||
@ -1930,7 +1954,6 @@
|
||||
DECB78170FA5882F00F5FBC7 /* PCHWriterStmt.cpp in Sources */,
|
||||
1A2A54B50FD1DD1C00F4CE45 /* AnalysisConsumer.cpp in Sources */,
|
||||
1A2A54B60FD1DD1C00F4CE45 /* ASTConsumers.cpp in Sources */,
|
||||
1A2A54B70FD1DD1C00F4CE45 /* Backend.cpp in Sources */,
|
||||
1A2A54B80FD1DD1C00F4CE45 /* CacheTokens.cpp in Sources */,
|
||||
1A2A54B90FD1DD1C00F4CE45 /* DependencyFile.cpp in Sources */,
|
||||
1A2A54BA0FD1DD1C00F4CE45 /* DiagChecker.cpp in Sources */,
|
||||
@ -1997,6 +2020,13 @@
|
||||
1A621C4511111D61009E6834 /* CIndexUSRs.cpp in Sources */,
|
||||
1A621C4611111D61009E6834 /* CXCursor.cpp in Sources */,
|
||||
1A96785211486FDC00F24372 /* RecordLayout.cpp in Sources */,
|
||||
BF89C3E211595818001C2D68 /* AnalysisBasedWarnings.cpp in Sources */,
|
||||
BF89C3E91159594A001C2D68 /* SemaObjCProperty.cpp in Sources */,
|
||||
BF89C3F911595A01001C2D68 /* SemaType.cpp in Sources */,
|
||||
BF89C3FB11595A37001C2D68 /* SemaCodeComplete.cpp in Sources */,
|
||||
BF89C3FD11595A5D001C2D68 /* SemaExceptionSpec.cpp in Sources */,
|
||||
1AFDD8721161085D00AE030A /* ASTMerge.cpp in Sources */,
|
||||
1AFDD8731161085D00AE030A /* CodeGenAction.cpp in Sources */,
|
||||
);
|
||||
runOnlyForDeploymentPostprocessing = 0;
|
||||
};
|
||||
|
@ -71,7 +71,8 @@ int main(int argc, const char **argv, char * const *envp) {
|
||||
Diagnostic Diags(&DiagClient);
|
||||
Driver TheDriver(Path.getBasename(), Path.getDirname(),
|
||||
llvm::sys::getHostTriple(),
|
||||
"a.out", /*IsProduction=*/false, Diags);
|
||||
"a.out", /*IsProduction=*/false, /*CXXIsProduction=*/false,
|
||||
Diags);
|
||||
TheDriver.setTitle("clang interpreter");
|
||||
|
||||
// FIXME: This is a hack to try to force the driver to do something we can
|
||||
|
@ -17,6 +17,7 @@
|
||||
#include "clang/Basic/IdentifierTable.h"
|
||||
#include "clang/Basic/LangOptions.h"
|
||||
#include "clang/Basic/OperatorKinds.h"
|
||||
#include "clang/Basic/PartialDiagnostic.h"
|
||||
#include "clang/AST/Attr.h"
|
||||
#include "clang/AST/Decl.h"
|
||||
#include "clang/AST/NestedNameSpecifier.h"
|
||||
@ -57,6 +58,7 @@ namespace clang {
|
||||
class ObjCIvarRefExpr;
|
||||
class ObjCPropertyDecl;
|
||||
class RecordDecl;
|
||||
class StoredDeclsMap;
|
||||
class TagDecl;
|
||||
class TemplateTypeParmDecl;
|
||||
class TranslationUnitDecl;
|
||||
@ -115,7 +117,7 @@ class ASTContext {
|
||||
llvm::FoldingSet<SubstTemplateTypeParmType> SubstTemplateTypeParmTypes;
|
||||
llvm::FoldingSet<TemplateSpecializationType> TemplateSpecializationTypes;
|
||||
llvm::FoldingSet<QualifiedNameType> QualifiedNameTypes;
|
||||
llvm::FoldingSet<TypenameType> TypenameTypes;
|
||||
llvm::FoldingSet<DependentNameType> DependentNameTypes;
|
||||
llvm::FoldingSet<ObjCInterfaceType> ObjCInterfaceTypes;
|
||||
llvm::FoldingSet<ObjCObjectPointerType> ObjCObjectPointerTypes;
|
||||
llvm::FoldingSet<ElaboratedType> ElaboratedTypes;
|
||||
@ -264,6 +266,9 @@ class ASTContext {
|
||||
llvm::MallocAllocator MallocAlloc;
|
||||
llvm::BumpPtrAllocator BumpAlloc;
|
||||
|
||||
/// \brief Allocator for partial diagnostics.
|
||||
PartialDiagnostic::StorageAllocator DiagAllocator;
|
||||
|
||||
public:
|
||||
const TargetInfo &Target;
|
||||
IdentifierTable &Idents;
|
||||
@ -289,6 +294,11 @@ public:
|
||||
if (FreeMemory)
|
||||
MallocAlloc.Deallocate(Ptr);
|
||||
}
|
||||
|
||||
PartialDiagnostic::StorageAllocator &getDiagAllocator() {
|
||||
return DiagAllocator;
|
||||
}
|
||||
|
||||
const LangOptions& getLangOptions() const { return LangOpts; }
|
||||
|
||||
FullSourceLoc getFullLoc(SourceLocation Loc) const {
|
||||
@ -437,6 +447,11 @@ public:
|
||||
/// allowable type.
|
||||
QualType getCallConvType(QualType T, CallingConv CallConv);
|
||||
|
||||
/// getRegParmType - Sets the specified regparm attribute to
|
||||
/// the given type, which must be a FunctionType or a pointer to an
|
||||
/// allowable type.
|
||||
QualType getRegParmType(QualType T, unsigned RegParm);
|
||||
|
||||
/// getComplexType - Return the uniqued reference to the type for a complex
|
||||
/// number with the specified element type.
|
||||
QualType getComplexType(QualType T);
|
||||
@ -554,8 +569,12 @@ public:
|
||||
|
||||
/// getFunctionNoProtoType - Return a K&R style C function type like 'int()'.
|
||||
///
|
||||
QualType getFunctionNoProtoType(QualType ResultTy, bool NoReturn = false,
|
||||
CallingConv CallConv = CC_Default);
|
||||
QualType getFunctionNoProtoType(QualType ResultTy,
|
||||
const FunctionType::ExtInfo &Info);
|
||||
|
||||
QualType getFunctionNoProtoType(QualType ResultTy) {
|
||||
return getFunctionNoProtoType(ResultTy, FunctionType::ExtInfo());
|
||||
}
|
||||
|
||||
/// getFunctionType - Return a normal function type with a typed argument
|
||||
/// list. isVariadic indicates whether the argument list includes '...'.
|
||||
@ -564,8 +583,7 @@ public:
|
||||
unsigned TypeQuals, bool hasExceptionSpec,
|
||||
bool hasAnyExceptionSpec,
|
||||
unsigned NumExs, const QualType *ExArray,
|
||||
bool NoReturn,
|
||||
CallingConv CallConv);
|
||||
const FunctionType::ExtInfo &Info);
|
||||
|
||||
/// getTypeDeclType - Return the unique reference to the type for
|
||||
/// the specified type declaration.
|
||||
@ -612,12 +630,14 @@ public:
|
||||
|
||||
QualType getQualifiedNameType(NestedNameSpecifier *NNS,
|
||||
QualType NamedType);
|
||||
QualType getTypenameType(NestedNameSpecifier *NNS,
|
||||
const IdentifierInfo *Name,
|
||||
QualType Canon = QualType());
|
||||
QualType getTypenameType(NestedNameSpecifier *NNS,
|
||||
const TemplateSpecializationType *TemplateId,
|
||||
QualType Canon = QualType());
|
||||
QualType getDependentNameType(ElaboratedTypeKeyword Keyword,
|
||||
NestedNameSpecifier *NNS,
|
||||
const IdentifierInfo *Name,
|
||||
QualType Canon = QualType());
|
||||
QualType getDependentNameType(ElaboratedTypeKeyword Keyword,
|
||||
NestedNameSpecifier *NNS,
|
||||
const TemplateSpecializationType *TemplateId,
|
||||
QualType Canon = QualType());
|
||||
QualType getElaboratedType(QualType UnderlyingType,
|
||||
ElaboratedType::TagKind Tag);
|
||||
|
||||
@ -937,8 +957,7 @@ public:
|
||||
llvm::SmallVectorImpl<ObjCIvarDecl*> &Ivars);
|
||||
void CollectNonClassIvars(const ObjCInterfaceDecl *OI,
|
||||
llvm::SmallVectorImpl<ObjCIvarDecl*> &Ivars);
|
||||
unsigned CountSynthesizedIvars(const ObjCInterfaceDecl *OI);
|
||||
unsigned CountProtocolSynthesizedIvars(const ObjCProtocolDecl *PD);
|
||||
unsigned CountNonClassIvars(const ObjCInterfaceDecl *OI);
|
||||
void CollectInheritedProtocols(const Decl *CDecl,
|
||||
llvm::SmallPtrSet<ObjCProtocolDecl*, 8> &Protocols);
|
||||
|
||||
@ -1273,9 +1292,8 @@ private:
|
||||
// FIXME: This currently contains the set of StoredDeclMaps used
|
||||
// by DeclContext objects. This probably should not be in ASTContext,
|
||||
// but we include it here so that ASTContext can quickly deallocate them.
|
||||
std::vector<void*> SDMs;
|
||||
llvm::PointerIntPair<StoredDeclsMap*,1> LastSDM;
|
||||
friend class DeclContext;
|
||||
void *CreateStoredDeclsMap();
|
||||
void ReleaseDeclContextMaps();
|
||||
};
|
||||
|
||||
|
@ -19,6 +19,7 @@
|
||||
#include "clang/AST/DeclCXX.h"
|
||||
#include "clang/AST/Type.h"
|
||||
#include "clang/AST/TypeOrdering.h"
|
||||
#include "llvm/ADT/DenseMap.h"
|
||||
#include "llvm/ADT/SmallVector.h"
|
||||
#include <list>
|
||||
#include <map>
|
||||
@ -227,6 +228,137 @@ public:
|
||||
/// object.
|
||||
void swap(CXXBasePaths &Other);
|
||||
};
|
||||
|
||||
/// \brief Uniquely identifies a virtual method within a class
|
||||
/// hierarchy by the method itself and a class subobject number.
|
||||
struct UniqueVirtualMethod {
|
||||
UniqueVirtualMethod() : Method(0), Subobject(0), InVirtualSubobject(0) { }
|
||||
|
||||
UniqueVirtualMethod(CXXMethodDecl *Method, unsigned Subobject,
|
||||
const CXXRecordDecl *InVirtualSubobject)
|
||||
: Method(Method), Subobject(Subobject),
|
||||
InVirtualSubobject(InVirtualSubobject) { }
|
||||
|
||||
/// \brief The overriding virtual method.
|
||||
CXXMethodDecl *Method;
|
||||
|
||||
/// \brief The subobject in which the overriding virtual method
|
||||
/// resides.
|
||||
unsigned Subobject;
|
||||
|
||||
/// \brief The virtual base class subobject of which this overridden
|
||||
/// virtual method is a part. Note that this records the closest
|
||||
/// derived virtual base class subobject.
|
||||
const CXXRecordDecl *InVirtualSubobject;
|
||||
|
||||
friend bool operator==(const UniqueVirtualMethod &X,
|
||||
const UniqueVirtualMethod &Y) {
|
||||
return X.Method == Y.Method && X.Subobject == Y.Subobject &&
|
||||
X.InVirtualSubobject == Y.InVirtualSubobject;
|
||||
}
|
||||
|
||||
friend bool operator!=(const UniqueVirtualMethod &X,
|
||||
const UniqueVirtualMethod &Y) {
|
||||
return !(X == Y);
|
||||
}
|
||||
};
|
||||
|
||||
/// \brief The set of methods that override a given virtual method in
|
||||
/// each subobject where it occurs.
|
||||
///
|
||||
/// The first part of the pair is the subobject in which the
|
||||
/// overridden virtual function occurs, while the second part of the
|
||||
/// pair is the virtual method that overrides it (including the
|
||||
/// subobject in which that virtual function occurs).
|
||||
class OverridingMethods {
|
||||
llvm::DenseMap<unsigned, llvm::SmallVector<UniqueVirtualMethod, 4> >
|
||||
Overrides;
|
||||
|
||||
public:
|
||||
// Iterate over the set of subobjects that have overriding methods.
|
||||
typedef llvm::DenseMap<unsigned, llvm::SmallVector<UniqueVirtualMethod, 4> >
|
||||
::iterator iterator;
|
||||
typedef llvm::DenseMap<unsigned, llvm::SmallVector<UniqueVirtualMethod, 4> >
|
||||
::const_iterator const_iterator;
|
||||
iterator begin() { return Overrides.begin(); }
|
||||
const_iterator begin() const { return Overrides.begin(); }
|
||||
iterator end() { return Overrides.end(); }
|
||||
const_iterator end() const { return Overrides.end(); }
|
||||
unsigned size() const { return Overrides.size(); }
|
||||
|
||||
// Iterate over the set of overriding virtual methods in a given
|
||||
// subobject.
|
||||
typedef llvm::SmallVector<UniqueVirtualMethod, 4>::iterator
|
||||
overriding_iterator;
|
||||
typedef llvm::SmallVector<UniqueVirtualMethod, 4>::const_iterator
|
||||
overriding_const_iterator;
|
||||
|
||||
// Add a new overriding method for a particular subobject.
|
||||
void add(unsigned OverriddenSubobject, UniqueVirtualMethod Overriding);
|
||||
|
||||
// Add all of the overriding methods from "other" into overrides for
|
||||
// this method. Used when merging the overrides from multiple base
|
||||
// class subobjects.
|
||||
void add(const OverridingMethods &Other);
|
||||
|
||||
// Replace all overriding virtual methods in all subobjects with the
|
||||
// given virtual method.
|
||||
void replaceAll(UniqueVirtualMethod Overriding);
|
||||
};
|
||||
|
||||
/// \brief A mapping from each virtual member function to its set of
|
||||
/// final overriders.
|
||||
///
|
||||
/// Within a class hierarchy for a given derived class, each virtual
|
||||
/// member function in that hierarchy has one or more "final
|
||||
/// overriders" (C++ [class.virtual]p2). A final overrider for a
|
||||
/// virtual function "f" is the virtual function that will actually be
|
||||
/// invoked when dispatching a call to "f" through the
|
||||
/// vtable. Well-formed classes have a single final overrider for each
|
||||
/// virtual function; in abstract classes, the final overrider for at
|
||||
/// least one virtual function is a pure virtual function. Due to
|
||||
/// multiple, virtual inheritance, it is possible for a class to have
|
||||
/// more than one final overrider. Athough this is an error (per C++
|
||||
/// [class.virtual]p2), it is not considered an error here: the final
|
||||
/// overrider map can represent multiple final overriders for a
|
||||
/// method, and it is up to the client to determine whether they are
|
||||
/// problem. For example, the following class \c D has two final
|
||||
/// overriders for the virtual function \c A::f(), one in \c C and one
|
||||
/// in \c D:
|
||||
///
|
||||
/// \code
|
||||
/// struct A { virtual void f(); };
|
||||
/// struct B : virtual A { virtual void f(); };
|
||||
/// struct C : virtual A { virtual void f(); };
|
||||
/// struct D : B, C { };
|
||||
/// \endcode
|
||||
///
|
||||
/// This data structure contaings a mapping from every virtual
|
||||
/// function *that does not override an existing virtual function* and
|
||||
/// in every subobject where that virtual function occurs to the set
|
||||
/// of virtual functions that override it. Thus, the same virtual
|
||||
/// function \c A::f can actually occur in multiple subobjects of type
|
||||
/// \c A due to multiple inheritance, and may be overriden by
|
||||
/// different virtual functions in each, as in the following example:
|
||||
///
|
||||
/// \code
|
||||
/// struct A { virtual void f(); };
|
||||
/// struct B : A { virtual void f(); };
|
||||
/// struct C : A { virtual void f(); };
|
||||
/// struct D : B, C { };
|
||||
/// \endcode
|
||||
///
|
||||
/// Unlike in the previous example, where the virtual functions \c
|
||||
/// B::f and \c C::f both overrode \c A::f in the same subobject of
|
||||
/// type \c A, in this example the two virtual functions both override
|
||||
/// \c A::f but in *different* subobjects of type A. This is
|
||||
/// represented by numbering the subobjects in which the overridden
|
||||
/// and the overriding virtual member functions are located. Subobject
|
||||
/// 0 represents the virtua base class subobject of that type, while
|
||||
/// subobject numbers greater than 0 refer to non-virtual base class
|
||||
/// subobjects of that type.
|
||||
class CXXFinalOverriderMap
|
||||
: public llvm::DenseMap<const CXXMethodDecl *, OverridingMethods> { };
|
||||
|
||||
} // end namespace clang
|
||||
|
||||
|
@ -165,6 +165,8 @@ public:
|
||||
// (dynamic) type.
|
||||
static CanQual<T> CreateUnsafe(QualType Other);
|
||||
|
||||
void dump() const { Stored.dump(); }
|
||||
|
||||
void Profile(llvm::FoldingSetNodeID &ID) const {
|
||||
ID.AddPointer(getAsOpaquePtr());
|
||||
}
|
||||
@ -562,24 +564,21 @@ struct CanProxyAdaptor<ExtVectorType> : public CanProxyBase<ExtVectorType> {
|
||||
template<>
|
||||
struct CanProxyAdaptor<FunctionType> : public CanProxyBase<FunctionType> {
|
||||
LLVM_CLANG_CANPROXY_TYPE_ACCESSOR(getResultType)
|
||||
LLVM_CLANG_CANPROXY_SIMPLE_ACCESSOR(bool, getNoReturnAttr)
|
||||
LLVM_CLANG_CANPROXY_SIMPLE_ACCESSOR(CallingConv, getCallConv)
|
||||
LLVM_CLANG_CANPROXY_SIMPLE_ACCESSOR(FunctionType::ExtInfo, getExtInfo)
|
||||
};
|
||||
|
||||
template<>
|
||||
struct CanProxyAdaptor<FunctionNoProtoType>
|
||||
: public CanProxyBase<FunctionNoProtoType> {
|
||||
LLVM_CLANG_CANPROXY_TYPE_ACCESSOR(getResultType)
|
||||
LLVM_CLANG_CANPROXY_SIMPLE_ACCESSOR(bool, getNoReturnAttr)
|
||||
LLVM_CLANG_CANPROXY_SIMPLE_ACCESSOR(CallingConv, getCallConv)
|
||||
LLVM_CLANG_CANPROXY_SIMPLE_ACCESSOR(FunctionType::ExtInfo, getExtInfo)
|
||||
};
|
||||
|
||||
template<>
|
||||
struct CanProxyAdaptor<FunctionProtoType>
|
||||
: public CanProxyBase<FunctionProtoType> {
|
||||
LLVM_CLANG_CANPROXY_TYPE_ACCESSOR(getResultType)
|
||||
LLVM_CLANG_CANPROXY_SIMPLE_ACCESSOR(bool, getNoReturnAttr)
|
||||
LLVM_CLANG_CANPROXY_SIMPLE_ACCESSOR(CallingConv, getCallConv)
|
||||
LLVM_CLANG_CANPROXY_SIMPLE_ACCESSOR(FunctionType::ExtInfo, getExtInfo)
|
||||
LLVM_CLANG_CANPROXY_SIMPLE_ACCESSOR(unsigned, getNumArgs)
|
||||
CanQualType getArgType(unsigned i) const {
|
||||
return CanQualType::CreateUnsafe(this->getTypePtr()->getArgType(i));
|
||||
|
@ -224,18 +224,26 @@ class NamespaceDecl : public NamedDecl, public DeclContext {
|
||||
// NextNamespace points to the next extended declaration.
|
||||
// OrigNamespace points to the original namespace declaration.
|
||||
// OrigNamespace of the first namespace decl points to itself.
|
||||
NamespaceDecl *OrigNamespace, *NextNamespace;
|
||||
NamespaceDecl *NextNamespace;
|
||||
|
||||
// The (most recently entered) anonymous namespace inside this
|
||||
// namespace.
|
||||
NamespaceDecl *AnonymousNamespace;
|
||||
/// \brief A pointer to either the original namespace definition for
|
||||
/// this namespace (if the boolean value is false) or the anonymous
|
||||
/// namespace that lives just inside this namespace (if the boolean
|
||||
/// value is true).
|
||||
///
|
||||
/// We can combine these two notions because the anonymous namespace
|
||||
/// must only be stored in one of the namespace declarations (so all
|
||||
/// of the namespace declarations can find it). We therefore choose
|
||||
/// the original namespace declaration, since all of the namespace
|
||||
/// declarations have a link directly to it; the original namespace
|
||||
/// declaration itself only needs to know that it is the original
|
||||
/// namespace declaration (which the boolean indicates).
|
||||
llvm::PointerIntPair<NamespaceDecl *, 1, bool> OrigOrAnonNamespace;
|
||||
|
||||
NamespaceDecl(DeclContext *DC, SourceLocation L, IdentifierInfo *Id)
|
||||
: NamedDecl(Namespace, DC, L, Id), DeclContext(Namespace) {
|
||||
OrigNamespace = this;
|
||||
NextNamespace = 0;
|
||||
AnonymousNamespace = 0;
|
||||
}
|
||||
: NamedDecl(Namespace, DC, L, Id), DeclContext(Namespace),
|
||||
NextNamespace(0), OrigOrAnonNamespace(0, true) { }
|
||||
|
||||
public:
|
||||
static NamespaceDecl *Create(ASTContext &C, DeclContext *DC,
|
||||
SourceLocation L, IdentifierInfo *Id);
|
||||
@ -258,22 +266,33 @@ public:
|
||||
void setNextNamespace(NamespaceDecl *ND) { NextNamespace = ND; }
|
||||
|
||||
NamespaceDecl *getOriginalNamespace() const {
|
||||
return OrigNamespace;
|
||||
if (OrigOrAnonNamespace.getInt())
|
||||
return const_cast<NamespaceDecl *>(this);
|
||||
|
||||
return OrigOrAnonNamespace.getPointer();
|
||||
}
|
||||
|
||||
void setOriginalNamespace(NamespaceDecl *ND) {
|
||||
if (ND != this) {
|
||||
OrigOrAnonNamespace.setPointer(ND);
|
||||
OrigOrAnonNamespace.setInt(false);
|
||||
}
|
||||
}
|
||||
void setOriginalNamespace(NamespaceDecl *ND) { OrigNamespace = ND; }
|
||||
|
||||
NamespaceDecl *getAnonymousNamespace() const {
|
||||
return AnonymousNamespace;
|
||||
return getOriginalNamespace()->OrigOrAnonNamespace.getPointer();
|
||||
}
|
||||
|
||||
void setAnonymousNamespace(NamespaceDecl *D) {
|
||||
assert(!D || D->isAnonymousNamespace());
|
||||
assert(!D || D->getParent() == this);
|
||||
AnonymousNamespace = D;
|
||||
getOriginalNamespace()->OrigOrAnonNamespace.setPointer(D);
|
||||
}
|
||||
|
||||
virtual NamespaceDecl *getCanonicalDecl() { return OrigNamespace; }
|
||||
const NamespaceDecl *getCanonicalDecl() const { return OrigNamespace; }
|
||||
virtual NamespaceDecl *getCanonicalDecl() { return getOriginalNamespace(); }
|
||||
const NamespaceDecl *getCanonicalDecl() const {
|
||||
return getOriginalNamespace();
|
||||
}
|
||||
|
||||
virtual SourceRange getSourceRange() const {
|
||||
return SourceRange(getLocation(), RBracLoc);
|
||||
@ -1819,12 +1838,12 @@ class RecordDecl : public TagDecl {
|
||||
/// If so, this cannot be contained in arrays or other structs as a member.
|
||||
bool HasFlexibleArrayMember : 1;
|
||||
|
||||
/// AnonymousStructOrUnion - Whether this is the type of an
|
||||
/// anonymous struct or union.
|
||||
/// AnonymousStructOrUnion - Whether this is the type of an anonymous struct
|
||||
/// or union.
|
||||
bool AnonymousStructOrUnion : 1;
|
||||
|
||||
/// HasObjectMember - This is true if this struct has at least one
|
||||
/// member containing an object
|
||||
/// HasObjectMember - This is true if this struct has at least one member
|
||||
/// containing an object.
|
||||
bool HasObjectMember : 1;
|
||||
|
||||
protected:
|
||||
|
@ -41,6 +41,8 @@ class LinkageSpecDecl;
|
||||
class BlockDecl;
|
||||
class DeclarationName;
|
||||
class CompoundStmt;
|
||||
class StoredDeclsMap;
|
||||
class DependentDiagnostic;
|
||||
}
|
||||
|
||||
namespace llvm {
|
||||
@ -450,15 +452,23 @@ public:
|
||||
/// same entity may not (and probably don't) share this property.
|
||||
void setObjectOfFriendDecl(bool PreviouslyDeclared) {
|
||||
unsigned OldNS = IdentifierNamespace;
|
||||
assert((OldNS == IDNS_Tag || OldNS == IDNS_Ordinary ||
|
||||
OldNS == (IDNS_Tag | IDNS_Ordinary))
|
||||
&& "unsupported namespace for undeclared friend");
|
||||
if (!PreviouslyDeclared) IdentifierNamespace = 0;
|
||||
assert((OldNS & (IDNS_Tag | IDNS_Ordinary |
|
||||
IDNS_TagFriend | IDNS_OrdinaryFriend)) &&
|
||||
"namespace includes neither ordinary nor tag");
|
||||
assert(!(OldNS & ~(IDNS_Tag | IDNS_Ordinary |
|
||||
IDNS_TagFriend | IDNS_OrdinaryFriend)) &&
|
||||
"namespace includes other than ordinary or tag");
|
||||
|
||||
if (OldNS == IDNS_Tag)
|
||||
IdentifierNamespace = 0;
|
||||
if (OldNS & (IDNS_Tag | IDNS_TagFriend)) {
|
||||
IdentifierNamespace |= IDNS_TagFriend;
|
||||
else
|
||||
if (PreviouslyDeclared) IdentifierNamespace |= IDNS_Tag;
|
||||
}
|
||||
|
||||
if (OldNS & (IDNS_Ordinary | IDNS_OrdinaryFriend)) {
|
||||
IdentifierNamespace |= IDNS_OrdinaryFriend;
|
||||
if (PreviouslyDeclared) IdentifierNamespace |= IDNS_Ordinary;
|
||||
}
|
||||
}
|
||||
|
||||
enum FriendObjectKind {
|
||||
@ -545,9 +555,9 @@ class DeclContext {
|
||||
mutable bool ExternalVisibleStorage : 1;
|
||||
|
||||
/// \brief Pointer to the data structure used to lookup declarations
|
||||
/// within this context, which is a DenseMap<DeclarationName,
|
||||
/// StoredDeclsList>.
|
||||
mutable void* LookupPtr;
|
||||
/// within this context (or a DependentStoredDeclsMap if this is a
|
||||
/// dependent context).
|
||||
mutable StoredDeclsMap *LookupPtr;
|
||||
|
||||
/// FirstDecl - The first declaration stored within this declaration
|
||||
/// context.
|
||||
@ -674,6 +684,9 @@ public:
|
||||
/// "primary" DeclContext structure, which will contain the
|
||||
/// information needed to perform name lookup into this context.
|
||||
DeclContext *getPrimaryContext();
|
||||
const DeclContext *getPrimaryContext() const {
|
||||
return const_cast<DeclContext*>(this)->getPrimaryContext();
|
||||
}
|
||||
|
||||
/// getLookupContext - Retrieve the innermost non-transparent
|
||||
/// context of this context, which corresponds to the innermost
|
||||
@ -976,10 +989,15 @@ public:
|
||||
return getUsingDirectives().second;
|
||||
}
|
||||
|
||||
// These are all defined in DependentDiagnostic.h.
|
||||
class ddiag_iterator;
|
||||
inline ddiag_iterator ddiag_begin() const;
|
||||
inline ddiag_iterator ddiag_end() const;
|
||||
|
||||
// Low-level accessors
|
||||
|
||||
/// \brief Retrieve the internal representation of the lookup structure.
|
||||
void* getLookupPtr() const { return LookupPtr; }
|
||||
StoredDeclsMap* getLookupPtr() const { return LookupPtr; }
|
||||
|
||||
/// \brief Whether this DeclContext has external storage containing
|
||||
/// additional declarations that are lexically in this context.
|
||||
@ -1013,6 +1031,9 @@ private:
|
||||
void LoadLexicalDeclsFromExternalStorage() const;
|
||||
void LoadVisibleDeclsFromExternalStorage() const;
|
||||
|
||||
friend class DependentDiagnostic;
|
||||
StoredDeclsMap *CreateStoredDeclsMap(ASTContext &C) const;
|
||||
|
||||
void buildLookup(DeclContext *DCtx);
|
||||
void makeDeclVisibleInContextImpl(NamedDecl *D);
|
||||
};
|
||||
|
@ -33,6 +33,7 @@ class CXXDestructorDecl;
|
||||
class CXXMethodDecl;
|
||||
class CXXRecordDecl;
|
||||
class CXXMemberLookupCriteria;
|
||||
class CXXFinalOverriderMap;
|
||||
class FriendDecl;
|
||||
|
||||
/// \brief Represents any kind of function declaration, whether it is a
|
||||
@ -328,6 +329,10 @@ class CXXRecordDecl : public RecordDecl {
|
||||
/// instantiated or specialized.
|
||||
llvm::PointerUnion<ClassTemplateDecl*, MemberSpecializationInfo*>
|
||||
TemplateOrInstantiation;
|
||||
|
||||
#ifndef NDEBUG
|
||||
void CheckConversionFunction(NamedDecl *D);
|
||||
#endif
|
||||
|
||||
protected:
|
||||
CXXRecordDecl(Kind K, TagKind TK, DeclContext *DC,
|
||||
@ -549,17 +554,26 @@ public:
|
||||
return getConversionFunctions()->replace(Old, New);
|
||||
}
|
||||
|
||||
/// Removes a conversion function from this class. The conversion
|
||||
/// function must currently be a member of this class. Furthermore,
|
||||
/// this class must currently be in the process of being defined.
|
||||
void removeConversion(const NamedDecl *Old);
|
||||
|
||||
/// getVisibleConversionFunctions - get all conversion functions visible
|
||||
/// in current class; including conversion function templates.
|
||||
const UnresolvedSetImpl *getVisibleConversionFunctions();
|
||||
|
||||
/// addConversionFunction - Add a new conversion function to the
|
||||
/// list of conversion functions.
|
||||
void addConversionFunction(CXXConversionDecl *ConvDecl);
|
||||
/// addConversionFunction - Registers a conversion function which
|
||||
/// this class declares directly.
|
||||
void addConversionFunction(NamedDecl *Decl) {
|
||||
#ifndef NDEBUG
|
||||
CheckConversionFunction(Decl);
|
||||
#endif
|
||||
|
||||
/// \brief Add a new conversion function template to the list of conversion
|
||||
/// functions.
|
||||
void addConversionFunction(FunctionTemplateDecl *ConvDecl);
|
||||
// We intentionally don't use the decl's access here because it
|
||||
// hasn't been set yet. That's really just a misdesign in Sema.
|
||||
data().Conversions.addDecl(Decl);
|
||||
}
|
||||
|
||||
/// isAggregate - Whether this class is an aggregate (C++
|
||||
/// [dcl.init.aggr]), which is a class with no user-declared
|
||||
@ -879,7 +893,12 @@ public:
|
||||
static bool FindNestedNameSpecifierMember(const CXXBaseSpecifier *Specifier,
|
||||
CXXBasePath &Path,
|
||||
void *UserData);
|
||||
|
||||
|
||||
/// \brief Retrieve the final overriders for each virtual member
|
||||
/// function in the class hierarchy where this class is the
|
||||
/// most-derived class in the class hierarchy.
|
||||
void getFinalOverriders(CXXFinalOverriderMap &FinaOverriders) const;
|
||||
|
||||
/// viewInheritance - Renders and displays an inheritance diagram
|
||||
/// for this C++ class and all of its base classes (transitively) using
|
||||
/// GraphViz.
|
||||
@ -935,7 +954,7 @@ public:
|
||||
|
||||
return (CD->begin_overridden_methods() != CD->end_overridden_methods());
|
||||
}
|
||||
|
||||
|
||||
/// \brief Determine whether this is a usual deallocation function
|
||||
/// (C++ [basic.stc.dynamic.deallocation]p2), which is an overloaded
|
||||
/// delete or delete[] operator with a particular signature.
|
||||
|
@ -24,6 +24,8 @@
|
||||
|
||||
namespace clang {
|
||||
|
||||
class DependentDiagnostic;
|
||||
|
||||
/// StoredDeclsList - This is an array of decls optimized a common case of only
|
||||
/// containing one entry.
|
||||
struct StoredDeclsList {
|
||||
@ -258,8 +260,28 @@ public:
|
||||
}
|
||||
};
|
||||
|
||||
typedef llvm::DenseMap<DeclarationName, StoredDeclsList> StoredDeclsMap;
|
||||
class StoredDeclsMap
|
||||
: public llvm::DenseMap<DeclarationName, StoredDeclsList> {
|
||||
|
||||
public:
|
||||
static void DestroyAll(StoredDeclsMap *Map, bool Dependent);
|
||||
|
||||
private:
|
||||
friend class ASTContext; // walks the chain deleting these
|
||||
friend class DeclContext;
|
||||
llvm::PointerIntPair<StoredDeclsMap*, 1> Previous;
|
||||
};
|
||||
|
||||
class DependentStoredDeclsMap : public StoredDeclsMap {
|
||||
public:
|
||||
DependentStoredDeclsMap() : FirstDiagnostic(0) {}
|
||||
|
||||
private:
|
||||
friend class DependentDiagnostic;
|
||||
friend class DeclContext; // iterates over diagnostics
|
||||
|
||||
DependentDiagnostic *FirstDiagnostic;
|
||||
};
|
||||
|
||||
} // end namespace clang
|
||||
|
||||
|
@ -36,7 +36,7 @@ namespace clang {
|
||||
/// The semantic context of a friend decl is its declaring class.
|
||||
class FriendDecl : public Decl {
|
||||
public:
|
||||
typedef llvm::PointerUnion<NamedDecl*,Type*> FriendUnion;
|
||||
typedef llvm::PointerUnion<NamedDecl*,TypeSourceInfo*> FriendUnion;
|
||||
|
||||
private:
|
||||
// The declaration that's a friend of this class.
|
||||
@ -73,8 +73,8 @@ public:
|
||||
/// possibly dependent) type, return the type; otherwise
|
||||
/// return null. This is used only for C++0x's unelaborated
|
||||
/// friend type declarations.
|
||||
Type *getFriendType() const {
|
||||
return Friend.dyn_cast<Type*>();
|
||||
TypeSourceInfo *getFriendType() const {
|
||||
return Friend.dyn_cast<TypeSourceInfo*>();
|
||||
}
|
||||
|
||||
/// If this friend declaration doesn't name an unelaborated
|
||||
|
@ -1238,7 +1238,7 @@ public:
|
||||
/// template <typename U> friend class Foo<T>::Nested; // friend template
|
||||
class FriendTemplateDecl : public Decl {
|
||||
public:
|
||||
typedef llvm::PointerUnion<NamedDecl*,Type*> FriendUnion;
|
||||
typedef llvm::PointerUnion<NamedDecl*,TypeSourceInfo*> FriendUnion;
|
||||
|
||||
private:
|
||||
// The number of template parameters; always non-zero.
|
||||
@ -1277,8 +1277,8 @@ public:
|
||||
/// If this friend declaration names a templated type (or
|
||||
/// a dependent member type of a templated type), return that
|
||||
/// type; otherwise return null.
|
||||
Type *getFriendType() const {
|
||||
return Friend.dyn_cast<Type*>();
|
||||
TypeSourceInfo *getFriendType() const {
|
||||
return Friend.dyn_cast<TypeSourceInfo*>();
|
||||
}
|
||||
|
||||
/// If this friend declaration names a templated function (or
|
||||
|
@ -378,7 +378,7 @@ inline const PartialDiagnostic &operator<<(const PartialDiagnostic &PD,
|
||||
Diagnostic::ak_declarationname);
|
||||
return PD;
|
||||
}
|
||||
|
||||
|
||||
} // end namespace clang
|
||||
|
||||
namespace llvm {
|
||||
|
183
include/clang/AST/DependentDiagnostic.h
Normal file
183
include/clang/AST/DependentDiagnostic.h
Normal file
@ -0,0 +1,183 @@
|
||||
//===-- DependentDiagnostic.h - Dependently-generated diagnostics -*- C++ -*-=//
|
||||
//
|
||||
// The LLVM Compiler Infrastructure
|
||||
//
|
||||
// This file is distributed under the University of Illinois Open Source
|
||||
// License. See LICENSE.TXT for details.
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
//
|
||||
// This file defines interfaces for diagnostics which may or may
|
||||
// fire based on how a template is instantiated.
|
||||
//
|
||||
// At the moment, the only consumer of this interface is access
|
||||
// control.
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
#ifndef LLVM_CLANG_AST_DEPENDENT_DIAGNOSTIC_H
|
||||
#define LLVM_CLANG_AST_DEPENDENT_DIAGNOSTIC_H
|
||||
|
||||
#include "clang/Basic/PartialDiagnostic.h"
|
||||
#include "clang/Basic/SourceLocation.h"
|
||||
#include "clang/AST/DeclBase.h"
|
||||
#include "clang/AST/DeclContextInternals.h"
|
||||
|
||||
namespace clang {
|
||||
|
||||
class ASTContext;
|
||||
class CXXRecordDecl;
|
||||
class NamedDecl;
|
||||
|
||||
/// A dependently-generated diagnostic.
|
||||
class DependentDiagnostic {
|
||||
public:
|
||||
enum AccessNonce { Access = 0 };
|
||||
|
||||
static DependentDiagnostic *Create(ASTContext &Context,
|
||||
DeclContext *Parent,
|
||||
AccessNonce _,
|
||||
SourceLocation Loc,
|
||||
bool IsMemberAccess,
|
||||
AccessSpecifier AS,
|
||||
NamedDecl *TargetDecl,
|
||||
CXXRecordDecl *NamingClass,
|
||||
const PartialDiagnostic &PDiag) {
|
||||
DependentDiagnostic *DD = Create(Context, Parent, PDiag);
|
||||
DD->AccessData.Loc = Loc.getRawEncoding();
|
||||
DD->AccessData.IsMember = IsMemberAccess;
|
||||
DD->AccessData.Access = AS;
|
||||
DD->AccessData.TargetDecl = TargetDecl;
|
||||
DD->AccessData.NamingClass = NamingClass;
|
||||
return DD;
|
||||
}
|
||||
|
||||
unsigned getKind() const {
|
||||
return Access;
|
||||
}
|
||||
|
||||
bool isAccessToMember() const {
|
||||
assert(getKind() == Access);
|
||||
return AccessData.IsMember;
|
||||
}
|
||||
|
||||
AccessSpecifier getAccess() const {
|
||||
assert(getKind() == Access);
|
||||
return AccessSpecifier(AccessData.Access);
|
||||
}
|
||||
|
||||
SourceLocation getAccessLoc() const {
|
||||
assert(getKind() == Access);
|
||||
return SourceLocation::getFromRawEncoding(AccessData.Loc);
|
||||
}
|
||||
|
||||
NamedDecl *getAccessTarget() const {
|
||||
assert(getKind() == Access);
|
||||
return AccessData.TargetDecl;
|
||||
}
|
||||
|
||||
NamedDecl *getAccessNamingClass() const {
|
||||
assert(getKind() == Access);
|
||||
return AccessData.NamingClass;
|
||||
}
|
||||
|
||||
const PartialDiagnostic &getDiagnostic() const {
|
||||
return Diag;
|
||||
}
|
||||
|
||||
private:
|
||||
DependentDiagnostic(const PartialDiagnostic &PDiag,
|
||||
PartialDiagnostic::Storage *Storage)
|
||||
: Diag(PDiag, Storage) {}
|
||||
|
||||
static DependentDiagnostic *Create(ASTContext &Context,
|
||||
DeclContext *Parent,
|
||||
const PartialDiagnostic &PDiag);
|
||||
|
||||
friend class DependentStoredDeclsMap;
|
||||
friend class DeclContext::ddiag_iterator;
|
||||
DependentDiagnostic *NextDiagnostic;
|
||||
|
||||
PartialDiagnostic Diag;
|
||||
|
||||
union {
|
||||
struct {
|
||||
unsigned Loc;
|
||||
unsigned Access : 2;
|
||||
unsigned IsMember : 1;
|
||||
NamedDecl *TargetDecl;
|
||||
CXXRecordDecl *NamingClass;
|
||||
} AccessData;
|
||||
};
|
||||
};
|
||||
|
||||
///
|
||||
|
||||
/// An iterator over the dependent diagnostics in a dependent context.
|
||||
class DeclContext::ddiag_iterator {
|
||||
public:
|
||||
ddiag_iterator() : Ptr(0) {}
|
||||
explicit ddiag_iterator(DependentDiagnostic *Ptr) : Ptr(Ptr) {}
|
||||
|
||||
typedef DependentDiagnostic *value_type;
|
||||
typedef DependentDiagnostic *reference;
|
||||
typedef DependentDiagnostic *pointer;
|
||||
typedef int difference_type;
|
||||
typedef std::forward_iterator_tag iterator_category;
|
||||
|
||||
reference operator*() const { return Ptr; }
|
||||
|
||||
ddiag_iterator &operator++() {
|
||||
assert(Ptr && "attempt to increment past end of diag list");
|
||||
Ptr = Ptr->NextDiagnostic;
|
||||
return *this;
|
||||
}
|
||||
|
||||
ddiag_iterator operator++(int) {
|
||||
ddiag_iterator tmp = *this;
|
||||
++*this;
|
||||
return tmp;
|
||||
}
|
||||
|
||||
bool operator==(ddiag_iterator Other) const {
|
||||
return Ptr == Other.Ptr;
|
||||
}
|
||||
|
||||
bool operator!=(ddiag_iterator Other) const {
|
||||
return Ptr != Other.Ptr;
|
||||
}
|
||||
|
||||
ddiag_iterator &operator+=(difference_type N) {
|
||||
assert(N >= 0 && "cannot rewind a DeclContext::ddiag_iterator");
|
||||
while (N--)
|
||||
++*this;
|
||||
return *this;
|
||||
}
|
||||
|
||||
ddiag_iterator operator+(difference_type N) const {
|
||||
ddiag_iterator tmp = *this;
|
||||
tmp += N;
|
||||
return tmp;
|
||||
}
|
||||
|
||||
private:
|
||||
DependentDiagnostic *Ptr;
|
||||
};
|
||||
|
||||
inline DeclContext::ddiag_iterator DeclContext::ddiag_begin() const {
|
||||
assert(isDependentContext()
|
||||
&& "cannot iterate dependent diagnostics of non-dependent context");
|
||||
const DependentStoredDeclsMap *Map
|
||||
= static_cast<DependentStoredDeclsMap*>(getPrimaryContext()->LookupPtr);
|
||||
|
||||
if (!Map) return ddiag_iterator();
|
||||
return ddiag_iterator(Map->FirstDiagnostic);
|
||||
}
|
||||
|
||||
inline DeclContext::ddiag_iterator DeclContext::ddiag_end() const {
|
||||
return ddiag_iterator();
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
#endif
|
@ -1263,6 +1263,11 @@ public:
|
||||
/// MemberExpr - [C99 6.5.2.3] Structure and Union Members. X->F and X.F.
|
||||
///
|
||||
class MemberExpr : public Expr {
|
||||
/// Extra data stored in some member expressions.
|
||||
struct MemberNameQualifier : public NameQualifier {
|
||||
NamedDecl *FoundDecl;
|
||||
};
|
||||
|
||||
/// Base - the expression for the base pointer or structure references. In
|
||||
/// X.F, this is "X".
|
||||
Stmt *Base;
|
||||
@ -1278,27 +1283,26 @@ class MemberExpr : public Expr {
|
||||
bool IsArrow : 1;
|
||||
|
||||
/// \brief True if this member expression used a nested-name-specifier to
|
||||
/// refer to the member, e.g., "x->Base::f". When true, a NameQualifier
|
||||
/// refer to the member, e.g., "x->Base::f", or found its member via a using
|
||||
/// declaration. When true, a MemberNameQualifier
|
||||
/// structure is allocated immediately after the MemberExpr.
|
||||
bool HasQualifier : 1;
|
||||
bool HasQualifierOrFoundDecl : 1;
|
||||
|
||||
/// \brief True if this member expression specified a template argument list
|
||||
/// explicitly, e.g., x->f<int>. When true, an ExplicitTemplateArgumentList
|
||||
/// structure (and its TemplateArguments) are allocated immediately after
|
||||
/// the MemberExpr or, if the member expression also has a qualifier, after
|
||||
/// the NameQualifier structure.
|
||||
/// the MemberNameQualifier structure.
|
||||
bool HasExplicitTemplateArgumentList : 1;
|
||||
|
||||
/// \brief Retrieve the qualifier that preceded the member name, if any.
|
||||
NameQualifier *getMemberQualifier() {
|
||||
if (!HasQualifier)
|
||||
return 0;
|
||||
|
||||
return reinterpret_cast<NameQualifier *> (this + 1);
|
||||
MemberNameQualifier *getMemberQualifier() {
|
||||
assert(HasQualifierOrFoundDecl);
|
||||
return reinterpret_cast<MemberNameQualifier *> (this + 1);
|
||||
}
|
||||
|
||||
/// \brief Retrieve the qualifier that preceded the member name, if any.
|
||||
const NameQualifier *getMemberQualifier() const {
|
||||
const MemberNameQualifier *getMemberQualifier() const {
|
||||
return const_cast<MemberExpr *>(this)->getMemberQualifier();
|
||||
}
|
||||
|
||||
@ -1308,7 +1312,7 @@ class MemberExpr : public Expr {
|
||||
if (!HasExplicitTemplateArgumentList)
|
||||
return 0;
|
||||
|
||||
if (!HasQualifier)
|
||||
if (!HasQualifierOrFoundDecl)
|
||||
return reinterpret_cast<ExplicitTemplateArgumentList *>(this + 1);
|
||||
|
||||
return reinterpret_cast<ExplicitTemplateArgumentList *>(
|
||||
@ -1321,26 +1325,22 @@ class MemberExpr : public Expr {
|
||||
return const_cast<MemberExpr *>(this)->getExplicitTemplateArgumentList();
|
||||
}
|
||||
|
||||
MemberExpr(Expr *base, bool isarrow, NestedNameSpecifier *qual,
|
||||
SourceRange qualrange, ValueDecl *memberdecl, SourceLocation l,
|
||||
const TemplateArgumentListInfo *targs, QualType ty);
|
||||
|
||||
public:
|
||||
MemberExpr(Expr *base, bool isarrow, ValueDecl *memberdecl,
|
||||
SourceLocation l, QualType ty)
|
||||
: Expr(MemberExprClass, ty,
|
||||
base->isTypeDependent(), base->isValueDependent()),
|
||||
Base(base), MemberDecl(memberdecl), MemberLoc(l), IsArrow(isarrow),
|
||||
HasQualifier(false), HasExplicitTemplateArgumentList(false) {}
|
||||
HasQualifierOrFoundDecl(false), HasExplicitTemplateArgumentList(false) {}
|
||||
|
||||
/// \brief Build an empty member reference expression.
|
||||
explicit MemberExpr(EmptyShell Empty)
|
||||
: Expr(MemberExprClass, Empty), HasQualifier(false),
|
||||
: Expr(MemberExprClass, Empty), HasQualifierOrFoundDecl(false),
|
||||
HasExplicitTemplateArgumentList(false) { }
|
||||
|
||||
static MemberExpr *Create(ASTContext &C, Expr *base, bool isarrow,
|
||||
NestedNameSpecifier *qual, SourceRange qualrange,
|
||||
ValueDecl *memberdecl,
|
||||
ValueDecl *memberdecl, NamedDecl *founddecl,
|
||||
SourceLocation l,
|
||||
const TemplateArgumentListInfo *targs,
|
||||
QualType ty);
|
||||
@ -1355,16 +1355,23 @@ public:
|
||||
ValueDecl *getMemberDecl() const { return MemberDecl; }
|
||||
void setMemberDecl(ValueDecl *D) { MemberDecl = D; }
|
||||
|
||||
/// \brief Retrieves the declaration found by lookup.
|
||||
NamedDecl *getFoundDecl() const {
|
||||
if (!HasQualifierOrFoundDecl)
|
||||
return getMemberDecl();
|
||||
return getMemberQualifier()->FoundDecl;
|
||||
}
|
||||
|
||||
/// \brief Determines whether this member expression actually had
|
||||
/// a C++ nested-name-specifier prior to the name of the member, e.g.,
|
||||
/// x->Base::foo.
|
||||
bool hasQualifier() const { return HasQualifier; }
|
||||
bool hasQualifier() const { return getQualifier() != 0; }
|
||||
|
||||
/// \brief If the member name was qualified, retrieves the source range of
|
||||
/// the nested-name-specifier that precedes the member name. Otherwise,
|
||||
/// returns an empty source range.
|
||||
SourceRange getQualifierRange() const {
|
||||
if (!HasQualifier)
|
||||
if (!HasQualifierOrFoundDecl)
|
||||
return SourceRange();
|
||||
|
||||
return getMemberQualifier()->Range;
|
||||
@ -1374,7 +1381,7 @@ public:
|
||||
/// nested-name-specifier that precedes the member name. Otherwise, returns
|
||||
/// NULL.
|
||||
NestedNameSpecifier *getQualifier() const {
|
||||
if (!HasQualifier)
|
||||
if (!HasQualifierOrFoundDecl)
|
||||
return 0;
|
||||
|
||||
return getMemberQualifier()->NNS;
|
||||
@ -1545,6 +1552,10 @@ public:
|
||||
/// CK_DerivedToBase - Derived to base class casts.
|
||||
CK_DerivedToBase,
|
||||
|
||||
/// CK_UncheckedDerivedToBase - Derived to base class casts that
|
||||
/// assume that the derived pointer is not null.
|
||||
CK_UncheckedDerivedToBase,
|
||||
|
||||
/// CK_Dynamic - Dynamic cast.
|
||||
CK_Dynamic,
|
||||
|
||||
|
@ -1095,8 +1095,8 @@ public:
|
||||
: Expr(CXXPseudoDestructorExprClass,
|
||||
Context.getPointerType(Context.getFunctionType(Context.VoidTy, 0, 0,
|
||||
false, 0, false,
|
||||
false, 0, 0, false,
|
||||
CC_Default)),
|
||||
false, 0, 0,
|
||||
FunctionType::ExtInfo())),
|
||||
/*isTypeDependent=*/(Base->isTypeDependent() ||
|
||||
(DestroyedType.getTypeSourceInfo() &&
|
||||
DestroyedType.getTypeSourceInfo()->getType()->isDependentType())),
|
||||
|
@ -17,6 +17,7 @@
|
||||
#include "clang/Basic/Diagnostic.h"
|
||||
#include "clang/Basic/IdentifierTable.h"
|
||||
#include "clang/Basic/Linkage.h"
|
||||
#include "clang/Basic/PartialDiagnostic.h"
|
||||
#include "clang/AST/NestedNameSpecifier.h"
|
||||
#include "clang/AST/TemplateName.h"
|
||||
#include "llvm/Support/Casting.h"
|
||||
@ -678,14 +679,6 @@ public:
|
||||
return getObjCGCAttr() == Qualifiers::Strong;
|
||||
}
|
||||
|
||||
/// getNoReturnAttr - Returns true if the type has the noreturn attribute,
|
||||
/// false otherwise.
|
||||
bool getNoReturnAttr() const;
|
||||
|
||||
/// getCallConv - Returns the calling convention of the type if the type
|
||||
/// is a function type, CC_Default otherwise.
|
||||
CallingConv getCallConv() const;
|
||||
|
||||
private:
|
||||
// These methods are implemented in a separate translation unit;
|
||||
// "static"-ize them to avoid creating temporary QualTypes in the
|
||||
@ -902,6 +895,9 @@ public:
|
||||
bool isDependentType() const { return Dependent; }
|
||||
bool isOverloadableType() const;
|
||||
|
||||
/// \brief Determine wither this type is a C++ elaborated-type-specifier.
|
||||
bool isElaboratedTypeSpecifier() const;
|
||||
|
||||
/// hasPointerRepresentation - Whether this type is represented
|
||||
/// natively as a pointer; this includes pointers, references, block
|
||||
/// pointers, and Objective-C interface, qualified id, and qualified
|
||||
@ -1747,25 +1743,101 @@ class FunctionType : public Type {
|
||||
/// NoReturn - Indicates if the function type is attribute noreturn.
|
||||
unsigned NoReturn : 1;
|
||||
|
||||
/// RegParm - How many arguments to pass inreg.
|
||||
unsigned RegParm : 3;
|
||||
|
||||
/// CallConv - The calling convention used by the function.
|
||||
unsigned CallConv : 2;
|
||||
|
||||
// The type returned by the function.
|
||||
QualType ResultType;
|
||||
|
||||
public:
|
||||
// This class is used for passing arround the information needed to
|
||||
// construct a call. It is not actually used for storage, just for
|
||||
// factoring together common arguments.
|
||||
// If you add a field (say Foo), other than the obvious places (both, constructors,
|
||||
// compile failures), what you need to update is
|
||||
// * Operetor==
|
||||
// * getFoo
|
||||
// * withFoo
|
||||
// * functionType. Add Foo, getFoo.
|
||||
// * ASTContext::getFooType
|
||||
// * ASTContext::mergeFunctionTypes
|
||||
// * FunctionNoProtoType::Profile
|
||||
// * FunctionProtoType::Profile
|
||||
// * TypePrinter::PrintFunctionProto
|
||||
// * PCH read and write
|
||||
// * Codegen
|
||||
|
||||
class ExtInfo {
|
||||
public:
|
||||
// Constructor with no defaults. Use this when you know that you
|
||||
// have all the elements (when reading a PCH file for example).
|
||||
ExtInfo(bool noReturn, unsigned regParm, CallingConv cc) :
|
||||
NoReturn(noReturn), RegParm(regParm), CC(cc) {}
|
||||
|
||||
// Constructor with all defaults. Use when for example creating a
|
||||
// function know to use defaults.
|
||||
ExtInfo() : NoReturn(false), RegParm(0), CC(CC_Default) {}
|
||||
|
||||
bool getNoReturn() const { return NoReturn; }
|
||||
unsigned getRegParm() const { return RegParm; }
|
||||
CallingConv getCC() const { return CC; }
|
||||
|
||||
bool operator==(const ExtInfo &Other) const {
|
||||
return getNoReturn() == Other.getNoReturn() &&
|
||||
getRegParm() == Other.getRegParm() &&
|
||||
getCC() == Other.getCC();
|
||||
}
|
||||
bool operator!=(const ExtInfo &Other) const {
|
||||
return !(*this == Other);
|
||||
}
|
||||
|
||||
// Note that we don't have setters. That is by design, use
|
||||
// the following with methods instead of mutating these objects.
|
||||
|
||||
ExtInfo withNoReturn(bool noReturn) const {
|
||||
return ExtInfo(noReturn, getRegParm(), getCC());
|
||||
}
|
||||
|
||||
ExtInfo withRegParm(unsigned RegParm) const {
|
||||
return ExtInfo(getNoReturn(), RegParm, getCC());
|
||||
}
|
||||
|
||||
ExtInfo withCallingConv(CallingConv cc) const {
|
||||
return ExtInfo(getNoReturn(), getRegParm(), cc);
|
||||
}
|
||||
|
||||
private:
|
||||
// True if we have __attribute__((noreturn))
|
||||
bool NoReturn;
|
||||
// The value passed to __attribute__((regparm(x)))
|
||||
unsigned RegParm;
|
||||
// The calling convention as specified via
|
||||
// __attribute__((cdecl|stdcall||fastcall))
|
||||
CallingConv CC;
|
||||
};
|
||||
|
||||
protected:
|
||||
FunctionType(TypeClass tc, QualType res, bool SubclassInfo,
|
||||
unsigned typeQuals, QualType Canonical, bool Dependent,
|
||||
bool noReturn = false, CallingConv callConv = CC_Default)
|
||||
const ExtInfo &Info)
|
||||
: Type(tc, Canonical, Dependent),
|
||||
SubClassData(SubclassInfo), TypeQuals(typeQuals), NoReturn(noReturn),
|
||||
CallConv(callConv), ResultType(res) {}
|
||||
SubClassData(SubclassInfo), TypeQuals(typeQuals),
|
||||
NoReturn(Info.getNoReturn()),
|
||||
RegParm(Info.getRegParm()), CallConv(Info.getCC()), ResultType(res) {}
|
||||
bool getSubClassData() const { return SubClassData; }
|
||||
unsigned getTypeQuals() const { return TypeQuals; }
|
||||
public:
|
||||
|
||||
QualType getResultType() const { return ResultType; }
|
||||
unsigned getRegParmType() const { return RegParm; }
|
||||
bool getNoReturnAttr() const { return NoReturn; }
|
||||
CallingConv getCallConv() const { return (CallingConv)CallConv; }
|
||||
ExtInfo getExtInfo() const {
|
||||
return ExtInfo(NoReturn, RegParm, (CallingConv)CallConv);
|
||||
}
|
||||
|
||||
static llvm::StringRef getNameForCallConv(CallingConv CC);
|
||||
|
||||
@ -1780,9 +1852,9 @@ public:
|
||||
/// no information available about its arguments.
|
||||
class FunctionNoProtoType : public FunctionType, public llvm::FoldingSetNode {
|
||||
FunctionNoProtoType(QualType Result, QualType Canonical,
|
||||
bool NoReturn = false, CallingConv CallConv = CC_Default)
|
||||
const ExtInfo &Info)
|
||||
: FunctionType(FunctionNoProto, Result, false, 0, Canonical,
|
||||
/*Dependent=*/false, NoReturn, CallConv) {}
|
||||
/*Dependent=*/false, Info) {}
|
||||
friend class ASTContext; // ASTContext creates these.
|
||||
public:
|
||||
// No additional state past what FunctionType provides.
|
||||
@ -1791,12 +1863,13 @@ public:
|
||||
QualType desugar() const { return QualType(this, 0); }
|
||||
|
||||
void Profile(llvm::FoldingSetNodeID &ID) {
|
||||
Profile(ID, getResultType(), getNoReturnAttr(), getCallConv());
|
||||
Profile(ID, getResultType(), getExtInfo());
|
||||
}
|
||||
static void Profile(llvm::FoldingSetNodeID &ID, QualType ResultType,
|
||||
bool NoReturn, CallingConv CallConv) {
|
||||
ID.AddInteger(CallConv);
|
||||
ID.AddInteger(NoReturn);
|
||||
const ExtInfo &Info) {
|
||||
ID.AddInteger(Info.getCC());
|
||||
ID.AddInteger(Info.getRegParm());
|
||||
ID.AddInteger(Info.getNoReturn());
|
||||
ID.AddPointer(ResultType.getAsOpaquePtr());
|
||||
}
|
||||
|
||||
@ -1827,12 +1900,12 @@ class FunctionProtoType : public FunctionType, public llvm::FoldingSetNode {
|
||||
FunctionProtoType(QualType Result, const QualType *ArgArray, unsigned numArgs,
|
||||
bool isVariadic, unsigned typeQuals, bool hasExs,
|
||||
bool hasAnyExs, const QualType *ExArray,
|
||||
unsigned numExs, QualType Canonical, bool NoReturn,
|
||||
CallingConv CallConv)
|
||||
unsigned numExs, QualType Canonical,
|
||||
const ExtInfo &Info)
|
||||
: FunctionType(FunctionProto, Result, isVariadic, typeQuals, Canonical,
|
||||
(Result->isDependentType() ||
|
||||
hasAnyDependentType(ArgArray, numArgs)), NoReturn,
|
||||
CallConv),
|
||||
hasAnyDependentType(ArgArray, numArgs)),
|
||||
Info),
|
||||
NumArgs(numArgs), NumExceptions(numExs), HasExceptionSpec(hasExs),
|
||||
AnyExceptionSpec(hasAnyExs) {
|
||||
// Fill in the trailing argument array.
|
||||
@ -1918,7 +1991,7 @@ public:
|
||||
bool isVariadic, unsigned TypeQuals,
|
||||
bool hasExceptionSpec, bool anyExceptionSpec,
|
||||
unsigned NumExceptions, exception_iterator Exs,
|
||||
bool NoReturn, CallingConv CallConv);
|
||||
const ExtInfo &ExtInfo);
|
||||
};
|
||||
|
||||
|
||||
@ -2481,6 +2554,24 @@ public:
|
||||
static bool classof(const InjectedClassNameType *T) { return true; }
|
||||
};
|
||||
|
||||
/// \brief The elaboration keyword that precedes a qualified type name or
|
||||
/// introduces an elaborated-type-specifier.
|
||||
enum ElaboratedTypeKeyword {
|
||||
/// \brief No keyword precedes the qualified type name.
|
||||
ETK_None,
|
||||
/// \brief The "typename" keyword precedes the qualified type name, e.g.,
|
||||
/// \c typename T::type.
|
||||
ETK_Typename,
|
||||
/// \brief The "class" keyword introduces the elaborated-type-specifier.
|
||||
ETK_Class,
|
||||
/// \brief The "struct" keyword introduces the elaborated-type-specifier.
|
||||
ETK_Struct,
|
||||
/// \brief The "union" keyword introduces the elaborated-type-specifier.
|
||||
ETK_Union,
|
||||
/// \brief The "enum" keyword introduces the elaborated-type-specifier.
|
||||
ETK_Enum
|
||||
};
|
||||
|
||||
/// \brief Represents a type that was referred to via a qualified
|
||||
/// name, e.g., N::M::type.
|
||||
///
|
||||
@ -2531,19 +2622,19 @@ public:
|
||||
static bool classof(const QualifiedNameType *T) { return true; }
|
||||
};
|
||||
|
||||
/// \brief Represents a 'typename' specifier that names a type within
|
||||
/// a dependent type, e.g., "typename T::type".
|
||||
/// \brief Represents a qualified type name for which the type name is
|
||||
/// dependent.
|
||||
///
|
||||
/// TypenameType has a very similar structure to QualifiedNameType,
|
||||
/// which also involves a nested-name-specifier following by a type,
|
||||
/// and (FIXME!) both can even be prefixed by the 'typename'
|
||||
/// keyword. However, the two types serve very different roles:
|
||||
/// QualifiedNameType is a non-semantic type that serves only as sugar
|
||||
/// to show how a particular type was written in the source
|
||||
/// code. TypenameType, on the other hand, only occurs when the
|
||||
/// nested-name-specifier is dependent, such that we cannot resolve
|
||||
/// the actual type until after instantiation.
|
||||
class TypenameType : public Type, public llvm::FoldingSetNode {
|
||||
/// DependentNameType represents a class of dependent types that involve a
|
||||
/// dependent nested-name-specifier (e.g., "T::") followed by a (dependent)
|
||||
/// name of a type. The DependentNameType may start with a "typename" (for a
|
||||
/// typename-specifier), "class", "struct", "union", or "enum" (for a
|
||||
/// dependent elaborated-type-specifier), or nothing (in contexts where we
|
||||
/// know that we must be referring to a type, e.g., in a base class specifier).
|
||||
class DependentNameType : public Type, public llvm::FoldingSetNode {
|
||||
/// \brief The keyword used to elaborate this type.
|
||||
ElaboratedTypeKeyword Keyword;
|
||||
|
||||
/// \brief The nested name specifier containing the qualifier.
|
||||
NestedNameSpecifier *NNS;
|
||||
|
||||
@ -2553,23 +2644,28 @@ class TypenameType : public Type, public llvm::FoldingSetNode {
|
||||
/// \brief The type that this typename specifier refers to.
|
||||
NameType Name;
|
||||
|
||||
TypenameType(NestedNameSpecifier *NNS, const IdentifierInfo *Name,
|
||||
QualType CanonType)
|
||||
: Type(Typename, CanonType, true), NNS(NNS), Name(Name) {
|
||||
DependentNameType(ElaboratedTypeKeyword Keyword, NestedNameSpecifier *NNS,
|
||||
const IdentifierInfo *Name, QualType CanonType)
|
||||
: Type(DependentName, CanonType, true),
|
||||
Keyword(Keyword), NNS(NNS), Name(Name) {
|
||||
assert(NNS->isDependent() &&
|
||||
"TypenameType requires a dependent nested-name-specifier");
|
||||
"DependentNameType requires a dependent nested-name-specifier");
|
||||
}
|
||||
|
||||
TypenameType(NestedNameSpecifier *NNS, const TemplateSpecializationType *Ty,
|
||||
QualType CanonType)
|
||||
: Type(Typename, CanonType, true), NNS(NNS), Name(Ty) {
|
||||
DependentNameType(ElaboratedTypeKeyword Keyword, NestedNameSpecifier *NNS,
|
||||
const TemplateSpecializationType *Ty, QualType CanonType)
|
||||
: Type(DependentName, CanonType, true),
|
||||
Keyword(Keyword), NNS(NNS), Name(Ty) {
|
||||
assert(NNS->isDependent() &&
|
||||
"TypenameType requires a dependent nested-name-specifier");
|
||||
"DependentNameType requires a dependent nested-name-specifier");
|
||||
}
|
||||
|
||||
friend class ASTContext; // ASTContext creates these
|
||||
|
||||
public:
|
||||
/// \brief Retrieve the keyword used to elaborate this type.
|
||||
ElaboratedTypeKeyword getKeyword() const { return Keyword; }
|
||||
|
||||
/// \brief Retrieve the qualification on this type.
|
||||
NestedNameSpecifier *getQualifier() const { return NNS; }
|
||||
|
||||
@ -2593,19 +2689,20 @@ public:
|
||||
QualType desugar() const { return QualType(this, 0); }
|
||||
|
||||
void Profile(llvm::FoldingSetNodeID &ID) {
|
||||
Profile(ID, NNS, Name);
|
||||
Profile(ID, Keyword, NNS, Name);
|
||||
}
|
||||
|
||||
static void Profile(llvm::FoldingSetNodeID &ID, NestedNameSpecifier *NNS,
|
||||
NameType Name) {
|
||||
static void Profile(llvm::FoldingSetNodeID &ID, ElaboratedTypeKeyword Keyword,
|
||||
NestedNameSpecifier *NNS, NameType Name) {
|
||||
ID.AddInteger(Keyword);
|
||||
ID.AddPointer(NNS);
|
||||
ID.AddPointer(Name.getOpaqueValue());
|
||||
}
|
||||
|
||||
static bool classof(const Type *T) {
|
||||
return T->getTypeClass() == Typename;
|
||||
return T->getTypeClass() == DependentName;
|
||||
}
|
||||
static bool classof(const TypenameType *T) { return true; }
|
||||
static bool classof(const DependentNameType *T) { return true; }
|
||||
};
|
||||
|
||||
/// ObjCInterfaceType - Interfaces are the core concept in Objective-C for
|
||||
@ -2936,37 +3033,18 @@ inline Qualifiers::GC QualType::getObjCGCAttr() const {
|
||||
return Qualifiers::GCNone;
|
||||
}
|
||||
|
||||
/// getNoReturnAttr - Returns true if the type has the noreturn attribute,
|
||||
/// false otherwise.
|
||||
inline bool QualType::getNoReturnAttr() const {
|
||||
QualType CT = getTypePtr()->getCanonicalTypeInternal();
|
||||
if (const PointerType *PT = getTypePtr()->getAs<PointerType>()) {
|
||||
inline FunctionType::ExtInfo getFunctionExtInfo(const Type &t) {
|
||||
if (const PointerType *PT = t.getAs<PointerType>()) {
|
||||
if (const FunctionType *FT = PT->getPointeeType()->getAs<FunctionType>())
|
||||
return FT->getNoReturnAttr();
|
||||
} else if (const FunctionType *FT = getTypePtr()->getAs<FunctionType>())
|
||||
return FT->getNoReturnAttr();
|
||||
return FT->getExtInfo();
|
||||
} else if (const FunctionType *FT = t.getAs<FunctionType>())
|
||||
return FT->getExtInfo();
|
||||
|
||||
return false;
|
||||
return FunctionType::ExtInfo();
|
||||
}
|
||||
|
||||
/// getCallConv - Returns the calling convention of the type if the type
|
||||
/// is a function type, CC_Default otherwise.
|
||||
inline CallingConv QualType::getCallConv() const {
|
||||
if (const PointerType *PT = getTypePtr()->getAs<PointerType>())
|
||||
return PT->getPointeeType().getCallConv();
|
||||
else if (const ReferenceType *RT = getTypePtr()->getAs<ReferenceType>())
|
||||
return RT->getPointeeType().getCallConv();
|
||||
else if (const MemberPointerType *MPT =
|
||||
getTypePtr()->getAs<MemberPointerType>())
|
||||
return MPT->getPointeeType().getCallConv();
|
||||
else if (const BlockPointerType *BPT =
|
||||
getTypePtr()->getAs<BlockPointerType>()) {
|
||||
if (const FunctionType *FT = BPT->getPointeeType()->getAs<FunctionType>())
|
||||
return FT->getCallConv();
|
||||
} else if (const FunctionType *FT = getTypePtr()->getAs<FunctionType>())
|
||||
return FT->getCallConv();
|
||||
|
||||
return CC_Default;
|
||||
inline FunctionType::ExtInfo getFunctionExtInfo(QualType t) {
|
||||
return getFunctionExtInfo(*t);
|
||||
}
|
||||
|
||||
/// isMoreQualifiedThan - Determine whether this type is more
|
||||
@ -3152,6 +3230,15 @@ inline const DiagnosticBuilder &operator<<(const DiagnosticBuilder &DB,
|
||||
return DB;
|
||||
}
|
||||
|
||||
/// Insertion operator for partial diagnostics. This allows sending QualType's
|
||||
/// into a diagnostic with <<.
|
||||
inline const PartialDiagnostic &operator<<(const PartialDiagnostic &PD,
|
||||
QualType T) {
|
||||
PD.AddTaggedVal(reinterpret_cast<intptr_t>(T.getAsOpaquePtr()),
|
||||
Diagnostic::ak_qualtype);
|
||||
return PD;
|
||||
}
|
||||
|
||||
// Helper class template that is used by Type::getAs to ensure that one does
|
||||
// not try to look through a qualified type to get to an array type.
|
||||
template<typename T,
|
||||
|
@ -1242,9 +1242,9 @@ class QualifiedNameTypeLoc :
|
||||
};
|
||||
|
||||
// FIXME: locations for the typename keyword and nested name specifier.
|
||||
class TypenameTypeLoc : public InheritingConcreteTypeLoc<TypeSpecTypeLoc,
|
||||
TypenameTypeLoc,
|
||||
TypenameType> {
|
||||
class DependentNameTypeLoc : public InheritingConcreteTypeLoc<TypeSpecTypeLoc,
|
||||
DependentNameTypeLoc,
|
||||
DependentNameType> {
|
||||
};
|
||||
|
||||
}
|
||||
|
@ -92,7 +92,7 @@ NON_CANONICAL_TYPE(SubstTemplateTypeParm, Type)
|
||||
NON_CANONICAL_UNLESS_DEPENDENT_TYPE(TemplateSpecialization, Type)
|
||||
NON_CANONICAL_TYPE(QualifiedName, Type)
|
||||
NON_CANONICAL_TYPE(InjectedClassName, Type)
|
||||
DEPENDENT_TYPE(Typename, Type)
|
||||
DEPENDENT_TYPE(DependentName, Type)
|
||||
TYPE(ObjCInterface, Type)
|
||||
TYPE(ObjCObjectPointer, Type)
|
||||
|
||||
|
@ -33,7 +33,7 @@ class ParentMap;
|
||||
class ImplicitParamDecl;
|
||||
class LocationContextManager;
|
||||
class StackFrameContext;
|
||||
|
||||
|
||||
/// AnalysisContext contains the context data for the function or method under
|
||||
/// analysis.
|
||||
class AnalysisContext {
|
||||
@ -41,6 +41,7 @@ class AnalysisContext {
|
||||
|
||||
// AnalysisContext owns the following data.
|
||||
CFG *cfg;
|
||||
bool builtCFG;
|
||||
LiveVariables *liveness;
|
||||
ParentMap *PM;
|
||||
llvm::DenseMap<const BlockDecl*,void*> *ReferencedBlockVars;
|
||||
@ -48,8 +49,8 @@ class AnalysisContext {
|
||||
bool AddEHEdges;
|
||||
public:
|
||||
AnalysisContext(const Decl *d, bool addehedges = false)
|
||||
: D(d), cfg(0), liveness(0), PM(0), ReferencedBlockVars(0),
|
||||
AddEHEdges(addehedges) {}
|
||||
: D(d), cfg(0), builtCFG(false), liveness(0), PM(0),
|
||||
ReferencedBlockVars(0), AddEHEdges(addehedges) {}
|
||||
|
||||
~AnalysisContext();
|
||||
|
||||
@ -69,7 +70,7 @@ public:
|
||||
|
||||
std::pair<referenced_decls_iterator, referenced_decls_iterator>
|
||||
getReferencedBlockVars(const BlockDecl *BD);
|
||||
|
||||
|
||||
/// Return the ImplicitParamDecl* associated with 'self' if this
|
||||
/// AnalysisContext wraps an ObjCMethodDecl. Returns NULL otherwise.
|
||||
const ImplicitParamDecl *getSelfDecl() const;
|
||||
@ -82,7 +83,7 @@ public:
|
||||
~AnalysisContextManager();
|
||||
|
||||
AnalysisContext *getContext(const Decl *D);
|
||||
|
||||
|
||||
// Discard all previously created AnalysisContexts.
|
||||
void clear();
|
||||
};
|
||||
@ -103,7 +104,7 @@ protected:
|
||||
|
||||
public:
|
||||
virtual ~LocationContext();
|
||||
|
||||
|
||||
ContextKind getKind() const { return Kind; }
|
||||
|
||||
AnalysisContext *getAnalysisContext() const { return Ctx; }
|
||||
@ -120,14 +121,14 @@ public:
|
||||
return getAnalysisContext()->getLiveVariables();
|
||||
}
|
||||
|
||||
ParentMap &getParentMap() const {
|
||||
ParentMap &getParentMap() const {
|
||||
return getAnalysisContext()->getParentMap();
|
||||
}
|
||||
|
||||
const ImplicitParamDecl *getSelfDecl() const {
|
||||
return Ctx->getSelfDecl();
|
||||
}
|
||||
|
||||
|
||||
const StackFrameContext *getCurrentStackFrame() const;
|
||||
const StackFrameContext *
|
||||
getStackFrameForDeclContext(const DeclContext *DC) const;
|
||||
@ -157,7 +158,7 @@ class StackFrameContext : public LocationContext {
|
||||
friend class LocationContextManager;
|
||||
StackFrameContext(AnalysisContext *ctx, const LocationContext *parent,
|
||||
const Stmt *s, const CFGBlock *blk, unsigned idx)
|
||||
: LocationContext(StackFrame, ctx, parent), CallSite(s), Block(blk),
|
||||
: LocationContext(StackFrame, ctx, parent), CallSite(s), Block(blk),
|
||||
Index(idx) {}
|
||||
|
||||
public:
|
||||
@ -170,9 +171,9 @@ public:
|
||||
unsigned getIndex() const { return Index; }
|
||||
|
||||
void Profile(llvm::FoldingSetNodeID &ID);
|
||||
|
||||
|
||||
static void Profile(llvm::FoldingSetNodeID &ID, AnalysisContext *ctx,
|
||||
const LocationContext *parent, const Stmt *s,
|
||||
const LocationContext *parent, const Stmt *s,
|
||||
const CFGBlock *blk, unsigned idx) {
|
||||
ProfileCommon(ID, StackFrame, ctx, parent, s);
|
||||
ID.AddPointer(blk);
|
||||
@ -186,7 +187,7 @@ public:
|
||||
|
||||
class ScopeContext : public LocationContext {
|
||||
const Stmt *Enter;
|
||||
|
||||
|
||||
friend class LocationContextManager;
|
||||
ScopeContext(AnalysisContext *ctx, const LocationContext *parent,
|
||||
const Stmt *s)
|
||||
@ -229,7 +230,7 @@ public:
|
||||
const LocationContext *parent, const BlockDecl *bd) {
|
||||
ProfileCommon(ID, Block, ctx, parent, bd);
|
||||
}
|
||||
|
||||
|
||||
static bool classof(const LocationContext* Ctx) {
|
||||
return Ctx->getKind() == Block;
|
||||
}
|
||||
@ -239,7 +240,7 @@ class LocationContextManager {
|
||||
llvm::FoldingSet<LocationContext> Contexts;
|
||||
public:
|
||||
~LocationContextManager();
|
||||
|
||||
|
||||
const StackFrameContext *getStackFrame(AnalysisContext *ctx,
|
||||
const LocationContext *parent,
|
||||
const Stmt *s, const CFGBlock *blk,
|
||||
@ -248,7 +249,7 @@ public:
|
||||
const ScopeContext *getScope(AnalysisContext *ctx,
|
||||
const LocationContext *parent,
|
||||
const Stmt *s);
|
||||
|
||||
|
||||
/// Discard all previously created LocationContext objects.
|
||||
void clear();
|
||||
private:
|
||||
|
@ -17,7 +17,8 @@
|
||||
#include "clang/Analysis/CFG.h"
|
||||
#include "clang/Analysis/ProgramPoint.h"
|
||||
#include "clang/Analysis/FlowSensitive/DataflowValues.h"
|
||||
#include "llvm/ADT/SmallPtrSet.h"
|
||||
#include "llvm/ADT/DenseMap.h"
|
||||
#include "llvm/ADT/SmallVector.h"
|
||||
#include "functional" // STL
|
||||
|
||||
namespace clang {
|
||||
@ -28,23 +29,30 @@ namespace clang {
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
class DataflowWorkListTy {
|
||||
typedef llvm::SmallPtrSet<const CFGBlock*,20> BlockSet;
|
||||
BlockSet wlist;
|
||||
llvm::DenseMap<const CFGBlock*, unsigned char> BlockSet;
|
||||
llvm::SmallVector<const CFGBlock *, 10> BlockQueue;
|
||||
public:
|
||||
/// enqueue - Add a block to the worklist. Blocks already on the
|
||||
/// worklist are not added a second time.
|
||||
void enqueue(const CFGBlock* B) { wlist.insert(B); }
|
||||
void enqueue(const CFGBlock* B) {
|
||||
unsigned char &x = BlockSet[B];
|
||||
if (x == 1)
|
||||
return;
|
||||
x = 1;
|
||||
BlockQueue.push_back(B);
|
||||
}
|
||||
|
||||
/// dequeue - Remove a block from the worklist.
|
||||
const CFGBlock* dequeue() {
|
||||
assert (!wlist.empty());
|
||||
const CFGBlock* B = *wlist.begin();
|
||||
wlist.erase(B);
|
||||
assert(!BlockQueue.empty());
|
||||
const CFGBlock *B = BlockQueue.back();
|
||||
BlockQueue.pop_back();
|
||||
BlockSet[B] = 0;
|
||||
return B;
|
||||
}
|
||||
|
||||
/// isEmpty - Return true if the worklist is empty.
|
||||
bool isEmpty() const { return wlist.empty(); }
|
||||
bool isEmpty() const { return BlockQueue.empty(); }
|
||||
};
|
||||
|
||||
//===----------------------------------------------------------------------===//
|
||||
@ -188,10 +196,7 @@ private:
|
||||
/// SolveDataflowEquations - Perform the actual worklist algorithm
|
||||
/// to compute dataflow values.
|
||||
void SolveDataflowEquations(CFG& cfg, bool recordStmtValues) {
|
||||
// Enqueue all blocks to ensure the dataflow values are computed
|
||||
// for every block. Not all blocks are guaranteed to reach the exit block.
|
||||
for (CFG::iterator I=cfg.begin(), E=cfg.end(); I!=E; ++I)
|
||||
WorkList.enqueue(&**I);
|
||||
EnqueueBlocksOnWorklist(cfg, AnalysisDirTag());
|
||||
|
||||
while (!WorkList.isEmpty()) {
|
||||
const CFGBlock* B = WorkList.dequeue();
|
||||
@ -201,6 +206,22 @@ private:
|
||||
}
|
||||
}
|
||||
|
||||
void EnqueueBlocksOnWorklist(CFG &cfg, dataflow::forward_analysis_tag) {
|
||||
// Enqueue all blocks to ensure the dataflow values are computed
|
||||
// for every block. Not all blocks are guaranteed to reach the exit block.
|
||||
for (CFG::iterator I=cfg.begin(), E=cfg.end(); I!=E; ++I)
|
||||
WorkList.enqueue(&**I);
|
||||
}
|
||||
|
||||
void EnqueueBlocksOnWorklist(CFG &cfg, dataflow::backward_analysis_tag) {
|
||||
// Enqueue all blocks to ensure the dataflow values are computed
|
||||
// for every block. Not all blocks are guaranteed to reach the exit block.
|
||||
// Enqueue in reverse order since that will more likely match with
|
||||
// the order they should ideally processed by the dataflow algorithm.
|
||||
for (CFG::reverse_iterator I=cfg.rbegin(), E=cfg.rend(); I!=E; ++I)
|
||||
WorkList.enqueue(&**I);
|
||||
}
|
||||
|
||||
void ProcessMerge(CFG& cfg, const CFGBlock* B) {
|
||||
ValTy& V = TF.getVal();
|
||||
TF.SetTopValue(V);
|
||||
|
@ -397,13 +397,6 @@ BUILTIN(__sync_fetch_and_xor_4, "ii*i.", "n")
|
||||
BUILTIN(__sync_fetch_and_xor_8, "LLiLLi*LLi.", "n")
|
||||
BUILTIN(__sync_fetch_and_xor_16, "LLLiLLLi*LLLi.", "n")
|
||||
|
||||
BUILTIN(__sync_fetch_and_nand, "v.", "")
|
||||
BUILTIN(__sync_fetch_and_nand_1, "cc*c.", "n")
|
||||
BUILTIN(__sync_fetch_and_nand_2, "ss*s.", "n")
|
||||
BUILTIN(__sync_fetch_and_nand_4, "ii*i.", "n")
|
||||
BUILTIN(__sync_fetch_and_nand_8, "LLiLLi*LLi.", "n")
|
||||
BUILTIN(__sync_fetch_and_nand_16, "LLLiLLLi*LLLi.", "n")
|
||||
|
||||
|
||||
BUILTIN(__sync_add_and_fetch, "v.", "")
|
||||
BUILTIN(__sync_add_and_fetch_1, "cc*c.", "n")
|
||||
@ -440,14 +433,6 @@ BUILTIN(__sync_xor_and_fetch_4, "ii*i.", "n")
|
||||
BUILTIN(__sync_xor_and_fetch_8, "LLiLLi*LLi.", "n")
|
||||
BUILTIN(__sync_xor_and_fetch_16, "LLLiLLLi*LLLi.", "n")
|
||||
|
||||
BUILTIN(__sync_nand_and_fetch, "v.", "")
|
||||
BUILTIN(__sync_nand_and_fetch_1, "cc*c.", "n")
|
||||
BUILTIN(__sync_nand_and_fetch_2, "ss*s.", "n")
|
||||
BUILTIN(__sync_nand_and_fetch_4, "ii*i.", "n")
|
||||
BUILTIN(__sync_nand_and_fetch_8, "LLiLLi*LLi.", "n")
|
||||
BUILTIN(__sync_nand_and_fetch_16, "LLLiLLLi*LLLi.", "n")
|
||||
|
||||
|
||||
BUILTIN(__sync_bool_compare_and_swap, "v.", "")
|
||||
BUILTIN(__sync_bool_compare_and_swap_1, "bcD*cc.", "n")
|
||||
BUILTIN(__sync_bool_compare_and_swap_2, "bsD*ss.", "n")
|
||||
|
@ -317,4 +317,12 @@ BUILTIN(__builtin_ia32_crc32qi, "iic", "")
|
||||
BUILTIN(__builtin_ia32_crc32hi, "iis", "")
|
||||
BUILTIN(__builtin_ia32_crc32si, "iii", "")
|
||||
BUILTIN(__builtin_ia32_crc32di, "LLiLLiLLi", "")
|
||||
|
||||
// AES
|
||||
BUILTIN(__builtin_ia32_aesenc128, "V2LLiV2LLiV2LLi", "")
|
||||
BUILTIN(__builtin_ia32_aesenclast128, "V2LLiV2LLiV2LLi", "")
|
||||
BUILTIN(__builtin_ia32_aesdec128, "V2LLiV2LLiV2LLi", "")
|
||||
BUILTIN(__builtin_ia32_aesdeclast128, "V2LLiV2LLiV2LLi", "")
|
||||
BUILTIN(__builtin_ia32_aesimc128, "V2LLiV2LLi", "")
|
||||
BUILTIN(__builtin_ia32_aeskeygenassist128, "V2LLiV2LLii", "")
|
||||
#undef BUILTIN
|
||||
|
@ -1,8 +1,8 @@
|
||||
macro(clang_diag_gen component)
|
||||
tablegen(Diagnostic${component}Kinds.inc
|
||||
-gen-clang-diags-defs -clang-component=${component})
|
||||
tablegen(Diagnostic${component}Kinds.inc
|
||||
-gen-clang-diags-defs -clang-component=${component})
|
||||
add_custom_target(ClangDiagnostic${component}
|
||||
DEPENDS ${CMAKE_CURRENT_BINARY_DIR}/Diagnostic${component}Kinds.inc)
|
||||
DEPENDS Diagnostic${component}Kinds.inc)
|
||||
endmacro(clang_diag_gen)
|
||||
|
||||
set(LLVM_TARGET_DEFINITIONS Diagnostic.td)
|
||||
@ -17,4 +17,4 @@ clang_diag_gen(Sema)
|
||||
tablegen(DiagnosticGroups.inc
|
||||
-gen-clang-diag-groups)
|
||||
add_custom_target(ClangDiagnosticGroups
|
||||
DEPENDS ${CMAKE_CURRENT_BINARY_DIR}/DiagnosticGroups.inc)
|
||||
DEPENDS DiagnosticGroups.inc)
|
||||
|
@ -95,7 +95,7 @@ namespace clang {
|
||||
/// should also provide full recovery from such errors, such that
|
||||
/// suppressing the diagnostic output can still result in successful
|
||||
/// compilation.
|
||||
class CodeModificationHint {
|
||||
class FixItHint {
|
||||
public:
|
||||
/// \brief Tokens that should be removed to correct the error.
|
||||
SourceRange RemoveRange;
|
||||
@ -110,7 +110,7 @@ public:
|
||||
|
||||
/// \brief Empty code modification hint, indicating that no code
|
||||
/// modification is known.
|
||||
CodeModificationHint() : RemoveRange(), InsertionLoc() { }
|
||||
FixItHint() : RemoveRange(), InsertionLoc() { }
|
||||
|
||||
bool isNull() const {
|
||||
return !RemoveRange.isValid() && !InsertionLoc.isValid();
|
||||
@ -118,9 +118,9 @@ public:
|
||||
|
||||
/// \brief Create a code modification hint that inserts the given
|
||||
/// code string at a specific location.
|
||||
static CodeModificationHint CreateInsertion(SourceLocation InsertionLoc,
|
||||
llvm::StringRef Code) {
|
||||
CodeModificationHint Hint;
|
||||
static FixItHint CreateInsertion(SourceLocation InsertionLoc,
|
||||
llvm::StringRef Code) {
|
||||
FixItHint Hint;
|
||||
Hint.InsertionLoc = InsertionLoc;
|
||||
Hint.CodeToInsert = Code;
|
||||
return Hint;
|
||||
@ -128,17 +128,17 @@ public:
|
||||
|
||||
/// \brief Create a code modification hint that removes the given
|
||||
/// source range.
|
||||
static CodeModificationHint CreateRemoval(SourceRange RemoveRange) {
|
||||
CodeModificationHint Hint;
|
||||
static FixItHint CreateRemoval(SourceRange RemoveRange) {
|
||||
FixItHint Hint;
|
||||
Hint.RemoveRange = RemoveRange;
|
||||
return Hint;
|
||||
}
|
||||
|
||||
/// \brief Create a code modification hint that replaces the given
|
||||
/// source range with the given code string.
|
||||
static CodeModificationHint CreateReplacement(SourceRange RemoveRange,
|
||||
llvm::StringRef Code) {
|
||||
CodeModificationHint Hint;
|
||||
static FixItHint CreateReplacement(SourceRange RemoveRange,
|
||||
llvm::StringRef Code) {
|
||||
FixItHint Hint;
|
||||
Hint.RemoveRange = RemoveRange;
|
||||
Hint.InsertionLoc = RemoveRange.getBegin();
|
||||
Hint.CodeToInsert = Code;
|
||||
@ -234,6 +234,18 @@ private:
|
||||
void *Cookie);
|
||||
void *ArgToStringCookie;
|
||||
ArgToStringFnTy ArgToStringFn;
|
||||
|
||||
/// \brief ID of the "delayed" diagnostic, which is a (typically
|
||||
/// fatal) diagnostic that had to be delayed because it was found
|
||||
/// while emitting another diagnostic.
|
||||
unsigned DelayedDiagID;
|
||||
|
||||
/// \brief First string argument for the delayed diagnostic.
|
||||
std::string DelayedDiagArg1;
|
||||
|
||||
/// \brief Second string argument for the delayed diagnostic.
|
||||
std::string DelayedDiagArg2;
|
||||
|
||||
public:
|
||||
explicit Diagnostic(DiagnosticClient *client = 0);
|
||||
~Diagnostic();
|
||||
@ -377,6 +389,28 @@ public:
|
||||
/// the diagnostic, this returns null.
|
||||
static const char *getWarningOptionForDiag(unsigned DiagID);
|
||||
|
||||
/// \brief Enumeration describing how the the emission of a diagnostic should
|
||||
/// be treated when it occurs during C++ template argument deduction.
|
||||
enum SFINAEResponse {
|
||||
/// \brief The diagnostic should not be reported, but it should cause
|
||||
/// template argument deduction to fail.
|
||||
///
|
||||
/// The vast majority of errors that occur during template argument
|
||||
/// deduction fall into this category.
|
||||
SFINAE_SubstitutionFailure,
|
||||
|
||||
/// \brief The diagnostic should be suppressed entirely.
|
||||
///
|
||||
/// Warnings generally fall into this category.
|
||||
SFINAE_Suppress,
|
||||
|
||||
/// \brief The diagnostic should be reported.
|
||||
///
|
||||
/// The diagnostic should be reported. Various fatal errors (e.g.,
|
||||
/// template instantiation depth exceeded) fall into this category.
|
||||
SFINAE_Report
|
||||
};
|
||||
|
||||
/// \brief Determines whether the given built-in diagnostic ID is
|
||||
/// for an error that is suppressed if it occurs during C++ template
|
||||
/// argument deduction.
|
||||
@ -385,7 +419,7 @@ public:
|
||||
/// deduction fails but no diagnostic is emitted. Certain classes of
|
||||
/// errors, such as those errors that involve C++ access control,
|
||||
/// are not SFINAE errors.
|
||||
static bool isBuiltinSFINAEDiag(unsigned DiagID);
|
||||
static SFINAEResponse getDiagnosticSFINAEResponse(unsigned DiagID);
|
||||
|
||||
/// getDiagnosticLevel - Based on the way the client configured the Diagnostic
|
||||
/// object, classify the specified diagnostic ID into a Level, consumable by
|
||||
@ -400,10 +434,41 @@ public:
|
||||
inline DiagnosticBuilder Report(FullSourceLoc Pos, unsigned DiagID);
|
||||
inline DiagnosticBuilder Report(unsigned DiagID);
|
||||
|
||||
/// \brief Determine whethere there is already a diagnostic in flight.
|
||||
bool isDiagnosticInFlight() const { return CurDiagID != ~0U; }
|
||||
|
||||
/// \brief Set the "delayed" diagnostic that will be emitted once
|
||||
/// the current diagnostic completes.
|
||||
///
|
||||
/// If a diagnostic is already in-flight but the front end must
|
||||
/// report a problem (e.g., with an inconsistent file system
|
||||
/// state), this routine sets a "delayed" diagnostic that will be
|
||||
/// emitted after the current diagnostic completes. This should
|
||||
/// only be used for fatal errors detected at inconvenient
|
||||
/// times. If emitting a delayed diagnostic causes a second delayed
|
||||
/// diagnostic to be introduced, that second delayed diagnostic
|
||||
/// will be ignored.
|
||||
///
|
||||
/// \param DiagID The ID of the diagnostic being delayed.
|
||||
///
|
||||
/// \param Arg1 A string argument that will be provided to the
|
||||
/// diagnostic. A copy of this string will be stored in the
|
||||
/// Diagnostic object itself.
|
||||
///
|
||||
/// \param Arg2 A string argument that will be provided to the
|
||||
/// diagnostic. A copy of this string will be stored in the
|
||||
/// Diagnostic object itself.
|
||||
void SetDelayedDiagnostic(unsigned DiagID, llvm::StringRef Arg1 = "",
|
||||
llvm::StringRef Arg2 = "");
|
||||
|
||||
/// \brief Clear out the current diagnostic.
|
||||
void Clear() { CurDiagID = ~0U; }
|
||||
|
||||
private:
|
||||
/// \brief Report the delayed diagnostic.
|
||||
void ReportDelayed();
|
||||
|
||||
|
||||
/// getDiagnosticMappingInfo - Return the mapping info currently set for the
|
||||
/// specified builtin diagnostic. This returns the high bit encoding, or zero
|
||||
/// if the field is completely uninitialized.
|
||||
@ -454,8 +519,8 @@ private:
|
||||
/// NumRanges - This is the number of ranges in the DiagRanges array.
|
||||
unsigned char NumDiagRanges;
|
||||
/// \brief The number of code modifications hints in the
|
||||
/// CodeModificationHints array.
|
||||
unsigned char NumCodeModificationHints;
|
||||
/// FixItHints array.
|
||||
unsigned char NumFixItHints;
|
||||
|
||||
/// DiagArgumentsKind - This is an array of ArgumentKind::ArgumentKind enum
|
||||
/// values, with one for each argument. This specifies whether the argument
|
||||
@ -477,11 +542,11 @@ private:
|
||||
/// only support 10 ranges, could easily be extended if needed.
|
||||
SourceRange DiagRanges[10];
|
||||
|
||||
enum { MaxCodeModificationHints = 3 };
|
||||
enum { MaxFixItHints = 3 };
|
||||
|
||||
/// CodeModificationHints - If valid, provides a hint with some code
|
||||
/// FixItHints - If valid, provides a hint with some code
|
||||
/// to insert, remove, or modify at a particular position.
|
||||
CodeModificationHint CodeModificationHints[MaxCodeModificationHints];
|
||||
FixItHint FixItHints[MaxFixItHints];
|
||||
|
||||
/// ProcessDiag - This is the method used to report a diagnostic that is
|
||||
/// finally fully formed.
|
||||
@ -508,13 +573,12 @@ private:
|
||||
/// for example.
|
||||
class DiagnosticBuilder {
|
||||
mutable Diagnostic *DiagObj;
|
||||
mutable unsigned NumArgs, NumRanges, NumCodeModificationHints;
|
||||
mutable unsigned NumArgs, NumRanges, NumFixItHints;
|
||||
|
||||
void operator=(const DiagnosticBuilder&); // DO NOT IMPLEMENT
|
||||
friend class Diagnostic;
|
||||
explicit DiagnosticBuilder(Diagnostic *diagObj)
|
||||
: DiagObj(diagObj), NumArgs(0), NumRanges(0),
|
||||
NumCodeModificationHints(0) {}
|
||||
: DiagObj(diagObj), NumArgs(0), NumRanges(0), NumFixItHints(0) {}
|
||||
|
||||
public:
|
||||
/// Copy constructor. When copied, this "takes" the diagnostic info from the
|
||||
@ -524,7 +588,7 @@ public:
|
||||
D.DiagObj = 0;
|
||||
NumArgs = D.NumArgs;
|
||||
NumRanges = D.NumRanges;
|
||||
NumCodeModificationHints = D.NumCodeModificationHints;
|
||||
NumFixItHints = D.NumFixItHints;
|
||||
}
|
||||
|
||||
/// \brief Simple enumeration value used to give a name to the
|
||||
@ -534,7 +598,7 @@ public:
|
||||
/// \brief Create an empty DiagnosticBuilder object that represents
|
||||
/// no actual diagnostic.
|
||||
explicit DiagnosticBuilder(SuppressKind)
|
||||
: DiagObj(0), NumArgs(0), NumRanges(0), NumCodeModificationHints(0) { }
|
||||
: DiagObj(0), NumArgs(0), NumRanges(0), NumFixItHints(0) { }
|
||||
|
||||
/// \brief Force the diagnostic builder to emit the diagnostic now.
|
||||
///
|
||||
@ -543,29 +607,7 @@ public:
|
||||
///
|
||||
/// \returns true if a diagnostic was emitted, false if the
|
||||
/// diagnostic was suppressed.
|
||||
bool Emit() {
|
||||
// If DiagObj is null, then its soul was stolen by the copy ctor
|
||||
// or the user called Emit().
|
||||
if (DiagObj == 0) return false;
|
||||
|
||||
// When emitting diagnostics, we set the final argument count into
|
||||
// the Diagnostic object.
|
||||
DiagObj->NumDiagArgs = NumArgs;
|
||||
DiagObj->NumDiagRanges = NumRanges;
|
||||
DiagObj->NumCodeModificationHints = NumCodeModificationHints;
|
||||
|
||||
// Process the diagnostic, sending the accumulated information to the
|
||||
// DiagnosticClient.
|
||||
bool Emitted = DiagObj->ProcessDiag();
|
||||
|
||||
// Clear out the current diagnostic object.
|
||||
DiagObj->Clear();
|
||||
|
||||
// This diagnostic is dead.
|
||||
DiagObj = 0;
|
||||
|
||||
return Emitted;
|
||||
}
|
||||
bool Emit();
|
||||
|
||||
/// Destructor - The dtor emits the diagnostic if it hasn't already
|
||||
/// been emitted.
|
||||
@ -605,14 +647,14 @@ public:
|
||||
DiagObj->DiagRanges[NumRanges++] = R;
|
||||
}
|
||||
|
||||
void AddCodeModificationHint(const CodeModificationHint &Hint) const {
|
||||
void AddFixItHint(const FixItHint &Hint) const {
|
||||
if (Hint.isNull())
|
||||
return;
|
||||
|
||||
assert(NumCodeModificationHints < Diagnostic::MaxCodeModificationHints &&
|
||||
"Too many code modification hints!");
|
||||
assert(NumFixItHints < Diagnostic::MaxFixItHints &&
|
||||
"Too many fix-it hints!");
|
||||
if (DiagObj)
|
||||
DiagObj->CodeModificationHints[NumCodeModificationHints++] = Hint;
|
||||
DiagObj->FixItHints[NumFixItHints++] = Hint;
|
||||
}
|
||||
};
|
||||
|
||||
@ -673,8 +715,8 @@ inline const DiagnosticBuilder &operator<<(const DiagnosticBuilder &DB,
|
||||
}
|
||||
|
||||
inline const DiagnosticBuilder &operator<<(const DiagnosticBuilder &DB,
|
||||
const CodeModificationHint &Hint) {
|
||||
DB.AddCodeModificationHint(Hint);
|
||||
const FixItHint &Hint) {
|
||||
DB.AddFixItHint(Hint);
|
||||
return DB;
|
||||
}
|
||||
|
||||
@ -770,17 +812,17 @@ public:
|
||||
return DiagObj->DiagRanges[Idx];
|
||||
}
|
||||
|
||||
unsigned getNumCodeModificationHints() const {
|
||||
return DiagObj->NumCodeModificationHints;
|
||||
unsigned getNumFixItHints() const {
|
||||
return DiagObj->NumFixItHints;
|
||||
}
|
||||
|
||||
const CodeModificationHint &getCodeModificationHint(unsigned Idx) const {
|
||||
return DiagObj->CodeModificationHints[Idx];
|
||||
const FixItHint &getFixItHint(unsigned Idx) const {
|
||||
return DiagObj->FixItHints[Idx];
|
||||
}
|
||||
|
||||
const CodeModificationHint *getCodeModificationHints() const {
|
||||
return DiagObj->NumCodeModificationHints?
|
||||
&DiagObj->CodeModificationHints[0] : 0;
|
||||
const FixItHint *getFixItHints() const {
|
||||
return DiagObj->NumFixItHints?
|
||||
&DiagObj->FixItHints[0] : 0;
|
||||
}
|
||||
|
||||
/// FormatDiagnostic - Format this diagnostic into a string, substituting the
|
||||
@ -803,7 +845,7 @@ class StoredDiagnostic {
|
||||
FullSourceLoc Loc;
|
||||
std::string Message;
|
||||
std::vector<SourceRange> Ranges;
|
||||
std::vector<CodeModificationHint> FixIts;
|
||||
std::vector<FixItHint> FixIts;
|
||||
|
||||
public:
|
||||
StoredDiagnostic();
|
||||
@ -823,7 +865,7 @@ public:
|
||||
range_iterator range_end() const { return Ranges.end(); }
|
||||
unsigned range_size() const { return Ranges.size(); }
|
||||
|
||||
typedef std::vector<CodeModificationHint>::const_iterator fixit_iterator;
|
||||
typedef std::vector<FixItHint>::const_iterator fixit_iterator;
|
||||
fixit_iterator fixit_begin() const { return FixIts.begin(); }
|
||||
fixit_iterator fixit_end() const { return FixIts.end(); }
|
||||
unsigned fixit_size() const { return FixIts.size(); }
|
||||
|
@ -22,7 +22,7 @@ def err_fe_stdout_binary : Error<"unable to change standard output to binary">,
|
||||
def err_fe_stderr_binary : Error<"unable to change standard error to binary">,
|
||||
DefaultFatal;
|
||||
def err_fe_dependency_file_requires_MT : Error<
|
||||
"-dependency-file requires at least one -MT option">;
|
||||
"-dependency-file requires at least one -MT or -MQ option">;
|
||||
def err_fe_incompatible_options : Error<
|
||||
"'%0' cannot be used with '%1'">, DefaultFatal;
|
||||
def err_fe_no_fixit_and_codegen : Error<
|
||||
@ -57,6 +57,9 @@ def err_fe_pch_malformed_block : Error<
|
||||
"malformed block record in PCH file: '%0'">, DefaultFatal;
|
||||
def err_fe_pch_error_at_end_block : Error<
|
||||
"error at end of module block in PCH file: '%0'">, DefaultFatal;
|
||||
def err_fe_pch_file_modified : Error<
|
||||
"file '%0' has been modified since the precompiled header was built">,
|
||||
DefaultFatal;
|
||||
def err_fe_unable_to_open_output : Error<
|
||||
"unable to open output file '%0': '%1'">;
|
||||
def err_fe_unable_to_open_logfile : Error<
|
||||
|
@ -31,6 +31,7 @@ def : DiagGroup<"char-align">;
|
||||
def Comment : DiagGroup<"comment">;
|
||||
def : DiagGroup<"ctor-dtor-privacy">;
|
||||
def : DiagGroup<"declaration-after-statement">;
|
||||
def GNUDesignator : DiagGroup<"gnu-designator">;
|
||||
def Deprecated : DiagGroup<"deprecated">;
|
||||
def : DiagGroup<"disabled-optimization">;
|
||||
def : DiagGroup<"discard-qual">;
|
||||
@ -115,6 +116,7 @@ def UnusedVariable : DiagGroup<"unused-variable">;
|
||||
def ReadOnlySetterAttrs : DiagGroup<"readonly-setter-attrs">;
|
||||
def Reorder : DiagGroup<"reorder">;
|
||||
def UndeclaredSelector : DiagGroup<"undeclared-selector">;
|
||||
def Protocol : DiagGroup<"protocol">;
|
||||
def SuperSubClassMismatch : DiagGroup<"super-class-method-mismatch">;
|
||||
def : DiagGroup<"variadic-macros">;
|
||||
def VariadicMacros : DiagGroup<"variadic-macros">;
|
||||
@ -185,3 +187,6 @@ def : DiagGroup<"comments", [Comment]>; // -Wcomments = -Wcomment
|
||||
// but which aren't on by default in GCC.
|
||||
def NonGCC : DiagGroup<"non-gcc",
|
||||
[SignCompare, Conversion, LiteralRange]>;
|
||||
|
||||
// A warning group for warnings about GCC extensions.
|
||||
def GNU : DiagGroup<"gnu", [GNUDesignator]>;
|
||||
|
@ -50,22 +50,26 @@ def ext_enumerator_list_comma : Extension<
|
||||
"feature">;
|
||||
|
||||
def ext_gnu_indirect_goto : Extension<
|
||||
"use of GNU indirect-goto extension">;
|
||||
"use of GNU indirect-goto extension">, InGroup<GNU>;
|
||||
def ext_gnu_address_of_label : Extension<
|
||||
"use of GNU address-of-label extension">;
|
||||
"use of GNU address-of-label extension">, InGroup<GNU>;
|
||||
def ext_gnu_statement_expr : Extension<
|
||||
"use of GNU statement expression extension">;
|
||||
"use of GNU statement expression extension">, InGroup<GNU>;
|
||||
def ext_gnu_conditional_expr : Extension<
|
||||
"use of GNU ?: expression extension, eliding middle term">;
|
||||
"use of GNU ?: expression extension, eliding middle term">, InGroup<GNU>;
|
||||
def ext_gnu_empty_initializer : Extension<
|
||||
"use of GNU empty initializer extension">;
|
||||
def ext_gnu_array_range : Extension<"use of GNU array range extension">;
|
||||
"use of GNU empty initializer extension">, InGroup<GNU>;
|
||||
def ext_gnu_array_range : Extension<"use of GNU array range extension">,
|
||||
InGroup<GNUDesignator>;
|
||||
def ext_gnu_missing_equal_designator : ExtWarn<
|
||||
"use of GNU 'missing =' extension in designator">;
|
||||
"use of GNU 'missing =' extension in designator">,
|
||||
InGroup<GNUDesignator>;
|
||||
def err_expected_equal_designator : Error<"expected '=' or another designator">;
|
||||
def ext_gnu_old_style_field_designator : ExtWarn<
|
||||
"use of GNU old-style field designator extension">;
|
||||
def ext_gnu_case_range : Extension<"use of GNU case range extension">;
|
||||
"use of GNU old-style field designator extension">,
|
||||
InGroup<GNUDesignator>;
|
||||
def ext_gnu_case_range : Extension<"use of GNU case range extension">,
|
||||
InGroup<GNU>;
|
||||
|
||||
// Generic errors.
|
||||
def err_parse_error : Error<"parse error">;
|
||||
|
@ -68,7 +68,7 @@ def err_designator_into_flexible_array_member : Error<
|
||||
def note_flexible_array_member : Note<
|
||||
"initialized flexible array member %0 is here">;
|
||||
def ext_flexible_array_init : Extension<
|
||||
"flexible array initialization is a GNU extension">;
|
||||
"flexible array initialization is a GNU extension">, InGroup<GNU>;
|
||||
|
||||
// Declarations.
|
||||
def ext_vla : Extension<
|
||||
@ -268,8 +268,6 @@ def err_duplicate_ivar_declaration : Error<
|
||||
"instance variable is already declared">;
|
||||
def warn_on_superclass_use : Warning<
|
||||
"class implementation may not have super class">;
|
||||
def err_non_private_ivar_declaration : Error<
|
||||
"only private ivars may be declared in implementation">;
|
||||
def err_conflicting_ivar_bitwidth : Error<
|
||||
"instance variable %0 has conflicting bit-field width">;
|
||||
def err_conflicting_ivar_name : Error<
|
||||
@ -277,7 +275,9 @@ def err_conflicting_ivar_name : Error<
|
||||
def err_inconsistant_ivar_count : Error<
|
||||
"inconsistent number of instance variables specified">;
|
||||
def warn_incomplete_impl : Warning<"incomplete implementation">;
|
||||
def warn_undef_method_impl : Warning<"method definition for %0 not found">;
|
||||
def note_undef_method_impl : Note<"method definition for %0 not found">;
|
||||
def note_required_for_protocol_at :
|
||||
Note<"required for direct or indirect protocol %0">;
|
||||
|
||||
def warn_conflicting_ret_types : Warning<
|
||||
"conflicting return type in implementation of %0: %1 vs %2">;
|
||||
@ -350,7 +350,7 @@ def error_synthesized_ivar_yet_not_supported : Error<
|
||||
" (need to declare %0 explicitly)">;
|
||||
|
||||
def error_property_ivar_type : Error<
|
||||
"type of property %0 does not match type of ivar %1">;
|
||||
"type of property %0 (%1) does not match type of ivar %2 (%3)">;
|
||||
def error_ivar_in_superclass_use : Error<
|
||||
"property %0 attempting to use ivar %1 declared in super class %2">;
|
||||
def error_weak_property : Error<
|
||||
@ -367,6 +367,8 @@ def warn_objc_property_attr_mutually_exclusive : Warning<
|
||||
InGroup<ReadOnlySetterAttrs>, DefaultIgnore;
|
||||
def warn_undeclared_selector : Warning<
|
||||
"undeclared selector %0">, InGroup<UndeclaredSelector>, DefaultIgnore;
|
||||
def warn_unimplemented_protocol_method : Warning<
|
||||
"method in protocol not implemented">, InGroup<Protocol>;
|
||||
|
||||
// C++ declarations
|
||||
def err_static_assert_expression_is_not_constant : Error<
|
||||
@ -393,7 +395,11 @@ def err_abstract_type_in_decl : Error<
|
||||
"%select{return|parameter|variable|field}0 type %1 is an abstract class">;
|
||||
def err_allocation_of_abstract_type : Error<
|
||||
"allocation of an object of abstract type %0">;
|
||||
|
||||
|
||||
def err_multiple_final_overriders : Error<
|
||||
"virtual function %q0 has more than one final overrider in %1">;
|
||||
def note_final_overrider : Note<"final overrider of %q0 in %1">;
|
||||
|
||||
def err_type_defined_in_type_specifier : Error<
|
||||
"%0 can not be defined in a type specifier">;
|
||||
def err_type_defined_in_result_type : Error<
|
||||
@ -432,6 +438,8 @@ def err_incompatible_exception_specs : Error<
|
||||
"target exception specification is not superset of source">;
|
||||
def err_deep_exception_specs_differ : Error<
|
||||
"exception specifications of %select{return|argument}0 types differ">;
|
||||
def warn_missing_exception_specification : Warning<
|
||||
"%0 is missing exception specification '%1'">;
|
||||
|
||||
// C++ access checking
|
||||
def err_class_redeclared_with_different_access : Error<
|
||||
@ -532,6 +540,7 @@ def err_implicit_object_parameter_init : Error<
|
||||
"of type %1">;
|
||||
|
||||
def note_field_decl : Note<"member is declared here">;
|
||||
def note_ivar_decl : Note<"ivar is declared here">;
|
||||
def note_bitfield_decl : Note<"bit-field is declared here">;
|
||||
def note_previous_decl : Note<"%0 declared here">;
|
||||
def note_member_synthesized_at : Note<
|
||||
@ -776,8 +785,9 @@ def warn_redeclaration_without_attribute_prev_attribute_ignored : Warning<
|
||||
def warn_attribute_ignored : Warning<"%0 attribute ignored">;
|
||||
def warn_attribute_precede_definition : Warning<
|
||||
"attribute declaration must precede definition">;
|
||||
def warn_attribute_void_function : Warning<
|
||||
"attribute %0 cannot be applied to functions without return value">;
|
||||
def warn_attribute_void_function_method : Warning<
|
||||
"attribute %0 cannot be applied to "
|
||||
"%select{functions|Objective-C method}1 without return value">;
|
||||
def warn_attribute_weak_on_field : Warning<
|
||||
"__weak attribute cannot be specified on a field declaration">;
|
||||
def warn_attribute_weak_on_local : Warning<
|
||||
@ -1199,26 +1209,40 @@ def err_template_arg_not_integral_or_enumeral : Error<
|
||||
def err_template_arg_not_ice : Error<
|
||||
"non-type template argument of type %0 is not an integral constant "
|
||||
"expression">;
|
||||
def err_deduced_non_type_template_arg_type_mismatch : Error<
|
||||
"deduced non-type template argument does not have the same type as the "
|
||||
"its corresponding template parameter (%0 vs %1)">;
|
||||
def err_template_arg_not_convertible : Error<
|
||||
"non-type template argument of type %0 cannot be converted to a value "
|
||||
"of type %1">;
|
||||
def err_template_arg_negative : Error<
|
||||
"non-type template argument provides negative value '%0' for unsigned "
|
||||
"template parameter of type %1">;
|
||||
def err_template_arg_too_large : Error<
|
||||
"non-type template argument value '%0' is too large for template "
|
||||
"parameter of type %1">;
|
||||
def warn_template_arg_negative : Warning<
|
||||
"non-type template argument with value '%0' converted to '%1' for unsigned "
|
||||
"template parameter of type %2">;
|
||||
def warn_template_arg_too_large : Warning<
|
||||
"non-type template argument value '%0' truncated to '%1' for "
|
||||
"template parameter of type %2">;
|
||||
def err_template_arg_no_ref_bind : Error<
|
||||
"non-type template parameter of reference type %0 cannot bind to template "
|
||||
"argument of type %1">;
|
||||
def err_template_arg_ref_bind_ignores_quals : Error<
|
||||
"reference binding of non-type template parameter of type %0 to template "
|
||||
"argument of type %1 ignores qualifiers">;
|
||||
def err_template_arg_unresolved_overloaded_function : Error<
|
||||
"overloaded function cannot be resolved to a non-type template parameter of "
|
||||
"type %0">;
|
||||
def err_template_arg_not_decl_ref : Error<
|
||||
"non-type template argument does not refer to any declaration">;
|
||||
def err_template_arg_not_object_or_func_form : Error<
|
||||
"non-type template argument does not directly refer to an object or "
|
||||
"function">;
|
||||
def err_template_arg_not_address_of : Error<
|
||||
"non-type template argument for template parameter of pointer type %0 must "
|
||||
"have its address taken">;
|
||||
def err_template_arg_address_of_non_pointer : Error<
|
||||
"address taken in non-type template argument for template parameter of "
|
||||
"reference type %0">;
|
||||
def err_template_arg_reference_var : Error<
|
||||
"non-type template argument of reference type %0 is not an object">;
|
||||
def err_template_arg_field : Error<
|
||||
"non-type template argument refers to non-static data member %0">;
|
||||
def err_template_arg_method : Error<
|
||||
@ -1251,6 +1275,8 @@ def err_template_spec_decl_function_scope : Error<
|
||||
"explicit specialization of %0 in function scope">;
|
||||
def err_template_spec_decl_class_scope : Error<
|
||||
"explicit specialization of %0 in class scope">;
|
||||
def err_template_spec_decl_friend : Error<
|
||||
"cannot declare an explicit specialization in a friend">;
|
||||
def err_template_spec_decl_out_of_scope_global : Error<
|
||||
"%select{class template|class template partial|function template|member "
|
||||
"function|static data member|member class}0 specialization of %1 must "
|
||||
@ -1372,13 +1398,13 @@ def note_default_function_arg_instantiation_here : Note<
|
||||
"for '%0' required here">;
|
||||
def note_explicit_template_arg_substitution_here : Note<
|
||||
"while substituting explicitly-specified template arguments into function "
|
||||
"template %f, here">;
|
||||
"template %0 %1">;
|
||||
def note_function_template_deduction_instantiation_here : Note<
|
||||
"while substituting deduced template arguments into function template %0, "
|
||||
"here">;
|
||||
"while substituting deduced template arguments into function template %0 "
|
||||
"%1">;
|
||||
def note_partial_spec_deduct_instantiation_here : Note<
|
||||
"during template argument deduction for class template partial "
|
||||
"specialization %0, here">;
|
||||
"specialization %0 %1">;
|
||||
def note_prior_template_arg_substitution : Note<
|
||||
"while substituting prior template arguments into %select{non-type|template}0"
|
||||
" template parameter%1 %2">;
|
||||
@ -1537,7 +1563,8 @@ def err_forward_ref_enum : Error<
|
||||
"ISO C++ forbids forward references to 'enum' types">;
|
||||
def err_redefinition_of_enumerator : Error<"redefinition of enumerator %0">;
|
||||
def err_duplicate_member : Error<"duplicate member %0">;
|
||||
def err_misplaced_ivar : Error<"ivars may not be placed in categories">;
|
||||
def err_misplaced_ivar : Error<
|
||||
"ivars may not be placed in %select{categories|class extension}0">;
|
||||
def ext_enum_value_not_int : Extension<
|
||||
"ISO C restricts enumerator values to range of 'int' (%0 is too "
|
||||
"%select{small|large}1)">;
|
||||
@ -1575,6 +1602,8 @@ def err_typecheck_invalid_restrict_invalid_pointee : Error<
|
||||
"pointer to function type %0 may not be 'restrict' qualified">;
|
||||
def ext_typecheck_zero_array_size : Extension<
|
||||
"zero size arrays are an extension">;
|
||||
def err_typecheck_zero_array_size : Error<
|
||||
"zero-length arrays are not permitted in C++">;
|
||||
def err_at_least_one_initializer_needed_to_size_array : Error<
|
||||
"at least one initializer value required to size array">;
|
||||
def err_array_size_non_int : Error<"size of array has non-integer type %0">;
|
||||
@ -1664,7 +1693,7 @@ def err_field_declared_as_function : Error<"field %0 declared as a function">;
|
||||
def err_field_incomplete : Error<"field has incomplete type %0">;
|
||||
def ext_variable_sized_type_in_struct : ExtWarn<
|
||||
"field %0 with variable sized type %1 not at the end of a struct or class is"
|
||||
" a GNU extension">;
|
||||
" a GNU extension">, InGroup<GNU>;
|
||||
|
||||
def err_flexible_array_empty_struct : Error<
|
||||
"flexible array %0 not allowed in otherwise empty struct">;
|
||||
@ -2164,7 +2193,7 @@ def err_invalid_declarator_global_scope : Error<
|
||||
def err_invalid_declarator_in_function : Error<
|
||||
"definition or redeclaration of %0 not allowed inside a function">;
|
||||
def err_not_tag_in_scope : Error<
|
||||
"%0 does not name a tag member in the specified scope">;
|
||||
"no %select{struct|union|class|enum}0 named %1 in %2">;
|
||||
|
||||
def err_cannot_form_pointer_to_member_of_reference_type : Error<
|
||||
"cannot form a pointer-to-member to member %0 of reference type %1">;
|
||||
@ -2322,7 +2351,8 @@ def warn_typecheck_cond_pointer_integer_mismatch : ExtWarn<
|
||||
def err_typecheck_choose_expr_requires_constant : Error<
|
||||
"'__builtin_choose_expr' requires a constant expression">;
|
||||
def ext_typecheck_expression_not_constant_but_accepted : Extension<
|
||||
"expression is not a constant, but is accepted as one by GNU extensions">;
|
||||
"expression is not a constant, but is accepted as one by GNU extensions">,
|
||||
InGroup<GNU>;
|
||||
def warn_unused_expr : Warning<"expression result unused">,
|
||||
InGroup<UnusedValue>;
|
||||
def warn_unused_property_expr : Warning<
|
||||
@ -2334,6 +2364,7 @@ def warn_unused_call : Warning<
|
||||
|
||||
def err_incomplete_type_used_in_type_trait_expr : Error<
|
||||
"incomplete type %0 used in type trait expression">;
|
||||
def err_expected_ident_or_lparen : Error<"expected identifier or '('">;
|
||||
|
||||
// inline asm.
|
||||
def err_asm_wide_character : Error<"wide string is invalid in 'asm'">;
|
||||
@ -2413,9 +2444,9 @@ def err_in_class_initializer_non_constant : Error<
|
||||
|
||||
// C++ anonymous unions and GNU anonymous structs/unions
|
||||
def ext_anonymous_union : Extension<
|
||||
"anonymous unions are a GNU extension in C">;
|
||||
"anonymous unions are a GNU extension in C">, InGroup<GNU>;
|
||||
def ext_anonymous_struct : Extension<
|
||||
"anonymous structs are a GNU extension">;
|
||||
"anonymous structs are a GNU extension">, InGroup<GNU>;
|
||||
def err_anonymous_union_not_static : Error<
|
||||
"anonymous unions at namespace or global scope must be declared 'static'">;
|
||||
def err_anonymous_union_with_storage_spec : Error<
|
||||
@ -2584,6 +2615,9 @@ def warn_printf_missing_format_string : Warning<
|
||||
def warn_printf_conversion_argument_type_mismatch : Warning<
|
||||
"conversion specifies type %0 but the argument has type %1">,
|
||||
InGroup<Format>;
|
||||
def warn_printf_positional_arg_exceeds_data_args : Warning <
|
||||
"data argument position '%0' exceeds the number of data arguments (%1)">,
|
||||
InGroup<Format>;
|
||||
def warn_printf_zero_positional_specifier : Warning<
|
||||
"position arguments in format strings start counting at 1 (not 0)">,
|
||||
InGroup<Format>;
|
||||
|
@ -15,19 +15,18 @@
|
||||
#ifndef LLVM_CLANG_PARTIALDIAGNOSTIC_H
|
||||
#define LLVM_CLANG_PARTIALDIAGNOSTIC_H
|
||||
|
||||
#include "clang/AST/Type.h"
|
||||
#include "clang/Basic/Diagnostic.h"
|
||||
#include "clang/Basic/SourceLocation.h"
|
||||
#include "llvm/ADT/STLExtras.h"
|
||||
#include "llvm/System/DataTypes.h"
|
||||
#include <cassert>
|
||||
|
||||
namespace clang {
|
||||
|
||||
class DeclarationName;
|
||||
|
||||
class PartialDiagnostic {
|
||||
public:
|
||||
struct Storage {
|
||||
Storage() : NumDiagArgs(0), NumDiagRanges(0), NumCodeModificationHints(0) {
|
||||
}
|
||||
Storage() : NumDiagArgs(0), NumDiagRanges(0), NumFixItHints(0) { }
|
||||
|
||||
enum {
|
||||
/// MaxArguments - The maximum number of arguments we can hold. We
|
||||
@ -44,8 +43,8 @@ class PartialDiagnostic {
|
||||
unsigned char NumDiagRanges;
|
||||
|
||||
/// \brief The number of code modifications hints in the
|
||||
/// CodeModificationHints array.
|
||||
unsigned char NumCodeModificationHints;
|
||||
/// FixItHints array.
|
||||
unsigned char NumFixItHints;
|
||||
|
||||
/// DiagArgumentsKind - This is an array of ArgumentKind::ArgumentKind enum
|
||||
/// values, with one for each argument. This specifies whether the argument
|
||||
@ -62,13 +61,49 @@ class PartialDiagnostic {
|
||||
/// only support 10 ranges, could easily be extended if needed.
|
||||
SourceRange DiagRanges[10];
|
||||
|
||||
enum { MaxCodeModificationHints = 3 };
|
||||
enum { MaxFixItHints = 3 };
|
||||
|
||||
/// CodeModificationHints - If valid, provides a hint with some code
|
||||
/// FixItHints - If valid, provides a hint with some code
|
||||
/// to insert, remove, or modify at a particular position.
|
||||
CodeModificationHint CodeModificationHints[MaxCodeModificationHints];
|
||||
FixItHint FixItHints[MaxFixItHints];
|
||||
};
|
||||
|
||||
/// \brief An allocator for Storage objects, which uses a small cache to
|
||||
/// objects, used to reduce malloc()/free() traffic for partial diagnostics.
|
||||
class StorageAllocator {
|
||||
static const unsigned NumCached = 4;
|
||||
Storage Cached[NumCached];
|
||||
Storage *FreeList[NumCached];
|
||||
unsigned NumFreeListEntries;
|
||||
|
||||
public:
|
||||
StorageAllocator();
|
||||
~StorageAllocator();
|
||||
|
||||
/// \brief Allocate new storage.
|
||||
Storage *Allocate() {
|
||||
if (NumFreeListEntries == 0)
|
||||
return new Storage;
|
||||
|
||||
Storage *Result = FreeList[--NumFreeListEntries];
|
||||
Result->NumDiagArgs = 0;
|
||||
Result->NumDiagRanges = 0;
|
||||
Result->NumFixItHints = 0;
|
||||
return Result;
|
||||
}
|
||||
|
||||
/// \brief Free the given storage object.
|
||||
void Deallocate(Storage *S) {
|
||||
if (S >= Cached && S <= Cached + NumCached) {
|
||||
FreeList[NumFreeListEntries++] = S;
|
||||
return;
|
||||
}
|
||||
|
||||
delete S;
|
||||
}
|
||||
};
|
||||
|
||||
private:
|
||||
// NOTE: Sema assumes that PartialDiagnostic is location-invariant
|
||||
// in the sense that its bits can be safely memcpy'ed and destructed
|
||||
// in the new location.
|
||||
@ -76,22 +111,40 @@ class PartialDiagnostic {
|
||||
/// DiagID - The diagnostic ID.
|
||||
mutable unsigned DiagID;
|
||||
|
||||
/// DiagStorare - Storge for args and ranges.
|
||||
/// DiagStorage - Storage for args and ranges.
|
||||
mutable Storage *DiagStorage;
|
||||
|
||||
void AddTaggedVal(intptr_t V, Diagnostic::ArgumentKind Kind) const {
|
||||
if (!DiagStorage)
|
||||
DiagStorage = new Storage;
|
||||
/// \brief Allocator used to allocate storage for this diagnostic.
|
||||
StorageAllocator *Allocator;
|
||||
|
||||
/// \brief Retrieve storage for this particular diagnostic.
|
||||
Storage *getStorage() const {
|
||||
if (DiagStorage)
|
||||
return DiagStorage;
|
||||
|
||||
assert(DiagStorage->NumDiagArgs < Storage::MaxArguments &&
|
||||
"Too many arguments to diagnostic!");
|
||||
DiagStorage->DiagArgumentsKind[DiagStorage->NumDiagArgs] = Kind;
|
||||
DiagStorage->DiagArgumentsVal[DiagStorage->NumDiagArgs++] = V;
|
||||
if (Allocator)
|
||||
DiagStorage = Allocator->Allocate();
|
||||
else {
|
||||
assert(Allocator != reinterpret_cast<StorageAllocator *>(~uintptr_t(0)));
|
||||
DiagStorage = new Storage;
|
||||
}
|
||||
return DiagStorage;
|
||||
}
|
||||
|
||||
|
||||
void freeStorage() {
|
||||
if (!DiagStorage)
|
||||
return;
|
||||
|
||||
if (Allocator)
|
||||
Allocator->Deallocate(DiagStorage);
|
||||
else if (Allocator != reinterpret_cast<StorageAllocator *>(~uintptr_t(0)))
|
||||
delete DiagStorage;
|
||||
DiagStorage = 0;
|
||||
}
|
||||
|
||||
void AddSourceRange(const SourceRange &R) const {
|
||||
if (!DiagStorage)
|
||||
DiagStorage = new Storage;
|
||||
DiagStorage = getStorage();
|
||||
|
||||
assert(DiagStorage->NumDiagRanges <
|
||||
llvm::array_lengthof(DiagStorage->DiagRanges) &&
|
||||
@ -99,53 +152,70 @@ class PartialDiagnostic {
|
||||
DiagStorage->DiagRanges[DiagStorage->NumDiagRanges++] = R;
|
||||
}
|
||||
|
||||
void AddCodeModificationHint(const CodeModificationHint &Hint) const {
|
||||
void AddFixItHint(const FixItHint &Hint) const {
|
||||
if (Hint.isNull())
|
||||
return;
|
||||
|
||||
if (!DiagStorage)
|
||||
DiagStorage = new Storage;
|
||||
DiagStorage = getStorage();
|
||||
|
||||
assert(DiagStorage->NumCodeModificationHints <
|
||||
Storage::MaxCodeModificationHints &&
|
||||
assert(DiagStorage->NumFixItHints < Storage::MaxFixItHints &&
|
||||
"Too many code modification hints!");
|
||||
DiagStorage->CodeModificationHints[DiagStorage->NumCodeModificationHints++]
|
||||
DiagStorage->FixItHints[DiagStorage->NumFixItHints++]
|
||||
= Hint;
|
||||
}
|
||||
|
||||
public:
|
||||
PartialDiagnostic(unsigned DiagID)
|
||||
: DiagID(DiagID), DiagStorage(0) { }
|
||||
|
||||
PartialDiagnostic(unsigned DiagID, StorageAllocator &Allocator)
|
||||
: DiagID(DiagID), DiagStorage(0), Allocator(&Allocator) { }
|
||||
|
||||
PartialDiagnostic(const PartialDiagnostic &Other)
|
||||
: DiagID(Other.DiagID), DiagStorage(0)
|
||||
: DiagID(Other.DiagID), DiagStorage(0), Allocator(Other.Allocator)
|
||||
{
|
||||
if (Other.DiagStorage)
|
||||
DiagStorage = new Storage(*Other.DiagStorage);
|
||||
if (Other.DiagStorage) {
|
||||
DiagStorage = getStorage();
|
||||
*DiagStorage = *Other.DiagStorage;
|
||||
}
|
||||
}
|
||||
|
||||
PartialDiagnostic(const PartialDiagnostic &Other, Storage *DiagStorage)
|
||||
: DiagID(Other.DiagID), DiagStorage(DiagStorage),
|
||||
Allocator(reinterpret_cast<StorageAllocator *>(~uintptr_t(0)))
|
||||
{
|
||||
if (Other.DiagStorage)
|
||||
*this->DiagStorage = *Other.DiagStorage;
|
||||
}
|
||||
|
||||
PartialDiagnostic &operator=(const PartialDiagnostic &Other) {
|
||||
DiagID = Other.DiagID;
|
||||
if (Other.DiagStorage) {
|
||||
if (DiagStorage)
|
||||
*DiagStorage = *Other.DiagStorage;
|
||||
else
|
||||
DiagStorage = new Storage(*Other.DiagStorage);
|
||||
if (!DiagStorage)
|
||||
DiagStorage = getStorage();
|
||||
|
||||
*DiagStorage = *Other.DiagStorage;
|
||||
} else {
|
||||
delete DiagStorage;
|
||||
DiagStorage = 0;
|
||||
freeStorage();
|
||||
}
|
||||
|
||||
return *this;
|
||||
}
|
||||
|
||||
~PartialDiagnostic() {
|
||||
delete DiagStorage;
|
||||
freeStorage();
|
||||
}
|
||||
|
||||
|
||||
unsigned getDiagID() const { return DiagID; }
|
||||
|
||||
void AddTaggedVal(intptr_t V, Diagnostic::ArgumentKind Kind) const {
|
||||
if (!DiagStorage)
|
||||
DiagStorage = getStorage();
|
||||
|
||||
assert(DiagStorage->NumDiagArgs < Storage::MaxArguments &&
|
||||
"Too many arguments to diagnostic!");
|
||||
DiagStorage->DiagArgumentsKind[DiagStorage->NumDiagArgs] = Kind;
|
||||
DiagStorage->DiagArgumentsVal[DiagStorage->NumDiagArgs++] = V;
|
||||
}
|
||||
|
||||
void Emit(const DiagnosticBuilder &DB) const {
|
||||
if (!DiagStorage)
|
||||
return;
|
||||
@ -161,17 +231,19 @@ public:
|
||||
DB.AddSourceRange(DiagStorage->DiagRanges[i]);
|
||||
|
||||
// Add all code modification hints
|
||||
for (unsigned i = 0, e = DiagStorage->NumCodeModificationHints; i != e; ++i)
|
||||
DB.AddCodeModificationHint(DiagStorage->CodeModificationHints[i]);
|
||||
for (unsigned i = 0, e = DiagStorage->NumFixItHints; i != e; ++i)
|
||||
DB.AddFixItHint(DiagStorage->FixItHints[i]);
|
||||
}
|
||||
|
||||
friend const PartialDiagnostic &operator<<(const PartialDiagnostic &PD,
|
||||
QualType T) {
|
||||
PD.AddTaggedVal(reinterpret_cast<intptr_t>(T.getAsOpaquePtr()),
|
||||
Diagnostic::ak_qualtype);
|
||||
return PD;
|
||||
/// \brief Clear out this partial diagnostic, giving it a new diagnostic ID
|
||||
/// and removing all of its arguments, ranges, and fix-it hints.
|
||||
void Reset(unsigned DiagID = 0) {
|
||||
this->DiagID = DiagID;
|
||||
freeStorage();
|
||||
}
|
||||
|
||||
|
||||
bool hasStorage() const { return DiagStorage != 0; }
|
||||
|
||||
friend const PartialDiagnostic &operator<<(const PartialDiagnostic &PD,
|
||||
unsigned I) {
|
||||
PD.AddTaggedVal(I, Diagnostic::ak_uint);
|
||||
@ -197,20 +269,13 @@ public:
|
||||
}
|
||||
|
||||
friend const PartialDiagnostic &operator<<(const PartialDiagnostic &PD,
|
||||
DeclarationName N);
|
||||
|
||||
friend const PartialDiagnostic &operator<<(const PartialDiagnostic &PD,
|
||||
const CodeModificationHint &Hint) {
|
||||
PD.AddCodeModificationHint(Hint);
|
||||
const FixItHint &Hint) {
|
||||
PD.AddFixItHint(Hint);
|
||||
return PD;
|
||||
}
|
||||
|
||||
};
|
||||
|
||||
inline PartialDiagnostic PDiag(unsigned DiagID = 0) {
|
||||
return PartialDiagnostic(DiagID);
|
||||
}
|
||||
|
||||
inline const DiagnosticBuilder &operator<<(const DiagnosticBuilder &DB,
|
||||
const PartialDiagnostic &PD) {
|
||||
PD.Emit(DB);
|
||||
@ -219,4 +284,4 @@ inline const DiagnosticBuilder &operator<<(const DiagnosticBuilder &DB,
|
||||
|
||||
|
||||
} // end namespace clang
|
||||
#endif
|
||||
#endif
|
||||
|
@ -28,7 +28,6 @@ namespace llvm {
|
||||
namespace clang {
|
||||
|
||||
class SourceManager;
|
||||
class FileEntry;
|
||||
|
||||
/// FileID - This is an opaque identifier used by SourceManager which refers to
|
||||
/// a source file (MemoryBuffer) along with its #include path and #line data.
|
||||
|
@ -15,17 +15,12 @@
|
||||
#ifndef LLVM_CLANG_ANALYSIS_BUGREPORTER
|
||||
#define LLVM_CLANG_ANALYSIS_BUGREPORTER
|
||||
|
||||
#include "clang/Basic/Diagnostic.h"
|
||||
#include "clang/Basic/SourceLocation.h"
|
||||
#include "clang/Checker/BugReporter/BugType.h"
|
||||
#include "clang/Checker/PathSensitive/ExplodedGraph.h"
|
||||
#include "clang/Checker/PathSensitive/GRState.h"
|
||||
#include "llvm/ADT/FoldingSet.h"
|
||||
#include "llvm/ADT/ImmutableList.h"
|
||||
#include "llvm/ADT/ImmutableSet.h"
|
||||
#include "llvm/ADT/SmallPtrSet.h"
|
||||
#include "llvm/ADT/SmallSet.h"
|
||||
#include "llvm/ADT/SmallString.h"
|
||||
#include <list>
|
||||
|
||||
namespace clang {
|
||||
@ -35,6 +30,8 @@ class PathDiagnosticPiece;
|
||||
class PathDiagnosticClient;
|
||||
class ASTContext;
|
||||
class Diagnostic;
|
||||
class ExplodedNode;
|
||||
class ExplodedGraph;
|
||||
class BugReporter;
|
||||
class BugReporterContext;
|
||||
class GRExprEngine;
|
||||
|
@ -14,15 +14,12 @@
|
||||
#ifndef LLVM_CLANG_ANALYSIS_BUGTYPE
|
||||
#define LLVM_CLANG_ANALYSIS_BUGTYPE
|
||||
|
||||
#include <llvm/ADT/FoldingSet.h>
|
||||
#include "clang/Checker/BugReporter/BugReporter.h"
|
||||
#include "llvm/ADT/FoldingSet.h"
|
||||
#include <string>
|
||||
|
||||
namespace clang {
|
||||
|
||||
class BugReportEquivClass;
|
||||
class BugReporter;
|
||||
class BuiltinBugReport;
|
||||
class BugReporterContext;
|
||||
class ExplodedNode;
|
||||
class GRExprEngine;
|
||||
|
||||
|
@ -168,7 +168,7 @@ public:
|
||||
|
||||
private:
|
||||
const std::string str;
|
||||
std::vector<CodeModificationHint> CodeModificationHints;
|
||||
std::vector<FixItHint> FixItHints;
|
||||
const Kind kind;
|
||||
const DisplayHint Hint;
|
||||
std::vector<SourceRange> ranges;
|
||||
@ -203,8 +203,8 @@ public:
|
||||
ranges.push_back(SourceRange(B,E));
|
||||
}
|
||||
|
||||
void addCodeModificationHint(const CodeModificationHint& Hint) {
|
||||
CodeModificationHints.push_back(Hint);
|
||||
void addFixItHint(const FixItHint& Hint) {
|
||||
FixItHints.push_back(Hint);
|
||||
}
|
||||
|
||||
typedef const SourceRange* range_iterator;
|
||||
@ -217,15 +217,15 @@ public:
|
||||
return ranges_begin() + ranges.size();
|
||||
}
|
||||
|
||||
typedef const CodeModificationHint *code_modifications_iterator;
|
||||
typedef const FixItHint *fixit_iterator;
|
||||
|
||||
code_modifications_iterator code_modifications_begin() const {
|
||||
return CodeModificationHints.empty()? 0 : &CodeModificationHints[0];
|
||||
fixit_iterator fixit_begin() const {
|
||||
return FixItHints.empty()? 0 : &FixItHints[0];
|
||||
}
|
||||
|
||||
code_modifications_iterator code_modifications_end() const {
|
||||
return CodeModificationHints.empty()? 0
|
||||
: &CodeModificationHints[0] + CodeModificationHints.size();
|
||||
fixit_iterator fixit_end() const {
|
||||
return FixItHints.empty()? 0
|
||||
: &FixItHints[0] + FixItHints.size();
|
||||
}
|
||||
|
||||
static inline bool classof(const PathDiagnosticPiece* P) {
|
||||
|
@ -14,7 +14,6 @@
|
||||
#ifndef LLVM_CLANG_CHECKER_DS_COCOA
|
||||
#define LLVM_CLANG_CHECKER_DS_COCOA
|
||||
|
||||
#include "clang/Basic/IdentifierTable.h"
|
||||
#include "clang/AST/Type.h"
|
||||
|
||||
namespace clang {
|
||||
|
@ -16,7 +16,6 @@
|
||||
#ifndef LLVM_CLANG_ANALYSIS_BASICVALUEFACTORY_H
|
||||
#define LLVM_CLANG_ANALYSIS_BASICVALUEFACTORY_H
|
||||
|
||||
#include "clang/Checker/PathSensitive/SymbolManager.h"
|
||||
#include "clang/Checker/PathSensitive/SVals.h"
|
||||
#include "clang/AST/ASTContext.h"
|
||||
#include "llvm/ADT/FoldingSet.h"
|
||||
|
@ -14,21 +14,15 @@
|
||||
|
||||
#ifndef LLVM_CLANG_ANALYSIS_CHECKER
|
||||
#define LLVM_CLANG_ANALYSIS_CHECKER
|
||||
|
||||
#include "clang/Analysis/Support/SaveAndRestore.h"
|
||||
#include "clang/Checker/PathSensitive/GRCoreEngine.h"
|
||||
#include "clang/Checker/PathSensitive/GRState.h"
|
||||
#include "clang/Checker/PathSensitive/GRExprEngine.h"
|
||||
#include "clang/AST/ExprCXX.h"
|
||||
#include "clang/AST/ExprObjC.h"
|
||||
#include "clang/AST/StmtCXX.h"
|
||||
#include "clang/AST/StmtObjC.h"
|
||||
|
||||
//===----------------------------------------------------------------------===//
|
||||
// Checker interface.
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
namespace clang {
|
||||
class GRExprEngine;
|
||||
|
||||
class CheckerContext {
|
||||
ExplodedNodeSet &Dst;
|
||||
|
@ -18,11 +18,8 @@
|
||||
// typedefs.
|
||||
#include "clang/Checker/PathSensitive/Store.h"
|
||||
|
||||
#include "llvm/ADT/ImmutableMap.h"
|
||||
#include "llvm/ADT/SmallVector.h"
|
||||
#include "clang/Checker/PathSensitive/SVals.h"
|
||||
#include "llvm/Support/Allocator.h"
|
||||
#include "llvm/ADT/FoldingSet.h"
|
||||
#include "llvm/ADT/ImmutableMap.h"
|
||||
|
||||
namespace clang {
|
||||
|
||||
|
@ -9,6 +9,10 @@
|
||||
//
|
||||
// This file defines the template classes ExplodedNode and ExplodedGraph,
|
||||
// which represent a path-sensitive, intra-procedural "exploded graph."
|
||||
// See "Precise interprocedural dataflow analysis via graph reachability"
|
||||
// by Reps, Horwitz, and Sagiv
|
||||
// (http://portal.acm.org/citation.cfm?id=199462) for the definition of an
|
||||
// exploded graph.
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
|
@ -22,6 +22,8 @@ namespace llvm {
|
||||
|
||||
namespace clang {
|
||||
|
||||
class StackFrameContext;
|
||||
|
||||
class GRBlockCounter {
|
||||
void* Data;
|
||||
|
||||
@ -30,7 +32,8 @@ class GRBlockCounter {
|
||||
public:
|
||||
GRBlockCounter() : Data(0) {}
|
||||
|
||||
unsigned getNumVisited(unsigned BlockID) const;
|
||||
unsigned getNumVisited(const StackFrameContext *CallSite,
|
||||
unsigned BlockID) const;
|
||||
|
||||
class Factory {
|
||||
void* F;
|
||||
@ -39,7 +42,9 @@ public:
|
||||
~Factory();
|
||||
|
||||
GRBlockCounter GetEmptyCounter();
|
||||
GRBlockCounter IncrementCount(GRBlockCounter BC, unsigned BlockID);
|
||||
GRBlockCounter IncrementCount(GRBlockCounter BC,
|
||||
const StackFrameContext *CallSite,
|
||||
unsigned BlockID);
|
||||
};
|
||||
|
||||
friend class Factory;
|
||||
|
@ -82,7 +82,7 @@ class GRCoreEngine {
|
||||
|
||||
void ProcessStmt(CFGElement E, GRStmtNodeBuilder& Builder);
|
||||
|
||||
bool ProcessBlockEntrance(CFGBlock* Blk, const GRState* State,
|
||||
bool ProcessBlockEntrance(CFGBlock* Blk, const ExplodedNode *Pred,
|
||||
GRBlockCounter BC);
|
||||
|
||||
|
||||
@ -174,7 +174,9 @@ public:
|
||||
GRBlockCounter getBlockCounter() const { return Eng.WList->getBlockCounter();}
|
||||
|
||||
unsigned getCurrentBlockCount() const {
|
||||
return getBlockCounter().getNumVisited(B.getBlockID());
|
||||
return getBlockCounter().getNumVisited(
|
||||
Pred->getLocationContext()->getCurrentStackFrame(),
|
||||
B.getBlockID());
|
||||
}
|
||||
|
||||
ExplodedNode* generateNode(PostStmt PP,const GRState* St,ExplodedNode* Pred) {
|
||||
@ -434,7 +436,9 @@ public:
|
||||
}
|
||||
|
||||
unsigned getCurrentBlockCount() const {
|
||||
return getBlockCounter().getNumVisited(B.getBlockID());
|
||||
return getBlockCounter().getNumVisited(
|
||||
Pred->getLocationContext()->getCurrentStackFrame(),
|
||||
B.getBlockID());
|
||||
}
|
||||
|
||||
ExplodedNode* generateNode(const GRState* State, const void *tag = 0,
|
||||
|
@ -16,7 +16,6 @@
|
||||
#ifndef LLVM_CLANG_ANALYSIS_GREXPRENGINE
|
||||
#define LLVM_CLANG_ANALYSIS_GREXPRENGINE
|
||||
|
||||
#include "clang/Checker/PathSensitive/AnalysisManager.h"
|
||||
#include "clang/Checker/PathSensitive/GRSubEngine.h"
|
||||
#include "clang/Checker/PathSensitive/GRCoreEngine.h"
|
||||
#include "clang/Checker/PathSensitive/GRState.h"
|
||||
@ -28,11 +27,9 @@
|
||||
#include "clang/AST/ExprCXX.h"
|
||||
|
||||
namespace clang {
|
||||
|
||||
class PathDiagnosticClient;
|
||||
class Diagnostic;
|
||||
class ObjCForCollectionStmt;
|
||||
class Checker;
|
||||
class AnalysisManager;
|
||||
class Checker;
|
||||
class ObjCForCollectionStmt;
|
||||
|
||||
class GRExprEngine : public GRSubEngine {
|
||||
AnalysisManager &AMgr;
|
||||
@ -153,7 +150,7 @@ public:
|
||||
/// ProcessBlockEntrance - Called by GRCoreEngine when start processing
|
||||
/// a CFGBlock. This method returns true if the analysis should continue
|
||||
/// exploring the given path, and false otherwise.
|
||||
bool ProcessBlockEntrance(CFGBlock* B, const GRState* St,
|
||||
bool ProcessBlockEntrance(CFGBlock* B, const ExplodedNode *Pred,
|
||||
GRBlockCounter BC);
|
||||
|
||||
/// ProcessBranch - Called by GRCoreEngine. Used to generate successor
|
||||
@ -216,7 +213,7 @@ public:
|
||||
const GRState* St,
|
||||
ProgramPoint::Kind K = ProgramPoint::PostStmtKind,
|
||||
const void *tag = 0);
|
||||
protected:
|
||||
|
||||
/// CheckerVisit - Dispatcher for performing checker-specific logic
|
||||
/// at specific statements.
|
||||
void CheckerVisit(Stmt *S, ExplodedNodeSet &Dst, ExplodedNodeSet &Src,
|
||||
@ -351,10 +348,21 @@ protected:
|
||||
void VisitCXXConstructExpr(const CXXConstructExpr *E, SVal Dest,
|
||||
ExplodedNode *Pred,
|
||||
ExplodedNodeSet &Dst);
|
||||
|
||||
void VisitCXXMemberCallExpr(const CXXMemberCallExpr *MCE, ExplodedNode *Pred,
|
||||
ExplodedNodeSet &Dst);
|
||||
|
||||
void VisitAggExpr(const Expr *E, SVal Dest, ExplodedNode *Pred,
|
||||
ExplodedNodeSet &Dst);
|
||||
|
||||
/// Create a C++ temporary object for an rvalue.
|
||||
void CreateCXXTemporaryObject(Expr *Ex, ExplodedNode *Pred,
|
||||
ExplodedNodeSet &Dst);
|
||||
|
||||
/// Synthesize CXXThisRegion.
|
||||
const CXXThisRegion *getCXXThisRegion(const CXXMethodDecl *MD,
|
||||
const StackFrameContext *SFC);
|
||||
|
||||
/// EvalEagerlyAssume - Given the nodes in 'Src', eagerly assume symbolic
|
||||
/// expressions of the form 'x != 0' and generate new nodes (stored in Dst)
|
||||
/// with those assumptions.
|
||||
|
@ -17,18 +17,9 @@
|
||||
#define LLVM_CLANG_ANALYSIS_GRAPICHECKS
|
||||
|
||||
#include "clang/Checker/PathSensitive/GRAuditor.h"
|
||||
#include "clang/Checker/PathSensitive/GRState.h"
|
||||
|
||||
namespace clang {
|
||||
|
||||
class Diagnostic;
|
||||
class BugReporter;
|
||||
class ASTContext;
|
||||
class GRExprEngine;
|
||||
class PathDiagnosticClient;
|
||||
class ExplodedGraph;
|
||||
|
||||
|
||||
class GRSimpleAPICheck : public GRAuditor {
|
||||
public:
|
||||
GRSimpleAPICheck() {}
|
||||
|
@ -14,30 +14,22 @@
|
||||
#ifndef LLVM_CLANG_ANALYSIS_VALUESTATE_H
|
||||
#define LLVM_CLANG_ANALYSIS_VALUESTATE_H
|
||||
|
||||
// FIXME: Reduce the number of includes.
|
||||
|
||||
#include "clang/AST/ASTContext.h"
|
||||
#include "clang/AST/Decl.h"
|
||||
#include "clang/AST/Expr.h"
|
||||
#include "clang/Analysis/Analyses/LiveVariables.h"
|
||||
#include "clang/Checker/PathSensitive/ConstraintManager.h"
|
||||
#include "clang/Checker/PathSensitive/Environment.h"
|
||||
#include "clang/Checker/PathSensitive/GRCoreEngine.h"
|
||||
#include "clang/Checker/PathSensitive/Store.h"
|
||||
#include "clang/Checker/PathSensitive/ValueManager.h"
|
||||
#include "llvm/ADT/APSInt.h"
|
||||
#include "llvm/ADT/DenseSet.h"
|
||||
#include "llvm/ADT/FoldingSet.h"
|
||||
#include "llvm/ADT/ImmutableMap.h"
|
||||
#include "llvm/ADT/SmallVector.h"
|
||||
#include "llvm/Support/Allocator.h"
|
||||
#include "llvm/Support/Casting.h"
|
||||
#include "llvm/Support/raw_ostream.h"
|
||||
#include "llvm/System/DataTypes.h"
|
||||
#include <functional>
|
||||
|
||||
namespace llvm {
|
||||
class APSInt;
|
||||
class BumpPtrAllocator;
|
||||
class raw_ostream;
|
||||
}
|
||||
|
||||
namespace clang {
|
||||
|
||||
class ASTContext;
|
||||
class GRStateManager;
|
||||
class Checker;
|
||||
|
||||
@ -302,6 +294,8 @@ public:
|
||||
template<typename T>
|
||||
const GRState *remove(typename GRStateTrait<T>::key_type K,
|
||||
typename GRStateTrait<T>::context_type C) const;
|
||||
template <typename T>
|
||||
const GRState *remove() const;
|
||||
|
||||
template<typename T>
|
||||
const GRState *set(typename GRStateTrait<T>::data_type D) const;
|
||||
@ -464,6 +458,7 @@ public:
|
||||
|
||||
// Methods that manipulate the GDM.
|
||||
const GRState* addGDM(const GRState* St, void* Key, void* Data);
|
||||
const GRState *removeGDM(const GRState *state, void *Key);
|
||||
|
||||
// Methods that query & manipulate the Store.
|
||||
|
||||
@ -528,6 +523,10 @@ public:
|
||||
GRStateTrait<T>::MakeVoidPtr(GRStateTrait<T>::Remove(st->get<T>(), K, C)));
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
const GRState *remove(const GRState *st) {
|
||||
return removeGDM(st, GRStateTrait<T>::GDMIndex());
|
||||
}
|
||||
|
||||
void* FindGDMContext(void* index,
|
||||
void* (*CreateContext)(llvm::BumpPtrAllocator&),
|
||||
@ -702,6 +701,11 @@ const GRState *GRState::remove(typename GRStateTrait<T>::key_type K,
|
||||
return getStateManager().remove<T>(this, K, C);
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
const GRState *GRState::remove() const {
|
||||
return getStateManager().remove<T>(this);
|
||||
}
|
||||
|
||||
template<typename T>
|
||||
const GRState *GRState::set(typename GRStateTrait<T>::data_type D) const {
|
||||
return getStateManager().set<T>(this, D);
|
||||
|
@ -20,6 +20,7 @@ namespace clang {
|
||||
class Stmt;
|
||||
class CFGBlock;
|
||||
class CFGElement;
|
||||
class ExplodedNode;
|
||||
class GRState;
|
||||
class GRStateManager;
|
||||
class GRBlockCounter;
|
||||
@ -47,7 +48,7 @@ public:
|
||||
/// ProcessBlockEntrance - Called by GRCoreEngine when start processing
|
||||
/// a CFGBlock. This method returns true if the analysis should continue
|
||||
/// exploring the given path, and false otherwise.
|
||||
virtual bool ProcessBlockEntrance(CFGBlock* B, const GRState* St,
|
||||
virtual bool ProcessBlockEntrance(CFGBlock* B, const ExplodedNode *Pred,
|
||||
GRBlockCounter BC) = 0;
|
||||
|
||||
/// ProcessBranch - Called by GRCoreEngine. Used to generate successor
|
||||
|
@ -15,16 +15,18 @@
|
||||
#ifndef LLVM_CLANG_ANALYSIS_GRTF
|
||||
#define LLVM_CLANG_ANALYSIS_GRTF
|
||||
|
||||
#include "clang/Checker/PathSensitive/SVals.h"
|
||||
#include "clang/Checker/PathSensitive/GRCoreEngine.h"
|
||||
#include "clang/Checker/PathSensitive/GRState.h"
|
||||
#include "clang/Checker/PathSensitive/SVals.h"
|
||||
#include <vector>
|
||||
|
||||
namespace clang {
|
||||
|
||||
class ExplodedNode;
|
||||
class ExplodedNodeSet;
|
||||
class GREndPathNodeBuilder;
|
||||
class GRExprEngine;
|
||||
class ObjCMessageExpr;
|
||||
class GRStmtNodeBuilder;
|
||||
class GRStmtNodeBuilderRef;
|
||||
class ObjCMessageExpr;
|
||||
|
||||
class GRTransferFuncs {
|
||||
public:
|
||||
|
@ -18,17 +18,15 @@
|
||||
|
||||
#include "clang/AST/Decl.h"
|
||||
#include "clang/AST/DeclObjC.h"
|
||||
#include "clang/Checker/PathSensitive/SymbolManager.h"
|
||||
#include "clang/Checker/PathSensitive/SVals.h"
|
||||
#include "clang/AST/ASTContext.h"
|
||||
#include "llvm/Support/Casting.h"
|
||||
#include "llvm/ADT/FoldingSet.h"
|
||||
#include "llvm/ADT/ImmutableList.h"
|
||||
#include "llvm/ADT/ImmutableMap.h"
|
||||
#include "llvm/Support/Allocator.h"
|
||||
#include <string>
|
||||
|
||||
namespace llvm { class raw_ostream; }
|
||||
namespace llvm {
|
||||
class BumpPtrAllocator;
|
||||
class raw_ostream;
|
||||
}
|
||||
|
||||
namespace clang {
|
||||
|
||||
|
@ -18,9 +18,6 @@
|
||||
#include "clang/Checker/PathSensitive/SVals.h"
|
||||
#include "clang/Checker/PathSensitive/ValueManager.h"
|
||||
#include "llvm/ADT/DenseSet.h"
|
||||
#include "llvm/ADT/SmallPtrSet.h"
|
||||
#include "llvm/ADT/SmallSet.h"
|
||||
#include "llvm/ADT/SmallVector.h"
|
||||
|
||||
namespace clang {
|
||||
|
||||
|
@ -17,14 +17,14 @@
|
||||
|
||||
#include "clang/AST/Decl.h"
|
||||
#include "clang/AST/Expr.h"
|
||||
#include "clang/Analysis/Analyses/LiveVariables.h"
|
||||
#include "clang/Analysis/AnalysisContext.h"
|
||||
#include "llvm/System/DataTypes.h"
|
||||
#include "llvm/Support/Allocator.h"
|
||||
#include "llvm/ADT/FoldingSet.h"
|
||||
#include "llvm/ADT/DenseSet.h"
|
||||
|
||||
namespace llvm {
|
||||
class raw_ostream;
|
||||
class BumpPtrAllocator;
|
||||
class raw_ostream;
|
||||
}
|
||||
|
||||
namespace clang {
|
||||
@ -34,9 +34,6 @@ namespace clang {
|
||||
class TypedRegion;
|
||||
class VarRegion;
|
||||
class StackFrameContext;
|
||||
}
|
||||
|
||||
namespace clang {
|
||||
|
||||
class SymExpr : public llvm::FoldingSetNode {
|
||||
public:
|
||||
@ -247,6 +244,7 @@ public:
|
||||
QualType t)
|
||||
: SymExpr(SymSymKind), LHS(lhs), Op(op), RHS(rhs), T(t) {}
|
||||
|
||||
BinaryOperator::Opcode getOpcode() const { return Op; }
|
||||
const SymExpr *getLHS() const { return LHS; }
|
||||
const SymExpr *getRHS() const { return RHS; }
|
||||
|
||||
|
@ -15,7 +15,6 @@
|
||||
#define LLVM_CLANG_CODEGEN_CODEGENOPTIONS_H
|
||||
|
||||
#include <string>
|
||||
#include <vector>
|
||||
|
||||
namespace clang {
|
||||
|
||||
|
@ -156,6 +156,7 @@ def dependency_file : Separate<"-dependency-file">,
|
||||
HelpText<"Filename (or -) to write dependency output to">;
|
||||
def sys_header_deps : Flag<"-sys-header-deps">,
|
||||
HelpText<"Include system headers in dependency output">;
|
||||
def MQ : Separate<"-MQ">, HelpText<"Specify target to quote for dependency">;
|
||||
def MT : Separate<"-MT">, HelpText<"Specify target for dependency">;
|
||||
def MP : Flag<"-MP">,
|
||||
HelpText<"Create phony target for each dependency (other than main file)">;
|
||||
@ -407,6 +408,8 @@ def fwritable_strings : Flag<"-fwritable-strings">,
|
||||
|
||||
def nostdinc : Flag<"-nostdinc">,
|
||||
HelpText<"Disable standard #include directories">;
|
||||
def nostdincxx : Flag<"-nostdinc++">,
|
||||
HelpText<"Disable standard #include directories for the C++ standard library">;
|
||||
def nobuiltininc : Flag<"-nobuiltininc">,
|
||||
HelpText<"Disable builtin #include directories">;
|
||||
def F : JoinedOrSeparate<"-F">, MetaVarName<"<directory>">,
|
||||
|
@ -2,10 +2,10 @@ set(LLVM_TARGET_DEFINITIONS Options.td)
|
||||
tablegen(Options.inc
|
||||
-gen-opt-parser-defs)
|
||||
add_custom_target(ClangDriverOptions
|
||||
DEPENDS ${CMAKE_CURRENT_BINARY_DIR}/Options.inc)
|
||||
DEPENDS Options.inc)
|
||||
|
||||
set(LLVM_TARGET_DEFINITIONS CC1Options.td)
|
||||
tablegen(CC1Options.inc
|
||||
-gen-opt-parser-defs)
|
||||
add_custom_target(ClangCC1Options
|
||||
DEPENDS ${CMAKE_CURRENT_BINARY_DIR}/CC1Options.inc)
|
||||
DEPENDS CC1Options.inc)
|
||||
|
@ -64,6 +64,12 @@ public:
|
||||
/// The path to the compiler resource directory.
|
||||
std::string ResourceDir;
|
||||
|
||||
/// A prefix directory used to emulated a limited subset of GCC's '-Bprefix'
|
||||
/// functionality.
|
||||
/// FIXME: This type of customization should be removed in favor of the
|
||||
/// universal driver when it is ready.
|
||||
std::string PrefixDir;
|
||||
|
||||
/// Default host triple.
|
||||
std::string DefaultHostTriple;
|
||||
|
||||
@ -133,7 +139,8 @@ public:
|
||||
Driver(llvm::StringRef _Name, llvm::StringRef _Dir,
|
||||
llvm::StringRef _DefaultHostTriple,
|
||||
llvm::StringRef _DefaultImageName,
|
||||
bool IsProduction, Diagnostic &_Diags);
|
||||
bool IsProduction, bool CXXIsProduction,
|
||||
Diagnostic &_Diags);
|
||||
~Driver();
|
||||
|
||||
/// @name Accessors
|
||||
|
@ -118,7 +118,7 @@ def ccc_ : Joined<"-ccc-">, Group<ccc_Group>, Flags<[Unsupported]>;
|
||||
def _HASH_HASH_HASH : Flag<"-###">, Flags<[DriverOption]>,
|
||||
HelpText<"Print the commands to run for this compilation">;
|
||||
def A : JoinedOrSeparate<"-A">;
|
||||
def B : JoinedOrSeparate<"-B">, Flags<[Unsupported]>;
|
||||
def B : JoinedOrSeparate<"-B">;
|
||||
def CC : Flag<"-CC">;
|
||||
def C : Flag<"-C">;
|
||||
def D : JoinedOrSeparate<"-D">, Group<CompileOnly_Group>;
|
||||
@ -470,6 +470,7 @@ def noprebind : Flag<"-noprebind">;
|
||||
def noseglinkedit : Flag<"-noseglinkedit">;
|
||||
def nostartfiles : Flag<"-nostartfiles">;
|
||||
def nostdinc : Flag<"-nostdinc">;
|
||||
def nostdincxx : Flag<"-nostdinc++">;
|
||||
def nostdlib : Flag<"-nostdlib">;
|
||||
def object : Flag<"-object">;
|
||||
def o : JoinedOrSeparate<"-o">, Flags<[DriverOption, RenderAsInput]>,
|
||||
|
@ -71,13 +71,17 @@ public:
|
||||
/// Include the system standard include search directories.
|
||||
unsigned UseStandardIncludes : 1;
|
||||
|
||||
/// Include the system standard C++ library include search directories.
|
||||
unsigned UseStandardCXXIncludes : 1;
|
||||
|
||||
/// Whether header search information should be output as for -v.
|
||||
unsigned Verbose : 1;
|
||||
|
||||
public:
|
||||
HeaderSearchOptions(llvm::StringRef _Sysroot = "/")
|
||||
: Sysroot(_Sysroot), UseBuiltinIncludes(true),
|
||||
UseStandardIncludes(true), Verbose(false) {}
|
||||
UseStandardIncludes(true), UseStandardCXXIncludes(true),
|
||||
Verbose(false) {}
|
||||
|
||||
/// AddPath - Add the \arg Path path to the specified \arg Group list.
|
||||
void AddPath(llvm::StringRef Path, frontend::IncludeDirGroup Group,
|
||||
|
@ -69,7 +69,7 @@ public:
|
||||
void EmitCaretDiagnostic(SourceLocation Loc,
|
||||
SourceRange *Ranges, unsigned NumRanges,
|
||||
SourceManager &SM,
|
||||
const CodeModificationHint *Hints,
|
||||
const FixItHint *Hints,
|
||||
unsigned NumHints,
|
||||
unsigned Columns);
|
||||
|
||||
|
@ -233,7 +233,7 @@ NODE_XML(QualifiedNameType, "QualifiedNameType")
|
||||
TYPE_ATTRIBUTE_XML(getNamedType())
|
||||
END_NODE_XML
|
||||
|
||||
NODE_XML(TypenameType, "TypenameType")
|
||||
NODE_XML(DependentNameType, "DependentNameType")
|
||||
ID_ATTRIBUTE_XML
|
||||
END_NODE_XML
|
||||
|
||||
|
@ -44,6 +44,12 @@ public:
|
||||
SrcMgr::CharacteristicKind FileType) {
|
||||
}
|
||||
|
||||
|
||||
/// EndOfMainFile - This callback is invoked when the end of the main file is
|
||||
/// reach, no subsequent callbacks will be made.
|
||||
virtual void EndOfMainFile() {
|
||||
}
|
||||
|
||||
/// Ident - This callback is invoked when a #ident or #sccs directive is read.
|
||||
///
|
||||
virtual void Ident(SourceLocation Loc, const std::string &str) {
|
||||
@ -90,6 +96,11 @@ public:
|
||||
Second->FileChanged(Loc, Reason, FileType);
|
||||
}
|
||||
|
||||
virtual void EndOfMainFile() {
|
||||
First->EndOfMainFile();
|
||||
Second->EndOfMainFile();
|
||||
}
|
||||
|
||||
virtual void Ident(SourceLocation Loc, const std::string &str) {
|
||||
First->Ident(Loc, str);
|
||||
Second->Ident(Loc, str);
|
||||
|
@ -368,6 +368,10 @@ public:
|
||||
/// which implicitly adds the builtin defines etc.
|
||||
bool EnterMainSourceFile();
|
||||
|
||||
/// EndSourceFile - Inform the preprocessor callbacks that processing is
|
||||
/// complete.
|
||||
void EndSourceFile();
|
||||
|
||||
/// EnterSourceFile - Add a source file to the top of the include stack and
|
||||
/// start lexing tokens from it instead of the current buffer. Return true
|
||||
/// and fill in ErrorStr with the error information on failure.
|
||||
|
@ -21,6 +21,7 @@
|
||||
|
||||
namespace clang {
|
||||
|
||||
class FileEntry;
|
||||
class Preprocessor;
|
||||
|
||||
class PreprocessorLexer {
|
||||
|
@ -1761,7 +1761,8 @@ public:
|
||||
virtual void ActOnFinishCXXMemberSpecification(Scope* S, SourceLocation RLoc,
|
||||
DeclPtrTy TagDecl,
|
||||
SourceLocation LBrac,
|
||||
SourceLocation RBrac) {
|
||||
SourceLocation RBrac,
|
||||
AttributeList *AttrList) {
|
||||
}
|
||||
|
||||
//===---------------------------C++ Templates----------------------------===//
|
||||
|
@ -45,7 +45,8 @@ ASTContext::ASTContext(const LangOptions& LOpts, SourceManager &SM,
|
||||
sigjmp_bufDecl(0), BlockDescriptorType(0), BlockDescriptorExtendedType(0),
|
||||
SourceMgr(SM), LangOpts(LOpts), FreeMemory(FreeMem), Target(t),
|
||||
Idents(idents), Selectors(sels),
|
||||
BuiltinInfo(builtins), ExternalSource(0), PrintingPolicy(LOpts) {
|
||||
BuiltinInfo(builtins), ExternalSource(0), PrintingPolicy(LOpts),
|
||||
LastSDM(0, 0) {
|
||||
ObjCIdRedefinitionType = QualType();
|
||||
ObjCClassRedefinitionType = QualType();
|
||||
ObjCSelRedefinitionType = QualType();
|
||||
@ -858,34 +859,22 @@ void ASTContext::CollectInheritedProtocols(const Decl *CDecl,
|
||||
}
|
||||
}
|
||||
|
||||
unsigned ASTContext::CountProtocolSynthesizedIvars(const ObjCProtocolDecl *PD) {
|
||||
unsigned count = 0;
|
||||
for (ObjCContainerDecl::prop_iterator I = PD->prop_begin(),
|
||||
E = PD->prop_end(); I != E; ++I)
|
||||
if ((*I)->getPropertyIvarDecl())
|
||||
unsigned ASTContext::CountNonClassIvars(const ObjCInterfaceDecl *OI) {
|
||||
unsigned count = 0;
|
||||
// Count ivars declared in class extension.
|
||||
if (const ObjCCategoryDecl *CDecl = OI->getClassExtension()) {
|
||||
for (ObjCCategoryDecl::ivar_iterator I = CDecl->ivar_begin(),
|
||||
E = CDecl->ivar_end(); I != E; ++I) {
|
||||
++count;
|
||||
|
||||
// Also look into nested protocols.
|
||||
for (ObjCProtocolDecl::protocol_iterator P = PD->protocol_begin(),
|
||||
E = PD->protocol_end(); P != E; ++P)
|
||||
count += CountProtocolSynthesizedIvars(*P);
|
||||
return count;
|
||||
}
|
||||
|
||||
unsigned ASTContext::CountSynthesizedIvars(const ObjCInterfaceDecl *OI) {
|
||||
unsigned count = 0;
|
||||
for (ObjCInterfaceDecl::prop_iterator I = OI->prop_begin(),
|
||||
E = OI->prop_end(); I != E; ++I) {
|
||||
if ((*I)->getPropertyIvarDecl())
|
||||
}
|
||||
}
|
||||
|
||||
// Count ivar defined in this class's implementation. This
|
||||
// includes synthesized ivars.
|
||||
if (ObjCImplementationDecl *ImplDecl = OI->getImplementation())
|
||||
for (ObjCImplementationDecl::ivar_iterator I = ImplDecl->ivar_begin(),
|
||||
E = ImplDecl->ivar_end(); I != E; ++I)
|
||||
++count;
|
||||
}
|
||||
// Also look into interface's protocol list for properties declared
|
||||
// in the protocol and whose ivars are synthesized.
|
||||
for (ObjCInterfaceDecl::protocol_iterator P = OI->protocol_begin(),
|
||||
PE = OI->protocol_end(); P != PE; ++P) {
|
||||
ObjCProtocolDecl *PD = (*P);
|
||||
count += CountProtocolSynthesizedIvars(PD);
|
||||
}
|
||||
return count;
|
||||
}
|
||||
|
||||
@ -966,7 +955,7 @@ ASTContext::getObjCLayout(const ObjCInterfaceDecl *D,
|
||||
|
||||
// Add in synthesized ivar count if laying out an implementation.
|
||||
if (Impl) {
|
||||
unsigned SynthCount = CountSynthesizedIvars(D);
|
||||
unsigned SynthCount = CountNonClassIvars(D);
|
||||
// If there aren't any sythesized ivars then reuse the interface
|
||||
// entry. Note we can't cache this because we simply free all
|
||||
// entries later; however we shouldn't look up implementations
|
||||
@ -1108,14 +1097,12 @@ QualType ASTContext::getObjCGCQualType(QualType T,
|
||||
return getExtQualType(TypeNode, Quals);
|
||||
}
|
||||
|
||||
static QualType getNoReturnCallConvType(ASTContext& Context, QualType T,
|
||||
bool AddNoReturn,
|
||||
CallingConv CallConv) {
|
||||
static QualType getExtFunctionType(ASTContext& Context, QualType T,
|
||||
const FunctionType::ExtInfo &Info) {
|
||||
QualType ResultType;
|
||||
if (const PointerType *Pointer = T->getAs<PointerType>()) {
|
||||
QualType Pointee = Pointer->getPointeeType();
|
||||
ResultType = getNoReturnCallConvType(Context, Pointee, AddNoReturn,
|
||||
CallConv);
|
||||
ResultType = getExtFunctionType(Context, Pointee, Info);
|
||||
if (ResultType == Pointee)
|
||||
return T;
|
||||
|
||||
@ -1123,19 +1110,18 @@ static QualType getNoReturnCallConvType(ASTContext& Context, QualType T,
|
||||
} else if (const BlockPointerType *BlockPointer
|
||||
= T->getAs<BlockPointerType>()) {
|
||||
QualType Pointee = BlockPointer->getPointeeType();
|
||||
ResultType = getNoReturnCallConvType(Context, Pointee, AddNoReturn,
|
||||
CallConv);
|
||||
ResultType = getExtFunctionType(Context, Pointee, Info);
|
||||
if (ResultType == Pointee)
|
||||
return T;
|
||||
|
||||
ResultType = Context.getBlockPointerType(ResultType);
|
||||
} else if (const FunctionType *F = T->getAs<FunctionType>()) {
|
||||
if (F->getNoReturnAttr() == AddNoReturn && F->getCallConv() == CallConv)
|
||||
if (F->getExtInfo() == Info)
|
||||
return T;
|
||||
|
||||
if (const FunctionNoProtoType *FNPT = dyn_cast<FunctionNoProtoType>(F)) {
|
||||
ResultType = Context.getFunctionNoProtoType(FNPT->getResultType(),
|
||||
AddNoReturn, CallConv);
|
||||
Info);
|
||||
} else {
|
||||
const FunctionProtoType *FPT = cast<FunctionProtoType>(F);
|
||||
ResultType
|
||||
@ -1146,7 +1132,7 @@ static QualType getNoReturnCallConvType(ASTContext& Context, QualType T,
|
||||
FPT->hasAnyExceptionSpec(),
|
||||
FPT->getNumExceptions(),
|
||||
FPT->exception_begin(),
|
||||
AddNoReturn, CallConv);
|
||||
Info);
|
||||
}
|
||||
} else
|
||||
return T;
|
||||
@ -1155,11 +1141,21 @@ static QualType getNoReturnCallConvType(ASTContext& Context, QualType T,
|
||||
}
|
||||
|
||||
QualType ASTContext::getNoReturnType(QualType T, bool AddNoReturn) {
|
||||
return getNoReturnCallConvType(*this, T, AddNoReturn, T.getCallConv());
|
||||
FunctionType::ExtInfo Info = getFunctionExtInfo(T);
|
||||
return getExtFunctionType(*this, T,
|
||||
Info.withNoReturn(AddNoReturn));
|
||||
}
|
||||
|
||||
QualType ASTContext::getCallConvType(QualType T, CallingConv CallConv) {
|
||||
return getNoReturnCallConvType(*this, T, T.getNoReturnAttr(), CallConv);
|
||||
FunctionType::ExtInfo Info = getFunctionExtInfo(T);
|
||||
return getExtFunctionType(*this, T,
|
||||
Info.withCallingConv(CallConv));
|
||||
}
|
||||
|
||||
QualType ASTContext::getRegParmType(QualType T, unsigned RegParm) {
|
||||
FunctionType::ExtInfo Info = getFunctionExtInfo(T);
|
||||
return getExtFunctionType(*this, T,
|
||||
Info.withRegParm(RegParm));
|
||||
}
|
||||
|
||||
/// getComplexType - Return the uniqued reference to the type for a complex
|
||||
@ -1617,12 +1613,13 @@ QualType ASTContext::getDependentSizedExtVectorType(QualType vecType,
|
||||
|
||||
/// getFunctionNoProtoType - Return a K&R style C function type like 'int()'.
|
||||
///
|
||||
QualType ASTContext::getFunctionNoProtoType(QualType ResultTy, bool NoReturn,
|
||||
CallingConv CallConv) {
|
||||
QualType ASTContext::getFunctionNoProtoType(QualType ResultTy,
|
||||
const FunctionType::ExtInfo &Info) {
|
||||
const CallingConv CallConv = Info.getCC();
|
||||
// Unique functions, to guarantee there is only one function of a particular
|
||||
// structure.
|
||||
llvm::FoldingSetNodeID ID;
|
||||
FunctionNoProtoType::Profile(ID, ResultTy, NoReturn, CallConv);
|
||||
FunctionNoProtoType::Profile(ID, ResultTy, Info);
|
||||
|
||||
void *InsertPos = 0;
|
||||
if (FunctionNoProtoType *FT =
|
||||
@ -1632,8 +1629,9 @@ QualType ASTContext::getFunctionNoProtoType(QualType ResultTy, bool NoReturn,
|
||||
QualType Canonical;
|
||||
if (!ResultTy.isCanonical() ||
|
||||
getCanonicalCallConv(CallConv) != CallConv) {
|
||||
Canonical = getFunctionNoProtoType(getCanonicalType(ResultTy), NoReturn,
|
||||
getCanonicalCallConv(CallConv));
|
||||
Canonical =
|
||||
getFunctionNoProtoType(getCanonicalType(ResultTy),
|
||||
Info.withCallingConv(getCanonicalCallConv(CallConv)));
|
||||
|
||||
// Get the new insert position for the node we care about.
|
||||
FunctionNoProtoType *NewIP =
|
||||
@ -1642,7 +1640,7 @@ QualType ASTContext::getFunctionNoProtoType(QualType ResultTy, bool NoReturn,
|
||||
}
|
||||
|
||||
FunctionNoProtoType *New = new (*this, TypeAlignment)
|
||||
FunctionNoProtoType(ResultTy, Canonical, NoReturn, CallConv);
|
||||
FunctionNoProtoType(ResultTy, Canonical, Info);
|
||||
Types.push_back(New);
|
||||
FunctionNoProtoTypes.InsertNode(New, InsertPos);
|
||||
return QualType(New, 0);
|
||||
@ -1654,14 +1652,15 @@ QualType ASTContext::getFunctionType(QualType ResultTy,const QualType *ArgArray,
|
||||
unsigned NumArgs, bool isVariadic,
|
||||
unsigned TypeQuals, bool hasExceptionSpec,
|
||||
bool hasAnyExceptionSpec, unsigned NumExs,
|
||||
const QualType *ExArray, bool NoReturn,
|
||||
CallingConv CallConv) {
|
||||
const QualType *ExArray,
|
||||
const FunctionType::ExtInfo &Info) {
|
||||
const CallingConv CallConv= Info.getCC();
|
||||
// Unique functions, to guarantee there is only one function of a particular
|
||||
// structure.
|
||||
llvm::FoldingSetNodeID ID;
|
||||
FunctionProtoType::Profile(ID, ResultTy, ArgArray, NumArgs, isVariadic,
|
||||
TypeQuals, hasExceptionSpec, hasAnyExceptionSpec,
|
||||
NumExs, ExArray, NoReturn, CallConv);
|
||||
NumExs, ExArray, Info);
|
||||
|
||||
void *InsertPos = 0;
|
||||
if (FunctionProtoType *FTP =
|
||||
@ -1686,8 +1685,8 @@ QualType ASTContext::getFunctionType(QualType ResultTy,const QualType *ArgArray,
|
||||
Canonical = getFunctionType(getCanonicalType(ResultTy),
|
||||
CanonicalArgs.data(), NumArgs,
|
||||
isVariadic, TypeQuals, false,
|
||||
false, 0, 0, NoReturn,
|
||||
getCanonicalCallConv(CallConv));
|
||||
false, 0, 0,
|
||||
Info.withCallingConv(getCanonicalCallConv(CallConv)));
|
||||
|
||||
// Get the new insert position for the node we care about.
|
||||
FunctionProtoType *NewIP =
|
||||
@ -1704,7 +1703,7 @@ QualType ASTContext::getFunctionType(QualType ResultTy,const QualType *ArgArray,
|
||||
NumExs*sizeof(QualType), TypeAlignment);
|
||||
new (FTP) FunctionProtoType(ResultTy, ArgArray, NumArgs, isVariadic,
|
||||
TypeQuals, hasExceptionSpec, hasAnyExceptionSpec,
|
||||
ExArray, NumExs, Canonical, NoReturn, CallConv);
|
||||
ExArray, NumExs, Canonical, Info);
|
||||
Types.push_back(FTP);
|
||||
FunctionProtoTypes.InsertNode(FTP, InsertPos);
|
||||
return QualType(FTP, 0);
|
||||
@ -1963,66 +1962,76 @@ ASTContext::getQualifiedNameType(NestedNameSpecifier *NNS,
|
||||
return QualType(T, 0);
|
||||
}
|
||||
|
||||
QualType ASTContext::getTypenameType(NestedNameSpecifier *NNS,
|
||||
const IdentifierInfo *Name,
|
||||
QualType Canon) {
|
||||
QualType ASTContext::getDependentNameType(ElaboratedTypeKeyword Keyword,
|
||||
NestedNameSpecifier *NNS,
|
||||
const IdentifierInfo *Name,
|
||||
QualType Canon) {
|
||||
assert(NNS->isDependent() && "nested-name-specifier must be dependent");
|
||||
|
||||
if (Canon.isNull()) {
|
||||
NestedNameSpecifier *CanonNNS = getCanonicalNestedNameSpecifier(NNS);
|
||||
if (CanonNNS != NNS)
|
||||
Canon = getTypenameType(CanonNNS, Name);
|
||||
ElaboratedTypeKeyword CanonKeyword = Keyword;
|
||||
if (Keyword == ETK_None)
|
||||
CanonKeyword = ETK_Typename;
|
||||
|
||||
if (CanonNNS != NNS || CanonKeyword != Keyword)
|
||||
Canon = getDependentNameType(CanonKeyword, CanonNNS, Name);
|
||||
}
|
||||
|
||||
llvm::FoldingSetNodeID ID;
|
||||
TypenameType::Profile(ID, NNS, Name);
|
||||
DependentNameType::Profile(ID, Keyword, NNS, Name);
|
||||
|
||||
void *InsertPos = 0;
|
||||
TypenameType *T
|
||||
= TypenameTypes.FindNodeOrInsertPos(ID, InsertPos);
|
||||
DependentNameType *T
|
||||
= DependentNameTypes.FindNodeOrInsertPos(ID, InsertPos);
|
||||
if (T)
|
||||
return QualType(T, 0);
|
||||
|
||||
T = new (*this) TypenameType(NNS, Name, Canon);
|
||||
T = new (*this) DependentNameType(Keyword, NNS, Name, Canon);
|
||||
Types.push_back(T);
|
||||
TypenameTypes.InsertNode(T, InsertPos);
|
||||
DependentNameTypes.InsertNode(T, InsertPos);
|
||||
return QualType(T, 0);
|
||||
}
|
||||
|
||||
QualType
|
||||
ASTContext::getTypenameType(NestedNameSpecifier *NNS,
|
||||
const TemplateSpecializationType *TemplateId,
|
||||
QualType Canon) {
|
||||
ASTContext::getDependentNameType(ElaboratedTypeKeyword Keyword,
|
||||
NestedNameSpecifier *NNS,
|
||||
const TemplateSpecializationType *TemplateId,
|
||||
QualType Canon) {
|
||||
assert(NNS->isDependent() && "nested-name-specifier must be dependent");
|
||||
|
||||
llvm::FoldingSetNodeID ID;
|
||||
TypenameType::Profile(ID, NNS, TemplateId);
|
||||
DependentNameType::Profile(ID, Keyword, NNS, TemplateId);
|
||||
|
||||
void *InsertPos = 0;
|
||||
TypenameType *T
|
||||
= TypenameTypes.FindNodeOrInsertPos(ID, InsertPos);
|
||||
DependentNameType *T
|
||||
= DependentNameTypes.FindNodeOrInsertPos(ID, InsertPos);
|
||||
if (T)
|
||||
return QualType(T, 0);
|
||||
|
||||
if (Canon.isNull()) {
|
||||
NestedNameSpecifier *CanonNNS = getCanonicalNestedNameSpecifier(NNS);
|
||||
QualType CanonType = getCanonicalType(QualType(TemplateId, 0));
|
||||
if (CanonNNS != NNS || CanonType != QualType(TemplateId, 0)) {
|
||||
ElaboratedTypeKeyword CanonKeyword = Keyword;
|
||||
if (Keyword == ETK_None)
|
||||
CanonKeyword = ETK_Typename;
|
||||
if (CanonNNS != NNS || CanonKeyword != Keyword ||
|
||||
CanonType != QualType(TemplateId, 0)) {
|
||||
const TemplateSpecializationType *CanonTemplateId
|
||||
= CanonType->getAs<TemplateSpecializationType>();
|
||||
assert(CanonTemplateId &&
|
||||
"Canonical type must also be a template specialization type");
|
||||
Canon = getTypenameType(CanonNNS, CanonTemplateId);
|
||||
Canon = getDependentNameType(CanonKeyword, CanonNNS, CanonTemplateId);
|
||||
}
|
||||
|
||||
TypenameType *CheckT
|
||||
= TypenameTypes.FindNodeOrInsertPos(ID, InsertPos);
|
||||
DependentNameType *CheckT
|
||||
= DependentNameTypes.FindNodeOrInsertPos(ID, InsertPos);
|
||||
assert(!CheckT && "Typename canonical type is broken"); (void)CheckT;
|
||||
}
|
||||
|
||||
T = new (*this) TypenameType(NNS, TemplateId, Canon);
|
||||
T = new (*this) DependentNameType(Keyword, NNS, TemplateId, Canon);
|
||||
Types.push_back(T);
|
||||
TypenameTypes.InsertNode(T, InsertPos);
|
||||
DependentNameTypes.InsertNode(T, InsertPos);
|
||||
return QualType(T, 0);
|
||||
}
|
||||
|
||||
@ -4127,14 +4136,15 @@ bool ASTContext::canAssignObjCInterfaces(const ObjCObjectPointerType *LHSOPT,
|
||||
bool ASTContext::canAssignObjCInterfacesInBlockPointer(
|
||||
const ObjCObjectPointerType *LHSOPT,
|
||||
const ObjCObjectPointerType *RHSOPT) {
|
||||
if (RHSOPT->isObjCBuiltinType())
|
||||
if (RHSOPT->isObjCBuiltinType() ||
|
||||
LHSOPT->isObjCIdType() || LHSOPT->isObjCQualifiedIdType())
|
||||
return true;
|
||||
|
||||
if (LHSOPT->isObjCBuiltinType()) {
|
||||
return RHSOPT->isObjCBuiltinType() || RHSOPT->isObjCQualifiedIdType();
|
||||
}
|
||||
|
||||
if (LHSOPT->isObjCQualifiedIdType() || RHSOPT->isObjCQualifiedIdType())
|
||||
if (RHSOPT->isObjCQualifiedIdType())
|
||||
return ObjCQualifiedIdTypesAreCompatible(QualType(LHSOPT,0),
|
||||
QualType(RHSOPT,0),
|
||||
false);
|
||||
@ -4315,13 +4325,22 @@ QualType ASTContext::mergeFunctionTypes(QualType lhs, QualType rhs,
|
||||
if (getCanonicalType(retType) != getCanonicalType(rbase->getResultType()))
|
||||
allRTypes = false;
|
||||
// FIXME: double check this
|
||||
bool NoReturn = lbase->getNoReturnAttr() || rbase->getNoReturnAttr();
|
||||
if (NoReturn != lbase->getNoReturnAttr())
|
||||
// FIXME: should we error if lbase->getRegParmAttr() != 0 &&
|
||||
// rbase->getRegParmAttr() != 0 &&
|
||||
// lbase->getRegParmAttr() != rbase->getRegParmAttr()?
|
||||
FunctionType::ExtInfo lbaseInfo = lbase->getExtInfo();
|
||||
FunctionType::ExtInfo rbaseInfo = rbase->getExtInfo();
|
||||
unsigned RegParm = lbaseInfo.getRegParm() == 0 ? rbaseInfo.getRegParm() :
|
||||
lbaseInfo.getRegParm();
|
||||
bool NoReturn = lbaseInfo.getNoReturn() || rbaseInfo.getNoReturn();
|
||||
if (NoReturn != lbaseInfo.getNoReturn() ||
|
||||
RegParm != lbaseInfo.getRegParm())
|
||||
allLTypes = false;
|
||||
if (NoReturn != rbase->getNoReturnAttr())
|
||||
if (NoReturn != rbaseInfo.getNoReturn() ||
|
||||
RegParm != rbaseInfo.getRegParm())
|
||||
allRTypes = false;
|
||||
CallingConv lcc = lbase->getCallConv();
|
||||
CallingConv rcc = rbase->getCallConv();
|
||||
CallingConv lcc = lbaseInfo.getCC();
|
||||
CallingConv rcc = rbaseInfo.getCC();
|
||||
// Compatible functions must have compatible calling conventions
|
||||
if (!isSameCallConv(lcc, rcc))
|
||||
return QualType();
|
||||
@ -4360,7 +4379,8 @@ QualType ASTContext::mergeFunctionTypes(QualType lhs, QualType rhs,
|
||||
if (allRTypes) return rhs;
|
||||
return getFunctionType(retType, types.begin(), types.size(),
|
||||
lproto->isVariadic(), lproto->getTypeQuals(),
|
||||
false, false, 0, 0, NoReturn, lcc);
|
||||
false, false, 0, 0,
|
||||
FunctionType::ExtInfo(NoReturn, RegParm, lcc));
|
||||
}
|
||||
|
||||
if (lproto) allRTypes = false;
|
||||
@ -4393,13 +4413,15 @@ QualType ASTContext::mergeFunctionTypes(QualType lhs, QualType rhs,
|
||||
if (allRTypes) return rhs;
|
||||
return getFunctionType(retType, proto->arg_type_begin(),
|
||||
proto->getNumArgs(), proto->isVariadic(),
|
||||
proto->getTypeQuals(),
|
||||
false, false, 0, 0, NoReturn, lcc);
|
||||
proto->getTypeQuals(),
|
||||
false, false, 0, 0,
|
||||
FunctionType::ExtInfo(NoReturn, RegParm, lcc));
|
||||
}
|
||||
|
||||
if (allLTypes) return lhs;
|
||||
if (allRTypes) return rhs;
|
||||
return getFunctionNoProtoType(retType, NoReturn, lcc);
|
||||
FunctionType::ExtInfo Info(NoReturn, RegParm, lcc);
|
||||
return getFunctionNoProtoType(retType, Info);
|
||||
}
|
||||
|
||||
QualType ASTContext::mergeTypes(QualType LHS, QualType RHS,
|
||||
@ -4903,7 +4925,7 @@ QualType ASTContext::GetBuiltinType(unsigned id,
|
||||
// FIXME: Should we create noreturn types?
|
||||
return getFunctionType(ResType, ArgTypes.data(), ArgTypes.size(),
|
||||
TypeStr[0] == '.', 0, false, false, 0, 0,
|
||||
false, CC_Default);
|
||||
FunctionType::ExtInfo());
|
||||
}
|
||||
|
||||
QualType
|
||||
|
@ -73,7 +73,7 @@ namespace {
|
||||
// FIXME: SubstTemplateTypeParmType
|
||||
// FIXME: TemplateSpecializationType
|
||||
QualType VisitQualifiedNameType(QualifiedNameType *T);
|
||||
// FIXME: TypenameType
|
||||
// FIXME: DependentNameType
|
||||
QualType VisitObjCInterfaceType(ObjCInterfaceType *T);
|
||||
QualType VisitObjCObjectPointerType(ObjCObjectPointerType *T);
|
||||
|
||||
@ -484,10 +484,8 @@ static bool IsStructurallyEquivalent(StructuralEquivalenceContext &Context,
|
||||
Function1->getResultType(),
|
||||
Function2->getResultType()))
|
||||
return false;
|
||||
if (Function1->getNoReturnAttr() != Function2->getNoReturnAttr())
|
||||
return false;
|
||||
if (Function1->getCallConv() != Function2->getCallConv())
|
||||
return false;
|
||||
if (Function1->getExtInfo() != Function2->getExtInfo())
|
||||
return false;
|
||||
break;
|
||||
}
|
||||
|
||||
@ -620,9 +618,9 @@ static bool IsStructurallyEquivalent(StructuralEquivalenceContext &Context,
|
||||
break;
|
||||
}
|
||||
|
||||
case Type::Typename: {
|
||||
const TypenameType *Typename1 = cast<TypenameType>(T1);
|
||||
const TypenameType *Typename2 = cast<TypenameType>(T2);
|
||||
case Type::DependentName: {
|
||||
const DependentNameType *Typename1 = cast<DependentNameType>(T1);
|
||||
const DependentNameType *Typename2 = cast<DependentNameType>(T2);
|
||||
if (!IsStructurallyEquivalent(Context,
|
||||
Typename1->getQualifier(),
|
||||
Typename2->getQualifier()))
|
||||
@ -1200,10 +1198,9 @@ QualType ASTNodeImporter::VisitFunctionNoProtoType(FunctionNoProtoType *T) {
|
||||
QualType ToResultType = Importer.Import(T->getResultType());
|
||||
if (ToResultType.isNull())
|
||||
return QualType();
|
||||
|
||||
|
||||
return Importer.getToContext().getFunctionNoProtoType(ToResultType,
|
||||
T->getNoReturnAttr(),
|
||||
T->getCallConv());
|
||||
T->getExtInfo());
|
||||
}
|
||||
|
||||
QualType ASTNodeImporter::VisitFunctionProtoType(FunctionProtoType *T) {
|
||||
@ -1241,8 +1238,7 @@ QualType ASTNodeImporter::VisitFunctionProtoType(FunctionProtoType *T) {
|
||||
T->hasAnyExceptionSpec(),
|
||||
ExceptionTypes.size(),
|
||||
ExceptionTypes.data(),
|
||||
T->getNoReturnAttr(),
|
||||
T->getCallConv());
|
||||
T->getExtInfo());
|
||||
}
|
||||
|
||||
QualType ASTNodeImporter::VisitTypedefType(TypedefType *T) {
|
||||
|
@ -9,6 +9,7 @@ add_clang_library(clangAST
|
||||
AttrImpl.cpp
|
||||
CXXInheritance.cpp
|
||||
Decl.cpp
|
||||
DeclarationName.cpp
|
||||
DeclBase.cpp
|
||||
DeclCXX.cpp
|
||||
DeclFriend.cpp
|
||||
@ -16,10 +17,9 @@ add_clang_library(clangAST
|
||||
DeclObjC.cpp
|
||||
DeclPrinter.cpp
|
||||
DeclTemplate.cpp
|
||||
DeclarationName.cpp
|
||||
Expr.cpp
|
||||
ExprCXX.cpp
|
||||
ExprConstant.cpp
|
||||
ExprCXX.cpp
|
||||
FullExpr.cpp
|
||||
InheritViz.cpp
|
||||
NestedNameSpecifier.cpp
|
||||
|
@ -416,3 +416,240 @@ FindNestedNameSpecifierMember(const CXXBaseSpecifier *Specifier,
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
void OverridingMethods::add(unsigned OverriddenSubobject,
|
||||
UniqueVirtualMethod Overriding) {
|
||||
llvm::SmallVector<UniqueVirtualMethod, 4> &SubobjectOverrides
|
||||
= Overrides[OverriddenSubobject];
|
||||
if (std::find(SubobjectOverrides.begin(), SubobjectOverrides.end(),
|
||||
Overriding) == SubobjectOverrides.end())
|
||||
SubobjectOverrides.push_back(Overriding);
|
||||
}
|
||||
|
||||
void OverridingMethods::add(const OverridingMethods &Other) {
|
||||
for (const_iterator I = Other.begin(), IE = Other.end(); I != IE; ++I) {
|
||||
for (overriding_const_iterator M = I->second.begin(),
|
||||
MEnd = I->second.end();
|
||||
M != MEnd;
|
||||
++M)
|
||||
add(I->first, *M);
|
||||
}
|
||||
}
|
||||
|
||||
void OverridingMethods::replaceAll(UniqueVirtualMethod Overriding) {
|
||||
for (iterator I = begin(), IEnd = end(); I != IEnd; ++I) {
|
||||
I->second.clear();
|
||||
I->second.push_back(Overriding);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
namespace {
|
||||
class FinalOverriderCollector {
|
||||
/// \brief The number of subobjects of a given class type that
|
||||
/// occur within the class hierarchy.
|
||||
llvm::DenseMap<const CXXRecordDecl *, unsigned> SubobjectCount;
|
||||
|
||||
/// \brief Overriders for each virtual base subobject.
|
||||
llvm::DenseMap<const CXXRecordDecl *, CXXFinalOverriderMap *> VirtualOverriders;
|
||||
|
||||
CXXFinalOverriderMap FinalOverriders;
|
||||
|
||||
public:
|
||||
~FinalOverriderCollector();
|
||||
|
||||
void Collect(const CXXRecordDecl *RD, bool VirtualBase,
|
||||
const CXXRecordDecl *InVirtualSubobject,
|
||||
CXXFinalOverriderMap &Overriders);
|
||||
};
|
||||
}
|
||||
|
||||
void FinalOverriderCollector::Collect(const CXXRecordDecl *RD,
|
||||
bool VirtualBase,
|
||||
const CXXRecordDecl *InVirtualSubobject,
|
||||
CXXFinalOverriderMap &Overriders) {
|
||||
unsigned SubobjectNumber = 0;
|
||||
if (!VirtualBase)
|
||||
SubobjectNumber
|
||||
= ++SubobjectCount[cast<CXXRecordDecl>(RD->getCanonicalDecl())];
|
||||
|
||||
for (CXXRecordDecl::base_class_const_iterator Base = RD->bases_begin(),
|
||||
BaseEnd = RD->bases_end(); Base != BaseEnd; ++Base) {
|
||||
if (const RecordType *RT = Base->getType()->getAs<RecordType>()) {
|
||||
const CXXRecordDecl *BaseDecl = cast<CXXRecordDecl>(RT->getDecl());
|
||||
if (!BaseDecl->isPolymorphic())
|
||||
continue;
|
||||
|
||||
if (Overriders.empty() && !Base->isVirtual()) {
|
||||
// There are no other overriders of virtual member functions,
|
||||
// so let the base class fill in our overriders for us.
|
||||
Collect(BaseDecl, false, InVirtualSubobject, Overriders);
|
||||
continue;
|
||||
}
|
||||
|
||||
// Collect all of the overridders from the base class subobject
|
||||
// and merge them into the set of overridders for this class.
|
||||
// For virtual base classes, populate or use the cached virtual
|
||||
// overrides so that we do not walk the virtual base class (and
|
||||
// its base classes) more than once.
|
||||
CXXFinalOverriderMap ComputedBaseOverriders;
|
||||
CXXFinalOverriderMap *BaseOverriders = &ComputedBaseOverriders;
|
||||
if (Base->isVirtual()) {
|
||||
CXXFinalOverriderMap *&MyVirtualOverriders = VirtualOverriders[BaseDecl];
|
||||
if (!MyVirtualOverriders) {
|
||||
MyVirtualOverriders = new CXXFinalOverriderMap;
|
||||
Collect(BaseDecl, true, BaseDecl, *MyVirtualOverriders);
|
||||
}
|
||||
|
||||
BaseOverriders = MyVirtualOverriders;
|
||||
} else
|
||||
Collect(BaseDecl, false, InVirtualSubobject, ComputedBaseOverriders);
|
||||
|
||||
// Merge the overriders from this base class into our own set of
|
||||
// overriders.
|
||||
for (CXXFinalOverriderMap::iterator OM = BaseOverriders->begin(),
|
||||
OMEnd = BaseOverriders->end();
|
||||
OM != OMEnd;
|
||||
++OM) {
|
||||
const CXXMethodDecl *CanonOM
|
||||
= cast<CXXMethodDecl>(OM->first->getCanonicalDecl());
|
||||
Overriders[CanonOM].add(OM->second);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
for (CXXRecordDecl::method_iterator M = RD->method_begin(),
|
||||
MEnd = RD->method_end();
|
||||
M != MEnd;
|
||||
++M) {
|
||||
// We only care about virtual methods.
|
||||
if (!M->isVirtual())
|
||||
continue;
|
||||
|
||||
CXXMethodDecl *CanonM = cast<CXXMethodDecl>(M->getCanonicalDecl());
|
||||
|
||||
if (CanonM->begin_overridden_methods()
|
||||
== CanonM->end_overridden_methods()) {
|
||||
// This is a new virtual function that does not override any
|
||||
// other virtual function. Add it to the map of virtual
|
||||
// functions for which we are tracking overridders.
|
||||
|
||||
// C++ [class.virtual]p2:
|
||||
// For convenience we say that any virtual function overrides itself.
|
||||
Overriders[CanonM].add(SubobjectNumber,
|
||||
UniqueVirtualMethod(CanonM, SubobjectNumber,
|
||||
InVirtualSubobject));
|
||||
continue;
|
||||
}
|
||||
|
||||
// This virtual method overrides other virtual methods, so it does
|
||||
// not add any new slots into the set of overriders. Instead, we
|
||||
// replace entries in the set of overriders with the new
|
||||
// overrider. To do so, we dig down to the original virtual
|
||||
// functions using data recursion and update all of the methods it
|
||||
// overrides.
|
||||
typedef std::pair<CXXMethodDecl::method_iterator,
|
||||
CXXMethodDecl::method_iterator> OverriddenMethods;
|
||||
llvm::SmallVector<OverriddenMethods, 4> Stack;
|
||||
Stack.push_back(std::make_pair(CanonM->begin_overridden_methods(),
|
||||
CanonM->end_overridden_methods()));
|
||||
while (!Stack.empty()) {
|
||||
OverriddenMethods OverMethods = Stack.back();
|
||||
Stack.pop_back();
|
||||
|
||||
for (; OverMethods.first != OverMethods.second; ++OverMethods.first) {
|
||||
const CXXMethodDecl *CanonOM
|
||||
= cast<CXXMethodDecl>((*OverMethods.first)->getCanonicalDecl());
|
||||
if (CanonOM->begin_overridden_methods()
|
||||
== CanonOM->end_overridden_methods()) {
|
||||
// C++ [class.virtual]p2:
|
||||
// A virtual member function C::vf of a class object S is
|
||||
// a final overrider unless the most derived class (1.8)
|
||||
// of which S is a base class subobject (if any) declares
|
||||
// or inherits another member function that overrides vf.
|
||||
//
|
||||
// Treating this object like the most derived class, we
|
||||
// replace any overrides from base classes with this
|
||||
// overriding virtual function.
|
||||
Overriders[CanonOM].replaceAll(
|
||||
UniqueVirtualMethod(CanonM, SubobjectNumber,
|
||||
InVirtualSubobject));
|
||||
continue;
|
||||
}
|
||||
|
||||
// Continue recursion to the methods that this virtual method
|
||||
// overrides.
|
||||
Stack.push_back(std::make_pair(CanonOM->begin_overridden_methods(),
|
||||
CanonOM->end_overridden_methods()));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
FinalOverriderCollector::~FinalOverriderCollector() {
|
||||
for (llvm::DenseMap<const CXXRecordDecl *, CXXFinalOverriderMap *>::iterator
|
||||
VO = VirtualOverriders.begin(), VOEnd = VirtualOverriders.end();
|
||||
VO != VOEnd;
|
||||
++VO)
|
||||
delete VO->second;
|
||||
}
|
||||
|
||||
void
|
||||
CXXRecordDecl::getFinalOverriders(CXXFinalOverriderMap &FinalOverriders) const {
|
||||
FinalOverriderCollector Collector;
|
||||
Collector.Collect(this, false, 0, FinalOverriders);
|
||||
|
||||
// Weed out any final overriders that come from virtual base class
|
||||
// subobjects that were hidden by other subobjects along any path.
|
||||
// This is the final-overrider variant of C++ [class.member.lookup]p10.
|
||||
for (CXXFinalOverriderMap::iterator OM = FinalOverriders.begin(),
|
||||
OMEnd = FinalOverriders.end();
|
||||
OM != OMEnd;
|
||||
++OM) {
|
||||
for (OverridingMethods::iterator SO = OM->second.begin(),
|
||||
SOEnd = OM->second.end();
|
||||
SO != SOEnd;
|
||||
++SO) {
|
||||
llvm::SmallVector<UniqueVirtualMethod, 4> &Overriding = SO->second;
|
||||
if (Overriding.size() < 2)
|
||||
continue;
|
||||
|
||||
for (llvm::SmallVector<UniqueVirtualMethod, 4>::iterator
|
||||
Pos = Overriding.begin(), PosEnd = Overriding.end();
|
||||
Pos != PosEnd;
|
||||
/* increment in loop */) {
|
||||
if (!Pos->InVirtualSubobject) {
|
||||
++Pos;
|
||||
continue;
|
||||
}
|
||||
|
||||
// We have an overriding method in a virtual base class
|
||||
// subobject (or non-virtual base class subobject thereof);
|
||||
// determine whether there exists an other overriding method
|
||||
// in a base class subobject that hides the virtual base class
|
||||
// subobject.
|
||||
bool Hidden = false;
|
||||
for (llvm::SmallVector<UniqueVirtualMethod, 4>::iterator
|
||||
OP = Overriding.begin(), OPEnd = Overriding.end();
|
||||
OP != OPEnd && !Hidden;
|
||||
++OP) {
|
||||
if (Pos == OP)
|
||||
continue;
|
||||
|
||||
if (OP->Method->getParent()->isVirtuallyDerivedFrom(
|
||||
const_cast<CXXRecordDecl *>(Pos->InVirtualSubobject)))
|
||||
Hidden = true;
|
||||
}
|
||||
|
||||
if (Hidden) {
|
||||
// The current overriding function is hidden by another
|
||||
// overriding function; remove this one.
|
||||
Pos = Overriding.erase(Pos);
|
||||
PosEnd = Overriding.end();
|
||||
} else {
|
||||
++Pos;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -1413,10 +1413,8 @@ void TagDecl::startDefinition() {
|
||||
CXXRecordDecl *D = cast<CXXRecordDecl>(this);
|
||||
struct CXXRecordDecl::DefinitionData *Data =
|
||||
new (getASTContext()) struct CXXRecordDecl::DefinitionData(D);
|
||||
do {
|
||||
D->DefinitionData = Data;
|
||||
D = cast_or_null<CXXRecordDecl>(D->getPreviousDeclaration());
|
||||
} while (D);
|
||||
for (redecl_iterator I = redecls_begin(), E = redecls_end(); I != E; ++I)
|
||||
cast<CXXRecordDecl>(*I)->DefinitionData = Data;
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -18,6 +18,7 @@
|
||||
#include "clang/AST/DeclFriend.h"
|
||||
#include "clang/AST/DeclObjC.h"
|
||||
#include "clang/AST/DeclTemplate.h"
|
||||
#include "clang/AST/DependentDiagnostic.h"
|
||||
#include "clang/AST/ExternalASTSource.h"
|
||||
#include "clang/AST/ASTContext.h"
|
||||
#include "clang/AST/Type.h"
|
||||
@ -481,7 +482,7 @@ DeclContext::~DeclContext() {
|
||||
// FIXME: Currently ~ASTContext will delete the StoredDeclsMaps because
|
||||
// ~DeclContext() is not guaranteed to be called when ASTContext uses
|
||||
// a BumpPtrAllocator.
|
||||
// delete static_cast<StoredDeclsMap*>(LookupPtr);
|
||||
// delete LookupPtr;
|
||||
}
|
||||
|
||||
void DeclContext::DestroyDecls(ASTContext &C) {
|
||||
@ -516,10 +517,16 @@ bool DeclContext::isDependentContext() const {
|
||||
if (Record->getDescribedClassTemplate())
|
||||
return true;
|
||||
|
||||
if (const FunctionDecl *Function = dyn_cast<FunctionDecl>(this))
|
||||
if (const FunctionDecl *Function = dyn_cast<FunctionDecl>(this)) {
|
||||
if (Function->getDescribedFunctionTemplate())
|
||||
return true;
|
||||
|
||||
// Friend function declarations are dependent if their *lexical*
|
||||
// context is dependent.
|
||||
if (cast<Decl>(this)->getFriendObjectKind())
|
||||
return getLexicalParent()->isDependentContext();
|
||||
}
|
||||
|
||||
return getParent() && getParent()->isDependentContext();
|
||||
}
|
||||
|
||||
@ -666,9 +673,7 @@ DeclContext::LoadVisibleDeclsFromExternalStorage() const {
|
||||
// Load the declaration IDs for all of the names visible in this
|
||||
// context.
|
||||
assert(!LookupPtr && "Have a lookup map before de-serialization?");
|
||||
StoredDeclsMap *Map =
|
||||
(StoredDeclsMap*) getParentASTContext().CreateStoredDeclsMap();
|
||||
LookupPtr = Map;
|
||||
StoredDeclsMap *Map = CreateStoredDeclsMap(getParentASTContext());
|
||||
for (unsigned I = 0, N = Decls.size(); I != N; ++I) {
|
||||
(*Map)[Decls[I].Name].setFromDeclIDs(Decls[I].Declarations);
|
||||
}
|
||||
@ -727,10 +732,9 @@ void DeclContext::removeDecl(Decl *D) {
|
||||
if (isa<NamedDecl>(D)) {
|
||||
NamedDecl *ND = cast<NamedDecl>(D);
|
||||
|
||||
void *OpaqueMap = getPrimaryContext()->LookupPtr;
|
||||
if (!OpaqueMap) return;
|
||||
StoredDeclsMap *Map = getPrimaryContext()->LookupPtr;
|
||||
if (!Map) return;
|
||||
|
||||
StoredDeclsMap *Map = static_cast<StoredDeclsMap*>(OpaqueMap);
|
||||
StoredDeclsMap::iterator Pos = Map->find(ND->getDeclName());
|
||||
assert(Pos != Map->end() && "no lookup entry for decl");
|
||||
Pos->second.remove(ND);
|
||||
@ -808,9 +812,8 @@ DeclContext::lookup(DeclarationName Name) {
|
||||
return lookup_result(0, 0);
|
||||
}
|
||||
|
||||
StoredDeclsMap *Map = static_cast<StoredDeclsMap*>(LookupPtr);
|
||||
StoredDeclsMap::iterator Pos = Map->find(Name);
|
||||
if (Pos == Map->end())
|
||||
StoredDeclsMap::iterator Pos = LookupPtr->find(Name);
|
||||
if (Pos == LookupPtr->end())
|
||||
return lookup_result(0, 0);
|
||||
return Pos->second.getLookupResult(getParentASTContext());
|
||||
}
|
||||
@ -878,12 +881,11 @@ void DeclContext::makeDeclVisibleInContextImpl(NamedDecl *D) {
|
||||
ASTContext *C = 0;
|
||||
if (!LookupPtr) {
|
||||
C = &getParentASTContext();
|
||||
LookupPtr = (StoredDeclsMap*) C->CreateStoredDeclsMap();
|
||||
CreateStoredDeclsMap(*C);
|
||||
}
|
||||
|
||||
// Insert this declaration into the map.
|
||||
StoredDeclsMap &Map = *static_cast<StoredDeclsMap*>(LookupPtr);
|
||||
StoredDeclsList &DeclNameEntries = Map[D->getDeclName()];
|
||||
StoredDeclsList &DeclNameEntries = (*LookupPtr)[D->getDeclName()];
|
||||
if (DeclNameEntries.isNull()) {
|
||||
DeclNameEntries.setOnlyValue(D);
|
||||
return;
|
||||
@ -952,13 +954,69 @@ void StoredDeclsList::materializeDecls(ASTContext &Context) {
|
||||
// Creation and Destruction of StoredDeclsMaps. //
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
void *ASTContext::CreateStoredDeclsMap() {
|
||||
StoredDeclsMap *M = new StoredDeclsMap();
|
||||
SDMs.push_back(M);
|
||||
StoredDeclsMap *DeclContext::CreateStoredDeclsMap(ASTContext &C) const {
|
||||
assert(!LookupPtr && "context already has a decls map");
|
||||
assert(getPrimaryContext() == this &&
|
||||
"creating decls map on non-primary context");
|
||||
|
||||
StoredDeclsMap *M;
|
||||
bool Dependent = isDependentContext();
|
||||
if (Dependent)
|
||||
M = new DependentStoredDeclsMap();
|
||||
else
|
||||
M = new StoredDeclsMap();
|
||||
M->Previous = C.LastSDM;
|
||||
C.LastSDM = llvm::PointerIntPair<StoredDeclsMap*,1>(M, Dependent);
|
||||
LookupPtr = M;
|
||||
return M;
|
||||
}
|
||||
|
||||
void ASTContext::ReleaseDeclContextMaps() {
|
||||
for (std::vector<void*>::iterator I = SDMs.begin(), E = SDMs.end(); I!=E; ++I)
|
||||
delete (StoredDeclsMap*) *I;
|
||||
// It's okay to delete DependentStoredDeclsMaps via a StoredDeclsMap
|
||||
// pointer because the subclass doesn't add anything that needs to
|
||||
// be deleted.
|
||||
|
||||
StoredDeclsMap::DestroyAll(LastSDM.getPointer(), LastSDM.getInt());
|
||||
}
|
||||
|
||||
void StoredDeclsMap::DestroyAll(StoredDeclsMap *Map, bool Dependent) {
|
||||
while (Map) {
|
||||
// Advance the iteration before we invalidate memory.
|
||||
llvm::PointerIntPair<StoredDeclsMap*,1> Next = Map->Previous;
|
||||
|
||||
if (Dependent)
|
||||
delete static_cast<DependentStoredDeclsMap*>(Map);
|
||||
else
|
||||
delete Map;
|
||||
|
||||
Map = Next.getPointer();
|
||||
Dependent = Next.getInt();
|
||||
}
|
||||
}
|
||||
|
||||
DependentDiagnostic *DependentDiagnostic::Create(ASTContext &C,
|
||||
DeclContext *Parent,
|
||||
const PartialDiagnostic &PDiag) {
|
||||
assert(Parent->isDependentContext()
|
||||
&& "cannot iterate dependent diagnostics of non-dependent context");
|
||||
Parent = Parent->getPrimaryContext();
|
||||
if (!Parent->LookupPtr)
|
||||
Parent->CreateStoredDeclsMap(C);
|
||||
|
||||
DependentStoredDeclsMap *Map
|
||||
= static_cast<DependentStoredDeclsMap*>(Parent->LookupPtr);
|
||||
|
||||
// Allocate the copy of the PartialDiagnostic via the ASTContext's
|
||||
// BumpPtrAllocator, rather than the ASTContext itself.
|
||||
PartialDiagnostic::Storage *DiagStorage = 0;
|
||||
if (PDiag.hasStorage())
|
||||
DiagStorage = new (C) PartialDiagnostic::Storage;
|
||||
|
||||
DependentDiagnostic *DD = new (C) DependentDiagnostic(PDiag, DiagStorage);
|
||||
|
||||
// TODO: Maybe we shouldn't reverse the order during insertion.
|
||||
DD->NextDiagnostic = Map->FirstDiagnostic;
|
||||
Map->FirstDiagnostic = DD;
|
||||
|
||||
return DD;
|
||||
}
|
||||
|
@ -83,9 +83,11 @@ CXXRecordDecl::setBases(CXXBaseSpecifier const * const *Bases,
|
||||
if (data().Bases)
|
||||
C.Deallocate(data().Bases);
|
||||
|
||||
int vbaseCount = 0;
|
||||
llvm::SmallVector<const CXXBaseSpecifier*, 8> UniqueVbases;
|
||||
bool hasDirectVirtualBase = false;
|
||||
// The set of seen virtual base types.
|
||||
llvm::SmallPtrSet<CanQualType, 8> SeenVBaseTypes;
|
||||
|
||||
// The virtual bases of this class.
|
||||
llvm::SmallVector<const CXXBaseSpecifier *, 8> VBases;
|
||||
|
||||
data().Bases = new(C) CXXBaseSpecifier [NumBases];
|
||||
data().NumBases = NumBases;
|
||||
@ -99,58 +101,44 @@ CXXRecordDecl::setBases(CXXBaseSpecifier const * const *Bases,
|
||||
continue;
|
||||
CXXRecordDecl *BaseClassDecl
|
||||
= cast<CXXRecordDecl>(BaseType->getAs<RecordType>()->getDecl());
|
||||
if (Base->isVirtual())
|
||||
hasDirectVirtualBase = true;
|
||||
|
||||
// Now go through all virtual bases of this base and add them.
|
||||
for (CXXRecordDecl::base_class_iterator VBase =
|
||||
BaseClassDecl->vbases_begin(),
|
||||
E = BaseClassDecl->vbases_end(); VBase != E; ++VBase) {
|
||||
// Add this vbase to the array of vbases for current class if it is
|
||||
// not already in the list.
|
||||
// FIXME. Note that we do a linear search as number of such classes are
|
||||
// very few.
|
||||
int i;
|
||||
for (i = 0; i < vbaseCount; ++i)
|
||||
if (UniqueVbases[i]->getType() == VBase->getType())
|
||||
break;
|
||||
if (i == vbaseCount) {
|
||||
UniqueVbases.push_back(VBase);
|
||||
++vbaseCount;
|
||||
}
|
||||
// Add this base if it's not already in the list.
|
||||
if (SeenVBaseTypes.insert(C.getCanonicalType(VBase->getType())))
|
||||
VBases.push_back(VBase);
|
||||
}
|
||||
|
||||
if (Base->isVirtual()) {
|
||||
// Add this base if it's not already in the list.
|
||||
if (SeenVBaseTypes.insert(C.getCanonicalType(BaseType)))
|
||||
VBases.push_back(Base);
|
||||
}
|
||||
|
||||
}
|
||||
if (hasDirectVirtualBase) {
|
||||
// Iterate one more time through the direct bases and add the virtual
|
||||
// base to the list of vritual bases for current class.
|
||||
for (unsigned i = 0; i < NumBases; ++i) {
|
||||
const CXXBaseSpecifier *VBase = Bases[i];
|
||||
if (!VBase->isVirtual())
|
||||
continue;
|
||||
int j;
|
||||
for (j = 0; j < vbaseCount; ++j)
|
||||
if (UniqueVbases[j]->getType() == VBase->getType())
|
||||
break;
|
||||
if (j == vbaseCount) {
|
||||
UniqueVbases.push_back(VBase);
|
||||
++vbaseCount;
|
||||
}
|
||||
}
|
||||
}
|
||||
if (vbaseCount > 0) {
|
||||
// build AST for inhireted, direct or indirect, virtual bases.
|
||||
data().VBases = new (C) CXXBaseSpecifier [vbaseCount];
|
||||
data().NumVBases = vbaseCount;
|
||||
for (int i = 0; i < vbaseCount; i++) {
|
||||
QualType QT = UniqueVbases[i]->getType();
|
||||
// Skip dependent types; we can't do any checking on them now.
|
||||
if (QT->isDependentType())
|
||||
continue;
|
||||
CXXRecordDecl *VBaseClassDecl
|
||||
= cast<CXXRecordDecl>(QT->getAs<RecordType>()->getDecl());
|
||||
data().VBases[i] =
|
||||
CXXBaseSpecifier(VBaseClassDecl->getSourceRange(), true,
|
||||
VBaseClassDecl->getTagKind() == RecordDecl::TK_class,
|
||||
UniqueVbases[i]->getAccessSpecifier(), QT);
|
||||
}
|
||||
|
||||
if (VBases.empty())
|
||||
return;
|
||||
|
||||
// Create base specifier for any direct or indirect virtual bases.
|
||||
data().VBases = new (C) CXXBaseSpecifier[VBases.size()];
|
||||
data().NumVBases = VBases.size();
|
||||
for (int I = 0, E = VBases.size(); I != E; ++I) {
|
||||
QualType VBaseType = VBases[I]->getType();
|
||||
|
||||
// Skip dependent types; we can't do any checking on them now.
|
||||
if (VBaseType->isDependentType())
|
||||
continue;
|
||||
|
||||
CXXRecordDecl *VBaseClassDecl
|
||||
= cast<CXXRecordDecl>(VBaseType->getAs<RecordType>()->getDecl());
|
||||
|
||||
data().VBases[I] =
|
||||
CXXBaseSpecifier(VBaseClassDecl->getSourceRange(), true,
|
||||
VBaseClassDecl->getTagKind() == RecordDecl::TK_class,
|
||||
VBases[I]->getAccessSpecifier(), VBaseType);
|
||||
}
|
||||
}
|
||||
|
||||
@ -320,6 +308,8 @@ void CXXRecordDecl::addedAssignmentOperator(ASTContext &Context,
|
||||
|
||||
static CanQualType GetConversionType(ASTContext &Context, NamedDecl *Conv) {
|
||||
QualType T;
|
||||
if (isa<UsingShadowDecl>(Conv))
|
||||
Conv = cast<UsingShadowDecl>(Conv)->getTargetDecl();
|
||||
if (FunctionTemplateDecl *ConvTemp = dyn_cast<FunctionTemplateDecl>(Conv))
|
||||
T = ConvTemp->getTemplatedDecl()->getResultType();
|
||||
else
|
||||
@ -457,26 +447,45 @@ const UnresolvedSetImpl *CXXRecordDecl::getVisibleConversionFunctions() {
|
||||
return &data().VisibleConversions;
|
||||
}
|
||||
|
||||
void CXXRecordDecl::addConversionFunction(CXXConversionDecl *ConvDecl) {
|
||||
assert(!ConvDecl->getDescribedFunctionTemplate() &&
|
||||
"Conversion function templates should cast to FunctionTemplateDecl.");
|
||||
#ifndef NDEBUG
|
||||
void CXXRecordDecl::CheckConversionFunction(NamedDecl *ConvDecl) {
|
||||
assert(ConvDecl->getDeclContext() == this &&
|
||||
"conversion function does not belong to this record");
|
||||
|
||||
// We intentionally don't use the decl's access here because it
|
||||
// hasn't been set yet. That's really just a misdesign in Sema.
|
||||
data().Conversions.addDecl(ConvDecl);
|
||||
ConvDecl = ConvDecl->getUnderlyingDecl();
|
||||
if (FunctionTemplateDecl *Temp = dyn_cast<FunctionTemplateDecl>(ConvDecl)) {
|
||||
assert(isa<CXXConversionDecl>(Temp->getTemplatedDecl()));
|
||||
} else {
|
||||
assert(isa<CXXConversionDecl>(ConvDecl));
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
void CXXRecordDecl::addConversionFunction(FunctionTemplateDecl *ConvDecl) {
|
||||
assert(isa<CXXConversionDecl>(ConvDecl->getTemplatedDecl()) &&
|
||||
"Function template is not a conversion function template");
|
||||
assert(ConvDecl->getDeclContext() == this &&
|
||||
"conversion function does not belong to this record");
|
||||
data().Conversions.addDecl(ConvDecl);
|
||||
void CXXRecordDecl::removeConversion(const NamedDecl *ConvDecl) {
|
||||
// This operation is O(N) but extremely rare. Sema only uses it to
|
||||
// remove UsingShadowDecls in a class that were followed by a direct
|
||||
// declaration, e.g.:
|
||||
// class A : B {
|
||||
// using B::operator int;
|
||||
// operator int();
|
||||
// };
|
||||
// This is uncommon by itself and even more uncommon in conjunction
|
||||
// with sufficiently large numbers of directly-declared conversions
|
||||
// that asymptotic behavior matters.
|
||||
|
||||
UnresolvedSetImpl &Convs = *getConversionFunctions();
|
||||
for (unsigned I = 0, E = Convs.size(); I != E; ++I) {
|
||||
if (Convs[I].getDecl() == ConvDecl) {
|
||||
Convs.erase(I);
|
||||
assert(std::find(Convs.begin(), Convs.end(), ConvDecl) == Convs.end()
|
||||
&& "conversion was found multiple times in unresolved set");
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
llvm_unreachable("conversion not found in set!");
|
||||
}
|
||||
|
||||
|
||||
void CXXRecordDecl::setMethodAsVirtual(FunctionDecl *Method) {
|
||||
Method->setVirtualAsWritten(true);
|
||||
setAggregate(false);
|
||||
|
@ -492,44 +492,45 @@ QualType CallExpr::getCallReturnType() const {
|
||||
return FnType->getResultType();
|
||||
}
|
||||
|
||||
MemberExpr::MemberExpr(Expr *base, bool isarrow, NestedNameSpecifier *qual,
|
||||
SourceRange qualrange, ValueDecl *memberdecl,
|
||||
SourceLocation l, const TemplateArgumentListInfo *targs,
|
||||
QualType ty)
|
||||
: Expr(MemberExprClass, ty,
|
||||
base->isTypeDependent() || (qual && qual->isDependent()),
|
||||
base->isValueDependent() || (qual && qual->isDependent())),
|
||||
Base(base), MemberDecl(memberdecl), MemberLoc(l), IsArrow(isarrow),
|
||||
HasQualifier(qual != 0), HasExplicitTemplateArgumentList(targs) {
|
||||
// Initialize the qualifier, if any.
|
||||
if (HasQualifier) {
|
||||
NameQualifier *NQ = getMemberQualifier();
|
||||
NQ->NNS = qual;
|
||||
NQ->Range = qualrange;
|
||||
}
|
||||
|
||||
// Initialize the explicit template argument list, if any.
|
||||
if (targs)
|
||||
getExplicitTemplateArgumentList()->initializeFrom(*targs);
|
||||
}
|
||||
|
||||
MemberExpr *MemberExpr::Create(ASTContext &C, Expr *base, bool isarrow,
|
||||
NestedNameSpecifier *qual,
|
||||
SourceRange qualrange,
|
||||
ValueDecl *memberdecl,
|
||||
NamedDecl *founddecl,
|
||||
SourceLocation l,
|
||||
const TemplateArgumentListInfo *targs,
|
||||
QualType ty) {
|
||||
std::size_t Size = sizeof(MemberExpr);
|
||||
if (qual != 0)
|
||||
Size += sizeof(NameQualifier);
|
||||
|
||||
bool hasQualOrFound = (qual != 0 || founddecl != memberdecl);
|
||||
if (hasQualOrFound)
|
||||
Size += sizeof(MemberNameQualifier);
|
||||
|
||||
if (targs)
|
||||
Size += ExplicitTemplateArgumentList::sizeFor(*targs);
|
||||
|
||||
void *Mem = C.Allocate(Size, llvm::alignof<MemberExpr>());
|
||||
return new (Mem) MemberExpr(base, isarrow, qual, qualrange, memberdecl, l,
|
||||
targs, ty);
|
||||
MemberExpr *E = new (Mem) MemberExpr(base, isarrow, memberdecl, l, ty);
|
||||
|
||||
if (hasQualOrFound) {
|
||||
if (qual && qual->isDependent()) {
|
||||
E->setValueDependent(true);
|
||||
E->setTypeDependent(true);
|
||||
}
|
||||
E->HasQualifierOrFoundDecl = true;
|
||||
|
||||
MemberNameQualifier *NQ = E->getMemberQualifier();
|
||||
NQ->NNS = qual;
|
||||
NQ->Range = qualrange;
|
||||
NQ->FoundDecl = founddecl;
|
||||
}
|
||||
|
||||
if (targs) {
|
||||
E->HasExplicitTemplateArgumentList = true;
|
||||
E->getExplicitTemplateArgumentList()->initializeFrom(*targs);
|
||||
}
|
||||
|
||||
return E;
|
||||
}
|
||||
|
||||
const char *CastExpr::getCastKindName() const {
|
||||
@ -544,6 +545,8 @@ const char *CastExpr::getCastKindName() const {
|
||||
return "BaseToDerived";
|
||||
case CastExpr::CK_DerivedToBase:
|
||||
return "DerivedToBase";
|
||||
case CastExpr::CK_UncheckedDerivedToBase:
|
||||
return "UncheckedDerivedToBase";
|
||||
case CastExpr::CK_Dynamic:
|
||||
return "Dynamic";
|
||||
case CastExpr::CK_ToUnion:
|
||||
@ -914,8 +917,15 @@ bool Expr::isUnusedResultAWarning(SourceLocation &Loc, SourceRange &R1,
|
||||
case CXXConstructExprClass:
|
||||
return false;
|
||||
|
||||
case ObjCMessageExprClass:
|
||||
case ObjCMessageExprClass: {
|
||||
const ObjCMessageExpr *ME = cast<ObjCMessageExpr>(this);
|
||||
const ObjCMethodDecl *MD = ME->getMethodDecl();
|
||||
if (MD && MD->getAttr<WarnUnusedResultAttr>()) {
|
||||
Loc = getExprLoc();
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
case ObjCImplicitSetterGetterRefExprClass: { // Dot syntax for message send.
|
||||
#if 0
|
||||
|
@ -750,7 +750,7 @@ bool Type::isSpecifierType() const {
|
||||
case SubstTemplateTypeParm:
|
||||
case TemplateSpecialization:
|
||||
case QualifiedName:
|
||||
case Typename:
|
||||
case DependentName:
|
||||
case ObjCInterface:
|
||||
case ObjCObjectPointer:
|
||||
case Elaborated:
|
||||
@ -760,6 +760,27 @@ bool Type::isSpecifierType() const {
|
||||
}
|
||||
}
|
||||
|
||||
bool Type::isElaboratedTypeSpecifier() const {
|
||||
if (getTypeClass() == Elaborated)
|
||||
return true;
|
||||
|
||||
if (const DependentNameType *Dependent = dyn_cast<DependentNameType>(this)) {
|
||||
switch (Dependent->getKeyword()) {
|
||||
case ETK_None:
|
||||
case ETK_Typename:
|
||||
return false;
|
||||
|
||||
case ETK_Class:
|
||||
case ETK_Struct:
|
||||
case ETK_Union:
|
||||
case ETK_Enum:
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
const char *Type::getTypeClassName() const {
|
||||
switch (TC) {
|
||||
default: assert(0 && "Type class not in TypeNodes.def!");
|
||||
@ -820,8 +841,8 @@ void FunctionProtoType::Profile(llvm::FoldingSetNodeID &ID, QualType Result,
|
||||
unsigned NumArgs, bool isVariadic,
|
||||
unsigned TypeQuals, bool hasExceptionSpec,
|
||||
bool anyExceptionSpec, unsigned NumExceptions,
|
||||
exception_iterator Exs, bool NoReturn,
|
||||
CallingConv CallConv) {
|
||||
exception_iterator Exs,
|
||||
const FunctionType::ExtInfo &Info) {
|
||||
ID.AddPointer(Result.getAsOpaquePtr());
|
||||
for (unsigned i = 0; i != NumArgs; ++i)
|
||||
ID.AddPointer(ArgTys[i].getAsOpaquePtr());
|
||||
@ -833,15 +854,16 @@ void FunctionProtoType::Profile(llvm::FoldingSetNodeID &ID, QualType Result,
|
||||
for (unsigned i = 0; i != NumExceptions; ++i)
|
||||
ID.AddPointer(Exs[i].getAsOpaquePtr());
|
||||
}
|
||||
ID.AddInteger(NoReturn);
|
||||
ID.AddInteger(CallConv);
|
||||
ID.AddInteger(Info.getNoReturn());
|
||||
ID.AddInteger(Info.getRegParm());
|
||||
ID.AddInteger(Info.getCC());
|
||||
}
|
||||
|
||||
void FunctionProtoType::Profile(llvm::FoldingSetNodeID &ID) {
|
||||
Profile(ID, getResultType(), arg_type_begin(), NumArgs, isVariadic(),
|
||||
getTypeQuals(), hasExceptionSpec(), hasAnyExceptionSpec(),
|
||||
getNumExceptions(), exception_begin(), getNoReturnAttr(),
|
||||
getCallConv());
|
||||
getNumExceptions(), exception_begin(),
|
||||
getExtInfo());
|
||||
}
|
||||
|
||||
void ObjCObjectPointerType::Profile(llvm::FoldingSetNodeID &ID,
|
||||
|
@ -282,7 +282,8 @@ void TypePrinter::PrintFunctionProto(const FunctionProtoType *T,
|
||||
|
||||
S += ")";
|
||||
|
||||
switch(T->getCallConv()) {
|
||||
FunctionType::ExtInfo Info = T->getExtInfo();
|
||||
switch(Info.getCC()) {
|
||||
case CC_Default:
|
||||
default: break;
|
||||
case CC_C:
|
||||
@ -295,9 +296,11 @@ void TypePrinter::PrintFunctionProto(const FunctionProtoType *T,
|
||||
S += " __attribute__((fastcall))";
|
||||
break;
|
||||
}
|
||||
if (T->getNoReturnAttr())
|
||||
if (Info.getNoReturn())
|
||||
S += " __attribute__((noreturn))";
|
||||
|
||||
if (Info.getRegParm())
|
||||
S += " __attribute__((regparm (" +
|
||||
llvm::utostr_32(Info.getRegParm()) + ")))";
|
||||
|
||||
if (T->hasExceptionSpec()) {
|
||||
S += " throw(";
|
||||
@ -564,12 +567,20 @@ void TypePrinter::PrintQualifiedName(const QualifiedNameType *T,
|
||||
S = MyString + ' ' + S;
|
||||
}
|
||||
|
||||
void TypePrinter::PrintTypename(const TypenameType *T, std::string &S) {
|
||||
void TypePrinter::PrintDependentName(const DependentNameType *T, std::string &S) {
|
||||
std::string MyString;
|
||||
|
||||
{
|
||||
llvm::raw_string_ostream OS(MyString);
|
||||
OS << "typename ";
|
||||
switch (T->getKeyword()) {
|
||||
case ETK_None: break;
|
||||
case ETK_Typename: OS << "typename "; break;
|
||||
case ETK_Class: OS << "class "; break;
|
||||
case ETK_Struct: OS << "struct "; break;
|
||||
case ETK_Union: OS << "union "; break;
|
||||
case ETK_Enum: OS << "enum "; break;
|
||||
}
|
||||
|
||||
T->getQualifier()->print(OS, Policy);
|
||||
|
||||
if (const IdentifierInfo *Ident = T->getIdentifier())
|
||||
@ -819,4 +830,3 @@ void QualType::getAsStringInternal(std::string &S,
|
||||
TypePrinter Printer(Policy);
|
||||
Printer.Print(*this, S);
|
||||
}
|
||||
|
||||
|
@ -54,8 +54,12 @@ const ImplicitParamDecl *AnalysisContext::getSelfDecl() const {
|
||||
}
|
||||
|
||||
CFG *AnalysisContext::getCFG() {
|
||||
if (!cfg)
|
||||
if (!builtCFG) {
|
||||
cfg = CFG::buildCFG(D, getBody(), &D->getASTContext(), AddEHEdges);
|
||||
// Even when the cfg is not successfully built, we don't
|
||||
// want to try building it again.
|
||||
builtCFG = true;
|
||||
}
|
||||
return cfg;
|
||||
}
|
||||
|
||||
@ -126,9 +130,9 @@ LocationContextManager::getLocationContext(AnalysisContext *ctx,
|
||||
llvm::FoldingSetNodeID ID;
|
||||
LOC::Profile(ID, ctx, parent, d);
|
||||
void *InsertPos;
|
||||
|
||||
|
||||
LOC *L = cast_or_null<LOC>(Contexts.FindNodeOrInsertPos(ID, InsertPos));
|
||||
|
||||
|
||||
if (!L) {
|
||||
L = new LOC(ctx, parent, d);
|
||||
Contexts.InsertNode(L, InsertPos);
|
||||
@ -144,7 +148,7 @@ LocationContextManager::getStackFrame(AnalysisContext *ctx,
|
||||
llvm::FoldingSetNodeID ID;
|
||||
StackFrameContext::Profile(ID, ctx, parent, s, blk, idx);
|
||||
void *InsertPos;
|
||||
StackFrameContext *L =
|
||||
StackFrameContext *L =
|
||||
cast_or_null<StackFrameContext>(Contexts.FindNodeOrInsertPos(ID, InsertPos));
|
||||
if (!L) {
|
||||
L = new StackFrameContext(ctx, parent, s, blk, idx);
|
||||
@ -253,7 +257,7 @@ public:
|
||||
IgnoredContexts.insert(BR->getBlockDecl());
|
||||
Visit(BR->getBlockDecl()->getBody());
|
||||
}
|
||||
};
|
||||
};
|
||||
} // end anonymous namespace
|
||||
|
||||
typedef BumpVector<const VarDecl*> DeclVec;
|
||||
@ -263,16 +267,16 @@ static DeclVec* LazyInitializeReferencedDecls(const BlockDecl *BD,
|
||||
llvm::BumpPtrAllocator &A) {
|
||||
if (Vec)
|
||||
return (DeclVec*) Vec;
|
||||
|
||||
|
||||
BumpVectorContext BC(A);
|
||||
DeclVec *BV = (DeclVec*) A.Allocate<DeclVec>();
|
||||
new (BV) DeclVec(BC, 10);
|
||||
|
||||
|
||||
// Find the referenced variables.
|
||||
FindBlockDeclRefExprsVals F(*BV, BC);
|
||||
F.Visit(BD->getBody());
|
||||
|
||||
Vec = BV;
|
||||
|
||||
Vec = BV;
|
||||
return BV;
|
||||
}
|
||||
|
||||
@ -281,7 +285,7 @@ std::pair<AnalysisContext::referenced_decls_iterator,
|
||||
AnalysisContext::getReferencedBlockVars(const BlockDecl *BD) {
|
||||
if (!ReferencedBlockVars)
|
||||
ReferencedBlockVars = new llvm::DenseMap<const BlockDecl*,void*>();
|
||||
|
||||
|
||||
DeclVec *V = LazyInitializeReferencedDecls(BD, (*ReferencedBlockVars)[BD], A);
|
||||
return std::make_pair(V->begin(), V->end());
|
||||
}
|
||||
@ -310,12 +314,12 @@ LocationContextManager::~LocationContextManager() {
|
||||
|
||||
void LocationContextManager::clear() {
|
||||
for (llvm::FoldingSet<LocationContext>::iterator I = Contexts.begin(),
|
||||
E = Contexts.end(); I != E; ) {
|
||||
E = Contexts.end(); I != E; ) {
|
||||
LocationContext *LC = &*I;
|
||||
++I;
|
||||
delete LC;
|
||||
}
|
||||
|
||||
|
||||
Contexts.clear();
|
||||
}
|
||||
|
||||
|
@ -571,7 +571,7 @@ static bool CanThrow(Expr *E) {
|
||||
CFGBlock *CFGBuilder::VisitCallExpr(CallExpr *C, AddStmtChoice asc) {
|
||||
// If this is a call to a no-return function, this stops the block here.
|
||||
bool NoReturn = false;
|
||||
if (C->getCallee()->getType().getNoReturnAttr()) {
|
||||
if (getFunctionExtInfo(*C->getCallee()->getType()).getNoReturn()) {
|
||||
NoReturn = true;
|
||||
}
|
||||
|
||||
|
@ -75,7 +75,7 @@ static OptionalAmount ParseAmount(const char *&Beg, const char *E) {
|
||||
char c = *I;
|
||||
if (c >= '0' && c <= '9') {
|
||||
hasDigits = true;
|
||||
accumulator += (accumulator * 10) + (c - '0');
|
||||
accumulator = (accumulator * 10) + (c - '0');
|
||||
continue;
|
||||
}
|
||||
|
||||
|
@ -12,6 +12,7 @@
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
#include "clang/Basic/Diagnostic.h"
|
||||
#include "clang/Basic/PartialDiagnostic.h"
|
||||
|
||||
#include "clang/Lex/LexDiagnostic.h"
|
||||
#include "clang/Parse/ParseDiagnostic.h"
|
||||
@ -124,10 +125,20 @@ const char *Diagnostic::getWarningOptionForDiag(unsigned DiagID) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
bool Diagnostic::isBuiltinSFINAEDiag(unsigned DiagID) {
|
||||
if (const StaticDiagInfoRec *Info = GetDiagInfo(DiagID))
|
||||
return Info->SFINAE && Info->Class == CLASS_ERROR;
|
||||
return false;
|
||||
Diagnostic::SFINAEResponse
|
||||
Diagnostic::getDiagnosticSFINAEResponse(unsigned DiagID) {
|
||||
if (const StaticDiagInfoRec *Info = GetDiagInfo(DiagID)) {
|
||||
if (!Info->SFINAE)
|
||||
return SFINAE_Report;
|
||||
|
||||
if (Info->Class == CLASS_ERROR)
|
||||
return SFINAE_SubstitutionFailure;
|
||||
|
||||
// Suppress notes, warnings, and extensions;
|
||||
return SFINAE_Suppress;
|
||||
}
|
||||
|
||||
return SFINAE_Report;
|
||||
}
|
||||
|
||||
/// getDiagClass - Return the class field of the diagnostic.
|
||||
@ -222,6 +233,8 @@ Diagnostic::Diagnostic(DiagnosticClient *client) : Client(client) {
|
||||
ArgToStringFn = DummyArgToStringFn;
|
||||
ArgToStringCookie = 0;
|
||||
|
||||
DelayedDiagID = 0;
|
||||
|
||||
// Set all mappings to 'unset'.
|
||||
DiagMappings BlankDiags(diag::DIAG_UPPER_LIMIT/2, 0);
|
||||
DiagMappingsStack.push_back(BlankDiags);
|
||||
@ -289,6 +302,23 @@ const char *Diagnostic::getDescription(unsigned DiagID) const {
|
||||
return CustomDiagInfo->getDescription(DiagID);
|
||||
}
|
||||
|
||||
void Diagnostic::SetDelayedDiagnostic(unsigned DiagID, llvm::StringRef Arg1,
|
||||
llvm::StringRef Arg2) {
|
||||
if (DelayedDiagID)
|
||||
return;
|
||||
|
||||
DelayedDiagID = DiagID;
|
||||
DelayedDiagArg1 = Arg1.str();
|
||||
DelayedDiagArg2 = Arg2.str();
|
||||
}
|
||||
|
||||
void Diagnostic::ReportDelayed() {
|
||||
Report(DelayedDiagID) << DelayedDiagArg1 << DelayedDiagArg2;
|
||||
DelayedDiagID = 0;
|
||||
DelayedDiagArg1.clear();
|
||||
DelayedDiagArg2.clear();
|
||||
}
|
||||
|
||||
/// getDiagnosticLevel - Based on the way the client configured the Diagnostic
|
||||
/// object, classify the specified diagnostic ID into a Level, consumable by
|
||||
/// the DiagnosticClient.
|
||||
@ -532,6 +562,35 @@ bool Diagnostic::ProcessDiag() {
|
||||
return true;
|
||||
}
|
||||
|
||||
bool DiagnosticBuilder::Emit() {
|
||||
// If DiagObj is null, then its soul was stolen by the copy ctor
|
||||
// or the user called Emit().
|
||||
if (DiagObj == 0) return false;
|
||||
|
||||
// When emitting diagnostics, we set the final argument count into
|
||||
// the Diagnostic object.
|
||||
DiagObj->NumDiagArgs = NumArgs;
|
||||
DiagObj->NumDiagRanges = NumRanges;
|
||||
DiagObj->NumFixItHints = NumFixItHints;
|
||||
|
||||
// Process the diagnostic, sending the accumulated information to the
|
||||
// DiagnosticClient.
|
||||
bool Emitted = DiagObj->ProcessDiag();
|
||||
|
||||
// Clear out the current diagnostic object.
|
||||
unsigned DiagID = DiagObj->CurDiagID;
|
||||
DiagObj->Clear();
|
||||
|
||||
// If there was a delayed diagnostic, emit it now.
|
||||
if (DiagObj->DelayedDiagID && DiagObj->DelayedDiagID != DiagID)
|
||||
DiagObj->ReportDelayed();
|
||||
|
||||
// This diagnostic is dead.
|
||||
DiagObj = 0;
|
||||
|
||||
return Emitted;
|
||||
}
|
||||
|
||||
|
||||
DiagnosticClient::~DiagnosticClient() {}
|
||||
|
||||
@ -937,9 +996,9 @@ StoredDiagnostic::StoredDiagnostic(Diagnostic::Level Level,
|
||||
for (unsigned I = 0, N = Info.getNumRanges(); I != N; ++I)
|
||||
Ranges.push_back(Info.getRange(I));
|
||||
|
||||
FixIts.reserve(Info.getNumCodeModificationHints());
|
||||
for (unsigned I = 0, N = Info.getNumCodeModificationHints(); I != N; ++I)
|
||||
FixIts.push_back(Info.getCodeModificationHint(I));
|
||||
FixIts.reserve(Info.getNumFixItHints());
|
||||
for (unsigned I = 0, N = Info.getNumFixItHints(); I != N; ++I)
|
||||
FixIts.push_back(Info.getFixItHint(I));
|
||||
}
|
||||
|
||||
StoredDiagnostic::~StoredDiagnostic() { }
|
||||
@ -1172,7 +1231,7 @@ StoredDiagnostic::Deserialize(FileManager &FM, SourceManager &SM,
|
||||
return Diag;
|
||||
}
|
||||
|
||||
CodeModificationHint Hint;
|
||||
FixItHint Hint;
|
||||
Hint.RemoveRange = SourceRange(RemoveBegin, RemoveEnd);
|
||||
Hint.InsertionLoc = InsertionLoc;
|
||||
Hint.CodeToInsert.assign(Memory, Memory + InsertLen);
|
||||
@ -1188,3 +1247,13 @@ StoredDiagnostic::Deserialize(FileManager &FM, SourceManager &SM,
|
||||
/// DiagnosticClient should be included in the number of diagnostics
|
||||
/// reported by Diagnostic.
|
||||
bool DiagnosticClient::IncludeInDiagnosticCounts() const { return true; }
|
||||
|
||||
PartialDiagnostic::StorageAllocator::StorageAllocator() {
|
||||
for (unsigned I = 0; I != NumCached; ++I)
|
||||
FreeList[I] = Cached + I;
|
||||
NumFreeListEntries = NumCached;
|
||||
}
|
||||
|
||||
PartialDiagnostic::StorageAllocator::~StorageAllocator() {
|
||||
assert(NumFreeListEntries == NumCached && "A partial is on the lamb");
|
||||
}
|
||||
|
@ -89,16 +89,26 @@ const llvm::MemoryBuffer *ContentCache::getBuffer(Diagnostic &Diag,
|
||||
char *Ptr = const_cast<char*>(Buffer.getPointer()->getBufferStart());
|
||||
for (unsigned i = 0, e = Entry->getSize(); i != e; ++i)
|
||||
Ptr[i] = FillStr[i % FillStr.size()];
|
||||
Diag.Report(diag::err_cannot_open_file)
|
||||
<< Entry->getName() << ErrorStr;
|
||||
|
||||
if (Diag.isDiagnosticInFlight())
|
||||
Diag.SetDelayedDiagnostic(diag::err_cannot_open_file,
|
||||
Entry->getName(), ErrorStr);
|
||||
else
|
||||
Diag.Report(diag::err_cannot_open_file)
|
||||
<< Entry->getName() << ErrorStr;
|
||||
|
||||
Buffer.setInt(true);
|
||||
} else if (FileInfo.st_size != Entry->getSize() ||
|
||||
FileInfo.st_mtime != Entry->getModificationTime() ||
|
||||
FileInfo.st_ino != Entry->getInode()) {
|
||||
FileInfo.st_mtime != Entry->getModificationTime()) {
|
||||
// Check that the file's size, modification time, and inode are
|
||||
// the same as in the file entry (which may have come from a
|
||||
// stat cache).
|
||||
Diag.Report(diag::err_file_modified) << Entry->getName();
|
||||
if (Diag.isDiagnosticInFlight())
|
||||
Diag.SetDelayedDiagnostic(diag::err_file_modified,
|
||||
Entry->getName());
|
||||
else
|
||||
Diag.Report(diag::err_file_modified) << Entry->getName();
|
||||
|
||||
Buffer.setInt(true);
|
||||
}
|
||||
}
|
||||
|
@ -292,6 +292,7 @@ protected:
|
||||
virtual void getOSDefines(const LangOptions &Opts, const llvm::Triple &Triple,
|
||||
MacroBuilder &Builder) const {
|
||||
// PS3 PPU defines.
|
||||
Builder.defineMacro("__PPC__");
|
||||
Builder.defineMacro("__PPU__");
|
||||
Builder.defineMacro("__CELLOS_LV2__");
|
||||
Builder.defineMacro("__ELF__");
|
||||
|
@ -14,11 +14,9 @@
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
#include "GRExprEngineInternalChecks.h"
|
||||
#include "clang/Checker/PathSensitive/GRExprEngine.h"
|
||||
#include "clang/Checker/BugReporter/BugReporter.h"
|
||||
#include "clang/Checker/PathSensitive/GRExprEngine.h"
|
||||
#include "clang/Checker/PathSensitive/CheckerVisitor.h"
|
||||
#include "clang/Basic/SourceManager.h"
|
||||
#include "llvm/ADT/SmallString.h"
|
||||
|
||||
using namespace clang;
|
||||
|
||||
|
55
lib/Checker/AggExprVisitor.cpp
Normal file
55
lib/Checker/AggExprVisitor.cpp
Normal file
@ -0,0 +1,55 @@
|
||||
//=-- AggExprVisitor.cpp - evaluating expressions of C++ class type -*- C++ -*-=
|
||||
//
|
||||
// The LLVM Compiler Infrastructure
|
||||
//
|
||||
// This file is distributed under the University of Illinois Open Source
|
||||
// License. See LICENSE.TXT for details.
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
//
|
||||
// This file defines AggExprVisitor class, which contains lots of boiler
|
||||
// plate code for evaluating expressions of C++ class type.
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
#include "clang/Checker/PathSensitive/GRExprEngine.h"
|
||||
#include "clang/AST/StmtVisitor.h"
|
||||
|
||||
using namespace clang;
|
||||
|
||||
namespace {
|
||||
class AggExprVisitor : public StmtVisitor<AggExprVisitor> {
|
||||
SVal DestPtr;
|
||||
ExplodedNode *Pred;
|
||||
ExplodedNodeSet &DstSet;
|
||||
GRExprEngine &Eng;
|
||||
|
||||
public:
|
||||
AggExprVisitor(SVal dest, ExplodedNode *N, ExplodedNodeSet &dst,
|
||||
GRExprEngine &eng)
|
||||
: DestPtr(dest), Pred(N), DstSet(dst), Eng(eng) {}
|
||||
|
||||
void VisitCastExpr(CastExpr *E);
|
||||
void VisitCXXConstructExpr(CXXConstructExpr *E);
|
||||
};
|
||||
}
|
||||
|
||||
void AggExprVisitor::VisitCastExpr(CastExpr *E) {
|
||||
switch (E->getCastKind()) {
|
||||
default:
|
||||
assert(0 && "Unhandled cast kind");
|
||||
case CastExpr::CK_NoOp:
|
||||
case CastExpr::CK_ConstructorConversion:
|
||||
Visit(E->getSubExpr());
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
void AggExprVisitor::VisitCXXConstructExpr(CXXConstructExpr *E) {
|
||||
Eng.VisitCXXConstructExpr(E, DestPtr, Pred, DstSet);
|
||||
}
|
||||
|
||||
void GRExprEngine::VisitAggExpr(const Expr *E, SVal Dest, ExplodedNode *Pred,
|
||||
ExplodedNodeSet &Dst) {
|
||||
AggExprVisitor(Dest, Pred, Dst, *this).Visit(const_cast<Expr *>(E));
|
||||
}
|
@ -13,9 +13,9 @@
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
#include "GRExprEngineInternalChecks.h"
|
||||
#include "clang/Checker/PathSensitive/GRExprEngine.h"
|
||||
#include "clang/Checker/BugReporter/BugReporter.h"
|
||||
#include "clang/Checker/BugReporter/BugType.h"
|
||||
#include "clang/Checker/PathSensitive/CheckerVisitor.h"
|
||||
#include "clang/Checker/PathSensitive/GRExprEngine.h"
|
||||
|
||||
using namespace clang;
|
||||
|
||||
|
@ -12,9 +12,9 @@
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
#include "clang/Checker/PathSensitive/CheckerVisitor.h"
|
||||
#include "clang/Checker/BugReporter/BugReporter.h"
|
||||
#include "GRExprEngineInternalChecks.h"
|
||||
#include "clang/Checker/BugReporter/BugType.h"
|
||||
#include "clang/Checker/PathSensitive/CheckerVisitor.h"
|
||||
|
||||
using namespace clang;
|
||||
|
||||
|
@ -19,9 +19,8 @@
|
||||
#include "clang/Checker/PathSensitive/GRSimpleAPICheck.h"
|
||||
#include "clang/Checker/PathSensitive/GRExprEngine.h"
|
||||
#include "clang/Checker/PathSensitive/GRState.h"
|
||||
#include "clang/Checker/BugReporter/BugReporter.h"
|
||||
#include "clang/Checker/BugReporter/BugType.h"
|
||||
#include "clang/Checker/PathSensitive/MemRegion.h"
|
||||
#include "clang/Checker/BugReporter/PathDiagnostic.h"
|
||||
#include "clang/Checker/PathSensitive/CheckerVisitor.h"
|
||||
#include "clang/Checker/Checkers/LocalCheckers.h"
|
||||
#include "clang/AST/DeclObjC.h"
|
||||
|
@ -13,6 +13,7 @@
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
#include "clang/Checker/BugReporter/BugReporter.h"
|
||||
#include "clang/Checker/BugReporter/BugType.h"
|
||||
#include "clang/Checker/PathSensitive/GRExprEngine.h"
|
||||
#include "clang/AST/ASTContext.h"
|
||||
#include "clang/Analysis/CFG.h"
|
||||
@ -1139,12 +1140,9 @@ void EdgeBuilder::addContext(const Stmt *S) {
|
||||
static void GenerateExtensivePathDiagnostic(PathDiagnostic& PD,
|
||||
PathDiagnosticBuilder &PDB,
|
||||
const ExplodedNode *N) {
|
||||
|
||||
|
||||
EdgeBuilder EB(PD, PDB);
|
||||
|
||||
const ExplodedNode* NextNode = N->pred_empty()
|
||||
? NULL : *(N->pred_begin());
|
||||
const ExplodedNode* NextNode = N->pred_empty() ? NULL : *(N->pred_begin());
|
||||
while (NextNode) {
|
||||
N = NextNode;
|
||||
NextNode = GetPredecessorNode(N);
|
||||
|
@ -16,6 +16,7 @@
|
||||
#include "clang/AST/ExprObjC.h"
|
||||
#include "clang/Checker/BugReporter/BugReporter.h"
|
||||
#include "clang/Checker/BugReporter/PathDiagnostic.h"
|
||||
#include "clang/Checker/PathSensitive/ExplodedGraph.h"
|
||||
#include "clang/Checker/PathSensitive/GRState.h"
|
||||
|
||||
using namespace clang;
|
||||
|
@ -16,8 +16,7 @@
|
||||
#include "clang/AST/StmtVisitor.h"
|
||||
#include "clang/Basic/LangOptions.h"
|
||||
#include "clang/Basic/SourceManager.h"
|
||||
#include "clang/Checker/BugReporter/BugReporter.h"
|
||||
#include "clang/Checker/BugReporter/PathDiagnostic.h"
|
||||
#include "clang/Checker/BugReporter/BugType.h"
|
||||
#include "clang/Checker/BugReporter/PathDiagnostic.h"
|
||||
#include "clang/Checker/Checkers/LocalCheckers.h"
|
||||
#include "clang/Checker/DomainSpecific/CocoaConventions.h"
|
||||
|
@ -2,6 +2,7 @@ set(LLVM_NO_RTTI 1)
|
||||
|
||||
add_clang_library(clangChecker
|
||||
AdjustedReturnValueChecker.cpp
|
||||
AggExprVisitor.cpp
|
||||
ArrayBoundChecker.cpp
|
||||
AttrNonNullChecker.cpp
|
||||
BasicConstraintManager.cpp
|
||||
@ -11,16 +12,16 @@ add_clang_library(clangChecker
|
||||
BugReporter.cpp
|
||||
BugReporterVisitors.cpp
|
||||
BuiltinFunctionChecker.cpp
|
||||
CFRefCount.cpp
|
||||
CallAndMessageChecker.cpp
|
||||
CallInliner.cpp
|
||||
CastToStructChecker.cpp
|
||||
CFRefCount.cpp
|
||||
CheckDeadStores.cpp
|
||||
Checker.cpp
|
||||
CheckObjCDealloc.cpp
|
||||
CheckObjCInstMethSignature.cpp
|
||||
CheckSecuritySyntaxOnly.cpp
|
||||
CheckSizeofPointer.cpp
|
||||
Checker.cpp
|
||||
CocoaConventions.cpp
|
||||
DereferenceChecker.cpp
|
||||
DivZeroChecker.cpp
|
||||
@ -38,11 +39,11 @@ add_clang_library(clangChecker
|
||||
MallocChecker.cpp
|
||||
ManagerRegistry.cpp
|
||||
MemRegion.cpp
|
||||
NoReturnFunctionChecker.cpp
|
||||
NSAutoreleasePoolChecker.cpp
|
||||
NSErrorChecker.cpp
|
||||
NoReturnFunctionChecker.cpp
|
||||
OSAtomicChecker.cpp
|
||||
ObjCUnusedIVarsChecker.cpp
|
||||
OSAtomicChecker.cpp
|
||||
PathDiagnostic.cpp
|
||||
PointerArithChecker.cpp
|
||||
PointerSubChecker.cpp
|
||||
@ -52,18 +53,18 @@ add_clang_library(clangChecker
|
||||
ReturnPointerRangeChecker.cpp
|
||||
ReturnStackAddressChecker.cpp
|
||||
ReturnUndefChecker.cpp
|
||||
SVals.cpp
|
||||
SValuator.cpp
|
||||
SimpleConstraintManager.cpp
|
||||
SimpleSValuator.cpp
|
||||
Store.cpp
|
||||
SVals.cpp
|
||||
SValuator.cpp
|
||||
SymbolManager.cpp
|
||||
UndefBranchChecker.cpp
|
||||
UndefCapturedBlockVarChecker.cpp
|
||||
UndefResultChecker.cpp
|
||||
UndefinedArraySubscriptChecker.cpp
|
||||
UndefinedAssignmentChecker.cpp
|
||||
UndefResultChecker.cpp
|
||||
UnixAPIChecker.cpp
|
||||
VLASizeChecker.cpp
|
||||
ValueManager.cpp
|
||||
VLASizeChecker.cpp
|
||||
)
|
||||
|
@ -12,11 +12,11 @@
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
#include "clang/Basic/TargetInfo.h"
|
||||
#include "clang/Checker/PathSensitive/CheckerVisitor.h"
|
||||
#include "clang/Checker/BugReporter/BugReporter.h"
|
||||
#include "clang/AST/ParentMap.h"
|
||||
#include "GRExprEngineInternalChecks.h"
|
||||
#include "clang/AST/ParentMap.h"
|
||||
#include "clang/Basic/TargetInfo.h"
|
||||
#include "clang/Checker/BugReporter/BugType.h"
|
||||
#include "clang/Checker/PathSensitive/CheckerVisitor.h"
|
||||
|
||||
using namespace clang;
|
||||
|
||||
|
@ -13,6 +13,7 @@
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
#include "clang/Checker/BugReporter/BugType.h"
|
||||
#include "clang/Checker/PathSensitive/CheckerVisitor.h"
|
||||
#include "GRExprEngineInternalChecks.h"
|
||||
|
||||
|
@ -36,7 +36,7 @@ class WalkAST : public StmtVisitor<WalkAST> {
|
||||
IdentifierInfo *II_random;
|
||||
enum { num_setids = 6 };
|
||||
IdentifierInfo *II_setid[num_setids];
|
||||
|
||||
|
||||
const bool CheckRand;
|
||||
|
||||
public:
|
||||
@ -214,8 +214,8 @@ void WalkAST::CheckLoopConditionForFloat(const ForStmt *FS) {
|
||||
const DeclRefExpr *drCond = vdLHS == drInc->getDecl() ? drLHS : drRHS;
|
||||
|
||||
llvm::SmallVector<SourceRange, 2> ranges;
|
||||
std::string sbuf;
|
||||
llvm::raw_string_ostream os(sbuf);
|
||||
llvm::SmallString<256> sbuf;
|
||||
llvm::raw_svector_ostream os(sbuf);
|
||||
|
||||
os << "Variable '" << drCond->getDecl()->getNameAsCString()
|
||||
<< "' with floating point type '" << drCond->getType().getAsString()
|
||||
@ -315,7 +315,7 @@ void WalkAST::CheckCall_mktemp(const CallExpr *CE, const FunctionDecl *FD) {
|
||||
const FunctionProtoType *FPT = dyn_cast<FunctionProtoType>(FD->getType());
|
||||
if(!FPT)
|
||||
return;
|
||||
|
||||
|
||||
// Verify that the funcion takes a single argument.
|
||||
if (FPT->getNumArgs() != 1)
|
||||
return;
|
||||
@ -328,17 +328,16 @@ void WalkAST::CheckCall_mktemp(const CallExpr *CE, const FunctionDecl *FD) {
|
||||
// Verify that the argument is a 'char*'.
|
||||
if (PT->getPointeeType().getUnqualifiedType() != BR.getContext().CharTy)
|
||||
return;
|
||||
|
||||
|
||||
// Issue a waring.
|
||||
SourceRange R = CE->getCallee()->getSourceRange();
|
||||
BR.EmitBasicReport("Potential insecure temporary file in call 'mktemp'",
|
||||
"Security",
|
||||
"Call to function 'mktemp' is insecure as it always "
|
||||
"creates or uses insecure temporary file",
|
||||
"creates or uses insecure temporary file. Use 'mkstemp' instead",
|
||||
CE->getLocStart(), &R, 1);
|
||||
}
|
||||
|
||||
|
||||
//===----------------------------------------------------------------------===//
|
||||
// Check: Linear congruent random number generators should not be used
|
||||
// Originally: <rdar://problem/63371000>
|
||||
@ -386,20 +385,18 @@ void WalkAST::CheckCall_rand(const CallExpr *CE, const FunctionDecl *FD) {
|
||||
return;
|
||||
|
||||
// Issue a warning.
|
||||
std::string buf1;
|
||||
llvm::raw_string_ostream os1(buf1);
|
||||
llvm::SmallString<256> buf1;
|
||||
llvm::raw_svector_ostream os1(buf1);
|
||||
os1 << "'" << FD->getNameAsString() << "' is a poor random number generator";
|
||||
|
||||
std::string buf2;
|
||||
llvm::raw_string_ostream os2(buf2);
|
||||
llvm::SmallString<256> buf2;
|
||||
llvm::raw_svector_ostream os2(buf2);
|
||||
os2 << "Function '" << FD->getNameAsString()
|
||||
<< "' is obsolete because it implements a poor random number generator."
|
||||
<< " Use 'arc4random' instead";
|
||||
|
||||
SourceRange R = CE->getCallee()->getSourceRange();
|
||||
|
||||
BR.EmitBasicReport(os1.str(), "Security", os2.str(),
|
||||
CE->getLocStart(), &R, 1);
|
||||
BR.EmitBasicReport(os1.str(), "Security", os2.str(),CE->getLocStart(), &R, 1);
|
||||
}
|
||||
|
||||
//===----------------------------------------------------------------------===//
|
||||
@ -425,8 +422,7 @@ void WalkAST::CheckCall_random(const CallExpr *CE, const FunctionDecl *FD) {
|
||||
"Security",
|
||||
"The 'random' function produces a sequence of values that "
|
||||
"an adversary may be able to predict. Use 'arc4random' "
|
||||
"instead",
|
||||
CE->getLocStart(), &R, 1);
|
||||
"instead", CE->getLocStart(), &R, 1);
|
||||
}
|
||||
|
||||
//===----------------------------------------------------------------------===//
|
||||
@ -474,22 +470,20 @@ void WalkAST::CheckUncheckedReturnValue(CallExpr *CE) {
|
||||
return;
|
||||
|
||||
// Issue a warning.
|
||||
std::string buf1;
|
||||
llvm::raw_string_ostream os1(buf1);
|
||||
llvm::SmallString<256> buf1;
|
||||
llvm::raw_svector_ostream os1(buf1);
|
||||
os1 << "Return value is not checked in call to '" << FD->getNameAsString()
|
||||
<< "'";
|
||||
|
||||
std::string buf2;
|
||||
llvm::raw_string_ostream os2(buf2);
|
||||
llvm::SmallString<256> buf2;
|
||||
llvm::raw_svector_ostream os2(buf2);
|
||||
os2 << "The return value from the call to '" << FD->getNameAsString()
|
||||
<< "' is not checked. If an error occurs in '"
|
||||
<< FD->getNameAsString()
|
||||
<< "', the following code may execute with unexpected privileges";
|
||||
|
||||
SourceRange R = CE->getCallee()->getSourceRange();
|
||||
|
||||
BR.EmitBasicReport(os1.str(), "Security", os2.str(),
|
||||
CE->getLocStart(), &R, 1);
|
||||
BR.EmitBasicReport(os1.str(), "Security", os2.str(),CE->getLocStart(), &R, 1);
|
||||
}
|
||||
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
@ -12,11 +12,11 @@
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
#include "GRExprEngineInternalChecks.h"
|
||||
#include "clang/Checker/BugReporter/BugType.h"
|
||||
#include "clang/Checker/Checkers/DereferenceChecker.h"
|
||||
#include "clang/Checker/PathSensitive/Checker.h"
|
||||
#include "clang/Checker/PathSensitive/GRExprEngine.h"
|
||||
#include "clang/Checker/BugReporter/BugReporter.h"
|
||||
#include "GRExprEngineInternalChecks.h"
|
||||
|
||||
using namespace clang;
|
||||
|
||||
@ -29,9 +29,9 @@ public:
|
||||
DereferenceChecker() : BT_null(0), BT_undef(0) {}
|
||||
static void *getTag() { static int tag = 0; return &tag; }
|
||||
void VisitLocation(CheckerContext &C, const Stmt *S, SVal location);
|
||||
|
||||
|
||||
std::pair<ExplodedNode * const*, ExplodedNode * const*>
|
||||
getImplicitNodes() const {
|
||||
getImplicitNodes() const {
|
||||
return std::make_pair(ImplicitNullDerefNodes.data(),
|
||||
ImplicitNullDerefNodes.data() +
|
||||
ImplicitNullDerefNodes.size());
|
||||
@ -59,7 +59,7 @@ void DereferenceChecker::VisitLocation(CheckerContext &C, const Stmt *S,
|
||||
if (ExplodedNode *N = C.GenerateSink()) {
|
||||
if (!BT_undef)
|
||||
BT_undef = new BuiltinBug("Dereference of undefined pointer value");
|
||||
|
||||
|
||||
EnhancedBugReport *report =
|
||||
new EnhancedBugReport(*BT_undef, BT_undef->getDescription(), N);
|
||||
report->addVisitorCreator(bugreporter::registerTrackNullOrUndefValue,
|
||||
@ -68,31 +68,32 @@ void DereferenceChecker::VisitLocation(CheckerContext &C, const Stmt *S,
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
DefinedOrUnknownSVal location = cast<DefinedOrUnknownSVal>(l);
|
||||
|
||||
// Check for null dereferences.
|
||||
|
||||
// Check for null dereferences.
|
||||
if (!isa<Loc>(location))
|
||||
return;
|
||||
|
||||
|
||||
const GRState *state = C.getState();
|
||||
const GRState *notNullState, *nullState;
|
||||
llvm::tie(notNullState, nullState) = state->Assume(location);
|
||||
|
||||
|
||||
// The explicit NULL case.
|
||||
if (nullState) {
|
||||
if (!notNullState) {
|
||||
if (!notNullState) {
|
||||
// Generate an error node.
|
||||
ExplodedNode *N = C.GenerateSink(nullState);
|
||||
if (!N)
|
||||
return;
|
||||
|
||||
|
||||
// We know that 'location' cannot be non-null. This is what
|
||||
// we call an "explicit" null dereference.
|
||||
// we call an "explicit" null dereference.
|
||||
if (!BT_null)
|
||||
BT_null = new BuiltinBug("Dereference of null pointer");
|
||||
|
||||
|
||||
llvm::SmallString<100> buf;
|
||||
llvm::SmallVector<SourceRange, 2> Ranges;
|
||||
|
||||
switch (S->getStmtClass()) {
|
||||
case Stmt::UnaryOperatorClass: {
|
||||
@ -101,10 +102,26 @@ void DereferenceChecker::VisitLocation(CheckerContext &C, const Stmt *S,
|
||||
if (const DeclRefExpr *DR = dyn_cast<DeclRefExpr>(SU)) {
|
||||
if (const VarDecl *VD = dyn_cast<VarDecl>(DR->getDecl())) {
|
||||
llvm::raw_svector_ostream os(buf);
|
||||
os << "Dereference of null pointer loaded from variable '"
|
||||
<< VD->getName() << '\'';
|
||||
os << "Dereference of null pointer (loaded from variable '"
|
||||
<< VD->getName() << "')";
|
||||
Ranges.push_back(DR->getSourceRange());
|
||||
}
|
||||
}
|
||||
break;
|
||||
}
|
||||
case Stmt::MemberExprClass: {
|
||||
const MemberExpr *M = cast<MemberExpr>(S);
|
||||
if (M->isArrow())
|
||||
if (DeclRefExpr *DR =
|
||||
dyn_cast<DeclRefExpr>(M->getBase()->IgnoreParenCasts())) {
|
||||
if (const VarDecl *VD = dyn_cast<VarDecl>(DR->getDecl())) {
|
||||
llvm::raw_svector_ostream os(buf);
|
||||
os << "Field access results in a dereference of a null pointer "
|
||||
"(loaded from variable '" << VD->getName() << "')";
|
||||
Ranges.push_back(M->getBase()->getSourceRange());
|
||||
}
|
||||
}
|
||||
break;
|
||||
}
|
||||
default:
|
||||
break;
|
||||
@ -117,19 +134,23 @@ void DereferenceChecker::VisitLocation(CheckerContext &C, const Stmt *S,
|
||||
|
||||
report->addVisitorCreator(bugreporter::registerTrackNullOrUndefValue,
|
||||
bugreporter::GetDerefExpr(N));
|
||||
|
||||
|
||||
for (llvm::SmallVectorImpl<SourceRange>::iterator
|
||||
I = Ranges.begin(), E = Ranges.end(); I!=E; ++I)
|
||||
report->addRange(*I);
|
||||
|
||||
C.EmitReport(report);
|
||||
return;
|
||||
}
|
||||
else {
|
||||
// Otherwise, we have the case where the location could either be
|
||||
// null or not-null. Record the error node as an "implicit" null
|
||||
// dereference.
|
||||
// dereference.
|
||||
if (ExplodedNode *N = C.GenerateSink(nullState))
|
||||
ImplicitNullDerefNodes.push_back(N);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
// From this point forward, we know that the location is not null.
|
||||
C.addTransition(notNullState);
|
||||
}
|
||||
|
@ -12,8 +12,9 @@
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
#include "clang/Checker/PathSensitive/CheckerVisitor.h"
|
||||
#include "GRExprEngineInternalChecks.h"
|
||||
#include "clang/Checker/BugReporter/BugType.h"
|
||||
#include "clang/Checker/PathSensitive/CheckerVisitor.h"
|
||||
|
||||
using namespace clang;
|
||||
|
||||
|
@ -10,9 +10,10 @@
|
||||
// This file defined the Environment and EnvironmentManager classes.
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
#include "clang/Analysis/AnalysisContext.h"
|
||||
#include "clang/Analysis/CFG.h"
|
||||
#include "clang/Checker/PathSensitive/GRState.h"
|
||||
#include "clang/Analysis/Analyses/LiveVariables.h"
|
||||
#include "llvm/ADT/ImmutableMap.h"
|
||||
|
||||
using namespace clang;
|
||||
|
||||
|
@ -13,8 +13,9 @@
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
#include "clang/Checker/PathSensitive/CheckerVisitor.h"
|
||||
#include "GRExprEngineInternalChecks.h"
|
||||
#include "clang/Checker/BugReporter/BugType.h"
|
||||
#include "clang/Checker/PathSensitive/CheckerVisitor.h"
|
||||
|
||||
using namespace clang;
|
||||
|
||||
|
@ -18,7 +18,34 @@
|
||||
|
||||
using namespace clang;
|
||||
|
||||
typedef llvm::ImmutableMap<unsigned,unsigned> CountMap;
|
||||
namespace {
|
||||
|
||||
class CountKey {
|
||||
const StackFrameContext *CallSite;
|
||||
unsigned BlockID;
|
||||
|
||||
public:
|
||||
CountKey(const StackFrameContext *CS, unsigned ID)
|
||||
: CallSite(CS), BlockID(ID) {}
|
||||
|
||||
bool operator==(const CountKey &RHS) const {
|
||||
return (CallSite == RHS.CallSite) && (BlockID == RHS.BlockID);
|
||||
}
|
||||
|
||||
bool operator<(const CountKey &RHS) const {
|
||||
return (CallSite == RHS.CallSite) ? (BlockID < RHS.BlockID)
|
||||
: (CallSite < RHS.CallSite);
|
||||
}
|
||||
|
||||
void Profile(llvm::FoldingSetNodeID &ID) const {
|
||||
ID.AddPointer(CallSite);
|
||||
ID.AddInteger(BlockID);
|
||||
}
|
||||
};
|
||||
|
||||
}
|
||||
|
||||
typedef llvm::ImmutableMap<CountKey, unsigned> CountMap;
|
||||
|
||||
static inline CountMap GetMap(void* D) {
|
||||
return CountMap(static_cast<CountMap::TreeTy*>(D));
|
||||
@ -28,9 +55,10 @@ static inline CountMap::Factory& GetFactory(void* F) {
|
||||
return *static_cast<CountMap::Factory*>(F);
|
||||
}
|
||||
|
||||
unsigned GRBlockCounter::getNumVisited(unsigned BlockID) const {
|
||||
unsigned GRBlockCounter::getNumVisited(const StackFrameContext *CallSite,
|
||||
unsigned BlockID) const {
|
||||
CountMap M = GetMap(Data);
|
||||
CountMap::data_type* T = M.lookup(BlockID);
|
||||
CountMap::data_type* T = M.lookup(CountKey(CallSite, BlockID));
|
||||
return T ? *T : 0;
|
||||
}
|
||||
|
||||
@ -43,9 +71,12 @@ GRBlockCounter::Factory::~Factory() {
|
||||
}
|
||||
|
||||
GRBlockCounter
|
||||
GRBlockCounter::Factory::IncrementCount(GRBlockCounter BC, unsigned BlockID) {
|
||||
return GRBlockCounter(GetFactory(F).Add(GetMap(BC.Data), BlockID,
|
||||
BC.getNumVisited(BlockID)+1).getRoot());
|
||||
GRBlockCounter::Factory::IncrementCount(GRBlockCounter BC,
|
||||
const StackFrameContext *CallSite,
|
||||
unsigned BlockID) {
|
||||
return GRBlockCounter(GetFactory(F).Add(GetMap(BC.Data),
|
||||
CountKey(CallSite, BlockID),
|
||||
BC.getNumVisited(CallSite, BlockID)+1).getRoot());
|
||||
}
|
||||
|
||||
GRBlockCounter
|
||||
|
@ -126,9 +126,9 @@ void GRCoreEngine::ProcessStmt(CFGElement E, GRStmtNodeBuilder& Builder) {
|
||||
SubEngine.ProcessStmt(E, Builder);
|
||||
}
|
||||
|
||||
bool GRCoreEngine::ProcessBlockEntrance(CFGBlock* Blk, const GRState* State,
|
||||
bool GRCoreEngine::ProcessBlockEntrance(CFGBlock* Blk, const ExplodedNode *Pred,
|
||||
GRBlockCounter BC) {
|
||||
return SubEngine.ProcessBlockEntrance(Blk, State, BC);
|
||||
return SubEngine.ProcessBlockEntrance(Blk, Pred, BC);
|
||||
}
|
||||
|
||||
void GRCoreEngine::ProcessBranch(Stmt* Condition, Stmt* Terminator,
|
||||
@ -256,7 +256,7 @@ void GRCoreEngine::HandleBlockEdge(const BlockEdge& L, ExplodedNode* Pred) {
|
||||
|
||||
// FIXME: Should we allow ProcessBlockEntrance to also manipulate state?
|
||||
|
||||
if (ProcessBlockEntrance(Blk, Pred->State, WList->getBlockCounter()))
|
||||
if (ProcessBlockEntrance(Blk, Pred, WList->getBlockCounter()))
|
||||
GenerateNode(BlockEntrance(Blk, Pred->getLocationContext()), Pred->State, Pred);
|
||||
}
|
||||
|
||||
@ -265,7 +265,9 @@ void GRCoreEngine::HandleBlockEntrance(const BlockEntrance& L,
|
||||
|
||||
// Increment the block counter.
|
||||
GRBlockCounter Counter = WList->getBlockCounter();
|
||||
Counter = BCounterFactory.IncrementCount(Counter, L.getBlock()->getBlockID());
|
||||
Counter = BCounterFactory.IncrementCount(Counter,
|
||||
Pred->getLocationContext()->getCurrentStackFrame(),
|
||||
L.getBlock()->getBlockID());
|
||||
WList->setBlockCounter(Counter);
|
||||
|
||||
// Process the entrance of the block.
|
||||
|
@ -13,6 +13,8 @@
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
#include "GRExprEngineInternalChecks.h"
|
||||
#include "clang/Checker/BugReporter/BugType.h"
|
||||
#include "clang/Checker/PathSensitive/AnalysisManager.h"
|
||||
#include "clang/Checker/PathSensitive/GRExprEngine.h"
|
||||
#include "clang/Checker/PathSensitive/GRExprEngineBuilders.h"
|
||||
#include "clang/Checker/PathSensitive/Checker.h"
|
||||
@ -582,7 +584,6 @@ void GRExprEngine::Visit(Stmt* S, ExplodedNode* Pred, ExplodedNodeSet& Dst) {
|
||||
|
||||
switch (S->getStmtClass()) {
|
||||
// C++ stuff we don't support yet.
|
||||
case Stmt::CXXMemberCallExprClass:
|
||||
case Stmt::CXXNamedCastExprClass:
|
||||
case Stmt::CXXStaticCastExprClass:
|
||||
case Stmt::CXXDynamicCastExprClass:
|
||||
@ -671,6 +672,12 @@ void GRExprEngine::Visit(Stmt* S, ExplodedNode* Pred, ExplodedNodeSet& Dst) {
|
||||
break;
|
||||
}
|
||||
|
||||
case Stmt::CXXMemberCallExprClass: {
|
||||
CXXMemberCallExpr *MCE = cast<CXXMemberCallExpr>(S);
|
||||
VisitCXXMemberCallExpr(MCE, Pred, Dst);
|
||||
break;
|
||||
}
|
||||
|
||||
// FIXME: ChooseExpr is really a constant. We need to fix
|
||||
// the CFG do not model them as explicit control-flow.
|
||||
|
||||
@ -895,6 +902,11 @@ void GRExprEngine::VisitLValue(Expr* Ex, ExplodedNode* Pred,
|
||||
return;
|
||||
}
|
||||
|
||||
case Stmt::ObjCIsaExprClass:
|
||||
// FIXME: Do something more intelligent with 'x->isa = ...'.
|
||||
// For now, just ignore the assignment.
|
||||
return;
|
||||
|
||||
case Stmt::ObjCPropertyRefExprClass:
|
||||
case Stmt::ObjCImplicitSetterGetterRefExprClass:
|
||||
// FIXME: Property assignments are lvalues, but not really "locations".
|
||||
@ -944,10 +956,11 @@ void GRExprEngine::VisitLValue(Expr* Ex, ExplodedNode* Pred,
|
||||
// Block entrance. (Update counters).
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
bool GRExprEngine::ProcessBlockEntrance(CFGBlock* B, const GRState*,
|
||||
bool GRExprEngine::ProcessBlockEntrance(CFGBlock* B, const ExplodedNode *Pred,
|
||||
GRBlockCounter BC) {
|
||||
|
||||
return BC.getNumVisited(B->getBlockID()) < 3;
|
||||
return BC.getNumVisited(Pred->getLocationContext()->getCurrentStackFrame(),
|
||||
B->getBlockID()) < 3;
|
||||
}
|
||||
|
||||
//===----------------------------------------------------------------------===//
|
||||
@ -1328,6 +1341,22 @@ void GRExprEngine::ProcessCallExit(GRCallExitNodeBuilder &B) {
|
||||
if (ReturnedExpr) {
|
||||
SVal RetVal = state->getSVal(ReturnedExpr);
|
||||
state = state->BindExpr(CE, RetVal);
|
||||
// Clear the return expr GDM.
|
||||
state = state->remove<ReturnExpr>();
|
||||
}
|
||||
|
||||
// Bind the constructed object value to CXXConstructExpr.
|
||||
if (const CXXConstructExpr *CCE = dyn_cast<CXXConstructExpr>(CE)) {
|
||||
const CXXThisRegion *ThisR = getCXXThisRegion(CCE->getConstructor(),LocCtx);
|
||||
// We might not have 'this' region in the binding if we didn't inline
|
||||
// the ctor call.
|
||||
SVal ThisV = state->getSVal(ThisR);
|
||||
loc::MemRegionVal *V = dyn_cast<loc::MemRegionVal>(&ThisV);
|
||||
if (V) {
|
||||
SVal ObjVal = state->getSVal(V->getRegion());
|
||||
assert(isa<nonloc::LazyCompoundVal>(ObjVal));
|
||||
state = state->BindExpr(CCE, ObjVal);
|
||||
}
|
||||
}
|
||||
|
||||
B.GenerateNode(state);
|
||||
@ -2282,6 +2311,7 @@ void GRExprEngine::VisitCast(CastExpr *CastE, Expr *Ex, ExplodedNode *Pred,
|
||||
case CastExpr::CK_AnyPointerToObjCPointerCast:
|
||||
case CastExpr::CK_AnyPointerToBlockPointerCast:
|
||||
case CastExpr::CK_DerivedToBase:
|
||||
case CastExpr::CK_UncheckedDerivedToBase:
|
||||
// Delegate to SValuator to process.
|
||||
for (ExplodedNodeSet::iterator I = S2.begin(), E = S2.end(); I != E; ++I) {
|
||||
ExplodedNode* N = *I;
|
||||
@ -2338,8 +2368,10 @@ void GRExprEngine::VisitDeclStmt(DeclStmt *DS, ExplodedNode *Pred,
|
||||
ExplodedNodeSet Tmp;
|
||||
|
||||
if (InitEx) {
|
||||
if (const CXXConstructExpr *E = dyn_cast<CXXConstructExpr>(InitEx)) {
|
||||
VisitCXXConstructExpr(E, GetState(Pred)->getLValue(VD,
|
||||
QualType InitTy = InitEx->getType();
|
||||
if (getContext().getLangOptions().CPlusPlus && InitTy->isRecordType()) {
|
||||
// Delegate expressions of C++ record type evaluation to AggExprVisitor.
|
||||
VisitAggExpr(InitEx, GetState(Pred)->getLValue(VD,
|
||||
Pred->getLocationContext()), Pred, Dst);
|
||||
return;
|
||||
} else if (VD->getType()->isReferenceType())
|
||||
@ -2908,7 +2940,8 @@ void GRExprEngine::VisitReturnStmt(ReturnStmt *RS, ExplodedNode *Pred,
|
||||
ExplodedNodeSet &Dst) {
|
||||
ExplodedNodeSet Src;
|
||||
if (Expr *RetE = RS->getRetValue()) {
|
||||
// Record the returned expression in the state.
|
||||
// Record the returned expression in the state. It will be used in
|
||||
// ProcessCallExit to bind the return value to the call expr.
|
||||
{
|
||||
static int Tag = 0;
|
||||
SaveAndRestore<const void *> OldTag(Builder->Tag, &Tag);
|
||||
@ -3137,6 +3170,10 @@ void GRExprEngine::CreateCXXTemporaryObject(Expr *Ex, ExplodedNode *Pred,
|
||||
void GRExprEngine::VisitCXXConstructExpr(const CXXConstructExpr *E, SVal Dest,
|
||||
ExplodedNode *Pred,
|
||||
ExplodedNodeSet &Dst) {
|
||||
if (E->isElidable()) {
|
||||
VisitAggExpr(E->getArg(0), Dest, Pred, Dst);
|
||||
return;
|
||||
}
|
||||
|
||||
const CXXConstructorDecl *CD = E->getConstructor();
|
||||
assert(CD);
|
||||
@ -3190,10 +3227,7 @@ void GRExprEngine::VisitCXXConstructExpr(const CXXConstructExpr *E, SVal Dest,
|
||||
Pred->getLocationContext(),
|
||||
E, Builder->getBlock(), Builder->getIndex());
|
||||
|
||||
Type *T = CD->getParent()->getTypeForDecl();
|
||||
QualType PT = getContext().getPointerType(QualType(T,0));
|
||||
const CXXThisRegion *ThisR = ValMgr.getRegionManager().getCXXThisRegion(PT,
|
||||
SFC);
|
||||
const CXXThisRegion *ThisR = getCXXThisRegion(E->getConstructor(), SFC);
|
||||
|
||||
CallEnter Loc(E, CD, Pred->getLocationContext());
|
||||
for (ExplodedNodeSet::iterator NI = ArgsEvaluated.begin(),
|
||||
@ -3206,6 +3240,91 @@ void GRExprEngine::VisitCXXConstructExpr(const CXXConstructExpr *E, SVal Dest,
|
||||
Dst.Add(N);
|
||||
}
|
||||
}
|
||||
|
||||
void GRExprEngine::VisitCXXMemberCallExpr(const CXXMemberCallExpr *MCE,
|
||||
ExplodedNode *Pred,
|
||||
ExplodedNodeSet &Dst) {
|
||||
// Get the method type.
|
||||
const FunctionProtoType *FnType =
|
||||
MCE->getCallee()->getType()->getAs<FunctionProtoType>();
|
||||
assert(FnType && "Method type not available");
|
||||
|
||||
// Evaluate explicit arguments with a worklist.
|
||||
CallExpr::arg_iterator AB = const_cast<CXXMemberCallExpr*>(MCE)->arg_begin(),
|
||||
AE = const_cast<CXXMemberCallExpr*>(MCE)->arg_end();
|
||||
llvm::SmallVector<CallExprWLItem, 20> WorkList;
|
||||
WorkList.reserve(AE - AB);
|
||||
WorkList.push_back(CallExprWLItem(AB, Pred));
|
||||
ExplodedNodeSet ArgsEvaluated;
|
||||
|
||||
while (!WorkList.empty()) {
|
||||
CallExprWLItem Item = WorkList.back();
|
||||
WorkList.pop_back();
|
||||
|
||||
if (Item.I == AE) {
|
||||
ArgsEvaluated.insert(Item.N);
|
||||
continue;
|
||||
}
|
||||
|
||||
ExplodedNodeSet Tmp;
|
||||
const unsigned ParamIdx = Item.I - AB;
|
||||
bool VisitAsLvalue = FnType->getArgType(ParamIdx)->isReferenceType();
|
||||
|
||||
if (VisitAsLvalue)
|
||||
VisitLValue(*Item.I, Item.N, Tmp);
|
||||
else
|
||||
Visit(*Item.I, Item.N, Tmp);
|
||||
|
||||
++(Item.I);
|
||||
for (ExplodedNodeSet::iterator NI=Tmp.begin(), NE=Tmp.end(); NI != NE; ++NI)
|
||||
WorkList.push_back(CallExprWLItem(Item.I, *NI));
|
||||
}
|
||||
// Evaluate the implicit object argument.
|
||||
ExplodedNodeSet AllArgsEvaluated;
|
||||
const MemberExpr *ME = dyn_cast<MemberExpr>(MCE->getCallee()->IgnoreParens());
|
||||
if (!ME)
|
||||
return;
|
||||
Expr *ObjArgExpr = ME->getBase();
|
||||
for (ExplodedNodeSet::iterator I = ArgsEvaluated.begin(),
|
||||
E = ArgsEvaluated.end(); I != E; ++I) {
|
||||
if (ME->isArrow())
|
||||
Visit(ObjArgExpr, *I, AllArgsEvaluated);
|
||||
else
|
||||
VisitLValue(ObjArgExpr, *I, AllArgsEvaluated);
|
||||
}
|
||||
|
||||
const CXXMethodDecl *MD = cast<CXXMethodDecl>(ME->getMemberDecl());
|
||||
assert(MD && "not a CXXMethodDecl?");
|
||||
|
||||
if (!MD->isThisDeclarationADefinition())
|
||||
// FIXME: conservative method call evaluation.
|
||||
return;
|
||||
|
||||
const StackFrameContext *SFC = AMgr.getStackFrame(MD,
|
||||
Pred->getLocationContext(),
|
||||
MCE,
|
||||
Builder->getBlock(),
|
||||
Builder->getIndex());
|
||||
const CXXThisRegion *ThisR = getCXXThisRegion(MD, SFC);
|
||||
CallEnter Loc(MCE, MD, Pred->getLocationContext());
|
||||
for (ExplodedNodeSet::iterator I = AllArgsEvaluated.begin(),
|
||||
E = AllArgsEvaluated.end(); I != E; ++I) {
|
||||
// Set up 'this' region.
|
||||
const GRState *state = GetState(*I);
|
||||
state = state->bindLoc(loc::MemRegionVal(ThisR),state->getSVal(ObjArgExpr));
|
||||
ExplodedNode *N = Builder->generateNode(Loc, state, *I);
|
||||
if (N)
|
||||
Dst.Add(N);
|
||||
}
|
||||
}
|
||||
|
||||
const CXXThisRegion *GRExprEngine::getCXXThisRegion(const CXXMethodDecl *D,
|
||||
const StackFrameContext *SFC) {
|
||||
Type *T = D->getParent()->getTypeForDecl();
|
||||
QualType PT = getContext().getPointerType(QualType(T,0));
|
||||
return ValMgr.getRegionManager().getCXXThisRegion(PT, SFC);
|
||||
}
|
||||
|
||||
//===----------------------------------------------------------------------===//
|
||||
// Checker registration/lookup.
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
@ -11,10 +11,10 @@
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
#include "clang/Analysis/CFG.h"
|
||||
#include "clang/Checker/PathSensitive/GRStateTrait.h"
|
||||
#include "clang/Checker/PathSensitive/GRState.h"
|
||||
#include "clang/Checker/PathSensitive/GRTransferFuncs.h"
|
||||
#include "llvm/ADT/SmallSet.h"
|
||||
#include "llvm/Support/raw_ostream.h"
|
||||
|
||||
using namespace clang;
|
||||
@ -227,6 +227,18 @@ const GRState* GRStateManager::addGDM(const GRState* St, void* Key, void* Data){
|
||||
return getPersistentState(NewSt);
|
||||
}
|
||||
|
||||
const GRState *GRStateManager::removeGDM(const GRState *state, void *Key) {
|
||||
GRState::GenericDataMap OldM = state->getGDM();
|
||||
GRState::GenericDataMap NewM = GDMFactory.Remove(OldM, Key);
|
||||
|
||||
if (NewM == OldM)
|
||||
return state;
|
||||
|
||||
GRState NewState = *state;
|
||||
NewState.GDM = NewM;
|
||||
return getPersistentState(NewState);
|
||||
}
|
||||
|
||||
//===----------------------------------------------------------------------===//
|
||||
// Utility.
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
@ -17,7 +17,7 @@
|
||||
|
||||
#include "GRExprEngineInternalChecks.h"
|
||||
#include "clang/Basic/TargetInfo.h"
|
||||
#include "clang/Checker/BugReporter/BugReporter.h"
|
||||
#include "clang/Checker/BugReporter/BugType.h"
|
||||
#include "clang/Checker/PathSensitive/CheckerVisitor.h"
|
||||
#include "clang/Checker/PathSensitive/GRStateTrait.h"
|
||||
#include "llvm/ADT/SmallString.h"
|
||||
|
@ -13,6 +13,7 @@
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
#include "GRExprEngineExperimentalChecks.h"
|
||||
#include "clang/Checker/BugReporter/BugType.h"
|
||||
#include "clang/Checker/PathSensitive/CheckerVisitor.h"
|
||||
#include "clang/Checker/PathSensitive/GRState.h"
|
||||
#include "clang/Checker/PathSensitive/GRStateTrait.h"
|
||||
|
@ -13,10 +13,10 @@
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
#include "clang/Analysis/AnalysisContext.h"
|
||||
#include "clang/Checker/PathSensitive/MemRegion.h"
|
||||
#include "clang/Analysis/AnalysisContext.h"
|
||||
#include "clang/Analysis/Support/BumpVector.h"
|
||||
#include "clang/AST/CharUnits.h"
|
||||
#include "clang/AST/StmtVisitor.h"
|
||||
#include "llvm/Support/raw_ostream.h"
|
||||
|
||||
using namespace clang;
|
||||
|
Some files were not shown because too many files have changed in this diff Show More
Loading…
x
Reference in New Issue
Block a user