diff options
author | rdivacky <rdivacky@FreeBSD.org> | 2010-01-23 11:10:26 +0000 |
---|---|---|
committer | rdivacky <rdivacky@FreeBSD.org> | 2010-01-23 11:10:26 +0000 |
commit | 2fce988e86bc01829142e4362d4eff1af0925147 (patch) | |
tree | c69d3f4f13d508570bb5257a6aea735f88bdf09c | |
parent | a3fa5c7f1b5e2ba4d6ec033dc0e2376326b05824 (diff) | |
download | FreeBSD-src-2fce988e86bc01829142e4362d4eff1af0925147.zip FreeBSD-src-2fce988e86bc01829142e4362d4eff1af0925147.tar.gz |
Update clang to r94309.
238 files changed, 9431 insertions, 6572 deletions
diff --git a/clang.xcodeproj/project.pbxproj b/clang.xcodeproj/project.pbxproj index ea72c9e..d1cd032 100644 --- a/clang.xcodeproj/project.pbxproj +++ b/clang.xcodeproj/project.pbxproj @@ -21,7 +21,6 @@ 1A2A54BD0FD1DD1C00F4CE45 /* HTMLPrint.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 1A2A54AC0FD1DD1C00F4CE45 /* HTMLPrint.cpp */; }; 1A2A54BE0FD1DD1C00F4CE45 /* PrintParserCallbacks.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 1A2A54AD0FD1DD1C00F4CE45 /* PrintParserCallbacks.cpp */; }; 1A2A54BF0FD1DD1C00F4CE45 /* PrintPreprocessedOutput.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 1A2A54AE0FD1DD1C00F4CE45 /* PrintPreprocessedOutput.cpp */; }; - 1A2A54C00FD1DD1C00F4CE45 /* RewriteBlocks.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 1A2A54AF0FD1DD1C00F4CE45 /* RewriteBlocks.cpp */; }; 1A2A54C10FD1DD1C00F4CE45 /* RewriteMacros.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 1A2A54B00FD1DD1C00F4CE45 /* RewriteMacros.cpp */; }; 1A2A54C20FD1DD1C00F4CE45 /* RewriteObjC.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 1A2A54B10FD1DD1C00F4CE45 /* RewriteObjC.cpp */; }; 1A2A54C30FD1DD1C00F4CE45 /* RewriteTest.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 1A2A54B20FD1DD1C00F4CE45 /* RewriteTest.cpp */; }; @@ -44,10 +43,20 @@ 1A81AA19108144F40094E50B /* CGVtable.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 1A81AA18108144F40094E50B /* CGVtable.cpp */; }; 1A869A700BA2164C008DA07A /* LiteralSupport.h in CopyFiles */ = {isa = PBXBuildFile; fileRef = 1A869A6E0BA2164C008DA07A /* LiteralSupport.h */; }; 1A869AA80BA21ABA008DA07A /* LiteralSupport.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 1A869AA70BA21ABA008DA07A /* LiteralSupport.cpp */; }; + 1A97825B1108BA18002B98FC /* CGVTT.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 1A97825A1108BA18002B98FC /* CGVTT.cpp */; }; 1A986AB710D0746D00A8EA9E /* CGDeclCXX.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 1A986AB610D0746D00A8EA9E /* CGDeclCXX.cpp */; }; 1AA1D91810125DE30078DEBC /* RecordLayoutBuilder.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 1AA1D91610125DE30078DEBC /* RecordLayoutBuilder.cpp */; }; 1AA963C410D85A7300786C86 /* FullExpr.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 1AA963C310D85A7300786C86 /* FullExpr.cpp */; }; 1ABC36940C7A4BDC006DB0AB /* CGBuiltin.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 1ABC36930C7A4BDC006DB0AB /* CGBuiltin.cpp */; }; + 1ACB57E41105820D0047B991 /* CompilerInstance.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 1ACB57DB1105820D0047B991 /* CompilerInstance.cpp */; }; + 1ACB57E51105820D0047B991 /* CompilerInvocation.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 1ACB57DC1105820D0047B991 /* CompilerInvocation.cpp */; }; + 1ACB57E61105820D0047B991 /* DeclXML.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 1ACB57DD1105820D0047B991 /* DeclXML.cpp */; }; + 1ACB57E71105820D0047B991 /* FrontendAction.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 1ACB57DE1105820D0047B991 /* FrontendAction.cpp */; }; + 1ACB57E81105820D0047B991 /* FrontendActions.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 1ACB57DF1105820D0047B991 /* FrontendActions.cpp */; }; + 1ACB57E91105820D0047B991 /* FrontendOptions.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 1ACB57E01105820D0047B991 /* FrontendOptions.cpp */; }; + 1ACB57EA1105820D0047B991 /* LangStandards.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 1ACB57E11105820D0047B991 /* LangStandards.cpp */; }; + 1ACB57EB1105820D0047B991 /* TypeXML.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 1ACB57E21105820D0047B991 /* TypeXML.cpp */; }; + 1ACB57EC1105820D0047B991 /* VerifyDiagnosticsClient.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 1ACB57E31105820D0047B991 /* VerifyDiagnosticsClient.cpp */; }; 1ADD795410A90C6100741BBA /* TypePrinter.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 1ADD795110A90C6100741BBA /* TypePrinter.cpp */; }; 1ADD795510A90C6100741BBA /* TypeLoc.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 1ADD795210A90C6100741BBA /* TypeLoc.cpp */; }; 1ADD795610A90C6100741BBA /* TemplateBase.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 1ADD795310A90C6100741BBA /* TemplateBase.cpp */; }; @@ -59,7 +68,6 @@ 3507E4C20E27FE2D00FB7B57 /* CheckObjCInstMethSignature.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 3507E4C10E27FE2D00FB7B57 /* CheckObjCInstMethSignature.cpp */; }; 352246E70F5C6BE000D0D279 /* HTMLDiagnostics.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 352246E10F5C6BE000D0D279 /* HTMLDiagnostics.cpp */; }; 352246E80F5C6BE000D0D279 /* InitHeaderSearch.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 352246E20F5C6BE000D0D279 /* InitHeaderSearch.cpp */; }; - 352246E90F5C6BE000D0D279 /* ManagerRegistry.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 352246E30F5C6BE000D0D279 /* ManagerRegistry.cpp */; }; 352246EA0F5C6BE000D0D279 /* PlistDiagnostics.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 352246E40F5C6BE000D0D279 /* PlistDiagnostics.cpp */; }; 352246EB0F5C6BE000D0D279 /* TextDiagnosticBuffer.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 352246E50F5C6BE000D0D279 /* TextDiagnosticBuffer.cpp */; }; 352246EC0F5C6BE000D0D279 /* TextDiagnosticPrinter.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 352246E60F5C6BE000D0D279 /* TextDiagnosticPrinter.cpp */; }; @@ -360,7 +368,6 @@ 1A2A54AC0FD1DD1C00F4CE45 /* HTMLPrint.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = HTMLPrint.cpp; path = lib/Frontend/HTMLPrint.cpp; sourceTree = "<group>"; }; 1A2A54AD0FD1DD1C00F4CE45 /* PrintParserCallbacks.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = PrintParserCallbacks.cpp; path = lib/Frontend/PrintParserCallbacks.cpp; sourceTree = "<group>"; }; 1A2A54AE0FD1DD1C00F4CE45 /* PrintPreprocessedOutput.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = PrintPreprocessedOutput.cpp; path = lib/Frontend/PrintPreprocessedOutput.cpp; sourceTree = "<group>"; }; - 1A2A54AF0FD1DD1C00F4CE45 /* RewriteBlocks.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = RewriteBlocks.cpp; path = lib/Frontend/RewriteBlocks.cpp; sourceTree = "<group>"; }; 1A2A54B00FD1DD1C00F4CE45 /* RewriteMacros.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = RewriteMacros.cpp; path = lib/Frontend/RewriteMacros.cpp; sourceTree = "<group>"; }; 1A2A54B10FD1DD1C00F4CE45 /* RewriteObjC.cpp */ = {isa = PBXFileReference; fileEncoding = 4; indentWidth = 2; lastKnownFileType = sourcecode.cpp.cpp; name = RewriteObjC.cpp; path = lib/Frontend/RewriteObjC.cpp; sourceTree = "<group>"; tabWidth = 2; }; 1A2A54B20FD1DD1C00F4CE45 /* RewriteTest.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = RewriteTest.cpp; path = lib/Frontend/RewriteTest.cpp; sourceTree = "<group>"; }; @@ -398,6 +405,7 @@ 1A81AA5D108278A20094E50B /* CGVtable.h */ = {isa = PBXFileReference; fileEncoding = 4; indentWidth = 2; lastKnownFileType = sourcecode.c.h; name = CGVtable.h; path = lib/CodeGen/CGVtable.h; sourceTree = "<group>"; tabWidth = 2; }; 1A869A6E0BA2164C008DA07A /* LiteralSupport.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = LiteralSupport.h; sourceTree = "<group>"; }; 1A869AA70BA21ABA008DA07A /* LiteralSupport.cpp */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.cpp.cpp; path = LiteralSupport.cpp; sourceTree = "<group>"; }; + 1A97825A1108BA18002B98FC /* CGVTT.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = CGVTT.cpp; path = lib/CodeGen/CGVTT.cpp; sourceTree = "<group>"; }; 1A986AB610D0746D00A8EA9E /* CGDeclCXX.cpp */ = {isa = PBXFileReference; fileEncoding = 4; indentWidth = 2; lastKnownFileType = sourcecode.cpp.cpp; name = CGDeclCXX.cpp; path = lib/CodeGen/CGDeclCXX.cpp; sourceTree = "<group>"; tabWidth = 2; }; 1AA1D91610125DE30078DEBC /* RecordLayoutBuilder.cpp */ = {isa = PBXFileReference; fileEncoding = 4; indentWidth = 2; lastKnownFileType = sourcecode.cpp.cpp; name = RecordLayoutBuilder.cpp; path = lib/AST/RecordLayoutBuilder.cpp; sourceTree = "<group>"; tabWidth = 2; }; 1AA1D91710125DE30078DEBC /* RecordLayoutBuilder.h */ = {isa = PBXFileReference; fileEncoding = 4; indentWidth = 2; lastKnownFileType = sourcecode.c.h; name = RecordLayoutBuilder.h; path = lib/AST/RecordLayoutBuilder.h; sourceTree = "<group>"; tabWidth = 2; }; @@ -405,6 +413,15 @@ 1AA963C310D85A7300786C86 /* FullExpr.cpp */ = {isa = PBXFileReference; fileEncoding = 4; indentWidth = 2; lastKnownFileType = sourcecode.cpp.cpp; name = FullExpr.cpp; path = lib/AST/FullExpr.cpp; sourceTree = "<group>"; tabWidth = 2; }; 1AB290021045858B00FE33D8 /* PartialDiagnostic.h */ = {isa = PBXFileReference; fileEncoding = 4; indentWidth = 2; lastKnownFileType = sourcecode.c.h; path = PartialDiagnostic.h; sourceTree = "<group>"; tabWidth = 2; }; 1ABC36930C7A4BDC006DB0AB /* CGBuiltin.cpp */ = {isa = PBXFileReference; fileEncoding = 4; indentWidth = 2; lastKnownFileType = sourcecode.cpp.cpp; name = CGBuiltin.cpp; path = lib/CodeGen/CGBuiltin.cpp; sourceTree = "<group>"; tabWidth = 2; }; + 1ACB57DB1105820D0047B991 /* CompilerInstance.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = CompilerInstance.cpp; path = lib/Frontend/CompilerInstance.cpp; sourceTree = "<group>"; }; + 1ACB57DC1105820D0047B991 /* CompilerInvocation.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = CompilerInvocation.cpp; path = lib/Frontend/CompilerInvocation.cpp; sourceTree = "<group>"; }; + 1ACB57DD1105820D0047B991 /* DeclXML.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = DeclXML.cpp; path = lib/Frontend/DeclXML.cpp; sourceTree = "<group>"; }; + 1ACB57DE1105820D0047B991 /* FrontendAction.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = FrontendAction.cpp; path = lib/Frontend/FrontendAction.cpp; sourceTree = "<group>"; }; + 1ACB57DF1105820D0047B991 /* FrontendActions.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = FrontendActions.cpp; path = lib/Frontend/FrontendActions.cpp; sourceTree = "<group>"; }; + 1ACB57E01105820D0047B991 /* FrontendOptions.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = FrontendOptions.cpp; path = lib/Frontend/FrontendOptions.cpp; sourceTree = "<group>"; }; + 1ACB57E11105820D0047B991 /* LangStandards.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = LangStandards.cpp; path = lib/Frontend/LangStandards.cpp; sourceTree = "<group>"; }; + 1ACB57E21105820D0047B991 /* TypeXML.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = TypeXML.cpp; path = lib/Frontend/TypeXML.cpp; sourceTree = "<group>"; }; + 1ACB57E31105820D0047B991 /* VerifyDiagnosticsClient.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = VerifyDiagnosticsClient.cpp; path = lib/Frontend/VerifyDiagnosticsClient.cpp; sourceTree = "<group>"; }; 1ADD795110A90C6100741BBA /* TypePrinter.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = TypePrinter.cpp; path = lib/AST/TypePrinter.cpp; sourceTree = "<group>"; }; 1ADD795210A90C6100741BBA /* TypeLoc.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = TypeLoc.cpp; path = lib/AST/TypeLoc.cpp; sourceTree = "<group>"; }; 1ADD795310A90C6100741BBA /* TemplateBase.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = TemplateBase.cpp; path = lib/AST/TemplateBase.cpp; sourceTree = "<group>"; }; @@ -418,7 +435,6 @@ 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>"; }; - 352246E30F5C6BE000D0D279 /* ManagerRegistry.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = ManagerRegistry.cpp; path = lib/Frontend/ManagerRegistry.cpp; sourceTree = "<group>"; }; 352246E40F5C6BE000D0D279 /* PlistDiagnostics.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = PlistDiagnostics.cpp; path = lib/Frontend/PlistDiagnostics.cpp; sourceTree = "<group>"; }; 352246E50F5C6BE000D0D279 /* TextDiagnosticBuffer.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = TextDiagnosticBuffer.cpp; path = lib/Frontend/TextDiagnosticBuffer.cpp; sourceTree = "<group>"; }; 352246E60F5C6BE000D0D279 /* TextDiagnosticPrinter.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = TextDiagnosticPrinter.cpp; path = lib/Frontend/TextDiagnosticPrinter.cpp; sourceTree = "<group>"; }; @@ -922,16 +938,22 @@ 1A2A54A50FD1DD1C00F4CE45 /* ASTConsumers.cpp */, 1A2A54A60FD1DD1C00F4CE45 /* Backend.cpp */, 1A2A54A70FD1DD1C00F4CE45 /* CacheTokens.cpp */, + 1ACB57DB1105820D0047B991 /* CompilerInstance.cpp */, + 1ACB57DC1105820D0047B991 /* CompilerInvocation.cpp */, + 1ACB57DD1105820D0047B991 /* DeclXML.cpp */, 1A2A54A80FD1DD1C00F4CE45 /* DependencyFile.cpp */, 1A2A54A90FD1DD1C00F4CE45 /* DiagChecker.cpp */, 1A2A54AA0FD1DD1C00F4CE45 /* DocumentXML.cpp */, DEF1683F0F9548DC0098507F /* FixItRewriter.cpp */, + 1ACB57DE1105820D0047B991 /* FrontendAction.cpp */, + 1ACB57DF1105820D0047B991 /* FrontendActions.cpp */, + 1ACB57E01105820D0047B991 /* FrontendOptions.cpp */, 1A2A54AB0FD1DD1C00F4CE45 /* GeneratePCH.cpp */, 352246E10F5C6BE000D0D279 /* HTMLDiagnostics.cpp */, 1A2A54AC0FD1DD1C00F4CE45 /* HTMLPrint.cpp */, 352246E20F5C6BE000D0D279 /* InitHeaderSearch.cpp */, DECB6F060F9D93A800F5FBC7 /* InitPreprocessor.cpp */, - 352246E30F5C6BE000D0D279 /* ManagerRegistry.cpp */, + 1ACB57E11105820D0047B991 /* LangStandards.cpp */, DEF165740F8FB3510098507F /* PCHReader.cpp */, DECB77780FA579B000F5FBC7 /* PCHReaderDecl.cpp */, DECB77120FA5752300F5FBC7 /* PCHReaderStmt.cpp */, @@ -943,11 +965,12 @@ 1A2A54AE0FD1DD1C00F4CE45 /* PrintPreprocessedOutput.cpp */, 352246E50F5C6BE000D0D279 /* TextDiagnosticBuffer.cpp */, 352246E60F5C6BE000D0D279 /* TextDiagnosticPrinter.cpp */, - 1A2A54AF0FD1DD1C00F4CE45 /* RewriteBlocks.cpp */, + 1ACB57E21105820D0047B991 /* TypeXML.cpp */, 1A2A54B00FD1DD1C00F4CE45 /* RewriteMacros.cpp */, 1A2A54B10FD1DD1C00F4CE45 /* RewriteObjC.cpp */, 1A2A54B20FD1DD1C00F4CE45 /* RewriteTest.cpp */, 1A2A54B30FD1DD1C00F4CE45 /* StmtXML.cpp */, + 1ACB57E31105820D0047B991 /* VerifyDiagnosticsClient.cpp */, 1A2A54B40FD1DD1C00F4CE45 /* Warnings.cpp */, ); name = Frontend; @@ -1296,6 +1319,7 @@ 35475B230E7997680000BFE4 /* CGValue.h */, 1A81AA18108144F40094E50B /* CGVtable.cpp */, 1A81AA5D108278A20094E50B /* CGVtable.h */, + 1A97825A1108BA18002B98FC /* CGVTT.cpp */, DE928B800C0A615B00231DA4 /* CodeGenFunction.h */, DE928B820C0A616000231DA4 /* CodeGenFunction.cpp */, DE928B7C0C0A615100231DA4 /* CodeGenModule.h */, @@ -1844,7 +1868,6 @@ DEB07AC80F4A427E00F5A2BE /* SemaAttr.cpp in Sources */, 352246E70F5C6BE000D0D279 /* HTMLDiagnostics.cpp in Sources */, 352246E80F5C6BE000D0D279 /* InitHeaderSearch.cpp in Sources */, - 352246E90F5C6BE000D0D279 /* ManagerRegistry.cpp in Sources */, 352246EA0F5C6BE000D0D279 /* PlistDiagnostics.cpp in Sources */, 352246EB0F5C6BE000D0D279 /* TextDiagnosticBuffer.cpp in Sources */, 352246EC0F5C6BE000D0D279 /* TextDiagnosticPrinter.cpp in Sources */, @@ -1892,7 +1915,6 @@ 1A2A54BD0FD1DD1C00F4CE45 /* HTMLPrint.cpp in Sources */, 1A2A54BE0FD1DD1C00F4CE45 /* PrintParserCallbacks.cpp in Sources */, 1A2A54BF0FD1DD1C00F4CE45 /* PrintPreprocessedOutput.cpp in Sources */, - 1A2A54C00FD1DD1C00F4CE45 /* RewriteBlocks.cpp in Sources */, 1A2A54C10FD1DD1C00F4CE45 /* RewriteMacros.cpp in Sources */, 1A2A54C20FD1DD1C00F4CE45 /* RewriteObjC.cpp in Sources */, 1A2A54C30FD1DD1C00F4CE45 /* RewriteTest.cpp in Sources */, @@ -1935,6 +1957,16 @@ 1A986AB710D0746D00A8EA9E /* CGDeclCXX.cpp in Sources */, E16B523510D30B2400430AC9 /* cc1_main.cpp in Sources */, 1AA963C410D85A7300786C86 /* FullExpr.cpp in Sources */, + 1ACB57E41105820D0047B991 /* CompilerInstance.cpp in Sources */, + 1ACB57E51105820D0047B991 /* CompilerInvocation.cpp in Sources */, + 1ACB57E61105820D0047B991 /* DeclXML.cpp in Sources */, + 1ACB57E71105820D0047B991 /* FrontendAction.cpp in Sources */, + 1ACB57E81105820D0047B991 /* FrontendActions.cpp in Sources */, + 1ACB57E91105820D0047B991 /* FrontendOptions.cpp in Sources */, + 1ACB57EA1105820D0047B991 /* LangStandards.cpp in Sources */, + 1ACB57EB1105820D0047B991 /* TypeXML.cpp in Sources */, + 1ACB57EC1105820D0047B991 /* VerifyDiagnosticsClient.cpp in Sources */, + 1A97825B1108BA18002B98FC /* CGVTT.cpp in Sources */, ); runOnlyForDeploymentPostprocessing = 0; }; diff --git a/include/clang-c/Index.h b/include/clang-c/Index.h index f11a9eb..ef17ed1 100644 --- a/include/clang-c/Index.h +++ b/include/clang-c/Index.h @@ -34,77 +34,42 @@ extern "C" { #define CINDEX_LINKAGE #endif -/* - Clang indeX abstractions. The backing store for the following API's will be - clangs AST file (currently based on PCH). AST files are created as follows: - - "clang -emit-ast <sourcefile.langsuffix> -o <sourcefile.ast>". - - Naming Conventions: To avoid namespace pollution, data types are prefixed - with "CX" and functions are prefixed with "clang_". -*/ -typedef void *CXIndex; /* An indexing instance. */ +/** \defgroup CINDEX C Interface to Clang + * + * The C Interface to Clang provides a relatively small API that exposes + * facilities for parsing source code into an abstract syntax tree (AST), + * loading already-parsed ASTs, traversing the AST, associating + * physical source locations with elements within the AST, and other + * facilities that support Clang-based development tools. + * + * This C interface to Clang will never provide all of the information + * representation stored in Clang's C++ AST, nor should it: the intent is to + * maintain an API that is relatively stable from one release to the next, + * providing only the basic functionality needed to support development tools. + * + * To avoid namespace pollution, data types are prefixed with "CX" and + * functions are prefixed with "clang_". + * + * @{ + */ + +/** + * \brief An "index" that consists of a set of translation units that would + * typically be linked together into an executable or library. + */ +typedef void *CXIndex; +/** + * \brief A single translation unit, which resides in an index. + */ typedef void *CXTranslationUnit; /* A translation unit instance. */ -typedef void *CXFile; /* A source file */ -typedef void *CXDecl; /* A specific declaration within a translation unit. */ -typedef void *CXStmt; /* A specific statement within a function/method */ - -/* Cursors represent declarations, definitions, and references. */ -enum CXCursorKind { - /* Declarations */ - CXCursor_FirstDecl = 1, - CXCursor_TypedefDecl = 2, - CXCursor_StructDecl = 3, - CXCursor_UnionDecl = 4, - CXCursor_ClassDecl = 5, - CXCursor_EnumDecl = 6, - CXCursor_FieldDecl = 7, - CXCursor_EnumConstantDecl = 8, - CXCursor_FunctionDecl = 9, - CXCursor_VarDecl = 10, - CXCursor_ParmDecl = 11, - CXCursor_ObjCInterfaceDecl = 12, - CXCursor_ObjCCategoryDecl = 13, - CXCursor_ObjCProtocolDecl = 14, - CXCursor_ObjCPropertyDecl = 15, - CXCursor_ObjCIvarDecl = 16, - CXCursor_ObjCInstanceMethodDecl = 17, - CXCursor_ObjCClassMethodDecl = 18, - CXCursor_LastDecl = 18, - - /* Definitions */ - CXCursor_FirstDefn = 32, - CXCursor_FunctionDefn = 32, - CXCursor_ObjCClassDefn = 33, - CXCursor_ObjCCategoryDefn = 34, - CXCursor_ObjCInstanceMethodDefn = 35, - CXCursor_ObjCClassMethodDefn = 36, - CXCursor_LastDefn = 36, - - /* References */ - CXCursor_FirstRef = 40, /* Decl references */ - CXCursor_ObjCSuperClassRef = 40, - CXCursor_ObjCProtocolRef = 41, - CXCursor_ObjCClassRef = 42, - - CXCursor_ObjCSelectorRef = 43, /* Expression references */ - CXCursor_ObjCIvarRef = 44, - CXCursor_VarRef = 45, - CXCursor_FunctionRef = 46, - CXCursor_EnumConstantRef = 47, - CXCursor_MemberRef = 48, - CXCursor_LastRef = 48, - - /* Error conditions */ - CXCursor_FirstInvalid = 70, - CXCursor_InvalidFile = 70, - CXCursor_NoDeclFound = 71, - CXCursor_NotImplemented = 72, - CXCursor_LastInvalid = 72 -}; - +/** + * \brief Opaque pointer representing client data that will be passed through + * to various callbacks and visitors. + */ +typedef void *CXClientData; + /** * \brief Provides the contents of a file that has not yet been saved to disk. * @@ -133,27 +98,19 @@ struct CXUnsavedFile { unsigned long Length; }; -/* A cursor into the CXTranslationUnit. */ - -typedef struct { - enum CXCursorKind kind; - CXDecl decl; - CXStmt stmt; /* expression reference */ - CXDecl referringDecl; -} CXCursor; - -/* A unique token for looking up "visible" CXDecls from a CXTranslationUnit. */ -typedef struct { - CXIndex index; - void *data; -} CXEntity; - /** - * For functions returning a string that might or might not need - * to be internally allocated and freed. - * Use clang_getCString to access the C string value. - * Use clang_disposeString to free the value. - * Treat it as an opaque type. + * \defgroup CINDEX_STRING String manipulation routines + * + * @{ + */ + +/** + * \brief A character string. + * + * The \c CXString type is used to return strings from the interface when + * the ownership of that string might different from one call to the next. + * Use \c clang_getCString() to retrieve the string data and, once finished + * with the string data, call \c clang_disposeString() to free the string. */ typedef struct { const char *Spelling; @@ -162,12 +119,20 @@ typedef struct { int MustFreeString; } CXString; -/* Get C string pointer from a CXString. */ +/** + * \brief Retrieve the character data associated with the given string. + */ CINDEX_LINKAGE const char *clang_getCString(CXString string); -/* Free CXString. */ +/** + * \brief Free the given string, + */ CINDEX_LINKAGE void clang_disposeString(CXString string); +/** + * @} + */ + /** * \brief clang_createIndex() provides a shared context for creating * translation units. It provides two options: @@ -191,14 +156,16 @@ CINDEX_LINKAGE void clang_disposeString(CXString string); * TU = clang_createTranslationUnit(Idx, "IndexTest.pch"); * * // This will load all the symbols from 'IndexTest.pch' - * clang_loadTranslationUnit(TU, TranslationUnitVisitor, 0); + * clang_visitChildren(clang_getTranslationUnitCursor(TU), + * TranslationUnitVisitor, 0); * clang_disposeTranslationUnit(TU); * * // This will load all the symbols from 'IndexTest.c', excluding symbols * // from 'IndexTest.pch'. * char *args[] = { "-Xclang", "-include-pch=IndexTest.pch", 0 }; * TU = clang_createTranslationUnitFromSourceFile(Idx, "IndexTest.c", 2, args); - * clang_loadTranslationUnit(TU, TranslationUnitVisitor, 0); + * clang_visitChildren(clang_getTranslationUnitCursor(TU), + * TranslationUnitVisitor, 0); * clang_disposeTranslationUnit(TU); * * This process of creating the 'pch', loading it separately, and using it (via @@ -211,7 +178,7 @@ CINDEX_LINKAGE void clang_disposeIndex(CXIndex index); CINDEX_LINKAGE CXString clang_getTranslationUnitSpelling(CXTranslationUnit CTUnit); -/* +/** * \brief Request that AST's be generated external for API calls which parse * source code on the fly, e.g. \see createTranslationUnitFromSourceFile. * @@ -224,7 +191,7 @@ clang_getTranslationUnitSpelling(CXTranslationUnit CTUnit); CINDEX_LINKAGE void clang_setUseExternalASTGeneration(CXIndex index, int value); -/* +/** * \brief Create a translation unit from an AST file (-emit-ast). */ CINDEX_LINKAGE CXTranslationUnit clang_createTranslationUnit( @@ -255,137 +222,632 @@ CINDEX_LINKAGE void clang_disposeTranslationUnit(CXTranslationUnit); * * \param source_filename - The name of the source file to load, or NULL if the * source file is included in clang_command_line_args. + * + * \param num_unsaved_files the number of unsaved file entries in \p + * unsaved_files. + * + * \param unsaved_files the files that have not yet been saved to disk + * but may be required for code completion, including the contents of + * those files. */ CINDEX_LINKAGE CXTranslationUnit clang_createTranslationUnitFromSourceFile( - CXIndex CIdx, - const char *source_filename, - int num_clang_command_line_args, - const char **clang_command_line_args -); + CXIndex CIdx, + const char *source_filename, + int num_clang_command_line_args, + const char **clang_command_line_args, + unsigned num_unsaved_files, + struct CXUnsavedFile *unsaved_files); -/* - Usage: clang_loadTranslationUnit(). Will load the toplevel declarations - within a translation unit, issuing a 'callback' for each one. - - void printObjCInterfaceNames(CXTranslationUnit X, CXCursor C) { - if (clang_getCursorKind(C) == Cursor_Declaration) { - CXDecl D = clang_getCursorDecl(C); - if (clang_getDeclKind(D) == CXDecl_ObjC_interface) - printf("@interface %s in file %s on line %d column %d\n", - clang_getDeclSpelling(D), clang_getCursorSource(C), - clang_getCursorLine(C), clang_getCursorColumn(C)); - } - } - static void usage { - clang_loadTranslationUnit(CXTranslationUnit, printObjCInterfaceNames); - } -*/ -typedef void *CXClientData; -typedef void (*CXTranslationUnitIterator)(CXTranslationUnit, CXCursor, - CXClientData); -CINDEX_LINKAGE void clang_loadTranslationUnit(CXTranslationUnit, - CXTranslationUnitIterator, - CXClientData); - -/* - Usage: clang_loadDeclaration(). Will load the declaration, issuing a - 'callback' for each declaration/reference within the respective declaration. - - For interface declarations, this will index the super class, protocols, - ivars, methods, etc. For structure declarations, this will index the fields. - For functions, this will index the parameters (and body, for function - definitions), local declarations/references. - - void getInterfaceDetails(CXDecl X, CXCursor C) { - switch (clang_getCursorKind(C)) { - case Cursor_ObjC_ClassRef: - CXDecl SuperClass = clang_getCursorDecl(C); - case Cursor_ObjC_ProtocolRef: - CXDecl AdoptsProtocol = clang_getCursorDecl(C); - case Cursor_Declaration: - CXDecl AnIvarOrMethod = clang_getCursorDecl(C); - } - } - static void usage() { - if (clang_getDeclKind(D) == CXDecl_ObjC_interface) { - clang_loadDeclaration(D, getInterfaceDetails); - } - } -*/ -typedef void (*CXDeclIterator)(CXDecl, CXCursor, CXClientData); - -CINDEX_LINKAGE void clang_loadDeclaration(CXDecl, CXDeclIterator, CXClientData); - -/* - * CXFile Operations. +/** + * \defgroup CINDEX_FILES File manipulation routines + * + * @{ + */ + +/** + * \brief A particular source file that is part of a translation unit. + */ +typedef void *CXFile; + + +/** + * \brief Retrieve the complete file and path name of the given file. */ CINDEX_LINKAGE const char *clang_getFileName(CXFile SFile); + +/** + * \brief Retrieve the last modification time of the given file. + */ CINDEX_LINKAGE time_t clang_getFileTime(CXFile SFile); -/* - * CXEntity Operations. +/** + * \brief Retrieve a file handle within the given translation unit. + * + * \param tu the translation unit + * + * \param file_name the name of the file. + * + * \returns the file handle for the named file in the translation unit \p tu, + * or a NULL file handle if the file was not a part of this translation unit. */ +CINDEX_LINKAGE CXFile clang_getFile(CXTranslationUnit tu, + const char *file_name); -/* clang_getDeclaration() maps from a CXEntity to the matching CXDecl (if any) - * in a specified translation unit. */ -CINDEX_LINKAGE CXDecl clang_getDeclaration(CXEntity, CXTranslationUnit); +/** + * @} + */ -/* - * CXDecl Operations. +/** + * \defgroup CINDEX_LOCATIONS Physical source locations + * + * Clang represents physical source locations in its abstract syntax tree in + * great detail, with file, line, and column information for the majority of + * the tokens parsed in the source code. These data types and functions are + * used to represent source location information, either for a particular + * point in the program or for a range of points in the program, and extract + * specific location information from those data types. + * + * @{ */ -CINDEX_LINKAGE CXCursor clang_getCursorFromDecl(CXDecl); -CINDEX_LINKAGE CXEntity clang_getEntityFromDecl(CXIndex, CXDecl); -CINDEX_LINKAGE CXString clang_getDeclSpelling(CXDecl); -CINDEX_LINKAGE unsigned clang_getDeclLine(CXDecl); -CINDEX_LINKAGE unsigned clang_getDeclColumn(CXDecl); -CINDEX_LINKAGE CXString clang_getDeclUSR(CXDecl); -CINDEX_LINKAGE const char *clang_getDeclSource(CXDecl); /* deprecate */ -CINDEX_LINKAGE CXFile clang_getDeclSourceFile(CXDecl); + +/** + * \brief Identifies a specific source location within a translation + * unit. + * + * Use clang_getInstantiationLocation() to map a source location to a + * particular file, line, and column. + */ +typedef struct { + void *ptr_data; + unsigned int_data; +} CXSourceLocation; -typedef struct CXSourceLineColumn { - unsigned line; - unsigned column; -} CXSourceLineColumn; +/** + * \brief Identifies a range of source locations in the source code. + * + * Use clang_getRangeStart() and clang_getRangeEnd() to retrieve the + * starting and end locations from a source range, respectively. + */ +typedef struct { + void *ptr_data; + unsigned begin_int_data; + unsigned end_int_data; +} CXSourceRange; + +/** + * \brief Retrieve a NULL (invalid) source location. + */ +CINDEX_LINKAGE CXSourceLocation clang_getNullLocation(); + +/** + * \determine Determine whether two source locations, which must refer into + * the same translation unit, refer to exactly the same point in the source + * code. + * + * \returns non-zero if the source locations refer to the same location, zero + * if they refer to different locations. + */ +CINDEX_LINKAGE unsigned clang_equalLocations(CXSourceLocation loc1, + CXSourceLocation loc2); + +/** + * \brief Retrieves the source location associated with a given + * file/line/column in a particular translation unit. + */ +CINDEX_LINKAGE CXSourceLocation clang_getLocation(CXTranslationUnit tu, + CXFile file, + unsigned line, + unsigned column); + +/** + * \brief Retrieve a source range given the beginning and ending source + * locations. + */ +CINDEX_LINKAGE CXSourceRange clang_getRange(CXSourceLocation begin, + CXSourceLocation end); + +/** + * \brief Retrieve the file, line, and column represented by the + * given source location. + * + * \param location the location within a source file that will be + * decomposed into its parts. + * + * \param file if non-NULL, will be set to the file to which the given + * source location points. + * + * \param line if non-NULL, will be set to the line to which the given + * source location points. + * + * \param column if non-NULL, will be set to the column to which the + * given source location points. + */ +CINDEX_LINKAGE void clang_getInstantiationLocation(CXSourceLocation location, + CXFile *file, + unsigned *line, + unsigned *column); + +/** + * \brief Retrieve a source location representing the first + * character within a source range. + */ +CINDEX_LINKAGE CXSourceLocation clang_getRangeStart(CXSourceRange range); + +/** + * \brief Retrieve a source location representing the last + * character within a source range. + */ +CINDEX_LINKAGE CXSourceLocation clang_getRangeEnd(CXSourceRange range); + +/** + * @} + */ -typedef struct CXDeclExtent { - CXSourceLineColumn begin; - CXSourceLineColumn end; -} CXSourceExtent; +/** + * \brief Describes the kind of entity that a cursor refers to. + */ +enum CXCursorKind { + /* Declarations */ + CXCursor_FirstDecl = 1, + /** + * \brief A declaration whose specific kind is not exposed via this + * interface. + * + * Unexposed declarations have the same operations as any other kind + * of declaration; one can extract their location information, + * spelling, find their definitions, etc. However, the specific kind + * of the declaration is not reported. + */ + CXCursor_UnexposedDecl = 1, + /** \brief A C or C++ struct. */ + CXCursor_StructDecl = 2, + /** \brief A C or C++ union. */ + CXCursor_UnionDecl = 3, + /** \brief A C++ class. */ + CXCursor_ClassDecl = 4, + /** \brief An enumeration. */ + CXCursor_EnumDecl = 5, + /** + * \brief A field (in C) or non-static data member (in C++) in a + * struct, union, or C++ class. + */ + CXCursor_FieldDecl = 6, + /** \brief An enumerator constant. */ + CXCursor_EnumConstantDecl = 7, + /** \brief A function. */ + CXCursor_FunctionDecl = 8, + /** \brief A variable. */ + CXCursor_VarDecl = 9, + /** \brief A function or method parameter. */ + CXCursor_ParmDecl = 10, + /** \brief An Objective-C @interface. */ + CXCursor_ObjCInterfaceDecl = 11, + /** \brief An Objective-C @interface for a category. */ + CXCursor_ObjCCategoryDecl = 12, + /** \brief An Objective-C @protocol declaration. */ + CXCursor_ObjCProtocolDecl = 13, + /** \brief An Objective-C @property declaration. */ + CXCursor_ObjCPropertyDecl = 14, + /** \brief An Objective-C instance variable. */ + CXCursor_ObjCIvarDecl = 15, + /** \brief An Objective-C instance method. */ + CXCursor_ObjCInstanceMethodDecl = 16, + /** \brief An Objective-C class method. */ + CXCursor_ObjCClassMethodDecl = 17, + /** \brief An Objective-C @implementation. */ + CXCursor_ObjCImplementationDecl = 18, + /** \brief An Objective-C @implementation for a category. */ + CXCursor_ObjCCategoryImplDecl = 19, + /** \brief A typedef */ + CXCursor_TypedefDecl = 20, + CXCursor_LastDecl = 20, + + /* References */ + CXCursor_FirstRef = 40, /* Decl references */ + CXCursor_ObjCSuperClassRef = 40, + CXCursor_ObjCProtocolRef = 41, + CXCursor_ObjCClassRef = 42, + /** + * \brief A reference to a type declaration. + * + * A type reference occurs anywhere where a type is named but not + * declared. For example, given: + * + * \code + * typedef unsigned size_type; + * size_type size; + * \endcode + * + * The typedef is a declaration of size_type (CXCursor_TypedefDecl), + * while the type of the variable "size" is referenced. The cursor + * referenced by the type of size is the typedef for size_type. + */ + CXCursor_TypeRef = 43, + CXCursor_LastRef = 43, + + /* Error conditions */ + CXCursor_FirstInvalid = 70, + CXCursor_InvalidFile = 70, + CXCursor_NoDeclFound = 71, + CXCursor_NotImplemented = 72, + CXCursor_LastInvalid = 72, + + /* Expressions */ + CXCursor_FirstExpr = 100, + + /** + * \brief An expression whose specific kind is not exposed via this + * interface. + * + * Unexposed expressions have the same operations as any other kind + * of expression; one can extract their location information, + * spelling, children, etc. However, the specific kind of the + * expression is not reported. + */ + CXCursor_UnexposedExpr = 100, + + /** + * \brief An expression that refers to some value declaration, such + * as a function, varible, or enumerator. + */ + CXCursor_DeclRefExpr = 101, + + /** + * \brief An expression that refers to a member of a struct, union, + * class, Objective-C class, etc. + */ + CXCursor_MemberRefExpr = 102, + + /** \brief An expression that calls a function. */ + CXCursor_CallExpr = 103, + + /** \brief An expression that sends a message to an Objective-C + object or class. */ + CXCursor_ObjCMessageExpr = 104, + CXCursor_LastExpr = 104, + + /* Statements */ + CXCursor_FirstStmt = 200, + /** + * \brief A statement whose specific kind is not exposed via this + * interface. + * + * Unexposed statements have the same operations as any other kind of + * statement; one can extract their location information, spelling, + * children, etc. However, the specific kind of the statement is not + * reported. + */ + CXCursor_UnexposedStmt = 200, + CXCursor_LastStmt = 200, + + /** + * \brief Cursor that represents the translation unit itself. + * + * The translation unit cursor exists primarily to act as the root + * cursor for traversing the contents of a translation unit. + */ + CXCursor_TranslationUnit = 300 +}; -/* clang_getDeclExtent() returns the physical extent of a declaration. The - * beginning line/column pair points to the start of the first token in the - * declaration, and the ending line/column pair points to the last character in - * the last token of the declaration. +/** + * \brief A cursor representing some element in the abstract syntax tree for + * a translation unit. + * + * The cursor abstraction unifies the different kinds of entities in a + * program--declaration, statements, expressions, references to declarations, + * etc.--under a single "cursor" abstraction with a common set of operations. + * Common operation for a cursor include: getting the physical location in + * a source file where the cursor points, getting the name associated with a + * cursor, and retrieving cursors for any child nodes of a particular cursor. + * + * Cursors can be produced in two specific ways. + * clang_getTranslationUnitCursor() produces a cursor for a translation unit, + * from which one can use clang_visitChildren() to explore the rest of the + * translation unit. clang_getCursor() maps from a physical source location + * to the entity that resides at that location, allowing one to map from the + * source code into the AST. */ -CINDEX_LINKAGE CXSourceExtent clang_getDeclExtent(CXDecl); +typedef struct { + enum CXCursorKind kind; + void *data[3]; +} CXCursor; -/* - * CXCursor Operations. +/** + * \defgroup CINDEX_CURSOR_MANIP Cursor manipulations + * + * @{ */ + /** - Usage: clang_getCursor() will translate a source/line/column position - into an AST cursor (to derive semantic information from the source code). + * \brief Retrieve the NULL cursor, which represents no entity. */ -CINDEX_LINKAGE CXCursor clang_getCursor(CXTranslationUnit, - const char *source_name, - unsigned line, unsigned column); - CINDEX_LINKAGE CXCursor clang_getNullCursor(void); + +/** + * \brief Retrieve the cursor that represents the given translation unit. + * + * The translation unit cursor can be used to start traversing the + * various declarations within the given translation unit. + */ +CINDEX_LINKAGE CXCursor clang_getTranslationUnitCursor(CXTranslationUnit); +/** + * \brief Determine whether two cursors are equivalent. + */ +CINDEX_LINKAGE unsigned clang_equalCursors(CXCursor, CXCursor); + +/** + * \brief Retrieve the kind of the given cursor. + */ CINDEX_LINKAGE enum CXCursorKind clang_getCursorKind(CXCursor); + +/** + * \brief Determine whether the given cursor kind represents a declaration. + */ CINDEX_LINKAGE unsigned clang_isDeclaration(enum CXCursorKind); + +/** + * \brief Determine whether the given cursor kind represents a simple + * reference. + * + * Note that other kinds of cursors (such as expressions) can also refer to + * other cursors. Use clang_getCursorReferenced() to determine whether a + * particular cursor refers to another entity. + */ CINDEX_LINKAGE unsigned clang_isReference(enum CXCursorKind); -CINDEX_LINKAGE unsigned clang_isDefinition(enum CXCursorKind); + +/** + * \brief Determine whether the given cursor kind represents an expression. + */ +CINDEX_LINKAGE unsigned clang_isExpression(enum CXCursorKind); + +/** + * \brief Determine whether the given cursor kind represents a statement. + */ +CINDEX_LINKAGE unsigned clang_isStatement(enum CXCursorKind); + +/** + * \brief Determine whether the given cursor kind represents an invalid + * cursor. + */ CINDEX_LINKAGE unsigned clang_isInvalid(enum CXCursorKind); -CINDEX_LINKAGE unsigned clang_equalCursors(CXCursor, CXCursor); +/** + * \brief Determine whether the given cursor kind represents a translation + * unit. + */ +CINDEX_LINKAGE unsigned clang_isTranslationUnit(enum CXCursorKind); + +/** + * @} + */ + +/** + * \defgroup CINDEX_CURSOR_SOURCE Mapping between cursors and source code + * + * Cursors represent a location within the Abstract Syntax Tree (AST). These + * routines help map between cursors and the physical locations where the + * described entities occur in the source code. The mapping is provided in + * both directions, so one can map from source code to the AST and back. + * + * @{ + */ + +/** + * \brief Map a source location to the cursor that describes the entity at that + * location in the source code. + * + * clang_getCursor() maps an arbitrary source location within a translation + * unit down to the most specific cursor that describes the entity at that + * location. For example, given an expression \c x + y, invoking + * clang_getCursor() with a source location pointing to "x" will return the + * cursor for "x"; similarly for "y". If the cursor points anywhere between + * "x" or "y" (e.g., on the + or the whitespace around it), clang_getCursor() + * will return a cursor referring to the "+" expression. + * + * \returns a cursor representing the entity at the given source location, or + * a NULL cursor if no such entity can be found. + */ +CINDEX_LINKAGE CXCursor clang_getCursor(CXTranslationUnit, CXSourceLocation); + +/** + * \brief Retrieve the physical location of the source constructor referenced + * by the given cursor. + * + * The location of a declaration is typically the location of the name of that + * declaration, where the name of that declaration would occur if it is + * unnamed, or some keyword that introduces that particular declaration. + * The location of a reference is where that reference occurs within the + * source code. + */ +CINDEX_LINKAGE CXSourceLocation clang_getCursorLocation(CXCursor); + +/** + * \brief Retrieve the physical extent of the source construct referenced by + * the given cursor. + * + * The extent of a cursor starts with the file/line/column pointing at the + * first character within the source construct that the cursor refers to and + * ends with the last character withinin that source construct. For a + * declaration, the extent covers the declaration itself. For a reference, + * the extent covers the location of the reference (e.g., where the referenced + * entity was actually used). + */ +CINDEX_LINKAGE CXSourceRange clang_getCursorExtent(CXCursor); -CINDEX_LINKAGE unsigned clang_getCursorLine(CXCursor); -CINDEX_LINKAGE unsigned clang_getCursorColumn(CXCursor); +/** + * @} + */ + +/** + * \defgroup CINDEX_CURSOR_TRAVERSAL Traversing the AST with cursors + * + * These routines provide the ability to traverse the abstract syntax tree + * using cursors. + * + * @{ + */ + +/** + * \brief Describes how the traversal of the children of a particular + * cursor should proceed after visiting a particular child cursor. + * + * A value of this enumeration type should be returned by each + * \c CXCursorVisitor to indicate how clang_visitChildren() proceed. + */ +enum CXChildVisitResult { + /** + * \brief Terminates the cursor traversal. + */ + CXChildVisit_Break, + /** + * \brief Continues the cursor traversal with the next sibling of + * the cursor just visited, without visiting its children. + */ + CXChildVisit_Continue, + /** + * \brief Recursively traverse the children of this cursor, using + * the same visitor and client data. + */ + CXChildVisit_Recurse +}; + +/** + * \brief Visitor invoked for each cursor found by a traversal. + * + * This visitor function will be invoked for each cursor found by + * clang_visitCursorChildren(). Its first argument is the cursor being + * visited, its second argument is the parent visitor for that cursor, + * and its third argument is the client data provided to + * clang_visitCursorChildren(). + * + * The visitor should return one of the \c CXChildVisitResult values + * to direct clang_visitCursorChildren(). + */ +typedef enum CXChildVisitResult (*CXCursorVisitor)(CXCursor cursor, + CXCursor parent, + CXClientData client_data); + +/** + * \brief Visit the children of a particular cursor. + * + * This function visits all the direct children of the given cursor, + * invoking the given \p visitor function with the cursors of each + * visited child. The traversal may be recursive, if the visitor returns + * \c CXChildVisit_Recurse. The traversal may also be ended prematurely, if + * the visitor returns \c CXChildVisit_Break. + * + * \param tu the translation unit into which the cursor refers. + * + * \param parent the cursor whose child may be visited. All kinds of + * cursors can be visited, including invalid visitors (which, by + * definition, have no children). + * + * \param visitor the visitor function that will be invoked for each + * child of \p parent. + * + * \param client_data pointer data supplied by the client, which will + * be passed to the visitor each time it is invoked. + * + * \returns a non-zero value if the traversal was terminated + * prematurely by the visitor returning \c CXChildVisit_Break. + */ +CINDEX_LINKAGE unsigned clang_visitChildren(CXCursor parent, + CXCursorVisitor visitor, + CXClientData client_data); + +/** + * @} + */ + +/** + * \defgroup CINDEX_CURSOR_XREF Cross-referencing in the AST + * + * These routines provide the ability to determine references within and + * across translation units, by providing the names of the entities referenced + * by cursors, follow reference cursors to the declarations they reference, + * and associate declarations with their definitions. + * + * @{ + */ + +/** + * \brief Retrieve a Unified Symbol Resolution (USR) for the entity referenced + * by the given cursor. + * + * A Unified Symbol Resolution (USR) is a string that identifies a particular + * entity (function, class, variable, etc.) within a program. USRs can be + * compared across translation units to determine, e.g., when references in + * one translation refer to an entity defined in another translation unit. + */ +CINDEX_LINKAGE CXString clang_getCursorUSR(CXCursor); + +/** + * \brief Retrieve a name for the entity referenced by this cursor. + */ CINDEX_LINKAGE CXString clang_getCursorSpelling(CXCursor); -CINDEX_LINKAGE const char *clang_getCursorSource(CXCursor); /* deprecate */ -CINDEX_LINKAGE CXFile clang_getCursorSourceFile(CXCursor); +/** \brief For a cursor that is a reference, retrieve a cursor representing the + * entity that it references. + * + * Reference cursors refer to other entities in the AST. For example, an + * Objective-C superclass reference cursor refers to an Objective-C class. + * This function produces the cursor for the Objective-C class from the + * cursor for the superclass reference. If the input cursor is a declaration or + * definition, it returns that declaration or definition unchanged. + * Othewise, returns the NULL cursor. + */ +CINDEX_LINKAGE CXCursor clang_getCursorReferenced(CXCursor); + +/** + * \brief For a cursor that is either a reference to or a declaration + * of some entity, retrieve a cursor that describes the definition of + * that entity. + * + * Some entities can be declared multiple times within a translation + * unit, but only one of those declarations can also be a + * definition. For example, given: + * + * \code + * int f(int, int); + * int g(int x, int y) { return f(x, y); } + * int f(int a, int b) { return a + b; } + * int f(int, int); + * \endcode + * + * there are three declarations of the function "f", but only the + * second one is a definition. The clang_getCursorDefinition() + * function will take any cursor pointing to a declaration of "f" + * (the first or fourth lines of the example) or a cursor referenced + * that uses "f" (the call to "f' inside "g") and will return a + * declaration cursor pointing to the definition (the second "f" + * declaration). + * + * If given a cursor for which there is no corresponding definition, + * e.g., because there is no definition of that entity within this + * translation unit, returns a NULL cursor. + */ +CINDEX_LINKAGE CXCursor clang_getCursorDefinition(CXCursor); + +/** + * \brief Determine whether the declaration pointed to by this cursor + * is also a definition of that entity. + */ +CINDEX_LINKAGE unsigned clang_isCursorDefinition(CXCursor); + +/** + * @} + */ + +/** + * \defgroup CINDEX_DEBUG Debugging facilities + * + * These routines are used for testing and debugging, only, and should not + * be relied upon. + * + * @{ + */ + /* for debug/testing */ CINDEX_LINKAGE const char *clang_getCursorKindSpelling(enum CXCursorKind Kind); CINDEX_LINKAGE void clang_getDefinitionSpellingAndExtent(CXCursor, @@ -396,13 +858,22 @@ CINDEX_LINKAGE void clang_getDefinitionSpellingAndExtent(CXCursor, unsigned *endLine, unsigned *endColumn); -/* - * If CXCursorKind == Cursor_Reference, then this will return the referenced - * declaration. - * If CXCursorKind == Cursor_Declaration, then this will return the declaration. +/** + * @} */ -CINDEX_LINKAGE CXDecl clang_getCursorDecl(CXCursor); - + +/** + * \defgroup CINDEX_CODE_COMPLET Code completion + * + * Code completion involves taking an (incomplete) source file, along with + * knowledge of where the user is actively editing that file, and suggesting + * syntactically- and semantically-valid constructs that the user might want to + * use at that particular point in the source code. These data structures and + * routines provide support for code completion. + * + * @{ + */ + /** * \brief A semantic string that describes a code-completion result. * @@ -771,6 +1242,27 @@ CXCodeCompleteResults *clang_codeComplete(CXIndex CIdx, CINDEX_LINKAGE void clang_disposeCodeCompleteResults(CXCodeCompleteResults *Results); +/** + * @} + */ + + +/** + * \defgroup CINDEX_MISC Miscellaneous utility functions + * + * @{ + */ + +CINDEX_LINKAGE const char *clang_getClangVersion(); + +/** + * @} + */ + +/** + * @} + */ + #ifdef __cplusplus } #endif diff --git a/include/clang/AST/ASTContext.h b/include/clang/AST/ASTContext.h index 5db8e20..e5429be 100644 --- a/include/clang/AST/ASTContext.h +++ b/include/clang/AST/ASTContext.h @@ -61,6 +61,7 @@ namespace clang { class TypedefDecl; class UsingDecl; class UsingShadowDecl; + class UnresolvedSetIterator; namespace Builtin { class Context; } @@ -397,6 +398,11 @@ public: /// BlockPointer. QualType getNoReturnType(QualType T, bool AddNoReturn = true); + /// getCallConvType - Adds the specified calling convention attribute to + /// the given type, which must be a FunctionType or a pointer to an + /// allowable type. + QualType getCallConvType(QualType T, CallingConv CallConv); + /// getComplexType - Return the uniqued reference to the type for a complex /// number with the specified element type. QualType getComplexType(QualType T); @@ -513,7 +519,8 @@ public: /// getFunctionNoProtoType - Return a K&R style C function type like 'int()'. /// - QualType getFunctionNoProtoType(QualType ResultTy, bool NoReturn = false); + QualType getFunctionNoProtoType(QualType ResultTy, bool NoReturn = false, + CallingConv CallConv = CC_Default); /// getFunctionType - Return a normal function type with a typed argument /// list. isVariadic indicates whether the argument list includes '...'. @@ -522,7 +529,8 @@ public: unsigned TypeQuals, bool hasExceptionSpec = false, bool hasAnyExceptionSpec = false, unsigned NumExs = 0, const QualType *ExArray = 0, - bool NoReturn = false); + bool NoReturn = false, + CallingConv CallConv = CC_Default); /// getTypeDeclType - Return the unique reference to the type for /// the specified type declaration. @@ -746,8 +754,8 @@ public: DeclarationName getNameForTemplate(TemplateName Name); - TemplateName getOverloadedTemplateName(NamedDecl * const *Begin, - NamedDecl * const *End); + TemplateName getOverloadedTemplateName(UnresolvedSetIterator Begin, + UnresolvedSetIterator End); TemplateName getQualifiedTemplateName(NestedNameSpecifier *NNS, bool TemplateKeyword, diff --git a/include/clang/AST/CXXInheritance.h b/include/clang/AST/CXXInheritance.h index 7c826fe..1491b1e 100644 --- a/include/clang/AST/CXXInheritance.h +++ b/include/clang/AST/CXXInheritance.h @@ -65,9 +65,21 @@ struct CXXBasePathElement { /// subobject is being used. class CXXBasePath : public llvm::SmallVector<CXXBasePathElement, 4> { public: + CXXBasePath() : Access(AS_public) {} + + /// \brief The access along this inheritance path. This is only + /// calculated when recording paths. AS_none is a special value + /// used to indicate a path which permits no legal access. + AccessSpecifier Access; + /// \brief The set of declarations found inside this base class /// subobject. DeclContext::lookup_result Decls; + + void clear() { + llvm::SmallVectorImpl<CXXBasePathElement>::clear(); + Access = AS_public; + } }; /// BasePaths - Represents the set of paths from a derived class to @@ -131,10 +143,10 @@ class CXXBasePaths { /// is also recorded. bool DetectVirtual; - /// ScratchPath - A BasePath that is used by Sema::IsDerivedFrom + /// ScratchPath - A BasePath that is used by Sema::lookupInBases /// to help build the set of paths. CXXBasePath ScratchPath; - + /// DetectedVirtual - The base class that is virtual. const RecordType *DetectedVirtual; diff --git a/include/clang/AST/Decl.h b/include/clang/AST/Decl.h index 21b5909..6d52b2b 100644 --- a/include/clang/AST/Decl.h +++ b/include/clang/AST/Decl.h @@ -55,32 +55,6 @@ public: TypeLoc getTypeLoc() const; }; -/// UnresolvedSet - A set of unresolved declarations. This is needed -/// in a lot of places, but isn't really worth breaking into its own -/// header right now. -class UnresolvedSet { - typedef llvm::SmallVector<NamedDecl*, 4> DeclsTy; - DeclsTy Decls; - -public: - void addDecl(NamedDecl *D) { - Decls.push_back(D); - } - - bool replace(const NamedDecl* Old, NamedDecl *New) { - for (DeclsTy::iterator I = Decls.begin(), E = Decls.end(); I != E; ++I) - if (*I == Old) - return (*I = New, true); - return false; - } - - unsigned size() const { return Decls.size(); } - - typedef DeclsTy::const_iterator iterator; - iterator begin() const { return Decls.begin(); } - iterator end() const { return Decls.end(); } -}; - /// TranslationUnitDecl - The top declaration context. class TranslationUnitDecl : public Decl, public DeclContext { ASTContext &Ctx; diff --git a/include/clang/AST/DeclBase.h b/include/clang/AST/DeclBase.h index 497f863..775bce2 100644 --- a/include/clang/AST/DeclBase.h +++ b/include/clang/AST/DeclBase.h @@ -16,8 +16,7 @@ #include "clang/AST/Attr.h" #include "clang/AST/Type.h" -// FIXME: Layering violation -#include "clang/Parse/AccessSpecifier.h" +#include "clang/Basic/Specifiers.h" #include "llvm/Support/PrettyStackTrace.h" #include "llvm/ADT/PointerUnion.h" @@ -1017,13 +1016,8 @@ private: }; inline bool Decl::isTemplateParameter() const { - return getKind() == TemplateTypeParm || getKind() == NonTypeTemplateParm; -} - -inline bool Decl::isDefinedOutsideFunctionOrMethod() const { - if (getDeclContext()) - return !getDeclContext()->getLookupContext()->isFunctionOrMethod(); - return true; + return getKind() == TemplateTypeParm || getKind() == NonTypeTemplateParm || + getKind() == TemplateTemplateParm; } } // end clang. diff --git a/include/clang/AST/DeclCXX.h b/include/clang/AST/DeclCXX.h index 336a895..73ebf52 100644 --- a/include/clang/AST/DeclCXX.h +++ b/include/clang/AST/DeclCXX.h @@ -16,6 +16,7 @@ #include "clang/AST/Expr.h" #include "clang/AST/Decl.h" +#include "clang/AST/UnresolvedSet.h" #include "llvm/ADT/SmallVector.h" #include "llvm/ADT/SmallPtrSet.h" @@ -275,13 +276,13 @@ class CXXRecordDecl : public RecordDecl { /// of this C++ class (but not its inherited conversion /// functions). Each of the entries in this overload set is a /// CXXConversionDecl. - UnresolvedSet Conversions; + UnresolvedSet<4> Conversions; /// VisibleConversions - Overload set containing the conversion functions /// of this C++ class and all those inherited conversion functions that /// are visible in this class. Each of the entries in this overload set is /// a CXXConversionDecl or a FunctionTemplateDecl. - UnresolvedSet VisibleConversions; + UnresolvedSet<4> VisibleConversions; /// \brief The template or declaration that this declaration /// describes or was instantiated from, respectively. @@ -483,20 +484,20 @@ public: /// getConversions - Retrieve the overload set containing all of the /// conversion functions in this class. - UnresolvedSet *getConversionFunctions() { + UnresolvedSetImpl *getConversionFunctions() { assert((this->isDefinition() || cast<RecordType>(getTypeForDecl())->isBeingDefined()) && "getConversionFunctions() called on incomplete type"); return &Conversions; } - const UnresolvedSet *getConversionFunctions() const { + const UnresolvedSetImpl *getConversionFunctions() const { assert((this->isDefinition() || cast<RecordType>(getTypeForDecl())->isBeingDefined()) && "getConversionFunctions() called on incomplete type"); return &Conversions; } - typedef UnresolvedSet::iterator conversion_iterator; + typedef UnresolvedSetImpl::iterator conversion_iterator; conversion_iterator conversion_begin() const { return Conversions.begin(); } conversion_iterator conversion_end() const { return Conversions.end(); } @@ -509,7 +510,7 @@ public: /// getVisibleConversionFunctions - get all conversion functions visible /// in current class; including conversion function templates. - const UnresolvedSet *getVisibleConversionFunctions(); + const UnresolvedSetImpl *getVisibleConversionFunctions(); /// addVisibleConversionFunction - Add a new conversion function to the /// list of visible conversion functions. @@ -816,6 +817,15 @@ public: /// GraphViz. void viewInheritance(ASTContext& Context) const; + /// MergeAccess - Calculates the access of a decl that is reached + /// along a path. + static AccessSpecifier MergeAccess(AccessSpecifier PathAccess, + AccessSpecifier DeclAccess) { + assert(DeclAccess != AS_none); + if (DeclAccess == AS_private) return AS_none; + return (PathAccess > DeclAccess ? PathAccess : DeclAccess); + } + static bool classof(const Decl *D) { return D->getKind() == CXXRecord || D->getKind() == ClassTemplateSpecialization || diff --git a/include/clang/AST/DeclObjC.h b/include/clang/AST/DeclObjC.h index 920d31f..0fb0db1 100644 --- a/include/clang/AST/DeclObjC.h +++ b/include/clang/AST/DeclObjC.h @@ -75,6 +75,24 @@ public: } }; +/// \brief A list of Objective-C protocols, along with the source +/// locations at which they were referenced. +class ObjCProtocolList : public ObjCList<ObjCProtocolDecl> { + SourceLocation *Locations; + + using ObjCList<ObjCProtocolDecl>::set; + +public: + ObjCProtocolList() : ObjCList<ObjCProtocolDecl>(), Locations(0) { } + + typedef const SourceLocation *loc_iterator; + loc_iterator loc_begin() const { return Locations; } + loc_iterator loc_end() const { return Locations + size(); } + + void set(ObjCProtocolDecl* const* InList, unsigned Elts, + const SourceLocation *Locs, ASTContext &Ctx); + void Destroy(ASTContext &Ctx); +}; /// ObjCMethodDecl - Represents an instance or class method declaration. @@ -410,9 +428,9 @@ class ObjCInterfaceDecl : public ObjCContainerDecl { ObjCInterfaceDecl *SuperClass; /// Protocols referenced in interface header declaration - ObjCList<ObjCProtocolDecl> ReferencedProtocols; + ObjCProtocolList ReferencedProtocols; - /// Instance variables in the interface. + /// Instance variables in the interface. This list is completely redundant. ObjCList<ObjCIvarDecl> IVars; /// List of categories defined for this class. @@ -442,7 +460,7 @@ public: SourceLocation ClassLoc = SourceLocation(), bool ForwardDecl = false, bool isInternal = false); - const ObjCList<ObjCProtocolDecl> &getReferencedProtocols() const { + const ObjCProtocolList &getReferencedProtocols() const { return ReferencedProtocols; } @@ -459,9 +477,16 @@ public: : getClassMethod(Sel); } - typedef ObjCList<ObjCProtocolDecl>::iterator protocol_iterator; + typedef ObjCProtocolList::iterator protocol_iterator; protocol_iterator protocol_begin() const {return ReferencedProtocols.begin();} protocol_iterator protocol_end() const { return ReferencedProtocols.end(); } + typedef ObjCProtocolList::loc_iterator protocol_loc_iterator; + protocol_loc_iterator protocol_loc_begin() const { + return ReferencedProtocols.loc_begin(); + } + protocol_loc_iterator protocol_loc_end() const { + return ReferencedProtocols.loc_end(); + } unsigned protocol_size() const { return ReferencedProtocols.size(); } typedef ObjCList<ObjCIvarDecl>::iterator ivar_iterator; @@ -473,14 +498,16 @@ public: /// setProtocolList - Set the list of protocols that this interface /// implements. void setProtocolList(ObjCProtocolDecl *const* List, unsigned Num, - ASTContext &C) { - ReferencedProtocols.set(List, Num, C); + const SourceLocation *Locs, ASTContext &C) { + ReferencedProtocols.set(List, Num, Locs, C); } /// mergeClassExtensionProtocolList - Merge class extension's protocol list /// into the protocol list for this class. - void mergeClassExtensionProtocolList(ObjCProtocolDecl *const* List, unsigned Num, - ASTContext &C); + void mergeClassExtensionProtocolList(ObjCProtocolDecl *const* List, + unsigned Num, + const SourceLocation *Locs, + ASTContext &C); void setIVarList(ObjCIvarDecl * const *List, unsigned Num, ASTContext &C) { IVars.set(List, Num, C); @@ -660,7 +687,7 @@ public: /// class ObjCProtocolDecl : public ObjCContainerDecl { /// Referenced protocols - ObjCList<ObjCProtocolDecl> ReferencedProtocols; + ObjCProtocolList ReferencedProtocols; bool isForwardProtoDecl; // declared with @protocol. @@ -680,19 +707,26 @@ public: /// Destroy - Call destructors and release memory. virtual void Destroy(ASTContext& C); - const ObjCList<ObjCProtocolDecl> &getReferencedProtocols() const { + const ObjCProtocolList &getReferencedProtocols() const { return ReferencedProtocols; } - typedef ObjCList<ObjCProtocolDecl>::iterator protocol_iterator; + typedef ObjCProtocolList::iterator protocol_iterator; protocol_iterator protocol_begin() const {return ReferencedProtocols.begin();} protocol_iterator protocol_end() const { return ReferencedProtocols.end(); } + typedef ObjCProtocolList::loc_iterator protocol_loc_iterator; + protocol_loc_iterator protocol_loc_begin() const { + return ReferencedProtocols.loc_begin(); + } + protocol_loc_iterator protocol_loc_end() const { + return ReferencedProtocols.loc_end(); + } unsigned protocol_size() const { return ReferencedProtocols.size(); } /// setProtocolList - Set the list of protocols that this interface /// implements. void setProtocolList(ObjCProtocolDecl *const*List, unsigned Num, - ASTContext &C) { - ReferencedProtocols.set(List, Num, C); + const SourceLocation *Locs, ASTContext &C) { + ReferencedProtocols.set(List, Num, Locs, C); } ObjCProtocolDecl *lookupProtocolNamed(IdentifierInfo *PName); @@ -772,31 +806,45 @@ public: /// @protocol NSTextInput, NSChangeSpelling, NSDraggingInfo; /// class ObjCForwardProtocolDecl : public Decl { - ObjCList<ObjCProtocolDecl> ReferencedProtocols; + ObjCProtocolList ReferencedProtocols; ObjCForwardProtocolDecl(DeclContext *DC, SourceLocation L, ObjCProtocolDecl *const *Elts, unsigned nElts, - ASTContext &C); + const SourceLocation *Locs, ASTContext &C); virtual ~ObjCForwardProtocolDecl() {} public: static ObjCForwardProtocolDecl *Create(ASTContext &C, DeclContext *DC, SourceLocation L, - ObjCProtocolDecl *const *Elts = 0, - unsigned Num = 0); + ObjCProtocolDecl *const *Elts, + unsigned Num, + const SourceLocation *Locs); + + static ObjCForwardProtocolDecl *Create(ASTContext &C, DeclContext *DC, + SourceLocation L) { + return Create(C, DC, L, 0, 0, 0); + } /// Destroy - Call destructors and release memory. virtual void Destroy(ASTContext& C); - typedef ObjCList<ObjCProtocolDecl>::iterator protocol_iterator; + typedef ObjCProtocolList::iterator protocol_iterator; protocol_iterator protocol_begin() const {return ReferencedProtocols.begin();} protocol_iterator protocol_end() const { return ReferencedProtocols.end(); } + typedef ObjCProtocolList::loc_iterator protocol_loc_iterator; + protocol_loc_iterator protocol_loc_begin() const { + return ReferencedProtocols.loc_begin(); + } + protocol_loc_iterator protocol_loc_end() const { + return ReferencedProtocols.loc_end(); + } + unsigned protocol_size() const { return ReferencedProtocols.size(); } /// setProtocolList - Set the list of forward protocols. void setProtocolList(ObjCProtocolDecl *const*List, unsigned Num, - ASTContext &C) { - ReferencedProtocols.set(List, Num, C); + const SourceLocation *Locs, ASTContext &C) { + ReferencedProtocols.set(List, Num, Locs, C); } static bool classof(const Decl *D) { return D->getKind() == ObjCForwardProtocol; @@ -826,22 +874,32 @@ class ObjCCategoryDecl : public ObjCContainerDecl { ObjCInterfaceDecl *ClassInterface; /// referenced protocols in this category. - ObjCList<ObjCProtocolDecl> ReferencedProtocols; + ObjCProtocolList ReferencedProtocols; /// Next category belonging to this class. /// FIXME: this should not be a singly-linked list. Move storage elsewhere. ObjCCategoryDecl *NextClassCategory; - SourceLocation EndLoc; // marks the '>' or identifier. + /// \brief The location of the '@' in '@interface' + SourceLocation AtLoc; - ObjCCategoryDecl(DeclContext *DC, SourceLocation L, IdentifierInfo *Id) - : ObjCContainerDecl(ObjCCategory, DC, L, Id), - ClassInterface(0), NextClassCategory(0){ + /// \brief The location of the category name in this declaration. + SourceLocation CategoryNameLoc; + + ObjCCategoryDecl(DeclContext *DC, SourceLocation AtLoc, + SourceLocation ClassNameLoc, SourceLocation CategoryNameLoc, + IdentifierInfo *Id) + : ObjCContainerDecl(ObjCCategory, DC, ClassNameLoc, Id), + ClassInterface(0), NextClassCategory(0), AtLoc(AtLoc), + CategoryNameLoc(CategoryNameLoc) { } public: static ObjCCategoryDecl *Create(ASTContext &C, DeclContext *DC, - SourceLocation L, IdentifierInfo *Id); + SourceLocation AtLoc, + SourceLocation ClassNameLoc, + SourceLocation CategoryNameLoc, + IdentifierInfo *Id); ObjCInterfaceDecl *getClassInterface() { return ClassInterface; } const ObjCInterfaceDecl *getClassInterface() const { return ClassInterface; } @@ -853,18 +911,25 @@ public: /// setProtocolList - Set the list of protocols that this interface /// implements. void setProtocolList(ObjCProtocolDecl *const*List, unsigned Num, - ASTContext &C) { - ReferencedProtocols.set(List, Num, C); + const SourceLocation *Locs, ASTContext &C) { + ReferencedProtocols.set(List, Num, Locs, C); } - const ObjCList<ObjCProtocolDecl> &getReferencedProtocols() const { + const ObjCProtocolList &getReferencedProtocols() const { return ReferencedProtocols; } - typedef ObjCList<ObjCProtocolDecl>::iterator protocol_iterator; + typedef ObjCProtocolList::iterator protocol_iterator; protocol_iterator protocol_begin() const {return ReferencedProtocols.begin();} protocol_iterator protocol_end() const { return ReferencedProtocols.end(); } unsigned protocol_size() const { return ReferencedProtocols.size(); } + typedef ObjCProtocolList::loc_iterator protocol_loc_iterator; + protocol_loc_iterator protocol_loc_begin() const { + return ReferencedProtocols.loc_begin(); + } + protocol_loc_iterator protocol_loc_end() const { + return ReferencedProtocols.loc_end(); + } ObjCCategoryDecl *getNextClassCategory() const { return NextClassCategory; } void setNextClassCategory(ObjCCategoryDecl *Cat) { @@ -874,10 +939,16 @@ public: NextClassCategory = ClassInterface->getCategoryList(); ClassInterface->setCategoryList(this); } - // Location information, modeled after the Stmt API. - SourceLocation getLocStart() const { return getLocation(); } // '@'interface - SourceLocation getLocEnd() const { return EndLoc; } - void setLocEnd(SourceLocation LE) { EndLoc = LE; } + + SourceLocation getAtLoc() const { return AtLoc; } + void setAtLoc(SourceLocation At) { AtLoc = At; } + + SourceLocation getCategoryNameLoc() const { return CategoryNameLoc; } + void setCategoryNameLoc(SourceLocation Loc) { CategoryNameLoc = Loc; } + + virtual SourceRange getSourceRange() const { + return SourceRange(AtLoc, getAtEndRange().getEnd()); + } static bool classof(const Decl *D) { return D->getKind() == ObjCCategory; } static bool classof(const ObjCCategoryDecl *D) { return true; } @@ -1133,6 +1204,7 @@ public: enum SetterKind { Assign, Retain, Copy }; enum PropertyControl { None, Required, Optional }; private: + SourceLocation AtLoc; // location of @property QualType DeclType; unsigned PropertyAttributes : 8; @@ -1147,8 +1219,8 @@ private: ObjCIvarDecl *PropertyIvarDecl; // Synthesize ivar for this property ObjCPropertyDecl(DeclContext *DC, SourceLocation L, IdentifierInfo *Id, - QualType T) - : NamedDecl(ObjCProperty, DC, L, Id), DeclType(T), + SourceLocation AtLocation, QualType T) + : NamedDecl(ObjCProperty, DC, L, Id), AtLoc(AtLocation), DeclType(T), PropertyAttributes(OBJC_PR_noattr), PropertyImplementation(None), GetterName(Selector()), SetterName(Selector()), @@ -1156,8 +1228,12 @@ private: public: static ObjCPropertyDecl *Create(ASTContext &C, DeclContext *DC, SourceLocation L, - IdentifierInfo *Id, QualType T, + IdentifierInfo *Id, SourceLocation AtLocation, + QualType T, PropertyControl propControl = None); + SourceLocation getAtLoc() const { return AtLoc; } + void setAtLoc(SourceLocation L) { AtLoc = L; } + QualType getType() const { return DeclType; } void setType(QualType T) { DeclType = T; } diff --git a/include/clang/AST/Expr.h b/include/clang/AST/Expr.h index cfbae9f..2527817 100644 --- a/include/clang/AST/Expr.h +++ b/include/clang/AST/Expr.h @@ -1462,14 +1462,19 @@ class CompoundLiteralExpr : public Expr { /// compound literal like "(int){4}". This can be null if this is a /// synthesized compound expression. SourceLocation LParenLoc; + + /// The type as written. This can be an incomplete array type, in + /// which case the actual expression type will be different. + TypeSourceInfo *TInfo; Stmt *Init; bool FileScope; public: // FIXME: Can compound literals be value-dependent? - CompoundLiteralExpr(SourceLocation lparenloc, QualType ty, Expr *init, - bool fileScope) - : Expr(CompoundLiteralExprClass, ty, ty->isDependentType(), false), - LParenLoc(lparenloc), Init(init), FileScope(fileScope) {} + CompoundLiteralExpr(SourceLocation lparenloc, TypeSourceInfo *tinfo, + QualType T, Expr *init, bool fileScope) + : Expr(CompoundLiteralExprClass, T, + tinfo->getType()->isDependentType(), false), + LParenLoc(lparenloc), TInfo(tinfo), Init(init), FileScope(fileScope) {} /// \brief Construct an empty compound literal. explicit CompoundLiteralExpr(EmptyShell Empty) @@ -1485,6 +1490,9 @@ public: SourceLocation getLParenLoc() const { return LParenLoc; } void setLParenLoc(SourceLocation L) { LParenLoc = L; } + TypeSourceInfo *getTypeSourceInfo() const { return TInfo; } + void setTypeSourceInfo(TypeSourceInfo* tinfo) { TInfo = tinfo; } + virtual SourceRange getSourceRange() const { // FIXME: Init should never be null. if (!Init) @@ -1712,24 +1720,28 @@ public: /// expression will be an lvalue. The reference type, however, will /// not be used as the type of the expression. class ExplicitCastExpr : public CastExpr { - /// TypeAsWritten - The type that this expression is casting to, as - /// written in the source code. - QualType TypeAsWritten; + /// TInfo - Source type info for the (written) type + /// this expression is casting to. + TypeSourceInfo *TInfo; protected: ExplicitCastExpr(StmtClass SC, QualType exprTy, CastKind kind, - Expr *op, QualType writtenTy) - : CastExpr(SC, exprTy, kind, op), TypeAsWritten(writtenTy) {} + Expr *op, TypeSourceInfo *writtenTy) + : CastExpr(SC, exprTy, kind, op), TInfo(writtenTy) {} /// \brief Construct an empty explicit cast. ExplicitCastExpr(StmtClass SC, EmptyShell Shell) : CastExpr(SC, Shell) { } public: + /// getTypeInfoAsWritten - Returns the type source info for the type + /// that this expression is casting to. + TypeSourceInfo *getTypeInfoAsWritten() const { return TInfo; } + void setTypeInfoAsWritten(TypeSourceInfo *writtenTy) { TInfo = writtenTy; } + /// getTypeAsWritten - Returns the type that this expression is /// casting to, as written in the source code. - QualType getTypeAsWritten() const { return TypeAsWritten; } - void setTypeAsWritten(QualType T) { TypeAsWritten = T; } + QualType getTypeAsWritten() const { return TInfo->getType(); } static bool classof(const Stmt *T) { StmtClass SC = T->getStmtClass(); @@ -1750,8 +1762,9 @@ class CStyleCastExpr : public ExplicitCastExpr { SourceLocation LPLoc; // the location of the left paren SourceLocation RPLoc; // the location of the right paren public: - CStyleCastExpr(QualType exprTy, CastKind kind, Expr *op, QualType writtenTy, - SourceLocation l, SourceLocation r) : + CStyleCastExpr(QualType exprTy, CastKind kind, Expr *op, + TypeSourceInfo *writtenTy, + SourceLocation l, SourceLocation r) : ExplicitCastExpr(CStyleCastExprClass, exprTy, kind, op, writtenTy), LPLoc(l), RPLoc(r) {} diff --git a/include/clang/AST/ExprCXX.h b/include/clang/AST/ExprCXX.h index 55d5108e..6ce95ac 100644 --- a/include/clang/AST/ExprCXX.h +++ b/include/clang/AST/ExprCXX.h @@ -16,7 +16,7 @@ #include "clang/Basic/TypeTraits.h" #include "clang/AST/Expr.h" -#include "clang/AST/Decl.h" +#include "clang/AST/UnresolvedSet.h" #include "clang/AST/TemplateBase.h" namespace clang { @@ -118,9 +118,12 @@ private: protected: CXXNamedCastExpr(StmtClass SC, QualType ty, CastKind kind, Expr *op, - QualType writtenTy, SourceLocation l) + TypeSourceInfo *writtenTy, SourceLocation l) : ExplicitCastExpr(SC, ty, kind, op, writtenTy), Loc(l) {} + explicit CXXNamedCastExpr(StmtClass SC, EmptyShell Shell) + : ExplicitCastExpr(SC, Shell) { } + public: const char *getCastName() const; @@ -154,9 +157,12 @@ public: class CXXStaticCastExpr : public CXXNamedCastExpr { public: CXXStaticCastExpr(QualType ty, CastKind kind, Expr *op, - QualType writtenTy, SourceLocation l) + TypeSourceInfo *writtenTy, SourceLocation l) : CXXNamedCastExpr(CXXStaticCastExprClass, ty, kind, op, writtenTy, l) {} + explicit CXXStaticCastExpr(EmptyShell Empty) + : CXXNamedCastExpr(CXXStaticCastExprClass, Empty) { } + static bool classof(const Stmt *T) { return T->getStmtClass() == CXXStaticCastExprClass; } @@ -171,10 +177,13 @@ public: /// @c dynamic_cast<Derived*>(BasePtr). class CXXDynamicCastExpr : public CXXNamedCastExpr { public: - CXXDynamicCastExpr(QualType ty, CastKind kind, Expr *op, QualType writtenTy, - SourceLocation l) + CXXDynamicCastExpr(QualType ty, CastKind kind, Expr *op, + TypeSourceInfo *writtenTy, SourceLocation l) : CXXNamedCastExpr(CXXDynamicCastExprClass, ty, kind, op, writtenTy, l) {} + explicit CXXDynamicCastExpr(EmptyShell Empty) + : CXXNamedCastExpr(CXXDynamicCastExprClass, Empty) { } + static bool classof(const Stmt *T) { return T->getStmtClass() == CXXDynamicCastExprClass; } @@ -190,10 +199,13 @@ public: class CXXReinterpretCastExpr : public CXXNamedCastExpr { public: CXXReinterpretCastExpr(QualType ty, CastKind kind, Expr *op, - QualType writtenTy, SourceLocation l) + TypeSourceInfo *writtenTy, SourceLocation l) : CXXNamedCastExpr(CXXReinterpretCastExprClass, ty, kind, op, writtenTy, l) {} + explicit CXXReinterpretCastExpr(EmptyShell Empty) + : CXXNamedCastExpr(CXXReinterpretCastExprClass, Empty) { } + static bool classof(const Stmt *T) { return T->getStmtClass() == CXXReinterpretCastExprClass; } @@ -207,10 +219,13 @@ public: /// @c const_cast<char*>(PtrToConstChar). class CXXConstCastExpr : public CXXNamedCastExpr { public: - CXXConstCastExpr(QualType ty, Expr *op, QualType writtenTy, + CXXConstCastExpr(QualType ty, Expr *op, TypeSourceInfo *writtenTy, SourceLocation l) : CXXNamedCastExpr(CXXConstCastExprClass, ty, CK_NoOp, op, writtenTy, l) {} + explicit CXXConstCastExpr(EmptyShell Empty) + : CXXNamedCastExpr(CXXConstCastExprClass, Empty) { } + static bool classof(const Stmt *T) { return T->getStmtClass() == CXXConstCastExprClass; } @@ -625,15 +640,20 @@ class CXXFunctionalCastExpr : public ExplicitCastExpr { SourceLocation TyBeginLoc; SourceLocation RParenLoc; public: - CXXFunctionalCastExpr(QualType ty, QualType writtenTy, + CXXFunctionalCastExpr(QualType ty, TypeSourceInfo *writtenTy, SourceLocation tyBeginLoc, CastKind kind, Expr *castExpr, SourceLocation rParenLoc) : ExplicitCastExpr(CXXFunctionalCastExprClass, ty, kind, castExpr, writtenTy), TyBeginLoc(tyBeginLoc), RParenLoc(rParenLoc) {} + explicit CXXFunctionalCastExpr(EmptyShell Shell) + : ExplicitCastExpr(CXXFunctionalCastExprClass, Shell) { } + SourceLocation getTypeBeginLoc() const { return TyBeginLoc; } + void setTypeBeginLoc(SourceLocation L) { TyBeginLoc = L; } SourceLocation getRParenLoc() const { return RParenLoc; } + void setRParenLoc(SourceLocation L) { RParenLoc = L; } virtual SourceRange getSourceRange() const { return SourceRange(TyBeginLoc, RParenLoc); @@ -1052,7 +1072,7 @@ public: class UnresolvedLookupExpr : public Expr { /// The results. These are undesugared, which is to say, they may /// include UsingShadowDecls. - UnresolvedSet Results; + UnresolvedSet<4> Results; /// The name declared. DeclarationName Name; @@ -1113,15 +1133,15 @@ public: /// Computes whether an unresolved lookup on the given declarations /// and optional template arguments is type- and value-dependent. - static bool ComputeDependence(NamedDecl * const *Begin, - NamedDecl * const *End, + static bool ComputeDependence(UnresolvedSetImpl::const_iterator Begin, + UnresolvedSetImpl::const_iterator End, const TemplateArgumentListInfo *Args); void addDecl(NamedDecl *Decl) { Results.addDecl(Decl); } - typedef UnresolvedSet::iterator decls_iterator; + typedef UnresolvedSetImpl::iterator decls_iterator; decls_iterator decls_begin() const { return Results.begin(); } decls_iterator decls_end() const { return Results.end(); } @@ -1696,7 +1716,7 @@ public: class UnresolvedMemberExpr : public Expr { /// The results. These are undesugared, which is to say, they may /// include UsingShadowDecls. - UnresolvedSet Results; + UnresolvedSet<4> Results; /// \brief The expression for the base pointer or class reference, /// e.g., the \c x in x.f. This can be null if this is an 'unbased' @@ -1775,7 +1795,7 @@ public: Results.addDecl(Decl); } - typedef UnresolvedSet::iterator decls_iterator; + typedef UnresolvedSetImpl::iterator decls_iterator; decls_iterator decls_begin() const { return Results.begin(); } decls_iterator decls_end() const { return Results.end(); } diff --git a/include/clang/AST/Type.h b/include/clang/AST/Type.h index 9b0cdc3..b7b60df 100644 --- a/include/clang/AST/Type.h +++ b/include/clang/AST/Type.h @@ -385,6 +385,14 @@ public: } }; +/// CallingConv - Specifies the calling convention that a function uses. +enum CallingConv { + CC_Default, + CC_C, // __attribute__((cdecl)) + CC_X86StdCall, // __attribute__((stdcall)) + CC_X86FastCall // __attribute__((fastcall)) +}; + /// QualType - For efficiency, we don't store CV-qualified types as nodes on /// their own: instead each reference to a type stores the qualifiers. This @@ -669,6 +677,10 @@ public: /// 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 @@ -1691,21 +1703,25 @@ class FunctionType : public Type { /// NoReturn - Indicates if the function type is attribute noreturn. unsigned NoReturn : 1; + /// CallConv - The calling convention used by the function. + unsigned CallConv : 2; + // The type returned by the function. QualType ResultType; protected: FunctionType(TypeClass tc, QualType res, bool SubclassInfo, unsigned typeQuals, QualType Canonical, bool Dependent, - bool noReturn = false) + bool noReturn = false, CallingConv callConv = CC_Default) : Type(tc, Canonical, Dependent), SubClassData(SubclassInfo), TypeQuals(typeQuals), NoReturn(noReturn), - ResultType(res) {} + CallConv(callConv), ResultType(res) {} bool getSubClassData() const { return SubClassData; } unsigned getTypeQuals() const { return TypeQuals; } public: QualType getResultType() const { return ResultType; } bool getNoReturnAttr() const { return NoReturn; } + CallingConv getCallConv() const { return (CallingConv)CallConv; } static bool classof(const Type *T) { return T->getTypeClass() == FunctionNoProto || @@ -1718,9 +1734,9 @@ public: /// no information available about its arguments. class FunctionNoProtoType : public FunctionType, public llvm::FoldingSetNode { FunctionNoProtoType(QualType Result, QualType Canonical, - bool NoReturn = false) + bool NoReturn = false, CallingConv CallConv = CC_Default) : FunctionType(FunctionNoProto, Result, false, 0, Canonical, - /*Dependent=*/false, NoReturn) {} + /*Dependent=*/false, NoReturn, CallConv) {} friend class ASTContext; // ASTContext creates these. public: // No additional state past what FunctionType provides. @@ -1762,10 +1778,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) + unsigned numExs, QualType Canonical, bool NoReturn, + CallingConv CallConv) : FunctionType(FunctionProto, Result, isVariadic, typeQuals, Canonical, (Result->isDependentType() || - hasAnyDependentType(ArgArray, numArgs)), NoReturn), + hasAnyDependentType(ArgArray, numArgs)), NoReturn, + CallConv), NumArgs(numArgs), NumExceptions(numExs), HasExceptionSpec(hasExs), AnyExceptionSpec(hasAnyExs) { // Fill in the trailing argument array. @@ -2496,26 +2514,31 @@ class ObjCInterfaceType : public Type, public llvm::FoldingSetNode { // List of protocols for this protocol conforming object type // List is sorted on protocol name. No protocol is enterred more than once. - llvm::SmallVector<ObjCProtocolDecl*, 4> Protocols; + ObjCProtocolDecl **Protocols; + unsigned NumProtocols; - ObjCInterfaceType(QualType Canonical, ObjCInterfaceDecl *D, - ObjCProtocolDecl **Protos, unsigned NumP) : - Type(ObjCInterface, Canonical, /*Dependent=*/false), - Decl(D), Protocols(Protos, Protos+NumP) { } + ObjCInterfaceType(ASTContext &Ctx, QualType Canonical, ObjCInterfaceDecl *D, + ObjCProtocolDecl **Protos, unsigned NumP); friend class ASTContext; // ASTContext creates these. public: + void Destroy(ASTContext& C); + ObjCInterfaceDecl *getDecl() const { return Decl; } /// getNumProtocols - Return the number of qualifying protocols in this /// interface type, or 0 if there are none. - unsigned getNumProtocols() const { return Protocols.size(); } + unsigned getNumProtocols() const { return NumProtocols; } /// qual_iterator and friends: this provides access to the (potentially empty) /// list of protocols qualifying this interface. - typedef llvm::SmallVector<ObjCProtocolDecl*, 8>::const_iterator qual_iterator; - qual_iterator qual_begin() const { return Protocols.begin(); } - qual_iterator qual_end() const { return Protocols.end(); } - bool qual_empty() const { return Protocols.size() == 0; } + typedef ObjCProtocolDecl* const * qual_iterator; + qual_iterator qual_begin() const { + return Protocols; + } + qual_iterator qual_end() const { + return Protocols ? Protocols + NumProtocols : 0; + } + bool qual_empty() const { return NumProtocols == 0; } bool isSugared() const { return false; } QualType desugar() const { return QualType(this, 0); } @@ -2541,15 +2564,16 @@ class ObjCObjectPointerType : public Type, public llvm::FoldingSetNode { // List of protocols for this protocol conforming object type // List is sorted on protocol name. No protocol is entered more than once. - llvm::SmallVector<ObjCProtocolDecl*, 8> Protocols; + ObjCProtocolDecl **Protocols; + unsigned NumProtocols; - ObjCObjectPointerType(QualType Canonical, QualType T, - ObjCProtocolDecl **Protos, unsigned NumP) : - Type(ObjCObjectPointer, Canonical, /*Dependent=*/false), - PointeeType(T), Protocols(Protos, Protos+NumP) { } + ObjCObjectPointerType(ASTContext &Ctx, QualType Canonical, QualType T, + ObjCProtocolDecl **Protos, unsigned NumP); friend class ASTContext; // ASTContext creates these. public: + void Destroy(ASTContext& C); + // Get the pointee type. Pointee will either be: // - a built-in type (for 'id' and 'Class'). // - an interface type (for user-defined types). @@ -2567,35 +2591,39 @@ public: /// isObjCIdType - true for "id". bool isObjCIdType() const { return getPointeeType()->isSpecificBuiltinType(BuiltinType::ObjCId) && - !Protocols.size(); + !NumProtocols; } /// isObjCClassType - true for "Class". bool isObjCClassType() const { return getPointeeType()->isSpecificBuiltinType(BuiltinType::ObjCClass) && - !Protocols.size(); + !NumProtocols; } /// isObjCQualifiedIdType - true for "id <p>". bool isObjCQualifiedIdType() const { return getPointeeType()->isSpecificBuiltinType(BuiltinType::ObjCId) && - Protocols.size(); + NumProtocols; } /// isObjCQualifiedClassType - true for "Class <p>". bool isObjCQualifiedClassType() const { return getPointeeType()->isSpecificBuiltinType(BuiltinType::ObjCClass) && - Protocols.size(); + NumProtocols; } /// qual_iterator and friends: this provides access to the (potentially empty) /// list of protocols qualifying this interface. - typedef llvm::SmallVector<ObjCProtocolDecl*, 8>::const_iterator qual_iterator; + typedef ObjCProtocolDecl* const * qual_iterator; - qual_iterator qual_begin() const { return Protocols.begin(); } - qual_iterator qual_end() const { return Protocols.end(); } - bool qual_empty() const { return Protocols.size() == 0; } + qual_iterator qual_begin() const { + return Protocols; + } + qual_iterator qual_end() const { + return Protocols ? Protocols + NumProtocols : NULL; + } + bool qual_empty() const { return NumProtocols == 0; } /// getNumProtocols - Return the number of qualifying protocols in this /// interface type, or 0 if there are none. - unsigned getNumProtocols() const { return Protocols.size(); } + unsigned getNumProtocols() const { return NumProtocols; } bool isSugared() const { return false; } QualType desugar() const { return QualType(this, 0); } @@ -2797,6 +2825,26 @@ inline bool QualType::getNoReturnAttr() const { return false; } +/// 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; +} + /// isMoreQualifiedThan - Determine whether this type is more /// qualified than the Other type. For example, "const volatile int" /// is more qualified than "const int", "volatile int", and diff --git a/include/clang/AST/TypeLoc.h b/include/clang/AST/TypeLoc.h index c36c0ff..6fb51ed 100644 --- a/include/clang/AST/TypeLoc.h +++ b/include/clang/AST/TypeLoc.h @@ -16,6 +16,7 @@ #include "clang/AST/Type.h" #include "clang/AST/TemplateBase.h" +#include "clang/Basic/Specifiers.h" namespace clang { class ParmVarDecl; @@ -372,6 +373,111 @@ public: }; +struct BuiltinLocInfo { + SourceLocation BuiltinLoc; +}; + +/// \brief Wrapper for source info for builtin types. +class BuiltinTypeLoc : public ConcreteTypeLoc<UnqualTypeLoc, + BuiltinTypeLoc, + BuiltinType, + BuiltinLocInfo> { +public: + enum { LocalDataSize = sizeof(BuiltinLocInfo) }; + + SourceLocation getBuiltinLoc() const { + return getLocalData()->BuiltinLoc; + } + void setBuiltinLoc(SourceLocation Loc) { + getLocalData()->BuiltinLoc = Loc; + } + + SourceLocation getNameLoc() const { return getBuiltinLoc(); } + + WrittenBuiltinSpecs& getWrittenBuiltinSpecs() { + return *(static_cast<WrittenBuiltinSpecs*>(getExtraLocalData())); + } + const WrittenBuiltinSpecs& getWrittenBuiltinSpecs() const { + return *(static_cast<WrittenBuiltinSpecs*>(getExtraLocalData())); + } + + bool needsExtraLocalData() const { + BuiltinType::Kind bk = getTypePtr()->getKind(); + return (bk >= BuiltinType::UShort && bk <= BuiltinType::UInt128) + || (bk >= BuiltinType::Short && bk <= BuiltinType::LongDouble) + || bk == BuiltinType::UChar + || bk == BuiltinType::SChar; + } + + unsigned getExtraLocalDataSize() const { + return needsExtraLocalData() ? sizeof(WrittenBuiltinSpecs) : 0; + } + + SourceRange getSourceRange() const { + return SourceRange(getBuiltinLoc(), getBuiltinLoc()); + } + + TypeSpecifierSign getWrittenSignSpec() const { + if (needsExtraLocalData()) + return static_cast<TypeSpecifierSign>(getWrittenBuiltinSpecs().Sign); + else + return TSS_unspecified; + } + bool hasWrittenSignSpec() const { + return getWrittenSignSpec() != TSS_unspecified; + } + void setWrittenSignSpec(TypeSpecifierSign written) { + if (needsExtraLocalData()) + getWrittenBuiltinSpecs().Sign = written; + } + + TypeSpecifierWidth getWrittenWidthSpec() const { + if (needsExtraLocalData()) + return static_cast<TypeSpecifierWidth>(getWrittenBuiltinSpecs().Width); + else + return TSW_unspecified; + } + bool hasWrittenWidthSpec() const { + return getWrittenWidthSpec() != TSW_unspecified; + } + void setWrittenWidthSpec(TypeSpecifierWidth written) { + if (needsExtraLocalData()) + getWrittenBuiltinSpecs().Width = written; + } + + TypeSpecifierType getWrittenTypeSpec() const; + bool hasWrittenTypeSpec() const { + return getWrittenTypeSpec() != TST_unspecified; + } + void setWrittenTypeSpec(TypeSpecifierType written) { + if (needsExtraLocalData()) + getWrittenBuiltinSpecs().Type = written; + } + + bool hasModeAttr() const { + if (needsExtraLocalData()) + return getWrittenBuiltinSpecs().ModeAttr; + else + return false; + } + void setModeAttr(bool written) { + if (needsExtraLocalData()) + getWrittenBuiltinSpecs().ModeAttr = written; + } + + void initializeLocal(SourceLocation Loc) { + setBuiltinLoc(Loc); + if (needsExtraLocalData()) { + WrittenBuiltinSpecs &wbs = getWrittenBuiltinSpecs(); + wbs.Sign = TSS_unspecified; + wbs.Width = TSW_unspecified; + wbs.Type = TST_unspecified; + wbs.ModeAttr = false; + } + } +}; + + /// \brief Wrapper for source info for typedefs. class TypedefTypeLoc : public InheritingConcreteTypeLoc<TypeSpecTypeLoc, TypedefTypeLoc, @@ -421,12 +527,6 @@ public: EnumDecl *getDecl() const { return getTypePtr()->getDecl(); } }; -/// \brief Wrapper for source info for builtin types. -class BuiltinTypeLoc : public InheritingConcreteTypeLoc<TypeSpecTypeLoc, - BuiltinTypeLoc, - BuiltinType> { -}; - /// \brief Wrapper for template type parameters. class TemplateTypeParmTypeLoc : public InheritingConcreteTypeLoc<TypeSpecTypeLoc, diff --git a/include/clang/AST/TypeLocVisitor.h b/include/clang/AST/TypeLocVisitor.h index 95ec175..50fc439 100644 --- a/include/clang/AST/TypeLocVisitor.h +++ b/include/clang/AST/TypeLocVisitor.h @@ -43,6 +43,7 @@ public: case TypeLoc::CLASS: DISPATCH(CLASS##TypeLoc); #include "clang/AST/TypeLocNodes.def" } + llvm_unreachable("unexpected type loc class!"); } #define TYPELOC(CLASS, PARENT) \ diff --git a/include/clang/AST/UnresolvedSet.h b/include/clang/AST/UnresolvedSet.h new file mode 100644 index 0000000..055d152 --- /dev/null +++ b/include/clang/AST/UnresolvedSet.h @@ -0,0 +1,211 @@ +//===-- UnresolvedSet.h - Unresolved sets of declarations ------*- C++ -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// +// This file defines the UnresolvedSet class, which is used to store +// collections of declarations in the AST. +// +//===----------------------------------------------------------------------===// + +#ifndef LLVM_CLANG_AST_UNRESOLVEDSET_H +#define LLVM_CLANG_AST_UNRESOLVEDSET_H + +#include <iterator> +#include "llvm/ADT/PointerIntPair.h" +#include "llvm/ADT/SmallVector.h" +#include "clang/Basic/Specifiers.h" + +namespace clang { + +class NamedDecl; + +/// The iterator over UnresolvedSets. Serves as both the const and +/// non-const iterator. +class UnresolvedSetIterator { + + typedef llvm::PointerIntPair<NamedDecl*, 2> DeclEntry; + typedef llvm::SmallVectorImpl<DeclEntry> DeclsTy; + typedef DeclsTy::iterator IteratorTy; + + IteratorTy ir; + + friend class UnresolvedSetImpl; + explicit UnresolvedSetIterator(DeclsTy::iterator ir) : ir(ir) {} + explicit UnresolvedSetIterator(DeclsTy::const_iterator ir) : + ir(const_cast<DeclsTy::iterator>(ir)) {} +public: + UnresolvedSetIterator() {} + + typedef std::iterator_traits<IteratorTy>::difference_type difference_type; + typedef NamedDecl *value_type; + typedef NamedDecl **pointer; + typedef NamedDecl *reference; + typedef std::iterator_traits<IteratorTy>::iterator_category iterator_category; + + NamedDecl *getDecl() const { return ir->getPointer(); } + AccessSpecifier getAccess() const { return AccessSpecifier(ir->getInt()); } + + NamedDecl *operator*() const { return getDecl(); } + + UnresolvedSetIterator &operator++() { ++ir; return *this; } + UnresolvedSetIterator operator++(int) { return UnresolvedSetIterator(ir++); } + UnresolvedSetIterator &operator--() { --ir; return *this; } + UnresolvedSetIterator operator--(int) { return UnresolvedSetIterator(ir--); } + + UnresolvedSetIterator &operator+=(difference_type d) { + ir += d; return *this; + } + UnresolvedSetIterator operator+(difference_type d) const { + return UnresolvedSetIterator(ir + d); + } + UnresolvedSetIterator &operator-=(difference_type d) { + ir -= d; return *this; + } + UnresolvedSetIterator operator-(difference_type d) const { + return UnresolvedSetIterator(ir - d); + } + value_type operator[](difference_type d) const { return *(*this + d); } + + difference_type operator-(const UnresolvedSetIterator &o) const { + return ir - o.ir; + } + + bool operator==(const UnresolvedSetIterator &o) const { return ir == o.ir; } + bool operator!=(const UnresolvedSetIterator &o) const { return ir != o.ir; } + bool operator<(const UnresolvedSetIterator &o) const { return ir < o.ir; } + bool operator<=(const UnresolvedSetIterator &o) const { return ir <= o.ir; } + bool operator>=(const UnresolvedSetIterator &o) const { return ir >= o.ir; } + bool operator>(const UnresolvedSetIterator &o) const { return ir > o.ir; } +}; + +/// UnresolvedSet - A set of unresolved declarations. This is needed +/// in a lot of places, but isn't really worth breaking into its own +/// header right now. +class UnresolvedSetImpl { + typedef UnresolvedSetIterator::DeclEntry DeclEntry; + typedef UnresolvedSetIterator::DeclsTy DeclsTy; + + // Don't allow direct construction, and only permit subclassing by + // UnresolvedSet. +private: + template <unsigned N> friend class UnresolvedSet; + UnresolvedSetImpl() {} + UnresolvedSetImpl(const UnresolvedSetImpl &) {} + +public: + // We don't currently support assignment through this iterator, so we might + // as well use the same implementation twice. + typedef UnresolvedSetIterator iterator; + typedef UnresolvedSetIterator const_iterator; + + iterator begin() { return iterator(decls().begin()); } + iterator end() { return iterator(decls().end()); } + + const_iterator begin() const { return const_iterator(decls().begin()); } + const_iterator end() const { return const_iterator(decls().end()); } + + void addDecl(NamedDecl *D) { + addDecl(D, AS_none); + } + + void addDecl(NamedDecl *D, AccessSpecifier AS) { + decls().push_back(DeclEntry(D, AS)); + } + + /// Replaces the given declaration with the new one, once. + /// + /// \return true if the set changed + bool replace(const NamedDecl* Old, NamedDecl *New) { + for (DeclsTy::iterator I = decls().begin(), E = decls().end(); I != E; ++I) + if (I->getPointer() == Old) + return (I->setPointer(New), true); + return false; + } + + /// Replaces the declaration at the given iterator with the new one, + /// preserving the original access bits. + void replace(iterator I, NamedDecl *New) { + I.ir->setPointer(New); + } + + void replace(iterator I, NamedDecl *New, AccessSpecifier AS) { + *I.ir = DeclEntry(New, AS); + } + + void erase(iterator I) { + *I.ir = decls().back(); + decls().pop_back(); + } + + void clear() { decls().clear(); } + void set_size(unsigned N) { decls().set_size(N); } + + bool empty() const { return decls().empty(); } + unsigned size() const { return decls().size(); } + + void append(iterator I, iterator E) { + decls().append(I.ir, E.ir); + } + + /// A proxy reference for implementing operator[]. + class Proxy { + DeclEntry &Ref; + + friend class UnresolvedSetImpl; + Proxy(DeclEntry &Ref) : Ref(Ref) {} + + public: + NamedDecl *getDecl() const { return Ref.getPointer(); } + void setDecl(NamedDecl *D) { Ref.setPointer(D); } + + AccessSpecifier getAccess() const { return AccessSpecifier(Ref.getInt()); } + void setAccess(AccessSpecifier AS) const { Ref.setInt(AS); } + + NamedDecl* operator->() const { return getDecl(); } + operator NamedDecl*() const { return getDecl(); } + Proxy &operator=(const Proxy &D) { Ref = D.Ref; return *this; } + }; + Proxy operator[](unsigned I) { return Proxy(decls()[I]); } + + /// A proxy reference for implementing operator[] const. + class ConstProxy { + const DeclEntry &Ref; + + friend class UnresolvedSetImpl; + ConstProxy(const DeclEntry &Ref) : Ref(Ref) {} + + public: + NamedDecl *getDecl() const { return Ref.getPointer(); } + AccessSpecifier getAccess() const { return AccessSpecifier(Ref.getInt()); } + + NamedDecl *operator->() const { return getDecl(); } + operator NamedDecl*() const { return getDecl(); } + }; + ConstProxy operator[](unsigned I) const { return ConstProxy(decls()[I]); } + +private: + // These work because the only permitted subclass is UnresolvedSetImpl + + DeclsTy &decls() { + return *reinterpret_cast<DeclsTy*>(this); + } + const DeclsTy &decls() const { + return *reinterpret_cast<const DeclsTy*>(this); + } +}; + +/// A set of unresolved declarations +template <unsigned InlineCapacity> class UnresolvedSet : + public UnresolvedSetImpl { + llvm::SmallVector<UnresolvedSetImpl::DeclEntry, InlineCapacity> Decls; +}; + + +} // namespace clang + +#endif diff --git a/include/clang/Analysis/CFG.h b/include/clang/Analysis/CFG.h index 38d4bdf..e87784f 100644 --- a/include/clang/Analysis/CFG.h +++ b/include/clang/Analysis/CFG.h @@ -20,12 +20,14 @@ #include "llvm/Support/Allocator.h" #include "llvm/Support/Casting.h" #include "clang/Analysis/Support/BumpVector.h" +#include "clang/Basic/SourceLocation.h" #include <cassert> namespace llvm { class raw_ostream; } namespace clang { + class Decl; class Stmt; class Expr; class CFG; @@ -33,15 +35,39 @@ namespace clang { class LangOptions; class ASTContext; +namespace { +// An element of the CFG for implicit descructor calls implied by the language +// rules. +class Dtor { + // Statement that introduces the variable. + Stmt *S; + // A token which ends the scope, return, goto, throw, }. + SourceLocation Loc; +public: + Dtor(Stmt *s, SourceLocation l) : S(s), Loc(l) { + } + SourceLocation getLoc() { return Loc; } + Stmt *getStmt() { return S; } +}; +} + /// CFGElement - Represents a top-level expression in a basic block. class CFGElement { - llvm::PointerIntPair<Stmt *, 1> Data; + llvm::PointerIntPair<Stmt *, 2> Data; public: + enum Type { StartScope, EndScope }; explicit CFGElement() {} CFGElement(Stmt *S, bool lvalue) : Data(S, lvalue ? 1 : 0) {} + CFGElement(Stmt *S, Type t) : Data(S, t == StartScope ? 2 : 3) {} + // CFGElement(Dtor *S, Type t) : Data(reinterpret_cast<Stmt*>(S), 4) {} Stmt *getStmt() const { return Data.getPointer(); } bool asLValue() const { return Data.getInt() == 1; } + bool asStartScope() const { return Data.getInt() == 2; } + bool asEndScope() const { return Data.getInt() == 3; } + bool asDtor() const { return Data.getInt() == 4; } operator Stmt*() const { return getStmt(); } + operator bool() const { return getStmt() != 0; } + operator Dtor*() const { return reinterpret_cast<Dtor*>(getStmt()); } }; /// CFGBlock - Represents a single basic block in a source-level CFG. @@ -107,7 +133,7 @@ class CFGBlock { /// Label - An (optional) label that prefixes the executable /// statements in the block. When this variable is non-NULL, it is - /// either an instance of LabelStmt or SwitchCase. + /// either an instance of LabelStmt, SwitchCase or CXXCatchStmt. Stmt *Label; /// Terminator - The terminator for a basic block that @@ -236,6 +262,12 @@ public: void appendStmt(Stmt* Statement, BumpVectorContext &C, bool asLValue) { Stmts.push_back(CFGElement(Statement, asLValue), C); } + void StartScope(Stmt* S, BumpVectorContext &C) { + Stmts.push_back(CFGElement(S, CFGElement::StartScope), C); + } + void EndScope(Stmt* S, BumpVectorContext &C) { + Stmts.push_back(CFGElement(S, CFGElement::EndScope), C); + } }; @@ -254,7 +286,9 @@ public: /// buildCFG - Builds a CFG from an AST. The responsibility to free the /// constructed CFG belongs to the caller. - static CFG* buildCFG(Stmt* AST, ASTContext *C); + static CFG* buildCFG(const Decl *D, Stmt* AST, ASTContext *C, + bool AddEHEdges = false, + bool AddScopes = false); /// createBlock - Create a new block in the CFG. The CFG owns the block; /// the caller should not directly free it. diff --git a/include/clang/Analysis/PathSensitive/AnalysisContext.h b/include/clang/Analysis/PathSensitive/AnalysisContext.h index 63ba558..c82bb96 100644 --- a/include/clang/Analysis/PathSensitive/AnalysisContext.h +++ b/include/clang/Analysis/PathSensitive/AnalysisContext.h @@ -46,14 +46,21 @@ class AnalysisContext { ParentMap *PM; llvm::DenseMap<const BlockDecl*,void*> *ReferencedBlockVars; llvm::BumpPtrAllocator A; + bool AddEHEdges; public: - AnalysisContext(const Decl *d) : D(d), cfg(0), liveness(0), PM(0), - ReferencedBlockVars(0) {} + AnalysisContext(const Decl *d, bool addehedges = false) + : D(d), cfg(0), liveness(0), PM(0), ReferencedBlockVars(0), + AddEHEdges(addehedges) {} ~AnalysisContext(); ASTContext &getASTContext() { return D->getASTContext(); } const Decl *getDecl() { return D; } + /// getAddEHEdges - Return true iff we are adding exceptional edges from + /// callExprs. If this is false, then try/catch statements and blocks + /// reachable from them can appear to be dead in the CFG, analysis passes must + /// cope with that. + bool getAddEHEdges() const { return AddEHEdges; } Stmt *getBody(); CFG *getCFG(); ParentMap &getParentMap(); diff --git a/include/clang/Analysis/PathSensitive/CheckerVisitor.h b/include/clang/Analysis/PathSensitive/CheckerVisitor.h index f5145bb..37ec8de 100644 --- a/include/clang/Analysis/PathSensitive/CheckerVisitor.h +++ b/include/clang/Analysis/PathSensitive/CheckerVisitor.h @@ -66,6 +66,11 @@ break; default: assert(false && "Unsupport statement."); return; + case Stmt::CompoundAssignOperatorClass: + static_cast<ImplClass*>(this)->PostVisitBinaryOperator(C, + static_cast<const BinaryOperator*>(S)); + break; + #define POSTVISIT(NAME, FALLBACK) \ case Stmt::NAME ## Class:\ static_cast<ImplClass*>(this)->\ diff --git a/include/clang/Analysis/PathSensitive/GRExprEngine.h b/include/clang/Analysis/PathSensitive/GRExprEngine.h index fb0e883..df90ad9 100644 --- a/include/clang/Analysis/PathSensitive/GRExprEngine.h +++ b/include/clang/Analysis/PathSensitive/GRExprEngine.h @@ -270,8 +270,8 @@ protected: ExplodedNodeSet& Dst, bool asLValue); /// VisitCast - Transfer function logic for all casts (implicit and explicit). - void VisitCast(Expr* CastE, Expr* Ex, ExplodedNode* Pred, - ExplodedNodeSet& Dst, bool asLValue); + void VisitCast(CastExpr *CastE, Expr *Ex, ExplodedNode *Pred, + ExplodedNodeSet &Dst, bool asLValue); /// VisitCompoundLiteralExpr - Transfer function logic for compound literals. void VisitCompoundLiteralExpr(CompoundLiteralExpr* CL, ExplodedNode* Pred, diff --git a/include/clang/Analysis/PathSensitive/Store.h b/include/clang/Analysis/PathSensitive/Store.h index 70c17ac..5606df0 100644 --- a/include/clang/Analysis/PathSensitive/Store.h +++ b/include/clang/Analysis/PathSensitive/Store.h @@ -105,7 +105,8 @@ public: // FIXME: Make out-of-line. virtual DefinedOrUnknownSVal getSizeInElements(const GRState *state, - const MemRegion *region) { + const MemRegion *region, + QualType EleTy) { return UnknownVal(); } diff --git a/include/clang/Basic/Builtins.def b/include/clang/Basic/Builtins.def index 14f7356..0894563 100644 --- a/include/clang/Basic/Builtins.def +++ b/include/clang/Basic/Builtins.def @@ -270,6 +270,7 @@ BUILTIN(__builtin_bswap64, "ULLiULLi", "nc") BUILTIN(__builtin_constant_p, "Us.", "nc") BUILTIN(__builtin_classify_type, "i.", "nc") BUILTIN(__builtin___CFStringMakeConstantString, "FC*cC*", "nc") +BUILTIN(__builtin___NSStringMakeConstantString, "FC*cC*", "nc") BUILTIN(__builtin_va_start, "vA.", "n") BUILTIN(__builtin_va_end, "vA", "n") BUILTIN(__builtin_va_copy, "vAA", "n") diff --git a/include/clang/Basic/BuiltinsX86.def b/include/clang/Basic/BuiltinsX86.def index 6315c16..0062846 100644 --- a/include/clang/Basic/BuiltinsX86.def +++ b/include/clang/Basic/BuiltinsX86.def @@ -79,12 +79,7 @@ BUILTIN(__builtin_ia32_pmaxub, "V8cV8cV8c", "") BUILTIN(__builtin_ia32_pmaxsw, "V4sV4sV4s", "") BUILTIN(__builtin_ia32_pminub, "V8cV8cV8c", "") BUILTIN(__builtin_ia32_pminsw, "V4sV4sV4s", "") -BUILTIN(__builtin_ia32_punpckhbw, "V8cV8cV8c", "") -BUILTIN(__builtin_ia32_punpckhwd, "V4sV4sV4s", "") -BUILTIN(__builtin_ia32_punpckhdq, "V2iV2iV2i", "") -BUILTIN(__builtin_ia32_punpcklbw, "V8cV8cV8c", "") BUILTIN(__builtin_ia32_punpcklwd, "V4sV4sV4s", "") -BUILTIN(__builtin_ia32_punpckldq, "V2iV2iV2i", "") BUILTIN(__builtin_ia32_cmppd, "V2dV2dV2dc", "") BUILTIN(__builtin_ia32_cmpsd, "V2dV2dV2dc", "") BUILTIN(__builtin_ia32_minpd, "V2dV2dV2d", "") @@ -99,7 +94,6 @@ BUILTIN(__builtin_ia32_paddusb128, "V16cV16cV16c", "") BUILTIN(__builtin_ia32_paddusw128, "V8sV8sV8s", "") BUILTIN(__builtin_ia32_psubusb128, "V16cV16cV16c", "") BUILTIN(__builtin_ia32_psubusw128, "V8sV8sV8s", "") -BUILTIN(__builtin_ia32_pmullw128, "V8sV8sV8s", "") BUILTIN(__builtin_ia32_pmulhw128, "V8sV8sV8s", "") BUILTIN(__builtin_ia32_pavgb128, "V16cV16cV16c", "") BUILTIN(__builtin_ia32_pavgw128, "V8sV8sV8s", "") diff --git a/include/clang/Basic/DiagnosticDriverKinds.td b/include/clang/Basic/DiagnosticDriverKinds.td index dfb6f8d..8cdf850 100644 --- a/include/clang/Basic/DiagnosticDriverKinds.td +++ b/include/clang/Basic/DiagnosticDriverKinds.td @@ -83,5 +83,7 @@ def warn_drv_assuming_mfloat_abi_is : Warning< "unknown platform, assuming -mfloat-abi=%0">; def warn_ignoring_ftabstop_value : Warning< "ignoring invalid -ftabstop value '%0', using default value %1">; +def warn_drv_missing_resource_library : Warning< + "missing resource library '%0', link may fail">; } diff --git a/include/clang/Basic/DiagnosticLexKinds.td b/include/clang/Basic/DiagnosticLexKinds.td index 26a80b5..3f765bd 100644 --- a/include/clang/Basic/DiagnosticLexKinds.td +++ b/include/clang/Basic/DiagnosticLexKinds.td @@ -172,9 +172,6 @@ def err_pp_hash_error : Error<"#error%0">; def err_pp_file_not_found : Error<"'%0' file not found">, DefaultFatal; def err_pp_error_opening_file : Error< "error opening file '%0': %1">, DefaultFatal; -def warn_pp_relative_include_from_framework : Warning< - "published framework headers should always #import headers within the " - "framework with framework paths">, InGroup<DiagGroup<"framework-headers">>; def err_pp_empty_filename : Error<"empty filename">; def err_pp_include_too_deep : Error<"#include nested too deeply">; def err_pp_expects_filename : Error<"expected \"FILENAME\" or <FILENAME>">; diff --git a/include/clang/Basic/DiagnosticSemaKinds.td b/include/clang/Basic/DiagnosticSemaKinds.td index 7e59f88..8d75d2e 100644 --- a/include/clang/Basic/DiagnosticSemaKinds.td +++ b/include/clang/Basic/DiagnosticSemaKinds.td @@ -412,6 +412,15 @@ def err_class_redeclared_with_different_access : Error< "%0 redeclared with '%1' access">; def note_previous_access_declaration : Note< "previously declared '%1' here">; +def err_access_outside_class : Error< + "access to %select{private|protected}0 member outside any class context">; +def note_access_natural : Note<"declared %select{private|protected}0 here">; +def note_access_constrained_by_path : Note< + "access to decl constrained by %select{private|protected}0 inheritance">; +def err_access_protected : Error< + "access to protected member of %0 from %1, which is not a subclass">; +def err_access_private : Error< + "access to private member of %0 from %1">; // C++ name lookup def err_incomplete_nested_name_spec : Error< @@ -537,8 +546,9 @@ def err_destructor_name : Error< // C++ initialization def err_init_conversion_failed : Error< "cannot initialize %select{a variable|a parameter|return object|an " - "exception object|a value|a base class|a member subobject|an array element}0" - " of type %1 with an %select{rvalue|lvalue}2 of type %3">; + "exception object|a member subobject|an array element|a new value|a value|a " + "base class|an array element}0 of type %1 with an %select{rvalue|lvalue}2 of " + "type %3">; def err_lvalue_to_rvalue_ref : Error<"rvalue reference cannot bind to lvalue">; def err_invalid_initialization : Error< @@ -913,10 +923,24 @@ def note_ovl_candidate_arity : Note<"candidate " "function (the implicit copy assignment operator)}0 not viable: requires" "%select{ at least| at most|}2 %3 argument%s3, but %4 %plural{1:was|:were}4 " "provided">; + def note_ovl_candidate_deleted : Note< "candidate %select{function|function|constructor|" "function |function |constructor |||}0%1 " "has been explicitly %select{made unavailable|deleted}2">; + +// Giving the index of the bad argument really clutters this message, and +// it's relatively unimportant because 1) it's generally obvious which +// argument(s) are of the given object type and 2) the fix is usually +// to complete the type, which doesn't involve changes to the call line +// anyway. If people complain, we can change it. +def note_ovl_candidate_bad_conv_incomplete : Note<"candidate " + "%select{function|function|constructor|" + "function |function |constructor |" + "constructor (the implicit default constructor)|" + "constructor (the implicit copy constructor)|" + "function (the implicit copy assignment operator)}0%1 " + "not viable: cannot convert argument of incomplete type %2 to %3">; def note_ovl_candidate_bad_conv : Note<"candidate " "%select{function|function|constructor|" "function |function |constructor |" @@ -1840,6 +1864,9 @@ def err_illegal_super_cast : Error< def warn_setter_getter_impl_required : Warning< "property %0 requires method %1 to be defined - " "use @synthesize, @dynamic or provide a method implementation">; +def warn_setter_getter_impl_required_in_category : Warning< + "property %0 requires method %1 to be defined - " + "use @dynamic or provide a method implementation in category">; def note_property_impl_required : Note< "implementation is here">; @@ -2458,8 +2485,6 @@ def warn_stringcompare : Warning< def err_blocks_disable : Error<"blocks support disabled - compile with -fblocks" " or pick a deployment target that supports them">; def err_expected_block_lbrace : Error<"expected '{' in block literal">; -def err_goto_in_block : Error< - "goto not allowed in block literal">; def err_return_in_block_expression : Error< "return not allowed in block expression literal">; def err_block_returns_array : Error< diff --git a/include/clang/Basic/MacroBuilder.h b/include/clang/Basic/MacroBuilder.h new file mode 100644 index 0000000..3287b30 --- /dev/null +++ b/include/clang/Basic/MacroBuilder.h @@ -0,0 +1,46 @@ +//===--- MacroBuilder.h - CPP Macro building utility ------------*- C++ -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// +// This file defines the MacroBuilder utility class. +// +//===----------------------------------------------------------------------===// + +#ifndef LLVM_CLANG_BASIC_MACROBUILDER_H +#define LLVM_CLANG_BASIC_MACROBUILDER_H + +#include "llvm/ADT/Twine.h" +#include "llvm/Support/raw_ostream.h" + +namespace clang { + +class MacroBuilder { + llvm::raw_ostream &Out; +public: + MacroBuilder(llvm::raw_ostream &Output) : Out(Output) {} + + /// Append a #define line for macro of the form "#define Name Value\n". + void defineMacro(const llvm::Twine &Name, const llvm::Twine &Value = "1") { + Out << "#define " << Name << ' ' << Value << '\n'; + } + + /// Append a #undef line for Name. Name should be of the form XXX + /// and we emit "#undef XXX". + void undefineMacro(const llvm::Twine &Name) { + Out << "#undef " << Name << '\n'; + } + + /// Directly append Str and a newline to the underlying buffer. + void append(const llvm::Twine &Str) { + Out << Str << '\n'; + } +}; + +} // end namespace clang + +#endif diff --git a/include/clang/Basic/Makefile b/include/clang/Basic/Makefile index b85eb07..48f7f9d 100644 --- a/include/clang/Basic/Makefile +++ b/include/clang/Basic/Makefile @@ -11,14 +11,12 @@ include $(LEVEL)/Makefile.common INPUT_TDS = $(wildcard $(PROJ_SRC_DIR)/Diagnostic*.td) -$(ObjDir)/Diagnostic%Kinds.inc.tmp : Diagnostic.td Diagnostic%Kinds.td $(TBLGEN) +$(ObjDir)/Diagnostic%Kinds.inc.tmp : Diagnostic.td Diagnostic%Kinds.td $(TBLGEN) $(ObjDir)/.dir $(Echo) "Building Clang $(patsubst Diagnostic%Kinds.inc.tmp,%,$(@F)) diagnostic tables with tblgen" - $(Verb) -$(MKDIR) $(@D) $(Verb) $(TableGen) -gen-clang-diags-defs -clang-component=$(patsubst Diagnostic%Kinds.inc.tmp,%,$(@F)) -o $(call SYSPATH, $@) $< -$(ObjDir)/DiagnosticGroups.inc.tmp : Diagnostic.td DiagnosticGroups.td $(INPUT_TDS) $(TBLGEN) +$(ObjDir)/DiagnosticGroups.inc.tmp : Diagnostic.td DiagnosticGroups.td $(INPUT_TDS) $(TBLGEN) $(ObjDir)/.dir $(Echo) "Building Clang diagnostic groups with tblgen" - $(Verb) -$(MKDIR) $(@D) $(Verb) $(TableGen) -gen-clang-diag-groups -o $(call SYSPATH, $@) $< diff --git a/include/clang/Basic/Specifiers.h b/include/clang/Basic/Specifiers.h new file mode 100644 index 0000000..4cace86 --- /dev/null +++ b/include/clang/Basic/Specifiers.h @@ -0,0 +1,82 @@ +//===--- Specifiers.h - Declaration and Type Specifiers ---------*- 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 various enumerations that describe declaration and +// type specifiers. +// +//===----------------------------------------------------------------------===// + +#ifndef LLVM_CLANG_BASIC_SPECIFIERS_H +#define LLVM_CLANG_BASIC_SPECIFIERS_H + +namespace clang { + /// \brief Specifies the width of a type, e.g., short, long, or long long. + enum TypeSpecifierWidth { + TSW_unspecified, + TSW_short, + TSW_long, + TSW_longlong + }; + + /// \brief Specifies the signedness of a type, e.g., signed or unsigned. + enum TypeSpecifierSign { + TSS_unspecified, + TSS_signed, + TSS_unsigned + }; + + /// \brief Specifies the kind of type. + enum TypeSpecifierType { + TST_unspecified, + TST_void, + TST_char, + TST_wchar, // C++ wchar_t + TST_char16, // C++0x char16_t + TST_char32, // C++0x char32_t + TST_int, + TST_float, + TST_double, + TST_bool, // _Bool + TST_decimal32, // _Decimal32 + TST_decimal64, // _Decimal64 + TST_decimal128, // _Decimal128 + TST_enum, + TST_union, + TST_struct, + TST_class, // C++ class type + TST_typename, // Typedef, C++ class-name or enum name, etc. + TST_typeofType, + TST_typeofExpr, + TST_decltype, // C++0x decltype + TST_auto, // C++0x auto + TST_error // erroneous type + }; + + /// WrittenBuiltinSpecs - Structure that packs information about the + /// type specifiers that were written in a particular type specifier + /// sequence. + struct WrittenBuiltinSpecs { + /*DeclSpec::TST*/ unsigned Type : 5; + /*DeclSpec::TSS*/ unsigned Sign : 2; + /*DeclSpec::TSW*/ unsigned Width : 2; + bool ModeAttr : 1; + }; + + /// AccessSpecifier - A C++ access specifier (public, private, + /// protected), plus the special value "none" which means + /// different things in different contexts. + enum AccessSpecifier { + AS_public, + AS_protected, + AS_private, + AS_none + }; +} + +#endif // LLVM_CLANG_BASIC_SPECIFIERS_H diff --git a/include/clang/Basic/Version.h b/include/clang/Basic/Version.h index 120d5a4..4710b6b 100644 --- a/include/clang/Basic/Version.h +++ b/include/clang/Basic/Version.h @@ -15,6 +15,8 @@ #ifndef LLVM_CLANG_BASIC_VERSION_H #define LLVM_CLANG_BASIC_VERSION_H +#include "llvm/ADT/StringRef.h" + /// \brief Clang major version #define CLANG_VERSION_MAJOR 1 @@ -47,13 +49,23 @@ #endif namespace clang { - /// \brief Retrieves the Subversion path that identifies the particular - /// Clang branch, tag, or trunk from which this Clang was built. - const char *getClangSubversionPath(); + /// \brief Retrieves the repository path (e.g., Subversion path) that + /// identifies the particular Clang branch, tag, or trunk from which this + /// Clang was built. + llvm::StringRef getClangRepositoryPath(); + + /// \brief Retrieves the repository revision number (or identifer) from which + /// this Clang was built. + llvm::StringRef getClangRevision(); + + /// \brief Retrieves the full repository version that is an amalgamation of + /// the information in getClangRepositoryPath() and getClangRevision(). + llvm::StringRef getClangFullRepositoryVersion(); - /// \brief Retrieves the Subversion revision number from which this Clang - /// was built. - unsigned getClangSubversionRevision(); + /// \brief Retrieves a string representing the complete clang version, + /// which includes the clang version number, the repository version, + /// and the vendor tag. + const char *getClangFullVersion(); } #endif // LLVM_CLANG_BASIC_VERSION_H diff --git a/include/clang/Driver/Driver.h b/include/clang/Driver/Driver.h index 8933619..3186471 100644 --- a/include/clang/Driver/Driver.h +++ b/include/clang/Driver/Driver.h @@ -61,6 +61,9 @@ public: /// command line. std::string Dir; + /// The path to the compiler resource directory. + std::string ResourceDir; + /// Default host triple. std::string DefaultHostTriple; diff --git a/include/clang/Frontend/ASTUnit.h b/include/clang/Frontend/ASTUnit.h index f18972a..2659dbb 100644 --- a/include/clang/Frontend/ASTUnit.h +++ b/include/clang/Frontend/ASTUnit.h @@ -21,6 +21,11 @@ #include <string> #include <vector> #include <cassert> +#include <utility> + +namespace llvm { + class MemoryBuffer; +} namespace clang { class ASTContext; @@ -111,6 +116,10 @@ public: return TopLevelDecls; } + /// \brief A mapping from a file name to the memory buffer that stores the + /// remapped contents of that file. + typedef std::pair<std::string, const llvm::MemoryBuffer *> RemappedFile; + /// \brief Create a ASTUnit from a PCH file. /// /// \param Filename - The PCH file to load. @@ -122,7 +131,9 @@ public: static ASTUnit *LoadFromPCHFile(const std::string &Filename, Diagnostic &Diags, bool OnlyLocalDecls = false, - bool UseBumpAllocator = false); + bool UseBumpAllocator = false, + RemappedFile *RemappedFiles = 0, + unsigned NumRemappedFiles = 0); /// LoadFromCompilerInvocation - Create an ASTUnit from a source file, via a /// CompilerInvocation object. @@ -158,7 +169,9 @@ public: Diagnostic &Diags, llvm::StringRef ResourceFilesPath, bool OnlyLocalDecls = false, - bool UseBumpAllocator = false); + bool UseBumpAllocator = false, + RemappedFile *RemappedFiles = 0, + unsigned NumRemappedFiles = 0); }; } // namespace clang diff --git a/include/clang/Frontend/PCHBitCodes.h b/include/clang/Frontend/PCHBitCodes.h index 536bd41..1a9f4ce 100644 --- a/include/clang/Frontend/PCHBitCodes.h +++ b/include/clang/Frontend/PCHBitCodes.h @@ -30,7 +30,7 @@ namespace clang { /// designed for the previous version could not support reading /// the new version), this number should be increased. /// - /// Version 3 of PCH files also requires that the Subversion branch and + /// Version 3 of PCH files also requires that the version control branch and /// revision match exactly, since there is no backward compatibility of /// PCH files at this time. const unsigned VERSION_MAJOR = 3; @@ -219,9 +219,9 @@ namespace clang { /// comments were encountered in the source code. COMMENT_RANGES = 20, - /// \brief Record code for the Subversion branch and revision information - /// of the compiler used to build this PCH file. - SVN_BRANCH_REVISION = 21 + /// \brief Record code for the version control branch and revision + /// information of the compiler used to build this PCH file. + VERSION_CONTROL_BRANCH_REVISION = 21 }; /// \brief Record types used within a source manager block. @@ -676,7 +676,17 @@ namespace clang { /// \brief A CXXOperatorCallExpr record. EXPR_CXX_OPERATOR_CALL, /// \brief A CXXConstructExpr record. - EXPR_CXX_CONSTRUCT + EXPR_CXX_CONSTRUCT, + // \brief A CXXStaticCastExpr record. + EXPR_CXX_STATIC_CAST, + // \brief A CXXDynamicCastExpr record. + EXPR_CXX_DYNAMIC_CAST, + // \brief A CXXReinterpretCastExpr record. + EXPR_CXX_REINTERPRET_CAST, + // \brief A CXXConstCastExpr record. + EXPR_CXX_CONST_CAST, + // \brief A CXXFunctionalCastExpr record. + EXPR_CXX_FUNCTIONAL_CAST }; /// \brief The kinds of designators that can occur in a diff --git a/include/clang/Frontend/PreprocessorOptions.h b/include/clang/Frontend/PreprocessorOptions.h index c43a1fe..7ba7c5c 100644 --- a/include/clang/Frontend/PreprocessorOptions.h +++ b/include/clang/Frontend/PreprocessorOptions.h @@ -16,6 +16,10 @@ #include <utility> #include <vector> +namespace llvm { + class MemoryBuffer; +} + namespace clang { class Preprocessor; @@ -48,6 +52,12 @@ public: /// pair). std::vector<std::pair<std::string, std::string> > RemappedFiles; + /// \brief The set of file-to-buffer remappings, which take existing files + /// on the system (the first part of each pair) and gives them the contents + /// of the specified memory buffer (the second part of each pair). + std::vector<std::pair<std::string, const llvm::MemoryBuffer *> > + RemappedFileBuffers; + typedef std::vector<std::pair<std::string, std::string> >::const_iterator remapped_file_iterator; remapped_file_iterator remapped_file_begin() const { @@ -57,6 +67,15 @@ public: return RemappedFiles.end(); } + typedef std::vector<std::pair<std::string, const llvm::MemoryBuffer *> >:: + const_iterator remapped_file_buffer_iterator; + remapped_file_buffer_iterator remapped_file_buffer_begin() const { + return RemappedFileBuffers.begin(); + } + remapped_file_buffer_iterator remapped_file_buffer_end() const { + return RemappedFileBuffers.end(); + } + public: PreprocessorOptions() : UsePredefines(true) {} @@ -69,6 +88,9 @@ public: void addRemappedFile(llvm::StringRef From, llvm::StringRef To) { RemappedFiles.push_back(std::make_pair(From, To)); } + void addRemappedFile(llvm::StringRef From, const llvm::MemoryBuffer * To) { + RemappedFileBuffers.push_back(std::make_pair(From, To)); + } }; } // end namespace clang diff --git a/include/clang/Frontend/Utils.h b/include/clang/Frontend/Utils.h index c8df494..7f43b2a 100644 --- a/include/clang/Frontend/Utils.h +++ b/include/clang/Frontend/Utils.h @@ -15,7 +15,6 @@ #define LLVM_CLANG_FRONTEND_UTILS_H #include "llvm/ADT/StringRef.h" -#include "llvm/ADT/Twine.h" #include "llvm/Support/raw_ostream.h" namespace llvm { @@ -41,28 +40,6 @@ class Stmt; class TargetInfo; class FrontendOptions; -class MacroBuilder { - llvm::raw_ostream &Out; -public: - MacroBuilder(llvm::raw_ostream &Output) : Out(Output) {} - - /// Append a #define line for macro of the form "#define Name Value\n". - void defineMacro(const llvm::Twine &Name, const llvm::Twine &Value = "1") { - Out << "#define " << Name << ' ' << Value << '\n'; - } - - /// Append a #undef line for Name. Name should be of the form XXX - /// and we emit "#undef XXX". - void undefineMacro(const llvm::Twine &Name) { - Out << "#undef " << Name << '\n'; - } - - /// Directly append Str and a newline to the underlying buffer. - void append(const llvm::Twine &Str) { - Out << Str << '\n'; - } -}; - /// Normalize \arg File for use in a user defined #include directive (in the /// predefines buffer). std::string NormalizeDashIncludePath(llvm::StringRef File); diff --git a/include/clang/Lex/Preprocessor.h b/include/clang/Lex/Preprocessor.h index fc2671f..dedbbd8 100644 --- a/include/clang/Lex/Preprocessor.h +++ b/include/clang/Lex/Preprocessor.h @@ -602,7 +602,12 @@ public: /// the returned source location would not be meaningful (e.g., if /// it points into a macro), this routine returns an invalid /// source location. - SourceLocation getLocForEndOfToken(SourceLocation Loc); + /// + /// \param Offset an offset from the end of the token, where the source + /// location should refer to. The default offset (0) produces a source + /// location pointing just past the end of the token; an offset of 1 produces + /// a source location pointing to the last character in the token, etc. + SourceLocation getLocForEndOfToken(SourceLocation Loc, unsigned Offset = 0); /// DumpToken - Print the token to stderr, used for debugging. /// @@ -697,8 +702,7 @@ public: /// return null on failure. isAngled indicates whether the file reference is /// for system #include's or not (i.e. using <> instead of ""). const FileEntry *LookupFile(llvm::StringRef Filename, - SourceLocation FilenameTokLoc, bool isAngled, - const DirectoryLookup *FromDir, + bool isAngled, const DirectoryLookup *FromDir, const DirectoryLookup *&CurDir); /// GetCurLookup - The DirectoryLookup structure used to find the current @@ -884,7 +888,9 @@ public: void HandlePragmaSystemHeader(Token &SysHeaderTok); void HandlePragmaDependency(Token &DependencyTok); void HandlePragmaComment(Token &CommentTok); - void HandleComment(SourceRange Comment); + // Return true and store the first token only if any CommentHandler + // has inserted some tokens and getCommentRetentionState() is false. + bool HandleComment(Token &Token, SourceRange Comment); }; /// \brief Abstract base class that describes a handler that will receive @@ -893,7 +899,9 @@ class CommentHandler { public: virtual ~CommentHandler(); - virtual void HandleComment(Preprocessor &PP, SourceRange Comment) = 0; + // The handler shall return true if it has pushed any tokens + // to be read using e.g. EnterToken or EnterTokenStream. + virtual bool HandleComment(Preprocessor &PP, SourceRange Comment) = 0; }; } // end namespace clang diff --git a/include/clang/Parse/AccessSpecifier.h b/include/clang/Parse/AccessSpecifier.h deleted file mode 100644 index 8d2cee8..0000000 --- a/include/clang/Parse/AccessSpecifier.h +++ /dev/null @@ -1,30 +0,0 @@ -//===--- AccessSpecifier.h - C++ Access Specifiers -*- 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 used for C++ access specifiers. -// -//===----------------------------------------------------------------------===// - -#ifndef LLVM_CLANG_PARSE_ACCESS_SPECIFIER_H -#define LLVM_CLANG_PARSE_ACCESS_SPECIFIER_H - -namespace clang { - -/// AccessSpecifier - A C++ access specifier (none, public, private, -/// protected). -enum AccessSpecifier { - AS_none, - AS_public, - AS_protected, - AS_private -}; - -} // end namespace clang - -#endif diff --git a/include/clang/Parse/Action.h b/include/clang/Parse/Action.h index 7209e0a..ff33f50 100644 --- a/include/clang/Parse/Action.h +++ b/include/clang/Parse/Action.h @@ -16,9 +16,9 @@ #include "clang/Basic/IdentifierTable.h" #include "clang/Basic/SourceLocation.h" +#include "clang/Basic/Specifiers.h" #include "clang/Basic/TemplateKinds.h" #include "clang/Basic/TypeTraits.h" -#include "clang/Parse/AccessSpecifier.h" #include "clang/Parse/DeclSpec.h" #include "clang/Parse/Ownership.h" #include "llvm/Support/PrettyStackTrace.h" @@ -2110,6 +2110,7 @@ public: SourceLocation SuperLoc, const DeclPtrTy *ProtoRefs, unsigned NumProtoRefs, + const SourceLocation *ProtoLocs, SourceLocation EndProtoLoc, AttributeList *AttrList) { return DeclPtrTy(); @@ -2131,6 +2132,7 @@ public: SourceLocation ProtocolLoc, const DeclPtrTy *ProtoRefs, unsigned NumProtoRefs, + const SourceLocation *ProtoLocs, SourceLocation EndProtoLoc, AttributeList *AttrList) { return DeclPtrTy(); @@ -2144,6 +2146,7 @@ public: SourceLocation CategoryLoc, const DeclPtrTy *ProtoRefs, unsigned NumProtoRefs, + const SourceLocation *ProtoLocs, SourceLocation EndProtoLoc) { return DeclPtrTy(); } @@ -2771,6 +2774,7 @@ public: SourceLocation SuperLoc, const DeclPtrTy *ProtoRefs, unsigned NumProtoRefs, + const SourceLocation *ProtoLocs, SourceLocation EndProtoLoc, AttributeList *AttrList); }; diff --git a/include/clang/Parse/DeclSpec.h b/include/clang/Parse/DeclSpec.h index 6a3d8a9..f923b5e 100644 --- a/include/clang/Parse/DeclSpec.h +++ b/include/clang/Parse/DeclSpec.h @@ -17,6 +17,7 @@ #include "clang/Parse/AttributeList.h" #include "clang/Lex/Token.h" #include "clang/Basic/OperatorKinds.h" +#include "clang/Basic/Specifiers.h" #include "llvm/ADT/SmallVector.h" namespace clang { @@ -78,51 +79,50 @@ public: SCS_mutable }; - // type-specifier - enum TSW { - TSW_unspecified, - TSW_short, - TSW_long, - TSW_longlong - }; - + // Import type specifier width enumeration and constants. + typedef TypeSpecifierWidth TSW; + static const TSW TSW_unspecified = clang::TSW_unspecified; + static const TSW TSW_short = clang::TSW_short; + static const TSW TSW_long = clang::TSW_long; + static const TSW TSW_longlong = clang::TSW_longlong; + enum TSC { TSC_unspecified, TSC_imaginary, TSC_complex }; - enum TSS { - TSS_unspecified, - TSS_signed, - TSS_unsigned - }; - - enum TST { - TST_unspecified, - TST_void, - TST_char, - TST_wchar, // C++ wchar_t - TST_char16, // C++0x char16_t - TST_char32, // C++0x char32_t - TST_int, - TST_float, - TST_double, - TST_bool, // _Bool - TST_decimal32, // _Decimal32 - TST_decimal64, // _Decimal64 - TST_decimal128, // _Decimal128 - TST_enum, - TST_union, - TST_struct, - TST_class, // C++ class type - TST_typename, // Typedef, C++ class-name or enum name, etc. - TST_typeofType, - TST_typeofExpr, - TST_decltype, // C++0x decltype - TST_auto, // C++0x auto - TST_error // erroneous type - }; + // Import type specifier sign enumeration and constants. + typedef TypeSpecifierSign TSS; + static const TSS TSS_unspecified = clang::TSS_unspecified; + static const TSS TSS_signed = clang::TSS_signed; + static const TSS TSS_unsigned = clang::TSS_unsigned; + + // Import type specifier type enumeration and constants. + typedef TypeSpecifierType TST; + static const TST TST_unspecified = clang::TST_unspecified; + static const TST TST_void = clang::TST_void; + static const TST TST_char = clang::TST_char; + static const TST TST_wchar = clang::TST_wchar; + static const TST TST_char16 = clang::TST_char16; + static const TST TST_char32 = clang::TST_char32; + static const TST TST_int = clang::TST_int; + static const TST TST_float = clang::TST_float; + static const TST TST_double = clang::TST_double; + static const TST TST_bool = clang::TST_bool; + static const TST TST_decimal32 = clang::TST_decimal32; + static const TST TST_decimal64 = clang::TST_decimal64; + static const TST TST_decimal128 = clang::TST_decimal128; + static const TST TST_enum = clang::TST_enum; + static const TST TST_union = clang::TST_union; + static const TST TST_struct = clang::TST_struct; + static const TST TST_class = clang::TST_class; + static const TST TST_typename = clang::TST_typename; + static const TST TST_typeofType = clang::TST_typeofType; + static const TST TST_typeofExpr = clang::TST_typeofExpr; + static const TST TST_decltype = clang::TST_decltype; + static const TST TST_auto = clang::TST_auto; + static const TST TST_error = clang::TST_error; // type-qualifiers enum TQ { // NOTE: These flags must be kept in sync with Qualifiers::TQ. @@ -199,6 +199,9 @@ private: SourceLocation FS_inlineLoc, FS_virtualLoc, FS_explicitLoc; SourceLocation FriendLoc, ConstexprLoc; + WrittenBuiltinSpecs writtenBS; + void SaveWrittenBuiltinSpecs(); + DeclSpec(const DeclSpec&); // DO NOT IMPLEMENT void operator=(const DeclSpec&); // DO NOT IMPLEMENT public: @@ -411,6 +414,10 @@ public: /// DeclSpec is guaranteed self-consistent, even if an error occurred. void Finish(Diagnostic &D, Preprocessor &PP); + const WrittenBuiltinSpecs& getWrittenBuiltinSpecs() const { + return writtenBS; + } + /// isMissingDeclaratorOk - This checks if this DeclSpec can stand alone, /// without a Declarator. Only tag declspecs can stand alone. bool isMissingDeclaratorOk(); diff --git a/include/clang/Parse/Parser.h b/include/clang/Parse/Parser.h index 0fc9413..e7cb0a2 100644 --- a/include/clang/Parse/Parser.h +++ b/include/clang/Parse/Parser.h @@ -14,8 +14,8 @@ #ifndef LLVM_CLANG_PARSE_PARSER_H #define LLVM_CLANG_PARSE_PARSER_H +#include "clang/Basic/Specifiers.h" #include "clang/Lex/Preprocessor.h" -#include "clang/Parse/AccessSpecifier.h" #include "clang/Parse/Action.h" #include "clang/Parse/DeclSpec.h" #include "llvm/ADT/OwningPtr.h" diff --git a/include/clang/Rewrite/DeltaTree.h b/include/clang/Rewrite/DeltaTree.h index 7e07965..f32906a 100644 --- a/include/clang/Rewrite/DeltaTree.h +++ b/include/clang/Rewrite/DeltaTree.h @@ -17,7 +17,7 @@ namespace clang { /// DeltaTree - a multiway search tree (BTree) structure with some fancy - /// features. B-Trees are are generally more memory and cache efficient than + /// features. B-Trees are generally more memory and cache efficient than /// binary trees, because they store multiple keys/values in each node. This /// implements a key/value mapping from index to delta, and allows fast lookup /// on index. However, an added (important) bonus is that it can also diff --git a/lib/AST/ASTContext.cpp b/lib/AST/ASTContext.cpp index 76ec852..c1bc709 100644 --- a/lib/AST/ASTContext.cpp +++ b/lib/AST/ASTContext.cpp @@ -1200,43 +1200,58 @@ QualType ASTContext::getObjCGCQualType(QualType T, return getExtQualType(TypeNode, Quals); } -QualType ASTContext::getNoReturnType(QualType T, bool AddNoReturn) { +static QualType getNoReturnCallConvType(ASTContext& Context, QualType T, + bool AddNoReturn, + CallingConv CallConv) { QualType ResultType; if (const PointerType *Pointer = T->getAs<PointerType>()) { QualType Pointee = Pointer->getPointeeType(); - ResultType = getNoReturnType(Pointee, AddNoReturn); + ResultType = getNoReturnCallConvType(Context, Pointee, AddNoReturn, + CallConv); if (ResultType == Pointee) return T; - - ResultType = getPointerType(ResultType); + + ResultType = Context.getPointerType(ResultType); } else if (const BlockPointerType *BlockPointer = T->getAs<BlockPointerType>()) { QualType Pointee = BlockPointer->getPointeeType(); - ResultType = getNoReturnType(Pointee, AddNoReturn); + ResultType = getNoReturnCallConvType(Context, Pointee, AddNoReturn, + CallConv); if (ResultType == Pointee) return T; - - ResultType = getBlockPointerType(ResultType); - } else if (const FunctionType *F = T->getAs<FunctionType>()) { - if (F->getNoReturnAttr() == AddNoReturn) + + ResultType = Context.getBlockPointerType(ResultType); + } else if (const FunctionType *F = T->getAs<FunctionType>()) { + if (F->getNoReturnAttr() == AddNoReturn && F->getCallConv() == CallConv) return T; - + if (const FunctionNoProtoType *FNPT = dyn_cast<FunctionNoProtoType>(F)) { - ResultType = getFunctionNoProtoType(FNPT->getResultType(), AddNoReturn); + ResultType = Context.getFunctionNoProtoType(FNPT->getResultType(), + AddNoReturn, CallConv); } else { const FunctionProtoType *FPT = cast<FunctionProtoType>(F); ResultType - = getFunctionType(FPT->getResultType(), FPT->arg_type_begin(), - FPT->getNumArgs(), FPT->isVariadic(), - FPT->getTypeQuals(), - FPT->hasExceptionSpec(), FPT->hasAnyExceptionSpec(), - FPT->getNumExceptions(), FPT->exception_begin(), - AddNoReturn); + = Context.getFunctionType(FPT->getResultType(), FPT->arg_type_begin(), + FPT->getNumArgs(), FPT->isVariadic(), + FPT->getTypeQuals(), + FPT->hasExceptionSpec(), + FPT->hasAnyExceptionSpec(), + FPT->getNumExceptions(), + FPT->exception_begin(), + AddNoReturn, CallConv); } } else return T; - - return getQualifiedType(ResultType, T.getLocalQualifiers()); + + return Context.getQualifiedType(ResultType, T.getLocalQualifiers()); +} + +QualType ASTContext::getNoReturnType(QualType T, bool AddNoReturn) { + return getNoReturnCallConvType(*this, T, AddNoReturn, T.getCallConv()); +} + +QualType ASTContext::getCallConvType(QualType T, CallingConv CallConv) { + return getNoReturnCallConvType(*this, T, T.getNoReturnAttr(), CallConv); } /// getComplexType - Return the uniqued reference to the type for a complex @@ -1679,9 +1694,16 @@ QualType ASTContext::getDependentSizedExtVectorType(QualType vecType, return QualType(New, 0); } +static CallingConv getCanonicalCallingConv(CallingConv CC) { + if (CC == CC_C) + return CC_Default; + return CC; +} + /// getFunctionNoProtoType - Return a K&R style C function type like 'int()'. /// -QualType ASTContext::getFunctionNoProtoType(QualType ResultTy, bool NoReturn) { +QualType ASTContext::getFunctionNoProtoType(QualType ResultTy, bool NoReturn, + CallingConv CallConv) { // Unique functions, to guarantee there is only one function of a particular // structure. llvm::FoldingSetNodeID ID; @@ -1693,8 +1715,10 @@ QualType ASTContext::getFunctionNoProtoType(QualType ResultTy, bool NoReturn) { return QualType(FT, 0); QualType Canonical; - if (!ResultTy.isCanonical()) { - Canonical = getFunctionNoProtoType(getCanonicalType(ResultTy), NoReturn); + if (!ResultTy.isCanonical() || + getCanonicalCallingConv(CallConv) != CallConv) { + Canonical = getFunctionNoProtoType(getCanonicalType(ResultTy), NoReturn, + getCanonicalCallingConv(CallConv)); // Get the new insert position for the node we care about. FunctionNoProtoType *NewIP = @@ -1715,7 +1739,8 @@ 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) { + const QualType *ExArray, bool NoReturn, + CallingConv CallConv) { // Unique functions, to guarantee there is only one function of a particular // structure. llvm::FoldingSetNodeID ID; @@ -1737,7 +1762,7 @@ QualType ASTContext::getFunctionType(QualType ResultTy,const QualType *ArgArray, // If this type isn't canonical, get the canonical version of it. // The exception spec is not part of the canonical type. QualType Canonical; - if (!isCanonical) { + if (!isCanonical || getCanonicalCallingConv(CallConv) != CallConv) { llvm::SmallVector<QualType, 16> CanonicalArgs; CanonicalArgs.reserve(NumArgs); for (unsigned i = 0; i != NumArgs; ++i) @@ -1746,7 +1771,8 @@ QualType ASTContext::getFunctionType(QualType ResultTy,const QualType *ArgArray, Canonical = getFunctionType(getCanonicalType(ResultTy), CanonicalArgs.data(), NumArgs, isVariadic, TypeQuals, false, - false, 0, 0, NoReturn); + false, 0, 0, NoReturn, + getCanonicalCallingConv(CallConv)); // Get the new insert position for the node we care about. FunctionProtoType *NewIP = @@ -1763,7 +1789,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); + ExArray, NumExs, Canonical, NoReturn, CallConv); Types.push_back(FTP); FunctionProtoTypes.InsertNode(FTP, InsertPos); return QualType(FTP, 0); @@ -2101,7 +2127,8 @@ QualType ASTContext::getObjCObjectPointerType(QualType InterfaceT, // No Match; ObjCObjectPointerType *QType = new (*this, TypeAlignment) - ObjCObjectPointerType(Canonical, InterfaceT, Protocols, NumProtocols); + ObjCObjectPointerType(*this, Canonical, InterfaceT, Protocols, + NumProtocols); Types.push_back(QType); ObjCObjectPointerTypes.InsertNode(QType, InsertPos); @@ -2135,7 +2162,7 @@ QualType ASTContext::getObjCInterfaceType(const ObjCInterfaceDecl *Decl, } ObjCInterfaceType *QType = new (*this, TypeAlignment) - ObjCInterfaceType(Canonical, const_cast<ObjCInterfaceDecl*>(Decl), + ObjCInterfaceType(*this, Canonical, const_cast<ObjCInterfaceDecl*>(Decl), Protocols, NumProtocols); Types.push_back(QType); @@ -3733,8 +3760,8 @@ void ASTContext::setObjCConstantStringInterface(ObjCInterfaceDecl *Decl) { /// \brief Retrieve the template name that corresponds to a non-empty /// lookup. -TemplateName ASTContext::getOverloadedTemplateName(NamedDecl * const *Begin, - NamedDecl * const *End) { +TemplateName ASTContext::getOverloadedTemplateName(UnresolvedSetIterator Begin, + UnresolvedSetIterator End) { unsigned size = End - Begin; assert(size > 1 && "set is not overloaded!"); @@ -3743,7 +3770,7 @@ TemplateName ASTContext::getOverloadedTemplateName(NamedDecl * const *Begin, OverloadedTemplateStorage *OT = new(memory) OverloadedTemplateStorage(size); NamedDecl **Storage = OT->getStorage(); - for (NamedDecl * const *I = Begin; I != End; ++I) { + for (UnresolvedSetIterator I = Begin; I != End; ++I) { NamedDecl *D = *I; assert(isa<FunctionTemplateDecl>(D) || (isa<UsingShadowDecl>(D) && @@ -4211,6 +4238,10 @@ bool ASTContext::typesAreCompatible(QualType LHS, QualType RHS) { return !mergeTypes(LHS, RHS).isNull(); } +static bool isSameCallingConvention(CallingConv lcc, CallingConv rcc) { + return (getCanonicalCallingConv(lcc) == getCanonicalCallingConv(rcc)); +} + QualType ASTContext::mergeFunctionTypes(QualType lhs, QualType rhs) { const FunctionType *lbase = lhs->getAs<FunctionType>(); const FunctionType *rbase = rhs->getAs<FunctionType>(); @@ -4232,6 +4263,11 @@ QualType ASTContext::mergeFunctionTypes(QualType lhs, QualType rhs) { allLTypes = false; if (NoReturn != rbase->getNoReturnAttr()) allRTypes = false; + CallingConv lcc = lbase->getCallConv(); + CallingConv rcc = rbase->getCallConv(); + // Compatible functions must have compatible calling conventions + if (!isSameCallingConvention(lcc, rcc)) + return QualType(); if (lproto && rproto) { // two C99 style function prototypes assert(!lproto->hasExceptionSpec() && !rproto->hasExceptionSpec() && @@ -4267,7 +4303,7 @@ QualType ASTContext::mergeFunctionTypes(QualType lhs, QualType rhs) { if (allRTypes) return rhs; return getFunctionType(retType, types.begin(), types.size(), lproto->isVariadic(), lproto->getTypeQuals(), - NoReturn); + NoReturn, lcc); } if (lproto) allRTypes = false; @@ -4294,12 +4330,12 @@ QualType ASTContext::mergeFunctionTypes(QualType lhs, QualType rhs) { if (allRTypes) return rhs; return getFunctionType(retType, proto->arg_type_begin(), proto->getNumArgs(), proto->isVariadic(), - proto->getTypeQuals(), NoReturn); + proto->getTypeQuals(), NoReturn, lcc); } if (allLTypes) return lhs; if (allRTypes) return rhs; - return getFunctionNoProtoType(retType, NoReturn); + return getFunctionNoProtoType(retType, NoReturn, lcc); } QualType ASTContext::mergeTypes(QualType LHS, QualType RHS) { diff --git a/lib/AST/CXXInheritance.cpp b/lib/AST/CXXInheritance.cpp index 92a58b7..7208328 100644 --- a/lib/AST/CXXInheritance.cpp +++ b/lib/AST/CXXInheritance.cpp @@ -145,7 +145,11 @@ bool CXXRecordDecl::lookupInBases(BaseMatchesCallback *BaseMatches, void *UserData, CXXBasePaths &Paths) const { bool FoundPath = false; - + + // The access of the path down to this record. + AccessSpecifier AccessToHere = Paths.ScratchPath.Access; + bool IsFirstStep = Paths.ScratchPath.empty(); + ASTContext &Context = getASTContext(); for (base_class_const_iterator BaseSpec = bases_begin(), BaseSpecEnd = bases_end(); BaseSpec != BaseSpecEnd; ++BaseSpec) { @@ -189,10 +193,31 @@ bool CXXRecordDecl::lookupInBases(BaseMatchesCallback *BaseMatches, else Element.SubobjectNumber = Subobjects.second; Paths.ScratchPath.push_back(Element); + + // Calculate the "top-down" access to this base class. + // The spec actually describes this bottom-up, but top-down is + // equivalent because the definition works out as follows: + // 1. Write down the access along each step in the inheritance + // chain, followed by the access of the decl itself. + // For example, in + // class A { public: int foo; }; + // class B : protected A {}; + // class C : public B {}; + // class D : private C {}; + // we would write: + // private public protected public + // 2. If 'private' appears anywhere except far-left, access is denied. + // 3. Otherwise, overall access is determined by the most restrictive + // access in the sequence. + if (IsFirstStep) + Paths.ScratchPath.Access = BaseSpec->getAccessSpecifier(); + else + Paths.ScratchPath.Access + = MergeAccess(AccessToHere, BaseSpec->getAccessSpecifier()); } if (BaseMatches(BaseSpec, Paths.ScratchPath, UserData)) { - // We've found a path that terminates that this base. + // We've found a path that terminates at this base. FoundPath = true; if (Paths.isRecordingPaths()) { // We have a path. Make a copy of it before moving on. @@ -223,13 +248,18 @@ bool CXXRecordDecl::lookupInBases(BaseMatchesCallback *BaseMatches, // Pop this base specifier off the current path (if we're // collecting paths). - if (Paths.isRecordingPaths()) + if (Paths.isRecordingPaths()) { Paths.ScratchPath.pop_back(); + } + // If we set a virtual earlier, and this isn't a path, forget it again. if (SetVirtual && !FoundPath) { Paths.DetectedVirtual = 0; } } + + // Reset the scratch path access. + Paths.ScratchPath.Access = AccessToHere; return FoundPath; } diff --git a/lib/AST/Decl.cpp b/lib/AST/Decl.cpp index e77661a..794b14a 100644 --- a/lib/AST/Decl.cpp +++ b/lib/AST/Decl.cpp @@ -629,9 +629,13 @@ VarDecl::~VarDecl() { } SourceRange VarDecl::getSourceRange() const { + SourceLocation Start = getTypeSpecStartLoc(); + if (Start.isInvalid()) + Start = getLocation(); + if (getInit()) - return SourceRange(getLocation(), getInit()->getLocEnd()); - return SourceRange(getLocation(), getLocation()); + return SourceRange(Start, getInit()->getLocEnd()); + return SourceRange(Start, getLocation()); } bool VarDecl::isOutOfLine() const { diff --git a/lib/AST/DeclBase.cpp b/lib/AST/DeclBase.cpp index 3afb4e4..84aa81c 100644 --- a/lib/AST/DeclBase.cpp +++ b/lib/AST/DeclBase.cpp @@ -102,6 +102,17 @@ bool Decl::isFunctionOrFunctionTemplate() const { return isa<FunctionDecl>(this) || isa<FunctionTemplateDecl>(this); } +bool Decl::isDefinedOutsideFunctionOrMethod() const { + for (const DeclContext *DC = getDeclContext(); + DC && !DC->isTranslationUnit(); + DC = DC->getParent()) + if (DC->isFunctionOrMethod()) + return false; + + return true; +} + + //===----------------------------------------------------------------------===// // PrettyStackTraceDecl Implementation //===----------------------------------------------------------------------===// @@ -399,8 +410,13 @@ SourceLocation Decl::getBodyRBrace() const { #ifndef NDEBUG void Decl::CheckAccessDeclContext() const { - // If the decl is the toplevel translation unit or if we're not in a - // record decl context, we don't need to check anything. + // Suppress this check if any of the following hold: + // 1. this is the translation unit (and thus has no parent) + // 2. this is a template parameter (and thus doesn't belong to its context) + // 3. this is a ParmVarDecl (which can be in a record context during + // the brief period between its creation and the creation of the + // FunctionDecl) + // 4. the context is not a record if (isa<TranslationUnitDecl>(this) || !isa<CXXRecordDecl>(getDeclContext())) return; diff --git a/lib/AST/DeclCXX.cpp b/lib/AST/DeclCXX.cpp index 1cce35c..fe6064d 100644 --- a/lib/AST/DeclCXX.cpp +++ b/lib/AST/DeclCXX.cpp @@ -312,8 +312,9 @@ void CXXRecordDecl::collectConversionFunctions( llvm::SmallPtrSet<CanQualType, 8>& ConversionsTypeSet) const { - const UnresolvedSet *Cs = getConversionFunctions(); - for (UnresolvedSet::iterator I = Cs->begin(), E = Cs->end(); I != E; ++I) { + const UnresolvedSetImpl *Cs = getConversionFunctions(); + for (UnresolvedSetImpl::iterator I = Cs->begin(), E = Cs->end(); + I != E; ++I) { NamedDecl *TopConv = *I; CanQualType TConvType; if (FunctionTemplateDecl *TConversionTemplate = @@ -344,10 +345,11 @@ CXXRecordDecl::getNestedVisibleConversionFunctions(CXXRecordDecl *RD, bool inTopClass = (RD == this); QualType ClassType = getASTContext().getTypeDeclType(this); if (const RecordType *Record = ClassType->getAs<RecordType>()) { - const UnresolvedSet *Cs + const UnresolvedSetImpl *Cs = cast<CXXRecordDecl>(Record->getDecl())->getConversionFunctions(); - for (UnresolvedSet::iterator I = Cs->begin(), E = Cs->end(); I != E; ++I) { + for (UnresolvedSetImpl::iterator I = Cs->begin(), E = Cs->end(); + I != E; ++I) { NamedDecl *Conv = *I; // Only those conversions not exact match of conversions in current // class are candidateconversion routines. @@ -410,7 +412,7 @@ CXXRecordDecl::getNestedVisibleConversionFunctions(CXXRecordDecl *RD, /// getVisibleConversionFunctions - get all conversion functions visible /// in current class; including conversion function templates. -const UnresolvedSet *CXXRecordDecl::getVisibleConversionFunctions() { +const UnresolvedSetImpl *CXXRecordDecl::getVisibleConversionFunctions() { // If root class, all conversions are visible. if (bases_begin() == bases_end()) return &Conversions; diff --git a/lib/AST/DeclObjC.cpp b/lib/AST/DeclObjC.cpp index 2506f27..ffda505 100644 --- a/lib/AST/DeclObjC.cpp +++ b/lib/AST/DeclObjC.cpp @@ -37,6 +37,21 @@ void ObjCListBase::set(void *const* InList, unsigned Elts, ASTContext &Ctx) { memcpy(List, InList, sizeof(void*)*Elts); } +void ObjCProtocolList::set(ObjCProtocolDecl* const* InList, unsigned Elts, + const SourceLocation *Locs, ASTContext &Ctx) { + if (Elts == 0) + return; + + Locations = new (Ctx) SourceLocation[Elts]; + memcpy(Locations, Locs, sizeof(SourceLocation) * Elts); + set(InList, Elts, Ctx); +} + +void ObjCProtocolList::Destroy(ASTContext &Ctx) { + Ctx.Deallocate(Locations); + Locations = 0; + ObjCList<ObjCProtocolDecl>::Destroy(Ctx); +} //===----------------------------------------------------------------------===// // ObjCInterfaceDecl @@ -141,16 +156,18 @@ ObjCContainerDecl::FindPropertyVisibleInPrimaryClass( void ObjCInterfaceDecl::mergeClassExtensionProtocolList( ObjCProtocolDecl *const* ExtList, unsigned ExtNum, + const SourceLocation *Locs, ASTContext &C) { if (ReferencedProtocols.empty()) { - ReferencedProtocols.set(ExtList, ExtNum, C); + ReferencedProtocols.set(ExtList, ExtNum, Locs, C); return; } // Check for duplicate protocol in class's protocol list. // This is (O)2. But it is extremely rare and number of protocols in // class or its extension are very few. llvm::SmallVector<ObjCProtocolDecl*, 8> ProtocolRefs; + llvm::SmallVector<SourceLocation, 8> ProtocolLocs; for (unsigned i = 0; i < ExtNum; i++) { bool protocolExists = false; ObjCProtocolDecl *ProtoInExtension = ExtList[i]; @@ -164,18 +181,23 @@ void ObjCInterfaceDecl::mergeClassExtensionProtocolList( } // Do we want to warn on a protocol in extension class which // already exist in the class? Probably not. - if (!protocolExists) + if (!protocolExists) { ProtocolRefs.push_back(ProtoInExtension); + ProtocolLocs.push_back(Locs[i]); + } } if (ProtocolRefs.empty()) return; // Merge ProtocolRefs into class's protocol list; + protocol_loc_iterator pl = protocol_loc_begin(); for (protocol_iterator p = protocol_begin(), e = protocol_end(); - p != e; p++) + p != e; ++p, ++pl) { ProtocolRefs.push_back(*p); + ProtocolLocs.push_back(*pl); + } ReferencedProtocols.Destroy(C); unsigned NumProtoRefs = ProtocolRefs.size(); - setProtocolList((ObjCProtocolDecl**)&ProtocolRefs[0], NumProtoRefs, C); + setProtocolList(ProtocolRefs.data(), NumProtoRefs, ProtocolLocs.data(), C); } ObjCIvarDecl *ObjCInterfaceDecl::lookupInstanceVariable(IdentifierInfo *ID, @@ -627,9 +649,9 @@ SourceRange ObjCClassDecl::getSourceRange() const { ObjCForwardProtocolDecl:: ObjCForwardProtocolDecl(DeclContext *DC, SourceLocation L, ObjCProtocolDecl *const *Elts, unsigned nElts, - ASTContext &C) + const SourceLocation *Locs, ASTContext &C) : Decl(ObjCForwardProtocol, DC, L) { - ReferencedProtocols.set(Elts, nElts, C); + ReferencedProtocols.set(Elts, nElts, Locs, C); } @@ -637,8 +659,9 @@ ObjCForwardProtocolDecl * ObjCForwardProtocolDecl::Create(ASTContext &C, DeclContext *DC, SourceLocation L, ObjCProtocolDecl *const *Elts, - unsigned NumElts) { - return new (C) ObjCForwardProtocolDecl(DC, L, Elts, NumElts, C); + unsigned NumElts, + const SourceLocation *Locs) { + return new (C) ObjCForwardProtocolDecl(DC, L, Elts, NumElts, Locs, C); } void ObjCForwardProtocolDecl::Destroy(ASTContext &C) { @@ -651,9 +674,11 @@ void ObjCForwardProtocolDecl::Destroy(ASTContext &C) { //===----------------------------------------------------------------------===// ObjCCategoryDecl *ObjCCategoryDecl::Create(ASTContext &C, DeclContext *DC, - SourceLocation L, + SourceLocation AtLoc, + SourceLocation ClassNameLoc, + SourceLocation CategoryNameLoc, IdentifierInfo *Id) { - return new (C) ObjCCategoryDecl(DC, L, Id); + return new (C) ObjCCategoryDecl(DC, AtLoc, ClassNameLoc, CategoryNameLoc, Id); } ObjCCategoryImplDecl *ObjCCategoryDecl::getImplementation() const { @@ -765,9 +790,10 @@ ObjCCompatibleAliasDecl::Create(ASTContext &C, DeclContext *DC, ObjCPropertyDecl *ObjCPropertyDecl::Create(ASTContext &C, DeclContext *DC, SourceLocation L, IdentifierInfo *Id, + SourceLocation AtLoc, QualType T, PropertyControl propControl) { - return new (C) ObjCPropertyDecl(DC, L, Id, T); + return new (C) ObjCPropertyDecl(DC, L, Id, AtLoc, T); } diff --git a/lib/AST/Expr.cpp b/lib/AST/Expr.cpp index 4c3046b..fa44b51 100644 --- a/lib/AST/Expr.cpp +++ b/lib/AST/Expr.cpp @@ -98,10 +98,12 @@ void DeclRefExpr::computeDependence() { // initialized with an expression that is value-dependent. else if (VarDecl *Var = dyn_cast<VarDecl>(D)) { if (Var->getType()->isIntegralType() && - Var->getType().getCVRQualifiers() == Qualifiers::Const && - Var->getInit() && - Var->getInit()->isValueDependent()) - ValueDependent = true; + Var->getType().getCVRQualifiers() == Qualifiers::Const) { + const VarDecl *Def = 0; + if (const Expr *Init = Var->getDefinition(Def)) + if (Init->isValueDependent()) + ValueDependent = true; + } } // (TD) - a nested-name-specifier or a qualified-id that names a // member of an unknown specialization. diff --git a/lib/AST/ExprCXX.cpp b/lib/AST/ExprCXX.cpp index 81584b7..a6574ef 100644 --- a/lib/AST/ExprCXX.cpp +++ b/lib/AST/ExprCXX.cpp @@ -135,10 +135,11 @@ UnresolvedLookupExpr::Create(ASTContext &C, bool Dependent, return ULE; } -bool UnresolvedLookupExpr::ComputeDependence(NamedDecl * const *Begin, - NamedDecl * const *End, - const TemplateArgumentListInfo *Args) { - for (NamedDecl * const *I = Begin; I != End; ++I) +bool UnresolvedLookupExpr:: + ComputeDependence(UnresolvedSetImpl::const_iterator Begin, + UnresolvedSetImpl::const_iterator End, + const TemplateArgumentListInfo *Args) { + for (UnresolvedSetImpl::const_iterator I = Begin; I != End; ++I) if ((*I)->getDeclContext()->isDependentContext()) return true; diff --git a/lib/AST/ExprConstant.cpp b/lib/AST/ExprConstant.cpp index dfff209..086249c 100644 --- a/lib/AST/ExprConstant.cpp +++ b/lib/AST/ExprConstant.cpp @@ -506,7 +506,9 @@ APValue PointerExprEvaluator::VisitCastExpr(CastExpr* E) { APValue PointerExprEvaluator::VisitCallExpr(CallExpr *E) { if (E->isBuiltinCall(Info.Ctx) == - Builtin::BI__builtin___CFStringMakeConstantString) + Builtin::BI__builtin___CFStringMakeConstantString || + E->isBuiltinCall(Info.Ctx) == + Builtin::BI__builtin___NSStringMakeConstantString) return APValue(E); return APValue(); } @@ -971,6 +973,8 @@ bool IntExprEvaluator::VisitCallExpr(const CallExpr *E) { case Builtin::BI__builtin_object_size: { const Expr *Arg = E->getArg(0)->IgnoreParens(); Expr::EvalResult Base; + + // TODO: Perhaps we should let LLVM lower this? if (Arg->EvaluateAsAny(Base, Info.Ctx) && Base.Val.getKind() == APValue::LValue && !Base.HasSideEffects) @@ -992,7 +996,8 @@ bool IntExprEvaluator::VisitCallExpr(const CallExpr *E) { } } - // TODO: Perhaps we should let LLVM lower this? + // If evaluating the argument has side-effects we can't determine + // the size of the object and lower it to unknown now. if (E->getArg(0)->HasSideEffects(Info.Ctx)) { if (E->getArg(1)->EvaluateAsInt(Info.Ctx).getZExtValue() <= 1) return Success(-1ULL, E); diff --git a/lib/AST/RecordLayoutBuilder.cpp b/lib/AST/RecordLayoutBuilder.cpp index cfd89ea..0aa0180 100644 --- a/lib/AST/RecordLayoutBuilder.cpp +++ b/lib/AST/RecordLayoutBuilder.cpp @@ -119,6 +119,11 @@ ASTRecordLayoutBuilder::SelectPrimaryVBase(const CXXRecordDecl *RD, return; } } + if (i->isVirtual()) { + SelectPrimaryVBase(Base, FirstPrimary); + if (PrimaryBase.getBase()) + return; + } } } diff --git a/lib/AST/Type.cpp b/lib/AST/Type.cpp index e0055f1..edfb580 100644 --- a/lib/AST/Type.cpp +++ b/lib/AST/Type.cpp @@ -339,6 +339,25 @@ const RecordType *Type::getAsUnionType() const { return 0; } +ObjCInterfaceType::ObjCInterfaceType(ASTContext &Ctx, QualType Canonical, + ObjCInterfaceDecl *D, + ObjCProtocolDecl **Protos, unsigned NumP) : + Type(ObjCInterface, Canonical, /*Dependent=*/false), + Decl(D), Protocols(0), NumProtocols(NumP) +{ + if (NumProtocols) { + Protocols = new (Ctx) ObjCProtocolDecl*[NumProtocols]; + memcpy(Protocols, Protos, NumProtocols * sizeof(*Protocols)); + } +} + +void ObjCInterfaceType::Destroy(ASTContext& C) { + if (Protocols) + C.Deallocate(Protocols); + this->~ObjCInterfaceType(); + C.Deallocate(this); +} + const ObjCInterfaceType *Type::getAsObjCQualifiedInterfaceType() const { // There is no sugar for ObjCInterfaceType's, just return the canonical // type pointer if it is the right class. There is no typedef information to @@ -353,6 +372,26 @@ bool Type::isObjCQualifiedInterfaceType() const { return getAsObjCQualifiedInterfaceType() != 0; } +ObjCObjectPointerType::ObjCObjectPointerType(ASTContext &Ctx, + QualType Canonical, QualType T, + ObjCProtocolDecl **Protos, + unsigned NumP) : + Type(ObjCObjectPointer, Canonical, /*Dependent=*/false), + PointeeType(T), Protocols(NULL), NumProtocols(NumP) +{ + if (NumProtocols) { + Protocols = new (Ctx) ObjCProtocolDecl*[NumProtocols]; + memcpy(Protocols, Protos, NumProtocols * sizeof(*Protocols)); + } +} + +void ObjCObjectPointerType::Destroy(ASTContext& C) { + if (Protocols) + C.Deallocate(Protocols); + this->~ObjCObjectPointerType(); + C.Deallocate(this); +} + const ObjCObjectPointerType *Type::getAsObjCQualifiedIdType() const { // There is no sugar for ObjCQualifiedIdType's, just return the canonical // type pointer if it is the right class. diff --git a/lib/AST/TypeLoc.cpp b/lib/AST/TypeLoc.cpp index 0840c52..fd9fbc1 100644 --- a/lib/AST/TypeLoc.cpp +++ b/lib/AST/TypeLoc.cpp @@ -14,6 +14,7 @@ #include "llvm/Support/raw_ostream.h" #include "clang/AST/TypeLocVisitor.h" #include "clang/AST/Expr.h" +#include "llvm/Support/ErrorHandling.h" using namespace clang; //===----------------------------------------------------------------------===// @@ -135,3 +136,56 @@ SourceRange TypeOfExprTypeLoc::getSourceRange() const { return SourceRange(getTypeofLoc(), getUnderlyingExpr()->getSourceRange().getEnd()); } + + +TypeSpecifierType BuiltinTypeLoc::getWrittenTypeSpec() const { + if (needsExtraLocalData()) + return static_cast<TypeSpecifierType>(getWrittenBuiltinSpecs().Type); + else { + switch (getTypePtr()->getKind()) { + case BuiltinType::Void: + return TST_void; + case BuiltinType::Bool: + return TST_bool; + case BuiltinType::Char_U: + case BuiltinType::Char_S: + return TST_char; + case BuiltinType::Char16: + return TST_char16; + case BuiltinType::Char32: + return TST_char32; + case BuiltinType::WChar: + return TST_wchar; + case BuiltinType::UndeducedAuto: + return TST_auto; + + case BuiltinType::UChar: + case BuiltinType::UShort: + case BuiltinType::UInt: + case BuiltinType::ULong: + case BuiltinType::ULongLong: + case BuiltinType::UInt128: + case BuiltinType::SChar: + case BuiltinType::Short: + case BuiltinType::Int: + case BuiltinType::Long: + case BuiltinType::LongLong: + case BuiltinType::Int128: + case BuiltinType::Float: + case BuiltinType::Double: + case BuiltinType::LongDouble: + llvm_unreachable("Builtin type needs extra local data!"); + // Fall through, if the impossible happens. + + case BuiltinType::NullPtr: + case BuiltinType::Overload: + case BuiltinType::Dependent: + case BuiltinType::ObjCId: + case BuiltinType::ObjCClass: + case BuiltinType::ObjCSel: + return TST_unspecified; + } + } + + return TST_unspecified; +} diff --git a/lib/Analysis/AnalysisContext.cpp b/lib/Analysis/AnalysisContext.cpp index 2093b5e..ad9f6dd 100644 --- a/lib/Analysis/AnalysisContext.cpp +++ b/lib/Analysis/AnalysisContext.cpp @@ -55,7 +55,7 @@ const ImplicitParamDecl *AnalysisContext::getSelfDecl() const { CFG *AnalysisContext::getCFG() { if (!cfg) - cfg = CFG::buildCFG(getBody(), &D->getASTContext()); + cfg = CFG::buildCFG(D, getBody(), &D->getASTContext(), AddEHEdges); return cfg; } diff --git a/lib/Analysis/ArrayBoundChecker.cpp b/lib/Analysis/ArrayBoundChecker.cpp index 3d95ab1..49c8606 100644 --- a/lib/Analysis/ArrayBoundChecker.cpp +++ b/lib/Analysis/ArrayBoundChecker.cpp @@ -57,7 +57,8 @@ void ArrayBoundChecker::VisitLocation(CheckerContext &C, const Stmt *S, SVal l){ // Get the size of the array. DefinedOrUnknownSVal NumElements - = C.getStoreManager().getSizeInElements(state, ER->getSuperRegion()); + = C.getStoreManager().getSizeInElements(state, ER->getSuperRegion(), + ER->getValueType(C.getASTContext())); const GRState *StInBound = state->AssumeInBound(Idx, NumElements, true); const GRState *StOutBound = state->AssumeInBound(Idx, NumElements, false); diff --git a/lib/Analysis/CFG.cpp b/lib/Analysis/CFG.cpp index eab7da7..5b8aeae 100644 --- a/lib/Analysis/CFG.cpp +++ b/lib/Analysis/CFG.cpp @@ -14,6 +14,7 @@ #include "clang/Analysis/Support/SaveAndRestore.h" #include "clang/Analysis/CFG.h" +#include "clang/AST/DeclCXX.h" #include "clang/AST/StmtVisitor.h" #include "clang/AST/PrettyPrinter.h" #include "llvm/Support/GraphWriter.h" @@ -70,6 +71,7 @@ class CFGBuilder { CFGBlock* BreakTargetBlock; CFGBlock* SwitchTerminatedBlock; CFGBlock* DefaultCaseBlock; + CFGBlock* TryTerminatedBlock; // LabelMap records the mapping from Label expressions to their blocks. typedef llvm::DenseMap<LabelStmt*,CFGBlock*> LabelMapTy; @@ -88,10 +90,12 @@ public: explicit CFGBuilder() : cfg(new CFG()), // crew a new CFG Block(NULL), Succ(NULL), ContinueTargetBlock(NULL), BreakTargetBlock(NULL), - SwitchTerminatedBlock(NULL), DefaultCaseBlock(NULL) {} + SwitchTerminatedBlock(NULL), DefaultCaseBlock(NULL), + TryTerminatedBlock(NULL) {} // buildCFG - Used by external clients to construct the CFG. - CFG* buildCFG(Stmt *Statement, ASTContext *C); + CFG* buildCFG(const Decl *D, Stmt *Statement, ASTContext *C, bool AddEHEdges, + bool AddScopes); private: // Visitors to walk an AST and construct the CFG. @@ -106,9 +110,9 @@ private: CFGBlock *VisitConditionalOperator(ConditionalOperator *C, AddStmtChoice asc); CFGBlock *VisitContinueStmt(ContinueStmt *C); - CFGBlock *VisitCXXCatchStmt(CXXCatchStmt *S) { return NYS(); } + CFGBlock *VisitCXXCatchStmt(CXXCatchStmt *S); CFGBlock *VisitCXXThrowExpr(CXXThrowExpr *T); - CFGBlock *VisitCXXTryStmt(CXXTryStmt *S) { return NYS(); } + CFGBlock *VisitCXXTryStmt(CXXTryStmt *S); CFGBlock *VisitDeclStmt(DeclStmt *DS); CFGBlock *VisitDeclSubExpr(Decl* D); CFGBlock *VisitDefaultStmt(DefaultStmt *D); @@ -139,6 +143,25 @@ private: return Block; } + CFGBlock *StartScope(Stmt *S, CFGBlock *B) { + if (!AddScopes) + return B; + + if (B == 0) + B = createBlock(); + B->StartScope(S, cfg->getBumpVectorContext()); + return B; + } + + void EndScope(Stmt *S) { + if (!AddScopes) + return; + + if (Block == 0) + Block = createBlock(); + Block->EndScope(S, cfg->getBumpVectorContext()); + } + void autoCreateBlock() { if (!Block) Block = createBlock(); } CFGBlock *createBlock(bool add_successor = true); bool FinishBlock(CFGBlock* B); @@ -186,6 +209,12 @@ private: } bool badCFG; + + // True iff EH edges on CallExprs should be added to the CFG. + bool AddEHEdges; + + // True iff scope start and scope end notes should be added to the CFG. + bool AddScopes; }; // FIXME: Add support for dependent-sized array types in C++? @@ -207,12 +236,15 @@ static VariableArrayType* FindVA(Type* t) { /// body (compound statement). The ownership of the returned CFG is /// transferred to the caller. If CFG construction fails, this method returns /// NULL. -CFG* CFGBuilder::buildCFG(Stmt* Statement, ASTContext* C) { +CFG* CFGBuilder::buildCFG(const Decl *D, Stmt* Statement, ASTContext* C, + bool addehedges, bool AddScopes) { + AddEHEdges = addehedges; Context = C; assert(cfg.get()); if (!Statement) return NULL; + this->AddScopes = AddScopes; badCFG = false; // Create an empty block that will serve as the exit block for the CFG. Since @@ -224,6 +256,11 @@ CFG* CFGBuilder::buildCFG(Stmt* Statement, ASTContext* C) { // Visit the statements and create the CFG. CFGBlock* B = addStmt(Statement); + + if (const CXXConstructorDecl *CD = dyn_cast_or_null<CXXConstructorDecl>(D)) { + // FIXME: Add code for base initializers and member initializers. + (void)CD; + } if (!B) B = Succ; @@ -329,6 +366,15 @@ tryAgain: case Stmt::ContinueStmtClass: return VisitContinueStmt(cast<ContinueStmt>(S)); + case Stmt::CXXCatchStmtClass: + return VisitCXXCatchStmt(cast<CXXCatchStmt>(S)); + + case Stmt::CXXThrowExprClass: + return VisitCXXThrowExpr(cast<CXXThrowExpr>(S)); + + case Stmt::CXXTryStmtClass: + return VisitCXXTryStmt(cast<CXXTryStmt>(S)); + case Stmt::DeclStmtClass: return VisitDeclStmt(cast<DeclStmt>(S)); @@ -356,9 +402,6 @@ tryAgain: case Stmt::ObjCAtCatchStmtClass: return VisitObjCAtCatchStmt(cast<ObjCAtCatchStmt>(S)); - case Stmt::CXXThrowExprClass: - return VisitCXXThrowExpr(cast<CXXThrowExpr>(S)); - case Stmt::ObjCAtSynchronizedStmtClass: return VisitObjCAtSynchronizedStmt(cast<ObjCAtSynchronizedStmt>(S)); @@ -456,7 +499,7 @@ CFGBlock *CFGBuilder::VisitBinaryOperator(BinaryOperator *B, AddSuccessor(LHSBlock, KnownVal.isTrue() ? NULL : ConfluenceBlock); AddSuccessor(LHSBlock, KnownVal.isFalse() ? NULL : RHSBlock); } else { - assert (B->getOpcode() == BinaryOperator::LAnd); + assert(B->getOpcode() == BinaryOperator::LAnd); AddSuccessor(LHSBlock, KnownVal.isFalse() ? NULL : RHSBlock); AddSuccessor(LHSBlock, KnownVal.isTrue() ? NULL : ConfluenceBlock); } @@ -504,6 +547,22 @@ CFGBlock *CFGBuilder::VisitBreakStmt(BreakStmt *B) { return Block; } +static bool CanThrow(Expr *E) { + QualType Ty = E->getType(); + if (Ty->isFunctionPointerType()) + Ty = Ty->getAs<PointerType>()->getPointeeType(); + else if (Ty->isBlockPointerType()) + Ty = Ty->getAs<BlockPointerType>()->getPointeeType(); + + const FunctionType *FT = Ty->getAs<FunctionType>(); + if (FT) { + if (const FunctionProtoType *Proto = dyn_cast<FunctionProtoType>(FT)) + if (Proto->hasEmptyExceptionSpec()) + return false; + } + return true; +} + 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; @@ -511,22 +570,47 @@ CFGBlock *CFGBuilder::VisitCallExpr(CallExpr *C, AddStmtChoice asc) { NoReturn = true; } - if (FunctionDecl *FD = C->getDirectCallee()) + bool AddEHEdge = false; + + // Languages without exceptions are assumed to not throw. + if (Context->getLangOptions().Exceptions) { + if (AddEHEdges) + AddEHEdge = true; + } + + if (FunctionDecl *FD = C->getDirectCallee()) { if (FD->hasAttr<NoReturnAttr>()) NoReturn = true; + if (FD->hasAttr<NoThrowAttr>()) + AddEHEdge = false; + } - if (!NoReturn) + if (!CanThrow(C->getCallee())) + AddEHEdge = false; + + if (!NoReturn && !AddEHEdge) return VisitStmt(C, asc); - if (Block && !FinishBlock(Block)) - return 0; + if (Block) { + Succ = Block; + if (!FinishBlock(Block)) + return 0; + } - // Create new block with no successor for the remaining pieces. - Block = createBlock(false); + Block = createBlock(!NoReturn); AppendStmt(Block, C, asc); - // Wire this to the exit block directly. - AddSuccessor(Block, &cfg->getExit()); + if (NoReturn) { + // Wire this to the exit block directly. + AddSuccessor(Block, &cfg->getExit()); + } + if (AddEHEdge) { + // Add exceptional edges. + if (TryTerminatedBlock) + AddSuccessor(Block, TryTerminatedBlock); + else + AddSuccessor(Block, &cfg->getExit()); + } return VisitChildren(C); } @@ -561,6 +645,8 @@ CFGBlock *CFGBuilder::VisitChooseExpr(ChooseExpr *C, CFGBlock* CFGBuilder::VisitCompoundStmt(CompoundStmt* C) { + EndScope(C); + CFGBlock* LastBlock = Block; for (CompoundStmt::reverse_body_iterator I=C->body_rbegin(), E=C->body_rend(); @@ -570,6 +656,9 @@ CFGBlock* CFGBuilder::VisitCompoundStmt(CompoundStmt* C) { if (badCFG) return NULL; } + + LastBlock = StartScope(C, LastBlock); + return LastBlock; } @@ -743,7 +832,7 @@ CFGBlock* CFGBuilder::VisitIfStmt(IfStmt* I) { CFGBlock* ThenBlock; { Stmt* Then = I->getThen(); - assert (Then); + assert(Then); SaveAndRestore<CFGBlock*> sv(Succ); Block = NULL; ThenBlock = addStmt(Then); @@ -919,12 +1008,12 @@ CFGBlock* CFGBuilder::VisitForStmt(ForStmt* F) { // Now create the loop body. { - assert (F->getBody()); + assert(F->getBody()); // Save the current values for Block, Succ, and continue and break targets SaveAndRestore<CFGBlock*> save_Block(Block), save_Succ(Succ), - save_continue(ContinueTargetBlock), - save_break(BreakTargetBlock); + save_continue(ContinueTargetBlock), + save_break(BreakTargetBlock); // Create a new block to contain the (bottom) of the loop body. Block = NULL; @@ -1252,8 +1341,12 @@ CFGBlock* CFGBuilder::VisitCXXThrowExpr(CXXThrowExpr* T) { // Create the new block. Block = createBlock(false); - // The Exit block is the only successor. - AddSuccessor(Block, &cfg->getExit()); + if (TryTerminatedBlock) + // The current try statement is the only successor. + AddSuccessor(Block, TryTerminatedBlock); + else + // otherwise the Exit block is the only successor. + AddSuccessor(Block, &cfg->getExit()); // Add the statement to the block. This may create new blocks if S contains // control-flow (short-circuit operations). @@ -1301,12 +1394,12 @@ CFGBlock *CFGBuilder::VisitDoStmt(DoStmt* D) { // Process the loop body. CFGBlock* BodyBlock = NULL; { - assert (D->getBody()); + assert(D->getBody()); // Save the current values for Block, Succ, and continue and break targets SaveAndRestore<CFGBlock*> save_Block(Block), save_Succ(Succ), - save_continue(ContinueTargetBlock), - save_break(BreakTargetBlock); + save_continue(ContinueTargetBlock), + save_break(BreakTargetBlock); // All continues within this loop should go to the condition block ContinueTargetBlock = EntryConditionBlock; @@ -1434,7 +1527,7 @@ CFGBlock* CFGBuilder::VisitSwitchStmt(SwitchStmt* Terminator) { // When visiting the body, the case statements should automatically get linked // up to the switch. We also don't keep a pointer to the body, since all // control-flow from the switch goes to case/default statements. - assert (Terminator->getBody() && "switch must contain a non-NULL body"); + assert(Terminator->getBody() && "switch must contain a non-NULL body"); Block = NULL; CFGBlock *BodyBlock = addStmt(Terminator->getBody()); if (Block) { @@ -1448,7 +1541,7 @@ CFGBlock* CFGBuilder::VisitSwitchStmt(SwitchStmt* Terminator) { // Add the terminator and condition in the switch block. SwitchTerminatedBlock->setTerminator(Terminator); - assert (Terminator->getCond() && "switch condition must be non-NULL"); + assert(Terminator->getCond() && "switch condition must be non-NULL"); Block = SwitchTerminatedBlock; Block = addStmt(Terminator->getCond()); @@ -1528,6 +1621,82 @@ CFGBlock* CFGBuilder::VisitDefaultStmt(DefaultStmt* Terminator) { return DefaultCaseBlock; } +CFGBlock *CFGBuilder::VisitCXXTryStmt(CXXTryStmt *Terminator) { + // "try"/"catch" is a control-flow statement. Thus we stop processing the + // current block. + CFGBlock* TrySuccessor = NULL; + + if (Block) { + if (!FinishBlock(Block)) + return 0; + TrySuccessor = Block; + } else TrySuccessor = Succ; + + CFGBlock *PrevTryTerminatedBlock = TryTerminatedBlock; + + // Create a new block that will contain the try statement. + CFGBlock *NewTryTerminatedBlock = createBlock(false); + // Add the terminator in the try block. + NewTryTerminatedBlock->setTerminator(Terminator); + + bool HasCatchAll = false; + for (unsigned h = 0; h <Terminator->getNumHandlers(); ++h) { + // The code after the try is the implicit successor. + Succ = TrySuccessor; + CXXCatchStmt *CS = Terminator->getHandler(h); + if (CS->getExceptionDecl() == 0) { + HasCatchAll = true; + } + Block = NULL; + CFGBlock *CatchBlock = VisitCXXCatchStmt(CS); + if (CatchBlock == 0) + return 0; + // Add this block to the list of successors for the block with the try + // statement. + AddSuccessor(NewTryTerminatedBlock, CatchBlock); + } + if (!HasCatchAll) { + if (PrevTryTerminatedBlock) + AddSuccessor(NewTryTerminatedBlock, PrevTryTerminatedBlock); + else + AddSuccessor(NewTryTerminatedBlock, &cfg->getExit()); + } + + // The code after the try is the implicit successor. + Succ = TrySuccessor; + + // Save the current "try" context. + SaveAndRestore<CFGBlock*> save_try(TryTerminatedBlock); + TryTerminatedBlock = NewTryTerminatedBlock; + + assert(Terminator->getTryBlock() && "try must contain a non-NULL body"); + Block = NULL; + Block = addStmt(Terminator->getTryBlock()); + return Block; +} + +CFGBlock* CFGBuilder::VisitCXXCatchStmt(CXXCatchStmt* CS) { + // CXXCatchStmt are treated like labels, so they are the first statement in a + // block. + + if (CS->getHandlerBlock()) + addStmt(CS->getHandlerBlock()); + + CFGBlock* CatchBlock = Block; + if (!CatchBlock) + CatchBlock = createBlock(); + + CatchBlock->setLabel(CS); + + if (!FinishBlock(CatchBlock)) + return 0; + + // We set Block to NULL to allow lazy creation of a new block (if necessary) + Block = NULL; + + return CatchBlock; +} + CFGBlock* CFGBuilder::VisitIndirectGotoStmt(IndirectGotoStmt* I) { // Lazily create the indirect-goto dispatch block if there isn't one already. CFGBlock* IBlock = cfg->getIndirectGotoBlock(); @@ -1571,9 +1740,10 @@ CFGBlock* CFG::createBlock() { /// buildCFG - Constructs a CFG from an AST. Ownership of the returned /// CFG is returned to the caller. -CFG* CFG::buildCFG(Stmt* Statement, ASTContext *C) { +CFG* CFG::buildCFG(const Decl *D, Stmt* Statement, ASTContext *C, + bool AddEHEdges, bool AddScopes) { CFGBuilder Builder; - return Builder.buildCFG(Statement, C); + return Builder.buildCFG(D, Statement, C, AddEHEdges, AddScopes); } //===----------------------------------------------------------------------===// @@ -1661,9 +1831,7 @@ CFG::BlkExprNumTy CFG::getBlkExprNum(const Stmt* S) { BlkExprMapTy* M = reinterpret_cast<BlkExprMapTy*>(BlkExprMap); BlkExprMapTy::iterator I = M->find(S); - - if (I == M->end()) return CFG::BlkExprNumTy(); - else return CFG::BlkExprNumTy(I->second); + return (I == M->end()) ? CFG::BlkExprNumTy() : CFG::BlkExprNumTy(I->second); } unsigned CFG::getNumBlkExprs() { @@ -1692,7 +1860,6 @@ CFG::~CFG() { namespace { class StmtPrinterHelper : public PrinterHelper { - typedef llvm::DenseMap<Stmt*,std::pair<unsigned,unsigned> > StmtMapTy; StmtMapTy StmtMap; signed CurrentBlock; @@ -1724,10 +1891,11 @@ public: return false; if (CurrentBlock >= 0 && I->second.first == (unsigned) CurrentBlock - && I->second.second == CurrentStmt) + && I->second.second == CurrentStmt) { return false; + } - OS << "[B" << I->second.first << "." << I->second.second << "]"; + OS << "[B" << I->second.first << "." << I->second.second << "]"; return true; } }; @@ -1741,7 +1909,6 @@ class CFGBlockTerminatorPrint llvm::raw_ostream& OS; StmtPrinterHelper* Helper; PrintingPolicy Policy; - public: CFGBlockTerminatorPrint(llvm::raw_ostream& os, StmtPrinterHelper* helper, const PrintingPolicy &Policy) @@ -1759,22 +1926,27 @@ public: void VisitForStmt(ForStmt* F) { OS << "for (" ; - if (F->getInit()) OS << "..."; + if (F->getInit()) + OS << "..."; OS << "; "; - if (Stmt* C = F->getCond()) C->printPretty(OS, Helper, Policy); + if (Stmt* C = F->getCond()) + C->printPretty(OS, Helper, Policy); OS << "; "; - if (F->getInc()) OS << "..."; + if (F->getInc()) + OS << "..."; OS << ")"; } void VisitWhileStmt(WhileStmt* W) { OS << "while " ; - if (Stmt* C = W->getCond()) C->printPretty(OS, Helper, Policy); + if (Stmt* C = W->getCond()) + C->printPretty(OS, Helper, Policy); } void VisitDoStmt(DoStmt* D) { OS << "do ... while "; - if (Stmt* C = D->getCond()) C->printPretty(OS, Helper, Policy); + if (Stmt* C = D->getCond()) + C->printPretty(OS, Helper, Policy); } void VisitSwitchStmt(SwitchStmt* Terminator) { @@ -1782,6 +1954,10 @@ public: Terminator->getCond()->printPretty(OS, Helper, Policy); } + void VisitCXXTryStmt(CXXTryStmt* CS) { + OS << "try ..."; + } + void VisitConditionalOperator(ConditionalOperator* C) { C->getCond()->printPretty(OS, Helper, Policy); OS << " ? ... : ..."; @@ -1826,7 +2002,18 @@ public: static void print_stmt(llvm::raw_ostream &OS, StmtPrinterHelper* Helper, - Stmt* Terminator) { + const CFGElement &E) { + Stmt *Terminator = E; + + if (E.asStartScope()) { + OS << "start scope\n"; + return; + } + if (E.asEndScope()) { + OS << "end scope\n"; + return; + } + if (Helper) { // special printing for statement-expressions. if (StmtExpr* SE = dyn_cast<StmtExpr>(Terminator)) { @@ -1876,14 +2063,14 @@ static void print_block(llvm::raw_ostream& OS, const CFG* cfg, OS << " ]\n"; // Print the label of this block. - if (Stmt* Terminator = const_cast<Stmt*>(B.getLabel())) { + if (Stmt* Label = const_cast<Stmt*>(B.getLabel())) { if (print_edges) OS << " "; - if (LabelStmt* L = dyn_cast<LabelStmt>(Terminator)) + if (LabelStmt* L = dyn_cast<LabelStmt>(Label)) OS << L->getName(); - else if (CaseStmt* C = dyn_cast<CaseStmt>(Terminator)) { + else if (CaseStmt* C = dyn_cast<CaseStmt>(Label)) { OS << "case "; C->getLHS()->printPretty(OS, Helper, PrintingPolicy(Helper->getLangOpts())); @@ -1892,9 +2079,18 @@ static void print_block(llvm::raw_ostream& OS, const CFG* cfg, C->getRHS()->printPretty(OS, Helper, PrintingPolicy(Helper->getLangOpts())); } - } else if (isa<DefaultStmt>(Terminator)) + } else if (isa<DefaultStmt>(Label)) OS << "default"; - else + else if (CXXCatchStmt *CS = dyn_cast<CXXCatchStmt>(Label)) { + OS << "catch ("; + if (CS->getExceptionDecl()) + CS->getExceptionDecl()->print(OS, PrintingPolicy(Helper->getLangOpts()), + 0); + else + OS << "..."; + OS << ")"; + + } else assert(false && "Invalid label statement in CFGBlock."); OS << ":\n"; diff --git a/lib/Analysis/CastToStructChecker.cpp b/lib/Analysis/CastToStructChecker.cpp index a366342..219c09f 100644 --- a/lib/Analysis/CastToStructChecker.cpp +++ b/lib/Analysis/CastToStructChecker.cpp @@ -8,7 +8,7 @@ //===----------------------------------------------------------------------===// // // This files defines CastToStructChecker, a builtin checker that checks for -// assignment of a fixed address to a pointer. +// cast from non-struct pointer to struct pointer. // This check corresponds to CWE-588. // //===----------------------------------------------------------------------===// diff --git a/lib/Analysis/GRExprEngine.cpp b/lib/Analysis/GRExprEngine.cpp index 40c12c9..8f8d859 100644 --- a/lib/Analysis/GRExprEngine.cpp +++ b/lib/Analysis/GRExprEngine.cpp @@ -2173,8 +2173,8 @@ void GRExprEngine::VisitObjCMessageExprDispatchHelper(ObjCMessageExpr* ME, // Transfer functions: Miscellaneous statements. //===----------------------------------------------------------------------===// -void GRExprEngine::VisitCast(Expr* CastE, Expr* Ex, ExplodedNode* Pred, - ExplodedNodeSet& Dst, bool asLValue){ +void GRExprEngine::VisitCast(CastExpr *CastE, Expr *Ex, ExplodedNode *Pred, + ExplodedNodeSet &Dst, bool asLValue) { ExplodedNodeSet S1; QualType T = CastE->getType(); QualType ExTy = Ex->getType(); @@ -2191,14 +2191,6 @@ void GRExprEngine::VisitCast(Expr* CastE, Expr* Ex, ExplodedNode* Pred, ExplodedNodeSet S2; CheckerVisit(CastE, S2, S1, true); - // Check for casting to "void". - if (T->isVoidType()) { - assert(!asLValue); - for (ExplodedNodeSet::iterator I = S2.begin(), E = S2.end(); I != E; ++I) - Dst.Add(*I); - return; - } - // If we are evaluating the cast in an lvalue context, we implicitly want // the cast to evaluate to a location. if (asLValue) { @@ -2207,13 +2199,51 @@ void GRExprEngine::VisitCast(Expr* CastE, Expr* Ex, ExplodedNode* Pred, ExTy = Ctx.getPointerType(Ctx.getCanonicalType(ExTy)); } - for (ExplodedNodeSet::iterator I = S2.begin(), E = S2.end(); I != E; ++I) { - ExplodedNode* N = *I; - const GRState* state = GetState(N); - SVal V = state->getSVal(Ex); - const SValuator::CastResult &Res = SVator.EvalCast(V, state, T, ExTy); - state = Res.getState()->BindExpr(CastE, Res.getSVal()); - MakeNode(Dst, CastE, N, state); + switch (CastE->getCastKind()) { + case CastExpr::CK_ToVoid: + assert(!asLValue); + for (ExplodedNodeSet::iterator I = S2.begin(), E = S2.end(); I != E; ++I) + Dst.Add(*I); + return; + + case CastExpr::CK_NoOp: + case CastExpr::CK_FunctionToPointerDecay: + for (ExplodedNodeSet::iterator I = S2.begin(), E = S2.end(); I != E; ++I) { + // Copy the SVal of Ex to CastE. + ExplodedNode *N = *I; + const GRState *state = GetState(N); + SVal V = state->getSVal(Ex); + state = state->BindExpr(CastE, V); + MakeNode(Dst, CastE, N, state); + } + return; + + case CastExpr::CK_Unknown: + case CastExpr::CK_ArrayToPointerDecay: + case CastExpr::CK_BitCast: + case CastExpr::CK_IntegralCast: + case CastExpr::CK_IntegralToPointer: + case CastExpr::CK_PointerToIntegral: + case CastExpr::CK_IntegralToFloating: + case CastExpr::CK_FloatingToIntegral: + case CastExpr::CK_FloatingCast: + case CastExpr::CK_AnyPointerToObjCPointerCast: + case CastExpr::CK_AnyPointerToBlockPointerCast: + case CastExpr::CK_DerivedToBase: + // Delegate to SValuator to process. + for (ExplodedNodeSet::iterator I = S2.begin(), E = S2.end(); I != E; ++I) { + ExplodedNode* N = *I; + const GRState* state = GetState(N); + SVal V = state->getSVal(Ex); + const SValuator::CastResult &Res = SVator.EvalCast(V, state, T, ExTy); + state = Res.getState()->BindExpr(CastE, Res.getSVal()); + MakeNode(Dst, CastE, N, state); + } + return; + + default: + llvm::errs() << "Cast kind " << CastE->getCastKind() << " not handled.\n"; + assert(0); } } @@ -2952,13 +2982,13 @@ void GRExprEngine::VisitBinaryOperator(BinaryOperator* B, // Perform a load (the LHS). This performs the checks for // null dereferences, and so on. - ExplodedNodeSet Tmp3; + ExplodedNodeSet Tmp4; SVal location = state->getSVal(LHS); - EvalLoad(Tmp3, LHS, *I2, state, location); + EvalLoad(Tmp4, LHS, *I2, state, location); - for (ExplodedNodeSet::iterator I3=Tmp3.begin(), E3=Tmp3.end(); I3!=E3; - ++I3) { - state = GetState(*I3); + for (ExplodedNodeSet::iterator I4=Tmp4.begin(), E4=Tmp4.end(); I4!=E4; + ++I4) { + state = GetState(*I4); SVal V = state->getSVal(LHS); // Get the computation type. @@ -3008,7 +3038,7 @@ void GRExprEngine::VisitBinaryOperator(BinaryOperator* B, llvm::tie(state, LHSVal) = SVator.EvalCast(Result, state, LTy, CTy); } - EvalStore(Tmp3, B, LHS, *I3, state->BindExpr(B, Result), + EvalStore(Tmp3, B, LHS, *I4, state->BindExpr(B, Result), location, LHSVal); } } diff --git a/lib/Analysis/MallocChecker.cpp b/lib/Analysis/MallocChecker.cpp index fab73ee..28f4db7 100644 --- a/lib/Analysis/MallocChecker.cpp +++ b/lib/Analysis/MallocChecker.cpp @@ -72,7 +72,7 @@ public: private: void MallocMem(CheckerContext &C, const CallExpr *CE); const GRState *MallocMemAux(CheckerContext &C, const CallExpr *CE, - const GRState *state); + const Expr *SizeEx, const GRState *state); void FreeMem(CheckerContext &C, const CallExpr *CE); const GRState *FreeMemAux(CheckerContext &C, const CallExpr *CE, const GRState *state); @@ -136,18 +136,24 @@ bool MallocChecker::EvalCallExpr(CheckerContext &C, const CallExpr *CE) { } void MallocChecker::MallocMem(CheckerContext &C, const CallExpr *CE) { - const GRState *state = MallocMemAux(C, CE, C.getState()); + const GRState *state = MallocMemAux(C, CE, CE->getArg(0), C.getState()); C.addTransition(state); } const GRState *MallocChecker::MallocMemAux(CheckerContext &C, const CallExpr *CE, + const Expr *SizeEx, const GRState *state) { unsigned Count = C.getNodeBuilder().getCurrentBlockCount(); ValueManager &ValMgr = C.getValueManager(); SVal RetVal = ValMgr.getConjuredSymbolVal(NULL, CE, CE->getType(), Count); + SVal Size = state->getSVal(SizeEx); + + state = C.getEngine().getStoreManager().setExtent(state, RetVal.getAsRegion(), + Size); + state = state->BindExpr(CE, RetVal); SymbolRef Sym = RetVal.getAsLocSymbol(); @@ -170,7 +176,12 @@ const GRState *MallocChecker::FreeMemAux(CheckerContext &C, const CallExpr *CE, assert(Sym); const RefState *RS = state->get<RegionState>(Sym); - assert(RS); + + // If the symbol has not been tracked, return. This is possible when free() is + // called on a pointer that does not get its pointee directly from malloc(). + // Full support of this requires inter-procedural analysis. + if (!RS) + return state; // Check double free. if (RS->isReleased()) { @@ -211,7 +222,7 @@ void MallocChecker::ReallocMem(CheckerContext &C, const CallExpr *CE) { if (Sym) stateEqual = stateEqual->set<RegionState>(Sym, RefState::getReleased(CE)); - const GRState *stateMalloc = MallocMemAux(C, CE, stateEqual); + const GRState *stateMalloc = MallocMemAux(C, CE, CE->getArg(1), stateEqual); C.addTransition(stateMalloc); } @@ -232,7 +243,8 @@ void MallocChecker::ReallocMem(CheckerContext &C, const CallExpr *CE) { const GRState *stateFree = FreeMemAux(C, CE, stateSizeNotZero); if (stateFree) { // FIXME: We should copy the content of the original buffer. - const GRState *stateRealloc = MallocMemAux(C, CE, stateFree); + const GRState *stateRealloc = MallocMemAux(C, CE, CE->getArg(1), + stateFree); C.addTransition(stateRealloc); } } diff --git a/lib/Analysis/RegionStore.cpp b/lib/Analysis/RegionStore.cpp index 9b5b44b..a735ed9 100644 --- a/lib/Analysis/RegionStore.cpp +++ b/lib/Analysis/RegionStore.cpp @@ -21,6 +21,7 @@ #include "clang/Analysis/Analyses/LiveVariables.h" #include "clang/Analysis/Support/Optional.h" #include "clang/Basic/TargetInfo.h" +#include "clang/AST/CharUnits.h" #include "llvm/ADT/ImmutableMap.h" #include "llvm/ADT/ImmutableList.h" @@ -423,9 +424,9 @@ public: // Region "extents". //===------------------------------------------------------------------===// - const GRState *setExtent(const GRState *state, const MemRegion* R, SVal Extent); + const GRState *setExtent(const GRState *state,const MemRegion* R,SVal Extent); DefinedOrUnknownSVal getSizeInElements(const GRState *state, - const MemRegion* R); + const MemRegion* R, QualType EleTy); //===------------------------------------------------------------------===// // Utility methods. @@ -767,7 +768,8 @@ SVal RegionStoreManager::getLValueElement(QualType elementType, SVal Offset, //===----------------------------------------------------------------------===// DefinedOrUnknownSVal RegionStoreManager::getSizeInElements(const GRState *state, - const MemRegion *R) { + const MemRegion *R, + QualType EleTy) { switch (R->getKind()) { case MemRegion::CXXThisRegionKind: @@ -793,10 +795,25 @@ DefinedOrUnknownSVal RegionStoreManager::getSizeInElements(const GRState *state, case MemRegion::ElementRegionKind: case MemRegion::FieldRegionKind: case MemRegion::ObjCIvarRegionKind: - case MemRegion::SymbolicRegionKind: case MemRegion::CXXObjectRegionKind: return UnknownVal(); + case MemRegion::SymbolicRegionKind: { + const SVal *Size = state->get<RegionExtents>(R); + if (!Size) + return UnknownVal(); + const nonloc::ConcreteInt *CI = dyn_cast<nonloc::ConcreteInt>(Size); + if (!CI) + return UnknownVal(); + + CharUnits RegionSize = + CharUnits::fromQuantity(CI->getValue().getSExtValue()); + CharUnits EleSize = getContext().getTypeSizeInChars(EleTy); + assert(RegionSize % EleSize == 0); + + return ValMgr.makeIntVal(RegionSize / EleSize, false); + } + case MemRegion::StringRegionKind: { const StringLiteral* Str = cast<StringRegion>(R)->getStringLiteral(); // We intentionally made the size value signed because it participates in diff --git a/lib/Analysis/ReturnPointerRangeChecker.cpp b/lib/Analysis/ReturnPointerRangeChecker.cpp index ab0fcab..b0350cb 100644 --- a/lib/Analysis/ReturnPointerRangeChecker.cpp +++ b/lib/Analysis/ReturnPointerRangeChecker.cpp @@ -65,7 +65,8 @@ void ReturnPointerRangeChecker::PreVisitReturnStmt(CheckerContext &C, // into a common place. DefinedOrUnknownSVal NumElements - = C.getStoreManager().getSizeInElements(state, ER->getSuperRegion()); + = C.getStoreManager().getSizeInElements(state, ER->getSuperRegion(), + ER->getValueType(C.getASTContext())); const GRState *StInBound = state->AssumeInBound(Idx, NumElements, true); const GRState *StOutBound = state->AssumeInBound(Idx, NumElements, false); diff --git a/lib/Basic/Makefile b/lib/Basic/Makefile index 5bd4314..f733578 100644 --- a/lib/Basic/Makefile +++ b/lib/Basic/Makefile @@ -17,10 +17,13 @@ BUILD_ARCHIVE = 1 CXXFLAGS = -fno-rtti CPPFLAGS += -I$(PROJ_SRC_DIR)/../../include -I$(PROJ_OBJ_DIR)/../../include +ifdef CLANG_VENDOR +CPPFLAGS += -DCLANG_VENDOR='"$(CLANG_VENDOR) "' +endif include $(LEVEL)/Makefile.common -SVN_REVISION := $(shell cd $(PROJ_SRC_DIR)/../.. && svnversion) +SVN_REVISION := $(shell $(LLVM_SRC_ROOT)/utils/GetSourceVersion $(PROJ_SRC_DIR)/../..) CPP.Defines += -I$(PROJ_SRC_DIR)/../../include -I$(PROJ_OBJ_DIR)/../../include \ -DSVN_REVISION='"$(SVN_REVISION)"' diff --git a/lib/Basic/Targets.cpp b/lib/Basic/Targets.cpp index bba2c3f..ea076ae 100644 --- a/lib/Basic/Targets.cpp +++ b/lib/Basic/Targets.cpp @@ -16,9 +16,9 @@ #include "clang/Basic/Builtins.h" #include "clang/Basic/Diagnostic.h" #include "clang/Basic/LangOptions.h" +#include "clang/Basic/MacroBuilder.h" #include "clang/Basic/TargetBuiltins.h" #include "clang/Basic/TargetOptions.h" -#include "clang/Frontend/Utils.h" #include "llvm/ADT/APFloat.h" #include "llvm/ADT/OwningPtr.h" #include "llvm/ADT/STLExtras.h" diff --git a/lib/Basic/Version.cpp b/lib/Basic/Version.cpp index ba31544..b1b250f 100644 --- a/lib/Basic/Version.cpp +++ b/lib/Basic/Version.cpp @@ -10,13 +10,17 @@ // This file defines several version-related utility functions for Clang. // //===----------------------------------------------------------------------===// + +#include "clang/Basic/Version.h" +#include "llvm/Support/raw_ostream.h" #include <cstring> #include <cstdlib> + using namespace std; namespace clang { -const char *getClangSubversionPath() { +llvm::StringRef getClangRepositoryPath() { static const char *Path = 0; if (Path) return Path; @@ -41,13 +45,43 @@ const char *getClangSubversionPath() { } -unsigned getClangSubversionRevision() { +llvm::StringRef getClangRevision() { #ifndef SVN_REVISION // Subversion was not available at build time? - return 0; + return llvm::StringRef(); #else - return strtol(SVN_REVISION, 0, 10); + static std::string revision; + if (revision.empty()) { + llvm::raw_string_ostream OS(revision); + OS << strtol(SVN_REVISION, 0, 10); + } + return revision; #endif } +llvm::StringRef getClangFullRepositoryVersion() { + static std::string buf; + if (buf.empty()) { + llvm::raw_string_ostream OS(buf); + OS << getClangRepositoryPath(); + llvm::StringRef Revision = getClangRevision(); + if (!Revision.empty()) + OS << ' ' << Revision; + } + return buf; +} + +const char *getClangFullVersion() { + static std::string buf; + if (buf.empty()) { + llvm::raw_string_ostream OS(buf); +#ifdef CLANG_VENDOR + OS << CLANG_VENDOR; +#endif + OS << "clang version " CLANG_VERSION_STRING " (" + << getClangFullRepositoryVersion() << ')'; + } + return buf.c_str(); +} + } // end namespace clang diff --git a/lib/CodeGen/CGBlocks.cpp b/lib/CodeGen/CGBlocks.cpp index 1fa422f..ca5b6fa 100644 --- a/lib/CodeGen/CGBlocks.cpp +++ b/lib/CodeGen/CGBlocks.cpp @@ -18,7 +18,6 @@ #include "llvm/Module.h" #include "llvm/Target/TargetData.h" #include <algorithm> -#include <cstdio> using namespace clang; using namespace CodeGen; @@ -221,11 +220,10 @@ llvm::Value *CodeGenFunction::BuildBlockLiteralTmp(const BlockExpr *BE) { C = llvm::ConstantStruct::get(VMContext, Elts, false); - char Name[32]; - sprintf(Name, "__block_holder_tmp_%d", CGM.getGlobalUniqueCount()); C = new llvm::GlobalVariable(CGM.getModule(), C->getType(), true, - llvm::GlobalValue::InternalLinkage, - C, Name); + llvm::GlobalValue::InternalLinkage, C, + "__block_holder_tmp_" + + llvm::Twine(CGM.getGlobalUniqueCount())); QualType BPT = BE->getType(); C = llvm::ConstantExpr::getBitCast(C, ConvertType(BPT)); return C; @@ -747,13 +745,12 @@ CodeGenFunction::GenerateBlockFunction(const BlockExpr *BExpr, const CGFunctionInfo &FI = CGM.getTypes().getFunctionInfo(ResultType, Args); - std::string Name = std::string("__") + Info.Name + "_block_invoke_"; CodeGenTypes &Types = CGM.getTypes(); const llvm::FunctionType *LTy = Types.GetFunctionType(FI, IsVariadic); llvm::Function *Fn = llvm::Function::Create(LTy, llvm::GlobalValue::InternalLinkage, - Name, + llvm::Twine("__") + Info.Name + "_block_invoke_", &CGM.getModule()); CGM.SetInternalFunctionAttributes(BD, Fn, FI); @@ -875,14 +872,12 @@ GenerateCopyHelperFunction(bool BlockHasCopyDispose, const llvm::StructType *T, // FIXME: We'd like to put these into a mergable by content, with // internal linkage. - std::string Name = std::string("__copy_helper_block_"); CodeGenTypes &Types = CGM.getTypes(); const llvm::FunctionType *LTy = Types.GetFunctionType(FI, false); llvm::Function *Fn = llvm::Function::Create(LTy, llvm::GlobalValue::InternalLinkage, - Name, - &CGM.getModule()); + "__copy_helper_block_", &CGM.getModule()); IdentifierInfo *II = &CGM.getContext().Idents.get("__copy_helper_block_"); @@ -958,14 +953,12 @@ GenerateDestroyHelperFunction(bool BlockHasCopyDispose, // FIXME: We'd like to put these into a mergable by content, with // internal linkage. - std::string Name = std::string("__destroy_helper_block_"); CodeGenTypes &Types = CGM.getTypes(); const llvm::FunctionType *LTy = Types.GetFunctionType(FI, false); llvm::Function *Fn = llvm::Function::Create(LTy, llvm::GlobalValue::InternalLinkage, - Name, - &CGM.getModule()); + "__destroy_helper_block_", &CGM.getModule()); IdentifierInfo *II = &CGM.getContext().Idents.get("__destroy_helper_block_"); @@ -1042,7 +1035,6 @@ GeneratebyrefCopyHelperFunction(const llvm::Type *T, int flag) { const CGFunctionInfo &FI = CGM.getTypes().getFunctionInfo(R, Args); - std::string Name = std::string("__Block_byref_id_object_copy_"); CodeGenTypes &Types = CGM.getTypes(); const llvm::FunctionType *LTy = Types.GetFunctionType(FI, false); @@ -1050,8 +1042,7 @@ GeneratebyrefCopyHelperFunction(const llvm::Type *T, int flag) { // internal linkage. llvm::Function *Fn = llvm::Function::Create(LTy, llvm::GlobalValue::InternalLinkage, - Name, - &CGM.getModule()); + "__Block_byref_id_object_copy_", &CGM.getModule()); IdentifierInfo *II = &CGM.getContext().Idents.get("__Block_byref_id_object_copy_"); @@ -1107,7 +1098,6 @@ BlockFunction::GeneratebyrefDestroyHelperFunction(const llvm::Type *T, const CGFunctionInfo &FI = CGM.getTypes().getFunctionInfo(R, Args); - std::string Name = std::string("__Block_byref_id_object_dispose_"); CodeGenTypes &Types = CGM.getTypes(); const llvm::FunctionType *LTy = Types.GetFunctionType(FI, false); @@ -1115,7 +1105,7 @@ BlockFunction::GeneratebyrefDestroyHelperFunction(const llvm::Type *T, // internal linkage. llvm::Function *Fn = llvm::Function::Create(LTy, llvm::GlobalValue::InternalLinkage, - Name, + "__Block_byref_id_object_dispose_", &CGM.getModule()); IdentifierInfo *II diff --git a/lib/CodeGen/CGBuiltin.cpp b/lib/CodeGen/CGBuiltin.cpp index 866c587..f11d52e 100644 --- a/lib/CodeGen/CGBuiltin.cpp +++ b/lib/CodeGen/CGBuiltin.cpp @@ -72,6 +72,7 @@ RValue CodeGenFunction::EmitBuiltinExpr(const FunctionDecl *FD, switch (BuiltinID) { default: break; // Handle intrinsics and libm functions below. case Builtin::BI__builtin___CFStringMakeConstantString: + case Builtin::BI__builtin___NSStringMakeConstantString: return RValue::get(CGM.EmitConstantExpr(E, E->getType(), 0)); case Builtin::BI__builtin_stdarg_start: case Builtin::BI__builtin_va_start: @@ -556,6 +557,18 @@ RValue CodeGenFunction::EmitBuiltinExpr(const FunctionDecl *FD, return RValue::get(0); } + case Builtin::BI__builtin_llvm_memory_barrier: { + Value *C[5] = { + EmitScalarExpr(E->getArg(0)), + EmitScalarExpr(E->getArg(1)), + EmitScalarExpr(E->getArg(2)), + EmitScalarExpr(E->getArg(3)), + EmitScalarExpr(E->getArg(4)) + }; + Builder.CreateCall(CGM.getIntrinsic(Intrinsic::memory_barrier), C, C + 5); + return RValue::get(0); + } + // Library functions with special handling. case Builtin::BIsqrt: case Builtin::BIsqrtf: diff --git a/lib/CodeGen/CGClass.cpp b/lib/CodeGen/CGClass.cpp index ab3fece..a822ca2 100644 --- a/lib/CodeGen/CGClass.cpp +++ b/lib/CodeGen/CGClass.cpp @@ -394,10 +394,8 @@ void CodeGenFunction::EmitClassAggrCopyAssignment(llvm::Value *Dest, if (BitwiseAssign) EmitAggregateCopy(Dest, Src, Ty); else { - bool hasCopyAssign = BaseClassDecl->hasConstCopyAssignment(getContext(), - MD); - assert(hasCopyAssign && "EmitClassAggrCopyAssignment - No user assign"); - (void)hasCopyAssign; + BaseClassDecl->hasConstCopyAssignment(getContext(), MD); + assert(MD && "EmitClassAggrCopyAssignment - No user assign"); const FunctionProtoType *FPT = MD->getType()->getAs<FunctionProtoType>(); const llvm::Type *LTy = CGM.getTypes().GetFunctionType(CGM.getTypes().getFunctionInfo(MD), @@ -410,8 +408,10 @@ void CodeGenFunction::EmitClassAggrCopyAssignment(llvm::Value *Dest, MD->getThisType(getContext()))); // Push the Src ptr. - CallArgs.push_back(std::make_pair(RValue::get(Src), - MD->getParamDecl(0)->getType())); + QualType SrcTy = MD->getParamDecl(0)->getType(); + RValue SrcValue = SrcTy->isReferenceType() ? RValue::get(Src) : + RValue::getAggregate(Src); + CallArgs.push_back(std::make_pair(SrcValue, SrcTy)); QualType ResultType = MD->getType()->getAs<FunctionType>()->getResultType(); EmitCall(CGM.getTypes().getFunctionInfo(ResultType, CallArgs), Callee, ReturnValueSlot(), CallArgs, MD); @@ -531,10 +531,8 @@ void CodeGenFunction::EmitClassCopyAssignment( } const CXXMethodDecl *MD = 0; - bool ConstCopyAssignOp = BaseClassDecl->hasConstCopyAssignment(getContext(), - MD); - assert(ConstCopyAssignOp && "EmitClassCopyAssignment - missing copy assign"); - (void)ConstCopyAssignOp; + BaseClassDecl->hasConstCopyAssignment(getContext(), MD); + assert(MD && "EmitClassCopyAssignment - missing copy assign"); const FunctionProtoType *FPT = MD->getType()->getAs<FunctionProtoType>(); const llvm::Type *LTy = @@ -548,8 +546,10 @@ void CodeGenFunction::EmitClassCopyAssignment( MD->getThisType(getContext()))); // Push the Src ptr. - CallArgs.push_back(std::make_pair(RValue::get(Src), - MD->getParamDecl(0)->getType())); + QualType SrcTy = MD->getParamDecl(0)->getType(); + RValue SrcValue = SrcTy->isReferenceType() ? RValue::get(Src) : + RValue::getAggregate(Src); + CallArgs.push_back(std::make_pair(SrcValue, SrcTy)); QualType ResultType = MD->getType()->getAs<FunctionType>()->getResultType(); EmitCall(CGM.getTypes().getFunctionInfo(ResultType, CallArgs), diff --git a/lib/CodeGen/CGDebugInfo.cpp b/lib/CodeGen/CGDebugInfo.cpp index ab8f663..1ffad3e 100644 --- a/lib/CodeGen/CGDebugInfo.cpp +++ b/lib/CodeGen/CGDebugInfo.cpp @@ -460,58 +460,15 @@ llvm::DIType CGDebugInfo::CreateType(const FunctionType *Ty, return DbgTy; } -/// CreateType - get structure or union type. -llvm::DIType CGDebugInfo::CreateType(const RecordType *Ty, - llvm::DICompileUnit Unit) { - RecordDecl *Decl = Ty->getDecl(); - - unsigned Tag; - if (Decl->isStruct()) - Tag = llvm::dwarf::DW_TAG_structure_type; - else if (Decl->isUnion()) - Tag = llvm::dwarf::DW_TAG_union_type; - else { - assert(Decl->isClass() && "Unknown RecordType!"); - Tag = llvm::dwarf::DW_TAG_class_type; - } - +/// CollectRecordFields - A helper function to collect debug info for +/// record fields. This is used while creating debug info entry for a Record. +void CGDebugInfo:: +CollectRecordFields(const RecordDecl *Decl, + llvm::DICompileUnit Unit, + llvm::SmallVectorImpl<llvm::DIDescriptor> &EltTys) { + unsigned FieldNo = 0; SourceManager &SM = CGM.getContext().getSourceManager(); - - // Get overall information about the record type for the debug info. - PresumedLoc PLoc = SM.getPresumedLoc(Decl->getLocation()); - llvm::DICompileUnit DefUnit; - unsigned Line = 0; - if (!PLoc.isInvalid()) { - DefUnit = getOrCreateCompileUnit(Decl->getLocation()); - Line = PLoc.getLine(); - } - - // Records and classes and unions can all be recursive. To handle them, we - // first generate a debug descriptor for the struct as a forward declaration. - // Then (if it is a definition) we go through and get debug info for all of - // its members. Finally, we create a descriptor for the complete type (which - // may refer to the forward decl if the struct is recursive) and replace all - // uses of the forward declaration with the final definition. - llvm::DICompositeType FwdDecl = - DebugFactory.CreateCompositeType(Tag, Unit, Decl->getName(), - DefUnit, Line, 0, 0, 0, 0, - llvm::DIType(), llvm::DIArray()); - - // If this is just a forward declaration, return it. - if (!Decl->getDefinition(CGM.getContext())) - return FwdDecl; - - llvm::TrackingVH<llvm::MDNode> FwdDeclNode = FwdDecl.getNode(); - // Otherwise, insert it into the TypeCache so that recursive uses will find - // it. - TypeCache[QualType(Ty, 0).getAsOpaquePtr()] = FwdDecl.getNode(); - - // Convert all the elements. - llvm::SmallVector<llvm::DIDescriptor, 16> EltTys; - const ASTRecordLayout &RL = CGM.getContext().getASTRecordLayout(Decl); - - unsigned FieldNo = 0; for (RecordDecl::field_iterator I = Decl->field_begin(), E = Decl->field_end(); I != E; ++I, ++FieldNo) { @@ -560,6 +517,125 @@ llvm::DIType CGDebugInfo::CreateType(const RecordType *Ty, FieldOffset, 0, FieldTy); EltTys.push_back(FieldTy); } +} + +/// CollectCXXMemberFunctions - A helper function to collect debug info for +/// C++ member functions.This is used while creating debug info entry for +/// a Record. +void CGDebugInfo:: +CollectCXXMemberFunctions(const CXXRecordDecl *Decl, + llvm::DICompileUnit Unit, + llvm::SmallVectorImpl<llvm::DIDescriptor> &EltTys, + llvm::DICompositeType &RecordTy) { + SourceManager &SM = CGM.getContext().getSourceManager(); + for(CXXRecordDecl::method_iterator I = Decl->method_begin(), + E = Decl->method_end(); I != E; ++I) { + CXXMethodDecl *Method = *I; + llvm::StringRef MethodName; + llvm::StringRef MethodLinkageName; + llvm::DIType MethodTy = getOrCreateType(Method->getType(), Unit); + if (CXXConstructorDecl *CDecl = dyn_cast<CXXConstructorDecl>(Method)) { + if (CDecl->isImplicit()) + continue; + MethodName = Decl->getName(); + // FIXME : Find linkage name. + } else if (CXXDestructorDecl *DDecl = dyn_cast<CXXDestructorDecl>(Method)) { + if (DDecl->isImplicit()) + continue; + MethodName = getFunctionName(Method); + // FIXME : Find linkage name. + } else { + if (Method->isImplicit()) + continue; + // regular method + MethodName = getFunctionName(Method); + MethodLinkageName = CGM.getMangledName(Method); + } + + // Get the location for the method. + SourceLocation MethodDefLoc = Method->getLocation(); + PresumedLoc PLoc = SM.getPresumedLoc(MethodDefLoc); + llvm::DICompileUnit MethodDefUnit; + unsigned MethodLine = 0; + + if (!PLoc.isInvalid()) { + MethodDefUnit = getOrCreateCompileUnit(MethodDefLoc); + MethodLine = PLoc.getLine(); + } + + llvm::DISubprogram SP = + DebugFactory.CreateSubprogram(RecordTy , MethodName, MethodName, + MethodLinkageName, + MethodDefUnit, MethodLine, + MethodTy, false, + Method->isThisDeclarationADefinition(), + 0 /*Virtuality*/, 0 /*VIndex*/, + llvm::DIType() /*ContainingType*/); + if (Method->isThisDeclarationADefinition()) + SPCache[cast<FunctionDecl>(Method)] = llvm::WeakVH(SP.getNode()); + EltTys.push_back(SP); + } +} + +/// CreateType - get structure or union type. +llvm::DIType CGDebugInfo::CreateType(const RecordType *Ty, + llvm::DICompileUnit Unit) { + RecordDecl *Decl = Ty->getDecl(); + + unsigned Tag; + if (Decl->isStruct()) + Tag = llvm::dwarf::DW_TAG_structure_type; + else if (Decl->isUnion()) + Tag = llvm::dwarf::DW_TAG_union_type; + else { + assert(Decl->isClass() && "Unknown RecordType!"); + Tag = llvm::dwarf::DW_TAG_class_type; + } + + SourceManager &SM = CGM.getContext().getSourceManager(); + + // Get overall information about the record type for the debug info. + PresumedLoc PLoc = SM.getPresumedLoc(Decl->getLocation()); + llvm::DICompileUnit DefUnit; + unsigned Line = 0; + if (!PLoc.isInvalid()) { + DefUnit = getOrCreateCompileUnit(Decl->getLocation()); + Line = PLoc.getLine(); + } + + // Records and classes and unions can all be recursive. To handle them, we + // first generate a debug descriptor for the struct as a forward declaration. + // Then (if it is a definition) we go through and get debug info for all of + // its members. Finally, we create a descriptor for the complete type (which + // may refer to the forward decl if the struct is recursive) and replace all + // uses of the forward declaration with the final definition. + + // A Decl->getName() is not unique. However, the debug info descriptors + // are uniqued. The debug info descriptor describing record's context is + // necessary to keep two Decl's descriptor unique if their name match. + // FIXME : Use RecordDecl's DeclContext's descriptor. As a temp. step + // use type's name in FwdDecl. + std::string STy = QualType(Ty, 0).getAsString(); + llvm::DICompositeType FwdDecl = + DebugFactory.CreateCompositeType(Tag, Unit, STy.c_str(), + DefUnit, Line, 0, 0, 0, 0, + llvm::DIType(), llvm::DIArray()); + + // If this is just a forward declaration, return it. + if (!Decl->getDefinition(CGM.getContext())) + return FwdDecl; + + llvm::TrackingVH<llvm::MDNode> FwdDeclNode = FwdDecl.getNode(); + // Otherwise, insert it into the TypeCache so that recursive uses will find + // it. + TypeCache[QualType(Ty, 0).getAsOpaquePtr()] = FwdDecl.getNode(); + + // Convert all the elements. + llvm::SmallVector<llvm::DIDescriptor, 16> EltTys; + + CollectRecordFields(Decl, Unit, EltTys); + if (CXXRecordDecl *CXXDecl = dyn_cast<CXXRecordDecl>(Decl)) + CollectCXXMemberFunctions(CXXDecl, Unit, EltTys, FwdDecl); llvm::DIArray Elements = DebugFactory.GetOrCreateArray(EltTys.data(), EltTys.size()); @@ -1000,18 +1076,27 @@ void CGDebugInfo::EmitFunctionStart(GlobalDecl GD, QualType FnType, const Decl *D = GD.getDecl(); if (const FunctionDecl *FD = dyn_cast<FunctionDecl>(D)) { + // If there is a DISubprogram for this function available then use it. + llvm::DenseMap<const FunctionDecl *, llvm::WeakVH>::iterator + FI = SPCache.find(FD); + if (FI != SPCache.end()) { + llvm::DISubprogram SP(dyn_cast_or_null<llvm::MDNode>(FI->second)); + if (!SP.isNull() && SP.isSubprogram() && SP.isDefinition()) { + RegionStack.push_back(SP.getNode()); + return; + } + } Name = getFunctionName(FD); - if (Name[0] == '\01') + if (!Name.empty() && Name[0] == '\01') Name = Name.substr(1); // Use mangled name as linkage name for c/c++ functions. LinkageName = CGM.getMangledName(GD); } else { // Use llvm function name as linkage name. Name = Fn->getName(); - // Skip the asm prefix if it exists. - if (Name[0] == '\01') - Name = Name.substr(1); LinkageName = Name; + if (!Name.empty() && Name[0] == '\01') + Name = Name.substr(1); } // It is expected that CurLoc is set before using EmitFunctionStart. diff --git a/lib/CodeGen/CGDebugInfo.h b/lib/CodeGen/CGDebugInfo.h index 8e88988..fddd23b 100644 --- a/lib/CodeGen/CGDebugInfo.h +++ b/lib/CodeGen/CGDebugInfo.h @@ -64,6 +64,8 @@ class CGDebugInfo { /// constructed on demand. For example, C++ destructors, C++ operators etc.. llvm::BumpPtrAllocator FunctionNames; + llvm::DenseMap<const FunctionDecl *, llvm::WeakVH> SPCache; + /// Helper functions for getOrCreateType. llvm::DIType CreateType(const BuiltinType *Ty, llvm::DICompileUnit U); llvm::DIType CreateType(const ComplexType *Ty, llvm::DICompileUnit U); @@ -85,6 +87,12 @@ class CGDebugInfo { llvm::DIType CreatePointerLikeType(unsigned Tag, const Type *Ty, QualType PointeeTy, llvm::DICompileUnit U); + void CollectCXXMemberFunctions(const CXXRecordDecl *Decl, + llvm::DICompileUnit U, + llvm::SmallVectorImpl<llvm::DIDescriptor> &E, + llvm::DICompositeType &T); + void CollectRecordFields(const RecordDecl *Decl, llvm::DICompileUnit U, + llvm::SmallVectorImpl<llvm::DIDescriptor> &E); public: CGDebugInfo(CodeGenModule &CGM); ~CGDebugInfo(); diff --git a/lib/CodeGen/CGExprConstant.cpp b/lib/CodeGen/CGExprConstant.cpp index dec06e2..7d5b3da 100644 --- a/lib/CodeGen/CGExprConstant.cpp +++ b/lib/CodeGen/CGExprConstant.cpp @@ -742,7 +742,8 @@ public: return CGM.GetAddrOfConstantStringFromObjCEncode(cast<ObjCEncodeExpr>(E)); case Expr::ObjCStringLiteralClass: { ObjCStringLiteral* SL = cast<ObjCStringLiteral>(E); - llvm::Constant *C = CGM.getObjCRuntime().GenerateConstantString(SL); + llvm::Constant *C = + CGM.getObjCRuntime().GenerateConstantString(SL->getString()); return llvm::ConstantExpr::getBitCast(C, ConvertType(E->getType())); } case Expr::PredefinedExprClass: { @@ -764,11 +765,18 @@ public: } case Expr::CallExprClass: { CallExpr* CE = cast<CallExpr>(E); - if (CE->isBuiltinCall(CGM.getContext()) != - Builtin::BI__builtin___CFStringMakeConstantString) + unsigned builtin = CE->isBuiltinCall(CGM.getContext()); + if (builtin != + Builtin::BI__builtin___CFStringMakeConstantString && + builtin != + Builtin::BI__builtin___NSStringMakeConstantString) break; const Expr *Arg = CE->getArg(0)->IgnoreParenCasts(); const StringLiteral *Literal = cast<StringLiteral>(Arg); + if (builtin == + Builtin::BI__builtin___NSStringMakeConstantString) { + return CGM.getObjCRuntime().GenerateConstantString(Literal); + } // FIXME: need to deal with UCN conversion issues. return CGM.GetAddrOfConstantCFString(Literal); } diff --git a/lib/CodeGen/CGObjC.cpp b/lib/CodeGen/CGObjC.cpp index ac391d9..896d220 100644 --- a/lib/CodeGen/CGObjC.cpp +++ b/lib/CodeGen/CGObjC.cpp @@ -26,7 +26,8 @@ using namespace CodeGen; /// Emits an instance of NSConstantString representing the object. llvm::Value *CodeGenFunction::EmitObjCStringLiteral(const ObjCStringLiteral *E) { - llvm::Constant *C = CGM.getObjCRuntime().GenerateConstantString(E); + llvm::Constant *C = + CGM.getObjCRuntime().GenerateConstantString(E->getString()); // FIXME: This bitcast should just be made an invariant on the Runtime. return llvm::ConstantExpr::getBitCast(C, ConvertType(E->getType())); } diff --git a/lib/CodeGen/CGObjCGNU.cpp b/lib/CodeGen/CGObjCGNU.cpp index e7a2093..77be9fb 100644 --- a/lib/CodeGen/CGObjCGNU.cpp +++ b/lib/CodeGen/CGObjCGNU.cpp @@ -124,7 +124,7 @@ private: void EmitClassRef(const std::string &className); public: CGObjCGNU(CodeGen::CodeGenModule &cgm); - virtual llvm::Constant *GenerateConstantString(const ObjCStringLiteral *); + virtual llvm::Constant *GenerateConstantString(const StringLiteral *); virtual CodeGen::RValue GenerateMessageSend(CodeGen::CodeGenFunction &CGF, QualType ResultType, @@ -240,15 +240,23 @@ CGObjCGNU::CGObjCGNU(CodeGen::CodeGenModule &cgm) Zeros[1] = Zeros[0]; NULLPtr = llvm::ConstantPointerNull::get(PtrToInt8Ty); // Get the selector Type. - SelectorTy = cast<llvm::PointerType>( - CGM.getTypes().ConvertType(CGM.getContext().getObjCSelType())); + QualType selTy = CGM.getContext().getObjCSelType(); + if (QualType() == selTy) { + SelectorTy = PtrToInt8Ty; + } else { + SelectorTy = cast<llvm::PointerType>(CGM.getTypes().ConvertType(selTy)); + } PtrToIntTy = llvm::PointerType::getUnqual(IntTy); PtrTy = PtrToInt8Ty; // Object type ASTIdTy = CGM.getContext().getObjCIdType(); - IdTy = cast<llvm::PointerType>(CGM.getTypes().ConvertType(ASTIdTy)); + if (QualType() == ASTIdTy) { + IdTy = PtrToInt8Ty; + } else { + IdTy = cast<llvm::PointerType>(CGM.getTypes().ConvertType(ASTIdTy)); + } // IMP type std::vector<const llvm::Type*> IMPArgs; @@ -348,12 +356,9 @@ llvm::Constant *CGObjCGNU::MakeGlobal(const llvm::ArrayType *Ty, } /// Generate an NSConstantString object. -//TODO: In case there are any crazy people still using the GNU runtime without -//an OpenStep implementation, this should let them select their own class for -//constant strings. -llvm::Constant *CGObjCGNU::GenerateConstantString(const ObjCStringLiteral *SL) { - std::string Str(SL->getString()->getStrData(), - SL->getString()->getByteLength()); +llvm::Constant *CGObjCGNU::GenerateConstantString(const StringLiteral *SL) { + std::string Str(SL->getStrData(), SL->getByteLength()); + std::vector<llvm::Constant*> Ivars; Ivars.push_back(NULLPtr); Ivars.push_back(MakeConstantString(Str)); diff --git a/lib/CodeGen/CGObjCMac.cpp b/lib/CodeGen/CGObjCMac.cpp index 727746f..137ea51 100644 --- a/lib/CodeGen/CGObjCMac.cpp +++ b/lib/CodeGen/CGObjCMac.cpp @@ -952,7 +952,7 @@ public: CGObjCCommonMac(CodeGen::CodeGenModule &cgm) : CGM(cgm), VMContext(cgm.getLLVMContext()) { } - virtual llvm::Constant *GenerateConstantString(const ObjCStringLiteral *SL); + virtual llvm::Constant *GenerateConstantString(const StringLiteral *SL); virtual llvm::Function *GenerateMethod(const ObjCMethodDecl *OMD, const ObjCContainerDecl *CD=0); @@ -1454,8 +1454,8 @@ llvm::Value *CGObjCMac::GetSelector(CGBuilderTy &Builder, const ObjCMethodDecl */ llvm::Constant *CGObjCCommonMac::GenerateConstantString( - const ObjCStringLiteral *SL) { - return CGM.GetAddrOfConstantCFString(SL->getString()); + const StringLiteral *SL) { + return CGM.GetAddrOfConstantCFString(SL); } /// Generates a message send where the super is the receiver. This is diff --git a/lib/CodeGen/CGObjCRuntime.h b/lib/CodeGen/CGObjCRuntime.h index 6b45562..ff5d40b 100644 --- a/lib/CodeGen/CGObjCRuntime.h +++ b/lib/CodeGen/CGObjCRuntime.h @@ -106,7 +106,7 @@ public: const ObjCMethodDecl *Method) = 0; /// Generate a constant string object. - virtual llvm::Constant *GenerateConstantString(const ObjCStringLiteral *) = 0; + virtual llvm::Constant *GenerateConstantString(const StringLiteral *) = 0; /// Generate a category. A category contains a list of methods (and /// accompanying metadata) and a list of protocols. diff --git a/lib/CodeGen/CGVTT.cpp b/lib/CodeGen/CGVTT.cpp new file mode 100644 index 0000000..9714bd9 --- /dev/null +++ b/lib/CodeGen/CGVTT.cpp @@ -0,0 +1,398 @@ +//===--- CGVTT.cpp - Emit LLVM Code for C++ VTTs --------------------------===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// +// This contains code dealing with C++ code generation of VTTs (vtable tables). +// +//===----------------------------------------------------------------------===// + +#include "CodeGenModule.h" +#include "clang/AST/RecordLayout.h" +using namespace clang; +using namespace CodeGen; + +#define D1(x) + +namespace { +class VTTBuilder { + /// Inits - The list of values built for the VTT. + std::vector<llvm::Constant *> &Inits; + /// Class - The most derived class that this vtable is being built for. + const CXXRecordDecl *Class; + CodeGenModule &CGM; // Per-module state. + llvm::SmallSet<const CXXRecordDecl *, 32> SeenVBase; + /// BLayout - Layout for the most derived class that this vtable is being + /// built for. + const ASTRecordLayout &BLayout; + CGVtableInfo::AddrMap_t &AddressPoints; + // vtbl - A pointer to the vtable for Class. + llvm::Constant *ClassVtbl; + llvm::LLVMContext &VMContext; + + /// SeenVBasesInSecondary - The seen virtual bases when building the + /// secondary virtual pointers. + llvm::SmallPtrSet<const CXXRecordDecl *, 32> SeenVBasesInSecondary; + + llvm::DenseMap<const CXXRecordDecl *, uint64_t> SubVTTIndicies; + + bool GenerateDefinition; + + llvm::DenseMap<BaseSubobject, llvm::Constant *> CtorVtables; + llvm::DenseMap<std::pair<const CXXRecordDecl *, BaseSubobject>, uint64_t> + CtorVtableAddressPoints; + + llvm::Constant *getCtorVtable(const BaseSubobject &Base) { + if (!GenerateDefinition) + return 0; + + llvm::Constant *&CtorVtable = CtorVtables[Base]; + if (!CtorVtable) { + // Build the vtable. + CGVtableInfo::CtorVtableInfo Info + = CGM.getVtableInfo().getCtorVtable(Class, Base); + + CtorVtable = Info.Vtable; + + // Add the address points for this base. + for (CGVtableInfo::AddressPointsMapTy::const_iterator I = + Info.AddressPoints.begin(), E = Info.AddressPoints.end(); + I != E; ++I) { + uint64_t &AddressPoint = + CtorVtableAddressPoints[std::make_pair(Base.getBase(), I->first)]; + + // Check if we already have the address points for this base. + if (AddressPoint) + break; + + // Otherwise, insert it. + AddressPoint = I->second; + } + } + + return CtorVtable; + } + + + /// BuildVtablePtr - Build up a referene to the given secondary vtable + llvm::Constant *BuildVtablePtr(llvm::Constant *Vtable, + const CXXRecordDecl *VtableClass, + const CXXRecordDecl *RD, + uint64_t Offset) { + if (!GenerateDefinition) + return 0; + + uint64_t AddressPoint; + + if (VtableClass != Class) { + // We have a ctor vtable, look for the address point in the ctor vtable + // address points. + AddressPoint = + CtorVtableAddressPoints[std::make_pair(VtableClass, + BaseSubobject(RD, Offset))]; + } else { + AddressPoint = + (*AddressPoints[VtableClass])[std::make_pair(RD, Offset)]; + } + + // FIXME: We can never have 0 address point. Do this for now so gepping + // retains the same structure. Later we'll just assert. + if (AddressPoint == 0) + AddressPoint = 1; + D1(printf("XXX address point for %s in %s layout %s at offset %d was %d\n", + RD->getNameAsCString(), VtblClass->getNameAsCString(), + Class->getNameAsCString(), (int)Offset, (int)AddressPoint)); + + llvm::Value *Idxs[] = { + llvm::ConstantInt::get(llvm::Type::getInt64Ty(VMContext), 0), + llvm::ConstantInt::get(llvm::Type::getInt64Ty(VMContext), AddressPoint) + }; + + llvm::Constant *Init = + llvm::ConstantExpr::getInBoundsGetElementPtr(Vtable, Idxs, 2); + + const llvm::Type *Int8PtrTy = llvm::Type::getInt8PtrTy(VMContext); + return llvm::ConstantExpr::getBitCast(Init, Int8PtrTy); + } + + /// Secondary - Add the secondary vtable pointers to Inits. Offset is the + /// current offset in bits to the object we're working on. + void Secondary(const CXXRecordDecl *RD, llvm::Constant *vtbl, + const CXXRecordDecl *VtblClass, uint64_t Offset=0, + bool MorallyVirtual=false) { + if (RD->getNumVBases() == 0 && ! MorallyVirtual) + return; + + for (CXXRecordDecl::base_class_const_iterator i = RD->bases_begin(), + e = RD->bases_end(); i != e; ++i) { + const CXXRecordDecl *Base = + cast<CXXRecordDecl>(i->getType()->getAs<RecordType>()->getDecl()); + + // We only want to visit each virtual base once. + if (i->isVirtual() && SeenVBasesInSecondary.count(Base)) + continue; + + // Itanium C++ ABI 2.6.2: + // Secondary virtual pointers are present for all bases with either + // virtual bases or virtual function declarations overridden along a + // virtual path. + // + // If the base class is not dynamic, we don't want to add it, nor any + // of its base classes. + if (!Base->isDynamicClass()) + continue; + + const ASTRecordLayout &Layout = CGM.getContext().getASTRecordLayout(RD); + const CXXRecordDecl *PrimaryBase = Layout.getPrimaryBase(); + const bool PrimaryBaseWasVirtual = Layout.getPrimaryBaseWasVirtual(); + bool NonVirtualPrimaryBase; + NonVirtualPrimaryBase = !PrimaryBaseWasVirtual && Base == PrimaryBase; + bool BaseMorallyVirtual = MorallyVirtual | i->isVirtual(); + uint64_t BaseOffset; + if (!i->isVirtual()) { + const ASTRecordLayout &Layout = CGM.getContext().getASTRecordLayout(RD); + BaseOffset = Offset + Layout.getBaseClassOffset(Base); + } else + BaseOffset = BLayout.getVBaseClassOffset(Base); + llvm::Constant *subvtbl = vtbl; + const CXXRecordDecl *subVtblClass = VtblClass; + if ((Base->getNumVBases() || BaseMorallyVirtual) + && !NonVirtualPrimaryBase) { + llvm::Constant *init; + if (BaseMorallyVirtual || VtblClass == Class) + init = BuildVtablePtr(vtbl, VtblClass, Base, BaseOffset); + else { + init = getCtorVtable(BaseSubobject(Base, BaseOffset)); + + subvtbl = init; + subVtblClass = Base; + + init = BuildVtablePtr(init, Class, Base, BaseOffset); + } + + Inits.push_back(init); + } + + if (i->isVirtual()) + SeenVBasesInSecondary.insert(Base); + + Secondary(Base, subvtbl, subVtblClass, BaseOffset, BaseMorallyVirtual); + } + } + + /// BuiltVTT - Add the VTT to Inits. Offset is the offset in bits to the + /// currnet object we're working on. + void BuildVTT(const CXXRecordDecl *RD, uint64_t Offset, bool MorallyVirtual) { + // Itanium C++ ABI 2.6.2: + // An array of virtual table addresses, called the VTT, is declared for + // each class type that has indirect or direct virtual base classes. + if (RD->getNumVBases() == 0) + return; + + // Remember the sub-VTT index. + SubVTTIndicies[RD] = Inits.size(); + + llvm::Constant *Vtable; + const CXXRecordDecl *VtableClass; + + // First comes the primary virtual table pointer... + if (MorallyVirtual) { + Vtable = ClassVtbl; + VtableClass = Class; + } else { + Vtable = getCtorVtable(BaseSubobject(RD, Offset)); + VtableClass = RD; + } + + llvm::Constant *Init = BuildVtablePtr(Vtable, VtableClass, RD, Offset); + Inits.push_back(Init); + + // then the secondary VTTs.... + SecondaryVTTs(RD, Offset, MorallyVirtual); + + // Make sure to clear the set of seen virtual bases. + SeenVBasesInSecondary.clear(); + + // and last the secondary vtable pointers. + Secondary(RD, Vtable, VtableClass, Offset, MorallyVirtual); + } + + /// SecondaryVTTs - Add the secondary VTTs to Inits. The secondary VTTs are + /// built from each direct non-virtual proper base that requires a VTT in + /// declaration order. + void SecondaryVTTs(const CXXRecordDecl *RD, uint64_t Offset=0, + bool MorallyVirtual=false) { + for (CXXRecordDecl::base_class_const_iterator i = RD->bases_begin(), + e = RD->bases_end(); i != e; ++i) { + const CXXRecordDecl *Base = + cast<CXXRecordDecl>(i->getType()->getAs<RecordType>()->getDecl()); + if (i->isVirtual()) + continue; + const ASTRecordLayout &Layout = CGM.getContext().getASTRecordLayout(RD); + uint64_t BaseOffset = Offset + Layout.getBaseClassOffset(Base); + + BuildVTT(Base, BaseOffset, MorallyVirtual); + } + } + + /// VirtualVTTs - Add the VTT for each proper virtual base in inheritance + /// graph preorder. + void VirtualVTTs(const CXXRecordDecl *RD) { + for (CXXRecordDecl::base_class_const_iterator i = RD->bases_begin(), + e = RD->bases_end(); i != e; ++i) { + const CXXRecordDecl *Base = + cast<CXXRecordDecl>(i->getType()->getAs<RecordType>()->getDecl()); + if (i->isVirtual() && !SeenVBase.count(Base)) { + SeenVBase.insert(Base); + uint64_t BaseOffset = BLayout.getVBaseClassOffset(Base); + BuildVTT(Base, BaseOffset, false); + } + VirtualVTTs(Base); + } + } + +public: + VTTBuilder(std::vector<llvm::Constant *> &inits, const CXXRecordDecl *c, + CodeGenModule &cgm, bool GenerateDefinition) + : Inits(inits), Class(c), CGM(cgm), + BLayout(cgm.getContext().getASTRecordLayout(c)), + AddressPoints(*cgm.getVtableInfo().AddressPoints[c]), + VMContext(cgm.getModule().getContext()), + GenerateDefinition(GenerateDefinition) { + + // First comes the primary virtual table pointer for the complete class... + ClassVtbl = GenerateDefinition ? CGM.getVtableInfo().getVtable(Class) : 0; + + llvm::Constant *Init = BuildVtablePtr(ClassVtbl, Class, Class, 0); + Inits.push_back(Init); + + // then the secondary VTTs... + SecondaryVTTs(Class); + + // Make sure to clear the set of seen virtual bases. + SeenVBasesInSecondary.clear(); + + // then the secondary vtable pointers... + Secondary(Class, ClassVtbl, Class); + + // and last, the virtual VTTs. + VirtualVTTs(Class); + } + + llvm::DenseMap<const CXXRecordDecl *, uint64_t> &getSubVTTIndicies() { + return SubVTTIndicies; + } +}; +} + +llvm::GlobalVariable * +CGVtableInfo::GenerateVTT(llvm::GlobalVariable::LinkageTypes Linkage, + bool GenerateDefinition, + const CXXRecordDecl *RD) { + // Only classes that have virtual bases need a VTT. + if (RD->getNumVBases() == 0) + return 0; + + llvm::SmallString<256> OutName; + CGM.getMangleContext().mangleCXXVTT(RD, OutName); + llvm::StringRef Name = OutName.str(); + + D1(printf("vtt %s\n", RD->getNameAsCString())); + + llvm::GlobalVariable *GV = CGM.getModule().getGlobalVariable(Name); + if (GV == 0 || GV->isDeclaration()) { + const llvm::Type *Int8PtrTy = + llvm::Type::getInt8PtrTy(CGM.getLLVMContext()); + + std::vector<llvm::Constant *> inits; + VTTBuilder b(inits, RD, CGM, GenerateDefinition); + + const llvm::ArrayType *Type = llvm::ArrayType::get(Int8PtrTy, inits.size()); + llvm::Constant *Init = 0; + if (GenerateDefinition) + Init = llvm::ConstantArray::get(Type, inits); + + llvm::GlobalVariable *OldGV = GV; + GV = new llvm::GlobalVariable(CGM.getModule(), Type, /*isConstant=*/true, + Linkage, Init, Name); + CGM.setGlobalVisibility(GV, RD); + + if (OldGV) { + GV->takeName(OldGV); + llvm::Constant *NewPtr = + llvm::ConstantExpr::getBitCast(GV, OldGV->getType()); + OldGV->replaceAllUsesWith(NewPtr); + OldGV->eraseFromParent(); + } + } + + return GV; +} + +CGVtableInfo::CtorVtableInfo +CGVtableInfo::getCtorVtable(const CXXRecordDecl *RD, + const BaseSubobject &Base) { + CtorVtableInfo Info; + + Info.Vtable = GenerateVtable(llvm::GlobalValue::InternalLinkage, + /*GenerateDefinition=*/true, + RD, Base.getBase(), Base.getBaseOffset(), + Info.AddressPoints); + return Info; +} + +llvm::GlobalVariable *CGVtableInfo::getVTT(const CXXRecordDecl *RD) { + return GenerateVTT(llvm::GlobalValue::ExternalLinkage, + /*GenerateDefinition=*/false, RD); + +} + + +bool CGVtableInfo::needsVTTParameter(GlobalDecl GD) { + const CXXMethodDecl *MD = cast<CXXMethodDecl>(GD.getDecl()); + + // We don't have any virtual bases, just return early. + if (!MD->getParent()->getNumVBases()) + return false; + + // Check if we have a base constructor. + if (isa<CXXConstructorDecl>(MD) && GD.getCtorType() == Ctor_Base) + return true; + + // Check if we have a base destructor. + if (isa<CXXDestructorDecl>(MD) && GD.getDtorType() == Dtor_Base) + return true; + + return false; +} + +uint64_t CGVtableInfo::getSubVTTIndex(const CXXRecordDecl *RD, + const CXXRecordDecl *Base) { + ClassPairTy ClassPair(RD, Base); + + SubVTTIndiciesTy::iterator I = + SubVTTIndicies.find(ClassPair); + if (I != SubVTTIndicies.end()) + return I->second; + + std::vector<llvm::Constant *> inits; + VTTBuilder Builder(inits, RD, CGM, /*GenerateDefinition=*/false); + + for (llvm::DenseMap<const CXXRecordDecl *, uint64_t>::iterator I = + Builder.getSubVTTIndicies().begin(), + E = Builder.getSubVTTIndicies().end(); I != E; ++I) { + // Insert all indices. + ClassPairTy ClassPair(RD, I->first); + + SubVTTIndicies.insert(std::make_pair(ClassPair, I->second)); + } + + I = SubVTTIndicies.find(ClassPair); + assert(I != SubVTTIndicies.end() && "Did not find index!"); + + return I->second; +} diff --git a/lib/CodeGen/CGVtable.cpp b/lib/CodeGen/CGVtable.cpp index ae900d6..e5abfc6 100644 --- a/lib/CodeGen/CGVtable.cpp +++ b/lib/CodeGen/CGVtable.cpp @@ -232,8 +232,8 @@ public: return llvm::ConstantExpr::getBitCast(m, Ptr8Ty); } -#define D1(x) -//#define D1(X) do { if (getenv("DEBUG")) { X; } } while (0) +//#define D1(x) +#define D1(X) do { if (getenv("DEBUG")) { X; } } while (0) void GenerateVBaseOffsets(const CXXRecordDecl *RD, uint64_t Offset, bool updateVBIndex, Index_t current_vbindex) { @@ -254,7 +254,7 @@ public: D1(printf(" vbase for %s at %d delta %d most derived %s\n", Base->getNameAsCString(), (int)-VCalls.size()-3, (int)BaseOffset, - Class->getNameAsCString())); + MostDerivedClass->getNameAsCString())); } // We also record offsets for non-virtual bases to closest enclosing // virtual base. We do this so that we don't have to search @@ -376,13 +376,14 @@ public: CurrentVBaseOffset)) return; + D1(printf(" vfn for %s at %d\n", + dyn_cast<CXXMethodDecl>(GD.getDecl())->getNameAsCString(), + (int)Methods.size())); + // We didn't find an entry in the vtable that we could use, add a new // entry. Methods.AddMethod(GD); - D1(printf(" vfn for %s at %d\n", MD->getNameAsString().c_str(), - (int)Index[GD])); - VCallOffset[GD] = Offset/8; if (MorallyVirtual) { Index_t &idx = VCall[GD]; @@ -392,7 +393,8 @@ public: idx = VCalls.size()+1; VCalls.push_back(0); D1(printf(" vcall for %s at %d with delta %d\n", - MD->getNameAsString().c_str(), (int)-VCalls.size()-3, 0)); + dyn_cast<CXXMethodDecl>(GD.getDecl())->getNameAsCString(), + (int)-VCalls.size()-3, 0)); } } } @@ -429,12 +431,11 @@ public: continue; const CXXRecordDecl *Base = cast<CXXRecordDecl>(i->getType()->getAs<RecordType>()->getDecl()); - if (Base != PrimaryBase || PrimaryBaseWasVirtual) { - uint64_t o = Offset + Layout.getBaseClassOffset(Base); - StartNewTable(); - GenerateVtableForBase(Base, o, MorallyVirtual, false, - CurrentVBaseOffset, Path); - } + uint64_t o = Offset + Layout.getBaseClassOffset(Base); + StartNewTable(); + GenerateVtableForBase(Base, o, MorallyVirtual, false, + true, Base == PrimaryBase && !PrimaryBaseWasVirtual, + CurrentVBaseOffset, Path); } Path->pop_back(); } @@ -463,7 +464,7 @@ public: void AddAddressPoints(const CXXRecordDecl *RD, uint64_t Offset, Index_t AddressPoint) { D1(printf("XXX address point for %s in %s layout %s at offset %d is %d\n", - RD->getNameAsCString(), Class->getNameAsCString(), + RD->getNameAsCString(), MostDerivedClass->getNameAsCString(), LayoutClass->getNameAsCString(), (int)Offset, (int)AddressPoint)); subAddressPoints[std::make_pair(RD, Offset)] = AddressPoint; AddressPoints[BaseSubobject(RD, Offset)] = AddressPoint; @@ -480,7 +481,7 @@ public: BLayout.getVBaseClassOffset(RD) != Offset) break; D1(printf("XXX address point for %s in %s layout %s at offset %d is %d\n", - RD->getNameAsCString(), Class->getNameAsCString(), + RD->getNameAsCString(), MostDerivedClass->getNameAsCString(), LayoutClass->getNameAsCString(), (int)Offset, (int)AddressPoint)); subAddressPoints[std::make_pair(RD, Offset)] = AddressPoint; AddressPoints[BaseSubobject(RD, Offset)] = AddressPoint; @@ -491,6 +492,7 @@ public: void FinishGenerateVtable(const CXXRecordDecl *RD, const ASTRecordLayout &Layout, const CXXRecordDecl *PrimaryBase, + bool ForNPNVBases, bool WasPrimaryBase, bool PrimaryBaseWasVirtual, bool MorallyVirtual, int64_t Offset, bool ForVirtualBase, int64_t CurrentVBaseOffset, @@ -503,23 +505,27 @@ public: StartNewTable(); extra = 0; - bool DeferVCalls = MorallyVirtual || ForVirtualBase; - int VCallInsertionPoint = VtableComponents.size(); - if (!DeferVCalls) { - insertVCalls(VCallInsertionPoint); - } else - // FIXME: just for extra, or for all uses of VCalls.size post this? - extra = -VCalls.size(); + Index_t AddressPoint = 0; + int VCallInsertionPoint = 0; + if (!ForNPNVBases || !WasPrimaryBase) { + bool DeferVCalls = MorallyVirtual || ForVirtualBase; + VCallInsertionPoint = VtableComponents.size(); + if (!DeferVCalls) { + insertVCalls(VCallInsertionPoint); + } else + // FIXME: just for extra, or for all uses of VCalls.size post this? + extra = -VCalls.size(); - // Add the offset to top. - VtableComponents.push_back(BuildVtable ? wrap(-((Offset-LayoutOffset)/8)) : 0); + // Add the offset to top. + VtableComponents.push_back(BuildVtable ? wrap(-((Offset-LayoutOffset)/8)) : 0); - // Add the RTTI information. - VtableComponents.push_back(rtti); + // Add the RTTI information. + VtableComponents.push_back(rtti); - Index_t AddressPoint = VtableComponents.size(); + AddressPoint = VtableComponents.size(); - AppendMethodsToVtable(); + AppendMethodsToVtable(); + } // and then the non-virtual bases. NonVirtualBases(RD, Layout, PrimaryBase, PrimaryBaseWasVirtual, @@ -537,7 +543,8 @@ public: insertVCalls(VCallInsertionPoint); } - AddAddressPoints(RD, Offset, AddressPoint); + if (!ForNPNVBases || !WasPrimaryBase) + AddAddressPoints(RD, Offset, AddressPoint); if (alloc) { delete Path; @@ -557,13 +564,13 @@ public: // vtables are composed from the chain of primaries. if (PrimaryBase && !PrimaryBaseWasVirtual) { D1(printf(" doing primaries for %s most derived %s\n", - RD->getNameAsCString(), Class->getNameAsCString())); + RD->getNameAsCString(), MostDerivedClass->getNameAsCString())); Primaries(PrimaryBase, PrimaryBaseWasVirtual|MorallyVirtual, Offset, updateVBIndex, current_vbindex, CurrentVBaseOffset); } D1(printf(" doing vcall entries for %s most derived %s\n", - RD->getNameAsCString(), Class->getNameAsCString())); + RD->getNameAsCString(), MostDerivedClass->getNameAsCString())); // And add the virtuals for the class to the primary vtable. AddMethods(RD, MorallyVirtual, Offset, CurrentVBaseOffset); @@ -589,7 +596,7 @@ public: } D1(printf(" doing primaries for %s most derived %s\n", - RD->getNameAsCString(), Class->getNameAsCString())); + RD->getNameAsCString(), MostDerivedClass->getNameAsCString())); VBPrimaries(PrimaryBase, PrimaryBaseWasVirtual|MorallyVirtual, Offset, updateVBIndex, current_vbindex, PrimaryBaseWasVirtual, @@ -597,7 +604,7 @@ public: } D1(printf(" doing vbase entries for %s most derived %s\n", - RD->getNameAsCString(), Class->getNameAsCString())); + RD->getNameAsCString(), MostDerivedClass->getNameAsCString())); GenerateVBaseOffsets(RD, Offset, updateVBIndex, current_vbindex); if (RDisVirtualBase || bottom) { @@ -609,6 +616,8 @@ public: void GenerateVtableForBase(const CXXRecordDecl *RD, int64_t Offset = 0, bool MorallyVirtual = false, bool ForVirtualBase = false, + bool ForNPNVBases = false, + bool WasPrimaryBase = true, int CurrentVBaseOffset = 0, Path_t *Path = 0) { if (!RD->isDynamicClass()) @@ -626,20 +635,22 @@ public: extra = 0; D1(printf("building entries for base %s most derived %s\n", - RD->getNameAsCString(), Class->getNameAsCString())); + RD->getNameAsCString(), MostDerivedClass->getNameAsCString())); if (ForVirtualBase) extra = VCalls.size(); - VBPrimaries(RD, MorallyVirtual, Offset, !ForVirtualBase, 0, ForVirtualBase, - CurrentVBaseOffset, true); + if (!ForNPNVBases || !WasPrimaryBase) { + VBPrimaries(RD, MorallyVirtual, Offset, !ForVirtualBase, 0, + ForVirtualBase, CurrentVBaseOffset, true); - if (Path) - OverrideMethods(Path, MorallyVirtual, Offset, CurrentVBaseOffset); + if (Path) + OverrideMethods(Path, MorallyVirtual, Offset, CurrentVBaseOffset); + } - FinishGenerateVtable(RD, Layout, PrimaryBase, PrimaryBaseWasVirtual, - MorallyVirtual, Offset, ForVirtualBase, - CurrentVBaseOffset, Path); + FinishGenerateVtable(RD, Layout, PrimaryBase, ForNPNVBases, WasPrimaryBase, + PrimaryBaseWasVirtual, MorallyVirtual, Offset, + ForVirtualBase, CurrentVBaseOffset, Path); } void GenerateVtableForVBases(const CXXRecordDecl *RD, @@ -665,9 +676,9 @@ public: int64_t BaseOffset = BLayout.getVBaseClassOffset(Base); int64_t CurrentVBaseOffset = BaseOffset; D1(printf("vtable %s virtual base %s\n", - Class->getNameAsCString(), Base->getNameAsCString())); - GenerateVtableForBase(Base, BaseOffset, true, true, CurrentVBaseOffset, - Path); + MostDerivedClass->getNameAsCString(), Base->getNameAsCString())); + GenerateVtableForBase(Base, BaseOffset, true, true, false, + true, CurrentVBaseOffset, Path); } int64_t BaseOffset; if (i->isVirtual()) @@ -823,14 +834,14 @@ bool VtableBuilder::OverrideMethod(GlobalDecl GD, bool MorallyVirtual, VCalls.push_back(0); D1(printf(" vcall for %s at %d with delta %d most derived %s\n", MD->getNameAsString().c_str(), (int)-idx-3, - (int)VCalls[idx-1], Class->getNameAsCString())); + (int)VCalls[idx-1], MostDerivedClass->getNameAsCString())); } else { NonVirtualOffset[GD] = NonVirtualOffset[OGD]; VCallOffset[GD] = VCallOffset[OGD]; VCalls[idx-1] = -VCallOffset[OGD] + OverrideOffset/8; D1(printf(" vcall patch for %s at %d with delta %d most derived %s\n", MD->getNameAsString().c_str(), (int)-idx-3, - (int)VCalls[idx-1], Class->getNameAsCString())); + (int)VCalls[idx-1], MostDerivedClass->getNameAsCString())); } int64_t NonVirtualAdjustment = NonVirtualOffset[GD]; int64_t VirtualAdjustment = @@ -1205,284 +1216,6 @@ CGVtableInfo::GenerateVtable(llvm::GlobalVariable::LinkageTypes Linkage, return GV; } -namespace { -class VTTBuilder { - /// Inits - The list of values built for the VTT. - std::vector<llvm::Constant *> &Inits; - /// Class - The most derived class that this vtable is being built for. - const CXXRecordDecl *Class; - CodeGenModule &CGM; // Per-module state. - llvm::SmallSet<const CXXRecordDecl *, 32> SeenVBase; - /// BLayout - Layout for the most derived class that this vtable is being - /// built for. - const ASTRecordLayout &BLayout; - CGVtableInfo::AddrMap_t &AddressPoints; - // vtbl - A pointer to the vtable for Class. - llvm::Constant *ClassVtbl; - llvm::LLVMContext &VMContext; - - llvm::DenseMap<const CXXRecordDecl *, uint64_t> SubVTTIndicies; - - bool GenerateDefinition; - - llvm::DenseMap<BaseSubobject, llvm::Constant *> CtorVtables; - llvm::DenseMap<std::pair<const CXXRecordDecl *, BaseSubobject>, uint64_t> - CtorVtableAddressPoints; - - llvm::Constant *getCtorVtable(const BaseSubobject &Base) { - if (!GenerateDefinition) - return 0; - - llvm::Constant *&CtorVtable = CtorVtables[Base]; - if (!CtorVtable) { - // Build the vtable. - CGVtableInfo::CtorVtableInfo Info - = CGM.getVtableInfo().getCtorVtable(Class, Base); - - CtorVtable = Info.Vtable; - - // Add the address points for this base. - for (CGVtableInfo::AddressPointsMapTy::const_iterator I = - Info.AddressPoints.begin(), E = Info.AddressPoints.end(); - I != E; ++I) { - uint64_t &AddressPoint = - CtorVtableAddressPoints[std::make_pair(Base.getBase(), I->first)]; - - // Check if we already have the address points for this base. - if (AddressPoint) - break; - - // Otherwise, insert it. - AddressPoint = I->second; - } - } - - return CtorVtable; - } - - - /// BuildVtablePtr - Build up a referene to the given secondary vtable - llvm::Constant *BuildVtablePtr(llvm::Constant *Vtable, - const CXXRecordDecl *VtableClass, - const CXXRecordDecl *RD, - uint64_t Offset) { - int64_t AddressPoint = - (*AddressPoints[VtableClass])[std::make_pair(RD, Offset)]; - - // FIXME: We can never have 0 address point. Do this for now so gepping - // retains the same structure. Later we'll just assert. - if (AddressPoint == 0) - AddressPoint = 1; - D1(printf("XXX address point for %s in %s layout %s at offset %d was %d\n", - RD->getNameAsCString(), VtblClass->getNameAsCString(), - Class->getNameAsCString(), (int)Offset, (int)AddressPoint)); - - llvm::Value *Idxs[] = { - llvm::ConstantInt::get(llvm::Type::getInt64Ty(VMContext), 0), - llvm::ConstantInt::get(llvm::Type::getInt64Ty(VMContext), AddressPoint) - }; - - llvm::Constant *Init = - llvm::ConstantExpr::getInBoundsGetElementPtr(Vtable, Idxs, 2); - - const llvm::Type *Int8PtrTy = llvm::Type::getInt8PtrTy(VMContext); - return llvm::ConstantExpr::getBitCast(Init, Int8PtrTy); - } - - /// Secondary - Add the secondary vtable pointers to Inits. Offset is the - /// current offset in bits to the object we're working on. - void Secondary(const CXXRecordDecl *RD, llvm::Constant *vtbl, - const CXXRecordDecl *VtblClass, uint64_t Offset=0, - bool MorallyVirtual=false) { - if (RD->getNumVBases() == 0 && ! MorallyVirtual) - return; - - for (CXXRecordDecl::base_class_const_iterator i = RD->bases_begin(), - e = RD->bases_end(); i != e; ++i) { - const CXXRecordDecl *Base = - cast<CXXRecordDecl>(i->getType()->getAs<RecordType>()->getDecl()); - const ASTRecordLayout &Layout = CGM.getContext().getASTRecordLayout(RD); - const CXXRecordDecl *PrimaryBase = Layout.getPrimaryBase(); - const bool PrimaryBaseWasVirtual = Layout.getPrimaryBaseWasVirtual(); - bool NonVirtualPrimaryBase; - NonVirtualPrimaryBase = !PrimaryBaseWasVirtual && Base == PrimaryBase; - bool BaseMorallyVirtual = MorallyVirtual | i->isVirtual(); - uint64_t BaseOffset; - if (!i->isVirtual()) { - const ASTRecordLayout &Layout = CGM.getContext().getASTRecordLayout(RD); - BaseOffset = Offset + Layout.getBaseClassOffset(Base); - } else - BaseOffset = BLayout.getVBaseClassOffset(Base); - llvm::Constant *subvtbl = vtbl; - const CXXRecordDecl *subVtblClass = VtblClass; - if ((Base->getNumVBases() || BaseMorallyVirtual) - && !NonVirtualPrimaryBase) { - // FIXME: Slightly too many of these for __ZTT8test8_B2 - llvm::Constant *init; - if (BaseMorallyVirtual) - init = GenerateDefinition ? - BuildVtablePtr(vtbl, VtblClass, RD, Offset) : 0; - else { - init = GenerateDefinition ? - getCtorVtable(BaseSubobject(Base, BaseOffset)) : 0; - - subvtbl = init; - subVtblClass = Base; - - init = GenerateDefinition ? - BuildVtablePtr(init, Class, Base, BaseOffset) : 0; - } - Inits.push_back(init); - } - Secondary(Base, subvtbl, subVtblClass, BaseOffset, BaseMorallyVirtual); - } - } - - /// BuiltVTT - Add the VTT to Inits. Offset is the offset in bits to the - /// currnet object we're working on. - void BuildVTT(const CXXRecordDecl *RD, uint64_t Offset, bool MorallyVirtual) { - if (RD->getNumVBases() == 0 && !MorallyVirtual) - return; - - llvm::Constant *Vtable; - const CXXRecordDecl *VtableClass; - - // First comes the primary virtual table pointer... - if (MorallyVirtual) { - Vtable = GenerateDefinition ? ClassVtbl : 0; - VtableClass = Class; - } else { - Vtable = GenerateDefinition ? - getCtorVtable(BaseSubobject(RD, Offset)) : 0; - VtableClass = RD; - } - - llvm::Constant *Init = GenerateDefinition ? - BuildVtablePtr(Vtable, VtableClass, RD, Offset) : 0; - Inits.push_back(Init); - - // then the secondary VTTs.... - SecondaryVTTs(RD, Offset, MorallyVirtual); - - // and last the secondary vtable pointers. - Secondary(RD, Vtable, VtableClass, Offset, MorallyVirtual); - } - - /// SecondaryVTTs - Add the secondary VTTs to Inits. The secondary VTTs are - /// built from each direct non-virtual proper base that requires a VTT in - /// declaration order. - void SecondaryVTTs(const CXXRecordDecl *RD, uint64_t Offset=0, - bool MorallyVirtual=false) { - for (CXXRecordDecl::base_class_const_iterator i = RD->bases_begin(), - e = RD->bases_end(); i != e; ++i) { - const CXXRecordDecl *Base = - cast<CXXRecordDecl>(i->getType()->getAs<RecordType>()->getDecl()); - if (i->isVirtual()) - continue; - const ASTRecordLayout &Layout = CGM.getContext().getASTRecordLayout(RD); - uint64_t BaseOffset = Offset + Layout.getBaseClassOffset(Base); - - // Remember the sub-VTT index. - SubVTTIndicies[Base] = Inits.size(); - - BuildVTT(Base, BaseOffset, MorallyVirtual); - } - } - - /// VirtualVTTs - Add the VTT for each proper virtual base in inheritance - /// graph preorder. - void VirtualVTTs(const CXXRecordDecl *RD) { - for (CXXRecordDecl::base_class_const_iterator i = RD->bases_begin(), - e = RD->bases_end(); i != e; ++i) { - const CXXRecordDecl *Base = - cast<CXXRecordDecl>(i->getType()->getAs<RecordType>()->getDecl()); - if (i->isVirtual() && !SeenVBase.count(Base)) { - // Remember the sub-VTT index. - SubVTTIndicies[Base] = Inits.size(); - - SeenVBase.insert(Base); - uint64_t BaseOffset = BLayout.getVBaseClassOffset(Base); - BuildVTT(Base, BaseOffset, true); - } - VirtualVTTs(Base); - } - } - -public: - VTTBuilder(std::vector<llvm::Constant *> &inits, const CXXRecordDecl *c, - CodeGenModule &cgm, bool GenerateDefinition) - : Inits(inits), Class(c), CGM(cgm), - BLayout(cgm.getContext().getASTRecordLayout(c)), - AddressPoints(*cgm.getVtableInfo().AddressPoints[c]), - VMContext(cgm.getModule().getContext()), - GenerateDefinition(GenerateDefinition) { - - // First comes the primary virtual table pointer for the complete class... - ClassVtbl = CGM.getVtableInfo().getVtable(Class); - llvm::Constant *Init = GenerateDefinition ? - BuildVtablePtr(ClassVtbl, Class, Class, 0) : 0; - Inits.push_back(Init); - - // then the secondary VTTs... - SecondaryVTTs(Class); - - // then the secondary vtable pointers... - Secondary(Class, ClassVtbl, Class); - - // and last, the virtual VTTs. - VirtualVTTs(Class); - } - - llvm::DenseMap<const CXXRecordDecl *, uint64_t> &getSubVTTIndicies() { - return SubVTTIndicies; - } -}; -} - -llvm::GlobalVariable * -CGVtableInfo::GenerateVTT(llvm::GlobalVariable::LinkageTypes Linkage, - bool GenerateDefinition, - const CXXRecordDecl *RD) { - // Only classes that have virtual bases need a VTT. - if (RD->getNumVBases() == 0) - return 0; - - llvm::SmallString<256> OutName; - CGM.getMangleContext().mangleCXXVTT(RD, OutName); - llvm::StringRef Name = OutName.str(); - - D1(printf("vtt %s\n", RD->getNameAsCString())); - - llvm::GlobalVariable *GV = CGM.getModule().getGlobalVariable(Name); - if (GV == 0 || GV->isDeclaration()) { - const llvm::Type *Int8PtrTy = - llvm::Type::getInt8PtrTy(CGM.getLLVMContext()); - - std::vector<llvm::Constant *> inits; - VTTBuilder b(inits, RD, CGM, GenerateDefinition); - - const llvm::ArrayType *Type = llvm::ArrayType::get(Int8PtrTy, inits.size()); - llvm::Constant *Init = 0; - if (GenerateDefinition) - Init = llvm::ConstantArray::get(Type, inits); - - llvm::GlobalVariable *OldGV = GV; - GV = new llvm::GlobalVariable(CGM.getModule(), Type, /*isConstant=*/true, - Linkage, Init, Name); - CGM.setGlobalVisibility(GV, RD); - - if (OldGV) { - GV->takeName(OldGV); - llvm::Constant *NewPtr = - llvm::ConstantExpr::getBitCast(GV, OldGV->getType()); - OldGV->replaceAllUsesWith(NewPtr); - OldGV->eraseFromParent(); - } - } - - return GV; -} - void CGVtableInfo::GenerateClassData(llvm::GlobalVariable::LinkageTypes Linkage, const CXXRecordDecl *RD) { llvm::GlobalVariable *&Vtable = Vtables[RD]; @@ -1510,25 +1243,6 @@ llvm::GlobalVariable *CGVtableInfo::getVtable(const CXXRecordDecl *RD) { return Vtable; } -CGVtableInfo::CtorVtableInfo -CGVtableInfo::getCtorVtable(const CXXRecordDecl *RD, - const BaseSubobject &Base) { - CtorVtableInfo Info; - - Info.Vtable = GenerateVtable(llvm::GlobalValue::InternalLinkage, - /*GenerateDefinition=*/true, - RD, Base.getBase(), Base.getBaseOffset(), - Info.AddressPoints); - return Info; -} - -llvm::GlobalVariable *CGVtableInfo::getVTT(const CXXRecordDecl *RD) { - return GenerateVTT(llvm::GlobalValue::ExternalLinkage, - /*GenerateDefinition=*/false, RD); - -} - - void CGVtableInfo::MaybeEmitVtable(GlobalDecl GD) { const CXXMethodDecl *MD = cast<CXXMethodDecl>(GD.getDecl()); const CXXRecordDecl *RD = MD->getParent(); @@ -1562,47 +1276,3 @@ void CGVtableInfo::MaybeEmitVtable(GlobalDecl GD) { } } -bool CGVtableInfo::needsVTTParameter(GlobalDecl GD) { - const CXXMethodDecl *MD = cast<CXXMethodDecl>(GD.getDecl()); - - // We don't have any virtual bases, just return early. - if (!MD->getParent()->getNumVBases()) - return false; - - // Check if we have a base constructor. - if (isa<CXXConstructorDecl>(MD) && GD.getCtorType() == Ctor_Base) - return true; - - // Check if we have a base destructor. - if (isa<CXXDestructorDecl>(MD) && GD.getDtorType() == Dtor_Base) - return true; - - return false; -} - -uint64_t CGVtableInfo::getSubVTTIndex(const CXXRecordDecl *RD, - const CXXRecordDecl *Base) { - ClassPairTy ClassPair(RD, Base); - - SubVTTIndiciesTy::iterator I = - SubVTTIndicies.find(ClassPair); - if (I != SubVTTIndicies.end()) - return I->second; - - std::vector<llvm::Constant *> inits; - VTTBuilder Builder(inits, RD, CGM, /*GenerateDefinition=*/false); - - for (llvm::DenseMap<const CXXRecordDecl *, uint64_t>::iterator I = - Builder.getSubVTTIndicies().begin(), - E = Builder.getSubVTTIndicies().end(); I != E; ++I) { - // Insert all indices. - ClassPairTy ClassPair(RD, I->first); - - SubVTTIndicies.insert(std::make_pair(ClassPair, I->second)); - } - - I = SubVTTIndicies.find(ClassPair); - assert(I != SubVTTIndicies.end() && "Did not find index!"); - - return I->second; -} diff --git a/lib/CodeGen/CMakeLists.txt b/lib/CodeGen/CMakeLists.txt index 45469d3..e72a1d9 100644 --- a/lib/CodeGen/CMakeLists.txt +++ b/lib/CodeGen/CMakeLists.txt @@ -24,6 +24,7 @@ add_clang_library(clangCodeGen CGStmt.cpp CGTemporaries.cpp CGVtable.cpp + CGVTT.cpp CodeGenFunction.cpp CodeGenModule.cpp CodeGenTypes.cpp diff --git a/lib/CodeGen/CodeGenModule.cpp b/lib/CodeGen/CodeGenModule.cpp index 5ecc30e..cf504a7 100644 --- a/lib/CodeGen/CodeGenModule.cpp +++ b/lib/CodeGen/CodeGenModule.cpp @@ -67,6 +67,15 @@ CodeGenModule::~CodeGenModule() { delete DebugInfo; } +void CodeGenModule::createObjCRuntime() { + if (!Features.NeXTRuntime) + Runtime = CreateGNUObjCRuntime(*this); + else if (Features.ObjCNonFragileABI) + Runtime = CreateMacNonFragileABIObjCRuntime(*this); + else + Runtime = CreateMacObjCRuntime(*this); +} + void CodeGenModule::Release() { EmitDeferred(); EmitCXXGlobalInitFunc(); diff --git a/lib/CodeGen/CodeGenModule.h b/lib/CodeGen/CodeGenModule.h index c7aa7a4..81f3979 100644 --- a/lib/CodeGen/CodeGenModule.h +++ b/lib/CodeGen/CodeGenModule.h @@ -161,6 +161,9 @@ class CodeGenModule : public BlockModule { /// strings. This value has type int * but is actually an Obj-C class pointer. llvm::Constant *CFConstantStringClassRef; + /// Lazily create the Objective-C runtime + void createObjCRuntime(); + llvm::LLVMContext &VMContext; public: CodeGenModule(ASTContext &C, const CodeGenOptions &CodeGenOpts, @@ -174,7 +177,7 @@ public: /// getObjCRuntime() - Return a reference to the configured /// Objective-C runtime. CGObjCRuntime &getObjCRuntime() { - assert(Runtime && "No Objective-C runtime has been configured."); + if (!Runtime) createObjCRuntime(); return *Runtime; } diff --git a/lib/CodeGen/TargetABIInfo.cpp b/lib/CodeGen/TargetABIInfo.cpp deleted file mode 100644 index 863a297..0000000 --- a/lib/CodeGen/TargetABIInfo.cpp +++ /dev/null @@ -1,1821 +0,0 @@ -//===---- TargetABIInfo.cpp - Encapsulate target ABI details ----*- C++ -*-===// -// -// The LLVM Compiler Infrastructure -// -// This file is distributed under the University of Illinois Open Source -// License. See LICENSE.TXT for details. -// -//===----------------------------------------------------------------------===// -// -// These classes wrap the information about a call or function -// definition used to handle ABI compliancy. -// -//===----------------------------------------------------------------------===// - -#include "ABIInfo.h" -#include "CodeGenFunction.h" -#include "clang/AST/RecordLayout.h" -#include "llvm/Type.h" -#include "llvm/ADT/Triple.h" -#include "llvm/Support/raw_ostream.h" -using namespace clang; -using namespace CodeGen; - -ABIInfo::~ABIInfo() {} - -void ABIArgInfo::dump() const { - llvm::raw_ostream &OS = llvm::errs(); - OS << "(ABIArgInfo Kind="; - switch (TheKind) { - case Direct: - OS << "Direct"; - break; - case Extend: - OS << "Extend"; - break; - case Ignore: - OS << "Ignore"; - break; - case Coerce: - OS << "Coerce Type="; - getCoerceToType()->print(OS); - break; - case Indirect: - OS << "Indirect Align=" << getIndirectAlign(); - break; - case Expand: - OS << "Expand"; - break; - } - OS << ")\n"; -} - -static bool isEmptyRecord(ASTContext &Context, QualType T, bool AllowArrays); - -/// isEmptyField - Return true iff a the field is "empty", that is it -/// is an unnamed bit-field or an (array of) empty record(s). -static bool isEmptyField(ASTContext &Context, const FieldDecl *FD, - bool AllowArrays) { - if (FD->isUnnamedBitfield()) - return true; - - QualType FT = FD->getType(); - - // Constant arrays of empty records count as empty, strip them off. - if (AllowArrays) - while (const ConstantArrayType *AT = Context.getAsConstantArrayType(FT)) - FT = AT->getElementType(); - - return isEmptyRecord(Context, FT, AllowArrays); -} - -/// isEmptyRecord - Return true iff a structure contains only empty -/// fields. Note that a structure with a flexible array member is not -/// considered empty. -static bool isEmptyRecord(ASTContext &Context, QualType T, bool AllowArrays) { - const RecordType *RT = T->getAs<RecordType>(); - if (!RT) - return 0; - const RecordDecl *RD = RT->getDecl(); - if (RD->hasFlexibleArrayMember()) - return false; - for (RecordDecl::field_iterator i = RD->field_begin(), e = RD->field_end(); - i != e; ++i) - if (!isEmptyField(Context, *i, AllowArrays)) - return false; - return true; -} - -/// hasNonTrivialDestructorOrCopyConstructor - Determine if a type has either -/// a non-trivial destructor or a non-trivial copy constructor. -static bool hasNonTrivialDestructorOrCopyConstructor(const RecordType *RT) { - const CXXRecordDecl *RD = dyn_cast<CXXRecordDecl>(RT->getDecl()); - if (!RD) - return false; - - return !RD->hasTrivialDestructor() || !RD->hasTrivialCopyConstructor(); -} - -/// isRecordWithNonTrivialDestructorOrCopyConstructor - Determine if a type is -/// a record type with either a non-trivial destructor or a non-trivial copy -/// constructor. -static bool isRecordWithNonTrivialDestructorOrCopyConstructor(QualType T) { - const RecordType *RT = T->getAs<RecordType>(); - if (!RT) - return false; - - return hasNonTrivialDestructorOrCopyConstructor(RT); -} - -/// isSingleElementStruct - Determine if a structure is a "single -/// element struct", i.e. it has exactly one non-empty field or -/// exactly one field which is itself a single element -/// struct. Structures with flexible array members are never -/// considered single element structs. -/// -/// \return The field declaration for the single non-empty field, if -/// it exists. -static const Type *isSingleElementStruct(QualType T, ASTContext &Context) { - const RecordType *RT = T->getAsStructureType(); - if (!RT) - return 0; - - const RecordDecl *RD = RT->getDecl(); - if (RD->hasFlexibleArrayMember()) - return 0; - - const Type *Found = 0; - for (RecordDecl::field_iterator i = RD->field_begin(), e = RD->field_end(); - i != e; ++i) { - const FieldDecl *FD = *i; - QualType FT = FD->getType(); - - // Ignore empty fields. - if (isEmptyField(Context, FD, true)) - continue; - - // If we already found an element then this isn't a single-element - // struct. - if (Found) - return 0; - - // Treat single element arrays as the element. - while (const ConstantArrayType *AT = Context.getAsConstantArrayType(FT)) { - if (AT->getSize().getZExtValue() != 1) - break; - FT = AT->getElementType(); - } - - if (!CodeGenFunction::hasAggregateLLVMType(FT)) { - Found = FT.getTypePtr(); - } else { - Found = isSingleElementStruct(FT, Context); - if (!Found) - return 0; - } - } - - return Found; -} - -static bool is32Or64BitBasicType(QualType Ty, ASTContext &Context) { - if (!Ty->getAs<BuiltinType>() && !Ty->isAnyPointerType() && - !Ty->isAnyComplexType() && !Ty->isEnumeralType() && - !Ty->isBlockPointerType()) - return false; - - uint64_t Size = Context.getTypeSize(Ty); - return Size == 32 || Size == 64; -} - -/// canExpandIndirectArgument - Test whether an argument type which is to be -/// passed indirectly (on the stack) would have the equivalent layout if it was -/// expanded into separate arguments. If so, we prefer to do the latter to avoid -/// inhibiting optimizations. -/// -// FIXME: This predicate is missing many cases, currently it just follows -// llvm-gcc (checks that all fields are 32-bit or 64-bit primitive types). We -// should probably make this smarter, or better yet make the LLVM backend -// capable of handling it. -static bool canExpandIndirectArgument(QualType Ty, ASTContext &Context) { - // We can only expand structure types. - const RecordType *RT = Ty->getAs<RecordType>(); - if (!RT) - return false; - - // We can only expand (C) structures. - // - // FIXME: This needs to be generalized to handle classes as well. - const RecordDecl *RD = RT->getDecl(); - if (!RD->isStruct() || isa<CXXRecordDecl>(RD)) - return false; - - for (RecordDecl::field_iterator i = RD->field_begin(), e = RD->field_end(); - i != e; ++i) { - const FieldDecl *FD = *i; - - if (!is32Or64BitBasicType(FD->getType(), Context)) - return false; - - // FIXME: Reject bit-fields wholesale; there are two problems, we don't know - // how to expand them yet, and the predicate for telling if a bitfield still - // counts as "basic" is more complicated than what we were doing previously. - if (FD->isBitField()) - return false; - } - - return true; -} - -static bool typeContainsSSEVector(const RecordDecl *RD, ASTContext &Context) { - for (RecordDecl::field_iterator i = RD->field_begin(), e = RD->field_end(); - i != e; ++i) { - const FieldDecl *FD = *i; - - if (FD->getType()->isVectorType() && - Context.getTypeSize(FD->getType()) >= 128) - return true; - - if (const RecordType* RT = FD->getType()->getAs<RecordType>()) - if (typeContainsSSEVector(RT->getDecl(), Context)) - return true; - } - - return false; -} - -namespace { -/// DefaultABIInfo - The default implementation for ABI specific -/// details. This implementation provides information which results in -/// self-consistent and sensible LLVM IR generation, but does not -/// conform to any particular ABI. -class DefaultABIInfo : public ABIInfo { - ABIArgInfo classifyReturnType(QualType RetTy, - ASTContext &Context, - llvm::LLVMContext &VMContext) const; - - ABIArgInfo classifyArgumentType(QualType RetTy, - ASTContext &Context, - llvm::LLVMContext &VMContext) const; - - virtual void computeInfo(CGFunctionInfo &FI, ASTContext &Context, - llvm::LLVMContext &VMContext) const { - FI.getReturnInfo() = classifyReturnType(FI.getReturnType(), Context, - VMContext); - for (CGFunctionInfo::arg_iterator it = FI.arg_begin(), ie = FI.arg_end(); - it != ie; ++it) - it->info = classifyArgumentType(it->type, Context, VMContext); - } - - virtual llvm::Value *EmitVAArg(llvm::Value *VAListAddr, QualType Ty, - CodeGenFunction &CGF) const; -}; - -/// X86_32ABIInfo - The X86-32 ABI information. -class X86_32ABIInfo : public ABIInfo { - ASTContext &Context; - bool IsDarwinVectorABI; - bool IsSmallStructInRegABI; - - static bool isRegisterSize(unsigned Size) { - return (Size == 8 || Size == 16 || Size == 32 || Size == 64); - } - - static bool shouldReturnTypeInRegister(QualType Ty, ASTContext &Context); - - static unsigned getIndirectArgumentAlignment(QualType Ty, - ASTContext &Context); - -public: - ABIArgInfo classifyReturnType(QualType RetTy, - ASTContext &Context, - llvm::LLVMContext &VMContext) const; - - ABIArgInfo classifyArgumentType(QualType RetTy, - ASTContext &Context, - llvm::LLVMContext &VMContext) const; - - virtual void computeInfo(CGFunctionInfo &FI, ASTContext &Context, - llvm::LLVMContext &VMContext) const { - FI.getReturnInfo() = classifyReturnType(FI.getReturnType(), Context, - VMContext); - for (CGFunctionInfo::arg_iterator it = FI.arg_begin(), ie = FI.arg_end(); - it != ie; ++it) - it->info = classifyArgumentType(it->type, Context, VMContext); - } - - virtual llvm::Value *EmitVAArg(llvm::Value *VAListAddr, QualType Ty, - CodeGenFunction &CGF) const; - - X86_32ABIInfo(ASTContext &Context, bool d, bool p) - : ABIInfo(), Context(Context), IsDarwinVectorABI(d), - IsSmallStructInRegABI(p) {} -}; -} - - -/// shouldReturnTypeInRegister - Determine if the given type should be -/// passed in a register (for the Darwin ABI). -bool X86_32ABIInfo::shouldReturnTypeInRegister(QualType Ty, - ASTContext &Context) { - uint64_t Size = Context.getTypeSize(Ty); - - // Type must be register sized. - if (!isRegisterSize(Size)) - return false; - - if (Ty->isVectorType()) { - // 64- and 128- bit vectors inside structures are not returned in - // registers. - if (Size == 64 || Size == 128) - return false; - - return true; - } - - // If this is a builtin, pointer, enum, or complex type, it is ok. - if (Ty->getAs<BuiltinType>() || Ty->isAnyPointerType() || - Ty->isAnyComplexType() || Ty->isEnumeralType() || - Ty->isBlockPointerType()) - return true; - - // Arrays are treated like records. - if (const ConstantArrayType *AT = Context.getAsConstantArrayType(Ty)) - return shouldReturnTypeInRegister(AT->getElementType(), Context); - - // Otherwise, it must be a record type. - const RecordType *RT = Ty->getAs<RecordType>(); - if (!RT) return false; - - // Structure types are passed in register if all fields would be - // passed in a register. - for (RecordDecl::field_iterator i = RT->getDecl()->field_begin(), - e = RT->getDecl()->field_end(); i != e; ++i) { - const FieldDecl *FD = *i; - - // Empty fields are ignored. - if (isEmptyField(Context, FD, true)) - continue; - - // Check fields recursively. - if (!shouldReturnTypeInRegister(FD->getType(), Context)) - return false; - } - - return true; -} - -ABIArgInfo X86_32ABIInfo::classifyReturnType(QualType RetTy, - ASTContext &Context, - llvm::LLVMContext &VMContext) const { - if (RetTy->isVoidType()) { - return ABIArgInfo::getIgnore(); - } else if (const VectorType *VT = RetTy->getAs<VectorType>()) { - // On Darwin, some vectors are returned in registers. - if (IsDarwinVectorABI) { - uint64_t Size = Context.getTypeSize(RetTy); - - // 128-bit vectors are a special case; they are returned in - // registers and we need to make sure to pick a type the LLVM - // backend will like. - if (Size == 128) - return ABIArgInfo::getCoerce(llvm::VectorType::get( - llvm::Type::getInt64Ty(VMContext), 2)); - - // Always return in register if it fits in a general purpose - // register, or if it is 64 bits and has a single element. - if ((Size == 8 || Size == 16 || Size == 32) || - (Size == 64 && VT->getNumElements() == 1)) - return ABIArgInfo::getCoerce(llvm::IntegerType::get(VMContext, Size)); - - return ABIArgInfo::getIndirect(0); - } - - return ABIArgInfo::getDirect(); - } else if (CodeGenFunction::hasAggregateLLVMType(RetTy)) { - if (const RecordType *RT = RetTy->getAsStructureType()) { - // Structures with either a non-trivial destructor or a non-trivial - // copy constructor are always indirect. - if (hasNonTrivialDestructorOrCopyConstructor(RT)) - return ABIArgInfo::getIndirect(0, /*ByVal=*/false); - - // Structures with flexible arrays are always indirect. - if (RT->getDecl()->hasFlexibleArrayMember()) - return ABIArgInfo::getIndirect(0); - } - - // If specified, structs and unions are always indirect. - if (!IsSmallStructInRegABI && !RetTy->isAnyComplexType()) - return ABIArgInfo::getIndirect(0); - - // Classify "single element" structs as their element type. - if (const Type *SeltTy = isSingleElementStruct(RetTy, Context)) { - if (const BuiltinType *BT = SeltTy->getAs<BuiltinType>()) { - if (BT->isIntegerType()) { - // We need to use the size of the structure, padding - // bit-fields can adjust that to be larger than the single - // element type. - uint64_t Size = Context.getTypeSize(RetTy); - return ABIArgInfo::getCoerce( - llvm::IntegerType::get(VMContext, (unsigned) Size)); - } else if (BT->getKind() == BuiltinType::Float) { - assert(Context.getTypeSize(RetTy) == Context.getTypeSize(SeltTy) && - "Unexpect single element structure size!"); - return ABIArgInfo::getCoerce(llvm::Type::getFloatTy(VMContext)); - } else if (BT->getKind() == BuiltinType::Double) { - assert(Context.getTypeSize(RetTy) == Context.getTypeSize(SeltTy) && - "Unexpect single element structure size!"); - return ABIArgInfo::getCoerce(llvm::Type::getDoubleTy(VMContext)); - } - } else if (SeltTy->isPointerType()) { - // FIXME: It would be really nice if this could come out as the proper - // pointer type. - const llvm::Type *PtrTy = llvm::Type::getInt8PtrTy(VMContext); - return ABIArgInfo::getCoerce(PtrTy); - } else if (SeltTy->isVectorType()) { - // 64- and 128-bit vectors are never returned in a - // register when inside a structure. - uint64_t Size = Context.getTypeSize(RetTy); - if (Size == 64 || Size == 128) - return ABIArgInfo::getIndirect(0); - - return classifyReturnType(QualType(SeltTy, 0), Context, VMContext); - } - } - - // Small structures which are register sized are generally returned - // in a register. - if (X86_32ABIInfo::shouldReturnTypeInRegister(RetTy, Context)) { - uint64_t Size = Context.getTypeSize(RetTy); - return ABIArgInfo::getCoerce(llvm::IntegerType::get(VMContext, Size)); - } - - return ABIArgInfo::getIndirect(0); - } else { - return (RetTy->isPromotableIntegerType() ? - ABIArgInfo::getExtend() : ABIArgInfo::getDirect()); - } -} - -unsigned X86_32ABIInfo::getIndirectArgumentAlignment(QualType Ty, - ASTContext &Context) { - unsigned Align = Context.getTypeAlign(Ty); - if (Align < 128) return 0; - if (const RecordType* RT = Ty->getAs<RecordType>()) - if (typeContainsSSEVector(RT->getDecl(), Context)) - return 16; - return 0; -} - -ABIArgInfo X86_32ABIInfo::classifyArgumentType(QualType Ty, - ASTContext &Context, - llvm::LLVMContext &VMContext) const { - // FIXME: Set alignment on indirect arguments. - if (CodeGenFunction::hasAggregateLLVMType(Ty)) { - // Structures with flexible arrays are always indirect. - if (const RecordType *RT = Ty->getAsStructureType()) - if (RT->getDecl()->hasFlexibleArrayMember()) - return ABIArgInfo::getIndirect(getIndirectArgumentAlignment(Ty, - Context)); - - // Ignore empty structs. - if (Ty->isStructureType() && Context.getTypeSize(Ty) == 0) - return ABIArgInfo::getIgnore(); - - // Expand small (<= 128-bit) record types when we know that the stack layout - // of those arguments will match the struct. This is important because the - // LLVM backend isn't smart enough to remove byval, which inhibits many - // optimizations. - if (Context.getTypeSize(Ty) <= 4*32 && - canExpandIndirectArgument(Ty, Context)) - return ABIArgInfo::getExpand(); - - return ABIArgInfo::getIndirect(getIndirectArgumentAlignment(Ty, Context)); - } else { - return (Ty->isPromotableIntegerType() ? - ABIArgInfo::getExtend() : ABIArgInfo::getDirect()); - } -} - -llvm::Value *X86_32ABIInfo::EmitVAArg(llvm::Value *VAListAddr, QualType Ty, - CodeGenFunction &CGF) const { - const llvm::Type *BP = llvm::Type::getInt8PtrTy(CGF.getLLVMContext()); - const llvm::Type *BPP = llvm::PointerType::getUnqual(BP); - - CGBuilderTy &Builder = CGF.Builder; - llvm::Value *VAListAddrAsBPP = Builder.CreateBitCast(VAListAddr, BPP, - "ap"); - llvm::Value *Addr = Builder.CreateLoad(VAListAddrAsBPP, "ap.cur"); - llvm::Type *PTy = - llvm::PointerType::getUnqual(CGF.ConvertType(Ty)); - llvm::Value *AddrTyped = Builder.CreateBitCast(Addr, PTy); - - uint64_t Offset = - llvm::RoundUpToAlignment(CGF.getContext().getTypeSize(Ty) / 8, 4); - llvm::Value *NextAddr = - Builder.CreateGEP(Addr, llvm::ConstantInt::get( - llvm::Type::getInt32Ty(CGF.getLLVMContext()), Offset), - "ap.next"); - Builder.CreateStore(NextAddr, VAListAddrAsBPP); - - return AddrTyped; -} - -namespace { -/// X86_64ABIInfo - The X86_64 ABI information. -class X86_64ABIInfo : public ABIInfo { - enum Class { - Integer = 0, - SSE, - SSEUp, - X87, - X87Up, - ComplexX87, - NoClass, - Memory - }; - - /// merge - Implement the X86_64 ABI merging algorithm. - /// - /// Merge an accumulating classification \arg Accum with a field - /// classification \arg Field. - /// - /// \param Accum - The accumulating classification. This should - /// always be either NoClass or the result of a previous merge - /// call. In addition, this should never be Memory (the caller - /// should just return Memory for the aggregate). - Class merge(Class Accum, Class Field) const; - - /// classify - Determine the x86_64 register classes in which the - /// given type T should be passed. - /// - /// \param Lo - The classification for the parts of the type - /// residing in the low word of the containing object. - /// - /// \param Hi - The classification for the parts of the type - /// residing in the high word of the containing object. - /// - /// \param OffsetBase - The bit offset of this type in the - /// containing object. Some parameters are classified different - /// depending on whether they straddle an eightbyte boundary. - /// - /// If a word is unused its result will be NoClass; if a type should - /// be passed in Memory then at least the classification of \arg Lo - /// will be Memory. - /// - /// The \arg Lo class will be NoClass iff the argument is ignored. - /// - /// If the \arg Lo class is ComplexX87, then the \arg Hi class will - /// also be ComplexX87. - void classify(QualType T, ASTContext &Context, uint64_t OffsetBase, - Class &Lo, Class &Hi) const; - - /// getCoerceResult - Given a source type \arg Ty and an LLVM type - /// to coerce to, chose the best way to pass Ty in the same place - /// that \arg CoerceTo would be passed, but while keeping the - /// emitted code as simple as possible. - /// - /// FIXME: Note, this should be cleaned up to just take an enumeration of all - /// the ways we might want to pass things, instead of constructing an LLVM - /// type. This makes this code more explicit, and it makes it clearer that we - /// are also doing this for correctness in the case of passing scalar types. - ABIArgInfo getCoerceResult(QualType Ty, - const llvm::Type *CoerceTo, - ASTContext &Context) const; - - /// getIndirectResult - Give a source type \arg Ty, return a suitable result - /// such that the argument will be passed in memory. - ABIArgInfo getIndirectResult(QualType Ty, - ASTContext &Context) const; - - ABIArgInfo classifyReturnType(QualType RetTy, - ASTContext &Context, - llvm::LLVMContext &VMContext) const; - - ABIArgInfo classifyArgumentType(QualType Ty, - ASTContext &Context, - llvm::LLVMContext &VMContext, - unsigned &neededInt, - unsigned &neededSSE) const; - -public: - virtual void computeInfo(CGFunctionInfo &FI, ASTContext &Context, - llvm::LLVMContext &VMContext) const; - - virtual llvm::Value *EmitVAArg(llvm::Value *VAListAddr, QualType Ty, - CodeGenFunction &CGF) const; -}; -} - -X86_64ABIInfo::Class X86_64ABIInfo::merge(Class Accum, - Class Field) const { - // AMD64-ABI 3.2.3p2: Rule 4. Each field of an object is - // classified recursively so that always two fields are - // considered. The resulting class is calculated according to - // the classes of the fields in the eightbyte: - // - // (a) If both classes are equal, this is the resulting class. - // - // (b) If one of the classes is NO_CLASS, the resulting class is - // the other class. - // - // (c) If one of the classes is MEMORY, the result is the MEMORY - // class. - // - // (d) If one of the classes is INTEGER, the result is the - // INTEGER. - // - // (e) If one of the classes is X87, X87UP, COMPLEX_X87 class, - // MEMORY is used as class. - // - // (f) Otherwise class SSE is used. - - // Accum should never be memory (we should have returned) or - // ComplexX87 (because this cannot be passed in a structure). - assert((Accum != Memory && Accum != ComplexX87) && - "Invalid accumulated classification during merge."); - if (Accum == Field || Field == NoClass) - return Accum; - else if (Field == Memory) - return Memory; - else if (Accum == NoClass) - return Field; - else if (Accum == Integer || Field == Integer) - return Integer; - else if (Field == X87 || Field == X87Up || Field == ComplexX87 || - Accum == X87 || Accum == X87Up) - return Memory; - else - return SSE; -} - -void X86_64ABIInfo::classify(QualType Ty, - ASTContext &Context, - uint64_t OffsetBase, - Class &Lo, Class &Hi) const { - // FIXME: This code can be simplified by introducing a simple value class for - // Class pairs with appropriate constructor methods for the various - // situations. - - // FIXME: Some of the split computations are wrong; unaligned vectors - // shouldn't be passed in registers for example, so there is no chance they - // can straddle an eightbyte. Verify & simplify. - - Lo = Hi = NoClass; - - Class &Current = OffsetBase < 64 ? Lo : Hi; - Current = Memory; - - if (const BuiltinType *BT = Ty->getAs<BuiltinType>()) { - BuiltinType::Kind k = BT->getKind(); - - if (k == BuiltinType::Void) { - Current = NoClass; - } else if (k == BuiltinType::Int128 || k == BuiltinType::UInt128) { - Lo = Integer; - Hi = Integer; - } else if (k >= BuiltinType::Bool && k <= BuiltinType::LongLong) { - Current = Integer; - } else if (k == BuiltinType::Float || k == BuiltinType::Double) { - Current = SSE; - } else if (k == BuiltinType::LongDouble) { - Lo = X87; - Hi = X87Up; - } - // FIXME: _Decimal32 and _Decimal64 are SSE. - // FIXME: _float128 and _Decimal128 are (SSE, SSEUp). - } else if (const EnumType *ET = Ty->getAs<EnumType>()) { - // Classify the underlying integer type. - classify(ET->getDecl()->getIntegerType(), Context, OffsetBase, Lo, Hi); - } else if (Ty->hasPointerRepresentation()) { - Current = Integer; - } else if (const VectorType *VT = Ty->getAs<VectorType>()) { - uint64_t Size = Context.getTypeSize(VT); - if (Size == 32) { - // gcc passes all <4 x char>, <2 x short>, <1 x int>, <1 x - // float> as integer. - Current = Integer; - - // If this type crosses an eightbyte boundary, it should be - // split. - uint64_t EB_Real = (OffsetBase) / 64; - uint64_t EB_Imag = (OffsetBase + Size - 1) / 64; - if (EB_Real != EB_Imag) - Hi = Lo; - } else if (Size == 64) { - // gcc passes <1 x double> in memory. :( - if (VT->getElementType()->isSpecificBuiltinType(BuiltinType::Double)) - return; - - // gcc passes <1 x long long> as INTEGER. - if (VT->getElementType()->isSpecificBuiltinType(BuiltinType::LongLong)) - Current = Integer; - else - Current = SSE; - - // If this type crosses an eightbyte boundary, it should be - // split. - if (OffsetBase && OffsetBase != 64) - Hi = Lo; - } else if (Size == 128) { - Lo = SSE; - Hi = SSEUp; - } - } else if (const ComplexType *CT = Ty->getAs<ComplexType>()) { - QualType ET = Context.getCanonicalType(CT->getElementType()); - - uint64_t Size = Context.getTypeSize(Ty); - if (ET->isIntegralType()) { - if (Size <= 64) - Current = Integer; - else if (Size <= 128) - Lo = Hi = Integer; - } else if (ET == Context.FloatTy) - Current = SSE; - else if (ET == Context.DoubleTy) - Lo = Hi = SSE; - else if (ET == Context.LongDoubleTy) - Current = ComplexX87; - - // If this complex type crosses an eightbyte boundary then it - // should be split. - uint64_t EB_Real = (OffsetBase) / 64; - uint64_t EB_Imag = (OffsetBase + Context.getTypeSize(ET)) / 64; - if (Hi == NoClass && EB_Real != EB_Imag) - Hi = Lo; - } else if (const ConstantArrayType *AT = Context.getAsConstantArrayType(Ty)) { - // Arrays are treated like structures. - - uint64_t Size = Context.getTypeSize(Ty); - - // AMD64-ABI 3.2.3p2: Rule 1. If the size of an object is larger - // than two eightbytes, ..., it has class MEMORY. - if (Size > 128) - return; - - // AMD64-ABI 3.2.3p2: Rule 1. If ..., or it contains unaligned - // fields, it has class MEMORY. - // - // Only need to check alignment of array base. - if (OffsetBase % Context.getTypeAlign(AT->getElementType())) - return; - - // Otherwise implement simplified merge. We could be smarter about - // this, but it isn't worth it and would be harder to verify. - Current = NoClass; - uint64_t EltSize = Context.getTypeSize(AT->getElementType()); - uint64_t ArraySize = AT->getSize().getZExtValue(); - for (uint64_t i=0, Offset=OffsetBase; i<ArraySize; ++i, Offset += EltSize) { - Class FieldLo, FieldHi; - classify(AT->getElementType(), Context, Offset, FieldLo, FieldHi); - Lo = merge(Lo, FieldLo); - Hi = merge(Hi, FieldHi); - if (Lo == Memory || Hi == Memory) - break; - } - - // Do post merger cleanup (see below). Only case we worry about is Memory. - if (Hi == Memory) - Lo = Memory; - assert((Hi != SSEUp || Lo == SSE) && "Invalid SSEUp array classification."); - } else if (const RecordType *RT = Ty->getAs<RecordType>()) { - uint64_t Size = Context.getTypeSize(Ty); - - // AMD64-ABI 3.2.3p2: Rule 1. If the size of an object is larger - // than two eightbytes, ..., it has class MEMORY. - if (Size > 128) - return; - - // AMD64-ABI 3.2.3p2: Rule 2. If a C++ object has either a non-trivial - // copy constructor or a non-trivial destructor, it is passed by invisible - // reference. - if (hasNonTrivialDestructorOrCopyConstructor(RT)) - return; - - const RecordDecl *RD = RT->getDecl(); - - // Assume variable sized types are passed in memory. - if (RD->hasFlexibleArrayMember()) - return; - - const ASTRecordLayout &Layout = Context.getASTRecordLayout(RD); - - // Reset Lo class, this will be recomputed. - Current = NoClass; - - // If this is a C++ record, classify the bases first. - if (const CXXRecordDecl *CXXRD = dyn_cast<CXXRecordDecl>(RD)) { - for (CXXRecordDecl::base_class_const_iterator i = CXXRD->bases_begin(), - e = CXXRD->bases_end(); i != e; ++i) { - assert(!i->isVirtual() && !i->getType()->isDependentType() && - "Unexpected base class!"); - const CXXRecordDecl *Base = - cast<CXXRecordDecl>(i->getType()->getAs<RecordType>()->getDecl()); - - // Classify this field. - // - // AMD64-ABI 3.2.3p2: Rule 3. If the size of the aggregate exceeds a - // single eightbyte, each is classified separately. Each eightbyte gets - // initialized to class NO_CLASS. - Class FieldLo, FieldHi; - uint64_t Offset = OffsetBase + Layout.getBaseClassOffset(Base); - classify(i->getType(), Context, Offset, FieldLo, FieldHi); - Lo = merge(Lo, FieldLo); - Hi = merge(Hi, FieldHi); - if (Lo == Memory || Hi == Memory) - break; - } - - // If this record has no fields but isn't empty, classify as INTEGER. - if (RD->field_empty() && Size) - Current = Integer; - } - - // Classify the fields one at a time, merging the results. - unsigned idx = 0; - for (RecordDecl::field_iterator i = RD->field_begin(), e = RD->field_end(); - i != e; ++i, ++idx) { - uint64_t Offset = OffsetBase + Layout.getFieldOffset(idx); - bool BitField = i->isBitField(); - - // AMD64-ABI 3.2.3p2: Rule 1. If ..., or it contains unaligned - // fields, it has class MEMORY. - // - // Note, skip this test for bit-fields, see below. - if (!BitField && Offset % Context.getTypeAlign(i->getType())) { - Lo = Memory; - return; - } - - // Classify this field. - // - // AMD64-ABI 3.2.3p2: Rule 3. If the size of the aggregate - // exceeds a single eightbyte, each is classified - // separately. Each eightbyte gets initialized to class - // NO_CLASS. - Class FieldLo, FieldHi; - - // Bit-fields require special handling, they do not force the - // structure to be passed in memory even if unaligned, and - // therefore they can straddle an eightbyte. - if (BitField) { - // Ignore padding bit-fields. - if (i->isUnnamedBitfield()) - continue; - - uint64_t Offset = OffsetBase + Layout.getFieldOffset(idx); - uint64_t Size = i->getBitWidth()->EvaluateAsInt(Context).getZExtValue(); - - uint64_t EB_Lo = Offset / 64; - uint64_t EB_Hi = (Offset + Size - 1) / 64; - FieldLo = FieldHi = NoClass; - if (EB_Lo) { - assert(EB_Hi == EB_Lo && "Invalid classification, type > 16 bytes."); - FieldLo = NoClass; - FieldHi = Integer; - } else { - FieldLo = Integer; - FieldHi = EB_Hi ? Integer : NoClass; - } - } else - classify(i->getType(), Context, Offset, FieldLo, FieldHi); - Lo = merge(Lo, FieldLo); - Hi = merge(Hi, FieldHi); - if (Lo == Memory || Hi == Memory) - break; - } - - // AMD64-ABI 3.2.3p2: Rule 5. Then a post merger cleanup is done: - // - // (a) If one of the classes is MEMORY, the whole argument is - // passed in memory. - // - // (b) If SSEUP is not preceeded by SSE, it is converted to SSE. - - // The first of these conditions is guaranteed by how we implement - // the merge (just bail). - // - // The second condition occurs in the case of unions; for example - // union { _Complex double; unsigned; }. - if (Hi == Memory) - Lo = Memory; - if (Hi == SSEUp && Lo != SSE) - Hi = SSE; - } -} - -ABIArgInfo X86_64ABIInfo::getCoerceResult(QualType Ty, - const llvm::Type *CoerceTo, - ASTContext &Context) const { - if (CoerceTo == llvm::Type::getInt64Ty(CoerceTo->getContext())) { - // Integer and pointer types will end up in a general purpose - // register. - if (Ty->isIntegralType() || Ty->hasPointerRepresentation()) - return (Ty->isPromotableIntegerType() ? - ABIArgInfo::getExtend() : ABIArgInfo::getDirect()); - } else if (CoerceTo == llvm::Type::getDoubleTy(CoerceTo->getContext())) { - // FIXME: It would probably be better to make CGFunctionInfo only map using - // canonical types than to canonize here. - QualType CTy = Context.getCanonicalType(Ty); - - // Float and double end up in a single SSE reg. - if (CTy == Context.FloatTy || CTy == Context.DoubleTy) - return ABIArgInfo::getDirect(); - - } - - return ABIArgInfo::getCoerce(CoerceTo); -} - -ABIArgInfo X86_64ABIInfo::getIndirectResult(QualType Ty, - ASTContext &Context) const { - // If this is a scalar LLVM value then assume LLVM will pass it in the right - // place naturally. - if (!CodeGenFunction::hasAggregateLLVMType(Ty)) - return (Ty->isPromotableIntegerType() ? - ABIArgInfo::getExtend() : ABIArgInfo::getDirect()); - - bool ByVal = !isRecordWithNonTrivialDestructorOrCopyConstructor(Ty); - - // FIXME: Set alignment correctly. - return ABIArgInfo::getIndirect(0, ByVal); -} - -ABIArgInfo X86_64ABIInfo::classifyReturnType(QualType RetTy, - ASTContext &Context, - llvm::LLVMContext &VMContext) const { - // AMD64-ABI 3.2.3p4: Rule 1. Classify the return type with the - // classification algorithm. - X86_64ABIInfo::Class Lo, Hi; - classify(RetTy, Context, 0, Lo, Hi); - - // Check some invariants. - assert((Hi != Memory || Lo == Memory) && "Invalid memory classification."); - assert((Lo != NoClass || Hi == NoClass) && "Invalid null classification."); - assert((Hi != SSEUp || Lo == SSE) && "Invalid SSEUp classification."); - - const llvm::Type *ResType = 0; - switch (Lo) { - case NoClass: - return ABIArgInfo::getIgnore(); - - case SSEUp: - case X87Up: - assert(0 && "Invalid classification for lo word."); - - // AMD64-ABI 3.2.3p4: Rule 2. Types of class memory are returned via - // hidden argument. - case Memory: - return getIndirectResult(RetTy, Context); - - // AMD64-ABI 3.2.3p4: Rule 3. If the class is INTEGER, the next - // available register of the sequence %rax, %rdx is used. - case Integer: - ResType = llvm::Type::getInt64Ty(VMContext); break; - - // AMD64-ABI 3.2.3p4: Rule 4. If the class is SSE, the next - // available SSE register of the sequence %xmm0, %xmm1 is used. - case SSE: - ResType = llvm::Type::getDoubleTy(VMContext); break; - - // AMD64-ABI 3.2.3p4: Rule 6. If the class is X87, the value is - // returned on the X87 stack in %st0 as 80-bit x87 number. - case X87: - ResType = llvm::Type::getX86_FP80Ty(VMContext); break; - - // AMD64-ABI 3.2.3p4: Rule 8. If the class is COMPLEX_X87, the real - // part of the value is returned in %st0 and the imaginary part in - // %st1. - case ComplexX87: - assert(Hi == ComplexX87 && "Unexpected ComplexX87 classification."); - ResType = llvm::StructType::get(VMContext, llvm::Type::getX86_FP80Ty(VMContext), - llvm::Type::getX86_FP80Ty(VMContext), - NULL); - break; - } - - switch (Hi) { - // Memory was handled previously and X87 should - // never occur as a hi class. - case Memory: - case X87: - assert(0 && "Invalid classification for hi word."); - - case ComplexX87: // Previously handled. - case NoClass: break; - - case Integer: - ResType = llvm::StructType::get(VMContext, ResType, - llvm::Type::getInt64Ty(VMContext), NULL); - break; - case SSE: - ResType = llvm::StructType::get(VMContext, ResType, - llvm::Type::getDoubleTy(VMContext), NULL); - break; - - // AMD64-ABI 3.2.3p4: Rule 5. If the class is SSEUP, the eightbyte - // is passed in the upper half of the last used SSE register. - // - // SSEUP should always be preceeded by SSE, just widen. - case SSEUp: - assert(Lo == SSE && "Unexpected SSEUp classification."); - ResType = llvm::VectorType::get(llvm::Type::getDoubleTy(VMContext), 2); - break; - - // AMD64-ABI 3.2.3p4: Rule 7. If the class is X87UP, the value is - // returned together with the previous X87 value in %st0. - case X87Up: - // If X87Up is preceeded by X87, we don't need to do - // anything. However, in some cases with unions it may not be - // preceeded by X87. In such situations we follow gcc and pass the - // extra bits in an SSE reg. - if (Lo != X87) - ResType = llvm::StructType::get(VMContext, ResType, - llvm::Type::getDoubleTy(VMContext), NULL); - break; - } - - return getCoerceResult(RetTy, ResType, Context); -} - -ABIArgInfo X86_64ABIInfo::classifyArgumentType(QualType Ty, ASTContext &Context, - llvm::LLVMContext &VMContext, - unsigned &neededInt, - unsigned &neededSSE) const { - X86_64ABIInfo::Class Lo, Hi; - classify(Ty, Context, 0, Lo, Hi); - - // Check some invariants. - // FIXME: Enforce these by construction. - assert((Hi != Memory || Lo == Memory) && "Invalid memory classification."); - assert((Lo != NoClass || Hi == NoClass) && "Invalid null classification."); - assert((Hi != SSEUp || Lo == SSE) && "Invalid SSEUp classification."); - - neededInt = 0; - neededSSE = 0; - const llvm::Type *ResType = 0; - switch (Lo) { - case NoClass: - return ABIArgInfo::getIgnore(); - - // AMD64-ABI 3.2.3p3: Rule 1. If the class is MEMORY, pass the argument - // on the stack. - case Memory: - - // AMD64-ABI 3.2.3p3: Rule 5. If the class is X87, X87UP or - // COMPLEX_X87, it is passed in memory. - case X87: - case ComplexX87: - return getIndirectResult(Ty, Context); - - case SSEUp: - case X87Up: - assert(0 && "Invalid classification for lo word."); - - // AMD64-ABI 3.2.3p3: Rule 2. If the class is INTEGER, the next - // available register of the sequence %rdi, %rsi, %rdx, %rcx, %r8 - // and %r9 is used. - case Integer: - ++neededInt; - ResType = llvm::Type::getInt64Ty(VMContext); - break; - - // AMD64-ABI 3.2.3p3: Rule 3. If the class is SSE, the next - // available SSE register is used, the registers are taken in the - // order from %xmm0 to %xmm7. - case SSE: - ++neededSSE; - ResType = llvm::Type::getDoubleTy(VMContext); - break; - } - - switch (Hi) { - // Memory was handled previously, ComplexX87 and X87 should - // never occur as hi classes, and X87Up must be preceed by X87, - // which is passed in memory. - case Memory: - case X87: - case ComplexX87: - assert(0 && "Invalid classification for hi word."); - break; - - case NoClass: break; - case Integer: - ResType = llvm::StructType::get(VMContext, ResType, - llvm::Type::getInt64Ty(VMContext), NULL); - ++neededInt; - break; - - // X87Up generally doesn't occur here (long double is passed in - // memory), except in situations involving unions. - case X87Up: - case SSE: - ResType = llvm::StructType::get(VMContext, ResType, - llvm::Type::getDoubleTy(VMContext), NULL); - ++neededSSE; - break; - - // AMD64-ABI 3.2.3p3: Rule 4. If the class is SSEUP, the - // eightbyte is passed in the upper half of the last used SSE - // register. - case SSEUp: - assert(Lo == SSE && "Unexpected SSEUp classification."); - ResType = llvm::VectorType::get(llvm::Type::getDoubleTy(VMContext), 2); - break; - } - - return getCoerceResult(Ty, ResType, Context); -} - -void X86_64ABIInfo::computeInfo(CGFunctionInfo &FI, ASTContext &Context, - llvm::LLVMContext &VMContext) const { - FI.getReturnInfo() = classifyReturnType(FI.getReturnType(), - Context, VMContext); - - // Keep track of the number of assigned registers. - unsigned freeIntRegs = 6, freeSSERegs = 8; - - // If the return value is indirect, then the hidden argument is consuming one - // integer register. - if (FI.getReturnInfo().isIndirect()) - --freeIntRegs; - - // AMD64-ABI 3.2.3p3: Once arguments are classified, the registers - // get assigned (in left-to-right order) for passing as follows... - for (CGFunctionInfo::arg_iterator it = FI.arg_begin(), ie = FI.arg_end(); - it != ie; ++it) { - unsigned neededInt, neededSSE; - it->info = classifyArgumentType(it->type, Context, VMContext, - neededInt, neededSSE); - - // AMD64-ABI 3.2.3p3: If there are no registers available for any - // eightbyte of an argument, the whole argument is passed on the - // stack. If registers have already been assigned for some - // eightbytes of such an argument, the assignments get reverted. - if (freeIntRegs >= neededInt && freeSSERegs >= neededSSE) { - freeIntRegs -= neededInt; - freeSSERegs -= neededSSE; - } else { - it->info = getIndirectResult(it->type, Context); - } - } -} - -static llvm::Value *EmitVAArgFromMemory(llvm::Value *VAListAddr, - QualType Ty, - CodeGenFunction &CGF) { - llvm::Value *overflow_arg_area_p = - CGF.Builder.CreateStructGEP(VAListAddr, 2, "overflow_arg_area_p"); - llvm::Value *overflow_arg_area = - CGF.Builder.CreateLoad(overflow_arg_area_p, "overflow_arg_area"); - - // AMD64-ABI 3.5.7p5: Step 7. Align l->overflow_arg_area upwards to a 16 - // byte boundary if alignment needed by type exceeds 8 byte boundary. - uint64_t Align = CGF.getContext().getTypeAlign(Ty) / 8; - if (Align > 8) { - // Note that we follow the ABI & gcc here, even though the type - // could in theory have an alignment greater than 16. This case - // shouldn't ever matter in practice. - - // overflow_arg_area = (overflow_arg_area + 15) & ~15; - llvm::Value *Offset = - llvm::ConstantInt::get(llvm::Type::getInt32Ty(CGF.getLLVMContext()), 15); - overflow_arg_area = CGF.Builder.CreateGEP(overflow_arg_area, Offset); - llvm::Value *AsInt = CGF.Builder.CreatePtrToInt(overflow_arg_area, - llvm::Type::getInt64Ty(CGF.getLLVMContext())); - llvm::Value *Mask = llvm::ConstantInt::get( - llvm::Type::getInt64Ty(CGF.getLLVMContext()), ~15LL); - overflow_arg_area = - CGF.Builder.CreateIntToPtr(CGF.Builder.CreateAnd(AsInt, Mask), - overflow_arg_area->getType(), - "overflow_arg_area.align"); - } - - // AMD64-ABI 3.5.7p5: Step 8. Fetch type from l->overflow_arg_area. - const llvm::Type *LTy = CGF.ConvertTypeForMem(Ty); - llvm::Value *Res = - CGF.Builder.CreateBitCast(overflow_arg_area, - llvm::PointerType::getUnqual(LTy)); - - // AMD64-ABI 3.5.7p5: Step 9. Set l->overflow_arg_area to: - // l->overflow_arg_area + sizeof(type). - // AMD64-ABI 3.5.7p5: Step 10. Align l->overflow_arg_area upwards to - // an 8 byte boundary. - - uint64_t SizeInBytes = (CGF.getContext().getTypeSize(Ty) + 7) / 8; - llvm::Value *Offset = - llvm::ConstantInt::get(llvm::Type::getInt32Ty(CGF.getLLVMContext()), - (SizeInBytes + 7) & ~7); - overflow_arg_area = CGF.Builder.CreateGEP(overflow_arg_area, Offset, - "overflow_arg_area.next"); - CGF.Builder.CreateStore(overflow_arg_area, overflow_arg_area_p); - - // AMD64-ABI 3.5.7p5: Step 11. Return the fetched type. - return Res; -} - -llvm::Value *X86_64ABIInfo::EmitVAArg(llvm::Value *VAListAddr, QualType Ty, - CodeGenFunction &CGF) const { - llvm::LLVMContext &VMContext = CGF.getLLVMContext(); - const llvm::Type *i32Ty = llvm::Type::getInt32Ty(VMContext); - const llvm::Type *DoubleTy = llvm::Type::getDoubleTy(VMContext); - - // Assume that va_list type is correct; should be pointer to LLVM type: - // struct { - // i32 gp_offset; - // i32 fp_offset; - // i8* overflow_arg_area; - // i8* reg_save_area; - // }; - unsigned neededInt, neededSSE; - ABIArgInfo AI = classifyArgumentType(Ty, CGF.getContext(), VMContext, - neededInt, neededSSE); - - // AMD64-ABI 3.5.7p5: Step 1. Determine whether type may be passed - // in the registers. If not go to step 7. - if (!neededInt && !neededSSE) - return EmitVAArgFromMemory(VAListAddr, Ty, CGF); - - // AMD64-ABI 3.5.7p5: Step 2. Compute num_gp to hold the number of - // general purpose registers needed to pass type and num_fp to hold - // the number of floating point registers needed. - - // AMD64-ABI 3.5.7p5: Step 3. Verify whether arguments fit into - // registers. In the case: l->gp_offset > 48 - num_gp * 8 or - // l->fp_offset > 304 - num_fp * 16 go to step 7. - // - // NOTE: 304 is a typo, there are (6 * 8 + 8 * 16) = 176 bytes of - // register save space). - - llvm::Value *InRegs = 0; - llvm::Value *gp_offset_p = 0, *gp_offset = 0; - llvm::Value *fp_offset_p = 0, *fp_offset = 0; - if (neededInt) { - gp_offset_p = CGF.Builder.CreateStructGEP(VAListAddr, 0, "gp_offset_p"); - gp_offset = CGF.Builder.CreateLoad(gp_offset_p, "gp_offset"); - InRegs = - CGF.Builder.CreateICmpULE(gp_offset, - llvm::ConstantInt::get(i32Ty, - 48 - neededInt * 8), - "fits_in_gp"); - } - - if (neededSSE) { - fp_offset_p = CGF.Builder.CreateStructGEP(VAListAddr, 1, "fp_offset_p"); - fp_offset = CGF.Builder.CreateLoad(fp_offset_p, "fp_offset"); - llvm::Value *FitsInFP = - CGF.Builder.CreateICmpULE(fp_offset, - llvm::ConstantInt::get(i32Ty, - 176 - neededSSE * 16), - "fits_in_fp"); - InRegs = InRegs ? CGF.Builder.CreateAnd(InRegs, FitsInFP) : FitsInFP; - } - - llvm::BasicBlock *InRegBlock = CGF.createBasicBlock("vaarg.in_reg"); - llvm::BasicBlock *InMemBlock = CGF.createBasicBlock("vaarg.in_mem"); - llvm::BasicBlock *ContBlock = CGF.createBasicBlock("vaarg.end"); - CGF.Builder.CreateCondBr(InRegs, InRegBlock, InMemBlock); - - // Emit code to load the value if it was passed in registers. - - CGF.EmitBlock(InRegBlock); - - // AMD64-ABI 3.5.7p5: Step 4. Fetch type from l->reg_save_area with - // an offset of l->gp_offset and/or l->fp_offset. This may require - // copying to a temporary location in case the parameter is passed - // in different register classes or requires an alignment greater - // than 8 for general purpose registers and 16 for XMM registers. - // - // FIXME: This really results in shameful code when we end up needing to - // collect arguments from different places; often what should result in a - // simple assembling of a structure from scattered addresses has many more - // loads than necessary. Can we clean this up? - const llvm::Type *LTy = CGF.ConvertTypeForMem(Ty); - llvm::Value *RegAddr = - CGF.Builder.CreateLoad(CGF.Builder.CreateStructGEP(VAListAddr, 3), - "reg_save_area"); - if (neededInt && neededSSE) { - // FIXME: Cleanup. - assert(AI.isCoerce() && "Unexpected ABI info for mixed regs"); - const llvm::StructType *ST = cast<llvm::StructType>(AI.getCoerceToType()); - llvm::Value *Tmp = CGF.CreateTempAlloca(ST); - assert(ST->getNumElements() == 2 && "Unexpected ABI info for mixed regs"); - const llvm::Type *TyLo = ST->getElementType(0); - const llvm::Type *TyHi = ST->getElementType(1); - assert((TyLo->isFloatingPoint() ^ TyHi->isFloatingPoint()) && - "Unexpected ABI info for mixed regs"); - const llvm::Type *PTyLo = llvm::PointerType::getUnqual(TyLo); - const llvm::Type *PTyHi = llvm::PointerType::getUnqual(TyHi); - llvm::Value *GPAddr = CGF.Builder.CreateGEP(RegAddr, gp_offset); - llvm::Value *FPAddr = CGF.Builder.CreateGEP(RegAddr, fp_offset); - llvm::Value *RegLoAddr = TyLo->isFloatingPoint() ? FPAddr : GPAddr; - llvm::Value *RegHiAddr = TyLo->isFloatingPoint() ? GPAddr : FPAddr; - llvm::Value *V = - CGF.Builder.CreateLoad(CGF.Builder.CreateBitCast(RegLoAddr, PTyLo)); - CGF.Builder.CreateStore(V, CGF.Builder.CreateStructGEP(Tmp, 0)); - V = CGF.Builder.CreateLoad(CGF.Builder.CreateBitCast(RegHiAddr, PTyHi)); - CGF.Builder.CreateStore(V, CGF.Builder.CreateStructGEP(Tmp, 1)); - - RegAddr = CGF.Builder.CreateBitCast(Tmp, - llvm::PointerType::getUnqual(LTy)); - } else if (neededInt) { - RegAddr = CGF.Builder.CreateGEP(RegAddr, gp_offset); - RegAddr = CGF.Builder.CreateBitCast(RegAddr, - llvm::PointerType::getUnqual(LTy)); - } else { - if (neededSSE == 1) { - RegAddr = CGF.Builder.CreateGEP(RegAddr, fp_offset); - RegAddr = CGF.Builder.CreateBitCast(RegAddr, - llvm::PointerType::getUnqual(LTy)); - } else { - assert(neededSSE == 2 && "Invalid number of needed registers!"); - // SSE registers are spaced 16 bytes apart in the register save - // area, we need to collect the two eightbytes together. - llvm::Value *RegAddrLo = CGF.Builder.CreateGEP(RegAddr, fp_offset); - llvm::Value *RegAddrHi = - CGF.Builder.CreateGEP(RegAddrLo, - llvm::ConstantInt::get(i32Ty, 16)); - const llvm::Type *DblPtrTy = - llvm::PointerType::getUnqual(DoubleTy); - const llvm::StructType *ST = llvm::StructType::get(VMContext, DoubleTy, - DoubleTy, NULL); - llvm::Value *V, *Tmp = CGF.CreateTempAlloca(ST); - V = CGF.Builder.CreateLoad(CGF.Builder.CreateBitCast(RegAddrLo, - DblPtrTy)); - CGF.Builder.CreateStore(V, CGF.Builder.CreateStructGEP(Tmp, 0)); - V = CGF.Builder.CreateLoad(CGF.Builder.CreateBitCast(RegAddrHi, - DblPtrTy)); - CGF.Builder.CreateStore(V, CGF.Builder.CreateStructGEP(Tmp, 1)); - RegAddr = CGF.Builder.CreateBitCast(Tmp, - llvm::PointerType::getUnqual(LTy)); - } - } - - // AMD64-ABI 3.5.7p5: Step 5. Set: - // l->gp_offset = l->gp_offset + num_gp * 8 - // l->fp_offset = l->fp_offset + num_fp * 16. - if (neededInt) { - llvm::Value *Offset = llvm::ConstantInt::get(i32Ty, neededInt * 8); - CGF.Builder.CreateStore(CGF.Builder.CreateAdd(gp_offset, Offset), - gp_offset_p); - } - if (neededSSE) { - llvm::Value *Offset = llvm::ConstantInt::get(i32Ty, neededSSE * 16); - CGF.Builder.CreateStore(CGF.Builder.CreateAdd(fp_offset, Offset), - fp_offset_p); - } - CGF.EmitBranch(ContBlock); - - // Emit code to load the value if it was passed in memory. - - CGF.EmitBlock(InMemBlock); - llvm::Value *MemAddr = EmitVAArgFromMemory(VAListAddr, Ty, CGF); - - // Return the appropriate result. - - CGF.EmitBlock(ContBlock); - llvm::PHINode *ResAddr = CGF.Builder.CreatePHI(RegAddr->getType(), - "vaarg.addr"); - ResAddr->reserveOperandSpace(2); - ResAddr->addIncoming(RegAddr, InRegBlock); - ResAddr->addIncoming(MemAddr, InMemBlock); - - return ResAddr; -} - -// PIC16 ABI Implementation - -namespace { - -class PIC16ABIInfo : public ABIInfo { - ABIArgInfo classifyReturnType(QualType RetTy, - ASTContext &Context, - llvm::LLVMContext &VMContext) const; - - ABIArgInfo classifyArgumentType(QualType RetTy, - ASTContext &Context, - llvm::LLVMContext &VMContext) const; - - virtual void computeInfo(CGFunctionInfo &FI, ASTContext &Context, - llvm::LLVMContext &VMContext) const { - FI.getReturnInfo() = classifyReturnType(FI.getReturnType(), Context, - VMContext); - for (CGFunctionInfo::arg_iterator it = FI.arg_begin(), ie = FI.arg_end(); - it != ie; ++it) - it->info = classifyArgumentType(it->type, Context, VMContext); - } - - virtual llvm::Value *EmitVAArg(llvm::Value *VAListAddr, QualType Ty, - CodeGenFunction &CGF) const; -}; - -} - -ABIArgInfo PIC16ABIInfo::classifyReturnType(QualType RetTy, - ASTContext &Context, - llvm::LLVMContext &VMContext) const { - if (RetTy->isVoidType()) { - return ABIArgInfo::getIgnore(); - } else { - return ABIArgInfo::getDirect(); - } -} - -ABIArgInfo PIC16ABIInfo::classifyArgumentType(QualType Ty, - ASTContext &Context, - llvm::LLVMContext &VMContext) const { - return ABIArgInfo::getDirect(); -} - -llvm::Value *PIC16ABIInfo::EmitVAArg(llvm::Value *VAListAddr, QualType Ty, - CodeGenFunction &CGF) const { - return 0; -} - -// ARM ABI Implementation - -namespace { - -class ARMABIInfo : public ABIInfo { -public: - enum ABIKind { - APCS = 0, - AAPCS = 1, - AAPCS_VFP - }; - -private: - ABIKind Kind; - -public: - ARMABIInfo(ABIKind _Kind) : Kind(_Kind) {} - -private: - ABIKind getABIKind() const { return Kind; } - - ABIArgInfo classifyReturnType(QualType RetTy, - ASTContext &Context, - llvm::LLVMContext &VMCOntext) const; - - ABIArgInfo classifyArgumentType(QualType RetTy, - ASTContext &Context, - llvm::LLVMContext &VMContext) const; - - virtual void computeInfo(CGFunctionInfo &FI, ASTContext &Context, - llvm::LLVMContext &VMContext) const; - - virtual llvm::Value *EmitVAArg(llvm::Value *VAListAddr, QualType Ty, - CodeGenFunction &CGF) const; -}; - -} - -void ARMABIInfo::computeInfo(CGFunctionInfo &FI, ASTContext &Context, - llvm::LLVMContext &VMContext) const { - FI.getReturnInfo() = classifyReturnType(FI.getReturnType(), Context, - VMContext); - for (CGFunctionInfo::arg_iterator it = FI.arg_begin(), ie = FI.arg_end(); - it != ie; ++it) { - it->info = classifyArgumentType(it->type, Context, VMContext); - } - - // ARM always overrides the calling convention. - switch (getABIKind()) { - case APCS: - FI.setEffectiveCallingConvention(llvm::CallingConv::ARM_APCS); - break; - - case AAPCS: - FI.setEffectiveCallingConvention(llvm::CallingConv::ARM_AAPCS); - break; - - case AAPCS_VFP: - FI.setEffectiveCallingConvention(llvm::CallingConv::ARM_AAPCS_VFP); - break; - } -} - -ABIArgInfo ARMABIInfo::classifyArgumentType(QualType Ty, - ASTContext &Context, - llvm::LLVMContext &VMContext) const { - if (!CodeGenFunction::hasAggregateLLVMType(Ty)) - return (Ty->isPromotableIntegerType() ? - ABIArgInfo::getExtend() : ABIArgInfo::getDirect()); - - // Ignore empty records. - if (isEmptyRecord(Context, Ty, true)) - return ABIArgInfo::getIgnore(); - - // FIXME: This is kind of nasty... but there isn't much choice because the ARM - // backend doesn't support byval. - // FIXME: This doesn't handle alignment > 64 bits. - const llvm::Type* ElemTy; - unsigned SizeRegs; - if (Context.getTypeAlign(Ty) > 32) { - ElemTy = llvm::Type::getInt64Ty(VMContext); - SizeRegs = (Context.getTypeSize(Ty) + 63) / 64; - } else { - ElemTy = llvm::Type::getInt32Ty(VMContext); - SizeRegs = (Context.getTypeSize(Ty) + 31) / 32; - } - std::vector<const llvm::Type*> LLVMFields; - LLVMFields.push_back(llvm::ArrayType::get(ElemTy, SizeRegs)); - const llvm::Type* STy = llvm::StructType::get(VMContext, LLVMFields, true); - return ABIArgInfo::getCoerce(STy); -} - -static bool isIntegerLikeType(QualType Ty, - ASTContext &Context, - llvm::LLVMContext &VMContext) { - // APCS, C Language Calling Conventions, Non-Simple Return Values: A structure - // is called integer-like if its size is less than or equal to one word, and - // the offset of each of its addressable sub-fields is zero. - - uint64_t Size = Context.getTypeSize(Ty); - - // Check that the type fits in a word. - if (Size > 32) - return false; - - // FIXME: Handle vector types! - if (Ty->isVectorType()) - return false; - - // Float types are never treated as "integer like". - if (Ty->isRealFloatingType()) - return false; - - // If this is a builtin or pointer type then it is ok. - if (Ty->getAs<BuiltinType>() || Ty->isPointerType()) - return true; - - // Complex types "should" be ok by the definition above, but they are not. - if (Ty->isAnyComplexType()) - return false; - - // Single element and zero sized arrays should be allowed, by the definition - // above, but they are not. - - // Otherwise, it must be a record type. - const RecordType *RT = Ty->getAs<RecordType>(); - if (!RT) return false; - - // Ignore records with flexible arrays. - const RecordDecl *RD = RT->getDecl(); - if (RD->hasFlexibleArrayMember()) - return false; - - // Check that all sub-fields are at offset 0, and are themselves "integer - // like". - const ASTRecordLayout &Layout = Context.getASTRecordLayout(RD); - - bool HadField = false; - unsigned idx = 0; - for (RecordDecl::field_iterator i = RD->field_begin(), e = RD->field_end(); - i != e; ++i, ++idx) { - const FieldDecl *FD = *i; - - // Check if this field is at offset 0. - uint64_t Offset = Layout.getFieldOffset(idx); - if (Offset != 0) { - // Allow padding bit-fields, but only if they are all at the end of the - // structure (despite the wording above, this matches gcc). - if (FD->isBitField() && - !FD->getBitWidth()->EvaluateAsInt(Context).getZExtValue()) { - for (; i != e; ++i) - if (!i->isBitField() || - i->getBitWidth()->EvaluateAsInt(Context).getZExtValue()) - return false; - - // All remaining fields are padding, allow this. - return true; - } - - return false; - } - - if (!isIntegerLikeType(FD->getType(), Context, VMContext)) - return false; - - // Only allow at most one field in a structure. Again this doesn't match the - // wording above, but follows gcc. - if (!RD->isUnion()) { - if (HadField) - return false; - - HadField = true; - } - } - - return true; -} - -ABIArgInfo ARMABIInfo::classifyReturnType(QualType RetTy, - ASTContext &Context, - llvm::LLVMContext &VMContext) const { - if (RetTy->isVoidType()) - return ABIArgInfo::getIgnore(); - - if (!CodeGenFunction::hasAggregateLLVMType(RetTy)) - return (RetTy->isPromotableIntegerType() ? - ABIArgInfo::getExtend() : ABIArgInfo::getDirect()); - - // Are we following APCS? - if (getABIKind() == APCS) { - if (isEmptyRecord(Context, RetTy, false)) - return ABIArgInfo::getIgnore(); - - // Integer like structures are returned in r0. - if (isIntegerLikeType(RetTy, Context, VMContext)) { - // Return in the smallest viable integer type. - uint64_t Size = Context.getTypeSize(RetTy); - if (Size <= 8) - return ABIArgInfo::getCoerce(llvm::Type::getInt8Ty(VMContext)); - if (Size <= 16) - return ABIArgInfo::getCoerce(llvm::Type::getInt16Ty(VMContext)); - return ABIArgInfo::getCoerce(llvm::Type::getInt32Ty(VMContext)); - } - - // Otherwise return in memory. - return ABIArgInfo::getIndirect(0); - } - - // Otherwise this is an AAPCS variant. - - if (isEmptyRecord(Context, RetTy, true)) - return ABIArgInfo::getIgnore(); - - // Aggregates <= 4 bytes are returned in r0; other aggregates - // are returned indirectly. - uint64_t Size = Context.getTypeSize(RetTy); - if (Size <= 32) { - // Return in the smallest viable integer type. - if (Size <= 8) - return ABIArgInfo::getCoerce(llvm::Type::getInt8Ty(VMContext)); - if (Size <= 16) - return ABIArgInfo::getCoerce(llvm::Type::getInt16Ty(VMContext)); - return ABIArgInfo::getCoerce(llvm::Type::getInt32Ty(VMContext)); - } - - return ABIArgInfo::getIndirect(0); -} - -llvm::Value *ARMABIInfo::EmitVAArg(llvm::Value *VAListAddr, QualType Ty, - CodeGenFunction &CGF) const { - // FIXME: Need to handle alignment - const llvm::Type *BP = llvm::Type::getInt8PtrTy(CGF.getLLVMContext()); - const llvm::Type *BPP = llvm::PointerType::getUnqual(BP); - - CGBuilderTy &Builder = CGF.Builder; - llvm::Value *VAListAddrAsBPP = Builder.CreateBitCast(VAListAddr, BPP, - "ap"); - llvm::Value *Addr = Builder.CreateLoad(VAListAddrAsBPP, "ap.cur"); - llvm::Type *PTy = - llvm::PointerType::getUnqual(CGF.ConvertType(Ty)); - llvm::Value *AddrTyped = Builder.CreateBitCast(Addr, PTy); - - uint64_t Offset = - llvm::RoundUpToAlignment(CGF.getContext().getTypeSize(Ty) / 8, 4); - llvm::Value *NextAddr = - Builder.CreateGEP(Addr, llvm::ConstantInt::get( - llvm::Type::getInt32Ty(CGF.getLLVMContext()), Offset), - "ap.next"); - Builder.CreateStore(NextAddr, VAListAddrAsBPP); - - return AddrTyped; -} - -ABIArgInfo DefaultABIInfo::classifyReturnType(QualType RetTy, - ASTContext &Context, - llvm::LLVMContext &VMContext) const { - if (RetTy->isVoidType()) { - return ABIArgInfo::getIgnore(); - } else if (CodeGenFunction::hasAggregateLLVMType(RetTy)) { - return ABIArgInfo::getIndirect(0); - } else { - return (RetTy->isPromotableIntegerType() ? - ABIArgInfo::getExtend() : ABIArgInfo::getDirect()); - } -} - -// SystemZ ABI Implementation - -namespace { - -class SystemZABIInfo : public ABIInfo { - bool isPromotableIntegerType(QualType Ty) const; - - ABIArgInfo classifyReturnType(QualType RetTy, ASTContext &Context, - llvm::LLVMContext &VMContext) const; - - ABIArgInfo classifyArgumentType(QualType RetTy, ASTContext &Context, - llvm::LLVMContext &VMContext) const; - - virtual void computeInfo(CGFunctionInfo &FI, ASTContext &Context, - llvm::LLVMContext &VMContext) const { - FI.getReturnInfo() = classifyReturnType(FI.getReturnType(), - Context, VMContext); - for (CGFunctionInfo::arg_iterator it = FI.arg_begin(), ie = FI.arg_end(); - it != ie; ++it) - it->info = classifyArgumentType(it->type, Context, VMContext); - } - - virtual llvm::Value *EmitVAArg(llvm::Value *VAListAddr, QualType Ty, - CodeGenFunction &CGF) const; -}; - -} - -bool SystemZABIInfo::isPromotableIntegerType(QualType Ty) const { - // SystemZ ABI requires all 8, 16 and 32 bit quantities to be extended. - if (const BuiltinType *BT = Ty->getAs<BuiltinType>()) - switch (BT->getKind()) { - case BuiltinType::Bool: - case BuiltinType::Char_S: - case BuiltinType::Char_U: - case BuiltinType::SChar: - case BuiltinType::UChar: - case BuiltinType::Short: - case BuiltinType::UShort: - case BuiltinType::Int: - case BuiltinType::UInt: - return true; - default: - return false; - } - return false; -} - -llvm::Value *SystemZABIInfo::EmitVAArg(llvm::Value *VAListAddr, QualType Ty, - CodeGenFunction &CGF) const { - // FIXME: Implement - return 0; -} - - -ABIArgInfo SystemZABIInfo::classifyReturnType(QualType RetTy, - ASTContext &Context, - llvm::LLVMContext &VMContext) const { - if (RetTy->isVoidType()) { - return ABIArgInfo::getIgnore(); - } else if (CodeGenFunction::hasAggregateLLVMType(RetTy)) { - return ABIArgInfo::getIndirect(0); - } else { - return (isPromotableIntegerType(RetTy) ? - ABIArgInfo::getExtend() : ABIArgInfo::getDirect()); - } -} - -ABIArgInfo SystemZABIInfo::classifyArgumentType(QualType Ty, - ASTContext &Context, - llvm::LLVMContext &VMContext) const { - if (CodeGenFunction::hasAggregateLLVMType(Ty)) { - return ABIArgInfo::getIndirect(0); - } else { - return (isPromotableIntegerType(Ty) ? - ABIArgInfo::getExtend() : ABIArgInfo::getDirect()); - } -} - -ABIArgInfo DefaultABIInfo::classifyArgumentType(QualType Ty, - ASTContext &Context, - llvm::LLVMContext &VMContext) const { - if (CodeGenFunction::hasAggregateLLVMType(Ty)) { - return ABIArgInfo::getIndirect(0); - } else { - return (Ty->isPromotableIntegerType() ? - ABIArgInfo::getExtend() : ABIArgInfo::getDirect()); - } -} - -llvm::Value *DefaultABIInfo::EmitVAArg(llvm::Value *VAListAddr, QualType Ty, - CodeGenFunction &CGF) const { - return 0; -} - -const ABIInfo &CodeGenTypes::getABIInfo() const { - if (TheABIInfo) - return *TheABIInfo; - - // For now we just cache the ABIInfo in CodeGenTypes and don't free it. - - const llvm::Triple &Triple(getContext().Target.getTriple()); - switch (Triple.getArch()) { - default: - return *(TheABIInfo = new DefaultABIInfo); - - case llvm::Triple::arm: - case llvm::Triple::thumb: - // FIXME: We want to know the float calling convention as well. - if (strcmp(getContext().Target.getABI(), "apcs-gnu") == 0) - return *(TheABIInfo = new ARMABIInfo(ARMABIInfo::APCS)); - - return *(TheABIInfo = new ARMABIInfo(ARMABIInfo::AAPCS)); - - case llvm::Triple::pic16: - return *(TheABIInfo = new PIC16ABIInfo()); - - case llvm::Triple::systemz: - return *(TheABIInfo = new SystemZABIInfo()); - - case llvm::Triple::x86: - switch (Triple.getOS()) { - case llvm::Triple::Darwin: - return *(TheABIInfo = new X86_32ABIInfo(Context, true, true)); - case llvm::Triple::Cygwin: - case llvm::Triple::MinGW32: - case llvm::Triple::MinGW64: - case llvm::Triple::AuroraUX: - case llvm::Triple::DragonFly: - case llvm::Triple::FreeBSD: - case llvm::Triple::OpenBSD: - return *(TheABIInfo = new X86_32ABIInfo(Context, false, true)); - - default: - return *(TheABIInfo = new X86_32ABIInfo(Context, false, false)); - } - - case llvm::Triple::x86_64: - return *(TheABIInfo = new X86_64ABIInfo()); - } -} diff --git a/lib/CodeGen/TargetInfo.cpp b/lib/CodeGen/TargetInfo.cpp index e5fd47e..4454662 100644 --- a/lib/CodeGen/TargetInfo.cpp +++ b/lib/CodeGen/TargetInfo.cpp @@ -257,7 +257,7 @@ class DefaultABIInfo : public ABIInfo { class DefaultTargetCodeGenInfo : public TargetCodeGenInfo { public: - DefaultTargetCodeGenInfo():TargetCodeGenInfo(new DefaultABIInfo()) {}; + DefaultTargetCodeGenInfo():TargetCodeGenInfo(new DefaultABIInfo()) {} }; llvm::Value *DefaultABIInfo::EmitVAArg(llvm::Value *VAListAddr, QualType Ty, @@ -320,7 +320,7 @@ public: class X86_32TargetCodeGenInfo : public TargetCodeGenInfo { public: X86_32TargetCodeGenInfo(ASTContext &Context, bool d, bool p) - :TargetCodeGenInfo(new X86_32ABIInfo(Context, d, p)) {}; + :TargetCodeGenInfo(new X86_32ABIInfo(Context, d, p)) {} }; } @@ -619,7 +619,7 @@ public: class X86_64TargetCodeGenInfo : public TargetCodeGenInfo { public: - X86_64TargetCodeGenInfo():TargetCodeGenInfo(new X86_64ABIInfo()) {}; + X86_64TargetCodeGenInfo():TargetCodeGenInfo(new X86_64ABIInfo()) {} }; } @@ -1428,7 +1428,7 @@ class PIC16ABIInfo : public ABIInfo { class PIC16TargetCodeGenInfo : public TargetCodeGenInfo { public: - PIC16TargetCodeGenInfo():TargetCodeGenInfo(new PIC16ABIInfo()) {}; + PIC16TargetCodeGenInfo():TargetCodeGenInfo(new PIC16ABIInfo()) {} }; } @@ -1493,7 +1493,7 @@ private: class ARMTargetCodeGenInfo : public TargetCodeGenInfo { public: ARMTargetCodeGenInfo(ARMABIInfo::ABIKind K) - :TargetCodeGenInfo(new ARMABIInfo(K)) {}; + :TargetCodeGenInfo(new ARMABIInfo(K)) {} }; } @@ -1754,7 +1754,7 @@ class SystemZABIInfo : public ABIInfo { class SystemZTargetCodeGenInfo : public TargetCodeGenInfo { public: - SystemZTargetCodeGenInfo():TargetCodeGenInfo(new SystemZABIInfo()) {}; + SystemZTargetCodeGenInfo():TargetCodeGenInfo(new SystemZABIInfo()) {} }; } @@ -1816,7 +1816,7 @@ namespace { class MSP430TargetCodeGenInfo : public TargetCodeGenInfo { public: - MSP430TargetCodeGenInfo():TargetCodeGenInfo(new DefaultABIInfo()) {}; + MSP430TargetCodeGenInfo():TargetCodeGenInfo(new DefaultABIInfo()) {} void SetTargetAttributes(const Decl *D, llvm::GlobalValue *GV, CodeGen::CodeGenModule &M) const; }; diff --git a/lib/CodeGen/TargetInfo.h b/lib/CodeGen/TargetInfo.h index 495b22f..58b7b79 100644 --- a/lib/CodeGen/TargetInfo.h +++ b/lib/CodeGen/TargetInfo.h @@ -34,7 +34,7 @@ namespace clang { ABIInfo *Info; public: // WARNING: Acquires the ownership of ABIInfo. - TargetCodeGenInfo(ABIInfo *info = 0):Info(info) { }; + TargetCodeGenInfo(ABIInfo *info = 0):Info(info) { } virtual ~TargetCodeGenInfo(); /// getABIInfo() - Returns ABI info helper for the target. @@ -43,7 +43,7 @@ namespace clang { /// SetTargetAttributes - Provides a convenient hook to handle extra /// target-specific attributes for the given global. virtual void SetTargetAttributes(const Decl *D, llvm::GlobalValue *GV, - CodeGen::CodeGenModule &M) const { }; + CodeGen::CodeGenModule &M) const { } }; } diff --git a/lib/Driver/Driver.cpp b/lib/Driver/Driver.cpp index ab4bd49..852a018 100644 --- a/lib/Driver/Driver.cpp +++ b/lib/Driver/Driver.cpp @@ -26,6 +26,7 @@ #include "clang/Basic/Version.h" #include "llvm/ADT/StringSet.h" +#include "llvm/ADT/OwningPtr.h" #include "llvm/Support/PrettyStackTrace.h" #include "llvm/Support/raw_ostream.h" #include "llvm/System/Path.h" @@ -66,6 +67,14 @@ Driver::Driver(llvm::StringRef _Name, llvm::StringRef _Dir, CCCUseClangCXX = false; } + + // Compute the path to the resource directory. + llvm::sys::Path P(Dir); + P.eraseComponent(); // Remove /bin from foo/bin + P.appendComponent("lib"); + P.appendComponent("clang"); + P.appendComponent(CLANG_VERSION_STRING); + ResourceDir = P.str(); } Driver::~Driver() { @@ -273,15 +282,7 @@ void Driver::PrintHelp(bool ShowHidden) const { void Driver::PrintVersion(const Compilation &C, llvm::raw_ostream &OS) const { // FIXME: The following handlers should use a callback mechanism, we don't // know what the client would like to do. -#ifdef CLANG_VENDOR - OS << CLANG_VENDOR; -#endif - OS << "clang version " CLANG_VERSION_STRING " (" - << getClangSubversionPath(); - if (unsigned Revision = getClangSubversionRevision()) - OS << " " << Revision; - OS << ")" << '\n'; - + OS << getClangFullVersion() << '\n'; const ToolChain &TC = C.getDefaultToolChain(); OS << "Target: " << TC.getTripleString() << '\n'; @@ -675,7 +676,7 @@ void Driver::BuildActions(const ArgList &Args, ActionList &Actions) const { } // Build the pipeline for this file. - Action *Current = new InputAction(*InputArg, InputType); + llvm::OwningPtr<Action> Current(new InputAction(*InputArg, InputType)); for (unsigned i = 0; i != NumSteps; ++i) { phases::ID Phase = types::getCompilationPhase(InputType, i); @@ -686,8 +687,7 @@ void Driver::BuildActions(const ArgList &Args, ActionList &Actions) const { // Queue linker inputs. if (Phase == phases::Link) { assert(i + 1 == NumSteps && "linking must be final compilation step."); - LinkerInputs.push_back(Current); - Current = 0; + LinkerInputs.push_back(Current.take()); break; } @@ -698,14 +698,14 @@ void Driver::BuildActions(const ArgList &Args, ActionList &Actions) const { continue; // Otherwise construct the appropriate action. - Current = ConstructPhaseAction(Args, Phase, Current); + Current.reset(ConstructPhaseAction(Args, Phase, Current.take())); if (Current->getType() == types::TY_Nothing) break; } // If we ended with something, add to the output list. if (Current) - Actions.push_back(Current); + Actions.push_back(Current.take()); } // Add a link action if necessary. diff --git a/lib/Driver/Makefile b/lib/Driver/Makefile index 4c3ca5c..dbacf8b 100644 --- a/lib/Driver/Makefile +++ b/lib/Driver/Makefile @@ -13,8 +13,5 @@ BUILD_ARCHIVE = 1 CXXFLAGS = -fno-rtti CPPFLAGS += -I$(PROJ_SRC_DIR)/../../include -I$(PROJ_OBJ_DIR)/../../include -ifdef CLANG_VENDOR -CPPFLAGS += -DCLANG_VENDOR='"$(CLANG_VENDOR) "' -endif include $(LEVEL)/Makefile.common diff --git a/lib/Driver/ToolChains.cpp b/lib/Driver/ToolChains.cpp index 42657d9..a9c6a68 100644 --- a/lib/Driver/ToolChains.cpp +++ b/lib/Driver/ToolChains.cpp @@ -47,6 +47,69 @@ Darwin::Darwin(const HostInfo &Host, const llvm::Triple& Triple, IPhoneOSVersionMin = "3.0"; } +// FIXME: Can we tablegen this? +static const char *GetArmArchForMArch(llvm::StringRef Value) { + if (Value == "armv6k") + return "armv6"; + + if (Value == "armv5tej") + return "armv5"; + + if (Value == "xscale") + return "xscale"; + + if (Value == "armv4t") + return "armv4t"; + + if (Value == "armv7" || Value == "armv7-a" || Value == "armv7-r" || + Value == "armv7-m" || Value == "armv7a" || Value == "armv7r" || + Value == "armv7m") + return "armv7"; + + return 0; +} + +// FIXME: Can we tablegen this? +static const char *GetArmArchForMCpu(llvm::StringRef Value) { + if (Value == "arm10tdmi" || Value == "arm1020t" || Value == "arm9e" || + Value == "arm946e-s" || Value == "arm966e-s" || + Value == "arm968e-s" || Value == "arm10e" || + Value == "arm1020e" || Value == "arm1022e" || Value == "arm926ej-s" || + Value == "arm1026ej-s") + return "armv5"; + + if (Value == "xscale") + return "xscale"; + + if (Value == "arm1136j-s" || Value == "arm1136jf-s" || + Value == "arm1176jz-s" || Value == "arm1176jzf-s") + return "armv6"; + + if (Value == "cortex-a8" || Value == "cortex-r4" || Value == "cortex-m3") + return "armv7"; + + return 0; +} + +llvm::StringRef Darwin::getDarwinArchName(const ArgList &Args) const { + switch (getTriple().getArch()) { + default: + return getArchName(); + + case llvm::Triple::arm: { + if (const Arg *A = Args.getLastArg(options::OPT_march_EQ)) + if (const char *Arch = GetArmArchForMArch(A->getValue(Args))) + return Arch; + + if (const Arg *A = Args.getLastArg(options::OPT_mcpu_EQ)) + if (const char *Arch = GetArmArchForMCpu(A->getValue(Args))) + return Arch; + + return "arm"; + } + } +} + DarwinGCC::DarwinGCC(const HostInfo &Host, const llvm::Triple& Triple, const unsigned (&DarwinVersion)[3], const unsigned (&_GCCVersion)[3], bool IsIPhoneOS) @@ -118,10 +181,6 @@ DarwinGCC::DarwinGCC(const HostInfo &Host, const llvm::Triple& Triple, Path += ToolChainDir; getProgramPaths().push_back(Path); - Path = getDriver().Dir; - Path += "/../libexec"; - getProgramPaths().push_back(Path); - getProgramPaths().push_back(getDriver().Dir); } @@ -235,13 +294,6 @@ DarwinClang::DarwinClang(const HostInfo &Host, const llvm::Triple& Triple, bool IsIPhoneOS) : Darwin(Host, Triple, DarwinVersion, IsIPhoneOS) { - // Add the relative libexec dir (for clang-cc). - // - // FIXME: We should sink clang-cc into libexec/clang/<version>/. - std::string Path = getDriver().Dir; - Path += "/../libexec"; - getProgramPaths().push_back(Path); - // We expect 'as', 'ld', etc. to be adjacent to our install dir. getProgramPaths().push_back(getDriver().Dir); } @@ -253,12 +305,10 @@ void DarwinClang::AddLinkSearchPathArgs(const ArgList &Args, void DarwinClang::AddLinkRuntimeLibArgs(const ArgList &Args, ArgStringList &CmdArgs) const { - // Check for static linking. - if (Args.hasArg(options::OPT_static)) { - // FIXME: We need to have compiler-rt available (perhaps as - // libclang_static.a) to link against. + // Darwin doesn't support real static executables, don't link any runtime + // libraries with -static. + if (Args.hasArg(options::OPT_static)) return; - } // Reject -static-libgcc for now, we can deal with this when and if someone // cares. This is useful in situations where someone wants to statically link @@ -269,12 +319,52 @@ void DarwinClang::AddLinkRuntimeLibArgs(const ArgList &Args, return; } - // Otherwise link libSystem, which should have the support routines. - // - // FIXME: This is only true for 10.6 and beyond. Legacy support isn't - // critical, but it should work... we should just link in the static - // compiler-rt library. + // Otherwise link libSystem, then the dynamic runtime library, and finally any + // target specific static runtime library. CmdArgs.push_back("-lSystem"); + + // Select the dynamic runtime library and the target specific static library. + const char *DarwinStaticLib = 0; + if (isIPhoneOS()) { + CmdArgs.push_back("-lgcc_s.1"); + + // We may need some static functions for armv6/thumb which are required to + // be in the same linkage unit as their caller. + if (getDarwinArchName(Args) == "armv6") + DarwinStaticLib = "libclang_rt.armv6.a"; + } else { + unsigned MacosxVersionMin[3]; + getMacosxVersionMin(Args, MacosxVersionMin); + + // The dynamic runtime library was merged with libSystem for 10.6 and + // beyond; only 10.4 and 10.5 need an additional runtime library. + if (isMacosxVersionLT(MacosxVersionMin, 10, 5)) + CmdArgs.push_back("-lgcc_s.10.4"); + else if (isMacosxVersionLT(MacosxVersionMin, 10, 6)) + CmdArgs.push_back("-lgcc_s.10.5"); + + // For OS X, we only need a static runtime library when targetting 10.4, to + // provide versions of the static functions which were omitted from + // 10.4.dylib. + if (isMacosxVersionLT(MacosxVersionMin, 10, 5)) + DarwinStaticLib = "libclang_rt.10.4.a"; + } + + /// Add the target specific static library, if needed. + if (DarwinStaticLib) { + llvm::sys::Path P(getDriver().ResourceDir); + P.appendComponent("lib"); + P.appendComponent("darwin"); + P.appendComponent(DarwinStaticLib); + + // For now, allow missing resource libraries to support developers who may + // not have compiler-rt checked out or integrated into their build. + if (!P.exists()) + getDriver().Diag(clang::diag::warn_drv_missing_resource_library) + << P.str(); + else + CmdArgs.push_back(Args.MakeArgString(P.str())); + } } void Darwin::getMacosxVersionMin(const ArgList &Args, @@ -544,10 +634,6 @@ const char *Darwin::GetForcedPicModel() const { Generic_GCC::Generic_GCC(const HostInfo &Host, const llvm::Triple& Triple) : ToolChain(Host, Triple) { - std::string Path(getDriver().Dir); - Path += "/../libexec"; - getProgramPaths().push_back(Path); - getProgramPaths().push_back(getDriver().Dir); } @@ -684,11 +770,6 @@ Tool &FreeBSD::SelectTool(const Compilation &C, const JobAction &JA) const { AuroraUX::AuroraUX(const HostInfo &Host, const llvm::Triple& Triple) : Generic_GCC(Host, Triple) { - // Path mangling to find libexec - std::string Path(getDriver().Dir); - - Path += "/../libexec"; - getProgramPaths().push_back(Path); getProgramPaths().push_back(getDriver().Dir); getFilePaths().push_back(getDriver().Dir + "/../lib"); @@ -753,10 +834,6 @@ DragonFly::DragonFly(const HostInfo &Host, const llvm::Triple& Triple) : Generic_GCC(Host, Triple) { // Path mangling to find libexec - std::string Path(getDriver().Dir); - - Path += "/../libexec"; - getProgramPaths().push_back(Path); getProgramPaths().push_back(getDriver().Dir); getFilePaths().push_back(getDriver().Dir + "/../lib"); diff --git a/lib/Driver/ToolChains.h b/lib/Driver/ToolChains.h index 374ad8c..3ca6ad8 100644 --- a/lib/Driver/ToolChains.h +++ b/lib/Driver/ToolChains.h @@ -85,6 +85,11 @@ public: Res[2] = DarwinVersion[1]; } + /// getDarwinArchName - Get the "Darwin" arch name for a particular compiler + /// invocation. For example, Darwin treats different ARM variations as + /// distinct architectures. + llvm::StringRef getDarwinArchName(const ArgList &Args) const; + /// getMacosxVersionMin - Get the effective -mmacosx-version-min, which is /// either the -mmacosx-version-min, or the current version if unspecified. void getMacosxVersionMin(const ArgList &Args, unsigned (&Res)[3]) const; diff --git a/lib/Driver/Tools.cpp b/lib/Driver/Tools.cpp index 010953d..afb22a2 100644 --- a/lib/Driver/Tools.cpp +++ b/lib/Driver/Tools.cpp @@ -9,7 +9,6 @@ #include "Tools.h" -#include "clang/Basic/Version.h" #include "clang/Driver/Action.h" #include "clang/Driver/Arg.h" #include "clang/Driver/ArgList.h" @@ -864,15 +863,8 @@ void Clang::ConstructJob(Compilation &C, const JobAction &JA, Args.AddLastArg(CmdArgs, options::OPT_nobuiltininc); // Pass the path to compiler resource files. - // - // FIXME: Get this from a configuration object. - llvm::sys::Path P(D.Dir); - P.eraseComponent(); // Remove /bin from foo/bin - P.appendComponent("lib"); - P.appendComponent("clang"); - P.appendComponent(CLANG_VERSION_STRING); CmdArgs.push_back("-resource-dir"); - CmdArgs.push_back(Args.MakeArgString(P.str())); + CmdArgs.push_back(D.ResourceDir.c_str()); // Add preprocessing options like -I, -D, etc. if we are using the // preprocessor. @@ -1857,87 +1849,17 @@ static bool isSourceSuffix(const char *Str) { .Default(false); } -// FIXME: Can we tablegen this? -static const char *GetArmArchForMArch(llvm::StringRef Value) { - if (Value == "armv6k") - return "armv6"; - - if (Value == "armv5tej") - return "armv5"; - - if (Value == "xscale") - return "xscale"; - - if (Value == "armv4t") - return "armv4t"; - - if (Value == "armv7" || Value == "armv7-a" || Value == "armv7-r" || - Value == "armv7-m" || Value == "armv7a" || Value == "armv7r" || - Value == "armv7m") - return "armv7"; - - return 0; -} - -// FIXME: Can we tablegen this? -static const char *GetArmArchForMCpu(llvm::StringRef Value) { - if (Value == "arm10tdmi" || Value == "arm1020t" || Value == "arm9e" || - Value == "arm946e-s" || Value == "arm966e-s" || - Value == "arm968e-s" || Value == "arm10e" || - Value == "arm1020e" || Value == "arm1022e" || Value == "arm926ej-s" || - Value == "arm1026ej-s") - return "armv5"; - - if (Value == "xscale") - return "xscale"; - - if (Value == "arm1136j-s" || Value == "arm1136jf-s" || - Value == "arm1176jz-s" || Value == "arm1176jzf-s") - return "armv6"; - - if (Value == "cortex-a8" || Value == "cortex-r4" || Value == "cortex-m3") - return "armv7"; - - return 0; -} - void darwin::DarwinTool::AddDarwinArch(const ArgList &Args, ArgStringList &CmdArgs) const { + llvm::StringRef ArchName = getDarwinToolChain().getDarwinArchName(Args); + // Derived from darwin_arch spec. CmdArgs.push_back("-arch"); + CmdArgs.push_back(Args.MakeArgString(ArchName)); - switch (getToolChain().getTriple().getArch()) { - default: - CmdArgs.push_back(Args.MakeArgString(getToolChain().getArchName())); - break; - - case llvm::Triple::arm: { - if (const Arg *A = Args.getLastArg(options::OPT_march_EQ)) { - if (const char *Arch = GetArmArchForMArch(A->getValue(Args))) { - CmdArgs.push_back(Arch); - return; - } - } - - if (const Arg *A = Args.getLastArg(options::OPT_mcpu_EQ)) { - if (const char *Arch = GetArmArchForMCpu(A->getValue(Args))) { - CmdArgs.push_back(Arch); - return; - } - } - - CmdArgs.push_back("arm"); + // FIXME: Is this needed anymore? + if (ArchName == "arm") CmdArgs.push_back("-force_cpusubtype_ALL"); - return; - } - } -} - -void darwin::DarwinTool::AddDarwinSubArch(const ArgList &Args, - ArgStringList &CmdArgs) const { - // Derived from darwin_subarch spec, not sure what the distinction - // exists for but at least for this chain it is the same. - AddDarwinArch(Args, CmdArgs); } void darwin::Link::AddLinkArgs(const ArgList &Args, @@ -1954,11 +1876,9 @@ void darwin::Link::AddLinkArgs(const ArgList &Args, } if (!Args.hasArg(options::OPT_dynamiclib)) { - if (Args.hasArg(options::OPT_force__cpusubtype__ALL)) { - AddDarwinArch(Args, CmdArgs); - CmdArgs.push_back("-force_cpusubtype_ALL"); - } else - AddDarwinSubArch(Args, CmdArgs); + AddDarwinArch(Args, CmdArgs); + // FIXME: Why do this only on this path? + Args.AddLastArg(CmdArgs, options::OPT_force__cpusubtype__ALL); Args.AddLastArg(CmdArgs, options::OPT_bundle); Args.AddAllArgs(CmdArgs, options::OPT_bundle__loader); @@ -1992,11 +1912,7 @@ void darwin::Link::AddLinkArgs(const ArgList &Args, Args.AddAllArgsTranslated(CmdArgs, options::OPT_current__version, "-dylib_current_version"); - if (Args.hasArg(options::OPT_force__cpusubtype__ALL)) { - AddDarwinArch(Args, CmdArgs); - // NOTE: We don't add -force_cpusubtype_ALL on this path. Ok. - } else - AddDarwinSubArch(Args, CmdArgs); + AddDarwinArch(Args, CmdArgs); Args.AddAllArgsTranslated(CmdArgs, options::OPT_install__name, "-dylib_install_name"); diff --git a/lib/Driver/Tools.h b/lib/Driver/Tools.h index 8f7da52..abd8cfc 100644 --- a/lib/Driver/Tools.h +++ b/lib/Driver/Tools.h @@ -130,7 +130,6 @@ namespace darwin { class VISIBILITY_HIDDEN DarwinTool : public Tool { protected: void AddDarwinArch(const ArgList &Args, ArgStringList &CmdArgs) const; - void AddDarwinSubArch(const ArgList &Args, ArgStringList &CmdArgs) const; const toolchains::Darwin &getDarwinToolChain() const { return reinterpret_cast<const toolchains::Darwin&>(getToolChain()); diff --git a/lib/Frontend/ASTConsumers.cpp b/lib/Frontend/ASTConsumers.cpp index 52b597e..33cb94e 100644 --- a/lib/Frontend/ASTConsumers.cpp +++ b/lib/Frontend/ASTConsumers.cpp @@ -421,6 +421,11 @@ void DeclContextPrinter::PrintDeclContext(const DeclContext* DC, Out << "<namespace alias> " << NAD->getNameAsString() << "\n"; break; } + case Decl::ClassTemplate: { + ClassTemplateDecl *CTD = cast<ClassTemplateDecl>(*I); + Out << "<class template> " << CTD->getNameAsString() << '\n'; + break; + } default: Out << "DeclKind: " << DK << '"' << I->getDeclKindName() << "\"\n"; assert(0 && "decl unhandled"); diff --git a/lib/Frontend/ASTUnit.cpp b/lib/Frontend/ASTUnit.cpp index 48296c7..2fb47cb 100644 --- a/lib/Frontend/ASTUnit.cpp +++ b/lib/Frontend/ASTUnit.cpp @@ -30,6 +30,7 @@ #include "clang/Basic/TargetOptions.h" #include "clang/Basic/TargetInfo.h" #include "clang/Basic/Diagnostic.h" +#include "llvm/Support/MemoryBuffer.h" #include "llvm/System/Host.h" #include "llvm/System/Path.h" using namespace clang; @@ -103,11 +104,31 @@ const std::string &ASTUnit::getPCHFileName() { ASTUnit *ASTUnit::LoadFromPCHFile(const std::string &Filename, Diagnostic &Diags, bool OnlyLocalDecls, - bool UseBumpAllocator) { + bool UseBumpAllocator, + RemappedFile *RemappedFiles, + unsigned NumRemappedFiles) { llvm::OwningPtr<ASTUnit> AST(new ASTUnit(true)); AST->OnlyLocalDecls = OnlyLocalDecls; AST->HeaderInfo.reset(new HeaderSearch(AST->getFileManager())); + for (unsigned I = 0; I != NumRemappedFiles; ++I) { + // Create the file entry for the file that we're mapping from. + const FileEntry *FromFile + = AST->getFileManager().getVirtualFile(RemappedFiles[I].first, + RemappedFiles[I].second->getBufferSize(), + 0); + if (!FromFile) { + Diags.Report(diag::err_fe_remap_missing_from_file) + << RemappedFiles[I].first; + continue; + } + + // Override the contents of the "from" file with the contents of + // the "to" file. + AST->getSourceManager().overrideFileContents(FromFile, + RemappedFiles[I].second); + } + // Gather Info for preprocessor construction later on. LangOptions LangInfo; @@ -289,7 +310,9 @@ ASTUnit *ASTUnit::LoadFromCommandLine(const char **ArgBegin, Diagnostic &Diags, llvm::StringRef ResourceFilesPath, bool OnlyLocalDecls, - bool UseBumpAllocator) { + bool UseBumpAllocator, + RemappedFile *RemappedFiles, + unsigned NumRemappedFiles) { llvm::SmallVector<const char *, 16> Args; Args.push_back("<clang>"); // FIXME: Remove dummy argument. Args.insert(Args.end(), ArgBegin, ArgEnd); @@ -327,6 +350,11 @@ ASTUnit *ASTUnit::LoadFromCommandLine(const char **ArgBegin, (const char**) CCArgs.data()+CCArgs.size(), Diags); + // Override any files that need remapping + for (unsigned I = 0; I != NumRemappedFiles; ++I) + CI.getPreprocessorOpts().addRemappedFile(RemappedFiles[I].first, + RemappedFiles[I].second); + // Override the resources path. CI.getHeaderSearchOpts().ResourceDir = ResourceFilesPath; diff --git a/lib/Frontend/AnalysisConsumer.cpp b/lib/Frontend/AnalysisConsumer.cpp index ad152d3..45a3b15 100644 --- a/lib/Frontend/AnalysisConsumer.cpp +++ b/lib/Frontend/AnalysisConsumer.cpp @@ -204,45 +204,47 @@ namespace llvm { void AnalysisConsumer::HandleTopLevelSingleDecl(Decl *D) { switch (D->getKind()) { - case Decl::Function: { - FunctionDecl* FD = cast<FunctionDecl>(D); + case Decl::Function: { + FunctionDecl* FD = cast<FunctionDecl>(D); - if (!Opts.AnalyzeSpecificFunction.empty() && - Opts.AnalyzeSpecificFunction != FD->getIdentifier()->getName()) - break; - - Stmt* Body = FD->getBody(); - if (Body) HandleCode(FD, Body, FunctionActions); + if (!Opts.AnalyzeSpecificFunction.empty() && + Opts.AnalyzeSpecificFunction != FD->getIdentifier()->getName()) break; - } - case Decl::ObjCMethod: { - ObjCMethodDecl* MD = cast<ObjCMethodDecl>(D); + Stmt* Body = FD->getBody(); + if (Body) HandleCode(FD, Body, FunctionActions); + break; + } - if (Opts.AnalyzeSpecificFunction.size() > 0 && - Opts.AnalyzeSpecificFunction != MD->getSelector().getAsString()) - return; + case Decl::ObjCMethod: { + ObjCMethodDecl* MD = cast<ObjCMethodDecl>(D); - Stmt* Body = MD->getBody(); - if (Body) HandleCode(MD, Body, ObjCMethodActions); - break; - } + if (Opts.AnalyzeSpecificFunction.size() > 0 && + Opts.AnalyzeSpecificFunction != MD->getSelector().getAsString()) + return; + + Stmt* Body = MD->getBody(); + if (Body) HandleCode(MD, Body, ObjCMethodActions); + break; + } - case Decl::CXXMethod: { - CXXMethodDecl *CXXMD = cast<CXXMethodDecl>(D); + case Decl::CXXConstructor: + case Decl::CXXDestructor: + case Decl::CXXConversion: + case Decl::CXXMethod: { + CXXMethodDecl *CXXMD = cast<CXXMethodDecl>(D); - if (Opts.AnalyzeSpecificFunction.size() > 0 && - Opts.AnalyzeSpecificFunction != CXXMD->getName()) - return; + if (Opts.AnalyzeSpecificFunction.size() > 0 && + Opts.AnalyzeSpecificFunction != CXXMD->getName()) + return; - Stmt *Body = CXXMD->getBody(); - if (Body) - HandleCode(CXXMD, Body, FunctionActions); - break; - } + Stmt *Body = CXXMD->getBody(); + if (Body) HandleCode(CXXMD, Body, FunctionActions); + break; + } - default: - break; + default: + break; } } @@ -409,20 +411,20 @@ static void ActionCheckerCFRef(AnalysisConsumer &C, AnalysisManager& mgr, Decl *D) { switch (mgr.getLangOptions().getGCMode()) { - default: - assert (false && "Invalid GC mode."); - case LangOptions::NonGC: - ActionCheckerCFRefAux(C, mgr, D, false); - break; - - case LangOptions::GCOnly: - ActionCheckerCFRefAux(C, mgr, D, true); - break; - - case LangOptions::HybridGC: - ActionCheckerCFRefAux(C, mgr, D, false); - ActionCheckerCFRefAux(C, mgr, D, true); - break; + default: + assert (false && "Invalid GC mode."); + case LangOptions::NonGC: + ActionCheckerCFRefAux(C, mgr, D, false); + break; + + case LangOptions::GCOnly: + ActionCheckerCFRefAux(C, mgr, D, true); + break; + + case LangOptions::HybridGC: + ActionCheckerCFRefAux(C, mgr, D, false); + ActionCheckerCFRefAux(C, mgr, D, true); + break; } } @@ -530,11 +532,11 @@ ASTConsumer* clang::CreateAnalysisConsumer(const Preprocessor& pp, for (unsigned i = 0; i < Opts.AnalysisList.size(); ++i) switch (Opts.AnalysisList[i]) { #define ANALYSIS(NAME, CMD, DESC, SCOPE)\ - case NAME:\ - C->add ## SCOPE ## Action(&Action ## NAME);\ - break; + case NAME:\ + C->add ## SCOPE ## Action(&Action ## NAME);\ + break; #include "clang/Frontend/Analyses.def" - default: break; + default: break; } // Last, disable the effects of '-Werror' when using the AnalysisConsumer. diff --git a/lib/Frontend/CacheTokens.cpp b/lib/Frontend/CacheTokens.cpp index 7296246..7326937 100644 --- a/lib/Frontend/CacheTokens.cpp +++ b/lib/Frontend/CacheTokens.cpp @@ -77,25 +77,25 @@ public: void EmitData(llvm::raw_ostream& Out) { switch (Kind) { - case IsFE: - // Emit stat information. - ::Emit32(Out, FE->getInode()); - ::Emit32(Out, FE->getDevice()); - ::Emit16(Out, FE->getFileMode()); - ::Emit64(Out, FE->getModificationTime()); - ::Emit64(Out, FE->getSize()); - break; - case IsDE: - // Emit stat information. - ::Emit32(Out, (uint32_t) StatBuf->st_ino); - ::Emit32(Out, (uint32_t) StatBuf->st_dev); - ::Emit16(Out, (uint16_t) StatBuf->st_mode); - ::Emit64(Out, (uint64_t) StatBuf->st_mtime); - ::Emit64(Out, (uint64_t) StatBuf->st_size); - delete StatBuf; - break; - default: - break; + case IsFE: + // Emit stat information. + ::Emit32(Out, FE->getInode()); + ::Emit32(Out, FE->getDevice()); + ::Emit16(Out, FE->getFileMode()); + ::Emit64(Out, FE->getModificationTime()); + ::Emit64(Out, FE->getSize()); + break; + case IsDE: + // Emit stat information. + ::Emit32(Out, (uint32_t) StatBuf->st_ino); + ::Emit32(Out, (uint32_t) StatBuf->st_dev); + ::Emit16(Out, (uint16_t) StatBuf->st_mode); + ::Emit64(Out, (uint64_t) StatBuf->st_mtime); + ::Emit64(Out, (uint64_t) StatBuf->st_size); + delete StatBuf; + break; + default: + break; } } diff --git a/lib/Frontend/DeclXML.cpp b/lib/Frontend/DeclXML.cpp index b981fc4..d7470d9 100644 --- a/lib/Frontend/DeclXML.cpp +++ b/lib/Frontend/DeclXML.cpp @@ -98,14 +98,14 @@ public: const char* pAttributeName = NAME; \ const bool optional = false; \ switch (T->FN) { \ - default: assert(0 && "unknown enum value"); + default: assert(0 && "unknown enum value"); #define ATTRIBUTE_ENUM_OPT_XML( FN, NAME ) \ { \ const char* pAttributeName = NAME; \ const bool optional = true; \ switch (T->FN) { \ - default: assert(0 && "unknown enum value"); + default: assert(0 && "unknown enum value"); #define ENUM_XML( VALUE, NAME ) case VALUE: if ((!optional) || NAME[0]) Doc.addAttribute(pAttributeName, NAME); break; #define END_ENUM_XML } } diff --git a/lib/Frontend/HTMLDiagnostics.cpp b/lib/Frontend/HTMLDiagnostics.cpp index 93421ca..b163e26 100644 --- a/lib/Frontend/HTMLDiagnostics.cpp +++ b/lib/Frontend/HTMLDiagnostics.cpp @@ -349,10 +349,10 @@ void HTMLDiagnostics::HandlePiece(Rewriter& R, FileID BugFileID, const char *Kind = 0; switch (P.getKind()) { - case PathDiagnosticPiece::Event: Kind = "Event"; break; - case PathDiagnosticPiece::ControlFlow: Kind = "Control"; break; - // Setting Kind to "Control" is intentional. - case PathDiagnosticPiece::Macro: Kind = "Control"; break; + case PathDiagnosticPiece::Event: Kind = "Event"; break; + case PathDiagnosticPiece::ControlFlow: Kind = "Control"; break; + // Setting Kind to "Control" is intentional. + case PathDiagnosticPiece::Macro: Kind = "Control"; break; } std::string sbuf; @@ -380,14 +380,14 @@ void HTMLDiagnostics::HandlePiece(Rewriter& R, FileID BugFileID, for (std::string::const_iterator I=Msg.begin(), E=Msg.end(); I!=E; ++I) switch (*I) { - default: - ++cnt; - continue; - case ' ': - case '\t': - case '\n': - if (cnt > max_token) max_token = cnt; - cnt = 0; + default: + ++cnt; + continue; + case ' ': + case '\t': + case '\n': + if (cnt > max_token) max_token = cnt; + cnt = 0; } if (cnt > max_token) diff --git a/lib/Frontend/InitHeaderSearch.cpp b/lib/Frontend/InitHeaderSearch.cpp index 6fceb98..6102760 100644 --- a/lib/Frontend/InitHeaderSearch.cpp +++ b/lib/Frontend/InitHeaderSearch.cpp @@ -189,10 +189,12 @@ void InitHeaderSearch::AddGnuCPlusPlusIncludePaths(llvm::StringRef Base, void InitHeaderSearch::AddMinGWCPlusPlusIncludePaths(llvm::StringRef Base, llvm::StringRef Arch, llvm::StringRef Version) { - llvm::Twine localBase = Base + "/" + Arch + "/" + Version + "/include"; - AddPath(localBase, System, true, false, false); - AddPath(localBase + "/c++", System, true, false, false); - AddPath(localBase + "/c++/backward", System, true, false, false); + AddPath(Base + "/" + Arch + "/" + Version + "/include", + System, true, false, false); + AddPath(Base + "/" + Arch + "/" + Version + "/include/c++", + System, true, false, false); + AddPath(Base + "/" + Arch + "/" + Version + "/include/c++/backward", + System, true, false, false); } // FIXME: This probably should goto to some platform utils place. @@ -206,8 +208,8 @@ void InitHeaderSearch::AddMinGWCPlusPlusIncludePaths(llvm::StringRef Base, // I.e. "HKEY_LOCAL_MACHINE\\SOFTWARE\\Microsoft\\VisualStudio\\$VERSION". // There can be additional characters in the component. Only the numberic // characters are compared. -bool getSystemRegistryString(const char *keyPath, const char *valueName, - char *value, size_t maxLength) { +static bool getSystemRegistryString(const char *keyPath, const char *valueName, + char *value, size_t maxLength) { HKEY hRootKey = NULL; HKEY hKey = NULL; const char* subKey = NULL; @@ -312,13 +314,13 @@ bool getSystemRegistryString(const char *keyPath, const char *valueName, } #else // _MSC_VER // Read registry string. -bool getSystemRegistryString(const char *, const char *, char *, size_t) { +static bool getSystemRegistryString(const char*, const char*, char*, size_t) { return(false); } #endif // _MSC_VER // Get Visual Studio installation directory. -bool getVisualStudioDir(std::string &path) { +static bool getVisualStudioDir(std::string &path) { char vsIDEInstallDir[256]; // Try the Windows registry first. bool hasVCDir = getSystemRegistryString( @@ -365,7 +367,7 @@ bool getVisualStudioDir(std::string &path) { } // Get Windows SDK installation directory. -bool getWindowsSDKDir(std::string &path) { +static bool getWindowsSDKDir(std::string &path) { char windowsSDKInstallDir[256]; // Try the Windows registry. bool hasSDKDir = getSystemRegistryString( @@ -508,6 +510,10 @@ void InitHeaderSearch::AddDefaultCPlusPlusIncludePaths(const llvm::Triple &tripl AddGnuCPlusPlusIncludePaths("/usr/include/c++/4.3.2", "i386-redhat-linux","", "", triple); + // Fedora 10 x86_64 + AddGnuCPlusPlusIncludePaths("/usr/include/c++/4.3.2", + "x86_64-redhat-linux", "32", "", triple); + // Fedora 11 AddGnuCPlusPlusIncludePaths("/usr/include/c++/4.4.1", "i586-redhat-linux","", "", triple); @@ -556,7 +562,7 @@ void InitHeaderSearch::AddDefaultCPlusPlusIncludePaths(const llvm::Triple &tripl "i686-pc-linux-gnu", "", "", triple); break; case llvm::Triple::FreeBSD: - AddPath("/usr/include/c++/4.2", System, true, false, false); + AddGnuCPlusPlusIncludePaths("/usr/include/c++/4.2", "", "", "", triple); break; case llvm::Triple::Solaris: // Solaris - Fall though.. diff --git a/lib/Frontend/InitPreprocessor.cpp b/lib/Frontend/InitPreprocessor.cpp index e4c380a..9aaf132 100644 --- a/lib/Frontend/InitPreprocessor.cpp +++ b/lib/Frontend/InitPreprocessor.cpp @@ -12,6 +12,7 @@ //===----------------------------------------------------------------------===// #include "clang/Frontend/Utils.h" +#include "clang/Basic/MacroBuilder.h" #include "clang/Basic/TargetInfo.h" #include "clang/Frontend/FrontendDiagnostic.h" #include "clang/Frontend/FrontendOptions.h" @@ -137,7 +138,10 @@ static void DefineFloatMacros(MacroBuilder &Builder, llvm::StringRef Prefix, "1.79769313486231580793728971405301e+308L", "1.18973149535723176508575932662800702e+4932L"); - llvm::Twine DefPrefix = "__" + Prefix + "_"; + llvm::SmallString<32> DefPrefix; + DefPrefix = "__"; + DefPrefix += Prefix; + DefPrefix += "_"; Builder.defineMacro(DefPrefix + "DENORM_MIN__", DenormMin); Builder.defineMacro(DefPrefix + "HAS_DENORM__"); @@ -420,40 +424,61 @@ static void InitializeFileRemapping(Diagnostic &Diags, SourceManager &SourceMgr, FileManager &FileMgr, const PreprocessorOptions &InitOpts) { - // Remap files in the source manager. + // Remap files in the source manager (with buffers). + for (PreprocessorOptions::remapped_file_buffer_iterator + Remap = InitOpts.remapped_file_buffer_begin(), + RemapEnd = InitOpts.remapped_file_buffer_end(); + Remap != RemapEnd; + ++Remap) { + // Create the file entry for the file that we're mapping from. + const FileEntry *FromFile = FileMgr.getVirtualFile(Remap->first, + Remap->second->getBufferSize(), + 0); + if (!FromFile) { + Diags.Report(diag::err_fe_remap_missing_from_file) + << Remap->first; + continue; + } + + // Override the contents of the "from" file with the contents of + // the "to" file. + SourceMgr.overrideFileContents(FromFile, Remap->second); + } + + // Remap files in the source manager (with other files). for (PreprocessorOptions::remapped_file_iterator - Remap = InitOpts.remapped_file_begin(), - RemapEnd = InitOpts.remapped_file_end(); + Remap = InitOpts.remapped_file_begin(), + RemapEnd = InitOpts.remapped_file_end(); Remap != RemapEnd; ++Remap) { // Find the file that we're mapping to. const FileEntry *ToFile = FileMgr.getFile(Remap->second); if (!ToFile) { Diags.Report(diag::err_fe_remap_missing_to_file) - << Remap->first << Remap->second; + << Remap->first << Remap->second; continue; } - + // Create the file entry for the file that we're mapping from. const FileEntry *FromFile = FileMgr.getVirtualFile(Remap->first, ToFile->getSize(), 0); if (!FromFile) { Diags.Report(diag::err_fe_remap_missing_from_file) - << Remap->first; + << Remap->first; continue; } - + // Load the contents of the file we're mapping to. std::string ErrorStr; const llvm::MemoryBuffer *Buffer - = llvm::MemoryBuffer::getFile(ToFile->getName(), &ErrorStr); + = llvm::MemoryBuffer::getFile(ToFile->getName(), &ErrorStr); if (!Buffer) { Diags.Report(diag::err_fe_error_opening) - << Remap->second << ErrorStr; + << Remap->second << ErrorStr; continue; } - + // Override the contents of the "from" file with the contents of // the "to" file. SourceMgr.overrideFileContents(FromFile, Buffer); diff --git a/lib/Frontend/PCHReader.cpp b/lib/Frontend/PCHReader.cpp index 07d5a78..2593551 100644 --- a/lib/Frontend/PCHReader.cpp +++ b/lib/Frontend/PCHReader.cpp @@ -1399,17 +1399,10 @@ PCHReader::ReadPCHBlock() { NumComments = BlobLen / sizeof(SourceRange); break; - case pch::SVN_BRANCH_REVISION: { - unsigned CurRevision = getClangSubversionRevision(); - if (Record[0] && CurRevision && Record[0] != CurRevision) { - Diag(Record[0] < CurRevision? diag::warn_pch_version_too_old - : diag::warn_pch_version_too_new); - return IgnorePCH; - } - - const char *CurBranch = getClangSubversionPath(); - if (strncmp(CurBranch, BlobStart, BlobLen)) { - std::string PCHBranch(BlobStart, BlobLen); + case pch::VERSION_CONTROL_BRANCH_REVISION: { + llvm::StringRef CurBranch = getClangFullRepositoryVersion(); + llvm::StringRef PCHBranch(BlobStart, BlobLen); + if (CurBranch != PCHBranch) { Diag(diag::warn_pch_different_branch) << PCHBranch << CurBranch; return IgnorePCH; } @@ -1909,18 +1902,20 @@ QualType PCHReader::ReadTypeRecord(uint64_t Offset) { } case pch::TYPE_FUNCTION_NO_PROTO: { - if (Record.size() != 2) { + if (Record.size() != 3) { Error("incorrect encoding of no-proto function type"); return QualType(); } QualType ResultType = GetType(Record[0]); - return Context->getFunctionNoProtoType(ResultType, Record[1]); + return Context->getFunctionNoProtoType(ResultType, Record[1], + (CallingConv)Record[2]); } case pch::TYPE_FUNCTION_PROTO: { QualType ResultType = GetType(Record[0]); bool NoReturn = Record[1]; - unsigned Idx = 2; + CallingConv CallConv = (CallingConv)Record[2]; + unsigned Idx = 3; unsigned NumParams = Record[Idx++]; llvm::SmallVector<QualType, 16> ParamTypes; for (unsigned I = 0; I != NumParams; ++I) @@ -1936,7 +1931,7 @@ QualType PCHReader::ReadTypeRecord(uint64_t Offset) { return Context->getFunctionType(ResultType, ParamTypes.data(), NumParams, isVariadic, Quals, hasExceptionSpec, hasAnyExceptionSpec, NumExceptions, - Exceptions.data(), NoReturn); + Exceptions.data(), NoReturn, CallConv); } case pch::TYPE_UNRESOLVED_USING: @@ -2040,7 +2035,13 @@ void TypeLocReader::VisitQualifiedTypeLoc(QualifiedTypeLoc TL) { // nothing to do } void TypeLocReader::VisitBuiltinTypeLoc(BuiltinTypeLoc TL) { - TL.setNameLoc(SourceLocation::getFromRawEncoding(Record[Idx++])); + TL.setBuiltinLoc(SourceLocation::getFromRawEncoding(Record[Idx++])); + if (TL.needsExtraLocalData()) { + TL.setWrittenTypeSpec(static_cast<DeclSpec::TST>(Record[Idx++])); + TL.setWrittenSignSpec(static_cast<DeclSpec::TSS>(Record[Idx++])); + TL.setWrittenWidthSpec(static_cast<DeclSpec::TSW>(Record[Idx++])); + TL.setModeAttr(Record[Idx++]); + } } void TypeLocReader::VisitComplexTypeLoc(ComplexTypeLoc TL) { TL.setNameLoc(SourceLocation::getFromRawEncoding(Record[Idx++])); diff --git a/lib/Frontend/PCHReaderDecl.cpp b/lib/Frontend/PCHReaderDecl.cpp index 69343ed..4dc1318 100644 --- a/lib/Frontend/PCHReaderDecl.cpp +++ b/lib/Frontend/PCHReaderDecl.cpp @@ -223,7 +223,12 @@ void PCHDeclReader::VisitObjCInterfaceDecl(ObjCInterfaceDecl *ID) { Protocols.reserve(NumProtocols); for (unsigned I = 0; I != NumProtocols; ++I) Protocols.push_back(cast<ObjCProtocolDecl>(Reader.GetDecl(Record[Idx++]))); - ID->setProtocolList(Protocols.data(), NumProtocols, *Reader.getContext()); + llvm::SmallVector<SourceLocation, 16> ProtoLocs; + ProtoLocs.reserve(NumProtocols); + for (unsigned I = 0; I != NumProtocols; ++I) + ProtoLocs.push_back(SourceLocation::getFromRawEncoding(Record[Idx++])); + ID->setProtocolList(Protocols.data(), NumProtocols, ProtoLocs.data(), + *Reader.getContext()); unsigned NumIvars = Record[Idx++]; llvm::SmallVector<ObjCIvarDecl *, 16> IVars; IVars.reserve(NumIvars); @@ -253,7 +258,12 @@ void PCHDeclReader::VisitObjCProtocolDecl(ObjCProtocolDecl *PD) { ProtoRefs.reserve(NumProtoRefs); for (unsigned I = 0; I != NumProtoRefs; ++I) ProtoRefs.push_back(cast<ObjCProtocolDecl>(Reader.GetDecl(Record[Idx++]))); - PD->setProtocolList(ProtoRefs.data(), NumProtoRefs, *Reader.getContext()); + llvm::SmallVector<SourceLocation, 16> ProtoLocs; + ProtoLocs.reserve(NumProtoRefs); + for (unsigned I = 0; I != NumProtoRefs; ++I) + ProtoLocs.push_back(SourceLocation::getFromRawEncoding(Record[Idx++])); + PD->setProtocolList(ProtoRefs.data(), NumProtoRefs, ProtoLocs.data(), + *Reader.getContext()); } void PCHDeclReader::VisitObjCAtDefsFieldDecl(ObjCAtDefsFieldDecl *FD) { @@ -282,7 +292,12 @@ void PCHDeclReader::VisitObjCForwardProtocolDecl(ObjCForwardProtocolDecl *FPD) { ProtoRefs.reserve(NumProtoRefs); for (unsigned I = 0; I != NumProtoRefs; ++I) ProtoRefs.push_back(cast<ObjCProtocolDecl>(Reader.GetDecl(Record[Idx++]))); - FPD->setProtocolList(ProtoRefs.data(), NumProtoRefs, *Reader.getContext()); + llvm::SmallVector<SourceLocation, 16> ProtoLocs; + ProtoLocs.reserve(NumProtoRefs); + for (unsigned I = 0; I != NumProtoRefs; ++I) + ProtoLocs.push_back(SourceLocation::getFromRawEncoding(Record[Idx++])); + FPD->setProtocolList(ProtoRefs.data(), NumProtoRefs, ProtoLocs.data(), + *Reader.getContext()); } void PCHDeclReader::VisitObjCCategoryDecl(ObjCCategoryDecl *CD) { @@ -293,9 +308,15 @@ void PCHDeclReader::VisitObjCCategoryDecl(ObjCCategoryDecl *CD) { ProtoRefs.reserve(NumProtoRefs); for (unsigned I = 0; I != NumProtoRefs; ++I) ProtoRefs.push_back(cast<ObjCProtocolDecl>(Reader.GetDecl(Record[Idx++]))); - CD->setProtocolList(ProtoRefs.data(), NumProtoRefs, *Reader.getContext()); + llvm::SmallVector<SourceLocation, 16> ProtoLocs; + ProtoLocs.reserve(NumProtoRefs); + for (unsigned I = 0; I != NumProtoRefs; ++I) + ProtoLocs.push_back(SourceLocation::getFromRawEncoding(Record[Idx++])); + CD->setProtocolList(ProtoRefs.data(), NumProtoRefs, ProtoLocs.data(), + *Reader.getContext()); CD->setNextClassCategory(cast_or_null<ObjCCategoryDecl>(Reader.GetDecl(Record[Idx++]))); - CD->setLocEnd(SourceLocation::getFromRawEncoding(Record[Idx++])); + CD->setAtLoc(SourceLocation::getFromRawEncoding(Record[Idx++])); + CD->setCategoryNameLoc(SourceLocation::getFromRawEncoding(Record[Idx++])); } void PCHDeclReader::VisitObjCCompatibleAliasDecl(ObjCCompatibleAliasDecl *CAD) { @@ -305,6 +326,7 @@ void PCHDeclReader::VisitObjCCompatibleAliasDecl(ObjCCompatibleAliasDecl *CAD) { void PCHDeclReader::VisitObjCPropertyDecl(ObjCPropertyDecl *D) { VisitNamedDecl(D); + D->setAtLoc(SourceLocation::getFromRawEncoding(Record[Idx++])); D->setType(Reader.GetType(Record[Idx++])); // FIXME: stable encoding D->setPropertyAttributes( @@ -671,7 +693,8 @@ Decl *PCHReader::ReadDeclRecord(uint64_t Offset, unsigned Index) { D = ObjCForwardProtocolDecl::Create(*Context, 0, SourceLocation()); break; case pch::DECL_OBJC_CATEGORY: - D = ObjCCategoryDecl::Create(*Context, 0, SourceLocation(), 0); + D = ObjCCategoryDecl::Create(*Context, 0, SourceLocation(), + SourceLocation(), SourceLocation(), 0); break; case pch::DECL_OBJC_CATEGORY_IMPL: D = ObjCCategoryImplDecl::Create(*Context, 0, SourceLocation(), 0, 0); @@ -683,7 +706,8 @@ Decl *PCHReader::ReadDeclRecord(uint64_t Offset, unsigned Index) { D = ObjCCompatibleAliasDecl::Create(*Context, 0, SourceLocation(), 0, 0); break; case pch::DECL_OBJC_PROPERTY: - D = ObjCPropertyDecl::Create(*Context, 0, SourceLocation(), 0, QualType()); + D = ObjCPropertyDecl::Create(*Context, 0, SourceLocation(), 0, SourceLocation(), + QualType()); break; case pch::DECL_OBJC_PROPERTY_IMPL: D = ObjCPropertyImplDecl::Create(*Context, 0, SourceLocation(), diff --git a/lib/Frontend/PCHReaderStmt.cpp b/lib/Frontend/PCHReaderStmt.cpp index 138f1e1..21c9cbf 100644 --- a/lib/Frontend/PCHReaderStmt.cpp +++ b/lib/Frontend/PCHReaderStmt.cpp @@ -117,6 +117,12 @@ namespace { unsigned VisitCXXOperatorCallExpr(CXXOperatorCallExpr *E); unsigned VisitCXXConstructExpr(CXXConstructExpr *E); + unsigned VisitCXXNamedCastExpr(CXXNamedCastExpr *E); + unsigned VisitCXXStaticCastExpr(CXXStaticCastExpr *E); + unsigned VisitCXXDynamicCastExpr(CXXDynamicCastExpr *E); + unsigned VisitCXXReinterpretCastExpr(CXXReinterpretCastExpr *E); + unsigned VisitCXXConstCastExpr(CXXConstCastExpr *E); + unsigned VisitCXXFunctionalCastExpr(CXXFunctionalCastExpr *E); }; } @@ -513,7 +519,7 @@ unsigned PCHStmtReader::VisitImplicitCastExpr(ImplicitCastExpr *E) { unsigned PCHStmtReader::VisitExplicitCastExpr(ExplicitCastExpr *E) { VisitCastExpr(E); - E->setTypeAsWritten(Reader.GetType(Record[Idx++])); + E->setTypeInfoAsWritten(Reader.GetTypeSourceInfo(Record, Idx)); return 1; } @@ -527,6 +533,7 @@ unsigned PCHStmtReader::VisitCStyleCastExpr(CStyleCastExpr *E) { unsigned PCHStmtReader::VisitCompoundLiteralExpr(CompoundLiteralExpr *E) { VisitExpr(E); E->setLParenLoc(SourceLocation::getFromRawEncoding(Record[Idx++])); + E->setTypeSourceInfo(Reader.GetTypeSourceInfo(Record, Idx)); E->setInitializer(cast<Expr>(StmtStack.back())); E->setFileScope(Record[Idx++]); return 1; @@ -868,6 +875,35 @@ unsigned PCHStmtReader::VisitCXXConstructExpr(CXXConstructExpr *E) { return E->getNumArgs(); } +unsigned PCHStmtReader::VisitCXXNamedCastExpr(CXXNamedCastExpr *E) { + unsigned num = VisitExplicitCastExpr(E); + E->setOperatorLoc(SourceLocation::getFromRawEncoding(Record[Idx++])); + return num; +} + +unsigned PCHStmtReader::VisitCXXStaticCastExpr(CXXStaticCastExpr *E) { + return VisitCXXNamedCastExpr(E); +} + +unsigned PCHStmtReader::VisitCXXDynamicCastExpr(CXXDynamicCastExpr *E) { + return VisitCXXNamedCastExpr(E); +} + +unsigned PCHStmtReader::VisitCXXReinterpretCastExpr(CXXReinterpretCastExpr *E) { + return VisitCXXNamedCastExpr(E); +} + +unsigned PCHStmtReader::VisitCXXConstCastExpr(CXXConstCastExpr *E) { + return VisitCXXNamedCastExpr(E); +} + +unsigned PCHStmtReader::VisitCXXFunctionalCastExpr(CXXFunctionalCastExpr *E) { + unsigned num = VisitExplicitCastExpr(E); + E->setTypeBeginLoc(SourceLocation::getFromRawEncoding(Record[Idx++])); + E->setRParenLoc(SourceLocation::getFromRawEncoding(Record[Idx++])); + return num; +} + // Within the bitstream, expressions are stored in Reverse Polish // Notation, with each of the subexpressions preceding the // expression they are stored in. To evaluate expressions, we @@ -1176,6 +1212,28 @@ Stmt *PCHReader::ReadStmt(llvm::BitstreamCursor &Cursor) { S = new (Context) CXXConstructExpr(Empty, *Context, Record[PCHStmtReader::NumExprFields + 2]); break; + + case pch::EXPR_CXX_STATIC_CAST: + S = new (Context) CXXStaticCastExpr(Empty); + break; + + case pch::EXPR_CXX_DYNAMIC_CAST: + S = new (Context) CXXDynamicCastExpr(Empty); + break; + + case pch::EXPR_CXX_REINTERPRET_CAST: + S = new (Context) CXXReinterpretCastExpr(Empty); + break; + + case pch::EXPR_CXX_CONST_CAST: + S = new (Context) CXXConstCastExpr(Empty); + break; + + case pch::EXPR_CXX_FUNCTIONAL_CAST: + S = new (Context) CXXFunctionalCastExpr(Empty); + break; + + } // We hit a STMT_STOP, so we're done with this expression. diff --git a/lib/Frontend/PCHWriter.cpp b/lib/Frontend/PCHWriter.cpp index 3f6841b..9909c95 100644 --- a/lib/Frontend/PCHWriter.cpp +++ b/lib/Frontend/PCHWriter.cpp @@ -139,6 +139,8 @@ void PCHTypeWriter::VisitExtVectorType(const ExtVectorType *T) { void PCHTypeWriter::VisitFunctionType(const FunctionType *T) { Writer.AddTypeRef(T->getResultType(), Record); Record.push_back(T->getNoReturnAttr()); + // FIXME: need to stabilize encoding of calling convention... + Record.push_back(T->getCallConv()); } void PCHTypeWriter::VisitFunctionNoProtoType(const FunctionNoProtoType *T) { @@ -275,7 +277,13 @@ void TypeLocWriter::VisitQualifiedTypeLoc(QualifiedTypeLoc TL) { // nothing to do } void TypeLocWriter::VisitBuiltinTypeLoc(BuiltinTypeLoc TL) { - Writer.AddSourceLocation(TL.getNameLoc(), Record); + Writer.AddSourceLocation(TL.getBuiltinLoc(), Record); + if (TL.needsExtraLocalData()) { + Record.push_back(TL.getWrittenTypeSpec()); + Record.push_back(TL.getWrittenSignSpec()); + Record.push_back(TL.getWrittenWidthSpec()); + Record.push_back(TL.hasModeAttr()); + } } void TypeLocWriter::VisitComplexTypeLoc(ComplexTypeLoc TL) { Writer.AddSourceLocation(TL.getNameLoc(), Record); @@ -535,7 +543,7 @@ void PCHWriter::WriteBlockInfoBlock() { RECORD(STAT_CACHE); RECORD(EXT_VECTOR_DECLS); RECORD(COMMENT_RANGES); - RECORD(SVN_BRANCH_REVISION); + RECORD(VERSION_CONTROL_BRANCH_REVISION); // SourceManager Block. BLOCK(SOURCE_MANAGER_BLOCK); @@ -699,16 +707,15 @@ void PCHWriter::WriteMetadata(ASTContext &Context, const char *isysroot) { Stream.EmitRecordWithBlob(FileAbbrevCode, Record, MainFileNameStr); } - // Subversion branch/version information. - BitCodeAbbrev *SvnAbbrev = new BitCodeAbbrev(); - SvnAbbrev->Add(BitCodeAbbrevOp(pch::SVN_BRANCH_REVISION)); - SvnAbbrev->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Fixed, 32)); // SVN revision - SvnAbbrev->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Blob)); // SVN branch/tag - unsigned SvnAbbrevCode = Stream.EmitAbbrev(SvnAbbrev); + // Repository branch/version information. + BitCodeAbbrev *RepoAbbrev = new BitCodeAbbrev(); + RepoAbbrev->Add(BitCodeAbbrevOp(pch::VERSION_CONTROL_BRANCH_REVISION)); + RepoAbbrev->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Blob)); // SVN branch/tag + unsigned RepoAbbrevCode = Stream.EmitAbbrev(RepoAbbrev); Record.clear(); - Record.push_back(pch::SVN_BRANCH_REVISION); - Record.push_back(getClangSubversionRevision()); - Stream.EmitRecordWithBlob(SvnAbbrevCode, Record, getClangSubversionPath()); + Record.push_back(pch::VERSION_CONTROL_BRANCH_REVISION); + Stream.EmitRecordWithBlob(RepoAbbrevCode, Record, + getClangFullRepositoryVersion()); } /// \brief Write the LangOptions structure. @@ -1263,7 +1270,7 @@ void PCHWriter::WriteType(QualType T) { // For all of the concrete, non-dependent types, call the // appropriate visitor function. #define TYPE(Class, Base) \ - case Type::Class: W.Visit##Class##Type(cast<Class##Type>(T)); break; + case Type::Class: W.Visit##Class##Type(cast<Class##Type>(T)); break; #define ABSTRACT_TYPE(Class, Base) #define DEPENDENT_TYPE(Class, Base) #include "clang/AST/TypeNodes.def" diff --git a/lib/Frontend/PCHWriterDecl.cpp b/lib/Frontend/PCHWriterDecl.cpp index 2dbcc27..020f69b 100644 --- a/lib/Frontend/PCHWriterDecl.cpp +++ b/lib/Frontend/PCHWriterDecl.cpp @@ -223,6 +223,10 @@ void PCHDeclWriter::VisitObjCInterfaceDecl(ObjCInterfaceDecl *D) { PEnd = D->protocol_end(); P != PEnd; ++P) Writer.AddDeclRef(*P, Record); + for (ObjCInterfaceDecl::protocol_loc_iterator PL = D->protocol_loc_begin(), + PLEnd = D->protocol_loc_end(); + PL != PLEnd; ++PL) + Writer.AddSourceLocation(*PL, Record); Record.push_back(D->ivar_size()); for (ObjCInterfaceDecl::ivar_iterator I = D->ivar_begin(), IEnd = D->ivar_end(); I != IEnd; ++I) @@ -251,6 +255,10 @@ void PCHDeclWriter::VisitObjCProtocolDecl(ObjCProtocolDecl *D) { for (ObjCProtocolDecl::protocol_iterator I = D->protocol_begin(), IEnd = D->protocol_end(); I != IEnd; ++I) Writer.AddDeclRef(*I, Record); + for (ObjCProtocolDecl::protocol_loc_iterator PL = D->protocol_loc_begin(), + PLEnd = D->protocol_loc_end(); + PL != PLEnd; ++PL) + Writer.AddSourceLocation(*PL, Record); Code = pch::DECL_OBJC_PROTOCOL; } @@ -272,9 +280,13 @@ void PCHDeclWriter::VisitObjCClassDecl(ObjCClassDecl *D) { void PCHDeclWriter::VisitObjCForwardProtocolDecl(ObjCForwardProtocolDecl *D) { VisitDecl(D); Record.push_back(D->protocol_size()); - for (ObjCProtocolDecl::protocol_iterator + for (ObjCForwardProtocolDecl::protocol_iterator I = D->protocol_begin(), IEnd = D->protocol_end(); I != IEnd; ++I) Writer.AddDeclRef(*I, Record); + for (ObjCForwardProtocolDecl::protocol_loc_iterator + PL = D->protocol_loc_begin(), PLEnd = D->protocol_loc_end(); + PL != PLEnd; ++PL) + Writer.AddSourceLocation(*PL, Record); Code = pch::DECL_OBJC_FORWARD_PROTOCOL; } @@ -282,11 +294,16 @@ void PCHDeclWriter::VisitObjCCategoryDecl(ObjCCategoryDecl *D) { VisitObjCContainerDecl(D); Writer.AddDeclRef(D->getClassInterface(), Record); Record.push_back(D->protocol_size()); - for (ObjCProtocolDecl::protocol_iterator + for (ObjCCategoryDecl::protocol_iterator I = D->protocol_begin(), IEnd = D->protocol_end(); I != IEnd; ++I) Writer.AddDeclRef(*I, Record); + for (ObjCCategoryDecl::protocol_loc_iterator + PL = D->protocol_loc_begin(), PLEnd = D->protocol_loc_end(); + PL != PLEnd; ++PL) + Writer.AddSourceLocation(*PL, Record); Writer.AddDeclRef(D->getNextClassCategory(), Record); - Writer.AddSourceLocation(D->getLocEnd(), Record); + Writer.AddSourceLocation(D->getAtLoc(), Record); + Writer.AddSourceLocation(D->getCategoryNameLoc(), Record); Code = pch::DECL_OBJC_CATEGORY; } @@ -298,6 +315,7 @@ void PCHDeclWriter::VisitObjCCompatibleAliasDecl(ObjCCompatibleAliasDecl *D) { void PCHDeclWriter::VisitObjCPropertyDecl(ObjCPropertyDecl *D) { VisitNamedDecl(D); + Writer.AddSourceLocation(D->getAtLoc(), Record); Writer.AddTypeRef(D->getType(), Record); // FIXME: stable encoding Record.push_back((unsigned)D->getPropertyAttributes()); diff --git a/lib/Frontend/PCHWriterStmt.cpp b/lib/Frontend/PCHWriterStmt.cpp index 4be9b81..fdfdfef 100644 --- a/lib/Frontend/PCHWriterStmt.cpp +++ b/lib/Frontend/PCHWriterStmt.cpp @@ -112,6 +112,12 @@ namespace { // C++ Statements void VisitCXXOperatorCallExpr(CXXOperatorCallExpr *E); void VisitCXXConstructExpr(CXXConstructExpr *E); + void VisitCXXNamedCastExpr(CXXNamedCastExpr *E); + void VisitCXXStaticCastExpr(CXXStaticCastExpr *E); + void VisitCXXDynamicCastExpr(CXXDynamicCastExpr *E); + void VisitCXXReinterpretCastExpr(CXXReinterpretCastExpr *E); + void VisitCXXConstCastExpr(CXXConstCastExpr *E); + void VisitCXXFunctionalCastExpr(CXXFunctionalCastExpr *E); }; } @@ -477,7 +483,7 @@ void PCHStmtWriter::VisitImplicitCastExpr(ImplicitCastExpr *E) { void PCHStmtWriter::VisitExplicitCastExpr(ExplicitCastExpr *E) { VisitCastExpr(E); - Writer.AddTypeRef(E->getTypeAsWritten(), Record); + Writer.AddTypeSourceInfo(E->getTypeInfoAsWritten(), Record); } void PCHStmtWriter::VisitCStyleCastExpr(CStyleCastExpr *E) { @@ -490,6 +496,7 @@ void PCHStmtWriter::VisitCStyleCastExpr(CStyleCastExpr *E) { void PCHStmtWriter::VisitCompoundLiteralExpr(CompoundLiteralExpr *E) { VisitExpr(E); Writer.AddSourceLocation(E->getLParenLoc(), Record); + Writer.AddTypeSourceInfo(E->getTypeSourceInfo(), Record); Writer.WriteSubStmt(E->getInitializer()); Record.push_back(E->isFileScope()); Code = pch::EXPR_COMPOUND_LITERAL; @@ -795,6 +802,38 @@ void PCHStmtWriter::VisitCXXConstructExpr(CXXConstructExpr *E) { Code = pch::EXPR_CXX_CONSTRUCT; } +void PCHStmtWriter::VisitCXXNamedCastExpr(CXXNamedCastExpr *E) { + VisitExplicitCastExpr(E); + Writer.AddSourceLocation(E->getOperatorLoc(), Record); +} + +void PCHStmtWriter::VisitCXXStaticCastExpr(CXXStaticCastExpr *E) { + VisitCXXNamedCastExpr(E); + Code = pch::EXPR_CXX_STATIC_CAST; +} + +void PCHStmtWriter::VisitCXXDynamicCastExpr(CXXDynamicCastExpr *E) { + VisitCXXNamedCastExpr(E); + Code = pch::EXPR_CXX_DYNAMIC_CAST; +} + +void PCHStmtWriter::VisitCXXReinterpretCastExpr(CXXReinterpretCastExpr *E) { + VisitCXXNamedCastExpr(E); + Code = pch::EXPR_CXX_REINTERPRET_CAST; +} + +void PCHStmtWriter::VisitCXXConstCastExpr(CXXConstCastExpr *E) { + VisitCXXNamedCastExpr(E); + Code = pch::EXPR_CXX_CONST_CAST; +} + +void PCHStmtWriter::VisitCXXFunctionalCastExpr(CXXFunctionalCastExpr *E) { + VisitExplicitCastExpr(E); + Writer.AddSourceLocation(E->getTypeBeginLoc(), Record); + Writer.AddSourceLocation(E->getRParenLoc(), Record); + Code = pch::EXPR_CXX_FUNCTIONAL_CAST; +} + //===----------------------------------------------------------------------===// // PCHWriter Implementation //===----------------------------------------------------------------------===// diff --git a/lib/Frontend/PlistDiagnostics.cpp b/lib/Frontend/PlistDiagnostics.cpp index 92cafe6..98be869 100644 --- a/lib/Frontend/PlistDiagnostics.cpp +++ b/lib/Frontend/PlistDiagnostics.cpp @@ -177,12 +177,12 @@ static llvm::raw_ostream& EmitString(llvm::raw_ostream& o, for (std::string::const_iterator I=s.begin(), E=s.end(); I!=E; ++I) { char c = *I; switch (c) { - default: o << c; break; - case '&': o << "&"; break; - case '<': o << "<"; break; - case '>': o << ">"; break; - case '\'': o << "'"; break; - case '\"': o << """; break; + default: o << c; break; + case '&': o << "&"; break; + case '<': o << "<"; break; + case '>': o << ">"; break; + case '\'': o << "'"; break; + case '\"': o << """; break; } } o << "</string>"; @@ -289,16 +289,16 @@ static void ReportMacro(llvm::raw_ostream& o, I!=E; ++I) { switch ((*I)->getKind()) { - default: - break; - case PathDiagnosticPiece::Event: - ReportEvent(o, cast<PathDiagnosticEventPiece>(**I), FM, SM, LangOpts, - indent); - break; - case PathDiagnosticPiece::Macro: - ReportMacro(o, cast<PathDiagnosticMacroPiece>(**I), FM, SM, LangOpts, - indent); - break; + default: + break; + case PathDiagnosticPiece::Event: + ReportEvent(o, cast<PathDiagnosticEventPiece>(**I), FM, SM, LangOpts, + indent); + break; + case PathDiagnosticPiece::Macro: + ReportMacro(o, cast<PathDiagnosticMacroPiece>(**I), FM, SM, LangOpts, + indent); + break; } } } @@ -310,18 +310,18 @@ static void ReportDiag(llvm::raw_ostream& o, const PathDiagnosticPiece& P, unsigned indent = 4; switch (P.getKind()) { - case PathDiagnosticPiece::ControlFlow: - ReportControlFlow(o, cast<PathDiagnosticControlFlowPiece>(P), FM, SM, - LangOpts, indent); - break; - case PathDiagnosticPiece::Event: - ReportEvent(o, cast<PathDiagnosticEventPiece>(P), FM, SM, LangOpts, - indent); - break; - case PathDiagnosticPiece::Macro: - ReportMacro(o, cast<PathDiagnosticMacroPiece>(P), FM, SM, LangOpts, - indent); - break; + case PathDiagnosticPiece::ControlFlow: + ReportControlFlow(o, cast<PathDiagnosticControlFlowPiece>(P), FM, SM, + LangOpts, indent); + break; + case PathDiagnosticPiece::Event: + ReportEvent(o, cast<PathDiagnosticEventPiece>(P), FM, SM, LangOpts, + indent); + break; + case PathDiagnosticPiece::Macro: + ReportMacro(o, cast<PathDiagnosticMacroPiece>(P), FM, SM, LangOpts, + indent); + break; } } diff --git a/lib/Frontend/PrintParserCallbacks.cpp b/lib/Frontend/PrintParserCallbacks.cpp index 95afb90..a91dd8d 100644 --- a/lib/Frontend/PrintParserCallbacks.cpp +++ b/lib/Frontend/PrintParserCallbacks.cpp @@ -65,6 +65,7 @@ namespace { SourceLocation SuperLoc, const DeclPtrTy *ProtoRefs, unsigned NumProtocols, + const SourceLocation *ProtoLocs, SourceLocation EndProtoLoc, AttributeList *AttrList) { Out << __FUNCTION__ << "\n"; @@ -72,7 +73,8 @@ namespace { ClassName, ClassLoc, SuperName, SuperLoc, ProtoRefs, NumProtocols, - EndProtoLoc, AttrList); + ProtoLocs, EndProtoLoc, + AttrList); } /// ActOnForwardClassDeclaration - diff --git a/lib/Frontend/PrintPreprocessedOutput.cpp b/lib/Frontend/PrintPreprocessedOutput.cpp index d9708d8..43deaee 100644 --- a/lib/Frontend/PrintPreprocessedOutput.cpp +++ b/lib/Frontend/PrintPreprocessedOutput.cpp @@ -22,7 +22,7 @@ #include "clang/Lex/Preprocessor.h" #include "clang/Lex/TokenConcatenation.h" #include "llvm/ADT/SmallString.h" -#include "llvm/ADT/StringExtras.h" +#include "llvm/ADT/STLExtras.h" #include "llvm/Config/config.h" #include "llvm/Support/raw_ostream.h" #include <cstdio> @@ -443,13 +443,11 @@ static void PrintPreprocessedTokens(Preprocessor &PP, Token &Tok, } } -namespace { - struct SortMacrosByID { - typedef std::pair<IdentifierInfo*, MacroInfo*> id_macro_pair; - bool operator()(const id_macro_pair &LHS, const id_macro_pair &RHS) const { - return LHS.first->getName() < RHS.first->getName(); - } - }; +typedef std::pair<IdentifierInfo*, MacroInfo*> id_macro_pair; +static int MacroIDCompare(const void* a, const void* b) { + const id_macro_pair *LHS = static_cast<const id_macro_pair*>(a); + const id_macro_pair *RHS = static_cast<const id_macro_pair*>(b); + return LHS->first->getName().compare(RHS->first->getName()); } static void DoPrintMacros(Preprocessor &PP, llvm::raw_ostream *OS) { @@ -461,11 +459,9 @@ static void DoPrintMacros(Preprocessor &PP, llvm::raw_ostream *OS) { do PP.Lex(Tok); while (Tok.isNot(tok::eof)); - std::vector<std::pair<IdentifierInfo*, MacroInfo*> > MacrosByID; - for (Preprocessor::macro_iterator I = PP.macro_begin(), E = PP.macro_end(); - I != E; ++I) - MacrosByID.push_back(*I); - std::sort(MacrosByID.begin(), MacrosByID.end(), SortMacrosByID()); + llvm::SmallVector<id_macro_pair, 128> + MacrosByID(PP.macro_begin(), PP.macro_end()); + llvm::array_pod_sort(MacrosByID.begin(), MacrosByID.end(), MacroIDCompare); for (unsigned i = 0, e = MacrosByID.size(); i != e; ++i) { MacroInfo &MI = *MacrosByID[i].second; @@ -473,7 +469,7 @@ static void DoPrintMacros(Preprocessor &PP, llvm::raw_ostream *OS) { if (MI.isBuiltinMacro()) continue; PrintMacroDefinition(*MacrosByID[i].first, MI, PP, *OS); - *OS << "\n"; + *OS << '\n'; } } diff --git a/lib/Frontend/RewriteObjC.cpp b/lib/Frontend/RewriteObjC.cpp index fc9401d..35d8dde 100644 --- a/lib/Frontend/RewriteObjC.cpp +++ b/lib/Frontend/RewriteObjC.cpp @@ -420,6 +420,14 @@ namespace { } } }; + + // Helper function: create a CStyleCastExpr with trivial type source info. + CStyleCastExpr* NoTypeInfoCStyleCastExpr(ASTContext *Ctx, QualType Ty, + CastExpr::CastKind Kind, Expr *E) { + TypeSourceInfo *TInfo = Ctx->getTrivialTypeSourceInfo(Ty, SourceLocation()); + return new (Ctx) CStyleCastExpr(Ty, Kind, E, TInfo, + SourceLocation(), SourceLocation()); + } } void RewriteObjC::RewriteBlocksInFunctionProtoType(QualType funcType, @@ -610,6 +618,7 @@ void RewriteObjC::Initialize(ASTContext &context) { Preamble += "#undef __OBJC_RW_DLLIMPORT\n"; Preamble += "#undef __OBJC_RW_STATICIMPORT\n"; Preamble += "#define __attribute__(X)\n"; + Preamble += "#define __weak\n"; } else { Preamble += "#define __block\n"; @@ -824,6 +833,10 @@ void RewriteObjC::RewriteForwardClassDecl(ObjCClassDecl *ClassDecl) { } void RewriteObjC::RewriteMethodDeclaration(ObjCMethodDecl *Method) { + // When method is a synthesized one, such as a getter/setter there is + // nothing to rewrite. + if (Method->isSynthesized()) + return; SourceLocation LocStart = Method->getLocStart(); SourceLocation LocEnd = Method->getLocEnd(); @@ -837,10 +850,9 @@ void RewriteObjC::RewriteMethodDeclaration(ObjCMethodDecl *Method) { } void RewriteObjC::RewriteProperty(ObjCPropertyDecl *prop) { - SourceLocation Loc = prop->getLocation(); + SourceLocation Loc = prop->getAtLoc(); ReplaceText(Loc, 0, "// ", 3); - // FIXME: handle properties that are declared across multiple lines. } @@ -1219,11 +1231,9 @@ Stmt *RewriteObjC::RewriteObjCIvarRefExpr(ObjCIvarRefExpr *IV, SourceLocation(), II); assert(RD && "RewriteObjCIvarRefExpr(): Can't find RecordDecl"); QualType castT = Context->getPointerType(Context->getTagDeclType(RD)); - CastExpr *castExpr = new (Context) CStyleCastExpr(castT, - CastExpr::CK_Unknown, - IV->getBase(), - castT,SourceLocation(), - SourceLocation()); + CastExpr *castExpr = NoTypeInfoCStyleCastExpr(Context, castT, + CastExpr::CK_Unknown, + IV->getBase()); // Don't forget the parens to enforce the proper binding. ParenExpr *PE = new (Context) ParenExpr(IV->getBase()->getLocStart(), IV->getBase()->getLocEnd(), @@ -1267,11 +1277,9 @@ Stmt *RewriteObjC::RewriteObjCIvarRefExpr(ObjCIvarRefExpr *IV, SourceLocation(), II); assert(RD && "RewriteObjCIvarRefExpr(): Can't find RecordDecl"); QualType castT = Context->getPointerType(Context->getTagDeclType(RD)); - CastExpr *castExpr = new (Context) CStyleCastExpr(castT, - CastExpr::CK_Unknown, - IV->getBase(), - castT, SourceLocation(), - SourceLocation()); + CastExpr *castExpr = NoTypeInfoCStyleCastExpr(Context, castT, + CastExpr::CK_Unknown, + IV->getBase()); // Don't forget the parens to enforce the proper binding. ParenExpr *PE = new (Context) ParenExpr(IV->getBase()->getLocStart(), IV->getBase()->getLocEnd(), castExpr); @@ -1584,12 +1592,9 @@ Stmt *RewriteObjC::RewriteObjCSynchronizedStmt(ObjCAtSynchronizedStmt *S) { std::string syncBuf; syncBuf += " objc_sync_exit("; - Expr *syncExpr = new (Context) CStyleCastExpr(Context->getObjCIdType(), - CastExpr::CK_Unknown, - S->getSynchExpr(), - Context->getObjCIdType(), - SourceLocation(), - SourceLocation()); + Expr *syncExpr = NoTypeInfoCStyleCastExpr(Context, Context->getObjCIdType(), + CastExpr::CK_Unknown, + S->getSynchExpr()); std::string syncExprBufS; llvm::raw_string_ostream syncExprBuf(syncExprBufS); syncExpr->printPretty(syncExprBuf, *Context, 0, @@ -2332,11 +2337,8 @@ Stmt *RewriteObjC::RewriteObjCStringLiteral(ObjCStringLiteral *Exp) { Context->getPointerType(DRE->getType()), SourceLocation()); // cast to NSConstantString * - CastExpr *cast = new (Context) CStyleCastExpr(Exp->getType(), - CastExpr::CK_Unknown, - Unop, Exp->getType(), - SourceLocation(), - SourceLocation()); + CastExpr *cast = NoTypeInfoCStyleCastExpr(Context, Exp->getType(), + CastExpr::CK_Unknown, Unop); ReplaceStmt(Exp, cast); // delete Exp; leak for now, see RewritePropertySetter() usage for more info. return cast; @@ -2465,13 +2467,12 @@ Stmt *RewriteObjC::SynthMessageExpr(ObjCMessageExpr *Exp) { // set the receiver to self, the first argument to all methods. InitExprs.push_back( - new (Context) CStyleCastExpr(Context->getObjCIdType(), - CastExpr::CK_Unknown, + NoTypeInfoCStyleCastExpr(Context, Context->getObjCIdType(), + CastExpr::CK_Unknown, new (Context) DeclRefExpr(CurMethodDef->getSelfDecl(), Context->getObjCIdType(), - SourceLocation()), - Context->getObjCIdType(), - SourceLocation(), SourceLocation())); // set the 'receiver'. + SourceLocation())) + ); // set the 'receiver'. llvm::SmallVector<Expr*, 8> ClsExprs; QualType argType = Context->getPointerType(Context->CharTy); @@ -2484,10 +2485,9 @@ Stmt *RewriteObjC::SynthMessageExpr(ObjCMessageExpr *Exp) { ClsExprs.size()); // To turn off a warning, type-cast to 'id' InitExprs.push_back( // set 'super class', using objc_getClass(). - new (Context) CStyleCastExpr(Context->getObjCIdType(), - CastExpr::CK_Unknown, - Cls, Context->getObjCIdType(), - SourceLocation(), SourceLocation())); + NoTypeInfoCStyleCastExpr(Context, + Context->getObjCIdType(), + CastExpr::CK_Unknown, Cls)); // struct objc_super QualType superType = getSuperStructType(); Expr *SuperRep; @@ -2509,17 +2509,18 @@ Stmt *RewriteObjC::SynthMessageExpr(ObjCMessageExpr *Exp) { SuperRep = new (Context) UnaryOperator(SuperRep, UnaryOperator::AddrOf, Context->getPointerType(SuperRep->getType()), SourceLocation()); - SuperRep = new (Context) CStyleCastExpr(Context->getPointerType(superType), - CastExpr::CK_Unknown, SuperRep, - Context->getPointerType(superType), - SourceLocation(), SourceLocation()); + SuperRep = NoTypeInfoCStyleCastExpr(Context, + Context->getPointerType(superType), + CastExpr::CK_Unknown, SuperRep); } else { // (struct objc_super) { <exprs from above> } InitListExpr *ILE = new (Context) InitListExpr(SourceLocation(), &InitExprs[0], InitExprs.size(), SourceLocation()); - SuperRep = new (Context) CompoundLiteralExpr(SourceLocation(), superType, ILE, - false); + TypeSourceInfo *superTInfo + = Context->getTrivialTypeSourceInfo(superType); + SuperRep = new (Context) CompoundLiteralExpr(SourceLocation(), superTInfo, + superType, ILE, false); // struct objc_super * SuperRep = new (Context) UnaryOperator(SuperRep, UnaryOperator::AddrOf, Context->getPointerType(SuperRep->getType()), @@ -2551,13 +2552,12 @@ Stmt *RewriteObjC::SynthMessageExpr(ObjCMessageExpr *Exp) { llvm::SmallVector<Expr*, 4> InitExprs; InitExprs.push_back( - new (Context) CStyleCastExpr(Context->getObjCIdType(), - CastExpr::CK_Unknown, + NoTypeInfoCStyleCastExpr(Context, Context->getObjCIdType(), + CastExpr::CK_Unknown, new (Context) DeclRefExpr(CurMethodDef->getSelfDecl(), Context->getObjCIdType(), - SourceLocation()), - Context->getObjCIdType(), - SourceLocation(), SourceLocation())); // set the 'receiver'. + SourceLocation())) + ); // set the 'receiver'. llvm::SmallVector<Expr*, 8> ClsExprs; QualType argType = Context->getPointerType(Context->CharTy); @@ -2571,9 +2571,8 @@ Stmt *RewriteObjC::SynthMessageExpr(ObjCMessageExpr *Exp) { // To turn off a warning, type-cast to 'id' InitExprs.push_back( // set 'super class', using objc_getClass(). - new (Context) CStyleCastExpr(Context->getObjCIdType(), - CastExpr::CK_Unknown, - Cls, Context->getObjCIdType(), SourceLocation(), SourceLocation())); + NoTypeInfoCStyleCastExpr(Context, Context->getObjCIdType(), + CastExpr::CK_Unknown, Cls)); // struct objc_super QualType superType = getSuperStructType(); Expr *SuperRep; @@ -2595,16 +2594,18 @@ Stmt *RewriteObjC::SynthMessageExpr(ObjCMessageExpr *Exp) { SuperRep = new (Context) UnaryOperator(SuperRep, UnaryOperator::AddrOf, Context->getPointerType(SuperRep->getType()), SourceLocation()); - SuperRep = new (Context) CStyleCastExpr(Context->getPointerType(superType), - CastExpr::CK_Unknown, - SuperRep, Context->getPointerType(superType), - SourceLocation(), SourceLocation()); + SuperRep = NoTypeInfoCStyleCastExpr(Context, + Context->getPointerType(superType), + CastExpr::CK_Unknown, SuperRep); } else { // (struct objc_super) { <exprs from above> } InitListExpr *ILE = new (Context) InitListExpr(SourceLocation(), &InitExprs[0], InitExprs.size(), SourceLocation()); - SuperRep = new (Context) CompoundLiteralExpr(SourceLocation(), superType, ILE, false); + TypeSourceInfo *superTInfo + = Context->getTrivialTypeSourceInfo(superType); + SuperRep = new (Context) CompoundLiteralExpr(SourceLocation(), superTInfo, + superType, ILE, false); } MsgExprs.push_back(SuperRep); } else { @@ -2612,10 +2613,8 @@ Stmt *RewriteObjC::SynthMessageExpr(ObjCMessageExpr *Exp) { // Foo<Proto> *. while (CStyleCastExpr *CE = dyn_cast<CStyleCastExpr>(recExpr)) recExpr = CE->getSubExpr(); - recExpr = new (Context) CStyleCastExpr(Context->getObjCIdType(), - CastExpr::CK_Unknown, recExpr, - Context->getObjCIdType(), - SourceLocation(), SourceLocation()); + recExpr = NoTypeInfoCStyleCastExpr(Context, Context->getObjCIdType(), + CastExpr::CK_Unknown, recExpr); MsgExprs.push_back(recExpr); } } @@ -2639,19 +2638,16 @@ Stmt *RewriteObjC::SynthMessageExpr(ObjCMessageExpr *Exp) { QualType type = ICE->getType()->isObjCQualifiedIdType() ? Context->getObjCIdType() : ICE->getType(); - userExpr = new (Context) CStyleCastExpr(type, CastExpr::CK_Unknown, - userExpr, type, SourceLocation(), - SourceLocation()); + userExpr = NoTypeInfoCStyleCastExpr(Context, type, CastExpr::CK_Unknown, + userExpr); } // Make id<P...> cast into an 'id' cast. else if (CStyleCastExpr *CE = dyn_cast<CStyleCastExpr>(userExpr)) { if (CE->getType()->isObjCQualifiedIdType()) { while ((CE = dyn_cast<CStyleCastExpr>(userExpr))) userExpr = CE->getSubExpr(); - userExpr = new (Context) CStyleCastExpr(Context->getObjCIdType(), - CastExpr::CK_Unknown, - userExpr, Context->getObjCIdType(), - SourceLocation(), SourceLocation()); + userExpr = NoTypeInfoCStyleCastExpr(Context, Context->getObjCIdType(), + CastExpr::CK_Unknown, userExpr); } } MsgExprs.push_back(userExpr); @@ -2701,10 +2697,9 @@ Stmt *RewriteObjC::SynthMessageExpr(ObjCMessageExpr *Exp) { // If we don't do this cast, we get the following bizarre warning/note: // xx.m:13: warning: function called through a non-compatible type // xx.m:13: note: if this code is reached, the program will abort - cast = new (Context) CStyleCastExpr(Context->getPointerType(Context->VoidTy), - CastExpr::CK_Unknown, DRE, - Context->getPointerType(Context->VoidTy), - SourceLocation(), SourceLocation()); + cast = NoTypeInfoCStyleCastExpr(Context, + Context->getPointerType(Context->VoidTy), + CastExpr::CK_Unknown, DRE); // Now do the "normal" pointer to function cast. QualType castType = Context->getFunctionType(returnType, @@ -2712,9 +2707,8 @@ Stmt *RewriteObjC::SynthMessageExpr(ObjCMessageExpr *Exp) { // If we don't have a method decl, force a variadic cast. Exp->getMethodDecl() ? Exp->getMethodDecl()->isVariadic() : true, 0); castType = Context->getPointerType(castType); - cast = new (Context) CStyleCastExpr(castType, CastExpr::CK_Unknown, cast, - castType, SourceLocation(), - SourceLocation()); + cast = NoTypeInfoCStyleCastExpr(Context, castType, CastExpr::CK_Unknown, + cast); // Don't forget the parens to enforce the proper binding. ParenExpr *PE = new (Context) ParenExpr(SourceLocation(), SourceLocation(), cast); @@ -2734,17 +2728,16 @@ Stmt *RewriteObjC::SynthMessageExpr(ObjCMessageExpr *Exp) { DeclRefExpr *STDRE = new (Context) DeclRefExpr(MsgSendStretFlavor, msgSendType, SourceLocation()); // Need to cast objc_msgSend_stret to "void *" (see above comment). - cast = new (Context) CStyleCastExpr(Context->getPointerType(Context->VoidTy), - CastExpr::CK_Unknown, STDRE, - Context->getPointerType(Context->VoidTy), - SourceLocation(), SourceLocation()); + cast = NoTypeInfoCStyleCastExpr(Context, + Context->getPointerType(Context->VoidTy), + CastExpr::CK_Unknown, STDRE); // Now do the "normal" pointer to function cast. castType = Context->getFunctionType(returnType, &ArgTypes[0], ArgTypes.size(), Exp->getMethodDecl() ? Exp->getMethodDecl()->isVariadic() : false, 0); castType = Context->getPointerType(castType); - cast = new (Context) CStyleCastExpr(castType, CastExpr::CK_Unknown, - cast, castType, SourceLocation(), SourceLocation()); + cast = NoTypeInfoCStyleCastExpr(Context, castType, CastExpr::CK_Unknown, + cast); // Don't forget the parens to enforce the proper binding. PE = new (Context) ParenExpr(SourceLocation(), SourceLocation(), cast); @@ -2819,10 +2812,9 @@ Stmt *RewriteObjC::RewriteObjCProtocolExpr(ObjCProtocolExpr *Exp) { Expr *DerefExpr = new (Context) UnaryOperator(DRE, UnaryOperator::AddrOf, Context->getPointerType(DRE->getType()), SourceLocation()); - CastExpr *castExpr = new (Context) CStyleCastExpr(DerefExpr->getType(), - CastExpr::CK_Unknown, - DerefExpr, DerefExpr->getType(), - SourceLocation(), SourceLocation()); + CastExpr *castExpr = NoTypeInfoCStyleCastExpr(Context, DerefExpr->getType(), + CastExpr::CK_Unknown, + DerefExpr); ReplaceStmt(Exp, castExpr); ProtocolExprDecls.insert(Exp->getProtocol()); // delete Exp; leak for now, see RewritePropertySetter() usage for more info. @@ -4043,7 +4035,7 @@ std::string RewriteObjC::SynthesizeBlockDescriptor(std::string DescTag, void RewriteObjC::SynthesizeBlockLiterals(SourceLocation FunLocStart, const char *FunName) { // Insert declaration for the function in which block literal is used. - if (CurFunctionDeclToDeclareForBlock) + if (CurFunctionDeclToDeclareForBlock && !Blocks.empty()) RewriteBlockLiteralFunctionDecl(CurFunctionDeclToDeclareForBlock); // Insert closures that were part of the function. for (unsigned i = 0; i < Blocks.size(); i++) { @@ -4204,11 +4196,9 @@ Stmt *RewriteObjC::SynthesizeBlockCall(CallExpr *Exp, const Expr *BlockExp) { PtrToFuncCastType = Context->getPointerType(PtrToFuncCastType); - CastExpr *BlkCast = new (Context) CStyleCastExpr(PtrBlock, - CastExpr::CK_Unknown, - const_cast<Expr*>(BlockExp), - PtrBlock, SourceLocation(), - SourceLocation()); + CastExpr *BlkCast = NoTypeInfoCStyleCastExpr(Context, PtrBlock, + CastExpr::CK_Unknown, + const_cast<Expr*>(BlockExp)); // Don't forget the parens to enforce the proper binding. ParenExpr *PE = new (Context) ParenExpr(SourceLocation(), SourceLocation(), BlkCast); @@ -4220,11 +4210,8 @@ Stmt *RewriteObjC::SynthesizeBlockCall(CallExpr *Exp, const Expr *BlockExp) { MemberExpr *ME = new (Context) MemberExpr(PE, true, FD, SourceLocation(), FD->getType()); - CastExpr *FunkCast = new (Context) CStyleCastExpr(PtrToFuncCastType, - CastExpr::CK_Unknown, ME, - PtrToFuncCastType, - SourceLocation(), - SourceLocation()); + CastExpr *FunkCast = NoTypeInfoCStyleCastExpr(Context, PtrToFuncCastType, + CastExpr::CK_Unknown, ME); PE = new (Context) ParenExpr(SourceLocation(), SourceLocation(), FunkCast); llvm::SmallVector<Expr*, 8> BlkExprs; @@ -4309,17 +4296,29 @@ void RewriteObjC::RewriteCastExpr(CStyleCastExpr *CE) { const char *startBuf = SM->getCharacterData(LocStart); const char *endBuf = SM->getCharacterData(LocEnd); - + QualType QT = CE->getType(); + const Type* TypePtr = QT->getAs<Type>(); + if (isa<TypeOfExprType>(TypePtr)) { + const TypeOfExprType *TypeOfExprTypePtr = cast<TypeOfExprType>(TypePtr); + QT = TypeOfExprTypePtr->getUnderlyingExpr()->getType(); + std::string TypeAsString = "("; + TypeAsString += QT.getAsString(); + TypeAsString += ")"; + ReplaceText(LocStart, endBuf-startBuf+1, + TypeAsString.c_str(), TypeAsString.size()); + return; + } + // advance the location to startArgList. const char *argPtr = startBuf; while (*argPtr++ && (argPtr < endBuf)) { switch (*argPtr) { - case '^': - // Replace the '^' with '*'. - LocStart = LocStart.getFileLocWithOffset(argPtr-startBuf); - ReplaceText(LocStart, 1, "*", 1); - break; + case '^': + // Replace the '^' with '*'. + LocStart = LocStart.getFileLocWithOffset(argPtr-startBuf); + ReplaceText(LocStart, 1, "*", 1); + break; } } return; @@ -4344,17 +4343,17 @@ void RewriteObjC::RewriteBlockPointerFunctionArgs(FunctionDecl *FD) { while (*argPtr++ && parenCount) { switch (*argPtr) { - case '^': - // Replace the '^' with '*'. - DeclLoc = DeclLoc.getFileLocWithOffset(argPtr-startArgList); - ReplaceText(DeclLoc, 1, "*", 1); - break; - case '(': - parenCount++; - break; - case ')': - parenCount--; - break; + case '^': + // Replace the '^' with '*'. + DeclLoc = DeclLoc.getFileLocWithOffset(argPtr-startArgList); + ReplaceText(DeclLoc, 1, "*", 1); + break; + case '(': + parenCount++; + break; + case ')': + parenCount--; + break; } } return; @@ -4390,9 +4389,9 @@ void RewriteObjC::GetExtentOfArgList(const char *Name, const char *&LParen, while (*argPtr && parenCount) { switch (*argPtr) { - case '(': parenCount++; break; - case ')': parenCount--; break; - default: break; + case '(': parenCount++; break; + case ')': parenCount--; break; + default: break; } if (parenCount) argPtr++; } @@ -4557,8 +4556,13 @@ void RewriteObjC::RewriteByRefVar(VarDecl *ND) { ByrefType += " " + Name + ";\n"; ByrefType += "};\n"; // Insert this type in global scope. It is needed by helper function. - assert(CurFunctionDef && "RewriteByRefVar - CurFunctionDef is null"); - SourceLocation FunLocStart = CurFunctionDef->getTypeSpecStartLoc(); + SourceLocation FunLocStart; + if (CurFunctionDef) + FunLocStart = CurFunctionDef->getTypeSpecStartLoc(); + else { + assert(CurMethodDef && "RewriteByRefVar - CurMethodDef is null"); + FunLocStart = CurMethodDef->getLocStart(); + } InsertText(FunLocStart, ByrefType.c_str(), ByrefType.size()); if (Ty.isObjCGCWeak()) { flag |= BLOCK_FIELD_IS_WEAK; @@ -4608,12 +4612,17 @@ void RewriteObjC::RewriteByRefVar(VarDecl *ND) { ByrefType.c_str(), ByrefType.size()); } else { - SourceLocation startLoc = ND->getInit()->getLocStart(); + SourceLocation startLoc; + Expr *E = ND->getInit(); + if (const CStyleCastExpr *ECE = dyn_cast<CStyleCastExpr>(E)) + startLoc = ECE->getLParenLoc(); + else + startLoc = E->getLocStart(); startLoc = SM->getInstantiationLoc(startLoc); + endBuf = SM->getCharacterData(startLoc); + ByrefType += " " + Name; - ReplaceText(DeclLoc, endBuf-startBuf, - ByrefType.c_str(), ByrefType.size()); - ByrefType = " = {(void*)"; + ByrefType += " = {(void*)"; ByrefType += utostr(isa); ByrefType += ", &" + Name + ", "; ByrefType += utostr(flags); @@ -4628,7 +4637,8 @@ void RewriteObjC::RewriteByRefVar(VarDecl *ND) { ByrefType += utostr(flag); ByrefType += ", "; } - InsertText(startLoc, ByrefType.c_str(), ByrefType.size()); + ReplaceText(DeclLoc, endBuf-startBuf, + ByrefType.c_str(), ByrefType.size()); // Complete the newly synthesized compound expression by inserting a right // curly brace before the end of the declaration. @@ -4719,10 +4729,8 @@ Stmt *RewriteObjC::SynthBlockInitExpr(BlockExpr *Exp) { FD = SynthBlockInitFunctionDecl(Func.c_str()); DeclRefExpr *Arg = new (Context) DeclRefExpr(FD, FD->getType(), SourceLocation()); - CastExpr *castExpr = new (Context) CStyleCastExpr(Context->VoidPtrTy, - CastExpr::CK_Unknown, Arg, - Context->VoidPtrTy, SourceLocation(), - SourceLocation()); + CastExpr *castExpr = NoTypeInfoCStyleCastExpr(Context, Context->VoidPtrTy, + CastExpr::CK_Unknown, Arg); InitExprs.push_back(castExpr); // Initialize the block descriptor. @@ -4753,11 +4761,8 @@ Stmt *RewriteObjC::SynthBlockInitExpr(BlockExpr *Exp) { } else if (isTopLevelBlockPointerType((*I)->getType())) { FD = SynthBlockInitFunctionDecl((*I)->getNameAsCString()); Arg = new (Context) DeclRefExpr(FD, FD->getType(), SourceLocation()); - Exp = new (Context) CStyleCastExpr(Context->VoidPtrTy, - CastExpr::CK_Unknown, Arg, - Context->VoidPtrTy, - SourceLocation(), - SourceLocation()); + Exp = NoTypeInfoCStyleCastExpr(Context, Context->VoidPtrTy, + CastExpr::CK_Unknown, Arg); } else { FD = SynthBlockInitFunctionDecl((*I)->getNameAsCString()); Exp = new (Context) DeclRefExpr(FD, FD->getType(), SourceLocation()); @@ -4789,9 +4794,8 @@ Stmt *RewriteObjC::SynthBlockInitExpr(BlockExpr *Exp) { NewRep = new (Context) UnaryOperator(NewRep, UnaryOperator::AddrOf, Context->getPointerType(NewRep->getType()), SourceLocation()); - NewRep = new (Context) CStyleCastExpr(FType, CastExpr::CK_Unknown, NewRep, - FType, SourceLocation(), - SourceLocation()); + NewRep = NoTypeInfoCStyleCastExpr(Context, FType, CastExpr::CK_Unknown, + NewRep); BlockDeclRefs.clear(); BlockByRefDecls.clear(); BlockByCopyDecls.clear(); diff --git a/lib/Frontend/StmtXML.cpp b/lib/Frontend/StmtXML.cpp index c0977b5..ce474d3 100644 --- a/lib/Frontend/StmtXML.cpp +++ b/lib/Frontend/StmtXML.cpp @@ -89,14 +89,14 @@ namespace { const char* pAttributeName = NAME; \ const bool optional = false; \ switch (S->FN) { \ - default: assert(0 && "unknown enum value"); + default: assert(0 && "unknown enum value"); #define ATTRIBUTE_ENUM_OPT_XML( FN, NAME ) \ { \ const char* pAttributeName = NAME; \ const bool optional = true; \ switch (S->FN) { \ - default: assert(0 && "unknown enum value"); + default: assert(0 && "unknown enum value"); #define ENUM_XML( VALUE, NAME ) case VALUE: if ((!optional) || NAME[0]) Doc.addAttribute(pAttributeName, NAME); break; #define END_ENUM_XML } } @@ -189,17 +189,17 @@ void StmtXML::VisitDeclRefExpr(DeclRefExpr *Node) { const char* pKind; switch (Node->getDecl()->getKind()) { - case Decl::Function: pKind = "FunctionDecl"; break; - case Decl::Var: pKind = "Var"; break; - case Decl::ParmVar: pKind = "ParmVar"; break; - case Decl::EnumConstant: pKind = "EnumConstant"; break; - case Decl::Typedef: pKind = "Typedef"; break; - case Decl::Record: pKind = "Record"; break; - case Decl::Enum: pKind = "Enum"; break; - case Decl::CXXRecord: pKind = "CXXRecord"; break; - case Decl::ObjCInterface: pKind = "ObjCInterface"; break; - case Decl::ObjCClass: pKind = "ObjCClass"; break; - default: pKind = "Decl"; break; + case Decl::Function: pKind = "FunctionDecl"; break; + case Decl::Var: pKind = "Var"; break; + case Decl::ParmVar: pKind = "ParmVar"; break; + case Decl::EnumConstant: pKind = "EnumConstant"; break; + case Decl::Typedef: pKind = "Typedef"; break; + case Decl::Record: pKind = "Record"; break; + case Decl::Enum: pKind = "Enum"; break; + case Decl::CXXRecord: pKind = "CXXRecord"; break; + case Decl::ObjCInterface: pKind = "ObjCInterface"; break; + case Decl::ObjCClass: pKind = "ObjCClass"; break; + default: pKind = "Decl"; break; } Doc.addAttribute("kind", pKind); @@ -210,10 +210,10 @@ void StmtXML::VisitDeclRefExpr(DeclRefExpr *Node) { void StmtXML::VisitPredefinedExpr(PredefinedExpr *Node) { DumpExpr(Node); switch (Node->getIdentType()) { - default: assert(0 && "unknown case"); - case PredefinedExpr::Func: Doc.addAttribute("predefined", " __func__"); break; - case PredefinedExpr::Function: Doc.addAttribute("predefined", " __FUNCTION__"); break; - case PredefinedExpr::PrettyFunction: Doc.addAttribute("predefined", " __PRETTY_FUNCTION__");break; + default: assert(0 && "unknown case"); + case PredefinedExpr::Func: Doc.addAttribute("predefined", " __func__"); break; + case PredefinedExpr::Function: Doc.addAttribute("predefined", " __FUNCTION__"); break; + case PredefinedExpr::PrettyFunction: Doc.addAttribute("predefined", " __PRETTY_FUNCTION__");break; } } diff --git a/lib/Frontend/TextDiagnosticPrinter.cpp b/lib/Frontend/TextDiagnosticPrinter.cpp index fcefd4e..83b4542 100644 --- a/lib/Frontend/TextDiagnosticPrinter.cpp +++ b/lib/Frontend/TextDiagnosticPrinter.cpp @@ -428,6 +428,42 @@ void TextDiagnosticPrinter::EmitCaretDiagnostic(SourceLocation Loc, } } } + // Now that we have the entire fixit line, expand the tabs in it. + // Since we don't want to insert spaces in the middle of a word, + // find each word and the column it should line up with and insert + // spaces until they match. + if (!FixItInsertionLine.empty()) { + unsigned FixItPos = 0; + unsigned LinePos = 0; + unsigned TabExpandedCol = 0; + unsigned LineLength = LineEnd - LineStart; + + while (FixItPos < FixItInsertionLine.size() && LinePos < LineLength) { + // Find the next word in the FixIt line. + while (FixItPos < FixItInsertionLine.size() && + FixItInsertionLine[FixItPos] == ' ') + ++FixItPos; + unsigned CharDistance = FixItPos - TabExpandedCol; + + // Walk forward in the source line, keeping track of + // the tab-expanded column. + for (unsigned I = 0; I < CharDistance; ++I, ++LinePos) + if (LinePos >= LineLength || LineStart[LinePos] != '\t') + ++TabExpandedCol; + else + TabExpandedCol = + (TabExpandedCol/DiagOpts->TabStop + 1) * DiagOpts->TabStop; + + // Adjust the fixit line to match this column. + FixItInsertionLine.insert(FixItPos, TabExpandedCol-FixItPos, ' '); + FixItPos = TabExpandedCol; + + // Walk to the end of the word. + while (FixItPos < FixItInsertionLine.size() && + FixItInsertionLine[FixItPos] != ' ') + ++FixItPos; + } + } } // If the source line is too long for our terminal, select only the diff --git a/lib/Frontend/TypeXML.cpp b/lib/Frontend/TypeXML.cpp index 8bd0544..be9db42 100644 --- a/lib/Frontend/TypeXML.cpp +++ b/lib/Frontend/TypeXML.cpp @@ -43,14 +43,14 @@ public: const char* pAttributeName = NAME; \ const bool optional = false; \ switch (T->FN) { \ - default: assert(0 && "unknown enum value"); + default: assert(0 && "unknown enum value"); #define ATTRIBUTE_ENUM_OPT_XML( FN, NAME ) \ { \ const char* pAttributeName = NAME; \ const bool optional = true; \ switch (T->FN) { \ - default: assert(0 && "unknown enum value"); + default: assert(0 && "unknown enum value"); #define ENUM_XML( VALUE, NAME ) case VALUE: if ((!optional) || NAME[0]) Doc.addAttribute(pAttributeName, NAME); break; #define END_ENUM_XML } } diff --git a/lib/Index/ResolveLocation.cpp b/lib/Index/ResolveLocation.cpp index 81a5de4..4bb1594 100644 --- a/lib/Index/ResolveLocation.cpp +++ b/lib/Index/ResolveLocation.cpp @@ -264,7 +264,7 @@ ASTLocation DeclLocResolver::VisitFunctionDecl(FunctionDecl *D) { return ASTLocation(D); // Second, search through the declarations that are part of the function. - // If we find he location there, we won't have to search through its body. + // If we find the location there, we won't have to search through its body. for (DeclContext::decl_iterator I = D->decls_begin(), E = D->decls_end(); I != E; ++I) { diff --git a/lib/Lex/Lexer.cpp b/lib/Lex/Lexer.cpp index 0a74b26..afd1ba8 100644 --- a/lib/Lex/Lexer.cpp +++ b/lib/Lex/Lexer.cpp @@ -210,6 +210,7 @@ void Lexer::Stringify(llvm::SmallVectorImpl<char> &Str) { } } +static bool isWhitespace(unsigned char c); /// MeasureTokenLength - Relex the token at the specified location and return /// its length in bytes in the input file. If the token needs cleaning (e.g. @@ -231,6 +232,9 @@ unsigned Lexer::MeasureTokenLength(SourceLocation Loc, std::pair<const char *,const char *> Buffer = SM.getBufferData(LocInfo.first); const char *StrData = Buffer.first+LocInfo.second; + if (isWhitespace(StrData[0])) + return 0; + // Create a lexer starting at the beginning of this token. Lexer TheLexer(Loc, LangOpts, Buffer.first, StrData, Buffer.second); TheLexer.SetCommentRetentionState(true); @@ -902,8 +906,10 @@ bool Lexer::SkipWhitespace(Token &Result, const char *CurPtr) { // SkipBCPLComment - We have just read the // characters from input. Skip until // we find the newline character thats terminate the comment. Then update -/// BufferPtr and return. If we're in KeepCommentMode, this will form the token -/// and return true. +/// BufferPtr and return. +/// +/// If we're in KeepCommentMode or any CommentHandler has inserted +/// some tokens, this will store the first token and return true. bool Lexer::SkipBCPLComment(Token &Result, const char *CurPtr) { // If BCPL comments aren't explicitly enabled for this language, emit an // extension warning. @@ -980,9 +986,12 @@ bool Lexer::SkipBCPLComment(Token &Result, const char *CurPtr) { } while (C != '\n' && C != '\r'); // Found but did not consume the newline. - if (PP) - PP->HandleComment(SourceRange(getSourceLocation(BufferPtr), - getSourceLocation(CurPtr))); + if (PP && PP->HandleComment(Result, + SourceRange(getSourceLocation(BufferPtr), + getSourceLocation(CurPtr)))) { + BufferPtr = CurPtr; + return true; // A token has to be returned. + } // If we are returning comments as tokens, return this comment as a token. if (inKeepCommentMode()) @@ -1108,8 +1117,8 @@ static bool isEndOfBlockCommentWithEscapedNewLine(const char *CurPtr, /// happen is the comment could end with an escaped newline between the */ end /// of comment. /// -/// If KeepCommentMode is enabled, this forms a token from the comment and -/// returns true. +/// If we're in KeepCommentMode or any CommentHandler has inserted +/// some tokens, this will store the first token and return true. bool Lexer::SkipBlockComment(Token &Result, const char *CurPtr) { // Scan one character past where we should, looking for a '/' character. Once // we find it, check to see if it was preceeded by a *. This common @@ -1226,9 +1235,12 @@ bool Lexer::SkipBlockComment(Token &Result, const char *CurPtr) { C = *CurPtr++; } - if (PP) - PP->HandleComment(SourceRange(getSourceLocation(BufferPtr), - getSourceLocation(CurPtr))); + if (PP && PP->HandleComment(Result, + SourceRange(getSourceLocation(BufferPtr), + getSourceLocation(CurPtr)))) { + BufferPtr = CurPtr; + return true; // A token has to be returned. + } // If we are returning comments as tokens, return this comment as a token. if (inKeepCommentMode()) { @@ -1606,10 +1618,12 @@ LexNextToken: // too (without going through the big switch stmt). if (CurPtr[0] == '/' && CurPtr[1] == '/' && !inKeepCommentMode() && Features.BCPLComment) { - SkipBCPLComment(Result, CurPtr+2); + if (SkipBCPLComment(Result, CurPtr+2)) + return; // There is a token to return. goto SkipIgnoredUnits; } else if (CurPtr[0] == '/' && CurPtr[1] == '*' && !inKeepCommentMode()) { - SkipBlockComment(Result, CurPtr+2); + if (SkipBlockComment(Result, CurPtr+2)) + return; // There is a token to return. goto SkipIgnoredUnits; } else if (isHorizontalWhitespace(*CurPtr)) { goto SkipHorizontalWhitespace; @@ -1795,7 +1809,7 @@ LexNextToken: if (Features.BCPLComment || getCharAndSize(CurPtr+SizeTmp, SizeTmp2) != '*') { if (SkipBCPLComment(Result, ConsumeChar(CurPtr, SizeTmp, Result))) - return; // KeepCommentMode + return; // There is a token to return. // It is common for the tokens immediately after a // comment to be // whitespace (indentation for the next line). Instead of going through @@ -1806,7 +1820,7 @@ LexNextToken: if (Char == '*') { // /**/ comment. if (SkipBlockComment(Result, ConsumeChar(CurPtr, SizeTmp, Result))) - return; // KeepCommentMode + return; // There is a token to return. goto LexNextToken; // GCC isn't tail call eliminating. } diff --git a/lib/Lex/LiteralSupport.cpp b/lib/Lex/LiteralSupport.cpp index 5cd5497..004e675 100644 --- a/lib/Lex/LiteralSupport.cpp +++ b/lib/Lex/LiteralSupport.cpp @@ -375,7 +375,7 @@ NumericLiteralParser(const char *begin, const char *end, continue; // Success. case 'i': if (PP.getLangOptions().Microsoft) { - if (isFPConstant || isUnsigned || isLong || isLongLong) break; + if (isFPConstant || isLong || isLongLong) break; // Allow i8, i16, i32, i64, and i128. if (s + 1 != ThisTokEnd) { diff --git a/lib/Lex/PPDirectives.cpp b/lib/Lex/PPDirectives.cpp index aa807f8..b0e784b 100644 --- a/lib/Lex/PPDirectives.cpp +++ b/lib/Lex/PPDirectives.cpp @@ -160,10 +160,7 @@ void Preprocessor::SkipExcludedConditionalBlock(SourceLocation IfTokenLoc, CurPPLexer->LexingRawMode = true; Token Tok; while (1) { - if (CurLexer) - CurLexer->Lex(Tok); - else - CurPTHLexer->Lex(Tok); + CurLexer->Lex(Tok); // If this is the end of the buffer, we have an error. if (Tok.is(tok::eof)) { @@ -405,7 +402,6 @@ void Preprocessor::PTHSkipExcludedConditionalBlock() { /// return null on failure. isAngled indicates whether the file reference is /// for system #include's or not (i.e. using <> instead of ""). const FileEntry *Preprocessor::LookupFile(llvm::StringRef Filename, - SourceLocation FilenameTokLoc, bool isAngled, const DirectoryLookup *FromDir, const DirectoryLookup *&CurDir) { @@ -432,16 +428,7 @@ const FileEntry *Preprocessor::LookupFile(llvm::StringRef Filename, CurDir = CurDirLookup; const FileEntry *FE = HeaderInfo.LookupFile(Filename, isAngled, FromDir, CurDir, CurFileEnt); - if (FE) { - // Warn about normal quoted #include from framework headers. Since - // framework headers are published (both public and private ones) they - // should not do relative searches, they should do an include with the - // framework path included. - if (!isAngled && CurDir && FilenameTokLoc.isValid() && - CurDir->isFramework() && CurDir == CurDirLookup) - Diag(FilenameTokLoc, diag::warn_pp_relative_include_from_framework); - return FE; - } + if (FE) return FE; // Otherwise, see if this is a subframework header. If so, this is relative // to one of the headers on the #include stack. Walk the list of the current @@ -1082,8 +1069,7 @@ void Preprocessor::HandleIncludeDirective(Token &IncludeTok, // Search include directories. const DirectoryLookup *CurDir; - const FileEntry *File = LookupFile(Filename, FilenameTok.getLocation(), - isAngled, LookupFrom, CurDir); + const FileEntry *File = LookupFile(Filename, isAngled, LookupFrom, CurDir); if (File == 0) { Diag(FilenameTok, diag::err_pp_file_not_found) << Filename; return; diff --git a/lib/Lex/PPMacroExpansion.cpp b/lib/Lex/PPMacroExpansion.cpp index 3792782..13aeb88 100644 --- a/lib/Lex/PPMacroExpansion.cpp +++ b/lib/Lex/PPMacroExpansion.cpp @@ -567,9 +567,7 @@ static bool EvaluateHasIncludeCommon(bool &Result, Token &Tok, // Search include directories. const DirectoryLookup *CurDir; - const FileEntry *File = PP.LookupFile(Filename, - SourceLocation(),// produce no warnings. - isAngled, LookupFrom, CurDir); + const FileEntry *File = PP.LookupFile(Filename, isAngled, LookupFrom, CurDir); // Get the result value. Result = true means the file exists. Result = File != 0; diff --git a/lib/Lex/Pragma.cpp b/lib/Lex/Pragma.cpp index 856b3bd..63b23b6 100644 --- a/lib/Lex/Pragma.cpp +++ b/lib/Lex/Pragma.cpp @@ -301,8 +301,7 @@ void Preprocessor::HandlePragmaDependency(Token &DependencyTok) { // Search include directories for this file. const DirectoryLookup *CurDir; - const FileEntry *File = LookupFile(Filename, FilenameTok.getLocation(), - isAngled, 0, CurDir); + const FileEntry *File = LookupFile(Filename, isAngled, 0, CurDir); if (File == 0) { Diag(FilenameTok, diag::err_pp_file_not_found) << Filename; return; diff --git a/lib/Lex/Preprocessor.cpp b/lib/Lex/Preprocessor.cpp index 26bb3a9..5689baa 100644 --- a/lib/Lex/Preprocessor.cpp +++ b/lib/Lex/Preprocessor.cpp @@ -429,21 +429,17 @@ SourceLocation Preprocessor::AdvanceToTokenCharacter(SourceLocation TokStart, return TokStart.getFileLocWithOffset(PhysOffset); } -/// \brief Computes the source location just past the end of the -/// token at this source location. -/// -/// This routine can be used to produce a source location that -/// points just past the end of the token referenced by \p Loc, and -/// is generally used when a diagnostic needs to point just after a -/// token where it expected something different that it received. If -/// the returned source location would not be meaningful (e.g., if -/// it points into a macro), this routine returns an invalid -/// source location. -SourceLocation Preprocessor::getLocForEndOfToken(SourceLocation Loc) { +SourceLocation Preprocessor::getLocForEndOfToken(SourceLocation Loc, + unsigned Offset) { if (Loc.isInvalid() || !Loc.isFileID()) return SourceLocation(); unsigned Len = Lexer::MeasureTokenLength(Loc, getSourceManager(), Features); + if (Len > Offset) + Len = Len - Offset; + else + return Loc; + return AdvanceToTokenCharacter(Loc, Len); } @@ -583,11 +579,18 @@ void Preprocessor::RemoveCommentHandler(CommentHandler *Handler) { CommentHandlers.erase(Pos); } -void Preprocessor::HandleComment(SourceRange Comment) { +bool Preprocessor::HandleComment(Token &result, SourceRange Comment) { + bool AnyPendingTokens = false; for (std::vector<CommentHandler *>::iterator H = CommentHandlers.begin(), HEnd = CommentHandlers.end(); - H != HEnd; ++H) - (*H)->HandleComment(*this, Comment); + H != HEnd; ++H) { + if ((*H)->HandleComment(*this, Comment)) + AnyPendingTokens = true; + } + if (!AnyPendingTokens || getCommentRetentionState()) + return false; + Lex(result); + return true; } CommentHandler::~CommentHandler() { } diff --git a/lib/Makefile b/lib/Makefile index adf9474..d499ee5 100755 --- a/lib/Makefile +++ b/lib/Makefile @@ -8,8 +8,8 @@ ##===----------------------------------------------------------------------===## LEVEL = ../../.. -PARALLEL_DIRS = Headers Basic Lex Parse AST Sema CodeGen Analysis Rewrite \ - Frontend Index Driver +PARALLEL_DIRS = Headers Runtime Basic Lex Parse AST Sema CodeGen Analysis \ + Rewrite Frontend Index Driver include $(LEVEL)/Makefile.common diff --git a/lib/Parse/DeclSpec.cpp b/lib/Parse/DeclSpec.cpp index f52d8b9..9e5f5a2 100644 --- a/lib/Parse/DeclSpec.cpp +++ b/lib/Parse/DeclSpec.cpp @@ -373,11 +373,30 @@ void DeclSpec::setProtocolQualifiers(const ActionBase::DeclPtrTy *Protos, ProtocolLAngleLoc = LAngleLoc; } +void DeclSpec::SaveWrittenBuiltinSpecs() { + writtenBS.Sign = getTypeSpecSign(); + writtenBS.Width = getTypeSpecWidth(); + writtenBS.Type = getTypeSpecType(); + // Search the list of attributes for the presence of a mode attribute. + writtenBS.ModeAttr = false; + AttributeList* attrs = getAttributes(); + while (attrs) { + if (attrs->getKind() == AttributeList::AT_mode) { + writtenBS.ModeAttr = true; + break; + } + attrs = attrs->getNext(); + } +} + /// Finish - This does final analysis of the declspec, rejecting things like /// "_Imaginary" (lacking an FP type). This returns a diagnostic to issue or /// diag::NUM_DIAGNOSTICS if there is no error. After calling this method, /// DeclSpec is guaranteed self-consistent, even if an error occurred. void DeclSpec::Finish(Diagnostic &D, Preprocessor &PP) { + // Before possibly changing their values, save specs as written. + SaveWrittenBuiltinSpecs(); + // Check the type specifier components first. SourceManager &SrcMgr = PP.getSourceManager(); diff --git a/lib/Parse/MinimalAction.cpp b/lib/Parse/MinimalAction.cpp index 8b207fa..5f48897 100644 --- a/lib/Parse/MinimalAction.cpp +++ b/lib/Parse/MinimalAction.cpp @@ -204,6 +204,7 @@ MinimalAction::ActOnStartClassInterface(SourceLocation AtInterfaceLoc, SourceLocation SuperLoc, const DeclPtrTy *ProtoRefs, unsigned NumProtocols, + const SourceLocation *ProtoLocs, SourceLocation EndProtoLoc, AttributeList *AttrList) { // Allocate and add the 'TypeNameInfo' "decl". diff --git a/lib/Parse/ParseDeclCXX.cpp b/lib/Parse/ParseDeclCXX.cpp index 90040c5..efaf8ee 100644 --- a/lib/Parse/ParseDeclCXX.cpp +++ b/lib/Parse/ParseDeclCXX.cpp @@ -983,7 +983,7 @@ Parser::BaseResult Parser::ParseBaseSpecifier(DeclPtrTy ClassDecl) { // Parse an (optional) access specifier. AccessSpecifier Access = getAccessSpecifierIfPresent(); - if (Access) + if (Access != AS_none) ConsumeToken(); // Parse the 'virtual' keyword (again!), in case it came after the @@ -1398,15 +1398,35 @@ void Parser::ParseCXXMemberSpecification(SourceLocation RecordLoc, PP.getSourceManager(), "parsing struct/union/class body"); - // Determine whether this is a top-level (non-nested) class. - bool TopLevelClass = ClassStack.empty() || - CurScope->isInCXXInlineMethodScope(); + // Determine whether this is a non-nested class. Note that local + // classes are *not* considered to be nested classes. + bool NonNestedClass = true; + if (!ClassStack.empty()) { + for (const Scope *S = CurScope; S; S = S->getParent()) { + if (S->isClassScope()) { + // We're inside a class scope, so this is a nested class. + NonNestedClass = false; + break; + } + + if ((S->getFlags() & Scope::FnScope)) { + // If we're in a function or function template declared in the + // body of a class, then this is a local class rather than a + // nested class. + const Scope *Parent = S->getParent(); + if (Parent->isTemplateParamScope()) + Parent = Parent->getParent(); + if (Parent->isClassScope()) + break; + } + } + } // Enter a scope for the class. ParseScope ClassScope(this, Scope::ClassScope|Scope::DeclScope); // Note that we are parsing a new (potentially-nested) class definition. - ParsingClassDefinition ParsingDef(*this, TagDecl, TopLevelClass); + ParsingClassDefinition ParsingDef(*this, TagDecl, NonNestedClass); if (TagDecl) Actions.ActOnTagStartDefinition(CurScope, TagDecl); @@ -1484,7 +1504,7 @@ void Parser::ParseCXXMemberSpecification(SourceLocation RecordLoc, // // FIXME: Only function bodies and constructor ctor-initializers are // parsed correctly, fix the rest. - if (TopLevelClass) { + if (NonNestedClass) { // We are not inside a nested class. This class and its nested classes // are complete and we can parse the delayed portions of method // declarations and the lexed inline method definitions. @@ -1666,10 +1686,10 @@ bool Parser::ParseExceptionSpecification(SourceLocation &EndLoc, /// \brief We have just started parsing the definition of a new class, /// so push that class onto our stack of classes that is currently /// being parsed. -void Parser::PushParsingClass(DeclPtrTy ClassDecl, bool TopLevelClass) { - assert((TopLevelClass || !ClassStack.empty()) && +void Parser::PushParsingClass(DeclPtrTy ClassDecl, bool NonNestedClass) { + assert((NonNestedClass || !ClassStack.empty()) && "Nested class without outer class"); - ClassStack.push(new ParsingClass(ClassDecl, TopLevelClass)); + ClassStack.push(new ParsingClass(ClassDecl, NonNestedClass)); } /// \brief Deallocate the given parsed class and all of its nested diff --git a/lib/Parse/ParseObjc.cpp b/lib/Parse/ParseObjc.cpp index 5e23635..ae85aa3 100644 --- a/lib/Parse/ParseObjc.cpp +++ b/lib/Parse/ParseObjc.cpp @@ -186,6 +186,7 @@ Parser::DeclPtrTy Parser::ParseObjCAtInterfaceDeclaration( categoryId, categoryLoc, ProtocolRefs.data(), ProtocolRefs.size(), + ProtocolLocs.data(), EndProtoLoc); ParseObjCInterfaceDeclList(CategoryType, tok::objc_not_keyword); @@ -224,6 +225,7 @@ Parser::DeclPtrTy Parser::ParseObjCAtInterfaceDeclaration( Actions.ActOnStartClassInterface(atLoc, nameId, nameLoc, superClassId, superClassLoc, ProtocolRefs.data(), ProtocolRefs.size(), + ProtocolLocs.data(), EndProtoLoc, attrList); if (Tok.is(tok::l_brace)) @@ -1127,6 +1129,7 @@ Parser::DeclPtrTy Parser::ParseObjCAtProtocolDeclaration(SourceLocation AtLoc, Actions.ActOnStartProtocolInterface(AtLoc, protocolName, nameLoc, ProtocolRefs.data(), ProtocolRefs.size(), + ProtocolLocs.data(), EndProtoLoc, attrList); ParseObjCInterfaceDeclList(ProtoType, tok::objc_protocol); return ProtoType; diff --git a/lib/Parse/Parser.cpp b/lib/Parse/Parser.cpp index 0aecac9..f2bc303 100644 --- a/lib/Parse/Parser.cpp +++ b/lib/Parse/Parser.cpp @@ -29,8 +29,9 @@ class ActionCommentHandler : public CommentHandler { public: explicit ActionCommentHandler(Action &Actions) : Actions(Actions) { } - virtual void HandleComment(Preprocessor &PP, SourceRange Comment) { + virtual bool HandleComment(Preprocessor &PP, SourceRange Comment) { Actions.ActOnComment(Comment); + return false; } }; diff --git a/lib/Rewrite/DeltaTree.cpp b/lib/Rewrite/DeltaTree.cpp index 101cf93..35e888b 100644 --- a/lib/Rewrite/DeltaTree.cpp +++ b/lib/Rewrite/DeltaTree.cpp @@ -20,7 +20,7 @@ using llvm::cast; using llvm::dyn_cast; /// The DeltaTree class is a multiway search tree (BTree) structure with some -/// fancy features. B-Trees are are generally more memory and cache efficient +/// fancy features. B-Trees are generally more memory and cache efficient /// than binary trees, because they store multiple keys/values in each node. /// /// DeltaTree implements a key/value mapping from FileIndex to Delta, allowing diff --git a/lib/Sema/CodeCompleteConsumer.cpp b/lib/Sema/CodeCompleteConsumer.cpp index fbd1450..8c4caaf 100644 --- a/lib/Sema/CodeCompleteConsumer.cpp +++ b/lib/Sema/CodeCompleteConsumer.cpp @@ -572,11 +572,11 @@ CIndexCodeCompleteConsumer::ProcessCodeCompleteResults(Sema &SemaRef, break; case Decl::ObjCImplementation: - Kind = CXCursor_ObjCClassDefn; + Kind = CXCursor_ObjCImplementationDecl; break; case Decl::ObjCCategoryImpl: - Kind = CXCursor_ObjCCategoryDefn; + Kind = CXCursor_ObjCCategoryImplDecl; break; default: diff --git a/lib/Sema/Lookup.h b/lib/Sema/Lookup.h index 9064de6..f4cea2e 100644 --- a/lib/Sema/Lookup.h +++ b/lib/Sema/Lookup.h @@ -123,9 +123,7 @@ public: Temporary }; - typedef llvm::SmallVector<NamedDecl*, 4> DeclsTy; - typedef DeclsTy::const_iterator iterator; - + typedef UnresolvedSetImpl::iterator iterator; typedef bool (*ResultFilter)(NamedDecl*, unsigned IDNS); LookupResult(Sema &SemaRef, DeclarationName Name, SourceLocation NameLoc, @@ -133,6 +131,7 @@ public: Sema::RedeclarationKind Redecl = Sema::NotForRedeclaration) : ResultKind(NotFound), Paths(0), + NamingClass(0), SemaRef(SemaRef), Name(Name), NameLoc(NameLoc), @@ -152,6 +151,7 @@ public: LookupResult(TemporaryToken _, const LookupResult &Other) : ResultKind(NotFound), Paths(0), + NamingClass(0), SemaRef(Other.SemaRef), Name(Other.Name), NameLoc(Other.NameLoc), @@ -224,8 +224,8 @@ public: return Ambiguity; } - iterator begin() const { return Decls.begin(); } - iterator end() const { return Decls.end(); } + iterator begin() const { return iterator(Decls.begin()); } + iterator end() const { return iterator(Decls.end()); } /// \brief Return true if no decls were found bool empty() const { return Decls.empty(); } @@ -247,32 +247,57 @@ public: return IDNS; } - /// \brief Add a declaration to these results. Does not test the - /// acceptance criteria. + /// \brief Returns whether these results arose from performing a + /// lookup into a class. + bool isClassLookup() const { + return NamingClass != 0; + } + + /// \brief Returns the 'naming class' for this lookup, i.e. the + /// class which was looked into to find these results. + /// + /// C++0x [class.access.base]p5: + /// The access to a member is affected by the class in which the + /// member is named. This naming class is the class in which the + /// member name was looked up and found. [Note: this class can be + /// explicit, e.g., when a qualified-id is used, or implicit, + /// e.g., when a class member access operator (5.2.5) is used + /// (including cases where an implicit "this->" is added). If both + /// a class member access operator and a qualified-id are used to + /// name the member (as in p->T::m), the class naming the member + /// is the class named by the nested-name-specifier of the + /// qualified-id (that is, T). -- end note ] + /// + /// This is set by the lookup routines when they find results in a class. + CXXRecordDecl *getNamingClass() const { + return NamingClass; + } + + /// \brief Sets the 'naming class' for this lookup. + void setNamingClass(CXXRecordDecl *Record) { + NamingClass = Record; + } + + /// \brief Add a declaration to these results with its natural access. + /// Does not test the acceptance criteria. void addDecl(NamedDecl *D) { - Decls.push_back(D); + addDecl(D, D->getAccess()); + } + + /// \brief Add a declaration to these results with the given access. + /// Does not test the acceptance criteria. + void addDecl(NamedDecl *D, AccessSpecifier AS) { + Decls.addDecl(D, AS); ResultKind = Found; } /// \brief Add all the declarations from another set of lookup /// results. void addAllDecls(const LookupResult &Other) { - Decls.append(Other.begin(), Other.end()); + Decls.append(Other.Decls.begin(), Other.Decls.end()); ResultKind = Found; } - /// \brief Hides a set of declarations. - template <class NamedDeclSet> void hideDecls(const NamedDeclSet &Set) { - unsigned I = 0, N = Decls.size(); - while (I < N) { - if (Set.count(Decls[I])) - Decls[I] = Decls[--N]; - else - I++; - } - Decls.set_size(N); - } - /// \brief Determine whether no result was found because we could not /// search into dependent base classes of the current instantiation. bool wasNotFoundInCurrentInstantiation() const { @@ -319,13 +344,13 @@ public: NamedDecl *getFoundDecl() const { assert(getResultKind() == Found && "getFoundDecl called on non-unique result"); - return Decls[0]->getUnderlyingDecl(); + return (*begin())->getUnderlyingDecl(); } /// Fetches a representative decl. Useful for lazy diagnostics. NamedDecl *getRepresentativeDecl() const { assert(!Decls.empty() && "cannot get representative of empty set"); - return Decls[0]; + return *begin(); } /// \brief Asks if the result is a single tag decl. @@ -403,7 +428,7 @@ public: /// sugared. class Filter { LookupResult &Results; - unsigned I; + LookupResult::iterator I; bool Changed; #ifndef NDEBUG bool CalledDone; @@ -411,7 +436,7 @@ public: friend class LookupResult; Filter(LookupResult &Results) - : Results(Results), I(0), Changed(false) + : Results(Results), I(Results.begin()), Changed(false) #ifndef NDEBUG , CalledDone(false) #endif @@ -426,23 +451,30 @@ public: #endif bool hasNext() const { - return I != Results.Decls.size(); + return I != Results.end(); } NamedDecl *next() { - assert(I < Results.Decls.size() && "next() called on empty filter"); - return Results.Decls[I++]; + assert(I != Results.end() && "next() called on empty filter"); + return *I++; } /// Erase the last element returned from this iterator. void erase() { - Results.Decls[--I] = Results.Decls.back(); - Results.Decls.pop_back(); + Results.Decls.erase(--I); Changed = true; } + /// Replaces the current entry with the given one, preserving the + /// access bits. void replace(NamedDecl *D) { - Results.Decls[I-1] = D; + Results.Decls.replace(I-1, D); + Changed = true; + } + + /// Replaces the current entry with the given one. + void replace(NamedDecl *D, AccessSpecifier AS) { + Results.Decls.replace(I-1, D, AS); Changed = true; } @@ -466,6 +498,8 @@ private: void diagnose() { if (isAmbiguous()) SemaRef.DiagnoseAmbiguousLookup(*this); + else if (isClassLookup() && SemaRef.getLangOptions().AccessControl) + SemaRef.CheckAccess(*this); } void setAmbiguous(AmbiguityKind AK) { @@ -482,7 +516,7 @@ private: assert(ResultKind != Found || Decls.size() == 1); assert(ResultKind != FoundOverloaded || Decls.size() > 1 || (Decls.size() == 1 && - isa<FunctionTemplateDecl>(Decls[0]->getUnderlyingDecl()))); + isa<FunctionTemplateDecl>((*begin())->getUnderlyingDecl()))); assert(ResultKind != FoundUnresolvedValue || sanityCheckUnresolved()); assert(ResultKind != Ambiguous || Decls.size() > 1 || (Decls.size() == 1 && Ambiguity == AmbiguousBaseSubobjects)); @@ -492,8 +526,7 @@ private: } bool sanityCheckUnresolved() const { - for (DeclsTy::const_iterator I = Decls.begin(), E = Decls.end(); - I != E; ++I) + for (iterator I = begin(), E = end(); I != E; ++I) if (isa<UnresolvedUsingValueDecl>(*I)) return true; return false; @@ -504,8 +537,9 @@ private: // Results. LookupResultKind ResultKind; AmbiguityKind Ambiguity; // ill-defined unless ambiguous - DeclsTy Decls; + UnresolvedSet<8> Decls; CXXBasePaths *Paths; + CXXRecordDecl *NamingClass; // Parameters. Sema &SemaRef; diff --git a/lib/Sema/Sema.h b/lib/Sema/Sema.h index fab7292..06e9e3a 100644 --- a/lib/Sema/Sema.h +++ b/lib/Sema/Sema.h @@ -1291,6 +1291,17 @@ public: ObjCContainerDecl* IDecl, bool IncompleteImpl = false); + /// DiagnoseUnimplementedProperties - This routine warns on those properties + /// which must be implemented by this implementation. + void DiagnoseUnimplementedProperties(ObjCImplDecl* IMPDecl, + ObjCContainerDecl *CDecl, + const llvm::DenseSet<Selector>& InsMap); + + /// CollectImmediateProperties - This routine collects all properties in + /// the class and its conforming protocols; but not those it its super class. + void CollectImmediateProperties(ObjCContainerDecl *CDecl, + llvm::DenseMap<IdentifierInfo *, ObjCPropertyDecl*>& PropMap); + /// AtomicPropertySetterGetterRules - This routine enforces the rule (via /// warning) when atomic property has one but not the other user-declared /// setter or getter. @@ -1651,6 +1662,11 @@ public: virtual OwningExprResult ActOnCastExpr(Scope *S, SourceLocation LParenLoc, TypeTy *Ty, SourceLocation RParenLoc, ExprArg Op); + OwningExprResult BuildCStyleCastExpr(SourceLocation LParenLoc, + TypeSourceInfo *Ty, + SourceLocation RParenLoc, + ExprArg Op); + virtual bool TypeIsVectorType(TypeTy *Ty) { return GetTypeFromParser(Ty)->isVectorType(); } @@ -1658,13 +1674,18 @@ public: OwningExprResult MaybeConvertParenListExprToParenExpr(Scope *S, ExprArg ME); OwningExprResult ActOnCastOfParenListExpr(Scope *S, SourceLocation LParenLoc, SourceLocation RParenLoc, ExprArg E, - QualType Ty); + TypeSourceInfo *TInfo); virtual OwningExprResult ActOnCompoundLiteral(SourceLocation LParenLoc, TypeTy *Ty, SourceLocation RParenLoc, ExprArg Op); + OwningExprResult BuildCompoundLiteralExpr(SourceLocation LParenLoc, + TypeSourceInfo *TInfo, + SourceLocation RParenLoc, + ExprArg InitExpr); + virtual OwningExprResult ActOnInitList(SourceLocation LParenLoc, MultiExprArg InitList, SourceLocation RParenLoc); @@ -1920,6 +1941,13 @@ public: ExprArg E, SourceLocation RParenLoc); + OwningExprResult BuildCXXNamedCast(SourceLocation OpLoc, + tok::TokenKind Kind, + TypeSourceInfo *Ty, + ExprArg E, + SourceRange AngleBrackets, + SourceRange Parens); + /// ActOnCXXTypeid - Parse typeid( something ). virtual OwningExprResult ActOnCXXTypeid(SourceLocation OpLoc, SourceLocation LParenLoc, bool isType, @@ -2033,7 +2061,6 @@ public: bool isDependentScopeSpecifier(const CXXScopeSpec &SS); CXXRecordDecl *getCurrentInstantiationOf(NestedNameSpecifier *NNS); bool isUnknownSpecialization(const CXXScopeSpec &SS); - bool isCurrentInstantiationWithDependentBases(const CXXScopeSpec &SS); /// ActOnCXXGlobalScopeSpecifier - Return the object that represents the /// global scope ('::'). @@ -2334,6 +2361,9 @@ public: CXXBasePaths &Paths, bool NoPrivileges = false); + void CheckAccess(const LookupResult &R); + bool CheckAccess(const LookupResult &R, NamedDecl *D, AccessSpecifier Access); + bool CheckBaseClassAccess(QualType Derived, QualType Base, unsigned InaccessibleBaseID, CXXBasePaths& Paths, SourceLocation AccessLoc, @@ -3153,13 +3183,17 @@ public: /// relevant to this particular scope). LocalInstantiationScope *Outer; + /// \brief Whether we have already exited this scope. + bool Exited; + // This class is non-copyable LocalInstantiationScope(const LocalInstantiationScope &); LocalInstantiationScope &operator=(const LocalInstantiationScope &); public: LocalInstantiationScope(Sema &SemaRef, bool CombineWithOuterScope = false) - : SemaRef(SemaRef), Outer(SemaRef.CurrentInstantiationScope) { + : SemaRef(SemaRef), Outer(SemaRef.CurrentInstantiationScope), + Exited(false) { if (!CombineWithOuterScope) SemaRef.CurrentInstantiationScope = this; else @@ -3168,7 +3202,15 @@ public: } ~LocalInstantiationScope() { + if (!Exited) + SemaRef.CurrentInstantiationScope = Outer; + } + + /// \brief Exit this local instantiation scope early. + void Exit() { SemaRef.CurrentInstantiationScope = Outer; + LocalDecls.clear(); + Exited = true; } Decl *getInstantiationOf(const Decl *D) { @@ -3215,7 +3257,16 @@ public: /// but have not yet been performed. std::deque<PendingImplicitInstantiation> PendingImplicitInstantiations; - void PerformPendingImplicitInstantiations(); + /// \brief The queue of implicit template instantiations that are required + /// and must be performed within the current local scope. + /// + /// This queue is only used for member functions of local classes in + /// templates, which must be instantiated in the same scope as their + /// enclosing function, so that they can reference function-local + /// types, static variables, enumerators, etc. + std::deque<PendingImplicitInstantiation> PendingLocalImplicitInstantiations; + + void PerformPendingImplicitInstantiations(bool LocalOnly = false); TypeSourceInfo *SubstType(TypeSourceInfo *T, const MultiLevelTemplateArgumentList &TemplateArgs, @@ -3300,6 +3351,7 @@ public: SourceLocation SuperLoc, const DeclPtrTy *ProtoRefs, unsigned NumProtoRefs, + const SourceLocation *ProtoLocs, SourceLocation EndProtoLoc, AttributeList *AttrList); @@ -3317,6 +3369,7 @@ public: SourceLocation AtProtoInterfaceLoc, IdentifierInfo *ProtocolName, SourceLocation ProtocolLoc, const DeclPtrTy *ProtoRefNames, unsigned NumProtoRefs, + const SourceLocation *ProtoLocs, SourceLocation EndProtoLoc, AttributeList *AttrList); @@ -3327,6 +3380,7 @@ public: SourceLocation CategoryLoc, const DeclPtrTy *ProtoRefs, unsigned NumProtoRefs, + const SourceLocation *ProtoLocs, SourceLocation EndProtoLoc); virtual DeclPtrTy ActOnStartClassImplementation( @@ -3373,14 +3427,13 @@ public: ObjCMethodDecl *MethodDecl, bool IsInstance); - void MergeProtocolPropertiesIntoClass(Decl *CDecl, - DeclPtrTy MergeProtocols); + void CompareProperties(Decl *CDecl, DeclPtrTy MergeProtocols); void DiagnoseClassExtensionDupMethods(ObjCCategoryDecl *CAT, ObjCInterfaceDecl *ID); - void MergeOneProtocolPropertiesIntoClass(Decl *CDecl, - ObjCProtocolDecl *PDecl); + void MatchOneProtocolPropertiesInClass(Decl *CDecl, + ObjCProtocolDecl *PDecl); virtual void ActOnAtEnd(SourceRange AtEnd, DeclPtrTy classDecl, diff --git a/lib/Sema/SemaAccess.cpp b/lib/Sema/SemaAccess.cpp index b7cc37b..51f9e30 100644 --- a/lib/Sema/SemaAccess.cpp +++ b/lib/Sema/SemaAccess.cpp @@ -12,6 +12,7 @@ //===----------------------------------------------------------------------===// #include "Sema.h" +#include "Lookup.h" #include "clang/AST/ASTContext.h" #include "clang/AST/CXXInheritance.h" #include "clang/AST/DeclCXX.h" @@ -137,3 +138,101 @@ bool Sema::CheckBaseClassAccess(QualType Derived, QualType Base, return false; } + +/// Diagnose the path which caused the given declaration to become +/// inaccessible. +static void DiagnoseAccessPath(Sema &S, const LookupResult &R, NamedDecl *D, + AccessSpecifier Access) { + // Easy case: the decl's natural access determined its path access. + if (Access == D->getAccess() || D->getAccess() == AS_private) { + S.Diag(D->getLocation(), diag::note_access_natural) + << (unsigned) (Access == AS_protected); + return; + } + + // TODO: flesh this out + S.Diag(D->getLocation(), diag::note_access_constrained_by_path) + << (unsigned) (Access == AS_protected); +} + +/// Checks access to the given declaration in the current context. +/// +/// \param R the means via which the access was made; must have a naming +/// class set +/// \param D the declaration accessed +/// \param Access the best access along any inheritance path from the +/// naming class to the declaration. AS_none means the path is impossible +bool Sema::CheckAccess(const LookupResult &R, NamedDecl *D, + AccessSpecifier Access) { + assert(R.getNamingClass() && "performing access check without naming class"); + + // If the access path is public, it's accessible everywhere. + if (Access == AS_public) + return false; + + // Otherwise, derive the current class context. + DeclContext *DC = CurContext; + while (isa<CXXRecordDecl>(DC) && + cast<CXXRecordDecl>(DC)->isAnonymousStructOrUnion()) + DC = DC->getParent(); + + CXXRecordDecl *CurRecord; + if (isa<CXXRecordDecl>(DC)) + CurRecord = cast<CXXRecordDecl>(DC); + else if (isa<CXXMethodDecl>(DC)) + CurRecord = cast<CXXMethodDecl>(DC)->getParent(); + else { + Diag(R.getNameLoc(), diag::err_access_outside_class) + << (Access == AS_protected); + DiagnoseAccessPath(*this, R, D, Access); + return true; + } + + CXXRecordDecl *NamingClass = R.getNamingClass(); + while (NamingClass->isAnonymousStructOrUnion()) + // This should be guaranteed by the fact that the decl has + // non-public access. If not, we should make it guaranteed! + NamingClass = cast<CXXRecordDecl>(NamingClass); + + // White-list accesses from within the declaring class. + if (Access != AS_none && + CurRecord->getCanonicalDecl() == NamingClass->getCanonicalDecl()) + return false; + + // Protected access. + if (Access == AS_protected) { + // FIXME: implement [class.protected]p1 + if (CurRecord->isDerivedFrom(NamingClass)) + return false; + + // FIXME: dependent classes + } + + // FIXME: friends + + // Okay, it's a bad access, reject it. + + + CXXRecordDecl *DeclaringClass = cast<CXXRecordDecl>(D->getDeclContext()); + + if (Access == AS_protected) { + Diag(R.getNameLoc(), diag::err_access_protected) + << Context.getTypeDeclType(DeclaringClass) + << Context.getTypeDeclType(CurRecord); + DiagnoseAccessPath(*this, R, D, Access); + return true; + } + + assert(Access == AS_private || Access == AS_none); + Diag(R.getNameLoc(), diag::err_access_private) + << Context.getTypeDeclType(DeclaringClass) + << Context.getTypeDeclType(CurRecord); + DiagnoseAccessPath(*this, R, D, Access); + return true; +} + +/// Checks access to all the declarations in the given result set. +void Sema::CheckAccess(const LookupResult &R) { + for (LookupResult::iterator I = R.begin(), E = R.end(); I != E; ++I) + CheckAccess(R, *I, I.getAccess()); +} diff --git a/lib/Sema/SemaCXXCast.cpp b/lib/Sema/SemaCXXCast.cpp index f924bd3..57c4f9b 100644 --- a/lib/Sema/SemaCXXCast.cpp +++ b/lib/Sema/SemaCXXCast.cpp @@ -116,11 +116,26 @@ Sema::ActOnCXXNamedCast(SourceLocation OpLoc, tok::TokenKind Kind, SourceLocation RAngleBracketLoc, SourceLocation LParenLoc, ExprArg E, SourceLocation RParenLoc) { + + TypeSourceInfo *DestTInfo; + QualType DestType = GetTypeFromParser(Ty, &DestTInfo); + if (!DestTInfo) + DestTInfo = Context.getTrivialTypeSourceInfo(DestType, SourceLocation()); + + return BuildCXXNamedCast(OpLoc, Kind, DestTInfo, move(E), + SourceRange(LAngleBracketLoc, RAngleBracketLoc), + SourceRange(LParenLoc, RParenLoc)); +} + +Action::OwningExprResult +Sema::BuildCXXNamedCast(SourceLocation OpLoc, tok::TokenKind Kind, + TypeSourceInfo *DestTInfo, ExprArg E, + SourceRange AngleBrackets, SourceRange Parens) { Expr *Ex = E.takeAs<Expr>(); - // FIXME: Preserve type source info. - QualType DestType = GetTypeFromParser(Ty); - SourceRange OpRange(OpLoc, RParenLoc); - SourceRange DestRange(LAngleBracketLoc, RAngleBracketLoc); + QualType DestType = DestTInfo->getType(); + + SourceRange OpRange(OpLoc, Parens.getEnd()); + SourceRange DestRange = AngleBrackets; // If the type is dependent, we won't do the semantic analysis now. // FIXME: should we check this in a more fine-grained manner? @@ -133,14 +148,14 @@ Sema::ActOnCXXNamedCast(SourceLocation OpLoc, tok::TokenKind Kind, if (!TypeDependent) CheckConstCast(*this, Ex, DestType, OpRange, DestRange); return Owned(new (Context) CXXConstCastExpr(DestType.getNonReferenceType(), - Ex, DestType, OpLoc)); + Ex, DestTInfo, OpLoc)); case tok::kw_dynamic_cast: { CastExpr::CastKind Kind = CastExpr::CK_Unknown; if (!TypeDependent) CheckDynamicCast(*this, Ex, DestType, OpRange, DestRange, Kind); return Owned(new (Context)CXXDynamicCastExpr(DestType.getNonReferenceType(), - Kind, Ex, DestType, OpLoc)); + Kind, Ex, DestTInfo, OpLoc)); } case tok::kw_reinterpret_cast: { CastExpr::CastKind Kind = CastExpr::CK_Unknown; @@ -148,7 +163,7 @@ Sema::ActOnCXXNamedCast(SourceLocation OpLoc, tok::TokenKind Kind, CheckReinterpretCast(*this, Ex, DestType, OpRange, DestRange, Kind); return Owned(new (Context) CXXReinterpretCastExpr( DestType.getNonReferenceType(), - Kind, Ex, DestType, OpLoc)); + Kind, Ex, DestTInfo, OpLoc)); } case tok::kw_static_cast: { CastExpr::CastKind Kind = CastExpr::CK_Unknown; @@ -169,7 +184,7 @@ Sema::ActOnCXXNamedCast(SourceLocation OpLoc, tok::TokenKind Kind, } return Owned(new (Context) CXXStaticCastExpr(DestType.getNonReferenceType(), - Kind, Ex, DestType, OpLoc)); + Kind, Ex, DestTInfo, OpLoc)); } } diff --git a/lib/Sema/SemaCXXScopeSpec.cpp b/lib/Sema/SemaCXXScopeSpec.cpp index 8594583..7a0b625 100644 --- a/lib/Sema/SemaCXXScopeSpec.cpp +++ b/lib/Sema/SemaCXXScopeSpec.cpp @@ -30,9 +30,9 @@ getCurrentInstantiationOf(ASTContext &Context, DeclContext *CurContext, if (T.isNull()) return 0; - T = Context.getCanonicalType(T); + T = Context.getCanonicalType(T).getUnqualifiedType(); - for (DeclContext *Ctx = CurContext; Ctx; Ctx = Ctx->getParent()) { + for (DeclContext *Ctx = CurContext; Ctx; Ctx = Ctx->getLookupParent()) { // If we've hit a namespace or the global scope, then the // nested-name-specifier can't refer to the current instantiation. if (Ctx->isFileContext()) @@ -210,28 +210,6 @@ bool Sema::isUnknownSpecialization(const CXXScopeSpec &SS) { return getCurrentInstantiationOf(NNS) == 0; } -/// \brief Determine whether the given scope specifier refers to a -/// current instantiation that has any dependent base clases. -/// -/// This check is typically used when we've performed lookup into the -/// current instantiation of a template, but that lookup failed. When -/// there are dependent bases present, however, the lookup needs to be -/// delayed until template instantiation time. -bool Sema::isCurrentInstantiationWithDependentBases(const CXXScopeSpec &SS) { - if (!SS.isSet()) - return false; - - NestedNameSpecifier *NNS = (NestedNameSpecifier*)SS.getScopeRep(); - if (!NNS->isDependent()) - return false; - - CXXRecordDecl *CurrentInstantiation = getCurrentInstantiationOf(NNS); - if (!CurrentInstantiation) - return false; - - return CurrentInstantiation->hasAnyDependentBases(); -} - /// \brief If the given nested name specifier refers to the current /// instantiation, return the declaration that corresponds to that /// current instantiation (C++0x [temp.dep.type]p1). diff --git a/lib/Sema/SemaChecking.cpp b/lib/Sema/SemaChecking.cpp index 5f124e4..6ff8b1d 100644 --- a/lib/Sema/SemaChecking.cpp +++ b/lib/Sema/SemaChecking.cpp @@ -13,14 +13,22 @@ //===----------------------------------------------------------------------===// #include "Sema.h" +#include "clang/Analysis/CFG.h" +#include "clang/Analysis/PathSensitive/AnalysisContext.h" #include "clang/AST/ASTContext.h" #include "clang/AST/CharUnits.h" #include "clang/AST/DeclObjC.h" #include "clang/AST/ExprCXX.h" #include "clang/AST/ExprObjC.h" +#include "clang/AST/DeclObjC.h" +#include "clang/AST/StmtCXX.h" +#include "clang/AST/StmtObjC.h" #include "clang/Lex/LiteralSupport.h" #include "clang/Lex/Preprocessor.h" +#include "llvm/ADT/BitVector.h" +#include "llvm/ADT/STLExtras.h" #include <limits> +#include <queue> using namespace clang; /// getLocationOfStringLiteralByte - Return a source location that points to the @@ -2029,3 +2037,522 @@ void Sema::CheckImplicitConversion(Expr *E, QualType T) { return; } +// MarkLive - Mark all the blocks reachable from e as live. Returns the total +// number of blocks just marked live. +static unsigned MarkLive(CFGBlock *e, llvm::BitVector &live) { + unsigned count = 0; + std::queue<CFGBlock*> workq; + // Prep work queue + live.set(e->getBlockID()); + ++count; + workq.push(e); + // Solve + while (!workq.empty()) { + CFGBlock *item = workq.front(); + workq.pop(); + for (CFGBlock::succ_iterator I=item->succ_begin(), + E=item->succ_end(); + I != E; + ++I) { + if ((*I) && !live[(*I)->getBlockID()]) { + live.set((*I)->getBlockID()); + ++count; + workq.push(*I); + } + } + } + return count; +} + +static SourceLocation GetUnreachableLoc(CFGBlock &b, SourceRange &R1, + SourceRange &R2) { + Stmt *S; + unsigned sn = 0; + R1 = R2 = SourceRange(); + + top: + if (sn < b.size()) + S = b[sn].getStmt(); + else if (b.getTerminator()) + S = b.getTerminator(); + else + return SourceLocation(); + + switch (S->getStmtClass()) { + case Expr::BinaryOperatorClass: { + BinaryOperator *BO = cast<BinaryOperator>(S); + if (BO->getOpcode() == BinaryOperator::Comma) { + if (sn+1 < b.size()) + return b[sn+1].getStmt()->getLocStart(); + CFGBlock *n = &b; + while (1) { + if (n->getTerminator()) + return n->getTerminator()->getLocStart(); + if (n->succ_size() != 1) + return SourceLocation(); + n = n[0].succ_begin()[0]; + if (n->pred_size() != 1) + return SourceLocation(); + if (!n->empty()) + return n[0][0].getStmt()->getLocStart(); + } + } + R1 = BO->getLHS()->getSourceRange(); + R2 = BO->getRHS()->getSourceRange(); + return BO->getOperatorLoc(); + } + case Expr::UnaryOperatorClass: { + const UnaryOperator *UO = cast<UnaryOperator>(S); + R1 = UO->getSubExpr()->getSourceRange(); + return UO->getOperatorLoc(); + } + case Expr::CompoundAssignOperatorClass: { + const CompoundAssignOperator *CAO = cast<CompoundAssignOperator>(S); + R1 = CAO->getLHS()->getSourceRange(); + R2 = CAO->getRHS()->getSourceRange(); + return CAO->getOperatorLoc(); + } + case Expr::ConditionalOperatorClass: { + const ConditionalOperator *CO = cast<ConditionalOperator>(S); + return CO->getQuestionLoc(); + } + case Expr::MemberExprClass: { + const MemberExpr *ME = cast<MemberExpr>(S); + R1 = ME->getSourceRange(); + return ME->getMemberLoc(); + } + case Expr::ArraySubscriptExprClass: { + const ArraySubscriptExpr *ASE = cast<ArraySubscriptExpr>(S); + R1 = ASE->getLHS()->getSourceRange(); + R2 = ASE->getRHS()->getSourceRange(); + return ASE->getRBracketLoc(); + } + case Expr::CStyleCastExprClass: { + const CStyleCastExpr *CSC = cast<CStyleCastExpr>(S); + R1 = CSC->getSubExpr()->getSourceRange(); + return CSC->getLParenLoc(); + } + case Expr::CXXFunctionalCastExprClass: { + const CXXFunctionalCastExpr *CE = cast <CXXFunctionalCastExpr>(S); + R1 = CE->getSubExpr()->getSourceRange(); + return CE->getTypeBeginLoc(); + } + case Expr::ImplicitCastExprClass: + ++sn; + goto top; + case Stmt::CXXTryStmtClass: { + return cast<CXXTryStmt>(S)->getHandler(0)->getCatchLoc(); + } + default: ; + } + R1 = S->getSourceRange(); + return S->getLocStart(); +} + +static SourceLocation MarkLiveTop(CFGBlock *e, llvm::BitVector &live, + SourceManager &SM) { + std::queue<CFGBlock*> workq; + // Prep work queue + workq.push(e); + SourceRange R1, R2; + SourceLocation top = GetUnreachableLoc(*e, R1, R2); + bool FromMainFile = false; + bool FromSystemHeader = false; + bool TopValid = false; + if (top.isValid()) { + FromMainFile = SM.isFromMainFile(top); + FromSystemHeader = SM.isInSystemHeader(top); + TopValid = true; + } + // Solve + while (!workq.empty()) { + CFGBlock *item = workq.front(); + workq.pop(); + SourceLocation c = GetUnreachableLoc(*item, R1, R2); + if (c.isValid() + && (!TopValid + || (SM.isFromMainFile(c) && !FromMainFile) + || (FromSystemHeader && !SM.isInSystemHeader(c)) + || SM.isBeforeInTranslationUnit(c, top))) { + top = c; + FromMainFile = SM.isFromMainFile(top); + FromSystemHeader = SM.isInSystemHeader(top); + } + live.set(item->getBlockID()); + for (CFGBlock::succ_iterator I=item->succ_begin(), + E=item->succ_end(); + I != E; + ++I) { + if ((*I) && !live[(*I)->getBlockID()]) { + live.set((*I)->getBlockID()); + workq.push(*I); + } + } + } + return top; +} + +static int LineCmp(const void *p1, const void *p2) { + SourceLocation *Line1 = (SourceLocation *)p1; + SourceLocation *Line2 = (SourceLocation *)p2; + return !(*Line1 < *Line2); +} + +namespace { + struct ErrLoc { + SourceLocation Loc; + SourceRange R1; + SourceRange R2; + ErrLoc(SourceLocation l, SourceRange r1, SourceRange r2) + : Loc(l), R1(r1), R2(r2) { } + }; +} + +/// CheckUnreachable - Check for unreachable code. +void Sema::CheckUnreachable(AnalysisContext &AC) { + unsigned count; + // We avoid checking when there are errors, as the CFG won't faithfully match + // the user's code. + if (getDiagnostics().hasErrorOccurred()) + return; + if (Diags.getDiagnosticLevel(diag::warn_unreachable) == Diagnostic::Ignored) + return; + + CFG *cfg = AC.getCFG(); + if (cfg == 0) + return; + + llvm::BitVector live(cfg->getNumBlockIDs()); + // Mark all live things first. + count = MarkLive(&cfg->getEntry(), live); + + if (count == cfg->getNumBlockIDs()) + // If there are no dead blocks, we're done. + return; + + SourceRange R1, R2; + + llvm::SmallVector<ErrLoc, 24> lines; + bool AddEHEdges = AC.getAddEHEdges(); + // First, give warnings for blocks with no predecessors, as they + // can't be part of a loop. + for (CFG::iterator I = cfg->begin(), E = cfg->end(); I != E; ++I) { + CFGBlock &b = **I; + if (!live[b.getBlockID()]) { + if (b.pred_begin() == b.pred_end()) { + if (!AddEHEdges && b.getTerminator() + && isa<CXXTryStmt>(b.getTerminator())) { + // When not adding EH edges from calls, catch clauses + // can otherwise seem dead. Avoid noting them as dead. + count += MarkLive(&b, live); + continue; + } + SourceLocation c = GetUnreachableLoc(b, R1, R2); + if (!c.isValid()) { + // Blocks without a location can't produce a warning, so don't mark + // reachable blocks from here as live. + live.set(b.getBlockID()); + ++count; + continue; + } + lines.push_back(ErrLoc(c, R1, R2)); + // Avoid excessive errors by marking everything reachable from here + count += MarkLive(&b, live); + } + } + } + + if (count < cfg->getNumBlockIDs()) { + // And then give warnings for the tops of loops. + for (CFG::iterator I = cfg->begin(), E = cfg->end(); I != E; ++I) { + CFGBlock &b = **I; + if (!live[b.getBlockID()]) + // Avoid excessive errors by marking everything reachable from here + lines.push_back(ErrLoc(MarkLiveTop(&b, live, Context.getSourceManager()), SourceRange(), SourceRange())); + } + } + + llvm::array_pod_sort(lines.begin(), lines.end(), LineCmp); + for (llvm::SmallVector<ErrLoc, 24>::iterator I = lines.begin(), + E = lines.end(); + I != E; + ++I) + if (I->Loc.isValid()) + Diag(I->Loc, diag::warn_unreachable) << I->R1 << I->R2; +} + +/// CheckFallThrough - Check that we don't fall off the end of a +/// Statement that should return a value. +/// +/// \returns AlwaysFallThrough iff we always fall off the end of the statement, +/// MaybeFallThrough iff we might or might not fall off the end, +/// NeverFallThroughOrReturn iff we never fall off the end of the statement or +/// return. We assume NeverFallThrough iff we never fall off the end of the +/// statement but we may return. We assume that functions not marked noreturn +/// will return. +Sema::ControlFlowKind Sema::CheckFallThrough(AnalysisContext &AC) { + CFG *cfg = AC.getCFG(); + if (cfg == 0) + // FIXME: This should be NeverFallThrough + return NeverFallThroughOrReturn; + + // The CFG leaves in dead things, and we don't want the dead code paths to + // confuse us, so we mark all live things first. + std::queue<CFGBlock*> workq; + llvm::BitVector live(cfg->getNumBlockIDs()); + unsigned count = MarkLive(&cfg->getEntry(), live); + + bool AddEHEdges = AC.getAddEHEdges(); + if (!AddEHEdges && count != cfg->getNumBlockIDs()) + // When there are things remaining dead, and we didn't add EH edges + // from CallExprs to the catch clauses, we have to go back and + // mark them as live. + for (CFG::iterator I = cfg->begin(), E = cfg->end(); I != E; ++I) { + CFGBlock &b = **I; + if (!live[b.getBlockID()]) { + if (b.pred_begin() == b.pred_end()) { + if (b.getTerminator() && isa<CXXTryStmt>(b.getTerminator())) + // When not adding EH edges from calls, catch clauses + // can otherwise seem dead. Avoid noting them as dead. + count += MarkLive(&b, live); + continue; + } + } + } + + // Now we know what is live, we check the live precessors of the exit block + // and look for fall through paths, being careful to ignore normal returns, + // and exceptional paths. + bool HasLiveReturn = false; + bool HasFakeEdge = false; + bool HasPlainEdge = false; + bool HasAbnormalEdge = false; + for (CFGBlock::pred_iterator I=cfg->getExit().pred_begin(), + E = cfg->getExit().pred_end(); + I != E; + ++I) { + CFGBlock& B = **I; + if (!live[B.getBlockID()]) + continue; + if (B.size() == 0) { + if (B.getTerminator() && isa<CXXTryStmt>(B.getTerminator())) { + HasAbnormalEdge = true; + continue; + } + + // A labeled empty statement, or the entry block... + HasPlainEdge = true; + continue; + } + Stmt *S = B[B.size()-1]; + if (isa<ReturnStmt>(S)) { + HasLiveReturn = true; + continue; + } + if (isa<ObjCAtThrowStmt>(S)) { + HasFakeEdge = true; + continue; + } + if (isa<CXXThrowExpr>(S)) { + HasFakeEdge = true; + continue; + } + if (const AsmStmt *AS = dyn_cast<AsmStmt>(S)) { + if (AS->isMSAsm()) { + HasFakeEdge = true; + HasLiveReturn = true; + continue; + } + } + if (isa<CXXTryStmt>(S)) { + HasAbnormalEdge = true; + continue; + } + + bool NoReturnEdge = false; + if (CallExpr *C = dyn_cast<CallExpr>(S)) { + if (B.succ_begin()[0] != &cfg->getExit()) { + HasAbnormalEdge = true; + continue; + } + Expr *CEE = C->getCallee()->IgnoreParenCasts(); + if (CEE->getType().getNoReturnAttr()) { + NoReturnEdge = true; + HasFakeEdge = true; + } else if (DeclRefExpr *DRE = dyn_cast<DeclRefExpr>(CEE)) { + ValueDecl *VD = DRE->getDecl(); + if (VD->hasAttr<NoReturnAttr>()) { + NoReturnEdge = true; + HasFakeEdge = true; + } + } + } + // FIXME: Add noreturn message sends. + if (NoReturnEdge == false) + HasPlainEdge = true; + } + if (!HasPlainEdge) { + if (HasLiveReturn) + return NeverFallThrough; + return NeverFallThroughOrReturn; + } + if (HasAbnormalEdge || HasFakeEdge || HasLiveReturn) + return MaybeFallThrough; + // This says AlwaysFallThrough for calls to functions that are not marked + // noreturn, that don't return. If people would like this warning to be more + // accurate, such functions should be marked as noreturn. + return AlwaysFallThrough; +} + +/// CheckFallThroughForFunctionDef - Check that we don't fall off the end of a +/// function that should return a value. Check that we don't fall off the end +/// of a noreturn function. We assume that functions and blocks not marked +/// noreturn will return. +void Sema::CheckFallThroughForFunctionDef(Decl *D, Stmt *Body, + AnalysisContext &AC) { + // FIXME: Would be nice if we had a better way to control cascading errors, + // but for now, avoid them. The problem is that when Parse sees: + // int foo() { return a; } + // The return is eaten and the Sema code sees just: + // int foo() { } + // which this code would then warn about. + if (getDiagnostics().hasErrorOccurred()) + return; + + bool ReturnsVoid = false; + bool HasNoReturn = false; + if (FunctionDecl *FD = dyn_cast<FunctionDecl>(D)) { + // If the result type of the function is a dependent type, we don't know + // whether it will be void or not, so don't + if (FD->getResultType()->isDependentType()) + return; + if (FD->getResultType()->isVoidType()) + ReturnsVoid = true; + if (FD->hasAttr<NoReturnAttr>()) + HasNoReturn = true; + } else if (ObjCMethodDecl *MD = dyn_cast<ObjCMethodDecl>(D)) { + if (MD->getResultType()->isVoidType()) + ReturnsVoid = true; + if (MD->hasAttr<NoReturnAttr>()) + HasNoReturn = true; + } + + // Short circuit for compilation speed. + if ((Diags.getDiagnosticLevel(diag::warn_maybe_falloff_nonvoid_function) + == Diagnostic::Ignored || ReturnsVoid) + && (Diags.getDiagnosticLevel(diag::warn_noreturn_function_has_return_expr) + == Diagnostic::Ignored || !HasNoReturn) + && (Diags.getDiagnosticLevel(diag::warn_suggest_noreturn_block) + == Diagnostic::Ignored || !ReturnsVoid)) + return; + // FIXME: Function try block + if (CompoundStmt *Compound = dyn_cast<CompoundStmt>(Body)) { + switch (CheckFallThrough(AC)) { + case MaybeFallThrough: + if (HasNoReturn) + Diag(Compound->getRBracLoc(), diag::warn_falloff_noreturn_function); + else if (!ReturnsVoid) + Diag(Compound->getRBracLoc(),diag::warn_maybe_falloff_nonvoid_function); + break; + case AlwaysFallThrough: + if (HasNoReturn) + Diag(Compound->getRBracLoc(), diag::warn_falloff_noreturn_function); + else if (!ReturnsVoid) + Diag(Compound->getRBracLoc(), diag::warn_falloff_nonvoid_function); + break; + case NeverFallThroughOrReturn: + if (ReturnsVoid && !HasNoReturn) + Diag(Compound->getLBracLoc(), diag::warn_suggest_noreturn_function); + break; + case NeverFallThrough: + break; + } + } +} + +/// CheckFallThroughForBlock - Check that we don't fall off the end of a block +/// that should return a value. Check that we don't fall off the end of a +/// noreturn block. We assume that functions and blocks not marked noreturn +/// will return. +void Sema::CheckFallThroughForBlock(QualType BlockTy, Stmt *Body, + AnalysisContext &AC) { + // FIXME: Would be nice if we had a better way to control cascading errors, + // but for now, avoid them. The problem is that when Parse sees: + // int foo() { return a; } + // The return is eaten and the Sema code sees just: + // int foo() { } + // which this code would then warn about. + if (getDiagnostics().hasErrorOccurred()) + return; + bool ReturnsVoid = false; + bool HasNoReturn = false; + if (const FunctionType *FT =BlockTy->getPointeeType()->getAs<FunctionType>()){ + if (FT->getResultType()->isVoidType()) + ReturnsVoid = true; + if (FT->getNoReturnAttr()) + HasNoReturn = true; + } + + // Short circuit for compilation speed. + if (ReturnsVoid + && !HasNoReturn + && (Diags.getDiagnosticLevel(diag::warn_suggest_noreturn_block) + == Diagnostic::Ignored || !ReturnsVoid)) + return; + // FIXME: Funtion try block + if (CompoundStmt *Compound = dyn_cast<CompoundStmt>(Body)) { + switch (CheckFallThrough(AC)) { + case MaybeFallThrough: + if (HasNoReturn) + Diag(Compound->getRBracLoc(), diag::err_noreturn_block_has_return_expr); + else if (!ReturnsVoid) + Diag(Compound->getRBracLoc(), diag::err_maybe_falloff_nonvoid_block); + break; + case AlwaysFallThrough: + if (HasNoReturn) + Diag(Compound->getRBracLoc(), diag::err_noreturn_block_has_return_expr); + else if (!ReturnsVoid) + Diag(Compound->getRBracLoc(), diag::err_falloff_nonvoid_block); + break; + case NeverFallThroughOrReturn: + if (ReturnsVoid) + Diag(Compound->getLBracLoc(), diag::warn_suggest_noreturn_block); + break; + case NeverFallThrough: + break; + } + } +} + +/// CheckParmsForFunctionDef - Check that the parameters of the given +/// function are appropriate for the definition of a function. This +/// takes care of any checks that cannot be performed on the +/// declaration itself, e.g., that the types of each of the function +/// parameters are complete. +bool Sema::CheckParmsForFunctionDef(FunctionDecl *FD) { + bool HasInvalidParm = false; + for (unsigned p = 0, NumParams = FD->getNumParams(); p < NumParams; ++p) { + ParmVarDecl *Param = FD->getParamDecl(p); + + // C99 6.7.5.3p4: the parameters in a parameter type list in a + // function declarator that is part of a function definition of + // that function shall not have incomplete type. + // + // This is also C++ [dcl.fct]p6. + if (!Param->isInvalidDecl() && + RequireCompleteType(Param->getLocation(), Param->getType(), + diag::err_typecheck_decl_incomplete_type)) { + Param->setInvalidDecl(); + HasInvalidParm = true; + } + + // C99 6.9.1p5: If the declarator includes a parameter type list, the + // declaration of each parameter shall include an identifier. + if (Param->getIdentifier() == 0 && + !Param->isImplicit() && + !getLangOptions().CPlusPlus) + Diag(Param->getLocation(), diag::err_parameter_name_omitted); + } + + return HasInvalidParm; +} diff --git a/lib/Sema/SemaCodeComplete.cpp b/lib/Sema/SemaCodeComplete.cpp index a4cda01..fcd419b 100644 --- a/lib/Sema/SemaCodeComplete.cpp +++ b/lib/Sema/SemaCodeComplete.cpp @@ -2234,30 +2234,36 @@ void Sema::CodeCompleteCall(Scope *S, ExprTy *FnIn, // FIXME: What if we're calling a pseudo-destructor? // FIXME: What if we're calling a member function? + typedef CodeCompleteConsumer::OverloadCandidate ResultCandidate; + llvm::SmallVector<ResultCandidate, 8> Results; + Expr *NakedFn = Fn->IgnoreParenCasts(); if (UnresolvedLookupExpr *ULE = dyn_cast<UnresolvedLookupExpr>(NakedFn)) AddOverloadedCallCandidates(ULE, Args, NumArgs, CandidateSet, /*PartialOverloading=*/ true); else if (DeclRefExpr *DRE = dyn_cast<DeclRefExpr>(NakedFn)) { FunctionDecl *FDecl = dyn_cast<FunctionDecl>(DRE->getDecl()); - if (FDecl) - AddOverloadCandidate(FDecl, Args, NumArgs, CandidateSet, - false, false, /*PartialOverloading*/ true); + if (FDecl) { + if (!FDecl->getType()->getAs<FunctionProtoType>()) + Results.push_back(ResultCandidate(FDecl)); + else + AddOverloadCandidate(FDecl, Args, NumArgs, CandidateSet, + false, false, /*PartialOverloading*/ true); + } } - // Sort the overload candidate set by placing the best overloads first. - std::stable_sort(CandidateSet.begin(), CandidateSet.end(), - IsBetterOverloadCandidate(*this)); + if (!CandidateSet.empty()) { + // Sort the overload candidate set by placing the best overloads first. + std::stable_sort(CandidateSet.begin(), CandidateSet.end(), + IsBetterOverloadCandidate(*this)); - // Add the remaining viable overload candidates as code-completion reslults. - typedef CodeCompleteConsumer::OverloadCandidate ResultCandidate; - llvm::SmallVector<ResultCandidate, 8> Results; - - for (OverloadCandidateSet::iterator Cand = CandidateSet.begin(), - CandEnd = CandidateSet.end(); - Cand != CandEnd; ++Cand) { - if (Cand->Viable) - Results.push_back(ResultCandidate(Cand->Function)); + // Add the remaining viable overload candidates as code-completion reslults. + for (OverloadCandidateSet::iterator Cand = CandidateSet.begin(), + CandEnd = CandidateSet.end(); + Cand != CandEnd; ++Cand) { + if (Cand->Viable) + Results.push_back(ResultCandidate(Cand->Function)); + } } if (Results.empty()) diff --git a/lib/Sema/SemaDecl.cpp b/lib/Sema/SemaDecl.cpp index 0ccb8f2..fbe0289 100644 --- a/lib/Sema/SemaDecl.cpp +++ b/lib/Sema/SemaDecl.cpp @@ -18,13 +18,10 @@ #include "clang/AST/APValue.h" #include "clang/AST/ASTConsumer.h" #include "clang/AST/ASTContext.h" -#include "clang/Analysis/CFG.h" #include "clang/AST/CXXInheritance.h" -#include "clang/AST/DeclObjC.h" #include "clang/AST/DeclTemplate.h" #include "clang/AST/ExprCXX.h" #include "clang/AST/StmtCXX.h" -#include "clang/AST/StmtObjC.h" #include "clang/Parse/DeclSpec.h" #include "clang/Parse/ParseDiagnostic.h" #include "clang/Parse/Template.h" @@ -34,13 +31,10 @@ // FIXME: layering (ideally, Sema shouldn't be dependent on Lex API's) #include "clang/Lex/Preprocessor.h" #include "clang/Lex/HeaderSearch.h" -#include "llvm/ADT/BitVector.h" -#include "llvm/ADT/STLExtras.h" #include "llvm/ADT/Triple.h" #include <algorithm> #include <cstring> #include <functional> -#include <queue> using namespace clang; /// getDeclName - Return a pretty name for the specified decl if possible, or @@ -1305,382 +1299,9 @@ void Sema::MergeVarDecl(VarDecl *New, LookupResult &Previous) { // Keep a chain of previous declarations. New->setPreviousDeclaration(Old); -} - -static void MarkLive(CFGBlock *e, llvm::BitVector &live) { - std::queue<CFGBlock*> workq; - // Prep work queue - workq.push(e); - // Solve - while (!workq.empty()) { - CFGBlock *item = workq.front(); - workq.pop(); - live.set(item->getBlockID()); - for (CFGBlock::succ_iterator I=item->succ_begin(), - E=item->succ_end(); - I != E; - ++I) { - if ((*I) && !live[(*I)->getBlockID()]) { - live.set((*I)->getBlockID()); - workq.push(*I); - } - } - } -} - -static SourceLocation MarkLiveTop(CFGBlock *e, llvm::BitVector &live, - SourceManager &SM) { - std::queue<CFGBlock*> workq; - // Prep work queue - workq.push(e); - SourceLocation top; - if (!e->empty()) - top = e[0][0].getStmt()->getLocStart(); - bool FromMainFile = false; - bool FromSystemHeader = false; - bool TopValid = false; - if (top.isValid()) { - FromMainFile = SM.isFromMainFile(top); - FromSystemHeader = SM.isInSystemHeader(top); - TopValid = true; - } - // Solve - while (!workq.empty()) { - CFGBlock *item = workq.front(); - workq.pop(); - SourceLocation c; - if (!item->empty()) - c = item[0][0].getStmt()->getLocStart(); - else if (item->getTerminator()) - c = item->getTerminator()->getLocStart(); - if (c.isValid() - && (!TopValid - || (SM.isFromMainFile(c) && !FromMainFile) - || (FromSystemHeader && !SM.isInSystemHeader(c)) - || SM.isBeforeInTranslationUnit(c, top))) { - top = c; - FromMainFile = SM.isFromMainFile(top); - FromSystemHeader = SM.isInSystemHeader(top); - } - live.set(item->getBlockID()); - for (CFGBlock::succ_iterator I=item->succ_begin(), - E=item->succ_end(); - I != E; - ++I) { - if ((*I) && !live[(*I)->getBlockID()]) { - live.set((*I)->getBlockID()); - workq.push(*I); - } - } - } - return top; -} -namespace { -class LineCmp { - SourceManager &SM; -public: - LineCmp(SourceManager &sm) : SM(sm) { - } - bool operator () (SourceLocation l1, SourceLocation l2) { - return l1 < l2; - } -}; -} - -/// CheckUnreachable - Check for unreachable code. -void Sema::CheckUnreachable(AnalysisContext &AC) { - // We avoid checking when there are errors, as the CFG won't faithfully match - // the user's code. - if (getDiagnostics().hasErrorOccurred()) - return; - if (Diags.getDiagnosticLevel(diag::warn_unreachable) == Diagnostic::Ignored) - return; - - CFG *cfg = AC.getCFG(); - if (cfg == 0) - return; - - llvm::BitVector live(cfg->getNumBlockIDs()); - // Mark all live things first. - MarkLive(&cfg->getEntry(), live); - - llvm::SmallVector<SourceLocation, 24> lines; - // First, give warnings for blocks with no predecessors, as they - // can't be part of a loop. - for (CFG::iterator I = cfg->begin(), E = cfg->end(); I != E; ++I) { - CFGBlock &b = **I; - if (!live[b.getBlockID()]) { - if (b.pred_begin() == b.pred_end()) { - if (!b.empty()) - lines.push_back(b[0].getStmt()->getLocStart()); - else if (b.getTerminator()) - lines.push_back(b.getTerminator()->getLocStart()); - // Avoid excessive errors by marking everything reachable from here - MarkLive(&b, live); - } - } - } - - // And then give warnings for the tops of loops. - for (CFG::iterator I = cfg->begin(), E = cfg->end(); I != E; ++I) { - CFGBlock &b = **I; - if (!live[b.getBlockID()]) - // Avoid excessive errors by marking everything reachable from here - lines.push_back(MarkLiveTop(&b, live, Context.getSourceManager())); - } - - std::sort(lines.begin(), lines.end(), LineCmp(Context.getSourceManager())); - for (llvm::SmallVector<SourceLocation, 24>::iterator I = lines.begin(), - E = lines.end(); - I != E; - ++I) - if (I->isValid()) - Diag(*I, diag::warn_unreachable); -} - -/// CheckFallThrough - Check that we don't fall off the end of a -/// Statement that should return a value. -/// -/// \returns AlwaysFallThrough iff we always fall off the end of the statement, -/// MaybeFallThrough iff we might or might not fall off the end, -/// NeverFallThroughOrReturn iff we never fall off the end of the statement or -/// return. We assume NeverFallThrough iff we never fall off the end of the -/// statement but we may return. We assume that functions not marked noreturn -/// will return. -Sema::ControlFlowKind Sema::CheckFallThrough(AnalysisContext &AC) { - CFG *cfg = AC.getCFG(); - if (cfg == 0) - // FIXME: This should be NeverFallThrough - return NeverFallThroughOrReturn; - - // The CFG leaves in dead things, and we don't want to dead code paths to - // confuse us, so we mark all live things first. - std::queue<CFGBlock*> workq; - llvm::BitVector live(cfg->getNumBlockIDs()); - MarkLive(&cfg->getEntry(), live); - - // Now we know what is live, we check the live precessors of the exit block - // and look for fall through paths, being careful to ignore normal returns, - // and exceptional paths. - bool HasLiveReturn = false; - bool HasFakeEdge = false; - bool HasPlainEdge = false; - for (CFGBlock::pred_iterator I=cfg->getExit().pred_begin(), - E = cfg->getExit().pred_end(); - I != E; - ++I) { - CFGBlock& B = **I; - if (!live[B.getBlockID()]) - continue; - if (B.size() == 0) { - // A labeled empty statement, or the entry block... - HasPlainEdge = true; - continue; - } - Stmt *S = B[B.size()-1]; - if (isa<ReturnStmt>(S)) { - HasLiveReturn = true; - continue; - } - if (isa<ObjCAtThrowStmt>(S)) { - HasFakeEdge = true; - continue; - } - if (isa<CXXThrowExpr>(S)) { - HasFakeEdge = true; - continue; - } - if (const AsmStmt *AS = dyn_cast<AsmStmt>(S)) { - if (AS->isMSAsm()) { - HasFakeEdge = true; - HasLiveReturn = true; - continue; - } - } - - bool NoReturnEdge = false; - if (CallExpr *C = dyn_cast<CallExpr>(S)) { - Expr *CEE = C->getCallee()->IgnoreParenCasts(); - if (CEE->getType().getNoReturnAttr()) { - NoReturnEdge = true; - HasFakeEdge = true; - } else if (DeclRefExpr *DRE = dyn_cast<DeclRefExpr>(CEE)) { - ValueDecl *VD = DRE->getDecl(); - if (VD->hasAttr<NoReturnAttr>()) { - NoReturnEdge = true; - HasFakeEdge = true; - } - } - } - // FIXME: Add noreturn message sends. - if (NoReturnEdge == false) - HasPlainEdge = true; - } - if (!HasPlainEdge) { - if (HasLiveReturn) - return NeverFallThrough; - return NeverFallThroughOrReturn; - } - if (HasFakeEdge || HasLiveReturn) - return MaybeFallThrough; - // This says AlwaysFallThrough for calls to functions that are not marked - // noreturn, that don't return. If people would like this warning to be more - // accurate, such functions should be marked as noreturn. - return AlwaysFallThrough; -} - -/// CheckFallThroughForFunctionDef - Check that we don't fall off the end of a -/// function that should return a value. Check that we don't fall off the end -/// of a noreturn function. We assume that functions and blocks not marked -/// noreturn will return. -void Sema::CheckFallThroughForFunctionDef(Decl *D, Stmt *Body, - AnalysisContext &AC) { - // FIXME: Would be nice if we had a better way to control cascading errors, - // but for now, avoid them. The problem is that when Parse sees: - // int foo() { return a; } - // The return is eaten and the Sema code sees just: - // int foo() { } - // which this code would then warn about. - if (getDiagnostics().hasErrorOccurred()) - return; - - bool ReturnsVoid = false; - bool HasNoReturn = false; - if (FunctionDecl *FD = dyn_cast<FunctionDecl>(D)) { - // If the result type of the function is a dependent type, we don't know - // whether it will be void or not, so don't - if (FD->getResultType()->isDependentType()) - return; - if (FD->getResultType()->isVoidType()) - ReturnsVoid = true; - if (FD->hasAttr<NoReturnAttr>()) - HasNoReturn = true; - } else if (ObjCMethodDecl *MD = dyn_cast<ObjCMethodDecl>(D)) { - if (MD->getResultType()->isVoidType()) - ReturnsVoid = true; - if (MD->hasAttr<NoReturnAttr>()) - HasNoReturn = true; - } - - // Short circuit for compilation speed. - if ((Diags.getDiagnosticLevel(diag::warn_maybe_falloff_nonvoid_function) - == Diagnostic::Ignored || ReturnsVoid) - && (Diags.getDiagnosticLevel(diag::warn_noreturn_function_has_return_expr) - == Diagnostic::Ignored || !HasNoReturn) - && (Diags.getDiagnosticLevel(diag::warn_suggest_noreturn_block) - == Diagnostic::Ignored || !ReturnsVoid)) - return; - // FIXME: Function try block - if (CompoundStmt *Compound = dyn_cast<CompoundStmt>(Body)) { - switch (CheckFallThrough(AC)) { - case MaybeFallThrough: - if (HasNoReturn) - Diag(Compound->getRBracLoc(), diag::warn_falloff_noreturn_function); - else if (!ReturnsVoid) - Diag(Compound->getRBracLoc(),diag::warn_maybe_falloff_nonvoid_function); - break; - case AlwaysFallThrough: - if (HasNoReturn) - Diag(Compound->getRBracLoc(), diag::warn_falloff_noreturn_function); - else if (!ReturnsVoid) - Diag(Compound->getRBracLoc(), diag::warn_falloff_nonvoid_function); - break; - case NeverFallThroughOrReturn: - if (ReturnsVoid && !HasNoReturn) - Diag(Compound->getLBracLoc(), diag::warn_suggest_noreturn_function); - break; - case NeverFallThrough: - break; - } - } -} - -/// CheckFallThroughForBlock - Check that we don't fall off the end of a block -/// that should return a value. Check that we don't fall off the end of a -/// noreturn block. We assume that functions and blocks not marked noreturn -/// will return. -void Sema::CheckFallThroughForBlock(QualType BlockTy, Stmt *Body, - AnalysisContext &AC) { - // FIXME: Would be nice if we had a better way to control cascading errors, - // but for now, avoid them. The problem is that when Parse sees: - // int foo() { return a; } - // The return is eaten and the Sema code sees just: - // int foo() { } - // which this code would then warn about. - if (getDiagnostics().hasErrorOccurred()) - return; - bool ReturnsVoid = false; - bool HasNoReturn = false; - if (const FunctionType *FT =BlockTy->getPointeeType()->getAs<FunctionType>()){ - if (FT->getResultType()->isVoidType()) - ReturnsVoid = true; - if (FT->getNoReturnAttr()) - HasNoReturn = true; - } - - // Short circuit for compilation speed. - if (ReturnsVoid - && !HasNoReturn - && (Diags.getDiagnosticLevel(diag::warn_suggest_noreturn_block) - == Diagnostic::Ignored || !ReturnsVoid)) - return; - // FIXME: Funtion try block - if (CompoundStmt *Compound = dyn_cast<CompoundStmt>(Body)) { - switch (CheckFallThrough(AC)) { - case MaybeFallThrough: - if (HasNoReturn) - Diag(Compound->getRBracLoc(), diag::err_noreturn_block_has_return_expr); - else if (!ReturnsVoid) - Diag(Compound->getRBracLoc(), diag::err_maybe_falloff_nonvoid_block); - break; - case AlwaysFallThrough: - if (HasNoReturn) - Diag(Compound->getRBracLoc(), diag::err_noreturn_block_has_return_expr); - else if (!ReturnsVoid) - Diag(Compound->getRBracLoc(), diag::err_falloff_nonvoid_block); - break; - case NeverFallThroughOrReturn: - if (ReturnsVoid) - Diag(Compound->getLBracLoc(), diag::warn_suggest_noreturn_block); - break; - case NeverFallThrough: - break; - } - } -} - -/// CheckParmsForFunctionDef - Check that the parameters of the given -/// function are appropriate for the definition of a function. This -/// takes care of any checks that cannot be performed on the -/// declaration itself, e.g., that the types of each of the function -/// parameters are complete. -bool Sema::CheckParmsForFunctionDef(FunctionDecl *FD) { - bool HasInvalidParm = false; - for (unsigned p = 0, NumParams = FD->getNumParams(); p < NumParams; ++p) { - ParmVarDecl *Param = FD->getParamDecl(p); - - // C99 6.7.5.3p4: the parameters in a parameter type list in a - // function declarator that is part of a function definition of - // that function shall not have incomplete type. - // - // This is also C++ [dcl.fct]p6. - if (!Param->isInvalidDecl() && - RequireCompleteType(Param->getLocation(), Param->getType(), - diag::err_typecheck_decl_incomplete_type)) { - Param->setInvalidDecl(); - HasInvalidParm = true; - } - - // C99 6.9.1p5: If the declarator includes a parameter type list, the - // declaration of each parameter shall include an identifier. - if (Param->getIdentifier() == 0 && - !Param->isImplicit() && - !getLangOptions().CPlusPlus) - Diag(Param->getLocation(), diag::err_parameter_name_omitted); - } - - return HasInvalidParm; + // Inherit access appropriately. + New->setAccess(Old->getAccess()); } /// ParsedFreeStandingDeclSpec - This method is invoked when a declspec with @@ -1773,6 +1394,7 @@ Sema::DeclPtrTy Sema::ParsedFreeStandingDeclSpec(Scope *S, DeclSpec &DS) { /// \return true if this is a forbidden redeclaration static bool CheckAnonMemberRedeclaration(Sema &SemaRef, Scope *S, + DeclContext *Owner, DeclarationName Name, SourceLocation NameLoc, unsigned diagnostic) { @@ -1785,6 +1407,11 @@ static bool CheckAnonMemberRedeclaration(Sema &SemaRef, // Pick a representative declaration. NamedDecl *PrevDecl = R.getRepresentativeDecl()->getUnderlyingDecl(); + if (PrevDecl && Owner->isRecord()) { + RecordDecl *Record = cast<RecordDecl>(Owner); + if (!SemaRef.isDeclInScope(PrevDecl, Record, S)) + return false; + } SemaRef.Diag(NameLoc, diagnostic) << Name; SemaRef.Diag(PrevDecl->getLocation(), diag::note_previous_declaration); @@ -1819,7 +1446,7 @@ bool Sema::InjectAnonymousStructOrUnionMembers(Scope *S, DeclContext *Owner, FEnd = AnonRecord->field_end(); F != FEnd; ++F) { if ((*F)->getDeclName()) { - if (CheckAnonMemberRedeclaration(*this, S, (*F)->getDeclName(), + if (CheckAnonMemberRedeclaration(*this, S, Owner, (*F)->getDeclName(), (*F)->getLocation(), diagKind)) { // C++ [class.union]p2: // The names of the members of an anonymous union shall be @@ -3243,7 +2870,7 @@ Sema::ActOnFunctionDeclarator(Scope* S, Declarator& D, DeclContext* DC, // Synthesize a parameter for each argument type. for (FunctionProtoType::arg_type_iterator AI = FT->arg_type_begin(), AE = FT->arg_type_end(); AI != AE; ++AI) { - ParmVarDecl *Param = ParmVarDecl::Create(Context, DC, + ParmVarDecl *Param = ParmVarDecl::Create(Context, NewFD, SourceLocation(), 0, *AI, /*TInfo=*/0, VarDecl::None, 0); @@ -3322,6 +2949,10 @@ Sema::ActOnFunctionDeclarator(Scope* S, Declarator& D, DeclContext* DC, } if (D.getCXXScopeSpec().isSet() && !NewFD->isInvalidDecl()) { + // Fake up an access specifier if it's supposed to be a class member. + if (isa<CXXRecordDecl>(NewFD->getDeclContext())) + NewFD->setAccess(AS_public); + // An out-of-line member function declaration must also be a // definition (C++ [dcl.meaning]p1). // Note that this is not the case for explicit specializations of @@ -3332,7 +2963,8 @@ Sema::ActOnFunctionDeclarator(Scope* S, Declarator& D, DeclContext* DC, Diag(NewFD->getLocation(), diag::err_out_of_line_declaration) << D.getCXXScopeSpec().getRange(); NewFD->setInvalidDecl(); - } else if (!Redeclaration) { + } else if (!Redeclaration && + !(isFriend && CurContext->isDependentContext())) { // The user tried to provide an out-of-line definition for a // function that is a member of a class or namespace, but there // was no such member function declared (C++ [class.mfct]p2, @@ -4236,8 +3868,13 @@ Sema::ActOnParamDeclarator(Scope *S, Declarator &D) { QualType T = adjustParameterType(parmDeclType); + // Temporarily put parameter variables in the translation unit, not + // the enclosing context. This prevents them from accidentally + // looking like class members in C++. + DeclContext *DC = Context.getTranslationUnitDecl(); + ParmVarDecl *New - = ParmVarDecl::Create(Context, CurContext, D.getIdentifierLoc(), II, + = ParmVarDecl::Create(Context, DC, D.getIdentifierLoc(), II, T, TInfo, StorageClass, 0); if (D.isInvalidType()) @@ -4476,7 +4113,9 @@ Sema::DeclPtrTy Sema::ActOnFinishFunctionBody(DeclPtrTy D, StmtArg BodyArg, Decl *dcl = D.getAs<Decl>(); Stmt *Body = BodyArg.takeAs<Stmt>(); - AnalysisContext AC(dcl); + // Don't generate EH edges for CallExprs as we'd like to avoid the n^2 + // explosion for destrutors that can result and the compile time hit. + AnalysisContext AC(dcl, false); FunctionDecl *FD = 0; FunctionTemplateDecl *FunTmpl = dyn_cast_or_null<FunctionTemplateDecl>(dcl); if (FunTmpl) @@ -6064,7 +5703,8 @@ Sema::DeclPtrTy Sema::ActOnEnumConstant(Scope *S, DeclPtrTy theEnumDecl, // Verify that there isn't already something declared with this name in this // scope. - NamedDecl *PrevDecl = LookupSingleName(S, Id, LookupOrdinaryName); + NamedDecl *PrevDecl = LookupSingleName(S, Id, LookupOrdinaryName, + ForRedeclaration); if (PrevDecl && PrevDecl->isTemplateParameter()) { // Maybe we will complain about the shadowed template parameter. DiagnoseTemplateParameterShadow(IdLoc, PrevDecl); @@ -6092,8 +5732,10 @@ Sema::DeclPtrTy Sema::ActOnEnumConstant(Scope *S, DeclPtrTy theEnumDecl, IdLoc, Id, Owned(Val)); // Register this decl in the current scope stack. - if (New) + if (New) { + New->setAccess(TheEnumDecl->getAccess()); PushOnScopeChains(New, S); + } return DeclPtrTy::make(New); } diff --git a/lib/Sema/SemaDeclCXX.cpp b/lib/Sema/SemaDeclCXX.cpp index a81a04e..9ec95f3 100644 --- a/lib/Sema/SemaDeclCXX.cpp +++ b/lib/Sema/SemaDeclCXX.cpp @@ -1062,8 +1062,23 @@ Sema::ActOnMemInitializer(DeclPtrTy ConstructorD, if (!TyD) { if (R.isAmbiguous()) return true; + if (SS.isSet() && isDependentScopeSpecifier(SS)) { + bool NotUnknownSpecialization = false; + DeclContext *DC = computeDeclContext(SS, false); + if (CXXRecordDecl *Record = dyn_cast_or_null<CXXRecordDecl>(DC)) + NotUnknownSpecialization = !Record->hasAnyDependentBases(); + + if (!NotUnknownSpecialization) { + // When the scope specifier can refer to a member of an unknown + // specialization, we take it as a type name. + BaseType = CheckTypenameType((NestedNameSpecifier *)SS.getScopeRep(), + *MemberOrBase, SS.getRange()); + R.clear(); + } + } + // If no results were found, try to correct typos. - if (R.empty() && + if (R.empty() && BaseType.isNull() && CorrectTypo(R, S, &SS, ClassDecl) && R.isSingleResult()) { if (FieldDecl *Member = R.getAsSingle<FieldDecl>()) { if (Member->getDeclContext()->getLookupContext()->Equals(ClassDecl)) { @@ -1106,20 +1121,22 @@ Sema::ActOnMemInitializer(DeclPtrTy ConstructorD, } } - if (!TyD) { + if (!TyD && BaseType.isNull()) { Diag(IdLoc, diag::err_mem_init_not_member_or_class) << MemberOrBase << SourceRange(IdLoc, RParenLoc); return true; } } - BaseType = Context.getTypeDeclType(TyD); - if (SS.isSet()) { - NestedNameSpecifier *Qualifier = - static_cast<NestedNameSpecifier*>(SS.getScopeRep()); + if (BaseType.isNull()) { + BaseType = Context.getTypeDeclType(TyD); + if (SS.isSet()) { + NestedNameSpecifier *Qualifier = + static_cast<NestedNameSpecifier*>(SS.getScopeRep()); - // FIXME: preserve source range information - BaseType = Context.getQualifiedNameType(Qualifier, BaseType); + // FIXME: preserve source range information + BaseType = Context.getQualifiedNameType(Qualifier, BaseType); + } } } @@ -4470,9 +4487,9 @@ Sema::CheckReferenceInit(Expr *&Init, QualType DeclType, = dyn_cast<CXXRecordDecl>(T2->getAs<RecordType>()->getDecl()); OverloadCandidateSet CandidateSet; - const UnresolvedSet *Conversions + const UnresolvedSetImpl *Conversions = T2RecordDecl->getVisibleConversionFunctions(); - for (UnresolvedSet::iterator I = Conversions->begin(), + for (UnresolvedSetImpl::iterator I = Conversions->begin(), E = Conversions->end(); I != E; ++I) { NamedDecl *D = *I; CXXRecordDecl *ActingDC = cast<CXXRecordDecl>(D->getDeclContext()); @@ -5594,26 +5611,24 @@ bool Sema::CheckOverridingFunctionReturnType(const CXXMethodDecl *New, QualType NewTy = New->getType()->getAs<FunctionType>()->getResultType(); QualType OldTy = Old->getType()->getAs<FunctionType>()->getResultType(); - QualType CNewTy = Context.getCanonicalType(NewTy); - QualType COldTy = Context.getCanonicalType(OldTy); - - if (CNewTy == COldTy && - CNewTy.getLocalCVRQualifiers() == COldTy.getLocalCVRQualifiers()) + if (Context.hasSameType(NewTy, OldTy)) return false; // Check if the return types are covariant QualType NewClassTy, OldClassTy; /// Both types must be pointers or references to classes. - if (PointerType *NewPT = dyn_cast<PointerType>(NewTy)) { - if (PointerType *OldPT = dyn_cast<PointerType>(OldTy)) { + if (const PointerType *NewPT = NewTy->getAs<PointerType>()) { + if (const PointerType *OldPT = OldTy->getAs<PointerType>()) { NewClassTy = NewPT->getPointeeType(); OldClassTy = OldPT->getPointeeType(); } - } else if (ReferenceType *NewRT = dyn_cast<ReferenceType>(NewTy)) { - if (ReferenceType *OldRT = dyn_cast<ReferenceType>(OldTy)) { - NewClassTy = NewRT->getPointeeType(); - OldClassTy = OldRT->getPointeeType(); + } else if (const ReferenceType *NewRT = NewTy->getAs<ReferenceType>()) { + if (const ReferenceType *OldRT = OldTy->getAs<ReferenceType>()) { + if (NewRT->getTypeClass() == OldRT->getTypeClass()) { + NewClassTy = NewRT->getPointeeType(); + OldClassTy = OldRT->getPointeeType(); + } } } @@ -5661,7 +5676,7 @@ bool Sema::CheckOverridingFunctionReturnType(const CXXMethodDecl *New, } // The qualifiers of the return types must be the same. - if (CNewTy.getLocalCVRQualifiers() != COldTy.getLocalCVRQualifiers()) { + if (NewTy.getLocalCVRQualifiers() != OldTy.getLocalCVRQualifiers()) { Diag(New->getLocation(), diag::err_covariant_return_type_different_qualifications) << New->getDeclName() << NewTy << OldTy; diff --git a/lib/Sema/SemaDeclObjC.cpp b/lib/Sema/SemaDeclObjC.cpp index f2fc1f4..1b07d19 100644 --- a/lib/Sema/SemaDeclObjC.cpp +++ b/lib/Sema/SemaDeclObjC.cpp @@ -81,6 +81,7 @@ ActOnStartClassInterface(SourceLocation AtInterfaceLoc, IdentifierInfo *ClassName, SourceLocation ClassLoc, IdentifierInfo *SuperName, SourceLocation SuperLoc, const DeclPtrTy *ProtoRefs, unsigned NumProtoRefs, + const SourceLocation *ProtoLocs, SourceLocation EndProtoLoc, AttributeList *AttrList) { assert(ClassName && "Missing class identifier"); @@ -201,7 +202,7 @@ ActOnStartClassInterface(SourceLocation AtInterfaceLoc, /// Check then save referenced protocols. if (NumProtoRefs) { IDecl->setProtocolList((ObjCProtocolDecl**)ProtoRefs, NumProtoRefs, - Context); + ProtoLocs, Context); IDecl->setLocEnd(EndProtoLoc); } @@ -279,6 +280,7 @@ Sema::ActOnStartProtocolInterface(SourceLocation AtProtoInterfaceLoc, SourceLocation ProtocolLoc, const DeclPtrTy *ProtoRefs, unsigned NumProtoRefs, + const SourceLocation *ProtoLocs, SourceLocation EndProtoLoc, AttributeList *AttrList) { // FIXME: Deal with AttrList. @@ -312,7 +314,8 @@ Sema::ActOnStartProtocolInterface(SourceLocation AtProtoInterfaceLoc, ProcessDeclAttributeList(TUScope, PDecl, AttrList); if (NumProtoRefs) { /// Check then save referenced protocols. - PDecl->setProtocolList((ObjCProtocolDecl**)ProtoRefs, NumProtoRefs,Context); + PDecl->setProtocolList((ObjCProtocolDecl**)ProtoRefs, NumProtoRefs, + ProtoLocs, Context); PDecl->setLocEnd(EndProtoLoc); } @@ -432,17 +435,17 @@ void Sema::ComparePropertiesInBaseAndSuper(ObjCInterfaceDecl *IDecl) { } } -/// MergeOneProtocolPropertiesIntoClass - This routine goes thru the list -/// of properties declared in a protocol and adds them to the list -/// of properties for current class/category if it is not there already. +/// MatchOneProtocolPropertiesInClass - This routine goes thru the list +/// of properties declared in a protocol and compares their attribute against +/// the same property declared in the class or category. void -Sema::MergeOneProtocolPropertiesIntoClass(Decl *CDecl, +Sema::MatchOneProtocolPropertiesInClass(Decl *CDecl, ObjCProtocolDecl *PDecl) { ObjCInterfaceDecl *IDecl = dyn_cast_or_null<ObjCInterfaceDecl>(CDecl); if (!IDecl) { // Category ObjCCategoryDecl *CatDecl = static_cast<ObjCCategoryDecl*>(CDecl); - assert (CatDecl && "MergeOneProtocolPropertiesIntoClass"); + assert (CatDecl && "MatchOneProtocolPropertiesInClass"); for (ObjCProtocolDecl::prop_iterator P = PDecl->prop_begin(), E = PDecl->prop_end(); P != E; ++P) { ObjCPropertyDecl *Pr = (*P); @@ -471,35 +474,35 @@ Sema::MergeOneProtocolPropertiesIntoClass(Decl *CDecl, } } -/// MergeProtocolPropertiesIntoClass - This routine merges properties -/// declared in 'MergeItsProtocols' objects (which can be a class or an -/// inherited protocol into the list of properties for class/category 'CDecl' +/// CompareProperties - This routine compares properties +/// declared in 'ClassOrProtocol' objects (which can be a class or an +/// inherited protocol with the list of properties for class/category 'CDecl' /// -void Sema::MergeProtocolPropertiesIntoClass(Decl *CDecl, - DeclPtrTy MergeItsProtocols) { - Decl *ClassDecl = MergeItsProtocols.getAs<Decl>(); +void Sema::CompareProperties(Decl *CDecl, + DeclPtrTy ClassOrProtocol) { + Decl *ClassDecl = ClassOrProtocol.getAs<Decl>(); ObjCInterfaceDecl *IDecl = dyn_cast_or_null<ObjCInterfaceDecl>(CDecl); if (!IDecl) { // Category ObjCCategoryDecl *CatDecl = static_cast<ObjCCategoryDecl*>(CDecl); - assert (CatDecl && "MergeProtocolPropertiesIntoClass"); + assert (CatDecl && "CompareProperties"); if (ObjCCategoryDecl *MDecl = dyn_cast<ObjCCategoryDecl>(ClassDecl)) { for (ObjCCategoryDecl::protocol_iterator P = MDecl->protocol_begin(), E = MDecl->protocol_end(); P != E; ++P) - // Merge properties of category (*P) into IDECL's - MergeOneProtocolPropertiesIntoClass(CatDecl, *P); + // Match properties of category with those of protocol (*P) + MatchOneProtocolPropertiesInClass(CatDecl, *P); - // Go thru the list of protocols for this category and recursively merge - // their properties into this class as well. + // Go thru the list of protocols for this category and recursively match + // their properties with those in the category. for (ObjCCategoryDecl::protocol_iterator P = CatDecl->protocol_begin(), E = CatDecl->protocol_end(); P != E; ++P) - MergeProtocolPropertiesIntoClass(CatDecl, DeclPtrTy::make(*P)); + CompareProperties(CatDecl, DeclPtrTy::make(*P)); } else { ObjCProtocolDecl *MD = cast<ObjCProtocolDecl>(ClassDecl); for (ObjCProtocolDecl::protocol_iterator P = MD->protocol_begin(), E = MD->protocol_end(); P != E; ++P) - MergeOneProtocolPropertiesIntoClass(CatDecl, *P); + MatchOneProtocolPropertiesInClass(CatDecl, *P); } return; } @@ -507,19 +510,19 @@ void Sema::MergeProtocolPropertiesIntoClass(Decl *CDecl, if (ObjCInterfaceDecl *MDecl = dyn_cast<ObjCInterfaceDecl>(ClassDecl)) { for (ObjCInterfaceDecl::protocol_iterator P = MDecl->protocol_begin(), E = MDecl->protocol_end(); P != E; ++P) - // Merge properties of class (*P) into IDECL's - MergeOneProtocolPropertiesIntoClass(IDecl, *P); + // Match properties of class IDecl with those of protocol (*P). + MatchOneProtocolPropertiesInClass(IDecl, *P); - // Go thru the list of protocols for this class and recursively merge - // their properties into this class as well. + // Go thru the list of protocols for this class and recursively match + // their properties with those declared in the class. for (ObjCInterfaceDecl::protocol_iterator P = IDecl->protocol_begin(), E = IDecl->protocol_end(); P != E; ++P) - MergeProtocolPropertiesIntoClass(IDecl, DeclPtrTy::make(*P)); + CompareProperties(IDecl, DeclPtrTy::make(*P)); } else { ObjCProtocolDecl *MD = cast<ObjCProtocolDecl>(ClassDecl); for (ObjCProtocolDecl::protocol_iterator P = MD->protocol_begin(), E = MD->protocol_end(); P != E; ++P) - MergeOneProtocolPropertiesIntoClass(IDecl, *P); + MatchOneProtocolPropertiesInClass(IDecl, *P); } } @@ -559,6 +562,7 @@ Sema::ActOnForwardProtocolDeclaration(SourceLocation AtProtocolLoc, unsigned NumElts, AttributeList *attrList) { llvm::SmallVector<ObjCProtocolDecl*, 32> Protocols; + llvm::SmallVector<SourceLocation, 8> ProtoLocs; for (unsigned i = 0; i != NumElts; ++i) { IdentifierInfo *Ident = IdentList[i].first; @@ -571,11 +575,13 @@ Sema::ActOnForwardProtocolDeclaration(SourceLocation AtProtocolLoc, if (attrList) ProcessDeclAttributeList(TUScope, PDecl, attrList); Protocols.push_back(PDecl); + ProtoLocs.push_back(IdentList[i].second); } ObjCForwardProtocolDecl *PDecl = ObjCForwardProtocolDecl::Create(Context, CurContext, AtProtocolLoc, - &Protocols[0], Protocols.size()); + Protocols.data(), Protocols.size(), + ProtoLocs.data()); CurContext->addDecl(PDecl); CheckObjCDeclScope(PDecl); return DeclPtrTy::make(PDecl); @@ -588,9 +594,11 @@ ActOnStartCategoryInterface(SourceLocation AtInterfaceLoc, SourceLocation CategoryLoc, const DeclPtrTy *ProtoRefs, unsigned NumProtoRefs, + const SourceLocation *ProtoLocs, SourceLocation EndProtoLoc) { ObjCCategoryDecl *CDecl = - ObjCCategoryDecl::Create(Context, CurContext, AtInterfaceLoc, CategoryName); + ObjCCategoryDecl::Create(Context, CurContext, AtInterfaceLoc, ClassLoc, + CategoryLoc, CategoryName); // FIXME: PushOnScopeChains? CurContext->addDecl(CDecl); @@ -623,12 +631,12 @@ ActOnStartCategoryInterface(SourceLocation AtInterfaceLoc, if (NumProtoRefs) { CDecl->setProtocolList((ObjCProtocolDecl**)ProtoRefs, NumProtoRefs, - Context); - CDecl->setLocEnd(EndProtoLoc); + ProtoLocs, Context); // Protocols in the class extension belong to the class. if (!CDecl->getIdentifier()) IDecl->mergeClassExtensionProtocolList((ObjCProtocolDecl**)ProtoRefs, - NumProtoRefs,Context); + NumProtoRefs, ProtoLocs, + Context); } CheckObjCDeclScope(CDecl); @@ -650,6 +658,7 @@ Sema::DeclPtrTy Sema::ActOnStartCategoryImplementation( // Category @implementation with no corresponding @interface. // Create and install one. CatIDecl = ObjCCategoryDecl::Create(Context, CurContext, SourceLocation(), + SourceLocation(), SourceLocation(), CatName); CatIDecl->setClassInterface(IDecl); CatIDecl->insertNextClassCategory(); @@ -1077,6 +1086,92 @@ void Sema::MatchAllMethodDeclarations(const llvm::DenseSet<Selector> &InsMap, } } +/// CollectImmediateProperties - This routine collects all properties in +/// the class and its conforming protocols; but not those it its super class. +void Sema::CollectImmediateProperties(ObjCContainerDecl *CDecl, + llvm::DenseMap<IdentifierInfo *, ObjCPropertyDecl*>& PropMap) { + if (ObjCInterfaceDecl *IDecl = dyn_cast<ObjCInterfaceDecl>(CDecl)) { + for (ObjCContainerDecl::prop_iterator P = IDecl->prop_begin(), + E = IDecl->prop_end(); P != E; ++P) { + ObjCPropertyDecl *Prop = (*P); + PropMap[Prop->getIdentifier()] = Prop; + } + // scan through class's protocols. + for (ObjCInterfaceDecl::protocol_iterator PI = IDecl->protocol_begin(), + E = IDecl->protocol_end(); PI != E; ++PI) + CollectImmediateProperties((*PI), PropMap); + } + if (ObjCCategoryDecl *CATDecl = dyn_cast<ObjCCategoryDecl>(CDecl)) { + for (ObjCContainerDecl::prop_iterator P = CATDecl->prop_begin(), + E = CATDecl->prop_end(); P != E; ++P) { + ObjCPropertyDecl *Prop = (*P); + PropMap[Prop->getIdentifier()] = Prop; + } + // scan through class's protocols. + for (ObjCInterfaceDecl::protocol_iterator PI = CATDecl->protocol_begin(), + E = CATDecl->protocol_end(); PI != E; ++PI) + CollectImmediateProperties((*PI), PropMap); + } + else if (ObjCProtocolDecl *PDecl = dyn_cast<ObjCProtocolDecl>(CDecl)) { + for (ObjCProtocolDecl::prop_iterator P = PDecl->prop_begin(), + E = PDecl->prop_end(); P != E; ++P) { + ObjCPropertyDecl *Prop = (*P); + ObjCPropertyDecl *&PropEntry = PropMap[Prop->getIdentifier()]; + if (!PropEntry) + PropEntry = Prop; + } + // scan through protocol's protocols. + for (ObjCProtocolDecl::protocol_iterator PI = PDecl->protocol_begin(), + E = PDecl->protocol_end(); PI != E; ++PI) + CollectImmediateProperties((*PI), PropMap); + } +} + +void Sema::DiagnoseUnimplementedProperties(ObjCImplDecl* IMPDecl, + ObjCContainerDecl *CDecl, + const llvm::DenseSet<Selector>& InsMap) { + llvm::DenseMap<IdentifierInfo *, ObjCPropertyDecl*> PropMap; + CollectImmediateProperties(CDecl, PropMap); + if (PropMap.empty()) + return; + + llvm::DenseSet<ObjCPropertyDecl *> PropImplMap; + for (ObjCImplDecl::propimpl_iterator + I = IMPDecl->propimpl_begin(), + EI = IMPDecl->propimpl_end(); I != EI; ++I) + PropImplMap.insert((*I)->getPropertyDecl()); + + for (llvm::DenseMap<IdentifierInfo *, ObjCPropertyDecl*>::iterator + P = PropMap.begin(), E = PropMap.end(); P != E; ++P) { + ObjCPropertyDecl *Prop = P->second; + // Is there a matching propery synthesize/dynamic? + if (Prop->isInvalidDecl() || + Prop->getPropertyImplementation() == ObjCPropertyDecl::Optional || + PropImplMap.count(Prop)) + continue; + + if (!InsMap.count(Prop->getGetterName())) { + Diag(Prop->getLocation(), + isa<ObjCCategoryDecl>(CDecl) ? + diag::warn_setter_getter_impl_required_in_category : + diag::warn_setter_getter_impl_required) + << Prop->getDeclName() << Prop->getGetterName(); + Diag(IMPDecl->getLocation(), + diag::note_property_impl_required); + } + + if (!Prop->isReadOnly() && !InsMap.count(Prop->getSetterName())) { + Diag(Prop->getLocation(), + isa<ObjCCategoryDecl>(CDecl) ? + diag::warn_setter_getter_impl_required_in_category : + diag::warn_setter_getter_impl_required) + << Prop->getDeclName() << Prop->getSetterName(); + Diag(IMPDecl->getLocation(), + diag::note_property_impl_required); + } + } +} + void Sema::ImplMethodsVsClassMethods(ObjCImplDecl* IMPDecl, ObjCContainerDecl* CDecl, bool IncompleteImpl) { @@ -1091,39 +1186,8 @@ void Sema::ImplMethodsVsClassMethods(ObjCImplDecl* IMPDecl, // an implementation or 2) there is a @synthesize/@dynamic implementation // of the property in the @implementation. if (isa<ObjCInterfaceDecl>(CDecl)) - for (ObjCContainerDecl::prop_iterator P = CDecl->prop_begin(), - E = CDecl->prop_end(); P != E; ++P) { - ObjCPropertyDecl *Prop = (*P); - if (Prop->isInvalidDecl()) - continue; - ObjCPropertyImplDecl *PI = 0; - // Is there a matching propery synthesize/dynamic? - for (ObjCImplDecl::propimpl_iterator - I = IMPDecl->propimpl_begin(), - EI = IMPDecl->propimpl_end(); I != EI; ++I) - if ((*I)->getPropertyDecl() == Prop) { - PI = (*I); - break; - } - if (PI) - continue; - if (!InsMap.count(Prop->getGetterName())) { - Diag(Prop->getLocation(), - diag::warn_setter_getter_impl_required) - << Prop->getDeclName() << Prop->getGetterName(); - Diag(IMPDecl->getLocation(), - diag::note_property_impl_required); - } - - if (!Prop->isReadOnly() && !InsMap.count(Prop->getSetterName())) { - Diag(Prop->getLocation(), - diag::warn_setter_getter_impl_required) - << Prop->getDeclName() << Prop->getSetterName(); - Diag(IMPDecl->getLocation(), - diag::note_property_impl_required); - } - } - + DiagnoseUnimplementedProperties(IMPDecl, CDecl, InsMap); + llvm::DenseSet<Selector> ClsMap; for (ObjCImplementationDecl::classmeth_iterator I = IMPDecl->classmeth_begin(), @@ -1163,7 +1227,18 @@ void Sema::ImplMethodsVsClassMethods(ObjCImplDecl* IMPDecl, E = C->protocol_end(); PI != E; ++PI) CheckProtocolMethodDefs(IMPDecl->getLocation(), *PI, IncompleteImpl, InsMap, ClsMap, C->getClassInterface()); - } + // Report unimplemented properties in the category as well. + // When reporting on missing setter/getters, do not report when + // setter/getter is implemented in category's primary class + // implementation. + if (ObjCInterfaceDecl *ID = C->getClassInterface()) + if (ObjCImplDecl *IMP = ID->getImplementation()) { + for (ObjCImplementationDecl::instmeth_iterator + I = IMP->instmeth_begin(), E = IMP->instmeth_end(); I!=E; ++I) + InsMap.insert((*I)->getSelector()); + } + DiagnoseUnimplementedProperties(IMPDecl, CDecl, InsMap); + } } else assert(false && "invalid ObjCContainerDecl type."); } @@ -1694,14 +1769,14 @@ void Sema::ActOnAtEnd(SourceRange AtEnd, // Compares properties declared in this class to those of its // super class. ComparePropertiesInBaseAndSuper(I); - MergeProtocolPropertiesIntoClass(I, DeclPtrTy::make(I)); + CompareProperties(I, DeclPtrTy::make(I)); } else if (ObjCCategoryDecl *C = dyn_cast<ObjCCategoryDecl>(ClassDecl)) { // Categories are used to extend the class by declaring new methods. // By the same token, they are also used to add new properties. No // need to compare the added property to those in the class. - // Merge protocol properties into category - MergeProtocolPropertiesIntoClass(C, DeclPtrTy::make(C)); + // Compare protocol properties with those in category + CompareProperties(C, DeclPtrTy::make(C)); if (C->getIdentifier() == 0) DiagnoseClassExtensionDupMethods(C, C->getClassInterface()); } @@ -2111,7 +2186,8 @@ Sema::DeclPtrTy Sema::ActOnProperty(Scope *S, SourceLocation AtLoc, assert(DC && "ClassDecl is not a DeclContext"); ObjCPropertyDecl *PDecl = ObjCPropertyDecl::Create(Context, DC, FD.D.getIdentifierLoc(), - FD.D.getIdentifier(), T); + FD.D.getIdentifier(), + AtLoc, T); DeclContext::lookup_result Found = DC->lookup(PDecl->getDeclName()); if (Found.first != Found.second && isa<ObjCPropertyDecl>(*Found.first)) { Diag(PDecl->getLocation(), diag::err_duplicate_property); diff --git a/lib/Sema/SemaExpr.cpp b/lib/Sema/SemaExpr.cpp index 034accd..50976f7 100644 --- a/lib/Sema/SemaExpr.cpp +++ b/lib/Sema/SemaExpr.cpp @@ -3082,15 +3082,9 @@ Sema::LookupMemberExpr(LookupResult &R, Expr *&BaseExpr, if (Setter && DiagnoseUseOfDecl(Setter, MemberLoc)) return ExprError(); - if (Getter || Setter) { + if (Getter) { QualType PType; - - if (Getter) - PType = Getter->getResultType(); - else - // Get the expression type from Setter's incoming parameter. - PType = (*(Setter->param_end() -1))->getType(); - // FIXME: we must check that the setter has property type. + PType = Getter->getResultType(); return Owned(new (Context) ObjCImplicitSetterGetterRefExpr(Getter, PType, Setter, MemberLoc, BaseExpr)); } @@ -3663,11 +3657,21 @@ Action::OwningExprResult Sema::ActOnCompoundLiteral(SourceLocation LParenLoc, TypeTy *Ty, SourceLocation RParenLoc, ExprArg InitExpr) { assert((Ty != 0) && "ActOnCompoundLiteral(): missing type"); - - QualType literalType = GetTypeFromParser(Ty); - // FIXME: put back this assert when initializers are worked out. //assert((InitExpr != 0) && "ActOnCompoundLiteral(): missing expression"); + + TypeSourceInfo *TInfo; + QualType literalType = GetTypeFromParser(Ty, &TInfo); + if (!TInfo) + TInfo = Context.getTrivialTypeSourceInfo(literalType); + + return BuildCompoundLiteralExpr(LParenLoc, TInfo, RParenLoc, move(InitExpr)); +} + +Action::OwningExprResult +Sema::BuildCompoundLiteralExpr(SourceLocation LParenLoc, TypeSourceInfo *TInfo, + SourceLocation RParenLoc, ExprArg InitExpr) { + QualType literalType = TInfo->getType(); Expr *literalExpr = static_cast<Expr*>(InitExpr.get()); if (literalType->isArrayType()) { @@ -3703,8 +3707,7 @@ Sema::ActOnCompoundLiteral(SourceLocation LParenLoc, TypeTy *Ty, Result.release(); - // FIXME: Store the TInfo to preserve type information better. - return Owned(new (Context) CompoundLiteralExpr(LParenLoc, literalType, + return Owned(new (Context) CompoundLiteralExpr(LParenLoc, TInfo, literalType, literalExpr, isFileScope)); } @@ -3906,26 +3909,38 @@ bool Sema::CheckExtVectorCast(SourceRange R, QualType DestTy, Expr *&CastExpr, Action::OwningExprResult Sema::ActOnCastExpr(Scope *S, SourceLocation LParenLoc, TypeTy *Ty, SourceLocation RParenLoc, ExprArg Op) { - CastExpr::CastKind Kind = CastExpr::CK_Unknown; - assert((Ty != 0) && (Op.get() != 0) && "ActOnCastExpr(): missing type or expr"); - Expr *castExpr = (Expr *)Op.get(); - //FIXME: Preserve type source info. - QualType castType = GetTypeFromParser(Ty); + TypeSourceInfo *castTInfo; + QualType castType = GetTypeFromParser(Ty, &castTInfo); + if (!castTInfo) + castTInfo = Context.getTrivialTypeSourceInfo(castType); // If the Expr being casted is a ParenListExpr, handle it specially. + Expr *castExpr = (Expr *)Op.get(); if (isa<ParenListExpr>(castExpr)) - return ActOnCastOfParenListExpr(S, LParenLoc, RParenLoc, move(Op),castType); + return ActOnCastOfParenListExpr(S, LParenLoc, RParenLoc, move(Op), + castTInfo); + + return BuildCStyleCastExpr(LParenLoc, castTInfo, RParenLoc, move(Op)); +} + +Action::OwningExprResult +Sema::BuildCStyleCastExpr(SourceLocation LParenLoc, TypeSourceInfo *Ty, + SourceLocation RParenLoc, ExprArg Op) { + Expr *castExpr = static_cast<Expr*>(Op.get()); + CXXMethodDecl *Method = 0; - if (CheckCastTypes(SourceRange(LParenLoc, RParenLoc), castType, castExpr, + CastExpr::CastKind Kind = CastExpr::CK_Unknown; + if (CheckCastTypes(SourceRange(LParenLoc, RParenLoc), Ty->getType(), castExpr, Kind, Method)) return ExprError(); if (Method) { - OwningExprResult CastArg = BuildCXXCastArgument(LParenLoc, castType, Kind, - Method, move(Op)); + // FIXME: preserve type source info here + OwningExprResult CastArg = BuildCXXCastArgument(LParenLoc, Ty->getType(), + Kind, Method, move(Op)); if (CastArg.isInvalid()) return ExprError(); @@ -3935,8 +3950,8 @@ Sema::ActOnCastExpr(Scope *S, SourceLocation LParenLoc, TypeTy *Ty, Op.release(); } - return Owned(new (Context) CStyleCastExpr(castType.getNonReferenceType(), - Kind, castExpr, castType, + return Owned(new (Context) CStyleCastExpr(Ty->getType().getNonReferenceType(), + Kind, castExpr, Ty, LParenLoc, RParenLoc)); } @@ -3961,8 +3976,9 @@ Sema::MaybeConvertParenListExprToParenExpr(Scope *S, ExprArg EA) { Action::OwningExprResult Sema::ActOnCastOfParenListExpr(Scope *S, SourceLocation LParenLoc, SourceLocation RParenLoc, ExprArg Op, - QualType Ty) { + TypeSourceInfo *TInfo) { ParenListExpr *PE = (ParenListExpr *)Op.get(); + QualType Ty = TInfo->getType(); // If this is an altivec initializer, '(' type ')' '(' init, ..., init ')' // then handle it as such. @@ -3982,13 +3998,12 @@ Sema::ActOnCastOfParenListExpr(Scope *S, SourceLocation LParenLoc, InitListExpr *E = new (Context) InitListExpr(LParenLoc, &initExprs[0], initExprs.size(), RParenLoc); E->setType(Ty); - return ActOnCompoundLiteral(LParenLoc, Ty.getAsOpaquePtr(), RParenLoc, - Owned(E)); + return BuildCompoundLiteralExpr(LParenLoc, TInfo, RParenLoc, Owned(E)); } else { // This is not an AltiVec-style cast, so turn the ParenListExpr into a // sequence of BinOp comma operators. Op = MaybeConvertParenListExprToParenExpr(S, move(Op)); - return ActOnCastExpr(S, LParenLoc, Ty.getAsOpaquePtr(), RParenLoc,move(Op)); + return BuildCStyleCastExpr(LParenLoc, TInfo, RParenLoc, move(Op)); } } @@ -4702,8 +4717,9 @@ static void ConstructTransparentUnion(ASTContext &C, Expr *&E, // Build a compound literal constructing a value of the transparent // union type from this initializer list. - E = new (C) CompoundLiteralExpr(SourceLocation(), UnionType, Initializer, - false); + TypeSourceInfo *unionTInfo = C.getTrivialTypeSourceInfo(UnionType); + E = new (C) CompoundLiteralExpr(SourceLocation(), unionTInfo, UnionType, + Initializer, false); } Sema::AssignConvertType @@ -6785,10 +6801,13 @@ void Sema::ActOnBlockArguments(Declarator &ParamInfo, Scope *CurScope) { CurBlock->TheDecl->setIsVariadic(CurBlock->isVariadic); ProcessDeclAttributes(CurScope, CurBlock->TheDecl, ParamInfo); for (BlockDecl::param_iterator AI = CurBlock->TheDecl->param_begin(), - E = CurBlock->TheDecl->param_end(); AI != E; ++AI) + E = CurBlock->TheDecl->param_end(); AI != E; ++AI) { + (*AI)->setOwningFunction(CurBlock->TheDecl); + // If this has an identifier, add it to the scope stack. if ((*AI)->getIdentifier()) PushOnScopeChains(*AI, CurBlock->TheScope); + } // Check for a valid sentinel attribute on this block. if (!CurBlock->isVariadic && @@ -6868,6 +6887,26 @@ Sema::OwningExprResult Sema::ActOnBlockStmtExpr(SourceLocation CaretLoc, CurFunctionNeedsScopeChecking = BSI->SavedFunctionNeedsScopeChecking; BSI->TheDecl->setBody(body.takeAs<CompoundStmt>()); + + bool Good = true; + // Check goto/label use. + for (llvm::DenseMap<IdentifierInfo*, LabelStmt*>::iterator + I = BSI->LabelMap.begin(), E = BSI->LabelMap.end(); I != E; ++I) { + LabelStmt *L = I->second; + + // Verify that we have no forward references left. If so, there was a goto + // or address of a label taken, but no definition of it. + if (L->getSubStmt() != 0) + continue; + + // Emit error. + Diag(L->getIdentLoc(), diag::err_undeclared_label_use) << L->getName(); + Good = false; + } + BSI->LabelMap.clear(); + if (!Good) + return ExprError(); + AnalysisContext AC(BSI->TheDecl); CheckFallThroughForBlock(BlockTy, BSI->TheDecl->getBody(), AC); CheckUnreachable(AC); @@ -7203,8 +7242,15 @@ void Sema::MarkDeclarationReferenced(SourceLocation Loc, Decl *D) { AlreadyInstantiated = true; } - if (!AlreadyInstantiated) - PendingImplicitInstantiations.push_back(std::make_pair(Function, Loc)); + if (!AlreadyInstantiated) { + if (isa<CXXRecordDecl>(Function->getDeclContext()) && + cast<CXXRecordDecl>(Function->getDeclContext())->isLocalClass()) + PendingLocalImplicitInstantiations.push_back(std::make_pair(Function, + Loc)); + else + PendingImplicitInstantiations.push_back(std::make_pair(Function, + Loc)); + } } // FIXME: keep track of references to static functions diff --git a/lib/Sema/SemaExprCXX.cpp b/lib/Sema/SemaExprCXX.cpp index d10e11f..b004fc3 100644 --- a/lib/Sema/SemaExprCXX.cpp +++ b/lib/Sema/SemaExprCXX.cpp @@ -196,8 +196,10 @@ Sema::ActOnCXXTypeConstructExpr(SourceRange TypeRange, TypeTy *TypeRep, SourceLocation *CommaLocs, SourceLocation RParenLoc) { assert(TypeRep && "Missing type!"); - // FIXME: Preserve type source info. - QualType Ty = GetTypeFromParser(TypeRep); + TypeSourceInfo *TInfo; + QualType Ty = GetTypeFromParser(TypeRep, &TInfo); + if (!TInfo) + TInfo = Context.getTrivialTypeSourceInfo(Ty, SourceLocation()); unsigned NumExprs = exprs.size(); Expr **Exprs = (Expr**)exprs.get(); SourceLocation TyBeginLoc = TypeRange.getBegin(); @@ -252,7 +254,7 @@ Sema::ActOnCXXTypeConstructExpr(SourceRange TypeRange, TypeTy *TypeRep, } return Owned(new (Context) CXXFunctionalCastExpr(Ty.getNonReferenceType(), - Ty, TyBeginLoc, Kind, + TInfo, TyBeginLoc, Kind, Exprs[0], RParenLoc)); } @@ -891,9 +893,9 @@ Sema::ActOnCXXDelete(SourceLocation StartLoc, bool UseGlobal, if (const RecordType *Record = Type->getAs<RecordType>()) { llvm::SmallVector<CXXConversionDecl *, 4> ObjectPtrConversions; CXXRecordDecl *RD = cast<CXXRecordDecl>(Record->getDecl()); - const UnresolvedSet *Conversions = RD->getVisibleConversionFunctions(); + const UnresolvedSetImpl *Conversions = RD->getVisibleConversionFunctions(); - for (UnresolvedSet::iterator I = Conversions->begin(), + for (UnresolvedSetImpl::iterator I = Conversions->begin(), E = Conversions->end(); I != E; ++I) { // Skip over templated conversion functions; they aren't considered. if (isa<FunctionTemplateDecl>(*I)) @@ -1448,12 +1450,14 @@ QualType Sema::CheckPointerToMemberOperands( // overkill? if (!IsDerivedFrom(LType, Class, Paths) || Paths.isAmbiguous(Context.getCanonicalType(Class))) { - const char *ReplaceStr = isIndirect ? ".*" : "->*"; Diag(Loc, diag::err_bad_memptr_lhs) << OpSpelling - << (int)isIndirect << lex->getType() << - CodeModificationHint::CreateReplacement(SourceRange(Loc), ReplaceStr); + << (int)isIndirect << lex->getType(); return QualType(); } + // Cast LHS to type of use. + QualType UseType = isIndirect ? Context.getPointerType(Class) : Class; + bool isLValue = !isIndirect && lex->isLvalue(Context) == Expr::LV_Valid; + ImpCastExprToType(lex, UseType, CastExpr::CK_DerivedToBase, isLValue); } if (isa<CXXZeroInitValueExpr>(rex->IgnoreParens())) { diff --git a/lib/Sema/SemaExprObjC.cpp b/lib/Sema/SemaExprObjC.cpp index 85889fa..ea8f4e3 100644 --- a/lib/Sema/SemaExprObjC.cpp +++ b/lib/Sema/SemaExprObjC.cpp @@ -398,7 +398,17 @@ Sema::ExprResult Sema::ActOnClassMessage( return ActOnInstanceMessage(ReceiverExpr.get(), Sel, lbrac, selectorLoc, rbrac, Args, NumArgs); } - return Diag(receiverLoc, diag::err_undeclared_var_use) << receiverName; + else if (TypedefDecl *OCTD = dyn_cast_or_null<TypedefDecl>(SuperDecl)) { + const ObjCInterfaceType *OCIT; + OCIT = OCTD->getUnderlyingType()->getAs<ObjCInterfaceType>(); + if (!OCIT) { + Diag(receiverLoc, diag::err_invalid_receiver_to_message); + return true; + } + ClassDecl = OCIT->getDecl(); + } + else + return Diag(receiverLoc, diag::err_undeclared_var_use) << receiverName; } } else ClassDecl = getObjCInterfaceDecl(receiverName, receiverLoc); diff --git a/lib/Sema/SemaInit.cpp b/lib/Sema/SemaInit.cpp index 1970f56..fd62e1a 100644 --- a/lib/Sema/SemaInit.cpp +++ b/lib/Sema/SemaInit.cpp @@ -382,7 +382,8 @@ InitListChecker::FillInValueInitializations(const InitializedEntity &Entity, if (hadError) return; - if (ElementEntity.getKind() == InitializedEntity::EK_ArrayOrVectorElement) + if (ElementEntity.getKind() == InitializedEntity::EK_ArrayElement || + ElementEntity.getKind() == InitializedEntity::EK_VectorElement) ElementEntity.setElementIndex(Init); if (Init >= NumInits || !ILE->getInit(Init)) { @@ -1828,12 +1829,15 @@ bool Sema::CheckInitList(const InitializedEntity &Entity, InitializedEntity::InitializedEntity(ASTContext &Context, unsigned Index, const InitializedEntity &Parent) - : Kind(EK_ArrayOrVectorElement), Parent(&Parent), Index(Index) + : Parent(&Parent), Index(Index) { - if (const ArrayType *AT = Context.getAsArrayType(Parent.getType())) + if (const ArrayType *AT = Context.getAsArrayType(Parent.getType())) { + Kind = EK_ArrayElement; Type = AT->getElementType(); - else + } else { + Kind = EK_VectorElement; Type = Parent.getType()->getAs<VectorType>()->getElementType(); + } } InitializedEntity InitializedEntity::InitializeBase(ASTContext &Context, @@ -1862,7 +1866,8 @@ DeclarationName InitializedEntity::getName() const { case EK_New: case EK_Temporary: case EK_Base: - case EK_ArrayOrVectorElement: + case EK_ArrayElement: + case EK_VectorElement: return DeclarationName(); } @@ -1882,7 +1887,8 @@ DeclaratorDecl *InitializedEntity::getDecl() const { case EK_New: case EK_Temporary: case EK_Base: - case EK_ArrayOrVectorElement: + case EK_ArrayElement: + case EK_VectorElement: return 0; } @@ -2141,11 +2147,10 @@ static OverloadingResult TryRefInitWithConversionFunction(Sema &S, // refers to. QualType ToType = AllowRValues? cv1T1 : DestType; - const UnresolvedSet *Conversions + const UnresolvedSetImpl *Conversions = T2RecordDecl->getVisibleConversionFunctions(); - for (UnresolvedSet::iterator I = Conversions->begin(), - E = Conversions->end(); - I != E; ++I) { + for (UnresolvedSetImpl::const_iterator I = Conversions->begin(), + E = Conversions->end(); I != E; ++I) { NamedDecl *D = *I; CXXRecordDecl *ActingDC = cast<CXXRecordDecl>(D->getDeclContext()); if (isa<UsingShadowDecl>(D)) @@ -2662,9 +2667,9 @@ static void TryUserDefinedConversion(Sema &S, CXXRecordDecl *SourceRecordDecl = cast<CXXRecordDecl>(SourceRecordType->getDecl()); - const UnresolvedSet *Conversions + const UnresolvedSetImpl *Conversions = SourceRecordDecl->getVisibleConversionFunctions(); - for (UnresolvedSet::iterator I = Conversions->begin(), + for (UnresolvedSetImpl::const_iterator I = Conversions->begin(), E = Conversions->end(); I != E; ++I) { NamedDecl *D = *I; @@ -2917,7 +2922,8 @@ getAssignmentAction(const InitializedEntity &Entity) { return Sema::AA_Casting; case InitializedEntity::EK_Member: - case InitializedEntity::EK_ArrayOrVectorElement: + case InitializedEntity::EK_ArrayElement: + case InitializedEntity::EK_VectorElement: return Sema::AA_Initializing; } @@ -2935,7 +2941,8 @@ static bool shouldBindAsTemporary(const InitializedEntity &Entity, case InitializedEntity::EK_Variable: case InitializedEntity::EK_Base: case InitializedEntity::EK_Member: - case InitializedEntity::EK_ArrayOrVectorElement: + case InitializedEntity::EK_ArrayElement: + case InitializedEntity::EK_VectorElement: return false; case InitializedEntity::EK_Parameter: @@ -2981,7 +2988,8 @@ static Sema::OwningExprResult CopyIfRequiredForEntity(Sema &S, case InitializedEntity::EK_Temporary: case InitializedEntity::EK_Base: case InitializedEntity::EK_Member: - case InitializedEntity::EK_ArrayOrVectorElement: + case InitializedEntity::EK_ArrayElement: + case InitializedEntity::EK_VectorElement: // We don't need to copy for any of these initialized entities. return move(CurInit); } diff --git a/lib/Sema/SemaInit.h b/lib/Sema/SemaInit.h index 5eb819a..d7d3756 100644 --- a/lib/Sema/SemaInit.h +++ b/lib/Sema/SemaInit.h @@ -47,6 +47,11 @@ public: /// \brief The entity being initialized is an exception object that /// is being thrown. EK_Exception, + /// \brief The entity being initialized is a non-static data member + /// subobject. + EK_Member, + /// \brief The entity being initialized is an element of an array. + EK_ArrayElement, /// \brief The entity being initialized is an object (or array of /// objects) allocated via new. EK_New, @@ -54,12 +59,10 @@ public: EK_Temporary, /// \brief The entity being initialized is a base member subobject. EK_Base, - /// \brief The entity being initialized is a non-static data member - /// subobject. - EK_Member, - /// \brief The entity being initialized is an element of an array + /// \brief The entity being initialized is an element of a vector. /// or vector. - EK_ArrayOrVectorElement + EK_VectorElement + }; private: @@ -211,7 +214,7 @@ public: /// \brief If this is already the initializer for an array or vector /// element, sets the element index. void setElementIndex(unsigned Index) { - assert(getKind() == EK_ArrayOrVectorElement); + assert(getKind() == EK_ArrayElement || getKind() == EK_VectorElement); this->Index = Index; } }; diff --git a/lib/Sema/SemaLookup.cpp b/lib/Sema/SemaLookup.cpp index cda245d..f5d2a7d 100644 --- a/lib/Sema/SemaLookup.cpp +++ b/lib/Sema/SemaLookup.cpp @@ -317,16 +317,16 @@ void LookupResult::resolveKind() { // Fast case: no possible ambiguity. if (N == 0) { - assert(ResultKind == NotFound); + assert(ResultKind == NotFound || ResultKind == NotFoundInCurrentInstantiation); return; } // If there's a single decl, we need to examine it to decide what // kind of lookup this is. if (N == 1) { - if (isa<FunctionTemplateDecl>(Decls[0])) + if (isa<FunctionTemplateDecl>(*Decls.begin())) ResultKind = FoundOverloaded; - else if (isa<UnresolvedUsingValueDecl>(Decls[0])) + else if (isa<UnresolvedUsingValueDecl>(*Decls.begin())) ResultKind = FoundUnresolvedValue; return; } @@ -445,8 +445,9 @@ static bool LookupDirect(LookupResult &R, const DeclContext *DC) { DeclContext::lookup_const_iterator I, E; for (llvm::tie(I, E) = DC->lookup(R.getLookupName()); I != E; ++I) { - if (R.isAcceptableDecl(*I)) { - R.addDecl(*I); + NamedDecl *D = *I; + if (R.isAcceptableDecl(D)) { + R.addDecl(D); Found = true; } } @@ -463,10 +464,9 @@ static bool LookupDirect(LookupResult &R, const DeclContext *DC) { if (!Record->isDefinition()) return Found; - const UnresolvedSet *Unresolved = Record->getConversionFunctions(); - for (UnresolvedSet::iterator U = Unresolved->begin(), - UEnd = Unresolved->end(); - U != UEnd; ++U) { + const UnresolvedSetImpl *Unresolved = Record->getConversionFunctions(); + for (UnresolvedSetImpl::iterator U = Unresolved->begin(), + UEnd = Unresolved->end(); U != UEnd; ++U) { FunctionTemplateDecl *ConvTemplate = dyn_cast<FunctionTemplateDecl>(*U); if (!ConvTemplate) continue; @@ -967,6 +967,8 @@ bool Sema::LookupQualifiedName(LookupResult &R, DeclContext *LookupCtx, // Perform qualified name lookup into the LookupCtx. if (LookupDirect(R, LookupCtx)) { R.resolveKind(); + if (isa<CXXRecordDecl>(LookupCtx)) + R.setNamingClass(cast<CXXRecordDecl>(LookupCtx)); return true; } @@ -1039,6 +1041,8 @@ bool Sema::LookupQualifiedName(LookupResult &R, DeclContext *LookupCtx, R.getLookupName().getAsOpaquePtr(), Paths)) return false; + R.setNamingClass(LookupRec); + // C++ [class.member.lookup]p2: // [...] If the resulting set of declarations are not all from // sub-objects of the same type, or the set has a nonstatic member @@ -1048,10 +1052,15 @@ bool Sema::LookupQualifiedName(LookupResult &R, DeclContext *LookupCtx, // FIXME: support using declarations! QualType SubobjectType; int SubobjectNumber = 0; + AccessSpecifier SubobjectAccess = AS_private; for (CXXBasePaths::paths_iterator Path = Paths.begin(), PathEnd = Paths.end(); Path != PathEnd; ++Path) { const CXXBasePathElement &PathElement = Path->back(); + // Pick the best (i.e. most permissive i.e. numerically lowest) access + // across all paths. + SubobjectAccess = std::min(SubobjectAccess, Path->Access); + // Determine whether we're looking at a distinct sub-object or not. if (SubobjectType.isNull()) { // This is the first subobject we've looked at. Record its type. @@ -1106,8 +1115,12 @@ bool Sema::LookupQualifiedName(LookupResult &R, DeclContext *LookupCtx, // Lookup in a base class succeeded; return these results. DeclContext::lookup_iterator I, E; - for (llvm::tie(I,E) = Paths.front().Decls; I != E; ++I) - R.addDecl(*I); + for (llvm::tie(I,E) = Paths.front().Decls; I != E; ++I) { + NamedDecl *D = *I; + AccessSpecifier AS = CXXRecordDecl::MergeAccess(SubobjectAccess, + D->getAccess()); + R.addDecl(D, AS); + } R.resolveKind(); return true; } @@ -1243,7 +1256,12 @@ bool Sema::DiagnoseAmbiguousLookup(LookupResult &Result) { Diag((*DI)->getLocation(), diag::note_hiding_object); // For recovery purposes, go ahead and implement the hiding. - Result.hideDecls(TagDecls); + LookupResult::Filter F = Result.makeFilter(); + while (F.hasNext()) { + if (TagDecls.count(F.next())) + F.erase(); + } + F.done(); return true; } diff --git a/lib/Sema/SemaOverload.cpp b/lib/Sema/SemaOverload.cpp index 6ec4d1b..44a8f15 100644 --- a/lib/Sema/SemaOverload.cpp +++ b/lib/Sema/SemaOverload.cpp @@ -25,7 +25,6 @@ #include "llvm/ADT/SmallPtrSet.h" #include "llvm/ADT/STLExtras.h" #include <algorithm> -#include <cstdio> namespace clang { @@ -183,51 +182,53 @@ isPointerConversionToVoidPointer(ASTContext& Context) const { /// DebugPrint - Print this standard conversion sequence to standard /// error. Useful for debugging overloading issues. void StandardConversionSequence::DebugPrint() const { + llvm::raw_ostream &OS = llvm::errs(); bool PrintedSomething = false; if (First != ICK_Identity) { - fprintf(stderr, "%s", GetImplicitConversionName(First)); + OS << GetImplicitConversionName(First); PrintedSomething = true; } if (Second != ICK_Identity) { if (PrintedSomething) { - fprintf(stderr, " -> "); + OS << " -> "; } - fprintf(stderr, "%s", GetImplicitConversionName(Second)); + OS << GetImplicitConversionName(Second); if (CopyConstructor) { - fprintf(stderr, " (by copy constructor)"); + OS << " (by copy constructor)"; } else if (DirectBinding) { - fprintf(stderr, " (direct reference binding)"); + OS << " (direct reference binding)"; } else if (ReferenceBinding) { - fprintf(stderr, " (reference binding)"); + OS << " (reference binding)"; } PrintedSomething = true; } if (Third != ICK_Identity) { if (PrintedSomething) { - fprintf(stderr, " -> "); + OS << " -> "; } - fprintf(stderr, "%s", GetImplicitConversionName(Third)); + OS << GetImplicitConversionName(Third); PrintedSomething = true; } if (!PrintedSomething) { - fprintf(stderr, "No conversions required"); + OS << "No conversions required"; } } /// DebugPrint - Print this user-defined conversion sequence to standard /// error. Useful for debugging overloading issues. void UserDefinedConversionSequence::DebugPrint() const { + llvm::raw_ostream &OS = llvm::errs(); if (Before.First || Before.Second || Before.Third) { Before.DebugPrint(); - fprintf(stderr, " -> "); + OS << " -> "; } - fprintf(stderr, "'%s'", ConversionFunction->getNameAsString().c_str()); + OS << "'" << ConversionFunction->getNameAsString() << "'"; if (After.First || After.Second || After.Third) { - fprintf(stderr, " -> "); + OS << " -> "; After.DebugPrint(); } } @@ -235,27 +236,28 @@ void UserDefinedConversionSequence::DebugPrint() const { /// DebugPrint - Print this implicit conversion sequence to standard /// error. Useful for debugging overloading issues. void ImplicitConversionSequence::DebugPrint() const { + llvm::raw_ostream &OS = llvm::errs(); switch (ConversionKind) { case StandardConversion: - fprintf(stderr, "Standard conversion: "); + OS << "Standard conversion: "; Standard.DebugPrint(); break; case UserDefinedConversion: - fprintf(stderr, "User-defined conversion: "); + OS << "User-defined conversion: "; UserDefined.DebugPrint(); break; case EllipsisConversion: - fprintf(stderr, "Ellipsis conversion"); + OS << "Ellipsis conversion"; break; case AmbiguousConversion: - fprintf(stderr, "Ambiguous conversion"); + OS << "Ambiguous conversion"; break; case BadConversion: - fprintf(stderr, "Bad conversion"); + OS << "Bad conversion"; break; } - fprintf(stderr, "\n"); + OS << "\n"; } void AmbiguousConversionSequence::construct() { @@ -1100,7 +1102,7 @@ bool Sema::isObjCPointerConversion(QualType FromType, QualType ToType, bool &IncompatibleObjC) { if (!getLangOptions().ObjC1) return false; - + // First, we handle all conversions on ObjC object pointer types. const ObjCObjectPointerType* ToObjCPtr = ToType->getAs<ObjCObjectPointerType>(); const ObjCObjectPointerType *FromObjCPtr = @@ -1141,8 +1143,23 @@ bool Sema::isObjCPointerConversion(QualType FromType, QualType ToType, QualType ToPointeeType; if (const PointerType *ToCPtr = ToType->getAs<PointerType>()) ToPointeeType = ToCPtr->getPointeeType(); - else if (const BlockPointerType *ToBlockPtr = ToType->getAs<BlockPointerType>()) + else if (const BlockPointerType *ToBlockPtr = + ToType->getAs<BlockPointerType>()) { + // Objective C++: We're able to convert from a pointer to any object + // to a block pointer type. + if (FromObjCPtr && FromObjCPtr->isObjCBuiltinType()) { + ConvertedType = ToType; + return true; + } ToPointeeType = ToBlockPtr->getPointeeType(); + } + else if (FromType->getAs<BlockPointerType>() && + ToObjCPtr && ToObjCPtr->isObjCBuiltinType()) { + // Objective C++: We're able to convert from a block pointer type to a + // pointer to any object. + ConvertedType = ToType; + return true; + } else return false; @@ -1164,6 +1181,16 @@ bool Sema::isObjCPointerConversion(QualType FromType, QualType ToType, ConvertedType = ToType; return true; } + // Allow conversion of pointee being objective-c pointer to another one; + // as in I* to id. + if (FromPointeeType->getAs<ObjCObjectPointerType>() && + ToPointeeType->getAs<ObjCObjectPointerType>() && + isObjCPointerConversion(FromPointeeType, ToPointeeType, ConvertedType, + IncompatibleObjC)) { + ConvertedType = ToType; + return true; + } + // If we have pointers to functions or blocks, check whether the only // differences in the argument and result types are in Objective-C // pointer conversions. If so, we permit the conversion (but @@ -1523,9 +1550,9 @@ OverloadingResult Sema::IsUserDefinedConversion(Expr *From, QualType ToType, if (CXXRecordDecl *FromRecordDecl = dyn_cast<CXXRecordDecl>(FromRecordType->getDecl())) { // Add all of the conversion functions as candidates. - const UnresolvedSet *Conversions + const UnresolvedSetImpl *Conversions = FromRecordDecl->getVisibleConversionFunctions(); - for (UnresolvedSet::iterator I = Conversions->begin(), + for (UnresolvedSetImpl::iterator I = Conversions->begin(), E = Conversions->end(); I != E; ++I) { NamedDecl *D = *I; CXXRecordDecl *ActingContext = cast<CXXRecordDecl>(D->getDeclContext()); @@ -2756,7 +2783,7 @@ Sema::AddConversionCandidate(CXXConversionDecl *Conversion, QualType ToCanon = Context.getCanonicalType(ToType).getUnqualifiedType(); if (FromCanon == ToCanon || IsDerivedFrom(FromCanon, ToCanon)) { Candidate.Viable = false; - Candidate.FailureKind = ovl_fail_bad_conversion; + Candidate.FailureKind = ovl_fail_trivial_conversion; return; } @@ -2794,7 +2821,7 @@ Sema::AddConversionCandidate(CXXConversionDecl *Conversion, case ImplicitConversionSequence::BadConversion: Candidate.Viable = false; - Candidate.FailureKind = ovl_fail_bad_conversion; + Candidate.FailureKind = ovl_fail_bad_final_conversion; break; default: @@ -2869,6 +2896,7 @@ void Sema::AddSurrogateCandidate(CXXConversionDecl *Conversion, if (ObjectInit.isBad()) { Candidate.Viable = false; Candidate.FailureKind = ovl_fail_bad_conversion; + Candidate.Conversions[0] = ObjectInit; return; } @@ -3270,9 +3298,9 @@ BuiltinCandidateTypeSet::AddTypesConvertedFrom(QualType Ty, } CXXRecordDecl *ClassDecl = cast<CXXRecordDecl>(TyRec->getDecl()); - const UnresolvedSet *Conversions + const UnresolvedSetImpl *Conversions = ClassDecl->getVisibleConversionFunctions(); - for (UnresolvedSet::iterator I = Conversions->begin(), + for (UnresolvedSetImpl::iterator I = Conversions->begin(), E = Conversions->end(); I != E; ++I) { // Skip conversion function templates; they don't tell us anything @@ -3334,10 +3362,10 @@ static Qualifiers CollectVRQualifiers(ASTContext &Context, Expr* ArgExpr) { } CXXRecordDecl *ClassDecl = cast<CXXRecordDecl>(TyRec->getDecl()); - const UnresolvedSet *Conversions = + const UnresolvedSetImpl *Conversions = ClassDecl->getVisibleConversionFunctions(); - for (UnresolvedSet::iterator I = Conversions->begin(), + for (UnresolvedSetImpl::iterator I = Conversions->begin(), E = Conversions->end(); I != E; ++I) { if (CXXConversionDecl *Conv = dyn_cast<CXXConversionDecl>(*I)) { QualType CanTy = Context.getCanonicalType(Conv->getConversionType()); @@ -4386,7 +4414,8 @@ void DiagnoseBadConversion(Sema &S, OverloadCandidate *Cand, unsigned I) { QualType FromTy = Conv.Bad.getFromType(); QualType ToTy = Conv.Bad.getToType(); - // Do some hand-waving analysis to see if the non-viability is due to a + // Do some hand-waving analysis to see if the non-viability is due + // to a qualifier mismatch. CanQualType CFromTy = S.Context.getCanonicalType(FromTy); CanQualType CToTy = S.Context.getCanonicalType(ToTy); if (CanQual<ReferenceType> RT = CToTy->getAs<ReferenceType>()) @@ -4436,6 +4465,20 @@ void DiagnoseBadConversion(Sema &S, OverloadCandidate *Cand, unsigned I) { return; } + // Diagnose references or pointers to incomplete types differently, + // since it's far from impossible that the incompleteness triggered + // the failure. + QualType TempFromTy = FromTy.getNonReferenceType(); + if (const PointerType *PTy = TempFromTy->getAs<PointerType>()) + TempFromTy = PTy->getPointeeType(); + if (TempFromTy->isIncompleteType()) { + S.Diag(Fn->getLocation(), diag::note_ovl_candidate_bad_conv_incomplete) + << (unsigned) FnKind << FnDesc + << (FromExpr ? FromExpr->getSourceRange() : SourceRange()) + << FromTy << ToTy << (unsigned) isObjectArgument << I+1; + return; + } + // TODO: specialize more based on the kind of mismatch S.Diag(Fn->getLocation(), diag::note_ovl_candidate_bad_conv) << (unsigned) FnKind << FnDesc @@ -4503,6 +4546,8 @@ void NoteFunctionCandidate(Sema &S, OverloadCandidate *Cand, return DiagnoseArityMismatch(S, Cand, NumArgs); case ovl_fail_bad_deduction: + case ovl_fail_trivial_conversion: + case ovl_fail_bad_final_conversion: return S.NoteOverloadCandidate(Fn); case ovl_fail_bad_conversion: @@ -4582,12 +4627,23 @@ void NoteAmbiguousUserConversions(Sema &S, SourceLocation OpLoc, } } +SourceLocation GetLocationForCandidate(const OverloadCandidate *Cand) { + if (Cand->Function) + return Cand->Function->getLocation(); + if (Cand->IsSurrogate) + return Cand->Surrogate->getLocation(); + return SourceLocation(); +} + struct CompareOverloadCandidatesForDisplay { Sema &S; CompareOverloadCandidatesForDisplay(Sema &S) : S(S) {} bool operator()(const OverloadCandidate *L, const OverloadCandidate *R) { + // Fast-path this check. + if (L == R) return false; + // Order first by viability. if (L->Viable) { if (!R->Viable) return true; @@ -4600,25 +4656,132 @@ struct CompareOverloadCandidatesForDisplay { } else if (R->Viable) return false; - // Put declared functions first. - if (L->Function) { - if (!R->Function) return true; - return S.SourceMgr.isBeforeInTranslationUnit(L->Function->getLocation(), - R->Function->getLocation()); - } else if (R->Function) return false; - - // Then surrogates. - if (L->IsSurrogate) { - if (!R->IsSurrogate) return true; - return S.SourceMgr.isBeforeInTranslationUnit(L->Surrogate->getLocation(), - R->Surrogate->getLocation()); - } else if (R->IsSurrogate) return false; - - // And builtins just come in a jumble. - return false; + assert(L->Viable == R->Viable); + + // Criteria by which we can sort non-viable candidates: + if (!L->Viable) { + // 1. Arity mismatches come after other candidates. + if (L->FailureKind == ovl_fail_too_many_arguments || + L->FailureKind == ovl_fail_too_few_arguments) + return false; + if (R->FailureKind == ovl_fail_too_many_arguments || + R->FailureKind == ovl_fail_too_few_arguments) + return true; + + // 2. Bad conversions come first and are ordered by the number + // of bad conversions and quality of good conversions. + if (L->FailureKind == ovl_fail_bad_conversion) { + if (R->FailureKind != ovl_fail_bad_conversion) + return true; + + // If there's any ordering between the defined conversions... + // FIXME: this might not be transitive. + assert(L->Conversions.size() == R->Conversions.size()); + + int leftBetter = 0; + for (unsigned I = 0, E = L->Conversions.size(); I != E; ++I) { + switch (S.CompareImplicitConversionSequences(L->Conversions[I], + R->Conversions[I])) { + case ImplicitConversionSequence::Better: + leftBetter++; + break; + + case ImplicitConversionSequence::Worse: + leftBetter--; + break; + + case ImplicitConversionSequence::Indistinguishable: + break; + } + } + if (leftBetter > 0) return true; + if (leftBetter < 0) return false; + + } else if (R->FailureKind == ovl_fail_bad_conversion) + return false; + + // TODO: others? + } + + // Sort everything else by location. + SourceLocation LLoc = GetLocationForCandidate(L); + SourceLocation RLoc = GetLocationForCandidate(R); + + // Put candidates without locations (e.g. builtins) at the end. + if (LLoc.isInvalid()) return false; + if (RLoc.isInvalid()) return true; + + return S.SourceMgr.isBeforeInTranslationUnit(LLoc, RLoc); } }; +/// CompleteNonViableCandidate - Normally, overload resolution only +/// computes up to the first +void CompleteNonViableCandidate(Sema &S, OverloadCandidate *Cand, + Expr **Args, unsigned NumArgs) { + assert(!Cand->Viable); + + // Don't do anything on failures other than bad conversion. + if (Cand->FailureKind != ovl_fail_bad_conversion) return; + + // Skip forward to the first bad conversion. + unsigned ConvIdx = 0; + unsigned ConvCount = Cand->Conversions.size(); + while (true) { + assert(ConvIdx != ConvCount && "no bad conversion in candidate"); + ConvIdx++; + if (Cand->Conversions[ConvIdx - 1].isBad()) + break; + } + + if (ConvIdx == ConvCount) + return; + + // FIXME: these should probably be preserved from the overload + // operation somehow. + bool SuppressUserConversions = false; + bool ForceRValue = false; + + const FunctionProtoType* Proto; + unsigned ArgIdx = ConvIdx; + + if (Cand->IsSurrogate) { + QualType ConvType + = Cand->Surrogate->getConversionType().getNonReferenceType(); + if (const PointerType *ConvPtrType = ConvType->getAs<PointerType>()) + ConvType = ConvPtrType->getPointeeType(); + Proto = ConvType->getAs<FunctionProtoType>(); + ArgIdx--; + } else if (Cand->Function) { + Proto = Cand->Function->getType()->getAs<FunctionProtoType>(); + if (isa<CXXMethodDecl>(Cand->Function) && + !isa<CXXConstructorDecl>(Cand->Function)) + ArgIdx--; + } else { + // Builtin binary operator with a bad first conversion. + assert(ConvCount <= 3); + for (; ConvIdx != ConvCount; ++ConvIdx) + Cand->Conversions[ConvIdx] + = S.TryCopyInitialization(Args[ConvIdx], + Cand->BuiltinTypes.ParamTypes[ConvIdx], + SuppressUserConversions, ForceRValue, + /*InOverloadResolution*/ true); + return; + } + + // Fill in the rest of the conversions. + unsigned NumArgsInProto = Proto->getNumArgs(); + for (; ConvIdx != ConvCount; ++ConvIdx, ++ArgIdx) { + if (ArgIdx < NumArgsInProto) + Cand->Conversions[ConvIdx] + = S.TryCopyInitialization(Args[ArgIdx], Proto->getArgType(ArgIdx), + SuppressUserConversions, ForceRValue, + /*InOverloadResolution=*/true); + else + Cand->Conversions[ConvIdx].setEllipsis(); + } +} + } // end anonymous namespace /// PrintOverloadCandidates - When overload resolution fails, prints @@ -4636,9 +4799,15 @@ Sema::PrintOverloadCandidates(OverloadCandidateSet& CandidateSet, if (OCD == OCD_AllCandidates) Cands.reserve(CandidateSet.size()); for (OverloadCandidateSet::iterator Cand = CandidateSet.begin(), LastCand = CandidateSet.end(); - Cand != LastCand; ++Cand) - if (Cand->Viable || OCD == OCD_AllCandidates) + Cand != LastCand; ++Cand) { + if (Cand->Viable) Cands.push_back(Cand); + else if (OCD == OCD_AllCandidates) { + CompleteNonViableCandidate(*this, Cand, Args, NumArgs); + Cands.push_back(Cand); + } + } + std::sort(Cands.begin(), Cands.end(), CompareOverloadCandidatesForDisplay(*this)); @@ -5909,9 +6078,9 @@ Sema::BuildCallToObjectOfClassType(Scope *S, Expr *Object, // functions for each conversion function declared in an // accessible base class provided the function is not hidden // within T by another intervening declaration. - const UnresolvedSet *Conversions + const UnresolvedSetImpl *Conversions = cast<CXXRecordDecl>(Record->getDecl())->getVisibleConversionFunctions(); - for (UnresolvedSet::iterator I = Conversions->begin(), + for (UnresolvedSetImpl::iterator I = Conversions->begin(), E = Conversions->end(); I != E; ++I) { NamedDecl *D = *I; CXXRecordDecl *ActingContext = cast<CXXRecordDecl>(D->getDeclContext()); diff --git a/lib/Sema/SemaOverload.h b/lib/Sema/SemaOverload.h index 20add00..f8353e3 100644 --- a/lib/Sema/SemaOverload.h +++ b/lib/Sema/SemaOverload.h @@ -390,7 +390,16 @@ namespace clang { ovl_fail_too_many_arguments, ovl_fail_too_few_arguments, ovl_fail_bad_conversion, - ovl_fail_bad_deduction + ovl_fail_bad_deduction, + + /// This conversion candidate was not considered because it + /// duplicates the work of a trivial or derived-to-base + /// conversion. + ovl_fail_trivial_conversion, + + /// This conversion candidate is not viable because its result + /// type is not implicitly convertible to the desired type. + ovl_fail_bad_final_conversion }; /// OverloadCandidate - A single candidate in an overload set (C++ 13.3). diff --git a/lib/Sema/SemaStmt.cpp b/lib/Sema/SemaStmt.cpp index 7855a7f..0c207fa 100644 --- a/lib/Sema/SemaStmt.cpp +++ b/lib/Sema/SemaStmt.cpp @@ -412,10 +412,10 @@ static bool CheckCXXSwitchCondition(Sema &S, SourceLocation SwitchLoc, llvm::SmallVector<CXXConversionDecl *, 4> ViableConversions; llvm::SmallVector<CXXConversionDecl *, 4> ExplicitConversions; if (const RecordType *RecordTy = CondType->getAs<RecordType>()) { - const UnresolvedSet *Conversions + const UnresolvedSetImpl *Conversions = cast<CXXRecordDecl>(RecordTy->getDecl()) ->getVisibleConversionFunctions(); - for (UnresolvedSet::iterator I = Conversions->begin(), + for (UnresolvedSetImpl::iterator I = Conversions->begin(), E = Conversions->end(); I != E; ++I) { if (CXXConversionDecl *Conversion = dyn_cast<CXXConversionDecl>(*I)) if (Conversion->getConversionType().getNonReferenceType() @@ -879,10 +879,6 @@ Sema::ActOnObjCForCollectionStmt(SourceLocation ForLoc, Action::OwningStmtResult Sema::ActOnGotoStmt(SourceLocation GotoLoc, SourceLocation LabelLoc, IdentifierInfo *LabelII) { - // If we are in a block, reject all gotos for now. - if (CurBlock) - return StmtError(Diag(GotoLoc, diag::err_goto_in_block)); - // Look up the record for this label identifier. LabelStmt *&LabelDecl = getLabelMap()[LabelII]; diff --git a/lib/Sema/SemaTemplate.cpp b/lib/Sema/SemaTemplate.cpp index 2fad832..0040156 100644 --- a/lib/Sema/SemaTemplate.cpp +++ b/lib/Sema/SemaTemplate.cpp @@ -449,8 +449,8 @@ Sema::DeclPtrTy Sema::ActOnTypeParameter(Scope *S, bool Typename, bool Ellipsis, Loc = KeyLoc; TemplateTypeParmDecl *Param - = TemplateTypeParmDecl::Create(Context, CurContext, Loc, - Depth, Position, ParamName, Typename, + = TemplateTypeParmDecl::Create(Context, Context.getTranslationUnitDecl(), + Loc, Depth, Position, ParamName, Typename, Ellipsis); if (Invalid) Param->setInvalidDecl(); @@ -572,7 +572,8 @@ Sema::DeclPtrTy Sema::ActOnNonTypeTemplateParameter(Scope *S, Declarator &D, } NonTypeTemplateParmDecl *Param - = NonTypeTemplateParmDecl::Create(Context, CurContext, D.getIdentifierLoc(), + = NonTypeTemplateParmDecl::Create(Context, Context.getTranslationUnitDecl(), + D.getIdentifierLoc(), Depth, Position, ParamName, T, TInfo); if (Invalid) Param->setInvalidDecl(); @@ -625,8 +626,8 @@ Sema::DeclPtrTy Sema::ActOnTemplateTemplateParameter(Scope* S, // Construct the parameter object. TemplateTemplateParmDecl *Param = - TemplateTemplateParmDecl::Create(Context, CurContext, TmpLoc, Depth, - Position, Name, + TemplateTemplateParmDecl::Create(Context, Context.getTranslationUnitDecl(), + TmpLoc, Depth, Position, Name, (TemplateParameterList*)Params); // Make sure the parameter is valid. @@ -1586,9 +1587,12 @@ Sema::ActOnDependentTemplateName(SourceLocation TemplateKWLoc, UnqualifiedId &Name, TypeTy *ObjectType, bool EnteringContext) { - if ((ObjectType && - computeDeclContext(QualType::getFromOpaquePtr(ObjectType))) || - (SS.isSet() && computeDeclContext(SS, EnteringContext))) { + DeclContext *LookupCtx = 0; + if (SS.isSet()) + LookupCtx = computeDeclContext(SS, EnteringContext); + if (!LookupCtx && ObjectType) + LookupCtx = computeDeclContext(QualType::getFromOpaquePtr(ObjectType)); + if (LookupCtx) { // C++0x [temp.names]p5: // If a name prefixed by the keyword template is not the name of // a template, the program is ill-formed. [Note: the keyword @@ -1608,8 +1612,9 @@ Sema::ActOnDependentTemplateName(SourceLocation TemplateKWLoc, TemplateTy Template; TemplateNameKind TNK = isTemplateName(0, SS, Name, ObjectType, EnteringContext, Template); - if (TNK == TNK_Non_template && - isCurrentInstantiationWithDependentBases(SS)) { + if (TNK == TNK_Non_template && LookupCtx->isDependentContext() && + isa<CXXRecordDecl>(LookupCtx) && + cast<CXXRecordDecl>(LookupCtx)->hasAnyDependentBases()) { // This is a dependent template. } else if (TNK == TNK_Non_template) { Diag(Name.getSourceRange().getBegin(), diff --git a/lib/Sema/SemaTemplateInstantiateDecl.cpp b/lib/Sema/SemaTemplateInstantiateDecl.cpp index e909c4f..23a9430 100644 --- a/lib/Sema/SemaTemplateInstantiateDecl.cpp +++ b/lib/Sema/SemaTemplateInstantiateDecl.cpp @@ -150,6 +150,7 @@ Decl *TemplateDeclInstantiator::VisitTypedefDecl(TypedefDecl *D) { Typedef->setPreviousDeclaration(cast<TypedefDecl>(InstPrev)); } + Typedef->setAccess(D->getAccess()); Owner->addDecl(Typedef); return Typedef; @@ -208,6 +209,8 @@ Decl *TemplateDeclInstantiator::VisitVarDecl(VarDecl *D) { if (D->isOutOfLine()) Var->setLexicalDeclContext(D->getLexicalDeclContext()); + Var->setAccess(D->getAccess()); + // FIXME: In theory, we could have a previous declaration for variables that // are not static data members. bool Redeclaration = false; @@ -375,6 +378,7 @@ Decl *TemplateDeclInstantiator::VisitFieldDecl(FieldDecl *D) { } Field->setImplicit(D->isImplicit()); + Field->setAccess(D->getAccess()); Owner->addDecl(Field); return Field; @@ -559,6 +563,7 @@ Decl *TemplateDeclInstantiator::VisitClassTemplateDecl(ClassTemplateDecl *D) { return Inst; } + Inst->setAccess(D->getAccess()); Owner->addDecl(Inst); // First, we sort the partial specializations by location, so @@ -634,6 +639,8 @@ TemplateDeclInstantiator::VisitFunctionTemplateDecl(FunctionTemplateDecl *D) { if (!Instantiated) return 0; + Instantiated->setAccess(D->getAccess()); + // Link the instantiated function template declaration to the function // template from which it was instantiated. FunctionTemplateDecl *InstTemplate @@ -717,7 +724,10 @@ Decl *TemplateDeclInstantiator::VisitFunctionDecl(FunctionDecl *D, return Info->Function; } - Sema::LocalInstantiationScope Scope(SemaRef, TemplateParams != 0); + bool MergeWithParentScope = (TemplateParams != 0) || + !(isa<Decl>(Owner) && + cast<Decl>(Owner)->isDefinedOutsideFunctionOrMethod()); + Sema::LocalInstantiationScope Scope(SemaRef, MergeWithParentScope); llvm::SmallVector<ParmVarDecl *, 4> Params; QualType T = SubstFunctionType(D, Params); @@ -844,7 +854,10 @@ TemplateDeclInstantiator::VisitCXXMethodDecl(CXXMethodDecl *D, return Info->Function; } - Sema::LocalInstantiationScope Scope(SemaRef, TemplateParams != 0); + bool MergeWithParentScope = (TemplateParams != 0) || + !(isa<Decl>(Owner) && + cast<Decl>(Owner)->isDefinedOutsideFunctionOrMethod()); + Sema::LocalInstantiationScope Scope(SemaRef, MergeWithParentScope); llvm::SmallVector<ParmVarDecl *, 4> Params; QualType T = SubstFunctionType(D, Params); @@ -958,6 +971,8 @@ TemplateDeclInstantiator::VisitCXXMethodDecl(CXXMethodDecl *D, if (D->isPure()) SemaRef.CheckPureMethod(Method, SourceRange()); + Method->setAccess(D->getAccess()); + if (!FunctionTemplate && (!Method->isInvalidDecl() || Previous.empty()) && !Method->getFriendObjectKind()) Owner->addDecl(Method); @@ -997,7 +1012,9 @@ ParmVarDecl *TemplateDeclInstantiator::VisitParmVarDecl(ParmVarDecl *D) { // Allocate the parameter ParmVarDecl *Param - = ParmVarDecl::Create(SemaRef.Context, Owner, D->getLocation(), + = ParmVarDecl::Create(SemaRef.Context, + SemaRef.Context.getTranslationUnitDecl(), + D->getLocation(), D->getIdentifier(), T, DI, D->getStorageClass(), 0); // Mark the default argument as being uninstantiated. @@ -1542,7 +1559,8 @@ TemplateDeclInstantiator::InitFunctionInstantiation(FunctionDecl *New, Proto->hasAnyExceptionSpec(), Exceptions.size(), Exceptions.data(), - Proto->getNoReturnAttr())); + Proto->getNoReturnAttr(), + Proto->getCallConv())); } return false; @@ -1647,8 +1665,14 @@ void Sema::InstantiateFunctionDefinition(SourceLocation PointOfInstantiation, ActOnStartOfFunctionDef(0, DeclPtrTy::make(Function)); // Introduce a new scope where local variable instantiations will be - // recorded. - LocalInstantiationScope Scope(*this); + // recorded, unless we're actually a member function within a local + // class, in which case we need to merge our results with the parent + // scope (of the enclosing function). + bool MergeWithParentScope = false; + if (CXXRecordDecl *Rec = dyn_cast<CXXRecordDecl>(Function->getDeclContext())) + MergeWithParentScope = Rec->isLocalClass(); + + LocalInstantiationScope Scope(*this, MergeWithParentScope); // Introduce the instantiated function parameters into the local // instantiation scope. @@ -1685,6 +1709,11 @@ void Sema::InstantiateFunctionDefinition(SourceLocation PointOfInstantiation, DeclGroupRef DG(Function); Consumer.HandleTopLevelDecl(DG); + // This class may have local implicit instantiations that need to be + // instantiation within this scope. + PerformPendingImplicitInstantiations(/*LocalOnly=*/true); + Scope.Exit(); + if (Recursive) { // Instantiate any pending implicit instantiations found during the // instantiation of this template. @@ -2217,10 +2246,18 @@ NamedDecl *Sema::FindInstantiatedDecl(NamedDecl *D, /// \brief Performs template instantiation for all implicit template /// instantiations we have seen until this point. -void Sema::PerformPendingImplicitInstantiations() { - while (!PendingImplicitInstantiations.empty()) { - PendingImplicitInstantiation Inst = PendingImplicitInstantiations.front(); - PendingImplicitInstantiations.pop_front(); +void Sema::PerformPendingImplicitInstantiations(bool LocalOnly) { + while (!PendingLocalImplicitInstantiations.empty() || + (!LocalOnly && !PendingImplicitInstantiations.empty())) { + PendingImplicitInstantiation Inst; + + if (PendingLocalImplicitInstantiations.empty()) { + Inst = PendingImplicitInstantiations.front(); + PendingImplicitInstantiations.pop_front(); + } else { + Inst = PendingLocalImplicitInstantiations.front(); + PendingLocalImplicitInstantiations.pop_front(); + } // Instantiate function definitions if (FunctionDecl *Function = dyn_cast<FunctionDecl>(Inst.first)) { diff --git a/lib/Sema/SemaType.cpp b/lib/Sema/SemaType.cpp index 9515834..9065761 100644 --- a/lib/Sema/SemaType.cpp +++ b/lib/Sema/SemaType.cpp @@ -1374,6 +1374,21 @@ namespace { Sema::GetTypeFromParser(DS.getTypeRep(), &TInfo); TL.setUnderlyingTInfo(TInfo); } + void VisitBuiltinTypeLoc(BuiltinTypeLoc TL) { + // By default, use the source location of the type specifier. + TL.setBuiltinLoc(DS.getTypeSpecTypeLoc()); + if (TL.needsExtraLocalData()) { + // Set info for the written builtin specifiers. + TL.getWrittenBuiltinSpecs() = DS.getWrittenBuiltinSpecs(); + // Try to have a meaningful source location. + if (TL.getWrittenSignSpec() != TSS_unspecified) + // Sign spec loc overrides the others (e.g., 'unsigned long'). + TL.setBuiltinLoc(DS.getTypeSpecSignLoc()); + else if (TL.getWrittenWidthSpec() != TSW_unspecified) + // Width spec loc overrides type spec loc (e.g., 'short int'). + TL.setBuiltinLoc(DS.getTypeSpecWidthLoc()); + } + } void VisitTypeLoc(TypeLoc TL) { // FIXME: add other typespec types and change this to an assert. TL.initialize(DS.getTypeSpecTypeLoc()); diff --git a/lib/Sema/TreeTransform.h b/lib/Sema/TreeTransform.h index 445ef0d..b2102af 100644 --- a/lib/Sema/TreeTransform.h +++ b/lib/Sema/TreeTransform.h @@ -1014,15 +1014,12 @@ public: /// /// By default, performs semantic analysis to build the new expression. /// Subclasses may override this routine to provide different behavior. - OwningExprResult RebuildCStyleCaseExpr(SourceLocation LParenLoc, - QualType ExplicitTy, + OwningExprResult RebuildCStyleCastExpr(SourceLocation LParenLoc, + TypeSourceInfo *TInfo, SourceLocation RParenLoc, ExprArg SubExpr) { - return getSema().ActOnCastExpr(/*Scope=*/0, - LParenLoc, - ExplicitTy.getAsOpaquePtr(), - RParenLoc, - move(SubExpr)); + return getSema().BuildCStyleCastExpr(LParenLoc, TInfo, RParenLoc, + move(SubExpr)); } /// \brief Build a new compound literal expression. @@ -1030,11 +1027,11 @@ public: /// By default, performs semantic analysis to build the new expression. /// Subclasses may override this routine to provide different behavior. OwningExprResult RebuildCompoundLiteralExpr(SourceLocation LParenLoc, - QualType T, + TypeSourceInfo *TInfo, SourceLocation RParenLoc, ExprArg Init) { - return getSema().ActOnCompoundLiteral(LParenLoc, T.getAsOpaquePtr(), - RParenLoc, move(Init)); + return getSema().BuildCompoundLiteralExpr(LParenLoc, TInfo, RParenLoc, + move(Init)); } /// \brief Build a new extended vector element access expression. @@ -1194,30 +1191,30 @@ public: OwningExprResult RebuildCXXNamedCastExpr(SourceLocation OpLoc, Stmt::StmtClass Class, SourceLocation LAngleLoc, - QualType T, + TypeSourceInfo *TInfo, SourceLocation RAngleLoc, SourceLocation LParenLoc, ExprArg SubExpr, SourceLocation RParenLoc) { switch (Class) { case Stmt::CXXStaticCastExprClass: - return getDerived().RebuildCXXStaticCastExpr(OpLoc, LAngleLoc, T, + return getDerived().RebuildCXXStaticCastExpr(OpLoc, LAngleLoc, TInfo, RAngleLoc, LParenLoc, move(SubExpr), RParenLoc); case Stmt::CXXDynamicCastExprClass: - return getDerived().RebuildCXXDynamicCastExpr(OpLoc, LAngleLoc, T, + return getDerived().RebuildCXXDynamicCastExpr(OpLoc, LAngleLoc, TInfo, RAngleLoc, LParenLoc, move(SubExpr), RParenLoc); case Stmt::CXXReinterpretCastExprClass: - return getDerived().RebuildCXXReinterpretCastExpr(OpLoc, LAngleLoc, T, + return getDerived().RebuildCXXReinterpretCastExpr(OpLoc, LAngleLoc, TInfo, RAngleLoc, LParenLoc, move(SubExpr), RParenLoc); case Stmt::CXXConstCastExprClass: - return getDerived().RebuildCXXConstCastExpr(OpLoc, LAngleLoc, T, + return getDerived().RebuildCXXConstCastExpr(OpLoc, LAngleLoc, TInfo, RAngleLoc, LParenLoc, move(SubExpr), RParenLoc); @@ -1235,14 +1232,15 @@ public: /// Subclasses may override this routine to provide different behavior. OwningExprResult RebuildCXXStaticCastExpr(SourceLocation OpLoc, SourceLocation LAngleLoc, - QualType T, + TypeSourceInfo *TInfo, SourceLocation RAngleLoc, SourceLocation LParenLoc, ExprArg SubExpr, SourceLocation RParenLoc) { - return getSema().ActOnCXXNamedCast(OpLoc, tok::kw_static_cast, - LAngleLoc, T.getAsOpaquePtr(), RAngleLoc, - LParenLoc, move(SubExpr), RParenLoc); + return getSema().BuildCXXNamedCast(OpLoc, tok::kw_static_cast, + TInfo, move(SubExpr), + SourceRange(LAngleLoc, RAngleLoc), + SourceRange(LParenLoc, RParenLoc)); } /// \brief Build a new C++ dynamic_cast expression. @@ -1251,14 +1249,15 @@ public: /// Subclasses may override this routine to provide different behavior. OwningExprResult RebuildCXXDynamicCastExpr(SourceLocation OpLoc, SourceLocation LAngleLoc, - QualType T, + TypeSourceInfo *TInfo, SourceLocation RAngleLoc, SourceLocation LParenLoc, ExprArg SubExpr, SourceLocation RParenLoc) { - return getSema().ActOnCXXNamedCast(OpLoc, tok::kw_dynamic_cast, - LAngleLoc, T.getAsOpaquePtr(), RAngleLoc, - LParenLoc, move(SubExpr), RParenLoc); + return getSema().BuildCXXNamedCast(OpLoc, tok::kw_dynamic_cast, + TInfo, move(SubExpr), + SourceRange(LAngleLoc, RAngleLoc), + SourceRange(LParenLoc, RParenLoc)); } /// \brief Build a new C++ reinterpret_cast expression. @@ -1267,14 +1266,15 @@ public: /// Subclasses may override this routine to provide different behavior. OwningExprResult RebuildCXXReinterpretCastExpr(SourceLocation OpLoc, SourceLocation LAngleLoc, - QualType T, + TypeSourceInfo *TInfo, SourceLocation RAngleLoc, SourceLocation LParenLoc, ExprArg SubExpr, SourceLocation RParenLoc) { - return getSema().ActOnCXXNamedCast(OpLoc, tok::kw_reinterpret_cast, - LAngleLoc, T.getAsOpaquePtr(), RAngleLoc, - LParenLoc, move(SubExpr), RParenLoc); + return getSema().BuildCXXNamedCast(OpLoc, tok::kw_reinterpret_cast, + TInfo, move(SubExpr), + SourceRange(LAngleLoc, RAngleLoc), + SourceRange(LParenLoc, RParenLoc)); } /// \brief Build a new C++ const_cast expression. @@ -1283,14 +1283,15 @@ public: /// Subclasses may override this routine to provide different behavior. OwningExprResult RebuildCXXConstCastExpr(SourceLocation OpLoc, SourceLocation LAngleLoc, - QualType T, + TypeSourceInfo *TInfo, SourceLocation RAngleLoc, SourceLocation LParenLoc, ExprArg SubExpr, SourceLocation RParenLoc) { - return getSema().ActOnCXXNamedCast(OpLoc, tok::kw_const_cast, - LAngleLoc, T.getAsOpaquePtr(), RAngleLoc, - LParenLoc, move(SubExpr), RParenLoc); + return getSema().BuildCXXNamedCast(OpLoc, tok::kw_const_cast, + TInfo, move(SubExpr), + SourceRange(LAngleLoc, RAngleLoc), + SourceRange(LParenLoc, RParenLoc)); } /// \brief Build a new C++ functional-style cast expression. @@ -1298,13 +1299,13 @@ public: /// By default, performs semantic analysis to build the new expression. /// Subclasses may override this routine to provide different behavior. OwningExprResult RebuildCXXFunctionalCastExpr(SourceRange TypeRange, - QualType T, + TypeSourceInfo *TInfo, SourceLocation LParenLoc, ExprArg SubExpr, SourceLocation RParenLoc) { void *Sub = SubExpr.takeAs<Expr>(); return getSema().ActOnCXXTypeConstructExpr(TypeRange, - T.getAsOpaquePtr(), + TInfo->getType().getAsOpaquePtr(), LParenLoc, Sema::MultiExprArg(getSema(), &Sub, 1), /*CommaLocs=*/0, @@ -2137,7 +2138,11 @@ QualType TransformTypeSpecType(TypeLocBuilder &TLB, TyLoc T) { template<typename Derived> QualType TreeTransform<Derived>::TransformBuiltinType(TypeLocBuilder &TLB, BuiltinTypeLoc T) { - return TransformTypeSpecType(TLB, T); + BuiltinTypeLoc NewT = TLB.push<BuiltinTypeLoc>(T.getType()); + NewT.setBuiltinLoc(T.getBuiltinLoc()); + if (T.needsExtraLocalData()) + NewT.getWrittenBuiltinSpecs() = T.getWrittenBuiltinSpecs(); + return T.getType(); } template<typename Derived> @@ -3815,15 +3820,17 @@ TreeTransform<Derived>::TransformExplicitCastExpr(ExplicitCastExpr *E) { template<typename Derived> Sema::OwningExprResult TreeTransform<Derived>::TransformCStyleCastExpr(CStyleCastExpr *E) { - QualType T; + TypeSourceInfo *OldT; + TypeSourceInfo *NewT; { // FIXME: Source location isn't quite accurate. SourceLocation TypeStartLoc = SemaRef.PP.getLocForEndOfToken(E->getLParenLoc()); TemporaryBase Rebase(*this, TypeStartLoc, DeclarationName()); - T = getDerived().TransformType(E->getTypeAsWritten()); - if (T.isNull()) + OldT = E->getTypeInfoAsWritten(); + NewT = getDerived().TransformType(OldT); + if (!NewT) return SemaRef.ExprError(); } @@ -3833,11 +3840,12 @@ TreeTransform<Derived>::TransformCStyleCastExpr(CStyleCastExpr *E) { return SemaRef.ExprError(); if (!getDerived().AlwaysRebuild() && - T == E->getTypeAsWritten() && + OldT == NewT && SubExpr.get() == E->getSubExpr()) return SemaRef.Owned(E->Retain()); - return getDerived().RebuildCStyleCaseExpr(E->getLParenLoc(), T, + return getDerived().RebuildCStyleCastExpr(E->getLParenLoc(), + NewT, E->getRParenLoc(), move(SubExpr)); } @@ -3845,28 +3853,25 @@ TreeTransform<Derived>::TransformCStyleCastExpr(CStyleCastExpr *E) { template<typename Derived> Sema::OwningExprResult TreeTransform<Derived>::TransformCompoundLiteralExpr(CompoundLiteralExpr *E) { - QualType T; - { - // FIXME: Source location isn't quite accurate. - SourceLocation FakeTypeLoc - = SemaRef.PP.getLocForEndOfToken(E->getLParenLoc()); - TemporaryBase Rebase(*this, FakeTypeLoc, DeclarationName()); - - T = getDerived().TransformType(E->getType()); - if (T.isNull()) - return SemaRef.ExprError(); - } + TypeSourceInfo *OldT = E->getTypeSourceInfo(); + TypeSourceInfo *NewT = getDerived().TransformType(OldT); + if (!NewT) + return SemaRef.ExprError(); OwningExprResult Init = getDerived().TransformExpr(E->getInitializer()); if (Init.isInvalid()) return SemaRef.ExprError(); if (!getDerived().AlwaysRebuild() && - T == E->getType() && + OldT == NewT && Init.get() == E->getInitializer()) return SemaRef.Owned(E->Retain()); - return getDerived().RebuildCompoundLiteralExpr(E->getLParenLoc(), T, + // Note: the expression type doesn't necessarily match the + // type-as-written, but that's okay, because it should always be + // derivable from the initializer. + + return getDerived().RebuildCompoundLiteralExpr(E->getLParenLoc(), NewT, /*FIXME:*/E->getInitializer()->getLocEnd(), move(Init)); } @@ -4237,15 +4242,17 @@ TreeTransform<Derived>::TransformCXXMemberCallExpr(CXXMemberCallExpr *E) { template<typename Derived> Sema::OwningExprResult TreeTransform<Derived>::TransformCXXNamedCastExpr(CXXNamedCastExpr *E) { - QualType ExplicitTy; + TypeSourceInfo *OldT; + TypeSourceInfo *NewT; { // FIXME: Source location isn't quite accurate. SourceLocation TypeStartLoc = SemaRef.PP.getLocForEndOfToken(E->getOperatorLoc()); TemporaryBase Rebase(*this, TypeStartLoc, DeclarationName()); - ExplicitTy = getDerived().TransformType(E->getTypeAsWritten()); - if (ExplicitTy.isNull()) + OldT = E->getTypeInfoAsWritten(); + NewT = getDerived().TransformType(OldT); + if (!NewT) return SemaRef.ExprError(); } @@ -4255,7 +4262,7 @@ TreeTransform<Derived>::TransformCXXNamedCastExpr(CXXNamedCastExpr *E) { return SemaRef.ExprError(); if (!getDerived().AlwaysRebuild() && - ExplicitTy == E->getTypeAsWritten() && + OldT == NewT && SubExpr.get() == E->getSubExpr()) return SemaRef.Owned(E->Retain()); @@ -4269,7 +4276,7 @@ TreeTransform<Derived>::TransformCXXNamedCastExpr(CXXNamedCastExpr *E) { return getDerived().RebuildCXXNamedCastExpr(E->getOperatorLoc(), E->getStmtClass(), FakeLAngleLoc, - ExplicitTy, + NewT, FakeRAngleLoc, FakeRAngleLoc, move(SubExpr), @@ -4305,12 +4312,14 @@ template<typename Derived> Sema::OwningExprResult TreeTransform<Derived>::TransformCXXFunctionalCastExpr( CXXFunctionalCastExpr *E) { - QualType ExplicitTy; + TypeSourceInfo *OldT; + TypeSourceInfo *NewT; { TemporaryBase Rebase(*this, E->getTypeBeginLoc(), DeclarationName()); - ExplicitTy = getDerived().TransformType(E->getTypeAsWritten()); - if (ExplicitTy.isNull()) + OldT = E->getTypeInfoAsWritten(); + NewT = getDerived().TransformType(OldT); + if (!NewT) return SemaRef.ExprError(); } @@ -4320,14 +4329,14 @@ TreeTransform<Derived>::TransformCXXFunctionalCastExpr( return SemaRef.ExprError(); if (!getDerived().AlwaysRebuild() && - ExplicitTy == E->getTypeAsWritten() && + OldT == NewT && SubExpr.get() == E->getSubExpr()) return SemaRef.Owned(E->Retain()); // FIXME: The end of the type's source range is wrong return getDerived().RebuildCXXFunctionalCastExpr( /*FIXME:*/SourceRange(E->getTypeBeginLoc()), - ExplicitTy, + NewT, /*FIXME:*/E->getSubExpr()->getLocStart(), move(SubExpr), E->getRParenLoc()); diff --git a/test/Analysis/NSString-failed-cases.m b/test/Analysis/NSString-failed-cases.m deleted file mode 100644 index 2b8242f..0000000 --- a/test/Analysis/NSString-failed-cases.m +++ /dev/null @@ -1,115 +0,0 @@ -// RUN: %clang_cc1 -triple i386-apple-darwin10 -analyze -analyzer-experimental-internal-checks -checker-cfref -analyzer-store=region -analyzer-constraints=basic -verify %s -// RUN: %clang_cc1 -triple i386-apple-darwin10 -analyze -analyzer-experimental-internal-checks -checker-cfref -analyzer-store=region -analyzer-constraints=range -verify %s -// RUN: %clang_cc1 -DTEST_64 -triple x86_64-apple-darwin10 -analyze -analyzer-experimental-internal-checks -checker-cfref -analyzer-store=region -analyzer-constraints=basic -verify %s -// RUN: %clang_cc1 -DTEST_64 -triple x86_64-apple-darwin10 -analyze -analyzer-experimental-internal-checks -checker-cfref -analyzer-store=region -analyzer-constraints=range -verify %s -// XFAIL: * - -//===----------------------------------------------------------------------===// -// The following code is reduced using delta-debugging from -// Foundation.h (Mac OS X). -// -// It includes the basic definitions for the test cases below. -// Not directly including Foundation.h directly makes this test case -// both svelte and portable to non-Mac platforms. -//===----------------------------------------------------------------------===// - -#ifdef TEST_64 -typedef long long int64_t; -_Bool OSAtomicCompareAndSwap64Barrier( int64_t __oldValue, int64_t __newValue, volatile int64_t *__theValue ); -#define COMPARE_SWAP_BARRIER OSAtomicCompareAndSwap64Barrier -typedef int64_t intptr_t; -#else -typedef int int32_t; -_Bool OSAtomicCompareAndSwap32Barrier( int32_t __oldValue, int32_t __newValue, volatile int32_t *__theValue ); -#define COMPARE_SWAP_BARRIER OSAtomicCompareAndSwap32Barrier -typedef int32_t intptr_t; -#endif - -typedef const void * CFTypeRef; -typedef const struct __CFString * CFStringRef; -typedef const struct __CFAllocator * CFAllocatorRef; -extern const CFAllocatorRef kCFAllocatorDefault; -extern CFTypeRef CFRetain(CFTypeRef cf); -void CFRelease(CFTypeRef cf); -typedef const struct __CFDictionary * CFDictionaryRef; -const void *CFDictionaryGetValue(CFDictionaryRef theDict, const void *key); -extern CFStringRef CFStringCreateWithFormat(CFAllocatorRef alloc, CFDictionaryRef formatOptions, CFStringRef format, ...); -typedef signed char BOOL; -typedef int NSInteger; -typedef unsigned int NSUInteger; -@class NSString, Protocol; -extern void NSLog(NSString *format, ...) __attribute__((format(__NSString__, 1, 2))); -typedef NSInteger NSComparisonResult; -typedef struct _NSZone NSZone; -@class NSInvocation, NSMethodSignature, NSCoder, NSString, NSEnumerator; -@protocol NSObject -- (BOOL)isEqual:(id)object; -- (oneway void)release; -- (id)retain; -- (id)autorelease; -@end -@protocol NSCopying -- (id)copyWithZone:(NSZone *)zone; -@end -@protocol NSMutableCopying -- (id)mutableCopyWithZone:(NSZone *)zone; -@end -@protocol NSCoding -- (void)encodeWithCoder:(NSCoder *)aCoder; -@end -@interface NSObject <NSObject> {} -- (id)init; -+ (id)alloc; -@end -extern id NSAllocateObject(Class aClass, NSUInteger extraBytes, NSZone *zone); -typedef struct {} NSFastEnumerationState; -@protocol NSFastEnumeration -- (NSUInteger)countByEnumeratingWithState:(NSFastEnumerationState *)state objects:(id *)stackbuf count:(NSUInteger)len; -@end -@class NSString; -typedef struct _NSRange {} NSRange; -@interface NSArray : NSObject <NSCopying, NSMutableCopying, NSCoding, NSFastEnumeration> -- (NSUInteger)count; -@end -@interface NSMutableArray : NSArray -- (void)addObject:(id)anObject; -- (id)initWithCapacity:(NSUInteger)numItems; -@end -typedef unsigned short unichar; -@class NSData, NSArray, NSDictionary, NSCharacterSet, NSData, NSURL, NSError, NSLocale; -typedef NSUInteger NSStringCompareOptions; -@interface NSString : NSObject <NSCopying, NSMutableCopying, NSCoding> - (NSUInteger)length; -- (NSComparisonResult)compare:(NSString *)string; -- (NSComparisonResult)compare:(NSString *)string options:(NSStringCompareOptions)mask; -- (NSComparisonResult)compare:(NSString *)string options:(NSStringCompareOptions)mask range:(NSRange)compareRange; -- (NSComparisonResult)compare:(NSString *)string options:(NSStringCompareOptions)mask range:(NSRange)compareRange locale:(id)locale; -- (NSComparisonResult)caseInsensitiveCompare:(NSString *)string; -- (NSArray *)componentsSeparatedByCharactersInSet:(NSCharacterSet *)separator; -+ (id)stringWithFormat:(NSString *)format, ... __attribute__((format(__NSString__, 1, 2))); -@end -@interface NSSimpleCString : NSString {} @end -@interface NSConstantString : NSSimpleCString @end -extern void *_NSConstantStringClassReference; - -//===----------------------------------------------------------------------===// -// Test cases. These should all be merged into NSString.m once these tests -// stop reporting leaks. -//===----------------------------------------------------------------------===// - -// FIXME: THIS TEST CASE INCORRECTLY REPORTS A LEAK. -void testOSCompareAndSwapXXBarrier_parameter(NSString **old) { - NSString *s = [[NSString alloc] init]; // no-warning - if (!COMPARE_SWAP_BARRIER((intptr_t) 0, (intptr_t) s, (intptr_t*) old)) - [s release]; - else - [*old release]; -} - -// FIXME: THIS TEST CASE INCORRECTLY REPORTS A LEAK. -void testOSCompareAndSwapXXBarrier_parameter_no_direct_release(NSString **old) { - NSString *s = [[NSString alloc] init]; // no-warning - if (!COMPARE_SWAP_BARRIER((intptr_t) 0, (intptr_t) s, (intptr_t*) old)) - return; - else - [*old release]; -} diff --git a/test/Analysis/malloc.c b/test/Analysis/malloc.c index 4d771ee..7d2b718 100644 --- a/test/Analysis/malloc.c +++ b/test/Analysis/malloc.c @@ -51,3 +51,9 @@ void f6() { else free(p); } + +char *doit2(); +void pr6069() { + char *buf = doit2(); + free(buf); +} diff --git a/test/Analysis/misc-ps.m b/test/Analysis/misc-ps.m index 9543a98..ae42dca 100644 --- a/test/Analysis/misc-ps.m +++ b/test/Analysis/misc-ps.m @@ -811,3 +811,29 @@ int pr6033(int x) { return x % y; // expected-warning{{The right operand of '%' is a garbage value}} } +struct trie { + struct trie* next; +}; + +struct kwset { + struct trie *trie; + unsigned char delta[10]; + struct trie* next[10]; + int d; +}; + +typedef struct trie trie_t; +typedef struct kwset kwset_t; + +void f(kwset_t *kws, char const *p, char const *q) { + struct trie const *trie; + struct trie * const *next = kws->next; + register unsigned char c; + register char const *end = p; + register char const *lim = q; + register int d = 1; + register unsigned char const *delta = kws->delta; + + d = delta[c = (end+=d)[-1]]; // no-warning + trie = next[c]; +} diff --git a/test/Analysis/outofbound.c b/test/Analysis/outofbound.c index 2142e9e..68e77ca 100644 --- a/test/Analysis/outofbound.c +++ b/test/Analysis/outofbound.c @@ -1,7 +1,15 @@ -// RUN: %clang_cc1 -analyze -analyzer-experimental-internal-checks -checker-cfref -analyzer-store=region -verify %s +// RUN: %clang_cc1 -analyze -analyzer-experimental-internal-checks -analyzer-experimental-checks -checker-cfref -analyzer-store=region -verify %s + +typedef __typeof(sizeof(int)) size_t; +void *malloc(size_t); char f1() { char* s = "abcd"; char c = s[4]; // no-warning return s[5] + c; // expected-warning{{Access out-of-bound array element (buffer overflow)}} } + +void f2() { + int *p = malloc(12); + p[3] = 4; // expected-warning{{Access out-of-bound array element (buffer overflow)}} +} diff --git a/test/CXX/class.access/class.access.base/p1.cpp b/test/CXX/class.access/class.access.base/p1.cpp new file mode 100644 index 0000000..fd0d9f6 --- /dev/null +++ b/test/CXX/class.access/class.access.base/p1.cpp @@ -0,0 +1,152 @@ +// RUN: %clang_cc1 -fsyntax-only -faccess-control -verify %s + +// C++0x [class.access.base]p1(a): +// If a class is declared to be a base class for another class using +// the public access specifier, the public members of the base class +// are accessible as public members of the derived class and protected +// members of the base class are accessible as protected members of +// the derived class. +namespace test0 { + class Base { + public: int pub; static int spub; + protected: int prot; static int sprot; // expected-note 4 {{declared protected here}} + private: int priv; static int spriv; // expected-note 8 {{declared private here}} + }; + + class Test : public Base { + void test() { + pub++; + spub++; + prot++; + sprot++; + priv++; // expected-error {{private member}} + spriv++; // expected-error {{private member}} + + Base::pub++; + Base::spub++; + Base::prot++; + Base::sprot++; + Base::priv++; // expected-error {{private member}} + Base::spriv++; // expected-error {{private member}} + } + }; + + void test(Test *t) { + t->pub++; + t->spub++; + t->prot++; // expected-error {{protected member}} + t->sprot++; // expected-error {{protected member}} + t->priv++; // expected-error {{private member}} + t->spriv++; // expected-error {{private member}} + + t->Base::pub++; + t->Base::spub++; + t->Base::prot++; // expected-error {{protected member}} + t->Base::sprot++; // expected-error {{protected member}} + t->Base::priv++; // expected-error {{private member}} + t->Base::spriv++; // expected-error {{private member}} + } +} + +// C++0x [class.access.base]p1(b): +// If a class is declared to be a base class for another class using +// the protected access specifier, the public and protected members +// of the base class are accessible as protected members of the +// derived class. +namespace test1 { + class Base { // expected-note 6 {{constrained by protected inheritance}} + public: int pub; static int spub; // expected-note 2 {{constrained by protected inheritance}} + protected: int prot; static int sprot; // expected-note 4 {{declared protected here}} + private: int priv; static int spriv; // expected-note 8 {{declared private here}} + }; + + class Test : protected Base { + void test() { + pub++; + spub++; + prot++; + sprot++; + priv++; // expected-error {{private member}} + spriv++; // expected-error {{private member}} + + Base::pub++; + Base::spub++; + Base::prot++; + Base::sprot++; + Base::priv++; // expected-error {{private member}} + Base::spriv++; // expected-error {{private member}} + } + }; + + void test(Test *t) { + t->pub++; // expected-error {{protected member}} + t->spub++; // expected-error {{protected member}} + t->prot++; // expected-error {{protected member}} + t->sprot++; // expected-error {{protected member}} + t->priv++; // expected-error {{private member}} + t->spriv++; // expected-error {{private member}} + + // Two possible errors here: one for Base, one for the member + t->Base::pub++; // expected-error {{protected member}} + t->Base::spub++; // expected-error {{protected member}} + t->Base::prot++; // expected-error 2 {{protected member}} + t->Base::sprot++; // expected-error 2 {{protected member}} + t->Base::priv++; // expected-error {{protected member}} expected-error {{private member}} + t->Base::spriv++; // expected-error {{protected member}} expected-error {{private member}} + } +} + +// C++0x [class.access.base]p1(b): +// If a class is declared to be a base class for another class using +// the private access specifier, the public and protected members of +// the base class are accessible as private members of the derived +// class. +namespace test2 { + class Base { //expected-note 6 {{constrained by private inheritance}} + public: + int pub; // expected-note {{constrained by private inheritance}} + static int spub; // expected-note {{constrained by private inheritance}} + protected: + int prot; // expected-note {{constrained by private inheritance}} \ + // expected-note {{declared protected here}} + static int sprot; // expected-note {{constrained by private inheritance}} \ + // expected-note {{declared protected here}} + private: + int priv; // expected-note 4 {{declared private here}} + static int spriv; // expected-note 4 {{declared private here}} + }; + + class Test : private Base { // expected-note 6 {{'private' inheritance specifier here}} + void test() { + pub++; + spub++; + prot++; + sprot++; + priv++; // expected-error {{private member}} + spriv++; // expected-error {{private member}} + + Base::pub++; + Base::spub++; + Base::prot++; + Base::sprot++; + Base::priv++; // expected-error {{private member}} + Base::spriv++; // expected-error {{private member}} + } + }; + + void test(Test *t) { + t->pub++; // expected-error {{private member}} expected-error {{inaccessible base class}} + t->spub++; // expected-error {{private member}} + t->prot++; // expected-error {{private member}} expected-error {{inaccessible base class}} + t->sprot++; // expected-error {{private member}} + t->priv++; // expected-error {{private member}} expected-error {{inaccessible base class}} + t->spriv++; // expected-error {{private member}} + + t->Base::pub++; // expected-error {{private member}} expected-error {{inaccessible base class}} + t->Base::spub++; // expected-error {{private member}} + t->Base::prot++; // expected-error {{protected member}} expected-error {{private member}} expected-error {{inaccessible base class}} + t->Base::sprot++; // expected-error {{protected member}} expected-error {{private member}} + t->Base::priv++; // expected-error 2 {{private member}} expected-error {{inaccessible base class}} + t->Base::spriv++; // expected-error 2 {{private member}} + } +} diff --git a/test/CodeCompletion/call.c b/test/CodeCompletion/call.c new file mode 100644 index 0000000..8210389 --- /dev/null +++ b/test/CodeCompletion/call.c @@ -0,0 +1,15 @@ +// Note: the run lines follow their respective tests, since line/column +// matter in this test. +void f0(float x, float y); +void f1(); +void test() { + f0(0, 0); + g0(0, 0); + f1(0, 0); + // RUN: %clang_cc1 -std=c89 -fsyntax-only -code-completion-at=%s:6:6 %s -o - | FileCheck -check-prefix=CC1 %s + // CHECK-CC1: f0(<#float x#>, float y) + // RUN: %clang_cc1 -std=c89 -fsyntax-only -code-completion-at=%s:6:9 %s -o - | FileCheck -check-prefix=CC2 %s + // CHECK-CC2: f0(float x, <#float y#>) + // RUN: %clang_cc1 -std=c89 -fsyntax-only -code-completion-at=%s:8:6 %s -o - | FileCheck -check-prefix=CC3 %s + // CHECK-CC3: f1() +} diff --git a/test/CodeGen/2009-10-20-GlobalDebug.c b/test/CodeGen/2009-10-20-GlobalDebug.c index f19ceb1..99be469 100644 --- a/test/CodeGen/2009-10-20-GlobalDebug.c +++ b/test/CodeGen/2009-10-20-GlobalDebug.c @@ -1,4 +1,4 @@ // RUN: %clang -ccc-host-triple i386-apple-darwin10 -S -g -dA %s -o - | FileCheck %s int global; -// CHECK: asciz "global" ## DW_AT_name +// CHECK: asciz "global" ## External Name int main() { return 0;} diff --git a/test/CodeGenCXX/copy-assign-synthesis-3.cpp b/test/CodeGenCXX/copy-assign-synthesis-3.cpp index 73c2261..ce4640a 100644 --- a/test/CodeGenCXX/copy-assign-synthesis-3.cpp +++ b/test/CodeGenCXX/copy-assign-synthesis-3.cpp @@ -1,18 +1,24 @@ // RUN: %clang_cc1 -emit-llvm-only -verify %s struct A { - A& operator=(const A&); + A& operator=(A&); }; struct B { + void operator=(B); +}; + +struct C { A a; - float b; - int (A::*c)(); - _Complex float d; - int e[10]; - A f[2]; + B b; + float c; + int (A::*d)(); + _Complex float e; + int f[10]; + A g[2]; + B h[2]; }; -void a(B& x, B& y) { +void a(C& x, C& y) { x = y; } diff --git a/test/CodeGenCXX/debug-info.cpp b/test/CodeGenCXX/debug-info.cpp index 705491e..cb6e830 100644 --- a/test/CodeGenCXX/debug-info.cpp +++ b/test/CodeGenCXX/debug-info.cpp @@ -18,3 +18,9 @@ void f() { int B::*a = 0; void (B::*b)() = 0; } + +namespace EmptyNameCrash { + struct A { A(); }; + typedef struct { A x; } B; + B x; +} diff --git a/test/CodeGenCXX/member-function-pointers.cpp b/test/CodeGenCXX/member-function-pointers.cpp index 2454dda..e1353a7 100644 --- a/test/CodeGenCXX/member-function-pointers.cpp +++ b/test/CodeGenCXX/member-function-pointers.cpp @@ -139,3 +139,14 @@ namespace PR5940 { void (foo::*ptr)(void) = &foo::baz; } } + +namespace MemberPointerImpCast { + struct A { + int x; + }; + struct B : public A { + }; + void f(B* obj, void (A::*method)()) { + (obj->*method)(); + } +} diff --git a/test/CodeGenCXX/temp-order.cpp b/test/CodeGenCXX/temp-order.cpp index e1ef7eb..05a9aed 100644 --- a/test/CodeGenCXX/temp-order.cpp +++ b/test/CodeGenCXX/temp-order.cpp @@ -167,13 +167,10 @@ void test() { if (f5() != ORDER4(5, 3, 7, 2)) error(); -// FIXME: Clang/LLVM currently can't fold this to a constant. If the error check -// is present (since it avoids single-caller inlining). PR5645. - -// CHECK: call void @print(i8* {{.*}}, i32 1251552576) +// CHECK: call void @print(i8* {{.*}}, i32 1251552576) print("f6", f6()); -// if (f6() != ORDER6(3, 7, 11, 5, 13, 2)) -// error(); + if (f6() != ORDER6(3, 7, 11, 5, 13, 2)) + error(); } diff --git a/test/CodeGenCXX/virt.cpp b/test/CodeGenCXX/virt.cpp index f7f4c9f..22e11fd 100644 --- a/test/CodeGenCXX/virt.cpp +++ b/test/CodeGenCXX/virt.cpp @@ -17,11 +17,7 @@ struct B { void B::bar1() { } void B::bar2() { } -// CHECK-LP64: __ZTV1B: -// CHECK-LP64-NEXT: .space 8 -// CHECK-LP64-NEXT: .quad __ZTI1B -// CHECK-LP64-NEXT: .quad __ZN1B4bar1Ev -// CHECK-LP64-NEXT: .quad __ZN1B4bar2Ev +// CHECK-LPLL64:@_ZTV1B = constant [4 x i8*] [i8* null, i8* bitcast (%0* @_ZTI1B to i8*), i8* bitcast (void (%struct.B*)* @_ZN1B4bar1Ev to i8*), i8* bitcast (void (%struct.B*)* @_ZN1B4bar2Ev to i8*)] struct C { virtual void bee1(); @@ -52,42 +48,8 @@ public: }; void F::foo() { } -// CHECK-LP64: __ZTV1F: -// CHECK-LP64-NEXT: .space 8 -// CHECK-LP64-NEXT: .quad 16 -// CHECK-LP64-NEXT: .space 8 -// CHECK-LP64-NEXT: .space 8 -// CHECK-LP64-NEXT: .quad __ZTI1F -// CHECK-LP64-NEXT: .quad __ZN1D3booEv -// CHECK-LP64-NEXT: .quad __ZN1F3fooEv -// CHECK-LP64-NEXT: .space 8 -// CHECK-LP64-NEXT: .space 8 -// CHECK-LP64-NEXT: .space 8 -// CHECK-LP64-NEXT: .space 8 -// CHECK-LP64-NEXT: .space 8 -// CHECK-LP64-NEXT: .quad 18446744073709551600 -// CHECK-LP64-NEXT: .quad __ZTI1F -// CHECK-LP64-NEXT: .quad __ZN2D13barEv -// CHECK-LP64-NEXT: .quad __ZN2D14bar2Ev -// CHECK-LP64-NEXT: .quad __ZN2D14bar3Ev -// CHECK-LP64-NEXT: .quad __ZN2D14bar4Ev -// CHECK-LP64-NEXT: .quad __ZN2D14bar5Ev - - -int j; -void *vp; -void test2() { - F f; - static int sz = (char *)(&f.f) - (char *)(&f); - vp = &sz; - j = sz; - // FIXME: These should result in a frontend constant a la fold, no run time - // initializer - // CHECK-LPLL64: define void @_Z5test2v() - // CHECK-LPLL64: = getelementptr inbounds %class.F* %f, i32 0, i32 1 -} +// CHECK-LPLL64:@_ZTV1F = constant [19 x i8*] [i8* null, i8* inttoptr (i64 16 to i8*), i8* null, i8* null, i8* bitcast (%1* @_ZTI1F to i8*), i8* bitcast (void (%class.test14*)* @_ZN1D3booEv to i8*), i8* bitcast (void (%class.F*)* @_ZN1F3fooEv to i8*), i8* null, i8* null, i8* null, i8* null, i8* null, i8* inttoptr (i64 -16 to i8*), i8* bitcast (%1* @_ZTI1F to i8*), i8* bitcast (void (%struct.D1*)* @_ZN2D13barEv to i8*), i8* bitcast (void (%struct.D1*)* @_ZN2D14bar2Ev to i8*), i8* bitcast (void (%struct.D1*)* @_ZN2D14bar3Ev to i8*), i8* bitcast (void (%struct.D1*)* @_ZN2D14bar4Ev to i8*), i8* bitcast (void (%struct.D1*)* @_ZN2D14bar5Ev to i8*)] -static_assert(sizeof(F) == sizeof(void*)*4, "invalid vbase size"); struct E { int e; @@ -105,6 +67,8 @@ public: void A::foo1() { } void A::foo2() { } +// CHECK-LPLL64:@_ZTV1A = constant [10 x i8*] [i8* null, i8* bitcast (%2* @_ZTI1A to i8*), i8* bitcast (void (%struct.B*)* @_ZN1B4bar1Ev to i8*), i8* bitcast (void (%struct.B*)* @_ZN1B4bar2Ev to i8*), i8* bitcast (void (%class.A*)* @_ZN1A4foo1Ev to i8*), i8* bitcast (void (%class.A*)* @_ZN1A4foo2Ev to i8*), i8* inttoptr (i64 -16 to i8*), i8* bitcast (%2* @_ZTI1A to i8*), i8* bitcast (void (%class.test14*)* @_ZN1C4bee1Ev to i8*), i8* bitcast (void (%class.test14*)* @_ZN1C4bee2Ev to i8*)] + int main() { A a; B b; @@ -112,18 +76,6 @@ int main() { ap->b = 2; } -// CHECK-LP64: __ZTV1A: -// CHECK-LP64-NEXT: .space 8 -// CHECK-LP64-NEXT: .quad __ZTI1A -// CHECK-LP64-NEXT: .quad __ZN1B4bar1Ev -// CHECK-LP64-NEXT: .quad __ZN1B4bar2Ev -// CHECK-LP64-NEXT: .quad __ZN1A4foo1Ev -// CHECK-LP64-NEXT: .quad __ZN1A4foo2Ev -// CHECK-LP64-NEXT: .quad 18446744073709551600 -// CHECK-LP64-NEXT: .quad __ZTI1A -// CHECK-LP64-NEXT: .quad __ZN1C4bee1Ev -// CHECK-LP64-NEXT: .quad __ZN1C4bee2Ev - struct test12_A { virtual void foo0() { } @@ -136,24 +88,6 @@ struct test12_B : public test12_A { struct test12_D : public test12_B { } *test12_pd; -void test12_foo() { - test12_pa->foo0(); - test12_pb->foo0(); - test12_pd->foo0(); - test12_pa->foo(); - test12_pb->foo(); - test12_pd->foo(); - test12_pa->test12_A::foo(); -} - -// CHECK-LPLL64:define void @_Z10test12_foov() nounwind { -// CHECK-LPLL64: call void % -// CHECK-LPLL64: call void % -// CHECK-LPLL64: call void % -// CHECK-LPLL64: call void % -// CHECK-LPLL64: call void % -// CHECK-LPLL64: call void % -// CHECK-LPLL64: call void @_ZN8test12_A3fooEv(%class.test14* %{{.*}}) struct test6_B2 { virtual void funcB2(); char b[1000]; }; @@ -162,7 +96,7 @@ struct test6_B1 : virtual test6_B2 { virtual void funcB1(); }; struct test6_D : test6_B2, virtual test6_B1 { }; -// CHECK-LP64: .zerofill __DATA, __common, _d6, 2024, 4 +// CHECK-LP64: .zerofill __DATA,__common,_d6,2024,4 struct test7_B2 { virtual void funcB2(); }; struct test7_B1 : virtual test7_B2 { virtual void funcB1(); }; @@ -170,7 +104,7 @@ struct test7_B1 : virtual test7_B2 { virtual void funcB1(); }; struct test7_D : test7_B2, virtual test7_B1 { }; -// CHECK-LP64: .zerofill __DATA, __common, _d7, 16, 3 +// CHECK-LP64: .zerofill __DATA,__common,_d7,16,3 struct test3_B3 { virtual void funcB3(); }; @@ -181,38 +115,13 @@ struct test3_D : virtual test3_B1 { virtual void funcD() { } }; -// CHECK-LP64:__ZTV7test3_D: -// CHECK-LP64-NEXT: .space 8 -// CHECK-LP64-NEXT: .space 8 -// CHECK-LP64-NEXT: .space 8 -// CHECK-LP64-NEXT: .space 8 -// CHECK-LP64-NEXT: .space 8 -// CHECK-LP64-NEXT: .space 8 -// CHECK-LP64-NEXT: .space 8 -// CHECK-LP64-NEXT: .quad __ZTI7test3_D -// CHECK-LP64-NEXT: .quad __ZN8test3_B36funcB3Ev -// CHECK-LP64-NEXT: .quad __ZN8test3_B26funcB2Ev -// CHECK-LP64-NEXT: .quad __ZN8test3_B16funcB1Ev -// CHECK-LP64-NEXT: .quad __ZN7test3_D5funcDEv +// CHECK-LPLL64:@_ZTV7test3_D = weak_odr constant [12 x i8*] [i8* null, i8* null, i8* null, i8* null, i8* null, i8* null, i8* null, i8* bitcast (%3* @_ZTI7test3_D to i8*), i8* bitcast (void (%class.test14*)* @_ZN8test3_B36funcB3Ev to i8*), i8* bitcast (void (%class.test17_B2*)* @_ZN8test3_B26funcB2Ev to i8*), i8* bitcast (void (%class.test17_B2*)* @_ZN8test3_B16funcB1Ev to i8*), i8* bitcast (void (%class.test17_B2*)* @_ZN7test3_D5funcDEv to i8*)] + struct test4_D : virtual B, virtual C { }; -// CHECK-LP64:__ZTV7test4_D: -// CHECK-LP64-NEXT: .space 8 -// CHECK-LP64-NEXT: .quad 8 -// CHECK-LP64-NEXT: .space 8 -// CHECK-LP64-NEXT: .space 8 -// CHECK-LP64-NEXT: .space 8 -// CHECK-LP64-NEXT: .quad __ZTI7test4_D -// CHECK-LP64-NEXT: .quad __ZN1C4bee1Ev -// CHECK-LP64-NEXT: .quad __ZN1C4bee2Ev -// CHECK-LP64-NEXT: .space 8 -// CHECK-LP64-NEXT: .space 8 -// CHECK-LP64-NEXT: .quad 18446744073709551608 -// CHECK-LP64-NEXT: .quad __ZTI7test4_D -// CHECK-LP64-NEXT: .quad __ZN1B4bar1Ev -// CHECK-LP64-NEXT: .quad __ZN1B4bar2Ev +// CHECK-LPLL64:@_ZTV7test4_D = weak_odr constant [14 x i8*] [i8* null, i8* inttoptr (i64 8 to i8*), i8* null, i8* null, i8* null, i8* bitcast (%1* @_ZTI7test4_D to i8*), i8* bitcast (void (%class.test14*)* @_ZN1C4bee1Ev to i8*), i8* bitcast (void (%class.test14*)* @_ZN1C4bee2Ev to i8*), i8* null, i8* null, i8* inttoptr (i64 -8 to i8*), i8* bitcast (%1* @_ZTI7test4_D to i8*), i8* bitcast (void (%struct.B*)* @_ZN1B4bar1Ev to i8*), i8* bitcast (void (%struct.B*)* @_ZN1B4bar2Ev to i8*)] struct test5_B3 { virtual void funcB3(); }; @@ -235,57 +144,7 @@ struct test5_D : virtual test5_B1, virtual test5_B21, virtual test5_B31 { virtual void funcD() { } }; -// CHECK-LP64:__ZTV7test5_D: -// CHECK-LP64-NEXT: .quad 32 -// CHECK-LP64-NEXT: .quad 24 -// CHECK-LP64-NEXT: .quad 16 -// CHECK-LP64-NEXT: .quad 16 -// CHECK-LP64-NEXT: .quad 16 -// CHECK-LP64-NEXT: .quad 8 -// CHECK-LP64-NEXT: .quad 8 -// CHECK-LP64-NEXT: .quad 8 -// CHECK-LP64-NEXT: .space 8 -// CHECK-LP64-NEXT: .space 8 -// CHECK-LP64-NEXT: .space 8 -// CHECK-LP64-NEXT: .space 8 -// CHECK-LP64-NEXT: .space 8 -// CHECK-LP64-NEXT: .space 8 -// CHECK-LP64-NEXT: .space 8 -// CHECK-LP64-NEXT: .quad __ZTI7test5_D -// CHECK-LP64-NEXT: .quad __ZN8test5_B36funcB3Ev -// CHECK-LP64-NEXT: .quad __ZN8test5_B26funcB2Ev -// CHECK-LP64-NEXT: .quad __ZN8test5_B16funcB1Ev -// CHECK-LP64-NEXT: .quad __ZN7test5_D5funcDEv -// CHECK-LP64-NEXT: .space 8 -// CHECK-LP64-NEXT: .space 8 -// CHECK-LP64-NEXT: .space 8 -// CHECK-LP64-NEXT: .space 8 -// CHECK-LP64-NEXT: .space 8 -// CHECK-LP64-NEXT: .quad 18446744073709551608 -// CHECK-LP64-NEXT: .quad __ZTI7test5_D -// CHECK-LP64-NEXT: .quad __ZN9test5_B237funcB23Ev -// CHECK-LP64-NEXT: .quad __ZN9test5_B227funcB22Ev -// CHECK-LP64-NEXT: .quad __ZN9test5_B217funcB21Ev -// CHECK-LP64-NEXT: .space 8 -// CHECK-LP64-NEXT: .quad 16 -// CHECK-LP64-NEXT: .space 8 -// CHECK-LP64-NEXT: .space 8 -// CHECK-LP64-NEXT: .quad 8 -// CHECK-LP64-NEXT: .space 8 -// CHECK-LP64-NEXT: .space 8 -// CHECK-LP64-NEXT: .quad 18446744073709551600 -// CHECK-LP64-NEXT: .quad __ZTI7test5_D -// CHECK-LP64-NEXT: .quad __ZN9test5_B337funcB33Ev -// CHECK-LP64-NEXT: .quad __ZN9test5_B327funcB32Ev -// CHECK-LP64-NEXT: .quad __ZN9test5_B317funcB31Ev -// CHECK-LP64-NEXT: .space 8 -// CHECK-LP64-NEXT: .quad 18446744073709551592 -// CHECK-LP64-NEXT: .quad __ZTI7test5_D -// CHECK-LP64-NEXT: .quad __ZN4B2328funcB232Ev -// CHECK-LP64-NEXT: .space 8 -// CHECK-LP64-NEXT: .quad 18446744073709551584 -// CHECK-LP64-NEXT: .quad __ZTI7test5_D -// CHECK-LP64-NEXT: .quad __ZN4B2318funcB231Ev +// CHECK-LPLL64:@_ZTV7test5_D = weak_odr constant [50 x i8*] [i8* inttoptr (i64 32 to i8*), i8* inttoptr (i64 24 to i8*), i8* inttoptr (i64 16 to i8*), i8* inttoptr (i64 16 to i8*), i8* inttoptr (i64 16 to i8*), i8* inttoptr (i64 8 to i8*), i8* inttoptr (i64 8 to i8*), i8* inttoptr (i64 8 to i8*), i8* null, i8* null, i8* null, i8* null, i8* null, i8* null, i8* null, i8* bitcast (%2* @_ZTI7test5_D to i8*), i8* bitcast (void (%class.test14*)* @_ZN8test5_B36funcB3Ev to i8*), i8* bitcast (void (%class.test17_B2*)* @_ZN8test5_B26funcB2Ev to i8*), i8* bitcast (void (%class.test17_B2*)* @_ZN8test5_B16funcB1Ev to i8*), i8* bitcast (void (%struct.test10_B2*)* @_ZN7test5_D5funcDEv to i8*), i8* null, i8* null, i8* null, i8* null, i8* null, i8* inttoptr (i64 -8 to i8*), i8* bitcast (%2* @_ZTI7test5_D to i8*), i8* bitcast (void (%class.test14*)* @_ZN9test5_B237funcB23Ev to i8*), i8* bitcast (void (%class.test17_B2*)* @_ZN9test5_B227funcB22Ev to i8*), i8* bitcast (void (%class.test17_B2*)* @_ZN9test5_B217funcB21Ev to i8*), i8* null, i8* inttoptr (i64 16 to i8*), i8* null, i8* null, i8* inttoptr (i64 8 to i8*), i8* null, i8* null, i8* inttoptr (i64 -16 to i8*), i8* bitcast (%2* @_ZTI7test5_D to i8*), i8* bitcast (void (%class.test14*)* @_ZN9test5_B337funcB33Ev to i8*), i8* bitcast (void (%class.test20_D*)* @_ZN9test5_B327funcB32Ev to i8*), i8* bitcast (void (%class.test23_D*)* @_ZN9test5_B317funcB31Ev to i8*), i8* null, i8* inttoptr (i64 -24 to i8*), i8* bitcast (%2* @_ZTI7test5_D to i8*), i8* bitcast (void (%class.test14*)* @_ZN4B2328funcB232Ev to i8*), i8* null, i8* inttoptr (i64 -32 to i8*), i8* bitcast (%2* @_ZTI7test5_D to i8*), i8* bitcast (void (%class.test14*)* @_ZN4B2318funcB231Ev to i8*)] struct test8_B1 { virtual void ftest8_B1() { } @@ -313,75 +172,13 @@ struct test8_B3 { class test8_D : test8_B1, test8_B2, test8_B3 { }; -// CHECK-LP64:__ZTV7test8_D: -// CHECK-LP64-NEXT: .quad 48 -// CHECK-LP64-NEXT: .quad 32 -// CHECK-LP64-NEXT: .space 8 -// CHECK-LP64-NEXT: .quad __ZTI7test8_D -// CHECK-LP64-NEXT: .quad __ZN8test8_B19ftest8_B1Ev -// CHECK-LP64-NEXT: .quad 40 -// CHECK-LP64-NEXT: .quad 24 -// CHECK-LP64-NEXT: .quad 18446744073709551608 -// CHECK-LP64-NEXT: .quad __ZTI7test8_D -// CHECK-LP64-NEXT: .quad __ZN9test8_B2a10ftest8_B2aEv -// CHECK-LP64-NEXT: .quad __ZN8test8_B29ftest8_B2Ev -// CHECK-LP64-NEXT: .quad 18446744073709551600 -// CHECK-LP64-NEXT: .quad __ZTI7test8_D -// CHECK-LP64-NEXT: .quad __ZN9test8_B2b10ftest8_B2bEv -// CHECK-LP64-NEXT: .quad 18446744073709551592 -// CHECK-LP64-NEXT: .quad __ZTI7test8_D -// CHECK-LP64-NEXT: .quad __ZN8test8_B39ftest8_B3Ev -// CHECK-LP64-NEXT: .space 8 -// CHECK-LP64-NEXT: .quad 18446744073709551584 -// CHECK-LP64-NEXT: .quad __ZTI7test8_D -// CHECK-LP64-NEXT: .quad __ZN10test8_B2aa11ftest8_B2aaEv -// CHECK-LP64-NEXT: .space 8 -// CHECK-LP64-NEXT: .quad 18446744073709551568 -// CHECK-LP64-NEXT: .quad __ZTI7test8_D -// CHECK-LP64-NEXT: .quad __ZN10test8_B2ab11ftest8_B2abEv - -// CHECK-LP64:__ZTC7test8_D8_8test8_B2: -// CHECK-LP64-NEXT: .quad 40 -// CHECK-LP64-NEXT: .quad 24 -// CHECK-LP64-NEXT: .space 8 -// CHECK-LP64-NEXT: .quad __ZTI8test8_B2 -// CHECK-LP64-NEXT: .quad __ZN9test8_B2a10ftest8_B2aEv -// CHECK-LP64-NEXT: .quad __ZN8test8_B29ftest8_B2Ev -// CHECK-LP64-NEXT: .space 8 -// CHECK-LP64-NEXT: .quad 18446744073709551592 -// CHECK-LP64-NEXT: .quad __ZTI8test8_B2 -// CHECK-LP64-NEXT: .quad __ZN10test8_B2aa11ftest8_B2aaEv -// CHECK-LP64-NEXT: .space 8 -// CHECK-LP64-NEXT: .quad 18446744073709551576 -// CHECK-LP64-NEXT: .quad __ZTI8test8_B2 -// CHECK-LP64-NEXT: .quad __ZN10test8_B2ab11ftest8_B2abEv - -// CHECK-LP64:__ZTC7test8_D8_9test8_B2a: -// CHECK-LP64-NEXT: .quad 40 -// CHECK-LP64-NEXT: .quad 24 -// CHECK-LP64-NEXT: .space 8 -// CHECK-LP64-NEXT: .quad __ZTI9test8_B2a -// CHECK-LP64-NEXT: .quad __ZN9test8_B2a10ftest8_B2aEv -// CHECK-LP64-NEXT: .space 8 -// CHECK-LP64-NEXT: .quad 18446744073709551592 -// CHECK-LP64-NEXT: .quad __ZTI9test8_B2a -// CHECK-LP64-NEXT: .quad __ZN10test8_B2aa11ftest8_B2aaEv -// CHECK-LP64-NEXT: .space 8 -// CHECK-LP64-NEXT: .quad 18446744073709551576 -// CHECK-LP64-NEXT: .quad __ZTI9test8_B2a -// CHECK-LP64-NEXT: .quad __ZN10test8_B2ab11ftest8_B2abEv - -// CHECK-LP64:__ZTT7test8_D: -// CHECK-LP64-NEXT: .quad (__ZTV7test8_D) + 32 -// CHECK-LP64-NEXT: .quad (__ZTC7test8_D8_8test8_B2) + 32 -// CHECK-LP64-NEXT: .quad (__ZTC7test8_D8_9test8_B2a) + 32 -// CHECK-LP64-NEXT .quad (__ZTC7test8_D8_9test8_B2a) + 64 -// CHECK-LP64-NEXT .quad (__ZTC7test8_D8_9test8_B2a) + 96 -// CHECK-LP64-NEXT .quad (__ZTC7test8_D8_8test8_B2) + 72 -// CHECK-LP64-NEXT .quad (__ZTC7test8_D8_8test8_B2) + 104 -// CHECK-LP64-NEXT .quad (__ZTV7test8_D) + 72 -// CHECK-LP64: .quad (__ZTV7test8_D) + 160 -// CHECK-LP64: .quad (__ZTV7test8_D) + 192 +// CHECK-LPLL64:@_ZTV7test8_D = weak_odr constant [25 x i8*] [i8* inttoptr (i64 48 to i8*), i8* inttoptr (i64 32 to i8*), i8* null, i8* bitcast (%2* @_ZTI7test8_D to i8*), i8* bitcast (void (%class.test14*)* @_ZN8test8_B19ftest8_B1Ev to i8*), i8* inttoptr (i64 40 to i8*), i8* inttoptr (i64 24 to i8*), i8* inttoptr (i64 -8 to i8*), i8* bitcast (%2* @_ZTI7test8_D to i8*), i8* bitcast (void (%struct.test10_B2a*)* @_ZN9test8_B2a10ftest8_B2aEv to i8*), i8* bitcast (void (%struct.test15_D*)* @_ZN8test8_B29ftest8_B2Ev to i8*), i8* inttoptr (i64 -16 to i8*), i8* bitcast (%2* @_ZTI7test8_D to i8*), i8* bitcast (void (%class.test14*)* @_ZN9test8_B2b10ftest8_B2bEv to i8*), i8* inttoptr (i64 -24 to i8*), i8* bitcast (%2* @_ZTI7test8_D to i8*), i8* bitcast (void (%class.test14*)* @_ZN8test8_B39ftest8_B3Ev to i8*), i8* null, i8* inttoptr (i64 -32 to i8*), i8* bitcast (%2* @_ZTI7test8_D to i8*), i8* bitcast (void (%struct.B*)* @_ZN10test8_B2aa11ftest8_B2aaEv to i8*), i8* null, i8* inttoptr (i64 -48 to i8*), i8* bitcast (%2* @_ZTI7test8_D to i8*), i8* bitcast (void (%struct.B*)* @_ZN10test8_B2ab11ftest8_B2abEv to i8*)] + +// CHECK-LPLL64:@_ZTC7test8_D8_8test8_B2 = internal constant [14 x i8*] [i8* inttoptr (i64 40 to i8*), i8* inttoptr (i64 24 to i8*), i8* null, i8* bitcast (%1* @_ZTI8test8_B2 to i8*), i8* bitcast (void (%struct.test10_B2a*)* @_ZN9test8_B2a10ftest8_B2aEv to i8*), i8* bitcast (void (%struct.test15_D*)* @_ZN8test8_B29ftest8_B2Ev to i8*), i8* null, i8* inttoptr (i64 -24 to i8*), i8* bitcast (%1* @_ZTI8test8_B2 to i8*), i8* bitcast (void (%struct.B*)* @_ZN10test8_B2aa11ftest8_B2aaEv to i8*), i8* null, i8* inttoptr (i64 -40 to i8*), i8* bitcast (%1* @_ZTI8test8_B2 to i8*), i8* bitcast (void (%struct.B*)* @_ZN10test8_B2ab11ftest8_B2abEv to i8*)] ; <[14 x i8*]*> [#uses=3] + +// CHECK-LPLL64:@_ZTC7test8_D8_9test8_B2a = internal constant [13 x i8*] [i8* inttoptr (i64 40 to i8*), i8* inttoptr (i64 24 to i8*), i8* null, i8* bitcast (%1* @_ZTI9test8_B2a to i8*), i8* bitcast (void (%struct.test10_B2a*)* @_ZN9test8_B2a10ftest8_B2aEv to i8*), i8* null, i8* inttoptr (i64 -24 to i8*), i8* bitcast (%1* @_ZTI9test8_B2a to i8*), i8* bitcast (void (%struct.B*)* @_ZN10test8_B2aa11ftest8_B2aaEv to i8*), i8* null, i8* inttoptr (i64 -40 to i8*), i8* bitcast (%1* @_ZTI9test8_B2a to i8*), i8* bitcast (void (%struct.B*)* @_ZN10test8_B2ab11ftest8_B2abEv to i8*)] ; <[13 x i8*]*> [#uses=3] + +// CHECK-LPLL64:@_ZTT7test8_D = weak_odr constant [10 x i8*] [i8* bitcast (i8** getelementptr inbounds ([25 x i8*]* @_ZTV7test8_D, i64 0, i64 4) to i8*), i8* bitcast (i8** getelementptr inbounds ([14 x i8*]* @_ZTC7test8_D8_8test8_B2, i64 0, i64 4) to i8*), i8* bitcast (i8** getelementptr inbounds ([13 x i8*]* @_ZTC7test8_D8_9test8_B2a, i64 0, i64 4) to i8*), i8* bitcast (i8** getelementptr inbounds ([13 x i8*]* @_ZTC7test8_D8_9test8_B2a, i64 0, i64 8) to i8*), i8* bitcast (i8** getelementptr inbounds ([13 x i8*]* @_ZTC7test8_D8_9test8_B2a, i64 0, i64 12) to i8*), i8* bitcast (i8** getelementptr inbounds ([14 x i8*]* @_ZTC7test8_D8_8test8_B2, i64 0, i64 9) to i8*), i8* bitcast (i8** getelementptr inbounds ([14 x i8*]* @_ZTC7test8_D8_8test8_B2, i64 0, i64 13) to i8*), i8* bitcast (i8** getelementptr inbounds ([25 x i8*]* @_ZTV7test8_D, i64 0, i64 9) to i8*), i8* bitcast (i8** getelementptr inbounds ([25 x i8*]* @_ZTV7test8_D, i64 0, i64 20) to i8*), i8* bitcast (i8** getelementptr inbounds ([25 x i8*]* @_ZTV7test8_D, i64 0, i64 24) to i8*)] struct test9_B3 { virtual void funcB3(); int i; }; @@ -404,77 +201,7 @@ struct test9_D : virtual test9_B1, virtual test9_B21, virtual test9_B31 { virtual void funcD() { } }; -// CHECK-LP64: __ZTV7test9_D: -// CHECK-LP64-NEXT: .quad 168 -// CHECK-LP64-NEXT: .quad 152 -// CHECK-LP64-NEXT: .quad 136 -// CHECK-LP64-NEXT: .quad 120 -// CHECK-LP64-NEXT: .quad 104 -// CHECK-LP64-NEXT: .quad 88 -// CHECK-LP64-NEXT: .quad 72 -// CHECK-LP64-NEXT: .quad 56 -// CHECK-LP64-NEXT: .quad 40 -// CHECK-LP64-NEXT: .quad 24 -// CHECK-LP64-NEXT: .quad 8 -// CHECK-LP64-NEXT: .space 8 -// CHECK-LP64-NEXT: .quad __ZTI7test9_D -// CHECK-LP64-NEXT: .quad __ZN7test9_D5funcDEv -// CHECK-LP64-NEXT: .space 8 -// CHECK-LP64-NEXT: .quad 32 -// CHECK-LP64-NEXT: .quad 16 -// CHECK-LP64-NEXT: .quad 18446744073709551608 -// CHECK-LP64-NEXT: .quad __ZTI7test9_D -// CHECK-LP64-NEXT: .quad __ZN8test9_B16funcB1Ev -// CHECK-LP64-NEXT: .space 8 -// CHECK-LP64-NEXT: .quad 16 -// CHECK-LP64-NEXT: .quad 18446744073709551592 -// CHECK-LP64-NEXT: .quad __ZTI7test9_D -// CHECK-LP64-NEXT: .quad __ZN8test9_B26funcB2Ev -// CHECK-LP64-NEXT: .space 8 -// CHECK-LP64-NEXT: .quad 18446744073709551576 -// CHECK-LP64-NEXT: .quad __ZTI7test9_D -// CHECK-LP64-NEXT: .quad __ZN8test9_B36funcB3Ev -// CHECK-LP64-NEXT: .space 8 -// CHECK-LP64-NEXT: .quad 32 -// CHECK-LP64-NEXT: .quad 16 -// CHECK-LP64-NEXT: .quad 18446744073709551560 -// CHECK-LP64-NEXT: .quad __ZTI7test9_D -// CHECK-LP64-NEXT: .quad __ZN9test9_B217funcB21Ev -// CHECK-LP64-NEXT: .space 8 -// CHECK-LP64-NEXT: .quad 16 -// CHECK-LP64-NEXT: .quad 18446744073709551544 -// CHECK-LP64-NEXT: .quad __ZTI7test9_D -// CHECK-LP64-NEXT: .quad __ZN9test9_B227funcB22Ev -// CHECK-LP64-NEXT: .space 8 -// CHECK-LP64-NEXT: .quad 18446744073709551528 -// CHECK-LP64-NEXT: .quad __ZTI7test9_D -// CHECK-LP64-NEXT: .quad __ZN9test9_B237funcB23Ev -// CHECK-LP64-NEXT: .space 8 -// CHECK-LP64-NEXT: .quad 64 -// CHECK-LP64-NEXT: .quad 48 -// CHECK-LP64-NEXT: .quad 32 -// CHECK-LP64-NEXT: .quad 16 -// CHECK-LP64-NEXT: .quad 18446744073709551512 -// CHECK-LP64-NEXT: .quad __ZTI7test9_D -// CHECK-LP64-NEXT: .quad __ZN9test9_B317funcB31Ev -// CHECK-LP64-NEXT: .space 8 -// CHECK-LP64-NEXT: .quad 32 -// CHECK-LP64-NEXT: .quad 16 -// CHECK-LP64-NEXT: .quad 18446744073709551496 -// CHECK-LP64-NEXT: .quad __ZTI7test9_D -// CHECK-LP64-NEXT: .quad __ZN9test9_B327funcB32Ev -// CHECK-LP64-NEXT: .space 8 -// CHECK-LP64-NEXT: .quad 18446744073709551480 -// CHECK-LP64-NEXT: .quad __ZTI7test9_D -// CHECK-LP64-NEXT: .quad __ZN9test9_B337funcB33Ev -// CHECK-LP64-NEXT: .space 8 -// CHECK-LP64-NEXT: .quad 18446744073709551464 -// CHECK-LP64-NEXT: .quad __ZTI7test9_D -// CHECK-LP64-NEXT: .quad __ZN10test9_B2328funcB232Ev -// CHECK-LP64-NEXT: .space 8 -// CHECK-LP64-NEXT: .quad 18446744073709551448 -// CHECK-LP64-NEXT: .quad __ZTI7test9_D -// CHECK-LP64-NEXT: .quad __ZN10test9_B2318funcB231Ev +// CHECK-LPLL64:@_ZTV7test9_D = weak_odr constant [70 x i8*] [i8* inttoptr (i64 168 to i8*), i8* inttoptr (i64 152 to i8*), i8* inttoptr (i64 136 to i8*), i8* inttoptr (i64 120 to i8*), i8* inttoptr (i64 104 to i8*), i8* inttoptr (i64 88 to i8*), i8* inttoptr (i64 72 to i8*), i8* inttoptr (i64 56 to i8*), i8* inttoptr (i64 40 to i8*), i8* inttoptr (i64 24 to i8*), i8* inttoptr (i64 8 to i8*), i8* null, i8* bitcast (%2* @_ZTI7test9_D to i8*), i8* bitcast (void (%struct.test9_D*)* @_ZN7test9_D5funcDEv to i8*), i8* null, i8* inttoptr (i64 32 to i8*), i8* inttoptr (i64 16 to i8*), i8* inttoptr (i64 -8 to i8*), i8* bitcast (%2* @_ZTI7test9_D to i8*), i8* bitcast (void (%struct.test9_B1*)* @_ZN8test9_B16funcB1Ev to i8*), i8* null, i8* inttoptr (i64 16 to i8*), i8* inttoptr (i64 -24 to i8*), i8* bitcast (%2* @_ZTI7test9_D to i8*), i8* bitcast (void (%struct.test13_B2*)* @_ZN8test9_B26funcB2Ev to i8*), i8* null, i8* inttoptr (i64 -40 to i8*), i8* bitcast (%2* @_ZTI7test9_D to i8*), i8* bitcast (void (%struct.B*)* @_ZN8test9_B36funcB3Ev to i8*), i8* null, i8* inttoptr (i64 32 to i8*), i8* inttoptr (i64 16 to i8*), i8* inttoptr (i64 -56 to i8*), i8* bitcast (%2* @_ZTI7test9_D to i8*), i8* bitcast (void (%struct.test9_B1*)* @_ZN9test9_B217funcB21Ev to i8*), i8* null, i8* inttoptr (i64 16 to i8*), i8* inttoptr (i64 -72 to i8*), i8* bitcast (%2* @_ZTI7test9_D to i8*), i8* bitcast (void (%struct.test13_B2*)* @_ZN9test9_B227funcB22Ev to i8*), i8* null, i8* inttoptr (i64 -88 to i8*), i8* bitcast (%2* @_ZTI7test9_D to i8*), i8* bitcast (void (%struct.B*)* @_ZN9test9_B237funcB23Ev to i8*), i8* null, i8* inttoptr (i64 64 to i8*), i8* inttoptr (i64 48 to i8*), i8* inttoptr (i64 32 to i8*), i8* inttoptr (i64 16 to i8*), i8* inttoptr (i64 -104 to i8*), i8* bitcast (%2* @_ZTI7test9_D to i8*), i8* bitcast (void (%struct.test9_B31*)* @_ZN9test9_B317funcB31Ev to i8*), i8* null, i8* inttoptr (i64 32 to i8*), i8* inttoptr (i64 16 to i8*), i8* inttoptr (i64 -120 to i8*), i8* bitcast (%2* @_ZTI7test9_D to i8*), i8* bitcast (void (%struct.test9_B1*)* @_ZN9test9_B327funcB32Ev to i8*), i8* null, i8* inttoptr (i64 -136 to i8*), i8* bitcast (%2* @_ZTI7test9_D to i8*), i8* bitcast (void (%struct.B*)* @_ZN9test9_B337funcB33Ev to i8*), i8* null, i8* inttoptr (i64 -152 to i8*), i8* bitcast (%2* @_ZTI7test9_D to i8*), i8* bitcast (void (%struct.B*)* @_ZN10test9_B2328funcB232Ev to i8*), i8* null, i8* inttoptr (i64 -168 to i8*), i8* bitcast (%2* @_ZTI7test9_D to i8*), i8* bitcast (void (%struct.B*)* @_ZN10test9_B2318funcB231Ev to i8*)] ; <[70 x i8*]*> [#uses=12] struct test10_O { int i; }; @@ -503,26 +230,7 @@ class test10_D : test10_B1, test10_B2 { void ftest10_B2aa() { } }; -// CHECK-LP64:__ZTV8test10_D: -// CHECK-LP64-NEXT: .quad 40 -// CHECK-LP64-NEXT: .quad 24 -// CHECK-LP64-NEXT: .quad 16 -// CHECK-LP64-NEXT: .space 8 -// CHECK-LP64-NEXT: .quad __ZTI8test10_D -// CHECK-LP64-NEXT: .quad __ZN9test10_B110ftest10_B1Ev -// CHECK-LP64-NEXT: .quad 32 -// CHECK-LP64-NEXT: .quad 8 -// CHECK-LP64-NEXT: .quad 16 -// CHECK-LP64-NEXT: .quad 18446744073709551608 -// CHECK-LP64-NEXT: .quad __ZTI8test10_D -// CHECK-LP64-NEXT: .quad __ZN10test10_B2a11ftest10_B2aEv -// CHECK-LP64-NEXT: .quad __ZN9test10_B210ftest10_B2Ev -// CHECK-LP64-NEXT: .quad 18446744073709551608 -// CHECK-LP64-NEXT: .quad 18446744073709551592 -// CHECK-LP64-NEXT: .quad __ZTI8test10_D -// CHECK-LP64-NEXT: .quad 18446744073709551592 -// CHECK-LP64-NEXT: .quad 18446744073709551576 -// CHECK-LP64-NEXT: .quad __ZTI8test10_D +// CHECK-LPLL64:@_ZTV8test10_D = weak_odr constant [19 x i8*] [i8* inttoptr (i64 40 to i8*), i8* inttoptr (i64 24 to i8*), i8* inttoptr (i64 16 to i8*), i8* null, i8* bitcast (%1* @_ZTI8test10_D to i8*), i8* bitcast (void (%struct.test10_B1*)* @_ZN9test10_B110ftest10_B1Ev to i8*), i8* inttoptr (i64 32 to i8*), i8* inttoptr (i64 8 to i8*), i8* inttoptr (i64 16 to i8*), i8* inttoptr (i64 -8 to i8*), i8* bitcast (%1* @_ZTI8test10_D to i8*), i8* bitcast (void (%struct.test10_B2a*)* @_ZN10test10_B2a11ftest10_B2aEv to i8*), i8* bitcast (void (%struct.test10_B2*)* @_ZN9test10_B210ftest10_B2Ev to i8*), i8* inttoptr (i64 -8 to i8*), i8* inttoptr (i64 -24 to i8*), i8* bitcast (%1* @_ZTI8test10_D to i8*), i8* inttoptr (i64 -24 to i8*), i8* inttoptr (i64 -40 to i8*), i8* bitcast (%1* @_ZTI8test10_D to i8*)] ; <[19 x i8*]*> [#uses=4] struct test11_B { @@ -537,14 +245,8 @@ struct test11_D : test11_B { virtual void D2() { } }; -// CHECK-LP64:__ZTV8test11_D: -// CHECK-LP64-NEXT: .space 8 -// CHECK-LP64-NEXT: .quad __ZTI8test11_D -// CHECK-LP64-NEXT: .quad __ZN8test11_B2B1Ev -// CHECK-LP64-NEXT: .quad __ZN8test11_D1DEv -// CHECK-LP64-NEXT: .quad __ZN8test11_B2B2Ev -// CHECK-LP64-NEXT: .quad __ZN8test11_D2D1Ev -// CHECK-LP64-NEXT: .quad __ZN8test11_D2D2Ev +// CHECK-LPLL64:@_ZTV8test11_D = weak_odr constant [7 x i8*] [i8* null, i8* bitcast (%4* @_ZTI8test11_D to i8*), i8* bitcast (void (%class.test14*)* @_ZN8test11_B2B1Ev to i8*), i8* bitcast (void (%class.test17_B2*)* @_ZN8test11_D1DEv to i8*), i8* bitcast (void (%class.test14*)* @_ZN8test11_B2B2Ev to i8*), i8* bitcast (void (%class.test17_B2*)* @_ZN8test11_D2D1Ev to i8*), i8* bitcast (void (%class.test17_B2*)* @_ZN8test11_D2D2Ev to i8*)] + struct test13_B { virtual void B1() { } @@ -583,46 +285,7 @@ struct test13_D : test13_NV1, virtual test13_B2 { virtual void fooNV1() { } }; -// CHECK-LP64:__ZTV8test13_D: -// CHECK-LP64-NEXT: .quad 24 -// CHECK-LP64-NEXT: .quad 8 -// CHECK-LP64-NEXT: .space 8 -// CHECK-LP64-NEXT: .quad __ZTI8test13_D -// CHECK-LP64-NEXT: .quad __ZN8test13_D6fooNV1Ev -// CHECK-LP64-NEXT: .quad __ZN8test13_D1DEv -// CHECK-LP64-NEXT: .quad __ZN8test13_D2D1Ev -// CHECK-LP64-NEXT: .quad __ZN8test13_D2DbEv -// CHECK-LP64-NEXT: .quad __ZN8test13_D2DdEv -// CHECK-LP64-NEXT: .quad __ZN8test13_D2D2Ev -// CHECK-LP64-NEXT: .space 8 -// CHECK-LP64-NEXT: .quad 18446744073709551608 -// CHECK-LP64-NEXT: .space 8 -// CHECK-LP64-NEXT: .quad 18446744073709551608 -// CHECK-LP64-NEXT: .space 8 -// CHECK-LP64-NEXT: .space 8 -// CHECK-LP64-NEXT: .quad 16 -// CHECK-LP64-NEXT: .quad 18446744073709551608 -// CHECK-LP64-NEXT: .quad __ZTI8test13_D -// CHECK-LP64-NEXT: .quad __ZN9test13_B23B2aEv -// CHECK-LP64-NEXT: .quad __ZN9test13_B22B2Ev -// CHECK-LP64-NEXT: .quad __ZTv0_n48_N8test13_D1DEv -// CHECK-LP64-NEXT: .quad __ZN9test13_B22DaEv -// CHECK-LP64-NEXT: .quad __ZTv0_n64_N8test13_D2DdEv -// CHECK-LP64-NEXT: .quad __ZN9test13_B23B2bEv -// CHECK-LP64-NEXT: .quad 18446744073709551600 -// CHECK-LP64-NEXT: .space 8 -// CHECK-LP64-NEXT: .quad 18446744073709551592 -// CHECK-LP64-NEXT: .quad 18446744073709551600 -// CHECK-LP64-NEXT: .quad 18446744073709551592 -// CHECK-LP64-NEXT: .space 8 -// CHECK-LP64-NEXT: .quad 18446744073709551592 -// CHECK-LP64-NEXT: .quad __ZTI8test13_D -// CHECK-LP64-NEXT: .quad __ZN8test13_B2B1Ev -// CHECK-LP64-NEXT: .quad __ZTv0_n32_N8test13_D1DEv -// CHECK-LP64-NEXT: .quad __ZTv0_n40_N9test13_B22DaEv -// CHECK-LP64-NEXT: .quad __ZTv0_n48_N8test13_D2DbEv -// CHECK-LP64-NEXT: .quad __ZN8test13_B2DcEv -// CHECK-LP64-NEXT: .quad __ZTv0_n64_N9test13_B22B2Ev +// CHECK-LPLL64:@_ZTV8test13_D = weak_odr constant [39 x i8*] [i8* inttoptr (i64 24 to i8*), i8* inttoptr (i64 8 to i8*), i8* null, i8* bitcast (%1* @_ZTI8test13_D to i8*), i8* bitcast (void (%struct.test10_B2*)* @_ZN8test13_D6fooNV1Ev to i8*), i8* bitcast (void (%struct.test10_B2*)* @_ZN8test13_D1DEv to i8*), i8* bitcast (void (%struct.test10_B2*)* @_ZN8test13_D2D1Ev to i8*), i8* bitcast (void (%struct.test10_B2*)* @_ZN8test13_D2DbEv to i8*), i8* bitcast (void (%struct.test10_B2*)* @_ZN8test13_D2DdEv to i8*), i8* bitcast (void (%struct.test10_B2*)* @_ZN8test13_D2D2Ev to i8*), i8* null, i8* inttoptr (i64 -8 to i8*), i8* null, i8* inttoptr (i64 -8 to i8*), i8* null, i8* null, i8* inttoptr (i64 16 to i8*), i8* inttoptr (i64 -8 to i8*), i8* bitcast (%1* @_ZTI8test13_D to i8*), i8* bitcast (void (%struct.test13_B2*)* @_ZN9test13_B23B2aEv to i8*), i8* bitcast (void (%struct.test13_B2*)* @_ZN9test13_B22B2Ev to i8*), i8* bitcast (void (%struct.test10_B2*)* @_ZTv0_n48_N8test13_D1DEv to i8*), i8* bitcast (void (%struct.test13_B2*)* @_ZN9test13_B22DaEv to i8*), i8* bitcast (void (%struct.test10_B2*)* @_ZTv0_n64_N8test13_D2DdEv to i8*), i8* bitcast (void (%struct.test13_B2*)* @_ZN9test13_B23B2bEv to i8*), i8* inttoptr (i64 -16 to i8*), i8* null, i8* inttoptr (i64 -24 to i8*), i8* inttoptr (i64 -16 to i8*), i8* inttoptr (i64 -24 to i8*), i8* null, i8* inttoptr (i64 -24 to i8*), i8* bitcast (%1* @_ZTI8test13_D to i8*), i8* bitcast (void (%struct.B*)* @_ZN8test13_B2B1Ev to i8*), i8* bitcast (void (%struct.test10_B2*)* @_ZTv0_n32_N8test13_D1DEv to i8*), i8* bitcast (void (%struct.test13_B2*)* @_ZTv0_n40_N9test13_B22DaEv to i8*), i8* bitcast (void (%struct.test10_B2*)* @_ZTv0_n48_N8test13_D2DbEv to i8*), i8* bitcast (void (%struct.B*)* @_ZN8test13_B2DcEv to i8*), i8* bitcast (void (%struct.test13_B2*)* @_ZTv0_n64_N9test13_B22B2Ev to i8*)] class test14 { @@ -662,30 +325,7 @@ struct test15_D : test15_NV1, virtual test15_B2 { virtual test15_D *foo1() { return 0; } }; -// CHECK-LP64:__ZTV8test15_D: -// CHECK-LP64-NEXT: .quad 32 -// CHECK-LP64-NEXT: .quad 16 -// CHECK-LP64-NEXT: .space 8 -// CHECK-LP64-NEXT: .quad __ZTI8test15_D -// CHECK-LP64-NEXT: .quad __ZN10test15_NV16fooNV1Ev -// CHECK-LP64-NEXT: .quad __ZN8test15_D4foo1Ev -// CHECK-LP64-NEXT: .space 8 -// CHECK-LP64-NEXT: .quad 18446744073709551600 -// CHECK-LP64-NEXT: .space 8 -// CHECK-LP64-NEXT: .quad 16 -// CHECK-LP64-NEXT: .quad 18446744073709551600 -// CHECK-LP64-NEXT: .quad __ZTI8test15_D -// CHECK-LP64-NEXT: .quad __ZN10test15_NV16fooNV1Ev -// CHECK-LP64-NEXT: .quad __ZTcv0_n40_v0_n24_N8test15_D4foo1Ev -// CHECK-LP64-NEXT: .quad __ZN9test15_B24foo2Ev -// CHECK-LP64-NEXT: .space 8 -// CHECK-LP64-NEXT: .quad 18446744073709551600 -// CHECK-LP64-NEXT: .quad 18446744073709551584 -// CHECK-LP64-NEXT: .quad 18446744073709551584 -// CHECK-LP64-NEXT: .quad __ZTI8test15_D -// CHECK-LP64-NEXT: .quad __ZTcv0_n24_v0_n32_N8test15_D4foo1Ev -// CHECK-LP64-NEXT: .quad __ZTcv0_n32_v0_n24_N9test15_B24foo2Ev -// CHECK-LP64-NEXT: .quad __ZN8test15_B4foo3Ev +// CHECK-LPLL64:@_ZTV8test15_D = weak_odr constant [23 x i8*] [i8* inttoptr (i64 32 to i8*), i8* inttoptr (i64 16 to i8*), i8* null, i8* bitcast (%1* @_ZTI8test15_D to i8*), i8* bitcast (void (%struct.B*)* @_ZN10test15_NV16fooNV1Ev to i8*), i8* bitcast (%struct.test15_D* (%struct.test15_D*)* @_ZN8test15_D4foo1Ev to i8*), i8* null, i8* inttoptr (i64 -16 to i8*), i8* null, i8* inttoptr (i64 16 to i8*), i8* inttoptr (i64 -16 to i8*), i8* bitcast (%1* @_ZTI8test15_D to i8*), i8* bitcast (void (%struct.B*)* @_ZN10test15_NV16fooNV1Ev to i8*), i8* bitcast (%struct.test15_D* (%struct.test15_D*)* @_ZTcv0_n40_v0_n24_N8test15_D4foo1Ev to i8*), i8* bitcast (%struct.test15_B2* (%struct.test15_B2*)* @_ZN9test15_B24foo2Ev to i8*), i8* null, i8* inttoptr (i64 -16 to i8*), i8* inttoptr (i64 -32 to i8*), i8* inttoptr (i64 -32 to i8*), i8* bitcast (%1* @_ZTI8test15_D to i8*), i8* bitcast (%struct.test15_D* (%struct.test15_D*)* @_ZTcv0_n24_v0_n32_N8test15_D4foo1Ev to i8*), i8* bitcast (%struct.test15_B2* (%struct.test15_B2*)* @_ZTcv0_n32_v0_n24_N9test15_B24foo2Ev to i8*), i8* bitcast (%struct.B* (%struct.B*)* @_ZN8test15_B4foo3Ev to i8*)] struct test16_NV1 { @@ -721,22 +361,23 @@ struct test16_D : test16_NV1, virtual test16_B2 { virtual test16_D *foo1() { return 0; } }; +// FIXME: // CHECK-LP64: __ZTV8test16_D: // CHECK-LP64-NEXT: .quad 32 // CHECK-LP64-NEXT: .quad 16 -// CHECK-LP64-NEXT: .space 8 +// CHECK-LP64-NEXT: .quad 0 // CHECK-LP64-NEXT: .quad __ZTI8test16_D // CHECK-LP64-NEXT: .quad __ZN10test16_NV16fooNV1Ev // CHECK-LP64-NEXT: .quad __ZN10test16_NV17foo_NV1Ev // CHECK-LP64-NEXT: .quad __ZN8test16_D3barEv // CHECK-LP64-NEXT: .quad __ZN8test16_D4foo1Ev -// CHECK-LP64-NEXT: .space 8 -// CHECK-LP64-NEXT: .space 8 -// CHECK-LP64-NEXT: .quad 18446744073709551600 -// CHECK-LP64-NEXT: .space 8 -// CHECK-LP64-NEXT: .space 8 +// CHECK-LP64-NEXT: .quad 0 +// CHECK-LP64-NEXT: .quad 0 +// CHECK-LP64-NEXT: .quad -16 +// CHECK-LP64-NEXT: .quad 0 +// CHECK-LP64-NEXT: .quad 0 // CHECK-LP64-NEXT: .quad 16 -// CHECK-LP64-NEXT: .quad 18446744073709551600 +// CHECK-LP64-NEXT: .quad -16 // CHECK-LP64-NEXT: .quad __ZTI8test16_D // CHECK-LP64-NEXT: .quad __ZN10test16_NV16fooNV1Ev // CHECK-LP64-NEXT: .quad __ZN10test16_NV17foo_NV1Ev @@ -745,13 +386,13 @@ struct test16_D : test16_NV1, virtual test16_B2 { // CHECK-LP64-NEXT: .quad __ZN9test16_B26foo_B2Ev // CHECK-LP64-NEXT .quad 16 // CHECK-LP64-NEXT .quad 16 -// CHECK-LP64-NEXT: .space 8 -// CHECK-LP64-NEXT: .space 8 -// CHECK-LP64: .quad 18446744073709551600 -// CHECK-LP64-NEXT: .quad 18446744073709551584 -// CHECK-LP64-NEXT: .space 8 -// CHECK-LP64-NEXT: .space 8 -// CHECK-LP64-NEXT: .quad 18446744073709551584 +// CHECK-LP64-NEXT: .quad 0 +// CHECK-LP64-NEXT: .quad 0 +// CHECK-LP64: .quad -16 +// CHECK-LP64-NEXT: .quad -32 +// CHECK-LP64-NEXT: .quad 0 +// CHECK-LP64-NEXT: .quad 0 +// CHECK-LP64-NEXT: .quad -32 // CHECK-LP64-NEXT: .quad __ZTI8test16_D // CHECK-LP64-NEXT: .quad __ZN10test16_NV16fooNV1Ev // CHECK-LP64-NEXT: .quad __ZN10test16_NV17foo_NV1Ev @@ -759,64 +400,13 @@ struct test16_D : test16_NV1, virtual test16_B2 { // CHECK-LP64-NEXT: .quad __ZTcv0_n48_v0_n24_N9test16_B24foo2Ev // CHECK-LP64-NEXT: .quad __ZN8test16_B4foo3Ev // CHECK-LP64-NEXT: .quad __ZN8test16_B5foo_BEv -// CHECK-LP64-NEXT: .quad 18446744073709551568 +// CHECK-LP64-NEXT: .quad -48 // CHECK-LP64-NEXT: .quad __ZTI8test16_D // CHECK-LP64-NEXT .quad __ZTcvn16_n40_v16_n32_N8test16_D4foo1Ev // CHECK-LP64: .quad __ZN10test16_NV27foo_NV2Ev // CHECK-LP64-NEXT: .quad __ZN10test16_NV28foo_NV2bEv -// FIXME: This is the wrong thunk, but until these issues are fixed, better -// than nothing. -// CHECK-LPLL64:define weak %class.test8_D* @_ZTcvn16_n72_v16_n32_N8test16_D4foo1Ev(%class.test8_D*) -// CHECK-LPLL64: %{{retval|2}} = alloca %class.test8_D* -// CHECK-LPLL64: %.addr = alloca %class.test8_D* -// CHECK-LPLL64: store %class.test8_D* %0, %class.test8_D** %.addr -// CHECK-LPLL64: %{{this|3}} = load %class.test8_D** %.addr -// CHECK-LPLL64: %{{1|4}} = bitcast %class.test8_D* %{{this|3}} to i8* -// CHECK-LPLL64: %{{2|5}} = getelementptr inbounds i8* %{{1|4}}, i64 -16 -// CHECK-LPLL64: %{{3|6}} = bitcast i8* %{{2|5}} to %class.test8_D* -// CHECK-LPLL64: %{{4|7}} = bitcast %class.test8_D* %{{3|6}} to i8* -// CHECK-LPLL64: %{{5|8}} = bitcast %class.test8_D* %3 to i64** -// CHECK-LPLL64: %{{vtable|9}} = load i64** %{{5|8}} -// CHECK-LPLL64: %{{6|10}} = getelementptr inbounds i64* %{{vtable|9}}, i64 -9 -// CHECK-LPLL64: %{{7|11}} = load i64* %{{6|10}} -// CHECK-LPLL64: %{{8|12}} = getelementptr i8* %{{4|7}}, i64 %{{7|11}} -// CHECK-LPLL64: %{{9|13}} = bitcast i8* %{{8|12}} to %class.test8_D* -// CHECK-LPLL64: %{{call|14}} = call %class.test8_D* @_ZTch0_v16_n32_N8test16_D4foo1Ev(%class.test8_D* %{{9|13}}) -// CHECK-LPLL64: store %class.test8_D* %{{call|14}}, %class.test8_D** %{{retval|2}} -// CHECK-LPLL64: %{{10|15}} = load %class.test8_D** %{{retval|2}} -// CHECK-LPLL64: ret %class.test8_D* %{{10|15}} -// CHECK-LPLL64:} - -// CHECK-LPLL64:define weak %class.test8_D* @_ZTch0_v16_n32_N8test16_D4foo1Ev(%{{class.test8_D|.*}}*) -// CHECK-LPLL64: %{{retval|2}} = alloca %class.test8_D* -// CHECK-LPLL64: %.addr = alloca %class.test8_D* -// CHECK-LPLL64: store %class.test8_D* %0, %class.test8_D** %.addr -// CHECK-LPLL64: %{{this|3}} = load %class.test8_D** %.addr -// CHECK-LPLL64: %{{call|4}} = call %class.test8_D* @_ZN8test16_D4foo1Ev(%class.test8_D* %{{this|3}}) -// CHECK-LPLL64: %{{1|5}} = icmp ne %class.test8_D* %{{call|4}}, null -// CHECK-LPLL64: br i1 %{{1|5}}, label %{{2|6}}, label %{{12|17}} -// CHECK-LPLL64:; <label>:{{2|6}} -// CHECK-LPLL64: %{{3|7}} = bitcast %class.test8_D* %{{call|4}} to i8* -// CHECK-LPLL64: %{{4|8}} = getelementptr inbounds i8* %{{3|7}}, i64 16 -// CHECK-LPLL64: %{{5|9}} = bitcast i8* %4 to %class.test8_D* -// CHECK-LPLL64: %{{6|10}} = bitcast %class.test8_D* %{{5|9}} to i8* -// CHECK-LPLL64: %{{7|11}} = bitcast %class.test8_D* %{{5|9}} to i64** -// CHECK-LPLL64: %{{vtable|12}} = load i64** %{{7|11}} -// CHECK-LPLL64: %{{8|13}} = getelementptr inbounds i64* %vtable, i64 -4 -// CHECK-LPLL64: %{{9|14}} = load i64* %{{8|13}} -// CHECK-LPLL64: %{{10|15}} = getelementptr i8* %{{6|10}}, i64 %{{9|14}} -// CHECK-LPLL64: %{{11|16}} = bitcast i8* %{{10|15}} to %class.test8_D* -// CHECK-LPLL64: br label %{{13|18}} -// CHECK-LPLL64:; <label>:{{12|17}} -// CHECK-LPLL64: br label %{{13|18}} -// CHECK-LPLL64:; <label>:{{13|18}} -// CHECK-LPLL64: %{{14|19}} = phi %class.test8_D* [ %{{11|16}}, %{{2|6}} ], [ %{{call|4}}, %{{12|17}} ] -// CHECK-LPLL64: store %class.test8_D* %{{14|19}}, %class.test8_D** %{{retval|2}} -// CHECK-LPLL64: %{{15|20}} = load %class.test8_D** %{{retval|2}} -// CHECK-LPLL64: ret %class.test8_D* %{{15|20}} -// CHECK-LPLL64:} class test17_B1 { @@ -834,23 +424,11 @@ class test17_D : public test17_B2 { }; -// CHECK-LP64:__ZTV8test17_D: -// CHECK-LP64-NEXT: .space 8 -// CHECK-LP64-NEXT: .quad __ZTI8test17_D -// CHECK-LP64-NEXT: .quad __ZN9test17_B23fooEv -// CHECK-LP64-NEXT: .quad __ZN8test17_D3barEv +// CHECK-LPLL64:@_ZTV8test17_D = weak_odr constant [4 x i8*] [i8* null, i8* bitcast (%4* @_ZTI8test17_D to i8*), i8* bitcast (void (%class.test17_B2*)* @_ZN9test17_B23fooEv to i8*), i8* bitcast (void (%class.test17_B2*)* @_ZN8test17_D3barEv to i8*)] -// CHECK-LP64:__ZTV9test17_B2: -// CHECK-LP64-NEXT: .space 8 -// CHECK-LP64-NEXT: .quad __ZTI9test17_B2 -// CHECK-LP64-NEXT: .quad __ZN9test17_B23fooEv -// CHECK-LP64-NEXT: .quad ___cxa_pure_virtual +// CHECK-LPLL64:@_ZTV9test17_B2 = weak_odr constant [4 x i8*] [i8* null, i8* bitcast (%4* @_ZTI9test17_B2 to i8*), i8* bitcast (void (%class.test17_B2*)* @_ZN9test17_B23fooEv to i8*), i8* bitcast (void ()* @__cxa_pure_virtual to i8*)] -// CHECK-LP64:__ZTV9test17_B1: -// CHECK-LP64-NEXT: .space 8 -// CHECK-LP64-NEXT: .quad __ZTI9test17_B1 -// CHECK-LP64-NEXT: .quad ___cxa_pure_virtual -// CHECK-LP64-NEXT: .quad __ZN9test17_B13barEv +// CHECK-LPLL64:@_ZTV9test17_B1 = weak_odr constant [4 x i8*] [i8* null, i8* bitcast (%0* @_ZTI9test17_B1 to i8*), i8* bitcast (void ()* @__cxa_pure_virtual to i8*), i8* bitcast (void (%class.test14*)* @_ZN9test17_B13barEv to i8*)] struct test18_NV1 { @@ -932,47 +510,19 @@ struct test19_D : virtual test19_B4 { }; -// CHECK-LP64: __ZTV8test19_D: -// CHECK-LP64-NEXT: .space 8 -// CHECK-LP64-NEXT: .space 8 -// CHECK-LP64-NEXT: .space 8 -// CHECK-LP64-NEXT: .space 8 -// CHECK-LP64-NEXT: .space 8 -// CHECK-LP64-NEXT: .space 8 -// CHECK-LP64-NEXT: .space 8 -// CHECK-LP64-NEXT: .space 8 -// CHECK-LP64-NEXT: .space 8 -// CHECK-LP64-NEXT: .space 8 -// CHECK-LP64-NEXT: .space 8 -// CHECK-LP64-NEXT: .space 8 -// CHECK-LP64-NEXT: .space 8 -// CHECK-LP64-NEXT: .space 8 -// CHECK-LP64-NEXT: .space 8 -// CHECK-LP64-NEXT: .space 8 -// CHECK-LP64-NEXT: .space 8 -// CHECK-LP64-NEXT: .quad __ZTI8test19_D -// CHECK-LP64-NEXT: .quad __ZN9test19_B13fB1Ev -// CHECK-LP64-NEXT: .quad __ZN9test19_B26foB1B2Ev -// CHECK-LP64-NEXT: .quad __ZN9test19_B36foB1B3Ev -// CHECK-LP64-NEXT: .quad __ZN9test19_B46foB1B4Ev -// CHECK-LP64-NEXT: .quad __ZN9test19_B23fB2Ev -// CHECK-LP64-NEXT: .quad __ZN9test19_B36foB2B3Ev -// CHECK-LP64-NEXT: .quad __ZN9test19_B46foB2B4Ev -// CHECK-LP64-NEXT: .quad __ZN9test19_B33fB3Ev -// CHECK-LP64-NEXT: .quad __ZN9test19_B46foB3B4Ev -// CHECK-LP64-NEXT: .quad __ZN9test19_B43fB4Ev +// CHECK-LPLL64:@_ZTV8test19_D = weak_odr constant [28 x i8*] [i8* null, i8* null, i8* null, i8* null, i8* null, i8* null, i8* null, i8* null, i8* null, i8* null, i8* null, i8* null, i8* null, i8* null, i8* null, i8* null, i8* null, i8* bitcast (%3* @_ZTI8test19_D to i8*), i8* bitcast (void (%class.test14*)* @_ZN9test19_B13fB1Ev to i8*), i8* bitcast (void (%class.test17_B2*)* @_ZN9test19_B26foB1B2Ev to i8*), i8* bitcast (void (%class.test17_B2*)* @_ZN9test19_B36foB1B3Ev to i8*), i8* bitcast (void (%class.test17_B2*)* @_ZN9test19_B46foB1B4Ev to i8*), i8* bitcast (void (%class.test17_B2*)* @_ZN9test19_B23fB2Ev to i8*), i8* bitcast (void (%class.test17_B2*)* @_ZN9test19_B36foB2B3Ev to i8*), i8* bitcast (void (%class.test17_B2*)* @_ZN9test19_B46foB2B4Ev to i8*), i8* bitcast (void (%class.test17_B2*)* @_ZN9test19_B33fB3Ev to i8*), i8* bitcast (void (%class.test17_B2*)* @_ZN9test19_B46foB3B4Ev to i8*), i8* bitcast (void (%class.test17_B2*)* @_ZN9test19_B43fB4Ev to i8*)] +// FIXME: // CHECK-LP64: __ZTT8test19_D: -// CHECK-LP64-NEXT: .quad (__ZTV8test19_D) + 144 -// CHECK-LP64-NEXT: .quad (__ZTV8test19_D) + 144 -// CHECK-LP64-NEXT .quad (__ZTV8test19_D) + 144 -// CHECK-LP64-NEXT .quad (__ZTC8test19_D0_9test19_B4) + 136 -// CHECK-LP64-NEXT .quad (__ZTC8test19_D0_9test19_B3) + 104 -// CHECK-LP64-NEXT .quad (__ZTC8test19_D0_9test19_B3) + 104 -// CHECK-LP64-NEXT .quad (__ZTC8test19_D0_9test19_B4) + 136 -// CHECK-LP64-NEXT .quad (__ZTC8test19_D0_9test19_B2) + 88 -// CHECK-LP64-NEXT .quad (__ZTC8test19_D0_9test19_B1) + 24 - +// CHECK-LP64-NEXT: .quad __ZTV8test19_D+144 +// CHECK-LP64-NEXT: .quad __ZTV8test19_D+144 +// CHECK-LP64-NEXT .quad __ZTV8test19_D+144 +// CHECK-LP64-NEXT .quad __ZTC8test19_D0_9test19_B4+136 +// CHECK-LP64-NEXT .quad __ZTC8test19_D0_9test19_B3+104 +// CHECK-LP64-NEXT .quad __ZTC8test19_D0_9test19_B3+104 +// CHECK-LP64-NEXT .quad __ZTC8test19_D0_9test19_B4+136 +// CHECK-LP64-NEXT .quad __ZTC8test19_D0_9test19_B2+88 +// CHECK-LP64-NEXT .quad __ZTC8test19_D0_9test19_B1+24 class test20_V { virtual void foo1(); @@ -987,42 +537,22 @@ class test20_B1 : virtual test20_V1 { class test20_D : public test20_B, public test20_B1 { }; -// CHECK-LP64: __ZTV8test20_D: -// CHECK-LP64-NEXT: .quad 8 -// CHECK-LP64-NEXT: .space 8 -// CHECK-LP64-NEXT: .space 8 -// CHECK-LP64-NEXT: .space 8 -// CHECK-LP64-NEXT: .quad __ZTI8test20_D -// CHECK-LP64-NEXT: .quad __ZN8test20_V4foo1Ev -// CHECK-LP64-NEXT: .space 8 -// CHECK-LP64-NEXT: .space 8 -// CHECK-LP64-NEXT: .quad 18446744073709551608 -// CHECK-LP64-NEXT: .quad __ZTI8test20_D -// CHECK-LP64-NEXT: .quad __ZN9test20_V14foo2Ev - -// CHECK-LP64: __ZTC8test20_D0_8test20_B: -// CHECK-LP64-NEXT: .space 8 -// CHECK-LP64-NEXT: .space 8 -// CHECK-LP64-NEXT: .space 8 -// CHECK-LP64-NEXT: .quad __ZTI8test20_B -// CHECK-LP64-NEXT: .quad __ZN8test20_V4foo1Ev - -// CHECK-LP64: __ZTC8test20_D8_9test20_B1: -// CHECK-LP64-NEXT: .space 8 -// CHECK-LP64-NEXT: .space 8 -// CHECK-LP64-NEXT: .space 8 -// CHECK-LP64-NEXT: .quad __ZTI9test20_B1 -// CHECK-LP64-NEXT: .quad __ZN9test20_V14foo2Ev +// CHECK-LPLL64:@_ZTV8test20_D = weak_odr constant [11 x i8*] [i8* inttoptr (i64 8 to i8*), i8* null, i8* null, i8* null, i8* bitcast (%1* @_ZTI8test20_D to i8*), i8* bitcast (void (%class.test14*)* @_ZN8test20_V4foo1Ev to i8*), i8* null, i8* null, i8* inttoptr (i64 -8 to i8*), i8* bitcast (%1* @_ZTI8test20_D to i8*), i8* bitcast (void (%class.test14*)* @_ZN9test20_V14foo2Ev to i8*)] + +// CHECK-LPLL64:@_ZTC8test20_D0_8test20_B = internal constant [5 x i8*] [i8* null, i8* null, i8* null, i8* bitcast (%3* @_ZTI8test20_B to i8*), i8* bitcast (void (%class.test14*)* @_ZN8test20_V4foo1Ev to i8*)] + +// CHECK-LPLL64:@_ZTC8test20_D8_9test20_B1 = internal constant [5 x i8*] [i8* null, i8* null, i8* null, i8* bitcast (%3* @_ZTI9test20_B1 to i8*), i8* bitcast (void (%class.test14*)* @_ZN9test20_V14foo2Ev to i8*)] ; <[5 x i8*]*> [#uses=1] +// FIXME: // CHECK-LP64: __ZTT8test20_D: -// CHECK-LP64-NEXT: .quad (__ZTV8test20_D) + 40 -// CHECK-LP64-NEXT: .quad (__ZTC8test20_D0_8test20_B) + 32 -// CHECK-LP64-NEXT: .quad (__ZTC8test20_D0_8test20_B) + 32 -// CHECK-LP64-NEXT: .quad (__ZTC8test20_D8_9test20_B1) + 32 -// CHECK-LP64-NEXT: .quad (__ZTC8test20_D8_9test20_B1) + 32 -// CHECK-LP64-NEXT .quad (__ZTV8test20_D) + 40 -// CHECK-LP64-NEXT .quad (__ZTV8test20_D) + 80 -// CHECK-LP64-NEXT .quad (__ZTV8test20_D) + 80 +// CHECK-LP64-NEXT: .quad __ZTV8test20_D+40 +// CHECK-LP64-NEXT: .quad __ZTC8test20_D0_8test20_B+32 +// CHECK-LP64-NEXT: .quad __ZTC8test20_D0_8test20_B+32 +// CHECK-LP64-NEXT: .quad __ZTC8test20_D8_9test20_B1+32 +// CHECK-LP64-NEXT: .quad __ZTC8test20_D8_9test20_B1+32 +// CHECK-LP64-NEXT .quad __ZTV8test20_D+40 +// CHECK-LP64-NEXT .quad __ZTV8test20_D+80 +// CHECK-LP64-NEXT .quad __ZTV8test20_D+80 class test21_V { @@ -1039,45 +569,73 @@ class test21_D : public test21_B, public test21_B1 { void foo() { } }; -// CHECK-LP64: __ZTV8test21_D: -// CHECK-LP64-NEXT: .quad 8 -// CHECK-LP64-NEXT: .space 8 -// CHECK-LP64-NEXT: .space 8 -// CHECK-LP64-NEXT: .space 8 -// CHECK-LP64-NEXT: .quad __ZTI8test21_D -// CHECK-LP64-NEXT: .quad __ZN8test21_D3fooEv -// CHECK-LP64-NEXT: .space 8 -// CHECK-LP64-NEXT: .quad 18446744073709551608 -// CHECK-LP64-NEXT: .quad 18446744073709551608 -// CHECK-LP64-NEXT: .quad __ZTI8test21_D -// CHECK-LP64-NEXT: .quad __ZTv0_n24_N8test21_D3fooEv - -// CHECK-LP64: __ZTC8test21_D0_8test21_B: -// CHECK-LP64-NEXT: .space 8 -// CHECK-LP64-NEXT: .space 8 -// CHECK-LP64-NEXT: .space 8 -// CHECK-LP64-NEXT: .quad __ZTI8test21_B -// CHECK-LP64-NEXT: .quad __ZN8test21_V3fooEv - -// CHECK-LP64: __ZTC8test21_D8_9test21_B1: -// CHECK-LP64-NEXT: .space 8 -// CHECK-LP64-NEXT: .space 8 -// CHECK-LP64-NEXT: .space 8 -// CHECK-LP64-NEXT: .quad __ZTI9test21_B1 -// CHECK-LP64-NEXT: .quad __ZN9test21_V13fooEv +// CHECK-LPLL64:@_ZTV8test21_D = weak_odr constant [11 x i8*] [i8* inttoptr (i64 8 to i8*), i8* null, i8* null, i8* null, i8* bitcast (%1* @_ZTI8test21_D to i8*), i8* bitcast (void (%class.test20_D*)* @_ZN8test21_D3fooEv to i8*), i8* null, i8* inttoptr (i64 -8 to i8*), i8* inttoptr (i64 -8 to i8*), i8* bitcast (%1* @_ZTI8test21_D to i8*), i8* bitcast (void (%class.test20_D*)* @_ZTv0_n24_N8test21_D3fooEv to i8*)] +// CHECK-LPLL64:@_ZTC8test21_D0_8test21_B = internal constant [5 x i8*] [i8* null, i8* null, i8* null, i8* bitcast (%3* @_ZTI8test21_B to i8*), i8* bitcast (void (%class.test14*)* @_ZN8test21_V3fooEv to i8*)] + +// CHECK-LPLL64:@_ZTC8test21_D8_9test21_B1 = internal constant [5 x i8*] [i8* null, i8* null, i8* null, i8* bitcast (%3* @_ZTI9test21_B1 to i8*), i8* bitcast (void (%class.test14*)* @_ZN9test21_V13fooEv to i8*)] ; <[5 x i8*]*> [#uses=1] + +// FIXME: // CHECK-LP64: __ZTT8test21_D: -// CHECK-LP64-NEXT: .quad (__ZTV8test21_D) + 40 -// CHECK-LP64-NEXT: .quad (__ZTC8test21_D0_8test21_B) + 32 -// CHECK-LP64-NEXT: .quad (__ZTC8test21_D0_8test21_B) + 32 -// CHECK-LP64-NEXT: .quad (__ZTC8test21_D8_9test21_B1) + 32 -// CHECK-LP64-NEXT: .quad (__ZTC8test21_D8_9test21_B1) + 32 -// CHECK-LP64-NEXT .quad (__ZTV8test21_D) + 40 -// CHECK-LP64-NEXT .quad (__ZTV8test21_D) + 80 -// CHECK-LP64-NEXT .quad (__ZTV8test21_D) + 80 +// CHECK-LP64-NEXT: .quad __ZTV8test21_D+40 +// CHECK-LP64-NEXT: .quad __ZTC8test21_D0_8test21_B+32 +// CHECK-LP64-NEXT: .quad __ZTC8test21_D0_8test21_B+32 +// CHECK-LP64-NEXT: .quad __ZTC8test21_D8_9test21_B1+32 +// CHECK-LP64-NEXT: .quad __ZTC8test21_D8_9test21_B1+32 +// CHECK-LP64-NEXT .quad __ZTV8test21_D+40 +// CHECK-LP64-NEXT .quad __ZTV8test21_D+80 +// CHECK-LP64-NEXT .quad __ZTV8test21_D+80 + + +struct test22_s1 { virtual void dtor() { } }; +struct test22_s2 { virtual void dtor() { } }; +struct test22_s3 : test22_s1, test22_s2 { virtual void dtor() { } }; +struct test22_D : test22_s3 { virtual void dtor() { } }; + +// CHECK-LPLL64:@_ZTV8test22_D = weak_odr constant [6 x i8*] [i8* null, i8* bitcast (%4* @_ZTI8test22_D to i8*), i8* bitcast (void (%class.test20_D*)* @_ZN8test22_D4dtorEv to i8*), i8* inttoptr (i64 -8 to i8*), i8* bitcast (%4* @_ZTI8test22_D to i8*), i8* bitcast (void (%class.test20_D*)* @_ZThn8_N8test22_D4dtorEv to i8*)] + + +class test23_s1 { + virtual void fun1(char *t) { } +}; +class test23_s2 { + virtual void fun2(char *t) { } +}; +class test23_s3 { + virtual void fun3(char *t) { } +}; +class test23_s4: virtual test23_s1, test23_s2, test23_s3 { + virtual void fun4(char *t) { } +}; +class test23_D: virtual test23_s4 { + virtual void fun5(char *t) { } +}; + +// FIXME: +// CHECK-LP64: __ZTV8test23_D: +// CHECK-LP64-NEXT: .quad 0 +// CHECK-LP64-NEXT: .quad 8 +// CHECK-LP64-NEXT: .quad 0 +// CHECK-LP64-NEXT: .quad 0 +// CHECK-LP64-NEXT: .quad __ZTI8test23_D +// CHECK-LP64-NEXT: .quad __ZN9test23_s14fun1EPc +// CHECK-LP64-NEXT: .quad __ZN8test23_D4fun5EPc +// CHECK-LP64-NEXT .quad 8 +// CHECK-LP64: .quad 0 +// CHECK-LP64-NEXT: .quad 0 +// CHECK-LP64: .quad -8 +// CHECK-LP64-NEXT: .quad -8 +// CHECK-LP64-NEXT: .quad __ZTI8test23_D +// CHECK-LP64-NEXT: .quad __ZN9test23_s24fun2EPc +// CHECK-LP64-NEXT: .quad __ZN9test23_s44fun4EPc +// CHECK-LP64-NEXT: .quad -16 +// CHECK-LP64-NEXT: .quad __ZTI8test23_D +// CHECK-LP64-NEXT: .quad __ZN9test23_s34fun3EPc +test23_D d23; +test22_D d22; test21_D d21; test20_D d20; test19_D d19; @@ -1097,3 +655,93 @@ test3_D d3; test6_D d6; test7_D d7; + + +int j; +void *vp; +void test2() { + F f; + static int sz = (char *)(&f.f) - (char *)(&f); + vp = &sz; + j = sz; + // FIXME: These should result in a frontend constant a la fold, no run time + // initializer + // CHECK-LPLL64: define void @_Z5test2v() + // CHECK-LPLL64: = getelementptr inbounds %class.F* %f, i32 0, i32 1 +} + +static_assert(sizeof(F) == sizeof(void*)*4, "invalid vbase size"); + + +void test12_foo() { + test12_pa->foo0(); + test12_pb->foo0(); + test12_pd->foo0(); + test12_pa->foo(); + test12_pb->foo(); + test12_pd->foo(); + test12_pa->test12_A::foo(); +} + + +// CHECK-LPLL64:define void @_Z10test12_foov() nounwind { +// CHECK-LPLL64: call void % +// CHECK-LPLL64: call void % +// CHECK-LPLL64: call void % +// CHECK-LPLL64: call void % +// CHECK-LPLL64: call void % +// CHECK-LPLL64: call void % +// CHECK-LPLL64: call void @_ZN8test12_A3fooEv(%class.test14* %{{.*}}) + + +// FIXME: This is the wrong thunk, but until these issues are fixed, better +// than nothing. +// CHECK-LPLL64:define weak %class.test8_D* @_ZTcvn16_n72_v16_n32_N8test16_D4foo1Ev(%class.test8_D*) +// CHECK-LPLL64: %{{retval|2}} = alloca %class.test8_D* +// CHECK-LPLL64: %.addr = alloca %class.test8_D* +// CHECK-LPLL64: store %class.test8_D* %0, %class.test8_D** %.addr +// CHECK-LPLL64: %{{this|3}} = load %class.test8_D** %.addr +// CHECK-LPLL64: %{{1|4}} = bitcast %class.test8_D* %{{this|3}} to i8* +// CHECK-LPLL64: %{{2|5}} = getelementptr inbounds i8* %{{1|4}}, i64 -16 +// CHECK-LPLL64: %{{3|6}} = bitcast i8* %{{2|5}} to %class.test8_D* +// CHECK-LPLL64: %{{4|7}} = bitcast %class.test8_D* %{{3|6}} to i8* +// CHECK-LPLL64: %{{5|8}} = bitcast %class.test8_D* %3 to i64** +// CHECK-LPLL64: %{{vtable|9}} = load i64** %{{5|8}} +// CHECK-LPLL64: %{{6|10}} = getelementptr inbounds i64* %{{vtable|9}}, i64 -9 +// CHECK-LPLL64: %{{7|11}} = load i64* %{{6|10}} +// CHECK-LPLL64: %{{8|12}} = getelementptr i8* %{{4|7}}, i64 %{{7|11}} +// CHECK-LPLL64: %{{9|13}} = bitcast i8* %{{8|12}} to %class.test8_D* +// CHECK-LPLL64: %{{call|14}} = call %class.test8_D* @_ZTch0_v16_n32_N8test16_D4foo1Ev(%class.test8_D* %{{9|13}}) +// CHECK-LPLL64: store %class.test8_D* %{{call|14}}, %class.test8_D** %{{retval|2}} +// CHECK-LPLL64: %{{10|15}} = load %class.test8_D** %{{retval|2}} +// CHECK-LPLL64: ret %class.test8_D* %{{10|15}} +// CHECK-LPLL64:} + +// CHECK-LPLL64:define weak %class.test8_D* @_ZTch0_v16_n32_N8test16_D4foo1Ev(%{{class.test8_D|.*}}*) +// CHECK-LPLL64: %{{retval|2}} = alloca %class.test8_D* +// CHECK-LPLL64: %.addr = alloca %class.test8_D* +// CHECK-LPLL64: store %class.test8_D* %0, %class.test8_D** %.addr +// CHECK-LPLL64: %{{this|3}} = load %class.test8_D** %.addr +// CHECK-LPLL64: %{{call|4}} = call %class.test8_D* @_ZN8test16_D4foo1Ev(%class.test8_D* %{{this|3}}) +// CHECK-LPLL64: %{{1|5}} = icmp ne %class.test8_D* %{{call|4}}, null +// CHECK-LPLL64: br i1 %{{1|5}}, label %{{2|6}}, label %{{12|17}} +// CHECK-LPLL64:; <label>:{{2|6}} +// CHECK-LPLL64: %{{3|7}} = bitcast %class.test8_D* %{{call|4}} to i8* +// CHECK-LPLL64: %{{4|8}} = getelementptr inbounds i8* %{{3|7}}, i64 16 +// CHECK-LPLL64: %{{5|9}} = bitcast i8* %4 to %class.test8_D* +// CHECK-LPLL64: %{{6|10}} = bitcast %class.test8_D* %{{5|9}} to i8* +// CHECK-LPLL64: %{{7|11}} = bitcast %class.test8_D* %{{5|9}} to i64** +// CHECK-LPLL64: %{{vtable|12}} = load i64** %{{7|11}} +// CHECK-LPLL64: %{{8|13}} = getelementptr inbounds i64* %vtable, i64 -4 +// CHECK-LPLL64: %{{9|14}} = load i64* %{{8|13}} +// CHECK-LPLL64: %{{10|15}} = getelementptr i8* %{{6|10}}, i64 %{{9|14}} +// CHECK-LPLL64: %{{11|16}} = bitcast i8* %{{10|15}} to %class.test8_D* +// CHECK-LPLL64: br label %{{13|18}} +// CHECK-LPLL64:; <label>:{{12|17}} +// CHECK-LPLL64: br label %{{13|18}} +// CHECK-LPLL64:; <label>:{{13|18}} +// CHECK-LPLL64: %{{14|19}} = phi %class.test8_D* [ %{{11|16}}, %{{2|6}} ], [ %{{call|4}}, %{{12|17}} ] +// CHECK-LPLL64: store %class.test8_D* %{{14|19}}, %class.test8_D** %{{retval|2}} +// CHECK-LPLL64: %{{15|20}} = load %class.test8_D** %{{retval|2}} +// CHECK-LPLL64: ret %class.test8_D* %{{15|20}} +// CHECK-LPLL64:} diff --git a/test/CodeGenCXX/vtt-layout.cpp b/test/CodeGenCXX/vtt-layout.cpp new file mode 100644 index 0000000..d7d4227 --- /dev/null +++ b/test/CodeGenCXX/vtt-layout.cpp @@ -0,0 +1,64 @@ +// RUN: %clang_cc1 %s -triple=x86_64-apple-darwin10 -emit-llvm -o - | FileCheck %s + +// Test1::B should just have a single entry in its VTT, which points to the vtable. +namespace Test1 { +struct A { }; + +struct B : virtual A { + virtual void f(); +}; + +void B::f() { } +} + +// Check that we don't add a secondary virtual pointer for Test2::A, since Test2::A doesn't have any virtual member functions or bases. +namespace Test2 { + struct A { }; + + struct B : A { virtual void f(); }; + struct C : virtual B { }; + + C c; +} + +// This is the sample from the C++ Itanium ABI, p2.6.2. +namespace Test3 { + class A1 { int i; }; + class A2 { int i; virtual void f(); }; + class V1 : public A1, public A2 { int i; }; + class B1 { int i; }; + class B2 { int i; }; + class V2 : public B1, public B2, public virtual V1 { int i; }; + class V3 {virtual void g(); }; + class C1 : public virtual V1 { int i; }; + class C2 : public virtual V3, virtual V2 { int i; }; + class X1 { int i; }; + class C3 : public X1 { int i; }; + class D : public C1, public C2, public C3 { int i; }; + + D d; +} + +// This is the sample from the C++ Itanium ABI, p2.6.2, with the change suggested +// (making A2 a virtual base of V1) +namespace Test4 { + class A1 { int i; }; + class A2 { int i; virtual void f(); }; + class V1 : public A1, public virtual A2 { int i; }; + class B1 { int i; }; + class B2 { int i; }; + class V2 : public B1, public B2, public virtual V1 { int i; }; + class V3 {virtual void g(); }; + class C1 : public virtual V1 { int i; }; + class C2 : public virtual V3, virtual V2 { int i; }; + class X1 { int i; }; + class C3 : public X1 { int i; }; + class D : public C1, public C2, public C3 { int i; }; + + D d; +} + +// CHECK: @_ZTTN5Test11BE = constant [1 x i8*] [i8* bitcast (i8** getelementptr inbounds ([4 x i8*]* @_ZTVN5Test11BE, i64 0, i64 3) to i8*)] +// CHECK: @_ZTTN5Test41DE = weak_odr constant [19 x i8*] [i8* bitcast (i8** getelementptr inbounds ([25 x i8*]* @_ZTVN5Test41DE, i64 0, i64 6) to i8*), i8* bitcast (i8** getelementptr inbounds ([11 x i8*]* @_ZTCN5Test41DE0_NS_2C1E, i64 0, i64 4) to i8*), i8* bitcast (i8** getelementptr inbounds ([11 x i8*]* @_ZTCN5Test41DE0_NS_2C1E, i64 0, i64 7) to i8*), i8* bitcast (i8** getelementptr inbounds ([11 x i8*]* @_ZTCN5Test41DE0_NS_2C1E, i64 0, i64 10) to i8*), i8* bitcast (i8** getelementptr inbounds ([19 x i8*]* @_ZTCN5Test41DE16_NS_2C2E, i64 0, i64 7) to i8*), i8* bitcast (i8** getelementptr inbounds ([19 x i8*]* @_ZTCN5Test41DE16_NS_2C2E, i64 0, i64 7) to i8*), i8* bitcast (i8** getelementptr inbounds ([19 x i8*]* @_ZTCN5Test41DE16_NS_2C2E, i64 0, i64 12) to i8*), i8* bitcast (i8** getelementptr inbounds ([19 x i8*]* @_ZTCN5Test41DE16_NS_2C2E, i64 0, i64 15) to i8*), i8* bitcast (i8** getelementptr inbounds ([19 x i8*]* @_ZTCN5Test41DE16_NS_2C2E, i64 0, i64 18) to i8*), i8* bitcast (i8** getelementptr inbounds ([25 x i8*]* @_ZTVN5Test41DE, i64 0, i64 17) to i8*), i8* bitcast (i8** getelementptr inbounds ([25 x i8*]* @_ZTVN5Test41DE, i64 0, i64 20) to i8*), i8* bitcast (i8** getelementptr inbounds ([25 x i8*]* @_ZTVN5Test41DE, i64 0, i64 13) to i8*), i8* bitcast (i8** getelementptr inbounds ([25 x i8*]* @_ZTVN5Test41DE, i64 0, i64 13) to i8*), i8* bitcast (i8** getelementptr inbounds ([25 x i8*]* @_ZTVN5Test41DE, i64 1, i64 0) to i8*), i8* bitcast (i8** getelementptr inbounds ([7 x i8*]* @_ZTCN5Test41DE40_NS_2V1E, i64 0, i64 3) to i8*), i8* bitcast (i8** getelementptr inbounds ([7 x i8*]* @_ZTCN5Test41DE40_NS_2V1E, i64 0, i64 6) to i8*), i8* bitcast (i8** getelementptr inbounds ([11 x i8*]* @_ZTCN5Test41DE72_NS_2V2E, i64 0, i64 4) to i8*), i8* bitcast (i8** getelementptr inbounds ([11 x i8*]* @_ZTCN5Test41DE72_NS_2V2E, i64 0, i64 7) to i8*), i8* bitcast (i8** getelementptr inbounds ([11 x i8*]* @_ZTCN5Test41DE72_NS_2V2E, i64 0, i64 10) to i8*)] ; <[19 x i8*]*> [#uses=4] +// CHECK: @_ZTTN5Test31DE = weak_odr constant [13 x i8*] [i8* bitcast (i8** getelementptr inbounds ([19 x i8*]* @_ZTVN5Test31DE, i64 0, i64 5) to i8*), i8* bitcast (i8** getelementptr inbounds ([7 x i8*]* @_ZTCN5Test31DE0_NS_2C1E, i64 0, i64 3) to i8*), i8* bitcast (i8** getelementptr inbounds ([7 x i8*]* @_ZTCN5Test31DE0_NS_2C1E, i64 0, i64 6) to i8*), i8* bitcast (i8** getelementptr inbounds ([14 x i8*]* @_ZTCN5Test31DE16_NS_2C2E, i64 0, i64 6) to i8*), i8* bitcast (i8** getelementptr inbounds ([14 x i8*]* @_ZTCN5Test31DE16_NS_2C2E, i64 0, i64 6) to i8*), i8* bitcast (i8** getelementptr inbounds ([14 x i8*]* @_ZTCN5Test31DE16_NS_2C2E, i64 0, i64 10) to i8*), i8* bitcast (i8** getelementptr inbounds ([14 x i8*]* @_ZTCN5Test31DE16_NS_2C2E, i64 0, i64 13) to i8*), i8* bitcast (i8** getelementptr inbounds ([19 x i8*]* @_ZTVN5Test31DE, i64 0, i64 15) to i8*), i8* bitcast (i8** getelementptr inbounds ([19 x i8*]* @_ZTVN5Test31DE, i64 0, i64 11) to i8*), i8* bitcast (i8** getelementptr inbounds ([19 x i8*]* @_ZTVN5Test31DE, i64 0, i64 11) to i8*), i8* bitcast (i8** getelementptr inbounds ([19 x i8*]* @_ZTVN5Test31DE, i64 1, i64 0) to i8*), i8* bitcast (i8** getelementptr inbounds ([7 x i8*]* @_ZTCN5Test31DE64_NS_2V2E, i64 0, i64 3) to i8*), i8* bitcast (i8** getelementptr inbounds ([7 x i8*]* @_ZTCN5Test31DE64_NS_2V2E, i64 0, i64 6) to i8*)] ; <[13 x i8*]*> [#uses=3] +// CHECK: @_ZTTN5Test21CE = weak_odr constant [2 x i8*] [i8* bitcast (i8** getelementptr inbounds ([5 x i8*]* @_ZTVN5Test21CE, i64 0, i64 4) to i8*), i8* bitcast (i8** getelementptr inbounds ([5 x i8*]* @_ZTVN5Test21CE, i64 0, i64 4) to i8*)] ; <[2 x i8*]*> [#uses=0] diff --git a/test/Driver/darwin-arm.c b/test/Driver/darwin-arm.c deleted file mode 100644 index 330918d..0000000 --- a/test/Driver/darwin-arm.c +++ /dev/null @@ -1,4 +0,0 @@ -// RUN: %clang -ccc-host-triple i386-apple-darwin9 -arch arm -print-search-dirs | FileCheck %s - -// Check that we look in the relative libexec directory. -// CHECK: {{programs: =.*/../libexec:}} diff --git a/test/FixIt/typo.m b/test/FixIt/typo.m index 4c3ee5f..c2069dd 100644 --- a/test/FixIt/typo.m +++ b/test/FixIt/typo.m @@ -12,6 +12,7 @@ void test() { } @protocol P1 +@optional @property int *sprop; // expected-note{{'sprop' declared here}} @end diff --git a/test/Index/Inputs/remap-load-to.c b/test/Index/Inputs/remap-load-to.c new file mode 100644 index 0000000..8f9e1eb --- /dev/null +++ b/test/Index/Inputs/remap-load-to.c @@ -0,0 +1,3 @@ +int foo(int parm1, float parm2) { + return parm1 + parm2; +} diff --git a/test/Index/TestClassDecl.m b/test/Index/TestClassDecl.m index fb97de1..f962712 100644 --- a/test/Index/TestClassDecl.m +++ b/test/Index/TestClassDecl.m @@ -16,23 +16,18 @@ void function(Foo * arg) } // CHECK-scan: {start_line=1 start_col=1 end_line=7 end_col=1} Invalid Cursor => NoDeclFound -// CHECK-scan: {start_line=8 start_col=1 end_line=8 end_col=7} Invalid Cursor => NotImplemented -// CHECK-scan: {start_line=8 start_col=8 end_line=8 end_col=10} ObjCClassRef=Foo:8:1 +// CHECK-scan: {start_line=8 start_col=1 end_line=8 end_col=7} UnexposedDecl=:8:1 +// CHECK-scan: {start_line=8 start_col=8 end_line=8 end_col=10} ObjCClassRef=Foo:10:12 // CHECK-scan: {start_line=8 start_col=11 end_line=9 end_col=1} Invalid Cursor => NoDeclFound -// CHECK-scan: {start_line=10 start_col=1 end_line=11 end_col=4} ObjCInterfaceDecl=Foo:10:1 -// CHECK-scan: {start_line=11 start_col=5 end_line=12 end_col=1} Invalid Cursor => NoDeclFound -// CHECK-scan: {start_line=13 start_col=1 end_line=13 end_col=4} FunctionDecl=function:13:6 -// CHECK-scan: {start_line=13 start_col=5 end_line=13 end_col=5} Invalid Cursor => NoDeclFound -// CHECK-scan: {start_line=13 start_col=6 end_line=13 end_col=14} FunctionDecl=function:13:6 -// CHECK-scan: {start_line=13 start_col=15 end_line=13 end_col=17} ObjCClassRef=Foo:13:21 -// CHECK-scan: {start_line=13 start_col=18 end_line=13 end_col=18} FunctionDecl=function:13:6 -// CHECK-scan: {start_line=13 start_col=19 end_line=13 end_col=19} ParmDecl=arg:13:21 -// CHECK-scan: {start_line=13 start_col=20 end_line=13 end_col=20} FunctionDecl=function:13:6 -// CHECK-scan: {start_line=13 start_col=21 end_line=13 end_col=23} ParmDecl=arg:13:21 -// CHECK-scan: {start_line=13 start_col=24 end_line=16 end_col=1} FunctionDecl=function:13:6 -// CHECK-scan: {start_line=16 start_col=2 end_line=38 end_col=1} Invalid Cursor => NoDeclFound +// CHECK-scan: {start_line=10 start_col=1 end_line=11 end_col=4} ObjCInterfaceDecl=Foo:10:12 +// CHECK-scan: {start_line=11 start_col=5 end_line=13 end_col=5} Invalid Cursor => NoDeclFound +// CHECK-scan: {start_line=13 start_col=6 end_line=13 end_col=14} FunctionDecl=function:13:6 (Definition) +// CHECK-scan: {start_line=13 start_col=15 end_line=13 end_col=17} ObjCClassRef=Foo:10:12 +// CHECK-scan: {start_line=13 start_col=18 end_line=13 end_col=23} ParmDecl=arg:13:21 (Definition) +// CHECK-scan: {start_line=13 start_col=24 end_line=13 end_col=25} FunctionDecl=function:13:6 (Definition) +// CHECK-scan: {start_line=14 start_col=1 end_line=16 end_col=1} UnexposedStmt=function -// CHECK-load: TestClassDecl.m:10:12: ObjCInterfaceDecl=Foo:10:1 [Context=TestClassDecl.m] [Extent=10:1:11:4] -// CHECK-load: TestClassDecl.m:13:6: FunctionDefn=function [Context=TestClassDecl.m] [Extent=13:6:16:1] -// CHECK-load: TestClassDecl.m:13:21: ParmDecl=arg:13:21 [Context=function] [Extent=13:21:13:23] +// CHECK-load: TestClassDecl.m:10:12: ObjCInterfaceDecl=Foo:10:12 [Extent=10:1:11:4] +// CHECK-load: TestClassDecl.m:13:6: FunctionDecl=function:13:6 (Definition) [Extent=13:6:16:1] +// CHECK-load: TestClassDecl.m:13:21: ParmDecl=arg:13:21 (Definition) [Extent=13:15:13:23] diff --git a/test/Index/TestClassForwardDecl.m b/test/Index/TestClassForwardDecl.m index e795972..c53453b 100644 --- a/test/Index/TestClassForwardDecl.m +++ b/test/Index/TestClassForwardDecl.m @@ -13,19 +13,14 @@ void function(Foo * arg) } // CHECK-scan: {start_line=1 start_col=1 end_line=7 end_col=1} Invalid Cursor => NoDeclFound -// CHECK-scan: {start_line=8 start_col=1 end_line=8 end_col=7} Invalid Cursor => NotImplemented -// CHECK-scan: {start_line=8 start_col=8 end_line=8 end_col=10} ObjCClassRef=Foo:8:1 -// CHECK-scan: {start_line=8 start_col=11 end_line=9 end_col=1} Invalid Cursor => NoDeclFound -// CHECK-scan: {start_line=10 start_col=1 end_line=10 end_col=4} FunctionDecl=function:10:6 -// CHECK-scan: {start_line=10 start_col=5 end_line=10 end_col=5} Invalid Cursor => NoDeclFound -// CHECK-scan: {start_line=10 start_col=6 end_line=10 end_col=14} FunctionDecl=function:10:6 -// CHECK-scan: {start_line=10 start_col=15 end_line=10 end_col=17} ObjCClassRef=Foo:10:21 -// CHECK-scan: {start_line=10 start_col=18 end_line=10 end_col=18} FunctionDecl=function:10:6 -// CHECK-scan: {start_line=10 start_col=19 end_line=10 end_col=19} ParmDecl=arg:10:21 -// CHECK-scan: {start_line=10 start_col=20 end_line=10 end_col=20} FunctionDecl=function:10:6 -// CHECK-scan: {start_line=10 start_col=21 end_line=10 end_col=23} ParmDecl=arg:10:21 -// CHECK-scan: {start_line=10 start_col=24 end_line=13 end_col=1} FunctionDecl=function:10:6 -// CHECK-scan: {start_line=13 start_col=2 end_line=46 end_col=1} Invalid Cursor => NoDeclFound +// CHECK-scan: {start_line=8 start_col=1 end_line=8 end_col=7} UnexposedDecl=:8:1 +// CHECK-scan: {start_line=8 start_col=8 end_line=8 end_col=10} ObjCClassRef=Foo:8:8 +// CHECK-scan: {start_line=8 start_col=11 end_line=10 end_col=5} Invalid Cursor => NoDeclFound +// CHECK-scan: {start_line=10 start_col=6 end_line=10 end_col=14} FunctionDecl=function:10:6 (Definition) +// CHECK-scan: {start_line=10 start_col=15 end_line=10 end_col=17} ObjCClassRef=Foo:8:8 +// CHECK-scan: {start_line=10 start_col=18 end_line=10 end_col=23} ParmDecl=arg:10:21 (Definition) +// CHECK-scan: {start_line=10 start_col=24 end_line=10 end_col=25} FunctionDecl=function:10:6 (Definition) +// CHECK-scan: {start_line=11 start_col=1 end_line=13 end_col=1} UnexposedStmt=function @@ -41,6 +36,6 @@ void function(Foo * arg) -// CHECK-load: TestClassForwardDecl.m:10:6: FunctionDefn=function [Context=TestClassForwardDecl.m] -// CHECK-load: TestClassForwardDecl.m:10:21: ParmDecl=arg:10:21 [Context=function] +// CHECK-load: TestClassForwardDecl.m:10:6: FunctionDecl=function:10:6 (Definition) +// CHECK-load: TestClassForwardDecl.m:10:21: ParmDecl=arg:10:21 diff --git a/test/Index/c-index-api-fn-scan.m b/test/Index/c-index-api-fn-scan.m deleted file mode 100644 index 8cbc036..0000000 --- a/test/Index/c-index-api-fn-scan.m +++ /dev/null @@ -1,217 +0,0 @@ -// RUN: %clang_cc1 -triple x86_64-apple-darwin10 -fobjc-nonfragile-abi -fblocks -emit-pch -x objective-c %s -o %t.ast -// RUN: c-index-test -test-load-tu %t.ast scan-function | FileCheck %s - - - - - - - - - - - - - - - - - -@interface Foo -{ -} - -- foo; -+ fooC; - -@end - -@interface Bar : Foo -{ -} - -@end - -@interface Foo (FooCat) -- (int) catMethodWithFloat:(float) fArg; -- (float) floatMethod; -@end - -@protocol Proto -- pMethod; -@end - -@protocol SubP <Proto> -- spMethod; -@end - -@interface Baz : Bar <SubP> -{ - int _anIVar; -} - -- (Foo *) bazMethod; - -@end - -enum { - someEnum -}; - - - - - - - - - - - - - - - - - - - - - - - -int main (int argc, const char * argv[]) { - Baz * bee; - id a = [bee foo]; - id <SubP> c = [Foo fooC]; - id <Proto> d; - d = c; - [d pMethod]; - [bee catMethodWithFloat:[bee floatMethod]]; - main(someEnum, (const char **)bee); -} - -// CHECK: c-index-api-fn-scan.m:84:2: ObjCClassRef=Baz:84:8 [Context:Baz] -// CHECK: c-index-api-fn-scan.m:84:3: ObjCClassRef=Baz:84:8 [Context:Baz] -// CHECK: c-index-api-fn-scan.m:84:4: ObjCClassRef=Baz:84:8 [Context:Baz] -// CHECK: c-index-api-fn-scan.m:84:6: VarDecl=bee:84:8 [Context:bee] -// CHECK: c-index-api-fn-scan.m:84:8: VarDecl=bee:84:8 [Context:bee] -// CHECK: c-index-api-fn-scan.m:84:9: VarDecl=bee:84:8 [Context:bee] -// CHECK: c-index-api-fn-scan.m:84:10: VarDecl=bee:84:8 [Context:bee] -// CHECK: <invalid loc>:85:2: TypedefDecl=id:0:0 [Context:id] -// CHECK: <invalid loc>:85:3: TypedefDecl=id:0:0 [Context:id] -// CHECK: c-index-api-fn-scan.m:85:5: VarDecl=a:85:5 [Context:a] -// CHECK: c-index-api-fn-scan.m:85:6: VarDecl=a:85:5 [Context:a] -// CHECK: c-index-api-fn-scan.m:85:7: VarDecl=a:85:5 [Context:a] -// CHECK: c-index-api-fn-scan.m:85:8: VarDecl=a:85:5 [Context:a] -// CHECK: c-index-api-fn-scan.m:85:9: ObjCSelectorRef=foo:24:1 [Context:a] -// CHECK: c-index-api-fn-scan.m:85:10: VarRef=bee:84:8 [Context:a] -// CHECK: c-index-api-fn-scan.m:85:11: VarRef=bee:84:8 [Context:a] -// CHECK: c-index-api-fn-scan.m:85:12: VarRef=bee:84:8 [Context:a] -// CHECK: c-index-api-fn-scan.m:85:13: ObjCSelectorRef=foo:24:1 [Context:a] -// CHECK: c-index-api-fn-scan.m:85:14: ObjCSelectorRef=foo:24:1 [Context:a] -// CHECK: c-index-api-fn-scan.m:85:15: ObjCSelectorRef=foo:24:1 [Context:a] -// CHECK: c-index-api-fn-scan.m:85:16: ObjCSelectorRef=foo:24:1 [Context:a] -// CHECK: c-index-api-fn-scan.m:85:17: ObjCSelectorRef=foo:24:1 [Context:a] -// CHECK: <invalid loc>:86:2: TypedefDecl=id:0:0 [Context:id] -// CHECK: <invalid loc>:86:3: TypedefDecl=id:0:0 [Context:id] -// CHECK: c-index-api-fn-scan.m:86:5: VarDecl=c:86:12 [Context:c] -// CHECK: c-index-api-fn-scan.m:86:6: ObjCProtocolRef=SubP:86:12 [Context:SubP] -// CHECK: c-index-api-fn-scan.m:86:7: ObjCProtocolRef=SubP:86:12 [Context:SubP] -// CHECK: c-index-api-fn-scan.m:86:8: ObjCProtocolRef=SubP:86:12 [Context:SubP] -// CHECK: c-index-api-fn-scan.m:86:9: ObjCProtocolRef=SubP:86:12 [Context:SubP] -// CHECK: c-index-api-fn-scan.m:86:10: VarDecl=c:86:12 [Context:c] -// CHECK: c-index-api-fn-scan.m:86:12: VarDecl=c:86:12 [Context:c] -// CHECK: c-index-api-fn-scan.m:86:13: VarDecl=c:86:12 [Context:c] -// CHECK: c-index-api-fn-scan.m:86:14: VarDecl=c:86:12 [Context:c] -// CHECK: c-index-api-fn-scan.m:86:15: VarDecl=c:86:12 [Context:c] -// CHECK: c-index-api-fn-scan.m:86:16: ObjCSelectorRef=fooC:25:1 [Context:c] -// CHECK: c-index-api-fn-scan.m:86:17: ObjCSelectorRef=fooC:25:1 [Context:c] -// CHECK: c-index-api-fn-scan.m:86:18: ObjCSelectorRef=fooC:25:1 [Context:c] -// CHECK: c-index-api-fn-scan.m:86:19: ObjCSelectorRef=fooC:25:1 [Context:c] -// CHECK: c-index-api-fn-scan.m:86:20: ObjCSelectorRef=fooC:25:1 [Context:c] -// CHECK: c-index-api-fn-scan.m:86:21: ObjCSelectorRef=fooC:25:1 [Context:c] -// CHECK: c-index-api-fn-scan.m:86:22: ObjCSelectorRef=fooC:25:1 [Context:c] -// CHECK: c-index-api-fn-scan.m:86:23: ObjCSelectorRef=fooC:25:1 [Context:c] -// CHECK: c-index-api-fn-scan.m:86:24: ObjCSelectorRef=fooC:25:1 [Context:c] -// CHECK: c-index-api-fn-scan.m:86:25: ObjCSelectorRef=fooC:25:1 [Context:c] -// CHECK: <invalid loc>:87:2: TypedefDecl=id:0:0 [Context:id] -// CHECK: <invalid loc>:87:3: TypedefDecl=id:0:0 [Context:id] -// CHECK: c-index-api-fn-scan.m:87:5: VarDecl=d:87:13 [Context:d] -// CHECK: c-index-api-fn-scan.m:87:6: ObjCProtocolRef=Proto:87:13 [Context:Proto] -// CHECK: c-index-api-fn-scan.m:87:7: ObjCProtocolRef=Proto:87:13 [Context:Proto] -// CHECK: c-index-api-fn-scan.m:87:8: ObjCProtocolRef=Proto:87:13 [Context:Proto] -// CHECK: c-index-api-fn-scan.m:87:9: ObjCProtocolRef=Proto:87:13 [Context:Proto] -// CHECK: c-index-api-fn-scan.m:87:10: ObjCProtocolRef=Proto:87:13 [Context:Proto] -// CHECK: c-index-api-fn-scan.m:87:11: VarDecl=d:87:13 [Context:d] -// CHECK: c-index-api-fn-scan.m:87:13: VarDecl=d:87:13 [Context:d] -// CHECK: c-index-api-fn-scan.m:88:2: VarRef=d:87:13 [Context:main] -// CHECK: c-index-api-fn-scan.m:88:6: VarRef=c:86:12 [Context:main] -// CHECK: c-index-api-fn-scan.m:89:2: ObjCSelectorRef=pMethod:41:1 [Context:main] -// CHECK: c-index-api-fn-scan.m:89:3: VarRef=d:87:13 [Context:main] -// CHECK: c-index-api-fn-scan.m:89:4: ObjCSelectorRef=pMethod:41:1 [Context:main] -// CHECK: c-index-api-fn-scan.m:89:5: ObjCSelectorRef=pMethod:41:1 [Context:main] -// CHECK: c-index-api-fn-scan.m:89:6: ObjCSelectorRef=pMethod:41:1 [Context:main] -// CHECK: c-index-api-fn-scan.m:89:7: ObjCSelectorRef=pMethod:41:1 [Context:main] -// CHECK: c-index-api-fn-scan.m:89:8: ObjCSelectorRef=pMethod:41:1 [Context:main] -// CHECK: c-index-api-fn-scan.m:89:9: ObjCSelectorRef=pMethod:41:1 [Context:main] -// CHECK: c-index-api-fn-scan.m:89:10: ObjCSelectorRef=pMethod:41:1 [Context:main] -// CHECK: c-index-api-fn-scan.m:89:11: ObjCSelectorRef=pMethod:41:1 [Context:main] -// CHECK: c-index-api-fn-scan.m:89:12: ObjCSelectorRef=pMethod:41:1 [Context:main] -// CHECK: c-index-api-fn-scan.m:90:2: ObjCSelectorRef=catMethodWithFloat::36:1 [Context:main] -// CHECK: c-index-api-fn-scan.m:90:3: VarRef=bee:84:8 [Context:main] -// CHECK: c-index-api-fn-scan.m:90:4: VarRef=bee:84:8 [Context:main] -// CHECK: c-index-api-fn-scan.m:90:5: VarRef=bee:84:8 [Context:main] -// CHECK: c-index-api-fn-scan.m:90:6: ObjCSelectorRef=catMethodWithFloat::36:1 [Context:main] -// CHECK: c-index-api-fn-scan.m:90:7: ObjCSelectorRef=catMethodWithFloat::36:1 [Context:main] -// CHECK: c-index-api-fn-scan.m:90:8: ObjCSelectorRef=catMethodWithFloat::36:1 [Context:main] -// CHECK: c-index-api-fn-scan.m:90:9: ObjCSelectorRef=catMethodWithFloat::36:1 [Context:main] -// CHECK: c-index-api-fn-scan.m:90:10: ObjCSelectorRef=catMethodWithFloat::36:1 [Context:main] -// CHECK: c-index-api-fn-scan.m:90:11: ObjCSelectorRef=catMethodWithFloat::36:1 [Context:main] -// CHECK: c-index-api-fn-scan.m:90:12: ObjCSelectorRef=catMethodWithFloat::36:1 [Context:main] -// CHECK: c-index-api-fn-scan.m:90:13: ObjCSelectorRef=catMethodWithFloat::36:1 [Context:main] -// CHECK: c-index-api-fn-scan.m:90:14: ObjCSelectorRef=catMethodWithFloat::36:1 [Context:main] -// CHECK: c-index-api-fn-scan.m:90:15: ObjCSelectorRef=catMethodWithFloat::36:1 [Context:main] -// CHECK: c-index-api-fn-scan.m:90:16: ObjCSelectorRef=catMethodWithFloat::36:1 [Context:main] -// CHECK: c-index-api-fn-scan.m:90:17: ObjCSelectorRef=catMethodWithFloat::36:1 [Context:main] -// CHECK: c-index-api-fn-scan.m:90:18: ObjCSelectorRef=catMethodWithFloat::36:1 [Context:main] -// CHECK: c-index-api-fn-scan.m:90:19: ObjCSelectorRef=catMethodWithFloat::36:1 [Context:main] -// CHECK: c-index-api-fn-scan.m:90:20: ObjCSelectorRef=catMethodWithFloat::36:1 [Context:main] -// CHECK: c-index-api-fn-scan.m:90:21: ObjCSelectorRef=catMethodWithFloat::36:1 [Context:main] -// CHECK: c-index-api-fn-scan.m:90:22: ObjCSelectorRef=catMethodWithFloat::36:1 [Context:main] -// CHECK: c-index-api-fn-scan.m:90:23: ObjCSelectorRef=catMethodWithFloat::36:1 [Context:main] -// CHECK: c-index-api-fn-scan.m:90:24: ObjCSelectorRef=catMethodWithFloat::36:1 [Context:main] -// CHECK: c-index-api-fn-scan.m:90:25: ObjCSelectorRef=catMethodWithFloat::36:1 [Context:main] -// CHECK: c-index-api-fn-scan.m:90:26: ObjCSelectorRef=floatMethod:37:1 [Context:main] -// CHECK: c-index-api-fn-scan.m:90:27: VarRef=bee:84:8 [Context:main] -// CHECK: c-index-api-fn-scan.m:90:28: VarRef=bee:84:8 [Context:main] -// CHECK: c-index-api-fn-scan.m:90:29: VarRef=bee:84:8 [Context:main] -// CHECK: c-index-api-fn-scan.m:90:30: ObjCSelectorRef=floatMethod:37:1 [Context:main] -// CHECK: c-index-api-fn-scan.m:90:31: ObjCSelectorRef=floatMethod:37:1 [Context:main] -// CHECK: c-index-api-fn-scan.m:90:32: ObjCSelectorRef=floatMethod:37:1 [Context:main] -// CHECK: c-index-api-fn-scan.m:90:33: ObjCSelectorRef=floatMethod:37:1 [Context:main] -// CHECK: c-index-api-fn-scan.m:90:34: ObjCSelectorRef=floatMethod:37:1 [Context:main] -// CHECK: c-index-api-fn-scan.m:90:35: ObjCSelectorRef=floatMethod:37:1 [Context:main] -// CHECK: c-index-api-fn-scan.m:90:36: ObjCSelectorRef=floatMethod:37:1 [Context:main] -// CHECK: c-index-api-fn-scan.m:90:37: ObjCSelectorRef=floatMethod:37:1 [Context:main] -// CHECK: c-index-api-fn-scan.m:90:38: ObjCSelectorRef=floatMethod:37:1 [Context:main] -// CHECK: c-index-api-fn-scan.m:90:39: ObjCSelectorRef=floatMethod:37:1 [Context:main] -// CHECK: c-index-api-fn-scan.m:90:40: ObjCSelectorRef=floatMethod:37:1 [Context:main] -// CHECK: c-index-api-fn-scan.m:90:41: ObjCSelectorRef=floatMethod:37:1 [Context:main] -// CHECK: c-index-api-fn-scan.m:90:42: ObjCSelectorRef=floatMethod:37:1 [Context:main] -// CHECK: c-index-api-fn-scan.m:90:43: ObjCSelectorRef=catMethodWithFloat::36:1 [Context:main] -// CHECK: c-index-api-fn-scan.m:91:3: FunctionRef=main:83:5 [Context:main] -// CHECK: c-index-api-fn-scan.m:91:4: FunctionRef=main:83:5 [Context:main] -// CHECK: c-index-api-fn-scan.m:91:5: FunctionRef=main:83:5 [Context:main] -// CHECK: c-index-api-fn-scan.m:91:6: FunctionRef=main:83:5 [Context:main] -// CHECK: c-index-api-fn-scan.m:91:8: EnumConstantRef=someEnum:58:3 [Context:main] -// CHECK: c-index-api-fn-scan.m:91:9: EnumConstantRef=someEnum:58:3 [Context:main] -// CHECK: c-index-api-fn-scan.m:91:10: EnumConstantRef=someEnum:58:3 [Context:main] -// CHECK: c-index-api-fn-scan.m:91:11: EnumConstantRef=someEnum:58:3 [Context:main] -// CHECK: c-index-api-fn-scan.m:91:12: EnumConstantRef=someEnum:58:3 [Context:main] -// CHECK: c-index-api-fn-scan.m:91:13: EnumConstantRef=someEnum:58:3 [Context:main] -// CHECK: c-index-api-fn-scan.m:91:14: EnumConstantRef=someEnum:58:3 [Context:main] -// CHECK: c-index-api-fn-scan.m:91:15: EnumConstantRef=someEnum:58:3 [Context:main] -// CHECK: c-index-api-fn-scan.m:91:33: VarRef=bee:84:8 [Context:main] -// CHECK: c-index-api-fn-scan.m:91:34: VarRef=bee:84:8 [Context:main] -// CHECK: c-index-api-fn-scan.m:91:35: VarRef=bee:84:8 [Context:main] diff --git a/test/Index/c-index-api-loadTU-test.m b/test/Index/c-index-api-loadTU-test.m index 8a1e4d1..cf0dbff 100644 --- a/test/Index/c-index-api-loadTU-test.m +++ b/test/Index/c-index-api-loadTU-test.m @@ -53,33 +53,79 @@ int main (int argc, const char * argv[]) { main(someEnum, (const char **)bee); } -// CHECK: c-index-api-loadTU-test.m:4:12: ObjCInterfaceDecl=Foo:4:1 [Context=c-index-api-loadTU-test.m] [Extent=4:1:11:4] -// CHECK: c-index-api-loadTU-test.m:8:1: ObjCInstanceMethodDecl=foo:8:1 [Context=Foo] [Extent=8:1:8:6] -// CHECK: c-index-api-loadTU-test.m:9:1: ObjCClassMethodDecl=fooC:9:1 [Context=Foo] [Extent=9:1:9:7] -// CHECK: c-index-api-loadTU-test.m:13:12: ObjCInterfaceDecl=Bar:13:1 [Context=c-index-api-loadTU-test.m] [Extent=13:1:17:4] -// CHECK: c-index-api-loadTU-test.m:13:18: ObjCSuperClassRef=Foo:13:1 [Context=Bar] [Extent=13:1:17:4] -// CHECK: c-index-api-loadTU-test.m:19:1: ObjCCategoryDecl=FooCat:19:1 [Context=c-index-api-loadTU-test.m] [Extent=19:1:22:4] -// CHECK: c-index-api-loadTU-test.m:4:1: ObjCClassRef=Foo:19:1 [Context=FooCat] [Extent=19:1:22:4] -// CHECK: c-index-api-loadTU-test.m:20:1: ObjCInstanceMethodDecl=catMethodWithFloat::20:1 [Context=FooCat] [Extent=20:1:20:40] -// CHECK: c-index-api-loadTU-test.m:21:1: ObjCInstanceMethodDecl=floatMethod:21:1 [Context=FooCat] [Extent=21:1:21:22] -// CHECK: c-index-api-loadTU-test.m:24:1: ObjCProtocolDecl=Proto:24:1 [Context=c-index-api-loadTU-test.m] [Extent=24:1:26:4] -// CHECK: c-index-api-loadTU-test.m:25:1: ObjCInstanceMethodDecl=pMethod:25:1 [Context=Proto] [Extent=25:1:25:10] -// CHECK: c-index-api-loadTU-test.m:28:1: ObjCProtocolDecl=SubP:28:1 [Context=c-index-api-loadTU-test.m] [Extent=28:1:30:4] -// CHECK: c-index-api-loadTU-test.m:24:1: ObjCProtocolRef=Proto:24:1 [Context=SubP] [Extent=24:1:26:4] -// CHECK: c-index-api-loadTU-test.m:29:1: ObjCInstanceMethodDecl=spMethod:29:1 [Context=SubP] [Extent=29:1:29:11] -// CHECK: c-index-api-loadTU-test.m:32:12: ObjCInterfaceDecl=Baz:32:1 [Context=c-index-api-loadTU-test.m] [Extent=32:1:39:4] -// CHECK: c-index-api-loadTU-test.m:32:18: ObjCSuperClassRef=Bar:32:1 [Context=Baz] [Extent=32:1:39:4] -// CHECK: c-index-api-loadTU-test.m:28:1: ObjCProtocolRef=SubP:28:1 [Context=Baz] [Extent=28:1:30:4] -// CHECK: c-index-api-loadTU-test.m:34:9: ObjCIvarDecl=_anIVar:34:9 [Context=Baz] [Extent=34:9:34:15] -// CHECK: c-index-api-loadTU-test.m:37:1: ObjCInstanceMethodDecl=bazMethod:37:1 [Context=Baz] [Extent=37:1:37:20] -// CHECK: c-index-api-loadTU-test.m:41:1: EnumDecl=:41:1 [Context=c-index-api-loadTU-test.m] [Extent=41:1:43:1] -// CHECK: c-index-api-loadTU-test.m:42:3: EnumConstantDecl=someEnum:42:3 [Context=] [Extent=42:3:42:10] -// CHECK: c-index-api-loadTU-test.m:45:5: FunctionDefn=main [Context=c-index-api-loadTU-test.m] [Extent=45:5:54:1] -// CHECK: c-index-api-loadTU-test.m:45:15: ParmDecl=argc:45:15 [Context=main] [Extent=45:15:45:18] -// CHECK: c-index-api-loadTU-test.m:45:34: ParmDecl=argv:45:34 [Context=main] [Extent=45:34:45:37] -// CHECK: c-index-api-loadTU-test.m:46:8: VarDecl=bee:46:8 [Context=main] [Extent=46:8:46:10] -// CHECK: c-index-api-loadTU-test.m:47:5: VarDecl=a:47:5 [Context=main] [Extent=47:5:47:17] -// CHECK: c-index-api-loadTU-test.m:48:12: VarDecl=c:48:12 [Context=main] [Extent=48:12:48:25] -// CHECK: c-index-api-loadTU-test.m:49:13: VarDecl=d:49:13 [Context=main] [Extent=49:13:49:13] - - +// CHECK: <invalid loc>:0:0: TypedefDecl=__int128_t:0:0 (Definition) +// CHECK: <invalid loc>:0:0: TypedefDecl=__uint128_t:0:0 (Definition) +// CHECK: <invalid loc>:0:0: TypedefDecl=SEL:0:0 (Definition) +// CHECK: <invalid loc>:0:0: TypeRef=SEL:0:0 +// CHECK: <invalid loc>:0:0: TypedefDecl=id:0:0 (Definition) +// CHECK: <invalid loc>:0:0: TypedefDecl=Class:0:0 (Definition) +// CHECK: <invalid loc>:87:16: StructDecl=__va_list_tag:87:16 (Definition) +// CHECK: <invalid loc>:87:42: FieldDecl=gp_offset:87:42 (Definition) +// CHECK: <invalid loc>:87:63: FieldDecl=fp_offset:87:63 (Definition) +// CHECK: <invalid loc>:87:81: FieldDecl=overflow_arg_area:87:81 (Definition) +// CHECK: <invalid loc>:87:107: FieldDecl=reg_save_area:87:107 (Definition) +// CHECK: <invalid loc>:87:123: TypedefDecl=__va_list_tag:87:123 (Definition) +// CHECK: <invalid loc>:87:9: TypeRef=struct __va_list_tag:87:16 +// CHECK: <invalid loc>:87:159: TypedefDecl=__builtin_va_list:87:159 (Definition) +// CHECK: <invalid loc>:87:145: TypeRef=__va_list_tag:87:123 +// CHECK: <invalid loc>:87:177: UnexposedExpr= +// CHECK: c-index-api-loadTU-test.m:4:12: ObjCInterfaceDecl=Foo:4:12 [Extent=4:1:11:4] +// CHECK: c-index-api-loadTU-test.m:8:1: ObjCInstanceMethodDecl=foo:8:1 [Extent=8:1:8:6] +// CHECK: c-index-api-loadTU-test.m:9:1: ObjCClassMethodDecl=fooC:9:1 [Extent=9:1:9:7] +// CHECK: c-index-api-loadTU-test.m:13:12: ObjCInterfaceDecl=Bar:13:12 [Extent=13:1:17:4] +// CHECK: c-index-api-loadTU-test.m:13:18: ObjCSuperClassRef=Foo:4:12 [Extent=13:18:13:20] +// CHECK: c-index-api-loadTU-test.m:19:12: ObjCCategoryDecl=FooCat:19:12 [Extent=19:1:22:4] +// CHECK: c-index-api-loadTU-test.m:19:12: ObjCClassRef=Foo:4:12 [Extent=19:12:19:14] +// CHECK: c-index-api-loadTU-test.m:20:1: ObjCInstanceMethodDecl=catMethodWithFloat::20:1 [Extent=20:1:20:40] +// CHECK: c-index-api-loadTU-test.m:20:36: ParmDecl=fArg:20:36 (Definition) [Extent=20:29:20:39] +// CHECK: c-index-api-loadTU-test.m:21:1: ObjCInstanceMethodDecl=floatMethod:21:1 [Extent=21:1:21:22] +// CHECK: c-index-api-loadTU-test.m:24:1: ObjCProtocolDecl=Proto:24:1 (Definition) [Extent=24:1:26:4] +// CHECK: c-index-api-loadTU-test.m:25:1: ObjCInstanceMethodDecl=pMethod:25:1 [Extent=25:1:25:10] +// CHECK: c-index-api-loadTU-test.m:28:1: ObjCProtocolDecl=SubP:28:1 (Definition) [Extent=28:1:30:4] +// CHECK: c-index-api-loadTU-test.m:28:17: ObjCProtocolRef=Proto:24:1 [Extent=28:17:28:21] +// CHECK: c-index-api-loadTU-test.m:29:1: ObjCInstanceMethodDecl=spMethod:29:1 [Extent=29:1:29:11] +// CHECK: c-index-api-loadTU-test.m:32:12: ObjCInterfaceDecl=Baz:32:12 [Extent=32:1:39:4] +// CHECK: c-index-api-loadTU-test.m:32:18: ObjCSuperClassRef=Bar:13:12 [Extent=32:18:32:20] +// CHECK: c-index-api-loadTU-test.m:32:23: ObjCProtocolRef=SubP:28:1 [Extent=32:23:32:26] +// CHECK: c-index-api-loadTU-test.m:34:9: ObjCIvarDecl=_anIVar:34:9 (Definition) [Extent=34:9:34:15] +// CHECK: c-index-api-loadTU-test.m:37:1: ObjCInstanceMethodDecl=bazMethod:37:1 [Extent=37:1:37:20] +// CHECK: c-index-api-loadTU-test.m:41:1: EnumDecl=:41:1 (Definition) [Extent=41:1:43:1] +// CHECK: c-index-api-loadTU-test.m:42:3: EnumConstantDecl=someEnum:42:3 (Definition) [Extent=42:3:42:10] +// CHECK: c-index-api-loadTU-test.m:45:5: FunctionDecl=main:45:5 (Definition) [Extent=45:5:54:1] +// CHECK: c-index-api-loadTU-test.m:45:15: ParmDecl=argc:45:15 (Definition) [Extent=45:11:45:18] +// CHECK: c-index-api-loadTU-test.m:45:34: ParmDecl=argv:45:34 (Definition) [Extent=45:27:45:37] +// CHECK: c-index-api-loadTU-test.m:45:5: UnexposedStmt=main [Extent=45:42:54:1] +// CHECK: c-index-api-loadTU-test.m:45:5: UnexposedStmt=main [Extent=46:2:46:11] +// CHECK: c-index-api-loadTU-test.m:46:8: VarDecl=bee:46:8 (Definition) [Extent=46:2:46:10] +// CHECK: c-index-api-loadTU-test.m:46:2: ObjCClassRef=Baz:32:12 [Extent=46:2:46:4] +// CHECK: c-index-api-loadTU-test.m:46:8: UnexposedStmt=bee [Extent=47:2:47:18] +// CHECK: c-index-api-loadTU-test.m:47:5: VarDecl=a:47:5 (Definition) [Extent=47:2:47:17] +// CHECK: c-index-api-loadTU-test.m:47:2: TypeRef=id:0:0 [Extent=47:2:47:3] +// CHECK: c-index-api-loadTU-test.m:47:9: ObjCMessageExpr=foo:8:1 [Extent=47:9:47:17] +// CHECK: c-index-api-loadTU-test.m:47:10: DeclRefExpr=bee:46:8 [Extent=47:10:47:12] +// CHECK: c-index-api-loadTU-test.m:47:5: UnexposedStmt=a [Extent=48:2:48:26] +// CHECK: c-index-api-loadTU-test.m:48:12: VarDecl=c:48:12 (Definition) [Extent=48:2:48:25] +// CHECK: c-index-api-loadTU-test.m:48:2: TypeRef=id:0:0 [Extent=48:2:48:3] +// CHECK: c-index-api-loadTU-test.m:48:6: ObjCProtocolRef=SubP:28:1 [Extent=48:6:48:9] +// CHECK: c-index-api-loadTU-test.m:48:16: UnexposedExpr=fooC:9:1 [Extent=48:16:48:25] +// CHECK: c-index-api-loadTU-test.m:48:16: ObjCMessageExpr=fooC:9:1 [Extent=48:16:48:25] +// CHECK: c-index-api-loadTU-test.m:48:12: UnexposedStmt=c [Extent=49:2:49:14] +// CHECK: c-index-api-loadTU-test.m:49:13: VarDecl=d:49:13 (Definition) [Extent=49:2:49:13] +// CHECK: c-index-api-loadTU-test.m:49:2: TypeRef=id:0:0 [Extent=49:2:49:3] +// CHECK: c-index-api-loadTU-test.m:49:6: ObjCProtocolRef=Proto:24:1 [Extent=49:6:49:10] +// CHECK: c-index-api-loadTU-test.m:50:2: UnexposedExpr= [Extent=50:2:50:6] +// CHECK: c-index-api-loadTU-test.m:50:2: DeclRefExpr=d:49:13 [Extent=50:2:50:2] +// CHECK: c-index-api-loadTU-test.m:50:6: UnexposedExpr=c:48:12 [Extent=50:6:50:6] +// CHECK: c-index-api-loadTU-test.m:50:6: DeclRefExpr=c:48:12 [Extent=50:6:50:6] +// CHECK: c-index-api-loadTU-test.m:51:2: ObjCMessageExpr=pMethod:25:1 [Extent=51:2:51:12] +// CHECK: c-index-api-loadTU-test.m:51:3: DeclRefExpr=d:49:13 [Extent=51:3:51:3] +// CHECK: c-index-api-loadTU-test.m:52:2: ObjCMessageExpr=catMethodWithFloat::20:1 [Extent=52:2:52:43] +// CHECK: c-index-api-loadTU-test.m:52:3: DeclRefExpr=bee:46:8 [Extent=52:3:52:5] +// CHECK: c-index-api-loadTU-test.m:52:26: ObjCMessageExpr=floatMethod:21:1 [Extent=52:26:52:42] +// CHECK: c-index-api-loadTU-test.m:52:27: DeclRefExpr=bee:46:8 [Extent=52:27:52:29] +// CHECK: c-index-api-loadTU-test.m:53:3: CallExpr=main:45:5 [Extent=53:3:53:36] +// CHECK: c-index-api-loadTU-test.m:53:3: UnexposedExpr=main:45:5 [Extent=53:3:53:6] +// CHECK: c-index-api-loadTU-test.m:53:3: DeclRefExpr=main:45:5 [Extent=53:3:53:6] +// CHECK: c-index-api-loadTU-test.m:53:8: DeclRefExpr=someEnum:42:3 [Extent=53:8:53:15] +// CHECK: c-index-api-loadTU-test.m:53:18: UnexposedExpr=bee:46:8 [Extent=53:18:53:35] +// CHECK: c-index-api-loadTU-test.m:53:33: DeclRefExpr=bee:46:8 [Extent=53:33:53:35] diff --git a/test/Index/c-index-getCursor-test.m b/test/Index/c-index-getCursor-test.m index 03ab5a8..8fb7ffc 100644 --- a/test/Index/c-index-getCursor-test.m +++ b/test/Index/c-index-getCursor-test.m @@ -53,108 +53,101 @@ int main (int argc, const char * argv[]) { } // CHECK: {start_line=1 start_col=1 end_line=2 end_col=62} Invalid Cursor => NoDeclFound -// CHECK: {start_line=3 start_col=1 end_line=6 end_col=1} ObjCInterfaceDecl=Foo:3:1 +// CHECK: {start_line=3 start_col=1 end_line=6 end_col=1} ObjCInterfaceDecl=Foo:3:12 // CHECK: {start_line=7 start_col=1 end_line=7 end_col=6} ObjCInstanceMethodDecl=foo:7:1 -// CHECK: {start_line=7 start_col=7 end_line=7 end_col=7} ObjCInterfaceDecl=Foo:3:1 +// CHECK: {start_line=7 start_col=7 end_line=7 end_col=7} ObjCInterfaceDecl=Foo:3:12 // CHECK: {start_line=8 start_col=1 end_line=8 end_col=7} ObjCClassMethodDecl=fooC:8:1 -// CHECK: {start_line=8 start_col=8 end_line=10 end_col=4} ObjCInterfaceDecl=Foo:3:1 +// CHECK: {start_line=8 start_col=8 end_line=10 end_col=4} ObjCInterfaceDecl=Foo:3:12 // CHECK: {start_line=10 start_col=5 end_line=11 end_col=1} Invalid Cursor => NoDeclFound -// CHECK: {start_line=12 start_col=1 end_line=16 end_col=4} ObjCInterfaceDecl=Bar:12:1 +// CHECK: {start_line=12 start_col=1 end_line=12 end_col=17} ObjCInterfaceDecl=Bar:12:12 +// CHECK: {start_line=12 start_col=18 end_line=12 end_col=20} ObjCSuperClassRef=Foo:3:12 +// CHECK: {start_line=12 start_col=21 end_line=16 end_col=4} ObjCInterfaceDecl=Bar:12:12 // CHECK: {start_line=16 start_col=5 end_line=17 end_col=1} Invalid Cursor => NoDeclFound -// CHECK: {start_line=18 start_col=1 end_line=18 end_col=24} ObjCCategoryDecl=FooCat:18:1 +// CHECK: {start_line=18 start_col=1 end_line=18 end_col=11} ObjCCategoryDecl=FooCat:18:12 +// CHECK: {start_line=18 start_col=12 end_line=18 end_col=14} ObjCClassRef=Foo:3:12 +// CHECK: {start_line=18 start_col=15 end_line=18 end_col=24} ObjCCategoryDecl=FooCat:18:12 // CHECK: {start_line=19 start_col=1 end_line=19 end_col=28} ObjCInstanceMethodDecl=catMethodWithFloat::19:1 -// CHECK: {start_line=19 start_col=29 end_line=19 end_col=33} ParmDecl=fArg:19:36 -// CHECK: {start_line=19 start_col=34 end_line=19 end_col=35} ObjCInstanceMethodDecl=catMethodWithFloat::19:1 -// CHECK: {start_line=19 start_col=36 end_line=19 end_col=39} ParmDecl=fArg:19:36 +// CHECK: {start_line=19 start_col=29 end_line=19 end_col=39} ParmDecl=fArg:19:36 (Definition) // CHECK: {start_line=19 start_col=40 end_line=19 end_col=40} ObjCInstanceMethodDecl=catMethodWithFloat::19:1 -// CHECK: {start_line=19 start_col=41 end_line=19 end_col=41} ObjCCategoryDecl=FooCat:18:1 +// CHECK: {start_line=19 start_col=41 end_line=19 end_col=41} ObjCCategoryDecl=FooCat:18:12 // CHECK: {start_line=20 start_col=1 end_line=20 end_col=22} ObjCInstanceMethodDecl=floatMethod:20:1 -// CHECK: {start_line=20 start_col=23 end_line=21 end_col=4} ObjCCategoryDecl=FooCat:18:1 +// CHECK: {start_line=20 start_col=23 end_line=21 end_col=4} ObjCCategoryDecl=FooCat:18:12 // CHECK: {start_line=21 start_col=5 end_line=22 end_col=1} Invalid Cursor => NoDeclFound -// CHECK: {start_line=23 start_col=1 end_line=23 end_col=16} ObjCProtocolDecl=Proto:23:1 +// CHECK: {start_line=23 start_col=1 end_line=23 end_col=16} ObjCProtocolDecl=Proto:23:1 (Definition) // CHECK: {start_line=24 start_col=1 end_line=24 end_col=10} ObjCInstanceMethodDecl=pMethod:24:1 -// CHECK: {start_line=24 start_col=11 end_line=25 end_col=4} ObjCProtocolDecl=Proto:23:1 +// CHECK: {start_line=24 start_col=11 end_line=25 end_col=4} ObjCProtocolDecl=Proto:23:1 (Definition) // CHECK: {start_line=25 start_col=5 end_line=26 end_col=1} Invalid Cursor => NoDeclFound -// CHECK: {start_line=27 start_col=1 end_line=27 end_col=23} ObjCProtocolDecl=SubP:27:1 +// CHECK: {start_line=27 start_col=1 end_line=27 end_col=16} ObjCProtocolDecl=SubP:27:1 (Definition) +// CHECK: {start_line=27 start_col=17 end_line=27 end_col=21} ObjCProtocolRef=Proto:23:1 +// CHECK: {start_line=27 start_col=22 end_line=27 end_col=23} ObjCProtocolDecl=SubP:27:1 (Definition) // CHECK: {start_line=28 start_col=1 end_line=28 end_col=11} ObjCInstanceMethodDecl=spMethod:28:1 -// CHECK: {start_line=28 start_col=12 end_line=29 end_col=4} ObjCProtocolDecl=SubP:27:1 +// CHECK: {start_line=28 start_col=12 end_line=29 end_col=4} ObjCProtocolDecl=SubP:27:1 (Definition) // CHECK: {start_line=29 start_col=5 end_line=30 end_col=1} Invalid Cursor => NoDeclFound -// CHECK: {start_line=31 start_col=1 end_line=33 end_col=4} ObjCInterfaceDecl=Baz:31:1 -// CHECK: {start_line=33 start_col=5 end_line=33 end_col=7} Invalid Cursor => NotImplemented -// CHECK: {start_line=33 start_col=8 end_line=33 end_col=8} ObjCInterfaceDecl=Baz:31:1 -// CHECK: {start_line=33 start_col=9 end_line=33 end_col=15} Invalid Cursor => NotImplemented -// CHECK: {start_line=33 start_col=16 end_line=35 end_col=1} ObjCInterfaceDecl=Baz:31:1 +// CHECK: {start_line=31 start_col=1 end_line=31 end_col=17} ObjCInterfaceDecl=Baz:31:12 +// CHECK: {start_line=31 start_col=18 end_line=31 end_col=20} ObjCSuperClassRef=Bar:12:12 +// CHECK: {start_line=31 start_col=21 end_line=31 end_col=22} ObjCInterfaceDecl=Baz:31:12 +// CHECK: {start_line=31 start_col=23 end_line=31 end_col=26} ObjCProtocolRef=SubP:27:1 +// CHECK: {start_line=31 start_col=27 end_line=33 end_col=8} ObjCInterfaceDecl=Baz:31:12 +// CHECK: {start_line=33 start_col=9 end_line=33 end_col=15} ObjCIvarDecl=_anIVar:33:9 (Definition) +// CHECK: {start_line=33 start_col=16 end_line=35 end_col=1} ObjCInterfaceDecl=Baz:31:12 // CHECK: {start_line=36 start_col=1 end_line=36 end_col=20} ObjCInstanceMethodDecl=bazMethod:36:1 -// CHECK: {start_line=36 start_col=21 end_line=38 end_col=4} ObjCInterfaceDecl=Baz:31:1 +// CHECK: {start_line=36 start_col=21 end_line=38 end_col=4} ObjCInterfaceDecl=Baz:31:12 // CHECK: {start_line=38 start_col=5 end_line=39 end_col=1} Invalid Cursor => NoDeclFound -// CHECK: {start_line=40 start_col=1 end_line=41 end_col=2} EnumDecl=:40:1 -// CHECK: {start_line=41 start_col=3 end_line=41 end_col=10} EnumConstantDecl=someEnum:41:3 -// CHECK: {start_line=41 start_col=11 end_line=42 end_col=1} EnumDecl=:40:1 -// CHECK: {start_line=42 start_col=2 end_line=43 end_col=1} Invalid Cursor => NoDeclFound -// CHECK: {start_line=44 start_col=1 end_line=44 end_col=3} FunctionDecl=main:44:5 -// CHECK: {start_line=44 start_col=4 end_line=44 end_col=4} Invalid Cursor => NoDeclFound -// CHECK: {start_line=44 start_col=5 end_line=44 end_col=10} FunctionDecl=main:44:5 -// CHECK: {start_line=44 start_col=11 end_line=44 end_col=13} ParmDecl=argc:44:15 -// CHECK: {start_line=44 start_col=14 end_line=44 end_col=14} FunctionDecl=main:44:5 -// CHECK: {start_line=44 start_col=15 end_line=44 end_col=18} ParmDecl=argc:44:15 -// CHECK: {start_line=44 start_col=19 end_line=44 end_col=26} FunctionDecl=main:44:5 -// CHECK: {start_line=44 start_col=27 end_line=44 end_col=30} ParmDecl=argv:44:34 -// CHECK: {start_line=44 start_col=31 end_line=44 end_col=31} FunctionDecl=main:44:5 -// CHECK: {start_line=44 start_col=32 end_line=44 end_col=32} ParmDecl=argv:44:34 -// CHECK: {start_line=44 start_col=33 end_line=44 end_col=33} FunctionDecl=main:44:5 -// CHECK: {start_line=44 start_col=34 end_line=44 end_col=39} ParmDecl=argv:44:34 -// CHECK: {start_line=44 start_col=40 end_line=45 end_col=1} FunctionDecl=main:44:5 -// CHECK: {start_line=45 start_col=2 end_line=45 end_col=4} ObjCClassRef=Baz:45:8 -// CHECK: {start_line=45 start_col=5 end_line=45 end_col=5} FunctionDecl=main:44:5 -// CHECK: {start_line=45 start_col=6 end_line=45 end_col=6} VarDecl=bee:45:8 -// CHECK: {start_line=45 start_col=7 end_line=45 end_col=7} FunctionDecl=main:44:5 -// CHECK: {start_line=45 start_col=8 end_line=45 end_col=10} VarDecl=bee:45:8 -// CHECK: {start_line=45 start_col=11 end_line=46 end_col=1} FunctionDecl=main:44:5 -// CHECK: {start_line=46 start_col=2 end_line=46 end_col=3} TypedefDecl=id:0:0 -// CHECK: {start_line=46 start_col=4 end_line=46 end_col=4} FunctionDecl=main:44:5 -// CHECK: {start_line=46 start_col=5 end_line=46 end_col=8} VarDecl=a:46:5 -// CHECK: {start_line=46 start_col=9 end_line=46 end_col=9} ObjCSelectorRef=foo:7:1 -// CHECK: {start_line=46 start_col=10 end_line=46 end_col=12} VarRef=bee:45:8 -// CHECK: {start_line=46 start_col=13 end_line=46 end_col=17} ObjCSelectorRef=foo:7:1 -// CHECK: {start_line=46 start_col=18 end_line=47 end_col=1} FunctionDecl=main:44:5 -// CHECK: {start_line=47 start_col=2 end_line=47 end_col=3} TypedefDecl=id:0:0 -// CHECK: {start_line=47 start_col=4 end_line=47 end_col=4} FunctionDecl=main:44:5 -// CHECK: {start_line=47 start_col=5 end_line=47 end_col=5} VarDecl=c:47:12 -// CHECK: {start_line=47 start_col=6 end_line=47 end_col=9} ObjCProtocolRef=SubP:47:12 -// CHECK: {start_line=47 start_col=10 end_line=47 end_col=10} VarDecl=c:47:12 -// CHECK: {start_line=47 start_col=11 end_line=47 end_col=11} FunctionDecl=main:44:5 -// CHECK: {start_line=47 start_col=12 end_line=47 end_col=15} VarDecl=c:47:12 -// CHECK: {start_line=47 start_col=16 end_line=47 end_col=25} ObjCSelectorRef=fooC:8:1 -// CHECK: {start_line=47 start_col=26 end_line=48 end_col=1} FunctionDecl=main:44:5 -// CHECK: {start_line=48 start_col=2 end_line=48 end_col=3} TypedefDecl=id:0:0 -// CHECK: {start_line=48 start_col=4 end_line=48 end_col=4} FunctionDecl=main:44:5 -// CHECK: {start_line=48 start_col=5 end_line=48 end_col=5} VarDecl=d:48:13 -// CHECK: {start_line=48 start_col=6 end_line=48 end_col=10} ObjCProtocolRef=Proto:48:13 -// CHECK: {start_line=48 start_col=11 end_line=48 end_col=11} VarDecl=d:48:13 -// CHECK: {start_line=48 start_col=12 end_line=48 end_col=12} FunctionDecl=main:44:5 -// CHECK: {start_line=48 start_col=13 end_line=48 end_col=13} VarDecl=d:48:13 -// CHECK: {start_line=48 start_col=14 end_line=49 end_col=1} FunctionDecl=main:44:5 -// CHECK: {start_line=49 start_col=2 end_line=49 end_col=2} VarRef=d:48:13 -// CHECK: {start_line=49 start_col=3 end_line=49 end_col=5} FunctionDecl=main:44:5 -// CHECK: {start_line=49 start_col=6 end_line=49 end_col=6} VarRef=c:47:12 -// CHECK: {start_line=49 start_col=7 end_line=50 end_col=1} FunctionDecl=main:44:5 -// CHECK: {start_line=50 start_col=2 end_line=50 end_col=2} ObjCSelectorRef=pMethod:24:1 -// CHECK: {start_line=50 start_col=3 end_line=50 end_col=3} VarRef=d:48:13 -// CHECK: {start_line=50 start_col=4 end_line=50 end_col=12} ObjCSelectorRef=pMethod:24:1 -// CHECK: {start_line=50 start_col=13 end_line=51 end_col=1} FunctionDecl=main:44:5 -// CHECK: {start_line=51 start_col=2 end_line=51 end_col=2} ObjCSelectorRef=catMethodWithFloat::19:1 -// CHECK: {start_line=51 start_col=3 end_line=51 end_col=5} VarRef=bee:45:8 -// CHECK: {start_line=51 start_col=6 end_line=51 end_col=25} ObjCSelectorRef=catMethodWithFloat::19:1 -// CHECK: {start_line=51 start_col=26 end_line=51 end_col=26} ObjCSelectorRef=floatMethod:20:1 -// CHECK: {start_line=51 start_col=27 end_line=51 end_col=29} VarRef=bee:45:8 -// CHECK: {start_line=51 start_col=30 end_line=51 end_col=42} ObjCSelectorRef=floatMethod:20:1 -// CHECK: {start_line=51 start_col=43 end_line=51 end_col=43} ObjCSelectorRef=catMethodWithFloat::19:1 -// CHECK: {start_line=51 start_col=44 end_line=52 end_col=2} FunctionDecl=main:44:5 -// CHECK: {start_line=52 start_col=3 end_line=52 end_col=6} FunctionRef=main:44:5 -// CHECK: {start_line=52 start_col=7 end_line=52 end_col=7} FunctionDecl=main:44:5 -// CHECK: {start_line=52 start_col=8 end_line=52 end_col=15} EnumConstantRef=someEnum:41:3 -// CHECK: {start_line=52 start_col=16 end_line=52 end_col=32} FunctionDecl=main:44:5 -// CHECK: {start_line=52 start_col=33 end_line=52 end_col=35} VarRef=bee:45:8 -// CHECK: {start_line=52 start_col=36 end_line=53 end_col=1} FunctionDecl=main:44:5 -// CHECK: {start_line=53 start_col=2 end_line=160 end_col=1} Invalid Cursor => NoDeclFound - +// CHECK: {start_line=40 start_col=1 end_line=41 end_col=2} EnumDecl=:40:1 (Definition) +// CHECK: {start_line=41 start_col=3 end_line=41 end_col=10} EnumConstantDecl=someEnum:41:3 (Definition) +// CHECK: {start_line=41 start_col=11 end_line=42 end_col=1} EnumDecl=:40:1 (Definition) +// CHECK: {start_line=42 start_col=2 end_line=44 end_col=4} Invalid Cursor => NoDeclFound +// CHECK: {start_line=44 start_col=5 end_line=44 end_col=10} FunctionDecl=main:44:5 (Definition) +// CHECK: {start_line=44 start_col=11 end_line=44 end_col=18} ParmDecl=argc:44:15 (Definition) +// CHECK: {start_line=44 start_col=19 end_line=44 end_col=26} FunctionDecl=main:44:5 (Definition) +// CHECK: {start_line=44 start_col=27 end_line=44 end_col=37} ParmDecl=argv:44:34 (Definition) +// CHECK: {start_line=44 start_col=38 end_line=44 end_col=41} FunctionDecl=main:44:5 (Definition) +// CHECK: {start_line=44 start_col=42 end_line=45 end_col=1} UnexposedStmt=main +// CHECK: {start_line=45 start_col=2 end_line=45 end_col=4} ObjCClassRef=Baz:31:12 +// CHECK: {start_line=45 start_col=5 end_line=45 end_col=10} VarDecl=bee:45:8 (Definition) +// CHECK: {start_line=45 start_col=11 end_line=45 end_col=11} UnexposedStmt=main +// CHECK: {start_line=45 start_col=12 end_line=46 end_col=1} UnexposedStmt=main +// CHECK: {start_line=46 start_col=2 end_line=46 end_col=3} TypeRef=id:0:0 +// CHECK: {start_line=46 start_col=4 end_line=46 end_col=8} VarDecl=a:46:5 (Definition) +// CHECK: {start_line=46 start_col=9 end_line=46 end_col=9} ObjCMessageExpr=foo:7:1 +// CHECK: {start_line=46 start_col=10 end_line=46 end_col=12} DeclRefExpr=bee:45:8 +// CHECK: {start_line=46 start_col=13 end_line=46 end_col=17} ObjCMessageExpr=foo:7:1 +// CHECK: {start_line=46 start_col=18 end_line=46 end_col=18} UnexposedStmt=main +// CHECK: {start_line=46 start_col=19 end_line=47 end_col=1} UnexposedStmt=main +// CHECK: {start_line=47 start_col=2 end_line=47 end_col=3} TypeRef=id:0:0 +// CHECK: {start_line=47 start_col=4 end_line=47 end_col=5} VarDecl=c:47:12 (Definition) +// CHECK: {start_line=47 start_col=6 end_line=47 end_col=9} ObjCProtocolRef=SubP:27:1 +// CHECK: {start_line=47 start_col=10 end_line=47 end_col=15} VarDecl=c:47:12 (Definition) +// CHECK: {start_line=47 start_col=16 end_line=47 end_col=25} ObjCMessageExpr=fooC:8:1 +// CHECK: {start_line=47 start_col=26 end_line=47 end_col=26} UnexposedStmt=main +// CHECK: {start_line=47 start_col=27 end_line=48 end_col=1} UnexposedStmt=main +// CHECK: {start_line=48 start_col=2 end_line=48 end_col=3} TypeRef=id:0:0 +// CHECK: {start_line=48 start_col=4 end_line=48 end_col=5} VarDecl=d:48:13 (Definition) +// CHECK: {start_line=48 start_col=6 end_line=48 end_col=10} ObjCProtocolRef=Proto:23:1 +// CHECK: {start_line=48 start_col=11 end_line=48 end_col=13} VarDecl=d:48:13 (Definition) +// CHECK: {start_line=48 start_col=14 end_line=48 end_col=14} UnexposedStmt=main +// CHECK: {start_line=48 start_col=15 end_line=49 end_col=1} UnexposedStmt=main +// CHECK: {start_line=49 start_col=2 end_line=49 end_col=2} DeclRefExpr=d:48:13 +// CHECK: {start_line=49 start_col=3 end_line=49 end_col=5} UnexposedExpr= +// CHECK: {start_line=49 start_col=6 end_line=49 end_col=6} DeclRefExpr=c:47:12 +// CHECK: {start_line=49 start_col=7 end_line=50 end_col=1} UnexposedStmt=main +// CHECK: {start_line=50 start_col=2 end_line=50 end_col=2} ObjCMessageExpr=pMethod:24:1 +// CHECK: {start_line=50 start_col=3 end_line=50 end_col=3} DeclRefExpr=d:48:13 +// CHECK: {start_line=50 start_col=4 end_line=50 end_col=12} ObjCMessageExpr=pMethod:24:1 +// CHECK: {start_line=50 start_col=13 end_line=51 end_col=1} UnexposedStmt=main +// CHECK: {start_line=51 start_col=2 end_line=51 end_col=2} ObjCMessageExpr=catMethodWithFloat::19:1 +// CHECK: {start_line=51 start_col=3 end_line=51 end_col=5} DeclRefExpr=bee:45:8 +// CHECK: {start_line=51 start_col=6 end_line=51 end_col=25} ObjCMessageExpr=catMethodWithFloat::19:1 +// CHECK: {start_line=51 start_col=26 end_line=51 end_col=26} ObjCMessageExpr=floatMethod:20:1 +// CHECK: {start_line=51 start_col=27 end_line=51 end_col=29} DeclRefExpr=bee:45:8 +// CHECK: {start_line=51 start_col=30 end_line=51 end_col=42} ObjCMessageExpr=floatMethod:20:1 +// CHECK: {start_line=51 start_col=43 end_line=51 end_col=43} ObjCMessageExpr=catMethodWithFloat::19:1 +// CHECK: {start_line=51 start_col=44 end_line=52 end_col=2} UnexposedStmt=main +// CHECK: {start_line=52 start_col=3 end_line=52 end_col=6} DeclRefExpr=main:44:5 +// CHECK: {start_line=52 start_col=7 end_line=52 end_col=7} CallExpr=main:44:5 +// CHECK: {start_line=52 start_col=8 end_line=52 end_col=15} DeclRefExpr=someEnum:41:3 +// CHECK: {start_line=52 start_col=16 end_line=52 end_col=17} CallExpr=main:44:5 +// CHECK: {start_line=52 start_col=18 end_line=52 end_col=32} UnexposedExpr=bee:45:8 +// CHECK: {start_line=52 start_col=33 end_line=52 end_col=35} DeclRefExpr=bee:45:8 +// CHECK: {start_line=52 start_col=36 end_line=52 end_col=36} CallExpr=main:44:5 +// CHECK: {start_line=52 start_col=37 end_line=53 end_col=1} UnexposedStmt=main diff --git a/test/Index/cindex-from-source.m b/test/Index/cindex-from-source.m index e775bb7..8f79304 100644 --- a/test/Index/cindex-from-source.m +++ b/test/Index/cindex-from-source.m @@ -2,8 +2,8 @@ // RUN: %clang -x objective-c-header %t.pfx.h -o %t.pfx.h.gch // RUN: c-index-test -test-load-source local %s -include %t.pfx.h > %t // RUN: FileCheck %s < %t -// CHECK: cindex-from-source.m:{{.*}}:{{.*}}: StructDecl=s0:{{.*}}:{{.*}} [Context=cindex-from-source.m] -// CHECK: cindex-from-source.m:{{.*}}:{{.*}}: VarDecl=g0:{{.*}}:{{.*}} [Context=cindex-from-source.m] - +// CHECK: cindex-from-source.m:{{.*}}:{{.*}}: StructDecl=s0:{{.*}}:{{.*}} +// CHECK: cindex-from-source.m:{{.*}}:{{.*}}: VarDecl=g0:{{.*}}:{{.*}} +// CHECK: cindex-from-source.m:9:1: TypeRef=t0:1:13 [Extent=9:1:9:2] struct s0 {}; t0 g0; diff --git a/test/Index/comments.c b/test/Index/comments.c deleted file mode 100644 index 0343177..0000000 --- a/test/Index/comments.c +++ /dev/null @@ -1,34 +0,0 @@ -// Run lines are sensitive to line numbers and come below the code. - -//! It all starts here. -/*! It's a little odd to continue line this, - * - * but we need more multi-line comments. */ -/// This comment comes before my other comments -/** This is a block comment that is associated with the function f. It - * runs for three lines. - */ -void f(int, int); - -// NOT IN THE COMMENT -/// This is a BCPL comment that is associated with the function g. -/// It has only two lines. -/** But there are other blocks that are part of the comment, too. */ -void g(int); - -void h(int); ///< This is a member comment. - - -// RUN: %clang_cc1 -emit-pch -o %t.ast %s - -// RUN: index-test %t.ast -point-at %s:11:6 > %t -// RUN: grep "starts here" %t -// RUN: grep "block comment" %t - -// RUN: index-test %t.ast -point-at %s:17:6 > %t -// RUN: grep "BCPL" %t -// RUN: grep "But" %t - -// RUN: index-test %t.ast -point-at %s:19:6 > %t -// RUN: grep "NOT" %t | count 0 -// RUN: grep "member" %t diff --git a/test/Index/find-decls.c b/test/Index/find-decls.c deleted file mode 100644 index f1999b2..0000000 --- a/test/Index/find-decls.c +++ /dev/null @@ -1,25 +0,0 @@ -// RUN: %clang_cc1 -fblocks -emit-pch %S/Inputs/t1.c -o %t1.ast -// RUN: %clang_cc1 -fblocks -emit-pch %S/Inputs/t2.c -o %t2.ast - -// RUN: index-test %t1.ast %t2.ast -point-at %S/Inputs/t1.c:8:7 -print-decls > %t -// RUN: cat %t | count 3 -// RUN: grep 'foo.h:4:6,' %t | count 2 -// RUN: grep 't2.c:5:6,' %t - -// RUN: index-test %t1.ast %t2.ast -point-at %S/Inputs/t1.c:5:47 -print-decls > %t -// RUN: cat %t | count 1 -// RUN: grep 't1.c:5:12,' %t - -// RUN: index-test %t1.ast %t2.ast -point-at %S/Inputs/t1.c:6:20 -print-decls > %t -// RUN: cat %t | count 1 -// RUN: grep 't1.c:3:19,' %t - -// field test - -// RUN: index-test %t1.ast %t2.ast -point-at %S/Inputs/t1.c:21:6 -print-decls > %t -// RUN: cat %t | count 1 -// RUN: grep 't1.c:12:7,' %t - -// RUN: index-test %t1.ast %t2.ast -point-at %S/Inputs/t1.c:22:21 -print-decls > %t -// RUN: cat %t | count 1 -// RUN: grep 't1.c:16:7,' %t diff --git a/test/Index/find-defs.c b/test/Index/find-defs.c deleted file mode 100644 index 5129270..0000000 --- a/test/Index/find-defs.c +++ /dev/null @@ -1,18 +0,0 @@ -// RUN: %clang_cc1 -fblocks -emit-pch %S/Inputs/t1.c -o %t1.ast -// RUN: %clang_cc1 -fblocks -emit-pch %S/Inputs/t2.c -o %t2.ast - -// RUN: index-test %t1.ast %t2.ast -point-at %S/Inputs/foo.h:1:14 -print-defs > %t -// RUN: cat %t | count 1 -// RUN: grep 't2.c:3:5,' %t - -// RUN: index-test %t1.ast %t2.ast -point-at %S/Inputs/foo.h:3:9 -print-defs > %t -// RUN: cat %t | count 1 -// RUN: grep 't1.c:3:6,' %t - -// RUN: index-test %t1.ast %t2.ast -point-at %S/Inputs/foo.h:4:9 -print-defs > %t -// RUN: cat %t | count 1 -// RUN: grep 't2.c:5:6,' %t - -// RUN: index-test %t1.ast %t2.ast -point-at %S/Inputs/t1.c:8:7 -print-defs > %t -// RUN: cat %t | count 1 -// RUN: grep 't2.c:5:6,' %t diff --git a/test/Index/find-refs.c b/test/Index/find-refs.c deleted file mode 100644 index 1f29a77..0000000 --- a/test/Index/find-refs.c +++ /dev/null @@ -1,47 +0,0 @@ -// RUN: %clang_cc1 -fblocks -emit-pch %S/Inputs/t1.c -o %t1.ast -// RUN: %clang_cc1 -fblocks -emit-pch %S/Inputs/t2.c -o %t2.ast - -// RUN: index-test %t1.ast %t2.ast -point-at %S/Inputs/foo.h:1:14 -print-refs > %t -// RUN: cat %t | count 4 -// RUN: grep 't1.c:4:19,' %t -// RUN: grep 't1.c:28:40,' %t -// RUN: grep 't2.c:6:3,' %t -// RUN: grep 't2.c:7:12,' %t - -// RUN: index-test %t1.ast %t2.ast -point-at %S/Inputs/foo.h:3:9 -print-refs > %t -// RUN: cat %t | count 1 -// RUN: grep 't2.c:7:3,' %t - -// RUN: index-test %t1.ast %t2.ast -point-at %S/Inputs/foo.h:4:9 -print-refs > %t -// RUN: cat %t | count 1 -// RUN: grep 't1.c:8:3,' %t - -// RUN: index-test %t1.ast %t2.ast -point-at %S/Inputs/t1.c:3:22 -print-refs > %t -// RUN: cat %t | count 1 -// RUN: grep 't1.c:6:17,' %t - -// RUN: index-test %t1.ast %t2.ast -point-at %S/Inputs/t1.c:4:11 -print-refs > %t -// RUN: cat %t | count 1 -// RUN: grep 't1.c:6:5,' %t - -// RUN: index-test %t1.ast %t2.ast -point-at %S/Inputs/t1.c:5:30 -print-refs > %t -// RUN: cat %t | count 3 -// RUN: grep 't1.c:5:27,' %t -// RUN: grep 't1.c:5:44,' %t -// RUN: grep 't1.c:6:26,' %t - -// field test - -// FIXME: References point at the start of MemberExpr, make them point at the field instead. -// RUN: index-test %t1.ast %t2.ast -point-at %S/Inputs/t1.c:12:7 -print-refs > %t -// RUN: cat %t | count 1 -// RUN: grep 't1.c:21:3,' %t - -// RUN: index-test %t1.ast %t2.ast -point-at %S/Inputs/t1.c:16:7 -print-refs > %t -// RUN: cat %t | count 1 -// RUN: grep 't1.c:22:3,' %t - -// RUN: index-test %t1.ast %t2.ast -point-at %S/Inputs/foo.h:7:11 -print-refs > %t -// RUN: cat %t | count 2 -// RUN: grep 't1.c:25:3,' %t -// RUN: grep 't2.c:10:3,' %t diff --git a/test/Index/load-exprs.c b/test/Index/load-exprs.c new file mode 100644 index 0000000..a360efd --- /dev/null +++ b/test/Index/load-exprs.c @@ -0,0 +1,13 @@ +typedef int T; +struct X { int a, b; }; +void f(void *ptr) { + T* t_ptr = (T *)ptr; + (void)sizeof(T); + struct X x = (struct X){1, 2}; +} + +// RUN: c-index-test -test-load-source all %s | FileCheck %s + +// CHECK: load-exprs.c:4:15: TypeRef=T:1:13 [Extent=4:15:4:15] +// CHECK: load-exprs.c:5:16: TypeRef=T:1:13 [Extent=5:16:5:16] +// FIXME: the source location for "struct X" points at "struct", not "X" diff --git a/test/Index/multiple-redecls.c b/test/Index/multiple-redecls.c deleted file mode 100644 index faea88f..0000000 --- a/test/Index/multiple-redecls.c +++ /dev/null @@ -1,12 +0,0 @@ -// RUN: %clang_cc1 -emit-pch %s -o %t.ast -// RUN: index-test %t.ast -point-at %s:8:4 -print-decls | count 2 -// RUN: index-test %t.ast -point-at %s:8:4 -print-defs | count 1 - -static void foo(int x); - -static void bar(void) { - foo(10); -} - -void foo(int x) { -} diff --git a/test/Index/objc-decls.m b/test/Index/objc-decls.m deleted file mode 100644 index 4fcd830..0000000 --- a/test/Index/objc-decls.m +++ /dev/null @@ -1,16 +0,0 @@ -// RUN: %clang_cc1 -emit-pch %S/Inputs/t1.m -o %t1.m.ast -// RUN: %clang_cc1 -emit-pch %S/Inputs/t2.m -o %t2.m.ast - -// RUN: index-test %t1.m.ast %t2.m.ast -point-at %S/Inputs/t1.m:12:12 -print-decls > %t -// RUN: cat %t | count 2 -// RUN: grep 'objc.h:2:9,' %t | count 2 - -// RUN: index-test %t1.m.ast %t2.m.ast -point-at %S/Inputs/objc.h:5:13 -print-decls > %t -// RUN: cat %t | count 3 -// RUN: grep 'objc.h:5:1,' %t | count 2 -// RUN: grep 't1.m:15:1,' %t | count 1 - -// RUN: index-test %t1.m.ast %t2.m.ast -point-at %S/Inputs/objc.h:10:13 -print-decls > %t -// RUN: cat %t | count 3 -// RUN: grep 'objc.h:10:1,' %t | count 2 -// RUN: grep 't2.m:11:1,' %t | count 1 diff --git a/test/Index/objc-message.m b/test/Index/objc-message.m deleted file mode 100644 index 151565b..0000000 --- a/test/Index/objc-message.m +++ /dev/null @@ -1,38 +0,0 @@ -// RUN: %clang_cc1 -emit-pch %S/Inputs/t1.m -o %t1.m.ast -// RUN: %clang_cc1 -emit-pch %S/Inputs/t2.m -o %t2.m.ast - -// RUN: index-test %t1.m.ast %t2.m.ast -point-at %S/Inputs/objc.h:5:13 -print-refs > %t -// RUN: cat %t | count 1 -// RUN: grep 't1.m:6:3,' %t - -// RUN: index-test %t1.m.ast %t2.m.ast -point-at %S/Inputs/objc.h:6:13 -print-refs > %t -// RUN: cat %t | count 2 -// RUN: grep 't1.m:7:3,' %t -// RUN: grep 't2.m:7:3,' %t - -// RUN: index-test %t1.m.ast %t2.m.ast -point-at %S/Inputs/objc.h:10:13 -print-refs > %t -// RUN: cat %t | count 2 -// RUN: grep 't1.m:6:3,' %t -// RUN: grep 't2.m:6:3,' %t - -// RUN: index-test %t1.m.ast %t2.m.ast -point-at %S/Inputs/t1.m:6:15 -print-decls > %t -// RUN: cat %t | count 6 -// RUN: grep 'objc.h:5:1,' %t | count 2 -// RUN: grep 'objc.h:10:1,' %t | count 2 -// RUN: grep 't1.m:15:1,' %t -// RUN: grep 't2.m:11:1,' %t - -// RUN: index-test %t1.m.ast %t2.m.ast -point-at %S/Inputs/t1.m:7:15 -print-decls > %t -// RUN: cat %t | count 3 -// RUN: grep 'objc.h:6:1,' %t | count 2 -// RUN: grep 't1.m:18:1,' %t - -// RUN: index-test %t2.m.ast %t1.m.ast -point-at %S/Inputs/t2.m:6:15 -print-decls > %t -// RUN: cat %t | count 3 -// RUN: grep 'objc.h:10:1,' %t | count 2 -// RUN: grep 't2.m:11:1,' %t - -// RUN: index-test %t2.m.ast %t1.m.ast -point-at %S/Inputs/t2.m:7:15 -print-decls > %t -// RUN: cat %t | count 3 -// RUN: grep 'objc.h:6:1,' %t | count 2 -// RUN: grep 't1.m:18:1,' %t diff --git a/test/Index/remap-cursor-at.c b/test/Index/remap-cursor-at.c new file mode 100644 index 0000000..f7bcf79 --- /dev/null +++ b/test/Index/remap-cursor-at.c @@ -0,0 +1,5 @@ +// RUN: c-index-test -cursor-at=%s:1:15 -cursor-at=%s:2:21 -remap-file="%s;%S/Inputs/remap-load-to.c" %s | FileCheck %s +// RUN: CINDEXTEST_USE_EXTERNAL_AST_GENERATION=1 c-index-test -cursor-at=%s:1:15 -cursor-at=%s:2:21 -remap-file="%s;%S/Inputs/remap-load-to.c" %s | FileCheck %s + +// CHECK: ParmDecl=parm1:1:13 (Definition) +// CHECK: DeclRefExpr=parm2:1:26 diff --git a/test/Index/remap-load.c b/test/Index/remap-load.c new file mode 100644 index 0000000..84e45bc --- /dev/null +++ b/test/Index/remap-load.c @@ -0,0 +1,13 @@ +// RUN: c-index-test -test-load-source all -remap-file="%s;%S/Inputs/remap-load-to.c" %s | FileCheck -check-prefix=CHECK %s +// RUN: CINDEXTEST_USE_EXTERNAL_AST_GENERATION=1 c-index-test -test-load-source all -remap-file="%s;%S/Inputs/remap-load-to.c" %s | FileCheck -check-prefix=CHECK %s + +// CHECK: remap-load.c:1:5: FunctionDecl=foo:1:5 (Definition) [Extent=1:5:3:1] +// CHECK: remap-load.c:1:13: ParmDecl=parm1:1:13 (Definition) [Extent=1:9:1:17] +// CHECK: remap-load.c:1:26: ParmDecl=parm2:1:26 (Definition) [Extent=1:20:1:30] +// CHECK: remap-load.c:1:5: UnexposedStmt=foo [Extent=1:33:3:1] +// CHECK: remap-load.c:1:5: UnexposedStmt=foo [Extent=2:3:2:22] +// CHECK: remap-load.c:2:10: UnexposedExpr= [Extent=2:10:2:22] +// CHECK: remap-load.c:2:10: UnexposedExpr= [Extent=2:10:2:22] +// CHECK: remap-load.c:2:10: UnexposedExpr=parm1:1:13 [Extent=2:10:2:14] +// CHECK: remap-load.c:2:10: DeclRefExpr=parm1:1:13 [Extent=2:10:2:14] +// CHECK: remap-load.c:2:18: DeclRefExpr=parm2:1:26 [Extent=2:18:2:22] diff --git a/test/Index/resolve-loc.c b/test/Index/resolve-loc.c deleted file mode 100644 index 68504ee..0000000 --- a/test/Index/resolve-loc.c +++ /dev/null @@ -1,37 +0,0 @@ -// Run lines are sensitive to line numbers and come below the code. - -int top_var; - -void top_func_decl(int param1); - -void top_func_def(int param2) { - int local_var1; - for (int for_var = 100; for_var < 500; ++for_var) { - int local_var2 = for_var + 1; - } -} - -struct S { - int field_var; -}; - - -// RUN: %clang_cc1 -emit-pch %s -o %t.ast -// RUN: index-test %t.ast -point-at %s:3:8 | grep top_var -// RUN: index-test %t.ast -point-at %s:5:15 | grep top_func_decl -// RUN: index-test %t.ast -point-at %s:5:25 | grep param1 -// RUN: index-test %t.ast -point-at %s:7:17 | grep top_func_def -// RUN: index-test %t.ast -point-at %s:7:23 | grep param2 -// RUN: index-test %t.ast -point-at %s:8:10 | grep local_var1 -// RUN: index-test %t.ast -point-at %s:9:15 | grep for_var - -// RUN: index-test %t.ast -point-at %s:9:43 > %t -// RUN: grep '++for_var' %t - -// RUN: index-test %t.ast -point-at %s:10:9 | grep local_var2 - -// RUN: index-test %t.ast -point-at %s:10:30 > %t -// RUN: grep 'for_var + 1' %t - -// fields test. -// RUN: index-test %t.ast -point-at %s:15:10 | grep field_var diff --git a/test/Lexer/constants-ms.c b/test/Lexer/constants-ms.c index 5b3f826..97e6600 100644 --- a/test/Lexer/constants-ms.c +++ b/test/Lexer/constants-ms.c @@ -7,6 +7,19 @@ __int64 x5 = 0x42i64; __int64 x4 = 70000000i128; __int64 y = 0x42i64u; // expected-error {{invalid suffix}} -__int64 w = 0x43ui64; // expected-error {{invalid suffix}} +__int64 w = 0x43ui64; __int64 z = 9Li64; // expected-error {{invalid suffix}} __int64 q = 10lli64; // expected-error {{invalid suffix}} + +// radar 7562363 +#define ULLONG_MAX 0xffffffffffffffffui64 +#define UINT 0xffffffffui32 +#define USHORT 0xffffui16 +#define UCHAR 0xffui8 + +void a() { + unsigned long long m = ULLONG_MAX; + unsigned int n = UINT; + unsigned short s = USHORT; + unsigned char c = UCHAR; +} diff --git a/test/Misc/tabstop.c b/test/Misc/tabstop.c index 3fabda7..66685c6 100644 --- a/test/Misc/tabstop.c +++ b/test/Misc/tabstop.c @@ -28,3 +28,23 @@ void* d = 1; //CHECK-5: {{^ void\* b = 1;}} //CHECK-5: {{^ void\* c = 1;}} //CHECK-5: {{^void\* d = 1;}} + +// Test code modification hints + +void f(void) +{ + if (0 & 1 == 1) + {} +} + +// CHECK-3: {{^ }}if (0 & 1 == 1) +// CHECK-3: {{^ }} ( ) +// CHECK-3: {{^ }} ( ) + +// CHECK-4: {{^ }}if (0 & 1 == 1) +// CHECK-4: {{^ }} ( ) +// CHECK-4: {{^ }} ( ) + +// CHECK-5: {{^ }}if (0 & 1 == 1) +// CHECK-5: {{^ }} ( ) +// CHECK-5: {{^ }} ( ) diff --git a/test/PCH/cxx_exprs.cpp b/test/PCH/cxx_exprs.cpp new file mode 100644 index 0000000..51269d5 --- /dev/null +++ b/test/PCH/cxx_exprs.cpp @@ -0,0 +1,26 @@ +// Test this without pch. +// RUN: %clang_cc1 -include %S/cxx_exprs.h -fsyntax-only -verify %s + +// Test with pch. +// RUN: %clang_cc1 -x c++-header -emit-pch -o %t %S/cxx_exprs.h +// RUN: %clang_cc1 -include-pch %t -fsyntax-only -verify %s + +int integer; +double floating; +char character; + +// CXXStaticCastExpr +static_cast_result void_ptr = &integer; + +// CXXDynamicCastExpr +Derived *d; +dynamic_cast_result derived_ptr = d; + +// CXXReinterpretCastExpr +reinterpret_cast_result void_ptr2 = &integer; + +// CXXConstCastExpr +const_cast_result char_ptr = &character; + +// CXXFunctionalCastExpr +functional_cast_result *double_ptr = &floating; diff --git a/test/PCH/cxx_exprs.h b/test/PCH/cxx_exprs.h new file mode 100644 index 0000000..b649428 --- /dev/null +++ b/test/PCH/cxx_exprs.h @@ -0,0 +1,21 @@ +// Header for PCH test cxx_exprs.cpp + +// CXXStaticCastExpr +typedef typeof(static_cast<void *>(0)) static_cast_result; + +// CXXDynamicCastExpr +struct Base { virtual void f(); }; +struct Derived : Base { }; +Base *base_ptr; +typedef typeof(dynamic_cast<Derived *>(base_ptr)) dynamic_cast_result; + +// CXXReinterpretCastExpr +typedef typeof(reinterpret_cast<void *>(0)) reinterpret_cast_result; + +// CXXConstCastExpr +const char *const_char_ptr_value; +typedef typeof(const_cast<char *>(const_char_ptr_value)) const_cast_result; + +// CXXFunctionalCastExpr +int int_value; +typedef typeof(double(int_value)) functional_cast_result; diff --git a/test/Preprocessor/foo.framework/Headers/bar.h b/test/Preprocessor/foo.framework/Headers/bar.h deleted file mode 100644 index 574e851..0000000 --- a/test/Preprocessor/foo.framework/Headers/bar.h +++ /dev/null @@ -1,3 +0,0 @@ - -int y; - diff --git a/test/Preprocessor/foo.framework/Headers/foo.h b/test/Preprocessor/foo.framework/Headers/foo.h deleted file mode 100644 index b08d948..0000000 --- a/test/Preprocessor/foo.framework/Headers/foo.h +++ /dev/null @@ -1,6 +0,0 @@ -// This should warn: published framework headers should always -// #import headers within the framework with framework paths. -#include "bar.h" - -int x; - diff --git a/test/Preprocessor/framework-include.m b/test/Preprocessor/framework-include.m deleted file mode 100644 index 7e50f18..0000000 --- a/test/Preprocessor/framework-include.m +++ /dev/null @@ -1,5 +0,0 @@ -// RUN: %clang -E -F%S %s 2>&1 | grep "published framework headers should always #import headers within the framework with framework paths" - -// rdar://7520940 -#include <foo/foo.h> - diff --git a/test/Rewriter/rewrite-byref-vars.mm b/test/Rewriter/rewrite-byref-vars.mm index 581437b..1489c59 100644 --- a/test/Rewriter/rewrite-byref-vars.mm +++ b/test/Rewriter/rewrite-byref-vars.mm @@ -31,5 +31,16 @@ __declspec(dllexport) extern "C" __declspec(dllexport) void XXXXBreakTheRewriter } +@interface I +{ + id list; +} +- (void) Meth; +@end + +@implementation I +- (void) Meth { __attribute__((__blocks__(byref))) void ** listp = (void **)list; } +@end + // $CLANG -cc1 -fms-extensions -rewrite-objc -x objective-c++ -fblocks bug.mm // g++ -c -D"__declspec(X)=" bug.cpp diff --git a/test/Rewriter/rewrite-extern-c.mm b/test/Rewriter/rewrite-extern-c.mm new file mode 100644 index 0000000..1c8e90f --- /dev/null +++ b/test/Rewriter/rewrite-extern-c.mm @@ -0,0 +1,8 @@ +// RUN: %clang_cc1 -x objective-c++ -fblocks -rewrite-objc -o - %s +// radar 7546096 + +extern "C" { + short foo() { } +} +typedef unsigned char Boolean; + diff --git a/test/Rewriter/rewrite-protocol-type-1.m b/test/Rewriter/rewrite-protocol-type-1.m index 902559d..2bdf8e4 100644 --- a/test/Rewriter/rewrite-protocol-type-1.m +++ b/test/Rewriter/rewrite-protocol-type-1.m @@ -22,3 +22,6 @@ INTF <MyProto1, MyProto2> * Func1(INTF *p2, INTF<MyProto1, MyProto2> *p3, INTF * return p3; } +@interface Foo +@property int (*hashFunction)(const void *item, int (*size)(const void *item)); +@end diff --git a/test/Rewriter/rewrite-typeof.mm b/test/Rewriter/rewrite-typeof.mm new file mode 100644 index 0000000..f95cd9a --- /dev/null +++ b/test/Rewriter/rewrite-typeof.mm @@ -0,0 +1,20 @@ +// RUN: %clang_cc1 -x objective-c++ -fblocks -fms-extensions -rewrite-objc -o - %s + +extern "C" { +extern "C" void *_Block_copy(const void *aBlock); +extern "C" void _Block_release(const void *aBlock); +} + +int main() { + __attribute__((__blocks__(byref))) int a = 42; + int save_a = a; + + void (^b)(void) = ^{ + ((__typeof(^{ a = 2; }))_Block_copy((const void *)(^{ a = 2; }))); + }; + + ((__typeof(b))_Block_copy((const void *)(b))); + + return 0; +} + diff --git a/test/Sema/block-literal.c b/test/Sema/block-literal.c index e9c2341..c303b84 100644 --- a/test/Sema/block-literal.c +++ b/test/Sema/block-literal.c @@ -33,7 +33,8 @@ void test2() { break; // expected-error {{'break' statement not in loop or switch statement}} continue; // expected-error {{'continue' statement not in loop statement}} while(1) break; // ok - goto foo; // expected-error {{goto not allowed}} + goto foo; // expected-error {{use of undeclared label 'foo'}} + a: goto a; // ok }); break; } diff --git a/test/Sema/block-misc.c b/test/Sema/block-misc.c index 52cebfe..1109be6 100644 --- a/test/Sema/block-misc.c +++ b/test/Sema/block-misc.c @@ -87,8 +87,7 @@ int test7(void (^p)()) { void test8() { somelabel: - // FIXME: This should say "jump out of block not legal" when gotos are allowed. - ^{ goto somelabel; }(); // expected-error {{goto not allowed in block literal}} + ^{ goto somelabel; }(); // expected-error {{use of undeclared label 'somelabel'}} } void test9() { diff --git a/test/Sema/compound-literal.c b/test/Sema/compound-literal.c index a650d12..0c8ddd4 100644 --- a/test/Sema/compound-literal.c +++ b/test/Sema/compound-literal.c @@ -31,3 +31,6 @@ void IncompleteFunc(unsigned x) { (void){1,2,3}; // -expected-error {{variable has incomplete type}} (void(void)) { 0 }; // -expected-error{{illegal initializer type 'void (void)'}} } + +// PR6080 +int array[(sizeof(int[3]) == sizeof( (int[]) {0,1,2} )) ? 1 : -1]; diff --git a/test/Sema/scope-check.c b/test/Sema/scope-check.c index 4d3f6cb..74bc7c4 100644 --- a/test/Sema/scope-check.c +++ b/test/Sema/scope-check.c @@ -181,15 +181,14 @@ void test11(int n) { // TODO: When and if gotos are allowed in blocks, this should work. void test12(int n) { void *P = ^{ - goto L1; // expected-error {{goto not allowed in block literal}} + goto L1; L1: - goto L2; // expected-error {{goto not allowed in block literal}} + goto L2; L2: - goto L3; // expected-error {{goto not allowed in block literal}} - // todo-error {{illegal goto into protected scope}} - int Arr[n]; // todo-note {{jump bypasses initialization of variable length array}} + goto L3; // expected-error {{illegal goto into protected scope}} + int Arr[n]; // expected-note {{jump bypasses initialization of variable length array}} L3: - goto L4; // expected-error {{goto not allowed in block literal}} + goto L4; L4: return; }; } diff --git a/test/Sema/warn-unreachable.c b/test/Sema/warn-unreachable.c index 2c123d0..1eef637 100644 --- a/test/Sema/warn-unreachable.c +++ b/test/Sema/warn-unreachable.c @@ -1,4 +1,8 @@ -// RUN: %clang %s -fsyntax-only -Xclang -verify -fblocks -Wunreachable-code +// RUN: %clang %s -fsyntax-only -Xclang -verify -fblocks -Wunreachable-code -Wno-unused-value + +int halt() __attribute__((noreturn)); +int live(); +int dead(); void test1() { goto c; @@ -18,3 +22,79 @@ void test1() { goto d; f: ; } + +void test2() { + int i; + switch (live()) { + case 1: + halt(), + dead(); // expected-warning {{will never be executed}} + + case 2: + live(), halt(), + dead(); // expected-warning {{will never be executed}} + + case 3: + live() + + // expected-warning {{will never be executed}} + halt(); + dead(); + + case 4: + a4: + live(), + halt(); + goto a4; // expected-warning {{will never be executed}} + + case 5: + goto a5; + c5: + dead(); // expected-warning {{will never be executed}} + goto b5; + a5: + live(), + halt(); + b5: + goto c5; + + case 6: + if (live()) + goto e6; + live(), + halt(); + d6: + dead(); // expected-warning {{will never be executed}} + goto b6; + c6: + dead(); + goto b6; + e6: + live(), + halt(); + b6: + goto c6; + case 7: + halt() + + // expected-warning {{will never be executed}} + dead(); + - // expected-warning {{will never be executed}} + halt(); + case 8: + i + += // expected-warning {{will never be executed}} + halt(); + case 9: + halt() + ? // expected-warning {{will never be executed}} + dead() : dead(); + case 10: + ( // expected-warning {{will never be executed}} + float)halt(); + case 11: { + int a[5]; + live(), + a[halt() + ]; // expected-warning {{will never be executed}} + } + } +} diff --git a/test/SemaCXX/access-control-check.cpp b/test/SemaCXX/access-control-check.cpp index e6e261c..cf2d191 100644 --- a/test/SemaCXX/access-control-check.cpp +++ b/test/SemaCXX/access-control-check.cpp @@ -5,12 +5,11 @@ class M { }; class P { - int iP; - int PPR(); + int iP; // expected-note {{declared private here}} + int PPR(); // expected-note {{declared private here}} }; class N : M,P { N() {} - // FIXME. No access violation is reported in method call or member access. - int PR() { return iP + PPR(); } + int PR() { return iP + PPR(); } // expected-error 2 {{access to private member of 'class P'}} }; diff --git a/test/SemaCXX/anonymous-union.cpp b/test/SemaCXX/anonymous-union.cpp index 374241c..0590db2 100644 --- a/test/SemaCXX/anonymous-union.cpp +++ b/test/SemaCXX/anonymous-union.cpp @@ -111,3 +111,13 @@ struct BadMembers { // <rdar://problem/6481130> typedef union { }; // expected-error{{declaration does not declare anything}} + +// <rdar://problem/7562438> +typedef struct objc_module *Foo ; + +typedef struct _s { + union { + int a; + int Foo; + }; +} s, *ps; diff --git a/test/SemaCXX/enum.cpp b/test/SemaCXX/enum.cpp index f1b02f5..47ae06a 100644 --- a/test/SemaCXX/enum.cpp +++ b/test/SemaCXX/enum.cpp @@ -56,3 +56,14 @@ namespace test1 { enum enum4 { v4 = __LONG_MAX__ * 2UL }; int test4[is_same<__typeof(+v4), unsigned long>::value]; } + +// PR6061 +namespace PR6061 { + struct A { enum { id }; }; + struct B { enum { id }; }; + + struct C : public A, public B + { + enum { id }; + }; +} diff --git a/test/SemaCXX/new-delete.cpp b/test/SemaCXX/new-delete.cpp index 0e0f630..b058fc1 100644 --- a/test/SemaCXX/new-delete.cpp +++ b/test/SemaCXX/new-delete.cpp @@ -65,7 +65,7 @@ void bad_news(int *ip) (void)new S(1); // expected-error {{no matching constructor}} (void)new S(1, 1); // expected-error {{call to constructor of 'struct S' is ambiguous}} (void)new const int; // expected-error {{default initialization of an object of const type 'int const'}} - (void)new float*(ip); // expected-error {{cannot initialize a value of type 'float *' with an lvalue of type 'int *'}} + (void)new float*(ip); // expected-error {{cannot initialize a new value of type 'float *' with an lvalue of type 'int *'}} // Undefined, but clang should reject it directly. (void)new int[-1]; // expected-error {{array size is negative}} (void)new int[*(S*)0]; // expected-error {{array size expression must have integral or enumerated type, not 'struct S'}} diff --git a/test/SemaCXX/overload-call.cpp b/test/SemaCXX/overload-call.cpp index d20bf23..12dc5da 100644 --- a/test/SemaCXX/overload-call.cpp +++ b/test/SemaCXX/overload-call.cpp @@ -333,3 +333,17 @@ namespace test2 { inline bool operator!=(const qrgb666 &v) const { return !(*this == v); } }; } + +// PR 6117 +namespace test3 { + struct Base {}; + struct Incomplete; + + void foo(Base *); // expected-note 2 {{cannot convert argument of incomplete type}} + void foo(Base &); // expected-note 2 {{cannot convert argument of incomplete type}} + + void test(Incomplete *P) { + foo(P); // expected-error {{no matching function for call to 'foo'}} + foo(*P); // expected-error {{no matching function for call to 'foo'}} + } +} diff --git a/test/SemaCXX/unused.cpp b/test/SemaCXX/unused.cpp index 6fd1081..88783ce 100644 --- a/test/SemaCXX/unused.cpp +++ b/test/SemaCXX/unused.cpp @@ -13,3 +13,12 @@ APSInt& APSInt::operator=(const APSInt &RHS) { APInt::operator=(RHS); return *this; } + +template<typename T> +struct X { + X(); +}; + +void test() { + X<int>(); +} diff --git a/test/SemaCXX/virtual-override.cpp b/test/SemaCXX/virtual-override.cpp index 4fdac85..5e1e9b0 100644 --- a/test/SemaCXX/virtual-override.cpp +++ b/test/SemaCXX/virtual-override.cpp @@ -1,4 +1,4 @@ -// RUN: %clang_cc1 -fsyntax-only -faccess-control -verify %s +// RUN: %clang_cc1 -fsyntax-only -faccess-control -verify %s -std=c++0x namespace T1 { class A { @@ -197,3 +197,59 @@ namespace PR5920 { virtual Derived<int>* Method(); }; } + +// Look through template types and typedefs to see whether return types are +// pointers or references. +namespace PR6110 { + class Base {}; + class Derived : public Base {}; + + typedef Base* BaseP; + typedef Derived* DerivedP; + + class X { virtual BaseP f(); }; + class X1 : public X { virtual DerivedP f(); }; + + template <typename T> class Y { virtual T f(); }; + template <typename T1, typename T> class Y1 : public Y<T> { virtual T1 f(); }; + Y1<Derived*, Base*> y; +} + +namespace T10 { + struct A { }; + struct B : A { }; + + struct C { + virtual A&& f(); + }; + + struct D : C { + virtual B&& f(); + }; +}; + +namespace T11 { + struct A { }; + struct B : A { }; + + struct C { + virtual A& f(); // expected-note {{overridden virtual function is here}} + }; + + struct D : C { + virtual B&& f(); // expected-error {{virtual function 'f' has a different return type ('struct T11::B &&') than the function it overrides (which has return type 'struct T11::A &')}} + }; +}; + +namespace T12 { + struct A { }; + struct B : A { }; + + struct C { + virtual A&& f(); // expected-note {{overridden virtual function is here}} + }; + + struct D : C { + virtual B& f(); // expected-error {{virtual function 'f' has a different return type ('struct T12::B &') than the function it overrides (which has return type 'struct T12::A &&')}} + }; +}; diff --git a/test/SemaCXX/warn-unreachable.cpp b/test/SemaCXX/warn-unreachable.cpp new file mode 100644 index 0000000..a7ed91d --- /dev/null +++ b/test/SemaCXX/warn-unreachable.cpp @@ -0,0 +1,76 @@ +// RUN: %clang %s -fsyntax-only -Xclang -verify -fblocks -Wunreachable-code -Wno-unused-value + +int &halt() __attribute__((noreturn)); +int &live(); +int dead(); +int liveti() throw(int); +int (*livetip)() throw(int); + +int test1() { + try { + live(); + } catch (int i) { + live(); + } + return 1; +} + +void test2() { + try { + live(); + } catch (int i) { + live(); + } + try { + liveti(); + } catch (int i) { + live(); + } + try { + livetip(); + } catch (int i) { + live(); + } + throw 1; + dead(); // expected-warning {{will never be executed}} +} + + +void test3() { + halt() + --; // expected-warning {{will never be executed}} + halt() + ? // expected-warning {{will never be executed}} + dead() : dead(); + live(), + float // expected-warning {{will never be executed}} + (halt()); +} + +void test4() { + struct S { + int mem; + } s; + S &foor(); + halt(), foor() + .mem; // expected-warning {{will never be executed}} +} + +void test5() { + struct S { + int mem; + } s; + S &foor() __attribute__((noreturn)); + foor() + .mem; // expected-warning {{will never be executed}} +} + +void test6() { + struct S { + ~S() { } + S(int i) { } + }; + live(), + S // expected-warning {{will never be executed}} + (halt()); +} diff --git a/test/SemaObjC/method-unused-attribute.m b/test/SemaObjC/method-unused-attribute.m new file mode 100644 index 0000000..a4e5321 --- /dev/null +++ b/test/SemaObjC/method-unused-attribute.m @@ -0,0 +1,15 @@ +// RUN: %clang_cc1 -fsyntax-only -Wunused-parameter -verify %s + +@interface INTF +- (void) correct_use_of_unused: (void *) notice : (id)another_arg; +- (void) will_warn_unused_arg: (void *) notice : (id)warn_unused; +- (void) unused_attr_on_decl_ignored: (void *) __attribute__((unused)) will_warn; +@end + +@implementation INTF +- (void) correct_use_of_unused: (void *) __attribute__((unused)) notice : (id) __attribute__((unused)) newarg{ +} +- (void) will_warn_unused_arg: (void *) __attribute__((unused)) notice : (id)warn_unused {} // expected-warning {{unused parameter 'warn_unused'}} +- (void) unused_attr_on_decl_ignored: (void *) will_warn{} // expected-warning {{unused parameter 'will_warn'}} +@end + diff --git a/test/SemaObjC/property-category-2.m b/test/SemaObjC/property-category-2.m index f258b2c..e63672b 100644 --- a/test/SemaObjC/property-category-2.m +++ b/test/SemaObjC/property-category-2.m @@ -4,7 +4,8 @@ @protocol MyProtocol @property float myFloat; -@property float anotherFloat; +@property float anotherFloat; // expected-warning {{property 'anotherFloat' requires method 'anotherFloat' to be defined - use @dynamic}} \ + // expected-warning {{property 'anotherFloat' requires method 'setAnotherFloat:' to be defined }} @end @interface MyObject { float anotherFloat; } @@ -13,7 +14,7 @@ @interface MyObject (CAT) <MyProtocol> @end -@implementation MyObject (CAT) +@implementation MyObject (CAT) // expected-note 2 {{implementation is here}} @dynamic myFloat; // OK @synthesize anotherFloat; // expected-error {{@synthesize not allowed in a category's implementation}} @end diff --git a/test/SemaObjC/property-category-impl.m b/test/SemaObjC/property-category-impl.m new file mode 100644 index 0000000..9979497 --- /dev/null +++ b/test/SemaObjC/property-category-impl.m @@ -0,0 +1,31 @@ +// RUN: %clang_cc1 -fsyntax-only -verify %s + +/* This test is for categories which don't implement the accessors but some accessors are + implemented in their base class implementation. In this case,no warning must be issued. +*/ + +@interface MyClass +{ + int _foo; +} +@property(readonly) int foo; +@end + +@implementation MyClass +- (int) foo { return _foo; } +@end + +@interface MyClass (private) +@property(readwrite) int foo; +@end + +@implementation MyClass (private) +- (void) setFoo:(int)foo { _foo = foo; } +@end + +@interface MyClass (public) +@property(readwrite) int foo; // expected-warning {{property 'foo' requires method 'setFoo:' to be defined }} +@end + +@implementation MyClass (public)// expected-note {{implementation is here}} +@end diff --git a/test/SemaObjC/property-user-setter.m b/test/SemaObjC/property-user-setter.m index c06f2b6..babccee 100644 --- a/test/SemaObjC/property-user-setter.m +++ b/test/SemaObjC/property-user-setter.m @@ -80,11 +80,24 @@ static int g_val; } @end +@interface C {} +// - (int)Foo; +- (void)setFoo:(int)value; +@end + +void g(int); + +void f(C *c) { + c.Foo = 17; // expected-error {{property 'Foo' not found on object of type 'C *'}} + g(c.Foo); // expected-error {{property 'Foo' not found on object of type 'C *'}} +} + + void abort(void); int main (void) { Subclass *x = [[Subclass alloc] init]; - x.setterOnly = 4; + x.setterOnly = 4; // expected-error {{property 'setterOnly' not found on object of type 'Subclass *'}} if (g_val != 4) abort (); return 0; diff --git a/test/SemaObjC/property.m b/test/SemaObjC/property.m index bc2056c..b7f0fca 100644 --- a/test/SemaObjC/property.m +++ b/test/SemaObjC/property.m @@ -11,7 +11,8 @@ @end @interface I(CAT) -@property int d1; +@property int d1; // expected-warning {{property 'd1' requires method 'd1' to be defined }} \ + // expected-warning {{property 'd1' requires method 'setD1:' to be defined }} @end @implementation I @@ -22,7 +23,7 @@ @synthesize name; // OK! property with same name as an accessible ivar of same name @end -@implementation I(CAT) +@implementation I(CAT) // expected-note 2 {{implementation is here}} @synthesize d1; // expected-error {{@synthesize not allowed in a category's implementation}} @dynamic bad; // expected-error {{property implementation must have its declaration in the category 'CAT'}} @end diff --git a/test/SemaObjC/super.m b/test/SemaObjC/super.m index 3b86972..a61d72f 100644 --- a/test/SemaObjC/super.m +++ b/test/SemaObjC/super.m @@ -39,3 +39,10 @@ void f0(int super) { void f1(int puper) { [super m]; // expected-error{{use of undeclared identifier 'super'}} } + +// radar 7400691 +typedef Foo super; + +void test() { + [super cMethod]; +} diff --git a/test/SemaObjC/unimplemented-protocol-prop.m b/test/SemaObjC/unimplemented-protocol-prop.m new file mode 100644 index 0000000..d3de50e --- /dev/null +++ b/test/SemaObjC/unimplemented-protocol-prop.m @@ -0,0 +1,20 @@ +// RUN: %clang_cc1 -fsyntax-only -verify %s + +@protocol PROTOCOL0 +@required +@property float MyProperty0; // expected-warning {{property 'MyProperty0' requires method 'MyProperty0' to be defined }} \ + // expected-warning {{property 'MyProperty0' requires method 'setMyProperty0:' to be defined}} +@end + +@protocol PROTOCOL<PROTOCOL0> +@required +@property float MyProperty; // expected-warning {{property 'MyProperty' requires method 'MyProperty' to be defined}} \ + // expected-warning {{property 'MyProperty' requires method 'setMyProperty:' to be defined}} +@optional +@property float OptMyProperty; +@end + +@interface I <PROTOCOL> +@end + +@implementation I @end // expected-note 4 {{implementation is here}} diff --git a/test/SemaObjCXX/cstyle-block-pointer-cast.mm b/test/SemaObjCXX/cstyle-block-pointer-cast.mm new file mode 100644 index 0000000..72f5283 --- /dev/null +++ b/test/SemaObjCXX/cstyle-block-pointer-cast.mm @@ -0,0 +1,42 @@ +// RUN: %clang_cc1 -fsyntax-only -verify -fblocks %s +// radar 7562285 + +typedef int (^blocktype)(int a, int b); + +@interface A { + A* a; + id b; + Class c; +} +- (blocktype)Meth; +@end + +@implementation A +- (blocktype)Meth { + if (b) + return (blocktype)b; + else if (a) + return (blocktype)a; // expected-error {{C-style cast from 'A *' to 'blocktype' (aka 'int (^)(int, int)') is not allowed}} + else + return (blocktype)c; +} +@end + +@interface B { + blocktype a; + blocktype b; + blocktype c; +} +- (id)Meth; +@end + +@implementation B +- (id)Meth { + if (a) + return (A*)a; // expected-error {{C-style cast from 'blocktype' (aka 'int (^)(int, int)') to 'A *' is not allowed}} + if (b) + return (id)b; + if (c) + return (Class)b; +} +@end diff --git a/test/SemaObjCXX/pointer-to-objc-pointer-conv.mm b/test/SemaObjCXX/pointer-to-objc-pointer-conv.mm new file mode 100644 index 0000000..80383eb --- /dev/null +++ b/test/SemaObjCXX/pointer-to-objc-pointer-conv.mm @@ -0,0 +1,21 @@ +// RUN: %clang_cc1 -fsyntax-only -verify %s + +@interface G +@end + +@interface F +- (void)bar:(id *)objects; +- (void)foo:(G**)objects; +@end + + +void a() { + F *b; + G **keys; + [b bar:keys]; + + id *PID; + [b foo:PID]; + +} + diff --git a/test/SemaTemplate/dependent-base-classes.cpp b/test/SemaTemplate/dependent-base-classes.cpp index 79b28c2..80d20b0 100644 --- a/test/SemaTemplate/dependent-base-classes.cpp +++ b/test/SemaTemplate/dependent-base-classes.cpp @@ -82,3 +82,31 @@ namespace Ambig { Derived<int> di; // expected-note{{instantiation of}} } + +namespace PR6081 { + template<typename T> + struct A { }; + + template<typename T> + class B : public A<T> + { + public: + template< class X > + void f0(const X & k) + { + this->template f1<int>()(k); + } + }; + + template<typename T> + class C + { + public: + template< class X > + void f0(const X & k) + { + this->template f1<int>()(k); // expected-error{{'f1' following the 'template' keyword does not refer to a template}} \ + // FIXME: expected-error{{unqualified-id}} + } + }; +} diff --git a/test/SemaTemplate/dependent-base-member-init.cpp b/test/SemaTemplate/dependent-base-member-init.cpp index c9823d2..1f13149 100644 --- a/test/SemaTemplate/dependent-base-member-init.cpp +++ b/test/SemaTemplate/dependent-base-member-init.cpp @@ -34,3 +34,26 @@ template<typename T> struct s1 : s0<typename s0_traits<T>::t0> { s1() {} }; +// PR6062 +namespace PR6062 { + template <typename T> + class A : public T::type + { + A() : T::type() + { + } + + template <typename U> + A(U const& init) + : T::type(init) + { } + + template<typename U> + A(U& init) : U::other_type(init) { } + }; +} + +template<typename T, typename U> +struct X0 : T::template apply<U> { + X0(int i) : T::template apply<U>(i) { } +}; diff --git a/test/SemaTemplate/dependent-expr.cpp b/test/SemaTemplate/dependent-expr.cpp index 412a811..3f481b5 100644 --- a/test/SemaTemplate/dependent-expr.cpp +++ b/test/SemaTemplate/dependent-expr.cpp @@ -5,3 +5,22 @@ template <typename Iterator> void Test(Iterator it) { *(it += 1); } + +namespace PR6045 { + template<unsigned int r> + class A + { + static const unsigned int member = r; + void f(); + }; + + template<unsigned int r> + const unsigned int A<r>::member; + + template<unsigned int r> + void A<r>::f() + { + unsigned k; + (void)(k % member); + } +} diff --git a/test/SemaTemplate/friend-template.cpp b/test/SemaTemplate/friend-template.cpp index 05289b1..8bc2631 100644 --- a/test/SemaTemplate/friend-template.cpp +++ b/test/SemaTemplate/friend-template.cpp @@ -1,5 +1,4 @@ // RUN: %clang_cc1 -fsyntax-only -verify %s - // PR5057 namespace test0 { namespace std { @@ -107,3 +106,20 @@ namespace test5 { template <typename T> friend struct cache; }; } + +// PR6022 +namespace PR6022 { + template <class T1, class T2 , class T3 > class A; + + namespace inner { + template<class T1, class T2, class T3, class T> + A<T1, T2, T3>& f0(A<T1, T2, T3>&, T); + } + + template<class T1, class T2, class T3> + class A { + template<class U1, class U2, class U3, class T> + friend A<U1, U2, U3>& inner::f0(A<U1, U2, U3>&, T); + }; +} + diff --git a/test/SemaTemplate/instantiate-local-class.cpp b/test/SemaTemplate/instantiate-local-class.cpp new file mode 100644 index 0000000..768eb21 --- /dev/null +++ b/test/SemaTemplate/instantiate-local-class.cpp @@ -0,0 +1,34 @@ +// RUN: %clang_cc1 -verify %s +template<typename T> +void f0() { + struct X; + typedef struct Y { + T (X::* f1())(int) { return 0; } + } Y2; + + Y2 y = Y(); +} + +template void f0<int>(); + +// PR5764 +namespace PR5764 { + class X { + template <typename T> + void Bar() { + typedef T ValueType; + class Y { + Y() { V = ValueType(); } + + ValueType V; + }; + + Y y; + } + }; + + void test(X x) { + x.Bar<int>(); + } +} + diff --git a/test/SemaTemplate/member-template-access-expr.cpp b/test/SemaTemplate/member-template-access-expr.cpp index 9edefe8..ea17cdb 100644 --- a/test/SemaTemplate/member-template-access-expr.cpp +++ b/test/SemaTemplate/member-template-access-expr.cpp @@ -103,3 +103,23 @@ struct X5 { this->f<T*>(); } }; + +namespace PR6021 { + template< class T1, class T2 > + class Outer + { + public: // Range operations + template< class X > X tmpl( const X* = 0 ) const; + + struct Inner + { + const Outer& o; + + template< class X > + operator X() const + { + return o.tmpl<X>(); + } + }; + }; +} diff --git a/tools/CIndex/CIndex.cpp b/tools/CIndex/CIndex.cpp index 86e0ddc..84f908d 100644 --- a/tools/CIndex/CIndex.cpp +++ b/tools/CIndex/CIndex.cpp @@ -13,10 +13,14 @@ //===----------------------------------------------------------------------===// #include "CIndexer.h" +#include "CXCursor.h" +#include "clang/Basic/Version.h" #include "clang/AST/DeclVisitor.h" #include "clang/AST/StmtVisitor.h" +#include "clang/AST/TypeLocVisitor.h" #include "clang/Lex/Lexer.h" +#include "clang/Lex/Preprocessor.h" #include "llvm/Support/MemoryBuffer.h" #include "llvm/System/Program.h" @@ -24,6 +28,7 @@ #include <cstdio> using namespace clang; +using namespace clang::cxcursor; using namespace idx; //===----------------------------------------------------------------------===// @@ -111,362 +116,744 @@ public: #endif #endif -//===----------------------------------------------------------------------===// -// Visitors. -//===----------------------------------------------------------------------===// +typedef llvm::PointerIntPair<ASTContext *, 1, bool> CXSourceLocationPtr; -namespace { -static enum CXCursorKind TranslateDeclRefExpr(DeclRefExpr *DRE) { - NamedDecl *D = DRE->getDecl(); - if (isa<VarDecl>(D)) - return CXCursor_VarRef; - else if (isa<FunctionDecl>(D)) - return CXCursor_FunctionRef; - else if (isa<EnumConstantDecl>(D)) - return CXCursor_EnumConstantRef; - else - return CXCursor_NotImplemented; +/// \brief Translate a Clang source location into a CIndex source location. +static CXSourceLocation translateSourceLocation(ASTContext &Context, + SourceLocation Loc, + bool AtEnd = false) { + CXSourceLocationPtr Ptr(&Context, AtEnd); + CXSourceLocation Result = { Ptr.getOpaqueValue(), Loc.getRawEncoding() }; + return Result; } -#if 0 -// Will be useful one day. -class CRefVisitor : public StmtVisitor<CRefVisitor> { - CXDecl CDecl; - CXDeclIterator Callback; - CXClientData CData; - - void Call(enum CXCursorKind CK, Stmt *SRef) { - CXCursor C = { CK, CDecl, SRef }; - Callback(CDecl, C, CData); - } +/// \brief Translate a Clang source range into a CIndex source range. +static CXSourceRange translateSourceRange(ASTContext &Context, SourceRange R) { + CXSourceRange Result = { &Context, + R.getBegin().getRawEncoding(), + R.getEnd().getRawEncoding() }; + return Result; +} -public: - CRefVisitor(CXDecl C, CXDeclIterator cback, CXClientData D) : - CDecl(C), Callback(cback), CData(D) {} +static SourceLocation translateSourceLocation(CXSourceLocation L) { + return SourceLocation::getFromRawEncoding(L.int_data); +} - void VisitStmt(Stmt *S) { - for (Stmt::child_iterator C = S->child_begin(), CEnd = S->child_end(); - C != CEnd; ++C) - Visit(*C); - } - void VisitDeclRefExpr(DeclRefExpr *Node) { - Call(TranslateDeclRefExpr(Node), Node); - } - void VisitMemberExpr(MemberExpr *Node) { - Call(CXCursor_MemberRef, Node); - } - void VisitObjCMessageExpr(ObjCMessageExpr *Node) { - Call(CXCursor_ObjCSelectorRef, Node); - } - void VisitObjCIvarRefExpr(ObjCIvarRefExpr *Node) { - Call(CXCursor_ObjCIvarRef, Node); - } +static SourceRange translateSourceRange(CXSourceRange R) { + return SourceRange(SourceLocation::getFromRawEncoding(R.begin_int_data), + SourceLocation::getFromRawEncoding(R.end_int_data)); +} + +/// \brief The result of comparing two source ranges. +enum RangeComparisonResult { + /// \brief Either the ranges overlap or one of the ranges is invalid. + RangeOverlap, + + /// \brief The first range ends before the second range starts. + RangeBefore, + + /// \brief The first range starts after the second range ends. + RangeAfter }; -#endif -// Translation Unit Visitor. +/// \brief Compare two source ranges to determine their relative position in +/// the translation unit. +static RangeComparisonResult RangeCompare(SourceManager &SM, + SourceRange R1, + SourceRange R2) { + assert(R1.isValid() && "First range is invalid?"); + assert(R2.isValid() && "Second range is invalid?"); + if (SM.isBeforeInTranslationUnit(R1.getEnd(), R2.getBegin())) + return RangeBefore; + if (SM.isBeforeInTranslationUnit(R2.getEnd(), R1.getBegin())) + return RangeAfter; + return RangeOverlap; +} -class TUVisitor : public DeclVisitor<TUVisitor> { -public: - typedef void (*Iterator)(void *, CXCursor, CXClientData); -private: - void *Root; // CXDecl or CXTranslationUnit - Iterator Callback; // CXTranslationUnitIterator or CXDeclIterator. - CXClientData CData; +//===----------------------------------------------------------------------===// +// Cursor visitor. +//===----------------------------------------------------------------------===// + +namespace { + +// Cursor visitor. +class CursorVisitor : public DeclVisitor<CursorVisitor, bool>, + public TypeLocVisitor<CursorVisitor, bool>, + public StmtVisitor<CursorVisitor, bool> +{ + /// \brief The translation unit we are traversing. + ASTUnit *TU; + + /// \brief The parent cursor whose children we are traversing. + CXCursor Parent; + + /// \brief The declaration that serves at the parent of any statement or + /// expression nodes. + Decl *StmtParent; + + /// \brief The visitor function. + CXCursorVisitor Visitor; + + /// \brief The opaque client data, to be passed along to the visitor. + CXClientData ClientData; + // MaxPCHLevel - the maximum PCH level of declarations that we will pass on // to the visitor. Declarations with a PCH level greater than this value will // be suppressed. unsigned MaxPCHLevel; - void Call(enum CXCursorKind CK, NamedDecl *ND) { - // Filter any declarations that have a PCH level greater than what we allow. - if (ND->getPCHLevel() > MaxPCHLevel) - return; + /// \brief When valid, a source range to which the cursor should restrict + /// its search. + SourceRange RegionOfInterest; + + using DeclVisitor<CursorVisitor, bool>::Visit; + using TypeLocVisitor<CursorVisitor, bool>::Visit; + using StmtVisitor<CursorVisitor, bool>::Visit; + + /// \brief Determine whether this particular source range comes before, comes + /// after, or overlaps the region of interest. + /// + /// \param R a source range retrieved from the abstract syntax tree. + RangeComparisonResult CompareRegionOfInterest(SourceRange R); + + /// \brief Determine whether this particular source range comes before, comes + /// after, or overlaps the region of interest. + /// + /// \param CXR a source range retrieved from a cursor. + RangeComparisonResult CompareRegionOfInterest(CXSourceRange CXR); + +public: + CursorVisitor(ASTUnit *TU, CXCursorVisitor Visitor, CXClientData ClientData, + unsigned MaxPCHLevel, + SourceRange RegionOfInterest = SourceRange()) + : TU(TU), Visitor(Visitor), ClientData(ClientData), + MaxPCHLevel(MaxPCHLevel), RegionOfInterest(RegionOfInterest) + { + Parent.kind = CXCursor_NoDeclFound; + Parent.data[0] = 0; + Parent.data[1] = 0; + Parent.data[2] = 0; + StmtParent = 0; + } + + bool Visit(CXCursor Cursor, bool CheckedRegionOfInterest = false); + bool VisitChildren(CXCursor Parent); + + // Declaration visitors + bool VisitDeclContext(DeclContext *DC); + bool VisitTranslationUnitDecl(TranslationUnitDecl *D); + bool VisitTypedefDecl(TypedefDecl *D); + bool VisitTagDecl(TagDecl *D); + bool VisitEnumConstantDecl(EnumConstantDecl *D); + bool VisitDeclaratorDecl(DeclaratorDecl *DD); + bool VisitFunctionDecl(FunctionDecl *ND); + bool VisitFieldDecl(FieldDecl *D); + bool VisitVarDecl(VarDecl *); + bool VisitObjCMethodDecl(ObjCMethodDecl *ND); + bool VisitObjCContainerDecl(ObjCContainerDecl *D); + bool VisitObjCCategoryDecl(ObjCCategoryDecl *ND); + bool VisitObjCProtocolDecl(ObjCProtocolDecl *PID); + bool VisitObjCInterfaceDecl(ObjCInterfaceDecl *D); + bool VisitObjCImplDecl(ObjCImplDecl *D); + bool VisitObjCCategoryImplDecl(ObjCCategoryImplDecl *D); + bool VisitObjCImplementationDecl(ObjCImplementationDecl *D); + // FIXME: ObjCPropertyDecl requires TypeSourceInfo, getter/setter locations, + // etc. + // FIXME: ObjCCompatibleAliasDecl requires aliased-class locations. + bool VisitObjCForwardProtocolDecl(ObjCForwardProtocolDecl *D); + bool VisitObjCClassDecl(ObjCClassDecl *D); + + // Type visitors + // FIXME: QualifiedTypeLoc doesn't provide any location information + bool VisitBuiltinTypeLoc(BuiltinTypeLoc TL); + bool VisitTypedefTypeLoc(TypedefTypeLoc TL); + bool VisitUnresolvedUsingTypeLoc(UnresolvedUsingTypeLoc TL); + bool VisitTagTypeLoc(TagTypeLoc TL); + // FIXME: TemplateTypeParmTypeLoc doesn't provide any location information + bool VisitObjCInterfaceTypeLoc(ObjCInterfaceTypeLoc TL); + bool VisitObjCObjectPointerTypeLoc(ObjCObjectPointerTypeLoc TL); + bool VisitPointerTypeLoc(PointerTypeLoc TL); + bool VisitBlockPointerTypeLoc(BlockPointerTypeLoc TL); + bool VisitMemberPointerTypeLoc(MemberPointerTypeLoc TL); + bool VisitLValueReferenceTypeLoc(LValueReferenceTypeLoc TL); + bool VisitRValueReferenceTypeLoc(RValueReferenceTypeLoc TL); + bool VisitFunctionTypeLoc(FunctionTypeLoc TL); + bool VisitArrayTypeLoc(ArrayTypeLoc TL); + // FIXME: Implement for TemplateSpecializationTypeLoc + // FIXME: Implement visitors here when the unimplemented TypeLocs get + // implemented + bool VisitTypeOfExprTypeLoc(TypeOfExprTypeLoc TL); + bool VisitTypeOfTypeLoc(TypeOfTypeLoc TL); + + // Statement visitors + bool VisitStmt(Stmt *S); + bool VisitDeclStmt(DeclStmt *S); + // FIXME: LabelStmt label? + bool VisitIfStmt(IfStmt *S); + bool VisitSwitchStmt(SwitchStmt *S); + + // Expression visitors + bool VisitSizeOfAlignOfExpr(SizeOfAlignOfExpr *E); + bool VisitExplicitCastExpr(ExplicitCastExpr *E); + bool VisitCompoundLiteralExpr(CompoundLiteralExpr *E); +}; + +} // end anonymous namespace - // Filter any implicit declarations (since the source info will be bogus). - if (ND->isImplicit()) - return; +RangeComparisonResult CursorVisitor::CompareRegionOfInterest(SourceRange R) { + assert(RegionOfInterest.isValid() && "RangeCompare called with invalid range"); + if (R.isInvalid()) + return RangeOverlap; + + // Move the end of the input range to the end of the last token in that + // range. + R.setEnd(TU->getPreprocessor().getLocForEndOfToken(R.getEnd(), 1)); + return RangeCompare(TU->getSourceManager(), R, RegionOfInterest); +} + +RangeComparisonResult CursorVisitor::CompareRegionOfInterest(CXSourceRange CXR) { + return CompareRegionOfInterest(translateSourceRange(CXR)); +} + +/// \brief Visit the given cursor and, if requested by the visitor, +/// its children. +/// +/// \param Cursor the cursor to visit. +/// +/// \param CheckRegionOfInterest if true, then the caller already checked that +/// this cursor is within the region of interest. +/// +/// \returns true if the visitation should be aborted, false if it +/// should continue. +bool CursorVisitor::Visit(CXCursor Cursor, bool CheckedRegionOfInterest) { + if (clang_isInvalid(Cursor.kind)) + return false; + + if (clang_isDeclaration(Cursor.kind)) { + Decl *D = getCursorDecl(Cursor); + assert(D && "Invalid declaration cursor"); + if (D->getPCHLevel() > MaxPCHLevel) + return false; + + if (D->isImplicit()) + return false; + } - CXCursor C = { CK, ND, 0, 0 }; - Callback(Root, C, CData); + // If we have a range of interest, and this cursor doesn't intersect with it, + // we're done. + if (RegionOfInterest.isValid() && !CheckedRegionOfInterest) { + CXSourceRange Range = clang_getCursorExtent(Cursor); + if (translateSourceRange(Range).isInvalid() || + CompareRegionOfInterest(Range)) + return false; } + + switch (Visitor(Cursor, Parent, ClientData)) { + case CXChildVisit_Break: + return true; -public: - TUVisitor(void *root, Iterator cback, CXClientData D, unsigned MaxPCHLevel) : - Root(root), Callback(cback), CData(D), MaxPCHLevel(MaxPCHLevel) {} - - void VisitDeclContext(DeclContext *DC); - void VisitFunctionDecl(FunctionDecl *ND); - void VisitObjCCategoryDecl(ObjCCategoryDecl *ND); - void VisitObjCCategoryImplDecl(ObjCCategoryImplDecl *ND); - void VisitObjCImplementationDecl(ObjCImplementationDecl *ND); - void VisitObjCInterfaceDecl(ObjCInterfaceDecl *ND); - void VisitObjCProtocolDecl(ObjCProtocolDecl *ND); - void VisitTagDecl(TagDecl *ND); - void VisitTranslationUnitDecl(TranslationUnitDecl *D); - void VisitTypedefDecl(TypedefDecl *ND); - void VisitVarDecl(VarDecl *ND); -}; + case CXChildVisit_Continue: + return false; -void TUVisitor::VisitDeclContext(DeclContext *DC) { - for (DeclContext::decl_iterator I = DC->decls_begin(), E = DC->decls_end(); - I != E; ++I) - Visit(*I); + case CXChildVisit_Recurse: + return VisitChildren(Cursor); + } + + llvm_unreachable("Silly GCC, we can't get here"); } + +/// \brief Visit the children of the given cursor. +/// +/// \returns true if the visitation should be aborted, false if it +/// should continue. +bool CursorVisitor::VisitChildren(CXCursor Cursor) { + if (clang_isReference(Cursor.kind)) { + // By definition, references have no children. + return false; + } -void TUVisitor::VisitFunctionDecl(FunctionDecl *ND) { - Call(ND->isThisDeclarationADefinition() ? CXCursor_FunctionDefn - : CXCursor_FunctionDecl, ND); + // Set the Parent field to Cursor, then back to its old value once we're + // done. + class SetParentRAII { + CXCursor &Parent; + Decl *&StmtParent; + CXCursor OldParent; + + public: + SetParentRAII(CXCursor &Parent, Decl *&StmtParent, CXCursor NewParent) + : Parent(Parent), StmtParent(StmtParent), OldParent(Parent) + { + Parent = NewParent; + if (clang_isDeclaration(Parent.kind)) + StmtParent = getCursorDecl(Parent); + } + + ~SetParentRAII() { + Parent = OldParent; + if (clang_isDeclaration(Parent.kind)) + StmtParent = getCursorDecl(Parent); + } + } SetParent(Parent, StmtParent, Cursor); + + if (clang_isDeclaration(Cursor.kind)) { + Decl *D = getCursorDecl(Cursor); + assert(D && "Invalid declaration cursor"); + return Visit(D); + } + + if (clang_isStatement(Cursor.kind)) + return Visit(getCursorStmt(Cursor)); + if (clang_isExpression(Cursor.kind)) + return Visit(getCursorExpr(Cursor)); + + if (clang_isTranslationUnit(Cursor.kind)) { + ASTUnit *CXXUnit = getCursorASTUnit(Cursor); + if (!CXXUnit->isMainFileAST() && CXXUnit->getOnlyLocalDecls() && + RegionOfInterest.isInvalid()) { + const std::vector<Decl*> &TLDs = CXXUnit->getTopLevelDecls(); + for (std::vector<Decl*>::const_iterator it = TLDs.begin(), + ie = TLDs.end(); it != ie; ++it) { + if (Visit(MakeCXCursor(*it, CXXUnit), true)) + return true; + } + } else { + return VisitDeclContext( + CXXUnit->getASTContext().getTranslationUnitDecl()); + } + + return false; + } + + // Nothing to visit at the moment. + return false; } + +bool CursorVisitor::VisitDeclContext(DeclContext *DC) { + for (DeclContext::decl_iterator + I = DC->decls_begin(), E = DC->decls_end(); I != E; ++I) { + if (RegionOfInterest.isValid()) { + SourceRange R = (*I)->getSourceRange(); + if (R.isInvalid()) + continue; + + switch (CompareRegionOfInterest(R)) { + case RangeBefore: + // This declaration comes before the region of interest; skip it. + continue; + + case RangeAfter: + // This declaration comes after the region of interest; we're done. + return false; + + case RangeOverlap: + // This declaration overlaps the region of interest; visit it. + break; + } + } + + if (Visit(MakeCXCursor(*I, TU), true)) + return true; + } -void TUVisitor::VisitObjCCategoryDecl(ObjCCategoryDecl *ND) { - Call(CXCursor_ObjCCategoryDecl, ND); + return false; } -void TUVisitor::VisitObjCCategoryImplDecl(ObjCCategoryImplDecl *ND) { - Call(CXCursor_ObjCCategoryDefn, ND); +bool CursorVisitor::VisitTranslationUnitDecl(TranslationUnitDecl *D) { + llvm_unreachable("Translation units are visited directly by Visit()"); + return false; } -void TUVisitor::VisitObjCImplementationDecl(ObjCImplementationDecl *ND) { - Call(CXCursor_ObjCClassDefn, ND); +bool CursorVisitor::VisitTypedefDecl(TypedefDecl *D) { + if (TypeSourceInfo *TSInfo = D->getTypeSourceInfo()) + return Visit(TSInfo->getTypeLoc()); + + return false; +} + +bool CursorVisitor::VisitTagDecl(TagDecl *D) { + return VisitDeclContext(D); +} + +bool CursorVisitor::VisitEnumConstantDecl(EnumConstantDecl *D) { + if (Expr *Init = D->getInitExpr()) + return Visit(MakeCXCursor(Init, StmtParent, TU)); + return false; +} + +bool CursorVisitor::VisitDeclaratorDecl(DeclaratorDecl *DD) { + if (TypeSourceInfo *TSInfo = DD->getTypeSourceInfo()) + if (Visit(TSInfo->getTypeLoc())) + return true; + + return false; } + +bool CursorVisitor::VisitFunctionDecl(FunctionDecl *ND) { + if (VisitDeclaratorDecl(ND)) + return true; + + if (ND->isThisDeclarationADefinition() && + Visit(MakeCXCursor(ND->getBody(), StmtParent, TU))) + return true; -void TUVisitor::VisitObjCInterfaceDecl(ObjCInterfaceDecl *ND) { - Call(CXCursor_ObjCInterfaceDecl, ND); -} + return false; +} -void TUVisitor::VisitObjCProtocolDecl(ObjCProtocolDecl *ND) { - Call(CXCursor_ObjCProtocolDecl, ND); +bool CursorVisitor::VisitFieldDecl(FieldDecl *D) { + if (VisitDeclaratorDecl(D)) + return true; + + if (Expr *BitWidth = D->getBitWidth()) + return Visit(MakeCXCursor(BitWidth, StmtParent, TU)); + + return false; } + +bool CursorVisitor::VisitVarDecl(VarDecl *D) { + if (VisitDeclaratorDecl(D)) + return true; -void TUVisitor::VisitTagDecl(TagDecl *ND) { - switch (ND->getTagKind()) { - case TagDecl::TK_struct: - Call(CXCursor_StructDecl, ND); - break; - case TagDecl::TK_class: - Call(CXCursor_ClassDecl, ND); - break; - case TagDecl::TK_union: - Call(CXCursor_UnionDecl, ND); - break; - case TagDecl::TK_enum: - Call(CXCursor_EnumDecl, ND); - break; + if (Expr *Init = D->getInit()) + return Visit(MakeCXCursor(Init, StmtParent, TU)); + + return false; +} + +bool CursorVisitor::VisitObjCMethodDecl(ObjCMethodDecl *ND) { + // FIXME: We really need a TypeLoc covering Objective-C method declarations. + // At the moment, we don't have information about locations in the return + // type. + for (ObjCMethodDecl::param_iterator P = ND->param_begin(), + PEnd = ND->param_end(); + P != PEnd; ++P) { + if (Visit(MakeCXCursor(*P, TU))) + return true; } + + if (ND->isThisDeclarationADefinition() && + Visit(MakeCXCursor(ND->getBody(), StmtParent, TU))) + return true; + + return false; } + +bool CursorVisitor::VisitObjCContainerDecl(ObjCContainerDecl *D) { + return VisitDeclContext(D); +} + +bool CursorVisitor::VisitObjCCategoryDecl(ObjCCategoryDecl *ND) { + if (Visit(MakeCursorObjCClassRef(ND->getClassInterface(), ND->getLocation(), + TU))) + return true; -void TUVisitor::VisitTranslationUnitDecl(TranslationUnitDecl *D) { - VisitDeclContext(dyn_cast<DeclContext>(D)); + ObjCCategoryDecl::protocol_loc_iterator PL = ND->protocol_loc_begin(); + for (ObjCCategoryDecl::protocol_iterator I = ND->protocol_begin(), + E = ND->protocol_end(); I != E; ++I, ++PL) + if (Visit(MakeCursorObjCProtocolRef(*I, *PL, TU))) + return true; + + return VisitObjCContainerDecl(ND); } + +bool CursorVisitor::VisitObjCProtocolDecl(ObjCProtocolDecl *PID) { + ObjCProtocolDecl::protocol_loc_iterator PL = PID->protocol_loc_begin(); + for (ObjCProtocolDecl::protocol_iterator I = PID->protocol_begin(), + E = PID->protocol_end(); I != E; ++I, ++PL) + if (Visit(MakeCursorObjCProtocolRef(*I, *PL, TU))) + return true; -void TUVisitor::VisitTypedefDecl(TypedefDecl *ND) { - Call(CXCursor_TypedefDecl, ND); + return VisitObjCContainerDecl(PID); } -void TUVisitor::VisitVarDecl(VarDecl *ND) { - Call(CXCursor_VarDecl, ND); +bool CursorVisitor::VisitObjCInterfaceDecl(ObjCInterfaceDecl *D) { + // Issue callbacks for super class. + if (D->getSuperClass() && + Visit(MakeCursorObjCSuperClassRef(D->getSuperClass(), + D->getSuperClassLoc(), + TU))) + return true; + + ObjCInterfaceDecl::protocol_loc_iterator PL = D->protocol_loc_begin(); + for (ObjCInterfaceDecl::protocol_iterator I = D->protocol_begin(), + E = D->protocol_end(); I != E; ++I, ++PL) + if (Visit(MakeCursorObjCProtocolRef(*I, *PL, TU))) + return true; + + return VisitObjCContainerDecl(D); } -// Declaration visitor. -class CDeclVisitor : public DeclVisitor<CDeclVisitor> { - CXDecl CDecl; - CXDeclIterator Callback; - CXClientData CData; +bool CursorVisitor::VisitObjCImplDecl(ObjCImplDecl *D) { + return VisitObjCContainerDecl(D); +} - // MaxPCHLevel - the maximum PCH level of declarations that we will pass on - // to the visitor. Declarations with a PCH level greater than this value will - // be suppressed. - unsigned MaxPCHLevel; +bool CursorVisitor::VisitObjCCategoryImplDecl(ObjCCategoryImplDecl *D) { + if (Visit(MakeCursorObjCClassRef(D->getCategoryDecl()->getClassInterface(), + D->getLocation(), TU))) + return true; + + return VisitObjCImplDecl(D); +} - void Call(enum CXCursorKind CK, NamedDecl *ND) { - // Disable the callback when the context is equal to the visiting decl. - if (CDecl == ND && !clang_isReference(CK)) - return; +bool CursorVisitor::VisitObjCImplementationDecl(ObjCImplementationDecl *D) { +#if 0 + // Issue callbacks for super class. + // FIXME: No source location information! + if (D->getSuperClass() && + Visit(MakeCursorObjCSuperClassRef(D->getSuperClass(), + D->getSuperClassLoc(), + TU))) + return true; +#endif + + return VisitObjCImplDecl(D); +} - // Filter any declarations that have a PCH level greater than what we allow. - if (ND->getPCHLevel() > MaxPCHLevel) - return; +bool CursorVisitor::VisitObjCForwardProtocolDecl(ObjCForwardProtocolDecl *D) { + ObjCForwardProtocolDecl::protocol_loc_iterator PL = D->protocol_loc_begin(); + for (ObjCForwardProtocolDecl::protocol_iterator I = D->protocol_begin(), + E = D->protocol_end(); + I != E; ++I, ++PL) + if (Visit(MakeCursorObjCProtocolRef(*I, *PL, TU))) + return true; + + return false; +} + +bool CursorVisitor::VisitObjCClassDecl(ObjCClassDecl *D) { + for (ObjCClassDecl::iterator C = D->begin(), CEnd = D->end(); C != CEnd; ++C) + if (Visit(MakeCursorObjCClassRef(C->getInterface(), C->getLocation(), TU))) + return true; + + return false; +} + +bool CursorVisitor::VisitBuiltinTypeLoc(BuiltinTypeLoc TL) { + ASTContext &Context = TU->getASTContext(); + + // Some builtin types (such as Objective-C's "id", "sel", and + // "Class") have associated declarations. Create cursors for those. + QualType VisitType; + switch (TL.getType()->getAs<BuiltinType>()->getKind()) { + case BuiltinType::Void: + case BuiltinType::Bool: + case BuiltinType::Char_U: + case BuiltinType::UChar: + case BuiltinType::Char16: + case BuiltinType::Char32: + case BuiltinType::UShort: + case BuiltinType::UInt: + case BuiltinType::ULong: + case BuiltinType::ULongLong: + case BuiltinType::UInt128: + case BuiltinType::Char_S: + case BuiltinType::SChar: + case BuiltinType::WChar: + case BuiltinType::Short: + case BuiltinType::Int: + case BuiltinType::Long: + case BuiltinType::LongLong: + case BuiltinType::Int128: + case BuiltinType::Float: + case BuiltinType::Double: + case BuiltinType::LongDouble: + case BuiltinType::NullPtr: + case BuiltinType::Overload: + case BuiltinType::Dependent: + break; + + case BuiltinType::UndeducedAuto: // FIXME: Deserves a cursor? + break; + + case BuiltinType::ObjCId: + VisitType = Context.getObjCIdType(); + break; + + case BuiltinType::ObjCClass: + VisitType = Context.getObjCClassType(); + break; + + case BuiltinType::ObjCSel: + VisitType = Context.getObjCSelType(); + break; + } - CXCursor C = { CK, ND, 0, 0 }; - Callback(CDecl, C, CData); + if (!VisitType.isNull()) { + if (const TypedefType *Typedef = VisitType->getAs<TypedefType>()) + return Visit(MakeCursorTypeRef(Typedef->getDecl(), TL.getBuiltinLoc(), + TU)); } -public: - CDeclVisitor(CXDecl C, CXDeclIterator cback, CXClientData D, - unsigned MaxPCHLevel) : - CDecl(C), Callback(cback), CData(D), MaxPCHLevel(MaxPCHLevel) {} - - void VisitDeclContext(DeclContext *DC); - void VisitEnumConstantDecl(EnumConstantDecl *ND); - void VisitFieldDecl(FieldDecl *ND); - void VisitFunctionDecl(FunctionDecl *ND); - void VisitObjCCategoryDecl(ObjCCategoryDecl *ND); - void VisitObjCCategoryImplDecl(ObjCCategoryImplDecl *D); - void VisitObjCImplementationDecl(ObjCImplementationDecl *D); - void VisitObjCInterfaceDecl(ObjCInterfaceDecl *D); - void VisitObjCIvarDecl(ObjCIvarDecl *ND); - void VisitObjCMethodDecl(ObjCMethodDecl *ND); - void VisitObjCPropertyDecl(ObjCPropertyDecl *ND); - void VisitObjCProtocolDecl(ObjCProtocolDecl *PID); - void VisitParmVarDecl(ParmVarDecl *ND); - void VisitTagDecl(TagDecl *D); - void VisitVarDecl(VarDecl *ND); -}; -} // end anonymous namespace -void CDeclVisitor::VisitDeclContext(DeclContext *DC) { - for (DeclContext::decl_iterator - I = DC->decls_begin(), E = DC->decls_end(); I != E; ++I) - Visit(*I); + return false; } -void CDeclVisitor::VisitEnumConstantDecl(EnumConstantDecl *ND) { - Call(CXCursor_EnumConstantDecl, ND); +bool CursorVisitor::VisitTypedefTypeLoc(TypedefTypeLoc TL) { + return Visit(MakeCursorTypeRef(TL.getTypedefDecl(), TL.getNameLoc(), TU)); } -void CDeclVisitor::VisitFieldDecl(FieldDecl *ND) { - Call(CXCursor_FieldDecl, ND); +bool CursorVisitor::VisitUnresolvedUsingTypeLoc(UnresolvedUsingTypeLoc TL) { + return Visit(MakeCursorTypeRef(TL.getDecl(), TL.getNameLoc(), TU)); } -void CDeclVisitor::VisitFunctionDecl(FunctionDecl *ND) { - if (ND->isThisDeclarationADefinition()) { - VisitDeclContext(dyn_cast<DeclContext>(ND)); -#if 0 - // Not currently needed. - CompoundStmt *Body = dyn_cast<CompoundStmt>(ND->getBody()); - CRefVisitor RVisit(CDecl, Callback, CData); - RVisit.Visit(Body); -#endif +bool CursorVisitor::VisitTagTypeLoc(TagTypeLoc TL) { + return Visit(MakeCursorTypeRef(TL.getDecl(), TL.getNameLoc(), TU)); +} + +bool CursorVisitor::VisitObjCInterfaceTypeLoc(ObjCInterfaceTypeLoc TL) { + if (Visit(MakeCursorObjCClassRef(TL.getIFaceDecl(), TL.getNameLoc(), TU))) + return true; + + for (unsigned I = 0, N = TL.getNumProtocols(); I != N; ++I) { + if (Visit(MakeCursorObjCProtocolRef(TL.getProtocol(I), TL.getProtocolLoc(I), + TU))) + return true; } -} -void CDeclVisitor::VisitObjCCategoryDecl(ObjCCategoryDecl *ND) { - // Issue callbacks for the containing class. - Call(CXCursor_ObjCClassRef, ND); - // FIXME: Issue callbacks for protocol refs. - VisitDeclContext(dyn_cast<DeclContext>(ND)); + return false; } -void CDeclVisitor::VisitObjCCategoryImplDecl(ObjCCategoryImplDecl *D) { - VisitDeclContext(dyn_cast<DeclContext>(D)); +bool CursorVisitor::VisitObjCObjectPointerTypeLoc(ObjCObjectPointerTypeLoc TL) { + if (TL.hasBaseTypeAsWritten() && Visit(TL.getBaseTypeLoc())) + return true; + + if (TL.hasProtocolsAsWritten()) { + for (unsigned I = 0, N = TL.getNumProtocols(); I != N; ++I) { + if (Visit(MakeCursorObjCProtocolRef(TL.getProtocol(I), + TL.getProtocolLoc(I), + TU))) + return true; + } + } + + return false; } -void CDeclVisitor::VisitObjCImplementationDecl(ObjCImplementationDecl *D) { - VisitDeclContext(dyn_cast<DeclContext>(D)); +bool CursorVisitor::VisitPointerTypeLoc(PointerTypeLoc TL) { + return Visit(TL.getPointeeLoc()); } -void CDeclVisitor::VisitObjCInterfaceDecl(ObjCInterfaceDecl *D) { - // Issue callbacks for super class. - if (D->getSuperClass()) - Call(CXCursor_ObjCSuperClassRef, D); - - for (ObjCProtocolDecl::protocol_iterator I = D->protocol_begin(), - E = D->protocol_end(); I != E; ++I) - Call(CXCursor_ObjCProtocolRef, *I); - VisitDeclContext(dyn_cast<DeclContext>(D)); +bool CursorVisitor::VisitBlockPointerTypeLoc(BlockPointerTypeLoc TL) { + return Visit(TL.getPointeeLoc()); } -void CDeclVisitor::VisitObjCIvarDecl(ObjCIvarDecl *ND) { - Call(CXCursor_ObjCIvarDecl, ND); +bool CursorVisitor::VisitMemberPointerTypeLoc(MemberPointerTypeLoc TL) { + return Visit(TL.getPointeeLoc()); } -void CDeclVisitor::VisitObjCMethodDecl(ObjCMethodDecl *ND) { - if (ND->getBody()) { - Call(ND->isInstanceMethod() ? CXCursor_ObjCInstanceMethodDefn - : CXCursor_ObjCClassMethodDefn, ND); - VisitDeclContext(dyn_cast<DeclContext>(ND)); - } else - Call(ND->isInstanceMethod() ? CXCursor_ObjCInstanceMethodDecl - : CXCursor_ObjCClassMethodDecl, ND); +bool CursorVisitor::VisitLValueReferenceTypeLoc(LValueReferenceTypeLoc TL) { + return Visit(TL.getPointeeLoc()); } -void CDeclVisitor::VisitObjCPropertyDecl(ObjCPropertyDecl *ND) { - Call(CXCursor_ObjCPropertyDecl, ND); +bool CursorVisitor::VisitRValueReferenceTypeLoc(RValueReferenceTypeLoc TL) { + return Visit(TL.getPointeeLoc()); } -void CDeclVisitor::VisitObjCProtocolDecl(ObjCProtocolDecl *PID) { - for (ObjCProtocolDecl::protocol_iterator I = PID->protocol_begin(), - E = PID->protocol_end(); I != E; ++I) - Call(CXCursor_ObjCProtocolRef, *I); +bool CursorVisitor::VisitFunctionTypeLoc(FunctionTypeLoc TL) { + if (Visit(TL.getResultLoc())) + return true; + + for (unsigned I = 0, N = TL.getNumArgs(); I != N; ++I) + if (Visit(MakeCXCursor(TL.getArg(I), TU))) + return true; + + return false; +} + +bool CursorVisitor::VisitArrayTypeLoc(ArrayTypeLoc TL) { + if (Visit(TL.getElementLoc())) + return true; + + if (Expr *Size = TL.getSizeExpr()) + return Visit(MakeCXCursor(Size, StmtParent, TU)); + + return false; +} + +bool CursorVisitor::VisitTypeOfExprTypeLoc(TypeOfExprTypeLoc TL) { + return Visit(MakeCXCursor(TL.getUnderlyingExpr(), StmtParent, TU)); +} + +bool CursorVisitor::VisitTypeOfTypeLoc(TypeOfTypeLoc TL) { + if (TypeSourceInfo *TSInfo = TL.getUnderlyingTInfo()) + return Visit(TSInfo->getTypeLoc()); + + return false; +} + +bool CursorVisitor::VisitStmt(Stmt *S) { + for (Stmt::child_iterator Child = S->child_begin(), ChildEnd = S->child_end(); + Child != ChildEnd; ++Child) { + if (Visit(MakeCXCursor(*Child, StmtParent, TU))) + return true; + } - VisitDeclContext(dyn_cast<DeclContext>(PID)); + return false; } -void CDeclVisitor::VisitParmVarDecl(ParmVarDecl *ND) { - Call(CXCursor_ParmDecl, ND); +bool CursorVisitor::VisitDeclStmt(DeclStmt *S) { + for (DeclStmt::decl_iterator D = S->decl_begin(), DEnd = S->decl_end(); + D != DEnd; ++D) { + if (Visit(MakeCXCursor(*D, TU))) + return true; + } + + return false; } -void CDeclVisitor::VisitTagDecl(TagDecl *D) { - VisitDeclContext(dyn_cast<DeclContext>(D)); +bool CursorVisitor::VisitIfStmt(IfStmt *S) { + if (VarDecl *Var = S->getConditionVariable()) { + if (Visit(MakeCXCursor(Var, TU))) + return true; + } else if (S->getCond() && Visit(MakeCXCursor(S->getCond(), StmtParent, TU))) + return true; + + if (S->getThen() && Visit(MakeCXCursor(S->getThen(), StmtParent, TU))) + return true; + + if (S->getElse() && Visit(MakeCXCursor(S->getElse(), StmtParent, TU))) + return true; + + return false; } -void CDeclVisitor::VisitVarDecl(VarDecl *ND) { - Call(CXCursor_VarDecl, ND); +bool CursorVisitor::VisitSwitchStmt(SwitchStmt *S) { + if (VarDecl *Var = S->getConditionVariable()) { + if (Visit(MakeCXCursor(Var, TU))) + return true; + } else if (S->getCond() && Visit(MakeCXCursor(S->getCond(), StmtParent, TU))) + return true; + + if (S->getBody() && Visit(MakeCXCursor(S->getBody(), StmtParent, TU))) + return true; + + return false; } -static SourceLocation getLocationFromCursor(CXCursor C, - SourceManager &SourceMgr, - NamedDecl *ND) { - if (clang_isReference(C.kind)) { - switch (C.kind) { - case CXCursor_ObjCClassRef: { - if (isa<ObjCInterfaceDecl>(ND)) { - // FIXME: This is a hack (storing the parent decl in the stmt slot). - NamedDecl *parentDecl = static_cast<NamedDecl *>(C.stmt); - return parentDecl->getLocation(); - } - ObjCCategoryDecl *OID = dyn_cast<ObjCCategoryDecl>(ND); - assert(OID && "clang_getCursorLine(): Missing category decl"); - return OID->getClassInterface()->getLocation(); - } - case CXCursor_ObjCSuperClassRef: { - ObjCInterfaceDecl *OID = dyn_cast<ObjCInterfaceDecl>(ND); - assert(OID && "clang_getCursorLine(): Missing interface decl"); - return OID->getSuperClassLoc(); - } - case CXCursor_ObjCProtocolRef: { - ObjCProtocolDecl *OID = dyn_cast<ObjCProtocolDecl>(ND); - assert(OID && "clang_getCursorLine(): Missing protocol decl"); - return OID->getLocation(); - } - case CXCursor_ObjCSelectorRef: { - ObjCMessageExpr *OME = dyn_cast<ObjCMessageExpr>( - static_cast<Stmt *>(C.stmt)); - assert(OME && "clang_getCursorLine(): Missing message expr"); - return OME->getLeftLoc(); /* FIXME: should be a range */ - } - case CXCursor_VarRef: - case CXCursor_FunctionRef: - case CXCursor_EnumConstantRef: { - DeclRefExpr *DRE = dyn_cast<DeclRefExpr>( - static_cast<Stmt *>(C.stmt)); - assert(DRE && "clang_getCursorLine(): Missing decl ref expr"); - return DRE->getLocation(); - } - default: - return SourceLocation(); - } - } else { // We have a declaration or a definition. - SourceLocation SLoc; - switch (ND->getKind()) { - case Decl::ObjCInterface: { - SLoc = dyn_cast<ObjCInterfaceDecl>(ND)->getClassLoc(); - break; - } - case Decl::ObjCProtocol: { - SLoc = ND->getLocation(); /* FIXME: need to get the name location. */ - break; - } - default: { - SLoc = ND->getLocation(); - break; - } - } - if (SLoc.isInvalid()) - return SourceLocation(); - return SourceMgr.getSpellingLoc(SLoc); // handles macro instantiations. +bool CursorVisitor::VisitSizeOfAlignOfExpr(SizeOfAlignOfExpr *E) { + if (E->isArgumentType()) { + if (TypeSourceInfo *TSInfo = E->getArgumentTypeInfo()) + return Visit(TSInfo->getTypeLoc()); + + return false; } + + return VisitExpr(E); +} + +bool CursorVisitor::VisitExplicitCastExpr(ExplicitCastExpr *E) { + if (TypeSourceInfo *TSInfo = E->getTypeInfoAsWritten()) + if (Visit(TSInfo->getTypeLoc())) + return true; + + return VisitCastExpr(E); +} + +bool CursorVisitor::VisitCompoundLiteralExpr(CompoundLiteralExpr *E) { + if (TypeSourceInfo *TSInfo = E->getTypeSourceInfo()) + if (Visit(TSInfo->getTypeLoc())) + return true; + + return VisitExpr(E); } CXString CIndexer::createCXString(const char *String, bool DupString){ @@ -484,7 +871,7 @@ CXString CIndexer::createCXString(const char *String, bool DupString){ extern "C" { CXIndex clang_createIndex(int excludeDeclarationsFromPCH, int displayDiagnostics) { - CIndexer *CIdxr = new CIndexer(new Program()); + CIndexer *CIdxr = new CIndexer(); if (excludeDeclarationsFromPCH) CIdxr->setOnlyLocalDecls(); if (displayDiagnostics) @@ -518,10 +905,22 @@ CXTranslationUnit clang_createTranslationUnitFromSourceFile(CXIndex CIdx, const char *source_filename, int num_command_line_args, - const char **command_line_args) { + const char **command_line_args, + unsigned num_unsaved_files, + struct CXUnsavedFile *unsaved_files) { assert(CIdx && "Passed null CXIndex"); CIndexer *CXXIdx = static_cast<CIndexer *>(CIdx); + llvm::SmallVector<ASTUnit::RemappedFile, 4> RemappedFiles; + for (unsigned I = 0; I != num_unsaved_files; ++I) { + const llvm::MemoryBuffer *Buffer + = llvm::MemoryBuffer::getMemBuffer(unsaved_files[I].Contents, + unsaved_files[I].Contents + unsaved_files[I].Length, + unsaved_files[I].Filename); + RemappedFiles.push_back(std::make_pair(unsaved_files[I].Filename, + Buffer)); + } + if (!CXXIdx->getUseExternalASTGeneration()) { llvm::SmallVector<const char *, 16> Args; @@ -544,7 +943,9 @@ clang_createTranslationUnitFromSourceFile(CXIndex CIdx, CXXIdx->getDiags(), CXXIdx->getClangResourcesPath(), CXXIdx->getOnlyLocalDecls(), - /* UseBumpAllocator = */ true)); + /* UseBumpAllocator = */ true, + RemappedFiles.data(), + RemappedFiles.size())); // FIXME: Until we have broader testing, just drop the entire AST if we // encountered an error. @@ -575,6 +976,17 @@ clang_createTranslationUnitFromSourceFile(CXIndex CIdx, char astTmpFile[L_tmpnam]; argv.push_back(tmpnam(astTmpFile)); + // Remap any unsaved files to temporary files. + std::vector<llvm::sys::Path> TemporaryFiles; + std::vector<std::string> RemapArgs; + if (RemapFiles(num_unsaved_files, unsaved_files, RemapArgs, TemporaryFiles)) + return 0; + + // The pointers into the elements of RemapArgs are stable because we + // won't be adding anything to RemapArgs after this point. + for (unsigned i = 0, e = RemapArgs.size(); i != e; ++i) + argv.push_back(RemapArgs[i].c_str()); + // Process the compiler options, stripping off '-o', '-c', '-fsyntax-only'. for (int i = 0; i < num_command_line_args; ++i) if (const char *arg = command_line_args[i]) { @@ -615,11 +1027,17 @@ clang_createTranslationUnitFromSourceFile(CXIndex CIdx, llvm::errs() << '\n'; } - // Finally, we create the translation unit from the ast file. - ASTUnit *ATU = static_cast<ASTUnit *>( - clang_createTranslationUnit(CIdx, astTmpFile)); + ASTUnit *ATU = ASTUnit::LoadFromPCHFile(astTmpFile, CXXIdx->getDiags(), + CXXIdx->getOnlyLocalDecls(), + /* UseBumpAllocator = */ true, + RemappedFiles.data(), + RemappedFiles.size()); if (ATU) ATU->unlinkTemporaryFile(); + + for (unsigned i = 0, e = TemporaryFiles.size(); i != e; ++i) + TemporaryFiles[i].eraseFromDisk(); + return ATU; } @@ -635,165 +1053,123 @@ CXString clang_getTranslationUnitSpelling(CXTranslationUnit CTUnit) { true); } -void clang_loadTranslationUnit(CXTranslationUnit CTUnit, - CXTranslationUnitIterator callback, - CXClientData CData) { - assert(CTUnit && "Passed null CXTranslationUnit"); - ASTUnit *CXXUnit = static_cast<ASTUnit *>(CTUnit); - ASTContext &Ctx = CXXUnit->getASTContext(); - - unsigned PCHLevel = Decl::MaxPCHLevel; - - // Set the PCHLevel to filter out unwanted decls if requested. - if (CXXUnit->getOnlyLocalDecls()) { - PCHLevel = 0; - - // If the main input was an AST, bump the level. - if (CXXUnit->isMainFileAST()) - ++PCHLevel; - } - - TUVisitor DVisit(CTUnit, callback, CData, PCHLevel); - - // If using a non-AST based ASTUnit, iterate over the stored list of top-level - // decls. - if (!CXXUnit->isMainFileAST() && CXXUnit->getOnlyLocalDecls()) { - const std::vector<Decl*> &TLDs = CXXUnit->getTopLevelDecls(); - for (std::vector<Decl*>::const_iterator it = TLDs.begin(), - ie = TLDs.end(); it != ie; ++it) { - DVisit.Visit(*it); - } - } else - DVisit.Visit(Ctx.getTranslationUnitDecl()); +CXCursor clang_getTranslationUnitCursor(CXTranslationUnit TU) { + CXCursor Result = { CXCursor_TranslationUnit, { 0, 0, TU } }; + return Result; } -void clang_loadDeclaration(CXDecl Dcl, - CXDeclIterator callback, - CXClientData CData) { - assert(Dcl && "Passed null CXDecl"); - - CDeclVisitor DVisit(Dcl, callback, CData, - static_cast<Decl *>(Dcl)->getPCHLevel()); - DVisit.Visit(static_cast<Decl *>(Dcl)); -} } // end: extern "C" //===----------------------------------------------------------------------===// -// CXDecl Operations. +// CXSourceLocation and CXSourceRange Operations. //===----------------------------------------------------------------------===// -static const FileEntry *getFileEntryFromSourceLocation(SourceManager &SMgr, - SourceLocation SLoc) { - FileID FID; - if (SLoc.isFileID()) - FID = SMgr.getFileID(SLoc); - else - FID = SMgr.getDecomposedSpellingLoc(SLoc).first; - return SMgr.getFileEntryForID(FID); -} - extern "C" { -CXString clang_getDeclSpelling(CXDecl AnonDecl) { - assert(AnonDecl && "Passed null CXDecl"); - NamedDecl *ND = static_cast<NamedDecl *>(AnonDecl); - - if (ObjCMethodDecl *OMD = dyn_cast<ObjCMethodDecl>(ND)) - return CIndexer::createCXString(OMD->getSelector().getAsString().c_str(), - true); - - if (ObjCCategoryImplDecl *CIMP = dyn_cast<ObjCCategoryImplDecl>(ND)) - // No, this isn't the same as the code below. getIdentifier() is non-virtual - // and returns different names. NamedDecl returns the class name and - // ObjCCategoryImplDecl returns the category name. - return CIndexer::createCXString(CIMP->getIdentifier()->getNameStart()); - - if (ND->getIdentifier()) - return CIndexer::createCXString(ND->getIdentifier()->getNameStart()); - - return CIndexer::createCXString(""); +CXSourceLocation clang_getNullLocation() { + CXSourceLocation Result = { 0, 0 }; + return Result; } -unsigned clang_getDeclLine(CXDecl AnonDecl) { - assert(AnonDecl && "Passed null CXDecl"); - NamedDecl *ND = static_cast<NamedDecl *>(AnonDecl); - SourceManager &SourceMgr = ND->getASTContext().getSourceManager(); - return SourceMgr.getSpellingLineNumber(ND->getLocation()); +unsigned clang_equalLocations(CXSourceLocation loc1, CXSourceLocation loc2) { + return loc1.ptr_data == loc2.ptr_data && loc1.int_data == loc2.int_data; } -unsigned clang_getDeclColumn(CXDecl AnonDecl) { - assert(AnonDecl && "Passed null CXDecl"); - NamedDecl *ND = static_cast<NamedDecl *>(AnonDecl); - SourceManager &SourceMgr = ND->getASTContext().getSourceManager(); - return SourceMgr.getSpellingColumnNumber(ND->getLocation()); -} +CXSourceLocation clang_getLocation(CXTranslationUnit tu, + CXFile file, + unsigned line, + unsigned column) { + if (!tu) + return clang_getNullLocation(); -CXDeclExtent clang_getDeclExtent(CXDecl AnonDecl) { - assert(AnonDecl && "Passed null CXDecl"); - NamedDecl *ND = static_cast<NamedDecl *>(AnonDecl); - SourceManager &SM = ND->getASTContext().getSourceManager(); - SourceRange R = ND->getSourceRange(); - - SourceLocation Begin = SM.getInstantiationLoc(R.getBegin()); - SourceLocation End = SM.getInstantiationLoc(R.getEnd()); + ASTUnit *CXXUnit = static_cast<ASTUnit *>(tu); + SourceLocation SLoc + = CXXUnit->getSourceManager().getLocation( + static_cast<const FileEntry *>(file), + line, column); + + return translateSourceLocation(CXXUnit->getASTContext(), SLoc, false); +} - if (!Begin.isValid()) { - CXDeclExtent extent = { { 0, 0 }, { 0, 0 } }; - return extent; +CXSourceRange clang_getRange(CXSourceLocation begin, CXSourceLocation end) { + if (begin.ptr_data != end.ptr_data) { + CXSourceRange Result = { 0, 0, 0 }; + return Result; } + CXSourceRange Result = { begin.ptr_data, begin.int_data, end.int_data }; + return Result; +} + +void clang_getInstantiationLocation(CXSourceLocation location, + CXFile *file, + unsigned *line, + unsigned *column) { + CXSourceLocationPtr Ptr + = CXSourceLocationPtr::getFromOpaqueValue(location.ptr_data); + SourceLocation Loc = SourceLocation::getFromRawEncoding(location.int_data); + + if (!Ptr.getPointer() || Loc.isInvalid()) { + if (file) + *file = 0; + if (line) + *line = 0; + if (column) + *column = 0; + return; + } + // FIXME: This is largely copy-paste from ///TextDiagnosticPrinter::HighlightRange. When it is clear that this is - // what we want the two routines should be refactored. - - // If the End location and the start location are the same and are a macro - // location, then the range was something that came from a macro expansion - // or _Pragma. If this is an object-like macro, the best we can do is to - // get the range. If this is a function-like macro, we'd also like to - // get the arguments. - if (Begin == End && R.getEnd().isMacroID()) - End = SM.getInstantiationRange(R.getEnd()).second; - - assert(SM.getFileID(Begin) == SM.getFileID(End)); - unsigned StartLineNo = SM.getInstantiationLineNumber(Begin); - unsigned EndLineNo = SM.getInstantiationLineNumber(End); - - // Compute the column number of the start. Keep the column based at 1. - unsigned StartColNo = SM.getInstantiationColumnNumber(Begin); - - // Compute the column number of the end. - unsigned EndColNo = SM.getInstantiationColumnNumber(End); - if (EndColNo) { - // Offset the end column by 1 so that we point to the last character - // in the last token. - --EndColNo; - - // Add in the length of the token, so that we cover multi-char tokens. - ASTContext &Ctx = ND->getTranslationUnitDecl()->getASTContext(); - const LangOptions &LOpts = Ctx.getLangOptions(); - - EndColNo += Lexer::MeasureTokenLength(End, SM, LOpts); + // what we want the two routines should be refactored. + ASTContext &Context = *Ptr.getPointer(); + SourceManager &SM = Context.getSourceManager(); + SourceLocation InstLoc = SM.getInstantiationLoc(Loc); + + if (Ptr.getInt()) { + // We want the last character in this location, so we will adjust + // the instantiation location accordingly. + + // If the location is from a macro instantiation, get the end of + // the instantiation range. + if (Loc.isMacroID()) + InstLoc = SM.getInstantiationRange(Loc).second; + + // Measure the length token we're pointing at, so we can adjust + // the physical location in the file to point at the last + // character. + // FIXME: This won't cope with trigraphs or escaped newlines + // well. For that, we actually need a preprocessor, which isn't + // currently available here. Eventually, we'll switch the pointer + // data of CXSourceLocation/CXSourceRange to a translation unit + // (CXXUnit), so that the preprocessor will be available here. At + // that point, we can use Preprocessor::getLocForEndOfToken(). + unsigned Length = Lexer::MeasureTokenLength(InstLoc, SM, + Context.getLangOptions()); + if (Length > 0) + InstLoc = InstLoc.getFileLocWithOffset(Length - 1); } - // Package up the line/column data and return to the caller. - CXDeclExtent extent = { { StartLineNo, StartColNo }, - { EndLineNo, EndColNo } }; - return extent; + if (file) + *file = (void *)SM.getFileEntryForID(SM.getFileID(InstLoc)); + if (line) + *line = SM.getInstantiationLineNumber(InstLoc); + if (column) + *column = SM.getInstantiationColumnNumber(InstLoc); } -const char *clang_getDeclSource(CXDecl AnonDecl) { - assert(AnonDecl && "Passed null CXDecl"); - FileEntry *FEnt = static_cast<FileEntry *>(clang_getDeclSourceFile(AnonDecl)); - assert(FEnt && "Cannot find FileEntry for Decl"); - return clang_getFileName(FEnt); +CXSourceLocation clang_getRangeStart(CXSourceRange range) { + CXSourceLocation Result = { range.ptr_data, range.begin_int_data }; + return Result; } - -CXFile clang_getDeclSourceFile(CXDecl AnonDecl) { - assert(AnonDecl && "Passed null CXDecl"); - NamedDecl *ND = static_cast<NamedDecl *>(AnonDecl); - SourceManager &SourceMgr = ND->getASTContext().getSourceManager(); - return (void *)getFileEntryFromSourceLocation(SourceMgr, ND->getLocation()); +CXSourceLocation clang_getRangeEnd(CXSourceRange range) { + llvm::PointerIntPair<ASTContext *, 1, bool> Ptr; + Ptr.setPointer(static_cast<ASTContext *>(range.ptr_data)); + Ptr.setInt(true); + CXSourceLocation Result = { Ptr.getOpaqueValue(), range.end_int_data }; + return Result; } + } // end: extern "C" //===----------------------------------------------------------------------===// @@ -802,58 +1178,40 @@ CXFile clang_getDeclSourceFile(CXDecl AnonDecl) { extern "C" { const char *clang_getFileName(CXFile SFile) { + if (!SFile) + return 0; + assert(SFile && "Passed null CXFile"); FileEntry *FEnt = static_cast<FileEntry *>(SFile); return FEnt->getName(); } time_t clang_getFileTime(CXFile SFile) { + if (!SFile) + return 0; + assert(SFile && "Passed null CXFile"); FileEntry *FEnt = static_cast<FileEntry *>(SFile); return FEnt->getModificationTime(); } + +CXFile clang_getFile(CXTranslationUnit tu, const char *file_name) { + if (!tu) + return 0; + + ASTUnit *CXXUnit = static_cast<ASTUnit *>(tu); + + FileManager &FMgr = CXXUnit->getFileManager(); + const FileEntry *File = FMgr.getFile(file_name, file_name+strlen(file_name)); + return const_cast<FileEntry *>(File); +} + } // end: extern "C" //===----------------------------------------------------------------------===// // CXCursor Operations. //===----------------------------------------------------------------------===// -static enum CXCursorKind TranslateKind(Decl *D) { - switch (D->getKind()) { - case Decl::Function: return CXCursor_FunctionDecl; - case Decl::Typedef: return CXCursor_TypedefDecl; - case Decl::Enum: return CXCursor_EnumDecl; - case Decl::EnumConstant: return CXCursor_EnumConstantDecl; - case Decl::Record: return CXCursor_StructDecl; // FIXME: union/class - case Decl::Field: return CXCursor_FieldDecl; - case Decl::Var: return CXCursor_VarDecl; - case Decl::ParmVar: return CXCursor_ParmDecl; - case Decl::ObjCInterface: return CXCursor_ObjCInterfaceDecl; - case Decl::ObjCCategory: return CXCursor_ObjCCategoryDecl; - case Decl::ObjCProtocol: return CXCursor_ObjCProtocolDecl; - case Decl::ObjCMethod: { - ObjCMethodDecl *MD = dyn_cast<ObjCMethodDecl>(D); - if (MD->isInstanceMethod()) - return CXCursor_ObjCInstanceMethodDecl; - return CXCursor_ObjCClassMethodDecl; - } - default: break; - } - return CXCursor_NotImplemented; -} - - -static CXCursor MakeCXCursor(CXCursorKind K, Decl *D) { - CXCursor C = { K, D, 0, 0 }; - return C; -} - -static CXCursor MakeCXCursor(CXCursorKind K, Decl *D, Stmt *S) { - assert(clang_isReference(K)); - CXCursor C = { K, D, S, 0 }; - return C; -} - static Decl *getDeclFromExpr(Stmt *E) { if (DeclRefExpr *RefExpr = dyn_cast<DeclRefExpr>(E)) return RefExpr->getDecl(); @@ -873,53 +1231,90 @@ static Decl *getDeclFromExpr(Stmt *E) { } extern "C" { + +unsigned clang_visitChildren(CXCursor parent, + CXCursorVisitor visitor, + CXClientData client_data) { + ASTUnit *CXXUnit = getCursorASTUnit(parent); + + unsigned PCHLevel = Decl::MaxPCHLevel; + + // Set the PCHLevel to filter out unwanted decls if requested. + if (CXXUnit->getOnlyLocalDecls()) { + PCHLevel = 0; + + // If the main input was an AST, bump the level. + if (CXXUnit->isMainFileAST()) + ++PCHLevel; + } + + CursorVisitor CursorVis(CXXUnit, visitor, client_data, PCHLevel); + return CursorVis.VisitChildren(parent); +} + +static CXString getDeclSpelling(Decl *D) { + NamedDecl *ND = dyn_cast_or_null<NamedDecl>(D); + if (!ND) + return CIndexer::createCXString(""); + + if (ObjCMethodDecl *OMD = dyn_cast<ObjCMethodDecl>(ND)) + return CIndexer::createCXString(OMD->getSelector().getAsString().c_str(), + true); + + if (ObjCCategoryImplDecl *CIMP = dyn_cast<ObjCCategoryImplDecl>(ND)) + // No, this isn't the same as the code below. getIdentifier() is non-virtual + // and returns different names. NamedDecl returns the class name and + // ObjCCategoryImplDecl returns the category name. + return CIndexer::createCXString(CIMP->getIdentifier()->getNameStart()); + + if (ND->getIdentifier()) + return CIndexer::createCXString(ND->getIdentifier()->getNameStart()); + + return CIndexer::createCXString(""); +} + CXString clang_getCursorSpelling(CXCursor C) { - assert(C.decl && "CXCursor has null decl"); - NamedDecl *ND = static_cast<NamedDecl *>(C.decl); + assert(getCursorDecl(C) && "CXCursor has null decl"); + if (clang_isTranslationUnit(C.kind)) + return clang_getTranslationUnitSpelling(C.data[2]); if (clang_isReference(C.kind)) { switch (C.kind) { case CXCursor_ObjCSuperClassRef: { - ObjCInterfaceDecl *OID = dyn_cast<ObjCInterfaceDecl>(ND); - assert(OID && "clang_getCursorLine(): Missing interface decl"); - return CIndexer::createCXString(OID->getSuperClass()->getIdentifier() - ->getNameStart()); + ObjCInterfaceDecl *Super = getCursorObjCSuperClassRef(C).first; + return CIndexer::createCXString(Super->getIdentifier()->getNameStart()); } case CXCursor_ObjCClassRef: { - if (ObjCInterfaceDecl *OID = dyn_cast<ObjCInterfaceDecl>(ND)) - return CIndexer::createCXString(OID->getIdentifier()->getNameStart()); - - ObjCCategoryDecl *OCD = dyn_cast<ObjCCategoryDecl>(ND); - assert(OCD && "clang_getCursorLine(): Missing category decl"); - return CIndexer::createCXString(OCD->getClassInterface()->getIdentifier() - ->getNameStart()); + ObjCInterfaceDecl *Class = getCursorObjCClassRef(C).first; + return CIndexer::createCXString(Class->getIdentifier()->getNameStart()); } case CXCursor_ObjCProtocolRef: { - ObjCProtocolDecl *OID = dyn_cast<ObjCProtocolDecl>(ND); - assert(OID && "clang_getCursorLine(): Missing protocol decl"); + ObjCProtocolDecl *OID = getCursorObjCProtocolRef(C).first; + assert(OID && "getCursorSpelling(): Missing protocol decl"); return CIndexer::createCXString(OID->getIdentifier()->getNameStart()); } - case CXCursor_ObjCSelectorRef: { - ObjCMessageExpr *OME = dyn_cast<ObjCMessageExpr>( - static_cast<Stmt *>(C.stmt)); - assert(OME && "clang_getCursorLine(): Missing message expr"); - return CIndexer::createCXString(OME->getSelector().getAsString().c_str(), + case CXCursor_TypeRef: { + TypeDecl *Type = getCursorTypeRef(C).first; + assert(Type && "Missing type decl"); + + return CIndexer::createCXString( + getCursorContext(C).getTypeDeclType(Type).getAsString().c_str(), true); } - case CXCursor_VarRef: - case CXCursor_FunctionRef: - case CXCursor_EnumConstantRef: { - DeclRefExpr *DRE = dyn_cast<DeclRefExpr>( - static_cast<Stmt *>(C.stmt)); - assert(DRE && "clang_getCursorLine(): Missing decl ref expr"); - return CIndexer::createCXString(DRE->getDecl()->getIdentifier() - ->getNameStart()); - } + default: return CIndexer::createCXString("<not implemented>"); } } - return clang_getDeclSpelling(C.decl); + + if (clang_isExpression(C.kind)) { + Decl *D = getDeclFromExpr(getCursorExpr(C)); + if (D) + return getDeclSpelling(D); + return CIndexer::createCXString(""); + } + + return getDeclSpelling(getCursorDecl(C)); } const char *clang_getCursorKindSpelling(enum CXCursorKind Kind) { @@ -941,90 +1336,66 @@ const char *clang_getCursorKindSpelling(enum CXCursorKind Kind) { case CXCursor_ObjCIvarDecl: return "ObjCIvarDecl"; case CXCursor_ObjCInstanceMethodDecl: return "ObjCInstanceMethodDecl"; case CXCursor_ObjCClassMethodDecl: return "ObjCClassMethodDecl"; - case CXCursor_FunctionDefn: return "FunctionDefn"; - case CXCursor_ObjCInstanceMethodDefn: return "ObjCInstanceMethodDefn"; - case CXCursor_ObjCClassMethodDefn: return "ObjCClassMethodDefn"; - case CXCursor_ObjCClassDefn: return "ObjCClassDefn"; - case CXCursor_ObjCCategoryDefn: return "ObjCCategoryDefn"; + case CXCursor_ObjCImplementationDecl: return "ObjCImplementationDecl"; + case CXCursor_ObjCCategoryImplDecl: return "ObjCCategoryImplDecl"; + case CXCursor_UnexposedDecl: return "UnexposedDecl"; case CXCursor_ObjCSuperClassRef: return "ObjCSuperClassRef"; case CXCursor_ObjCProtocolRef: return "ObjCProtocolRef"; case CXCursor_ObjCClassRef: return "ObjCClassRef"; - case CXCursor_ObjCSelectorRef: return "ObjCSelectorRef"; - - case CXCursor_VarRef: return "VarRef"; - case CXCursor_FunctionRef: return "FunctionRef"; - case CXCursor_EnumConstantRef: return "EnumConstantRef"; - case CXCursor_MemberRef: return "MemberRef"; - + case CXCursor_TypeRef: return "TypeRef"; + case CXCursor_UnexposedExpr: return "UnexposedExpr"; + case CXCursor_DeclRefExpr: return "DeclRefExpr"; + case CXCursor_MemberRefExpr: return "MemberRefExpr"; + case CXCursor_CallExpr: return "CallExpr"; + case CXCursor_ObjCMessageExpr: return "ObjCMessageExpr"; + case CXCursor_UnexposedStmt: return "UnexposedStmt"; case CXCursor_InvalidFile: return "InvalidFile"; case CXCursor_NoDeclFound: return "NoDeclFound"; case CXCursor_NotImplemented: return "NotImplemented"; - default: return "<not implemented>"; + case CXCursor_TranslationUnit: return "TranslationUnit"; } + + llvm_unreachable("Unhandled CXCursorKind"); + return NULL; } -CXCursor clang_getCursor(CXTranslationUnit CTUnit, const char *source_name, - unsigned line, unsigned column) { - assert(CTUnit && "Passed null CXTranslationUnit"); - ASTUnit *CXXUnit = static_cast<ASTUnit *>(CTUnit); - - FileManager &FMgr = CXXUnit->getFileManager(); - const FileEntry *File = FMgr.getFile(source_name, - source_name+strlen(source_name)); - if (!File) +enum CXChildVisitResult GetCursorVisitor(CXCursor cursor, + CXCursor parent, + CXClientData client_data) { + CXCursor *BestCursor = static_cast<CXCursor *>(client_data); + *BestCursor = cursor; + return CXChildVisit_Recurse; +} + +CXCursor clang_getCursor(CXTranslationUnit TU, CXSourceLocation Loc) { + if (!TU) return clang_getNullCursor(); + + ASTUnit *CXXUnit = static_cast<ASTUnit *>(TU); - SourceLocation SLoc = - CXXUnit->getSourceManager().getLocation(File, line, column); - - ASTLocation LastLoc = CXXUnit->getLastASTLocation(); - ASTLocation ALoc = ResolveLocationInAST(CXXUnit->getASTContext(), SLoc, - &LastLoc); - - // FIXME: This doesn't look thread-safe. - if (ALoc.isValid()) - CXXUnit->setLastASTLocation(ALoc); - - Decl *Dcl = ALoc.getParentDecl(); - if (ALoc.isNamedRef()) - Dcl = ALoc.AsNamedRef().ND; - Stmt *Stm = ALoc.dyn_AsStmt(); - if (Dcl) { - if (Stm) { - if (DeclRefExpr *DRE = dyn_cast<DeclRefExpr>(Stm)) - return MakeCXCursor(TranslateDeclRefExpr(DRE), Dcl, Stm); - else if (ObjCMessageExpr *MExp = dyn_cast<ObjCMessageExpr>(Stm)) - return MakeCXCursor(CXCursor_ObjCSelectorRef, Dcl, MExp); - // Fall through...treat as a decl, not a ref. - } - if (ALoc.isNamedRef()) { - if (isa<ObjCInterfaceDecl>(Dcl)) { - CXCursor C = { CXCursor_ObjCClassRef, Dcl, ALoc.getParentDecl(), 0 }; - return C; - } - if (isa<ObjCProtocolDecl>(Dcl)) { - CXCursor C = { CXCursor_ObjCProtocolRef, Dcl, ALoc.getParentDecl(), 0 }; - return C; - } - } - return MakeCXCursor(TranslateKind(Dcl), Dcl); + SourceLocation SLoc = translateSourceLocation(Loc); + CXCursor Result = MakeCXCursorInvalid(CXCursor_NoDeclFound); + if (SLoc.isValid()) { + SourceRange RegionOfInterest(SLoc, + CXXUnit->getPreprocessor().getLocForEndOfToken(SLoc, 1)); + + // FIXME: Would be great to have a "hint" cursor, then walk from that + // hint cursor upward until we find a cursor whose source range encloses + // the region of interest, rather than starting from the translation unit. + CXCursor Parent = clang_getTranslationUnitCursor(CXXUnit); + CursorVisitor CursorVis(CXXUnit, GetCursorVisitor, &Result, + Decl::MaxPCHLevel, RegionOfInterest); + CursorVis.VisitChildren(Parent); } - return MakeCXCursor(CXCursor_NoDeclFound, 0); + return Result; } CXCursor clang_getNullCursor(void) { - return MakeCXCursor(CXCursor_InvalidFile, 0); + return MakeCXCursorInvalid(CXCursor_InvalidFile); } unsigned clang_equalCursors(CXCursor X, CXCursor Y) { - return X.kind == Y.kind && X.decl == Y.decl && X.stmt == Y.stmt && - X.referringDecl == Y.referringDecl; -} - -CXCursor clang_getCursorFromDecl(CXDecl AnonDecl) { - assert(AnonDecl && "Passed null CXDecl"); - NamedDecl *ND = static_cast<NamedDecl *>(AnonDecl); - return MakeCXCursor(TranslateKind(ND), ND); + return X == Y; } unsigned clang_isInvalid(enum CXCursorKind K) { @@ -1039,80 +1410,413 @@ unsigned clang_isReference(enum CXCursorKind K) { return K >= CXCursor_FirstRef && K <= CXCursor_LastRef; } -unsigned clang_isDefinition(enum CXCursorKind K) { - return K >= CXCursor_FirstDefn && K <= CXCursor_LastDefn; +unsigned clang_isExpression(enum CXCursorKind K) { + return K >= CXCursor_FirstExpr && K <= CXCursor_LastExpr; +} + +unsigned clang_isStatement(enum CXCursorKind K) { + return K >= CXCursor_FirstStmt && K <= CXCursor_LastStmt; +} + +unsigned clang_isTranslationUnit(enum CXCursorKind K) { + return K == CXCursor_TranslationUnit; } CXCursorKind clang_getCursorKind(CXCursor C) { return C.kind; } -CXDecl clang_getCursorDecl(CXCursor C) { - if (clang_isDeclaration(C.kind)) - return C.decl; +static SourceLocation getLocationFromExpr(Expr *E) { + if (ObjCMessageExpr *Msg = dyn_cast<ObjCMessageExpr>(E)) + return /*FIXME:*/Msg->getLeftLoc(); + if (DeclRefExpr *DRE = dyn_cast<DeclRefExpr>(E)) + return DRE->getLocation(); + if (MemberExpr *Member = dyn_cast<MemberExpr>(E)) + return Member->getMemberLoc(); + if (ObjCIvarRefExpr *Ivar = dyn_cast<ObjCIvarRefExpr>(E)) + return Ivar->getLocation(); + return E->getLocStart(); +} +CXSourceLocation clang_getCursorLocation(CXCursor C) { if (clang_isReference(C.kind)) { - if (C.stmt) { - if (C.kind == CXCursor_ObjCClassRef || - C.kind == CXCursor_ObjCProtocolRef) - return static_cast<Stmt *>(C.stmt); - else - return getDeclFromExpr(static_cast<Stmt *>(C.stmt)); - } else - return C.decl; + switch (C.kind) { + case CXCursor_ObjCSuperClassRef: { + std::pair<ObjCInterfaceDecl *, SourceLocation> P + = getCursorObjCSuperClassRef(C); + return translateSourceLocation(P.first->getASTContext(), P.second); + } + + case CXCursor_ObjCProtocolRef: { + std::pair<ObjCProtocolDecl *, SourceLocation> P + = getCursorObjCProtocolRef(C); + return translateSourceLocation(P.first->getASTContext(), P.second); + } + + case CXCursor_ObjCClassRef: { + std::pair<ObjCInterfaceDecl *, SourceLocation> P + = getCursorObjCClassRef(C); + return translateSourceLocation(P.first->getASTContext(), P.second); + } + + case CXCursor_TypeRef: { + std::pair<TypeDecl *, SourceLocation> P = getCursorTypeRef(C); + return translateSourceLocation(P.first->getASTContext(), P.second); + } + + default: + // FIXME: Need a way to enumerate all non-reference cases. + llvm_unreachable("Missed a reference kind"); + } } - return 0; -} -unsigned clang_getCursorLine(CXCursor C) { - assert(C.decl && "CXCursor has null decl"); - NamedDecl *ND = static_cast<NamedDecl *>(C.decl); - SourceManager &SourceMgr = ND->getASTContext().getSourceManager(); + if (clang_isExpression(C.kind)) + return translateSourceLocation(getCursorContext(C), + getLocationFromExpr(getCursorExpr(C))); + + if (!getCursorDecl(C)) { + CXSourceLocation empty = { 0, 0 }; + return empty; + } - SourceLocation SLoc = getLocationFromCursor(C, SourceMgr, ND); - return SourceMgr.getSpellingLineNumber(SLoc); + Decl *D = getCursorDecl(C); + SourceLocation Loc = D->getLocation(); + if (ObjCInterfaceDecl *Class = dyn_cast<ObjCInterfaceDecl>(D)) + Loc = Class->getClassLoc(); + return translateSourceLocation(D->getASTContext(), Loc); } + +CXSourceRange clang_getCursorExtent(CXCursor C) { + if (clang_isReference(C.kind)) { + switch (C.kind) { + case CXCursor_ObjCSuperClassRef: { + std::pair<ObjCInterfaceDecl *, SourceLocation> P + = getCursorObjCSuperClassRef(C); + return translateSourceRange(P.first->getASTContext(), P.second); + } + + case CXCursor_ObjCProtocolRef: { + std::pair<ObjCProtocolDecl *, SourceLocation> P + = getCursorObjCProtocolRef(C); + return translateSourceRange(P.first->getASTContext(), P.second); + } + + case CXCursor_ObjCClassRef: { + std::pair<ObjCInterfaceDecl *, SourceLocation> P + = getCursorObjCClassRef(C); + + return translateSourceRange(P.first->getASTContext(), P.second); + } + + case CXCursor_TypeRef: { + std::pair<TypeDecl *, SourceLocation> P = getCursorTypeRef(C); + return translateSourceRange(P.first->getASTContext(), P.second); + } + + default: + // FIXME: Need a way to enumerate all non-reference cases. + llvm_unreachable("Missed a reference kind"); + } + } + + if (clang_isExpression(C.kind)) + return translateSourceRange(getCursorContext(C), + getCursorExpr(C)->getSourceRange()); + + if (clang_isStatement(C.kind)) + return translateSourceRange(getCursorContext(C), + getCursorStmt(C)->getSourceRange()); -unsigned clang_getCursorColumn(CXCursor C) { - assert(C.decl && "CXCursor has null decl"); - NamedDecl *ND = static_cast<NamedDecl *>(C.decl); - SourceManager &SourceMgr = ND->getASTContext().getSourceManager(); + if (!getCursorDecl(C)) { + CXSourceRange empty = { 0, 0, 0 }; + return empty; + } - SourceLocation SLoc = getLocationFromCursor(C, SourceMgr, ND); - return SourceMgr.getSpellingColumnNumber(SLoc); + Decl *D = getCursorDecl(C); + return translateSourceRange(D->getASTContext(), D->getSourceRange()); } -const char *clang_getCursorSource(CXCursor C) { - assert(C.decl && "CXCursor has null decl"); - NamedDecl *ND = static_cast<NamedDecl *>(C.decl); - SourceManager &SourceMgr = ND->getASTContext().getSourceManager(); +CXCursor clang_getCursorReferenced(CXCursor C) { + if (clang_isInvalid(C.kind)) + return clang_getNullCursor(); - SourceLocation SLoc = getLocationFromCursor(C, SourceMgr, ND); + ASTUnit *CXXUnit = getCursorASTUnit(C); + if (clang_isDeclaration(C.kind)) + return C; - if (SLoc.isFileID()) { - const char *bufferName = SourceMgr.getBufferName(SLoc); - return bufferName[0] == '<' ? NULL : bufferName; + if (clang_isExpression(C.kind)) { + Decl *D = getDeclFromExpr(getCursorExpr(C)); + if (D) + return MakeCXCursor(D, CXXUnit); + return clang_getNullCursor(); } + + if (!clang_isReference(C.kind)) + return clang_getNullCursor(); - // Retrieve the file in which the macro was instantiated, then provide that - // buffer name. - // FIXME: Do we want to give specific macro-instantiation information? - const llvm::MemoryBuffer *Buffer - = SourceMgr.getBuffer(SourceMgr.getDecomposedSpellingLoc(SLoc).first); - if (!Buffer) - return 0; + switch (C.kind) { + case CXCursor_ObjCSuperClassRef: + return MakeCXCursor(getCursorObjCSuperClassRef(C).first, CXXUnit); + + case CXCursor_ObjCProtocolRef: { + return MakeCXCursor(getCursorObjCProtocolRef(C).first, CXXUnit); + + case CXCursor_ObjCClassRef: + return MakeCXCursor(getCursorObjCClassRef(C).first, CXXUnit); + + case CXCursor_TypeRef: + return MakeCXCursor(getCursorTypeRef(C).first, CXXUnit); + + default: + // We would prefer to enumerate all non-reference cursor kinds here. + llvm_unreachable("Unhandled reference cursor kind"); + break; + } + } - return Buffer->getBufferIdentifier(); + return clang_getNullCursor(); } -CXFile clang_getCursorSourceFile(CXCursor C) { - assert(C.decl && "CXCursor has null decl"); - NamedDecl *ND = static_cast<NamedDecl *>(C.decl); - SourceManager &SourceMgr = ND->getASTContext().getSourceManager(); +CXCursor clang_getCursorDefinition(CXCursor C) { + if (clang_isInvalid(C.kind)) + return clang_getNullCursor(); + + ASTUnit *CXXUnit = getCursorASTUnit(C); + + bool WasReference = false; + if (clang_isReference(C.kind) || clang_isExpression(C.kind)) { + C = clang_getCursorReferenced(C); + WasReference = true; + } + + if (!clang_isDeclaration(C.kind)) + return clang_getNullCursor(); + + Decl *D = getCursorDecl(C); + if (!D) + return clang_getNullCursor(); + + switch (D->getKind()) { + // Declaration kinds that don't really separate the notions of + // declaration and definition. + case Decl::Namespace: + case Decl::Typedef: + case Decl::TemplateTypeParm: + case Decl::EnumConstant: + case Decl::Field: + case Decl::ObjCIvar: + case Decl::ObjCAtDefsField: + case Decl::ImplicitParam: + case Decl::ParmVar: + case Decl::NonTypeTemplateParm: + case Decl::TemplateTemplateParm: + case Decl::ObjCCategoryImpl: + case Decl::ObjCImplementation: + case Decl::LinkageSpec: + case Decl::ObjCPropertyImpl: + case Decl::FileScopeAsm: + case Decl::StaticAssert: + case Decl::Block: + return C; + + // Declaration kinds that don't make any sense here, but are + // nonetheless harmless. + case Decl::TranslationUnit: + case Decl::Template: + case Decl::ObjCContainer: + break; + + // Declaration kinds for which the definition is not resolvable. + case Decl::UnresolvedUsingTypename: + case Decl::UnresolvedUsingValue: + break; + + case Decl::UsingDirective: + return MakeCXCursor(cast<UsingDirectiveDecl>(D)->getNominatedNamespace(), + CXXUnit); + + case Decl::NamespaceAlias: + return MakeCXCursor(cast<NamespaceAliasDecl>(D)->getNamespace(), CXXUnit); + + case Decl::Enum: + case Decl::Record: + case Decl::CXXRecord: + case Decl::ClassTemplateSpecialization: + case Decl::ClassTemplatePartialSpecialization: + if (TagDecl *Def = cast<TagDecl>(D)->getDefinition(D->getASTContext())) + return MakeCXCursor(Def, CXXUnit); + return clang_getNullCursor(); + + case Decl::Function: + case Decl::CXXMethod: + case Decl::CXXConstructor: + case Decl::CXXDestructor: + case Decl::CXXConversion: { + const FunctionDecl *Def = 0; + if (cast<FunctionDecl>(D)->getBody(Def)) + return MakeCXCursor(const_cast<FunctionDecl *>(Def), CXXUnit); + return clang_getNullCursor(); + } + + case Decl::Var: { + VarDecl *Var = cast<VarDecl>(D); + + // Variables with initializers have definitions. + const VarDecl *Def = 0; + if (Var->getDefinition(Def)) + return MakeCXCursor(const_cast<VarDecl *>(Def), CXXUnit); + + // extern and private_extern variables are not definitions. + if (Var->hasExternalStorage()) + return clang_getNullCursor(); + + // In-line static data members do not have definitions. + if (Var->isStaticDataMember() && !Var->isOutOfLine()) + return clang_getNullCursor(); + + // All other variables are themselves definitions. + return C; + } + + case Decl::FunctionTemplate: { + const FunctionDecl *Def = 0; + if (cast<FunctionTemplateDecl>(D)->getTemplatedDecl()->getBody(Def)) + return MakeCXCursor(Def->getDescribedFunctionTemplate(), CXXUnit); + return clang_getNullCursor(); + } + + case Decl::ClassTemplate: { + if (RecordDecl *Def = cast<ClassTemplateDecl>(D)->getTemplatedDecl() + ->getDefinition(D->getASTContext())) + return MakeCXCursor( + cast<CXXRecordDecl>(Def)->getDescribedClassTemplate(), + CXXUnit); + return clang_getNullCursor(); + } + + case Decl::Using: { + UsingDecl *Using = cast<UsingDecl>(D); + CXCursor Def = clang_getNullCursor(); + for (UsingDecl::shadow_iterator S = Using->shadow_begin(), + SEnd = Using->shadow_end(); + S != SEnd; ++S) { + if (Def != clang_getNullCursor()) { + // FIXME: We have no way to return multiple results. + return clang_getNullCursor(); + } + + Def = clang_getCursorDefinition(MakeCXCursor((*S)->getTargetDecl(), + CXXUnit)); + } + + return Def; + } + + case Decl::UsingShadow: + return clang_getCursorDefinition( + MakeCXCursor(cast<UsingShadowDecl>(D)->getTargetDecl(), + CXXUnit)); + + case Decl::ObjCMethod: { + ObjCMethodDecl *Method = cast<ObjCMethodDecl>(D); + if (Method->isThisDeclarationADefinition()) + return C; + + // Dig out the method definition in the associated + // @implementation, if we have it. + // FIXME: The ASTs should make finding the definition easier. + if (ObjCInterfaceDecl *Class + = dyn_cast<ObjCInterfaceDecl>(Method->getDeclContext())) + if (ObjCImplementationDecl *ClassImpl = Class->getImplementation()) + if (ObjCMethodDecl *Def = ClassImpl->getMethod(Method->getSelector(), + Method->isInstanceMethod())) + if (Def->isThisDeclarationADefinition()) + return MakeCXCursor(Def, CXXUnit); + + return clang_getNullCursor(); + } + + case Decl::ObjCCategory: + if (ObjCCategoryImplDecl *Impl + = cast<ObjCCategoryDecl>(D)->getImplementation()) + return MakeCXCursor(Impl, CXXUnit); + return clang_getNullCursor(); + + case Decl::ObjCProtocol: + if (!cast<ObjCProtocolDecl>(D)->isForwardDecl()) + return C; + return clang_getNullCursor(); + + case Decl::ObjCInterface: + // There are two notions of a "definition" for an Objective-C + // class: the interface and its implementation. When we resolved a + // reference to an Objective-C class, produce the @interface as + // the definition; when we were provided with the interface, + // produce the @implementation as the definition. + if (WasReference) { + if (!cast<ObjCInterfaceDecl>(D)->isForwardDecl()) + return C; + } else if (ObjCImplementationDecl *Impl + = cast<ObjCInterfaceDecl>(D)->getImplementation()) + return MakeCXCursor(Impl, CXXUnit); + return clang_getNullCursor(); - return (void *) - getFileEntryFromSourceLocation(SourceMgr, getLocationFromCursor(C,SourceMgr, - ND)); + case Decl::ObjCProperty: + // FIXME: We don't really know where to find the + // ObjCPropertyImplDecls that implement this property. + return clang_getNullCursor(); + + case Decl::ObjCCompatibleAlias: + if (ObjCInterfaceDecl *Class + = cast<ObjCCompatibleAliasDecl>(D)->getClassInterface()) + if (!Class->isForwardDecl()) + return MakeCXCursor(Class, CXXUnit); + + return clang_getNullCursor(); + + case Decl::ObjCForwardProtocol: { + ObjCForwardProtocolDecl *Forward = cast<ObjCForwardProtocolDecl>(D); + if (Forward->protocol_size() == 1) + return clang_getCursorDefinition( + MakeCXCursor(*Forward->protocol_begin(), + CXXUnit)); + + // FIXME: Cannot return multiple definitions. + return clang_getNullCursor(); + } + + case Decl::ObjCClass: { + ObjCClassDecl *Class = cast<ObjCClassDecl>(D); + if (Class->size() == 1) { + ObjCInterfaceDecl *IFace = Class->begin()->getInterface(); + if (!IFace->isForwardDecl()) + return MakeCXCursor(IFace, CXXUnit); + return clang_getNullCursor(); + } + + // FIXME: Cannot return multiple definitions. + return clang_getNullCursor(); + } + + case Decl::Friend: + if (NamedDecl *Friend = cast<FriendDecl>(D)->getFriendDecl()) + return clang_getCursorDefinition(MakeCXCursor(Friend, CXXUnit)); + return clang_getNullCursor(); + + case Decl::FriendTemplate: + if (NamedDecl *Friend = cast<FriendTemplateDecl>(D)->getFriendDecl()) + return clang_getCursorDefinition(MakeCXCursor(Friend, CXXUnit)); + return clang_getNullCursor(); + } + + return clang_getNullCursor(); +} + +unsigned clang_isCursorDefinition(CXCursor C) { + if (!clang_isDeclaration(C.kind)) + return 0; + + return clang_getCursorDefinition(C) == C; } void clang_getDefinitionSpellingAndExtent(CXCursor C, @@ -1122,8 +1826,8 @@ void clang_getDefinitionSpellingAndExtent(CXCursor C, unsigned *startColumn, unsigned *endLine, unsigned *endColumn) { - assert(C.decl && "CXCursor has null decl"); - NamedDecl *ND = static_cast<NamedDecl *>(C.decl); + assert(getCursorDecl(C) && "CXCursor has null decl"); + NamedDecl *ND = static_cast<NamedDecl *>(getCursorDecl(C)); FunctionDecl *FD = dyn_cast<FunctionDecl>(ND); CompoundStmt *Body = dyn_cast<CompoundStmt>(FD->getBody()); @@ -1151,4 +1855,18 @@ void clang_disposeString(CXString string) { if (string.MustFreeString && string.Spelling) free((void*)string.Spelling); } + } // end: extern "C" + +//===----------------------------------------------------------------------===// +// Misc. utility functions. +//===----------------------------------------------------------------------===// + +extern "C" { + +const char *clang_getClangVersion() { + return getClangFullVersion(); +} + +} // end: extern "C" + diff --git a/tools/CIndex/CIndex.exports b/tools/CIndex/CIndex.exports index a695ba2..d349086 100644 --- a/tools/CIndex/CIndex.exports +++ b/tools/CIndex/CIndex.exports @@ -7,40 +7,41 @@ _clang_disposeIndex _clang_disposeString _clang_disposeTranslationUnit _clang_equalCursors +_clang_equalLocations +_clang_getClangVersion _clang_getCString _clang_getCompletionChunkCompletionString _clang_getCompletionChunkKind _clang_getCompletionChunkText _clang_getCursor -_clang_getCursorColumn -_clang_getCursorDecl -_clang_getCursorFromDecl +_clang_getCursorDefinition +_clang_getCursorExtent _clang_getCursorKind _clang_getCursorKindSpelling -_clang_getCursorLine -_clang_getCursorSource -_clang_getCursorSourceFile +_clang_getCursorLocation +_clang_getCursorReferenced _clang_getCursorSpelling -_clang_getDeclColumn -_clang_getDeclExtent -_clang_getDeclLine -_clang_getDeclExtent -_clang_getDeclSource -_clang_getDeclSourceFile -_clang_getDeclSpelling -_clang_getDeclUSR -_clang_getDeclaration +_clang_getCursorUSR _clang_getDefinitionSpellingAndExtent -_clang_getEntityFromDecl +_clang_getFile _clang_getFileName _clang_getFileTime +_clang_getInstantiationLocation +_clang_getLocation _clang_getNullCursor +_clang_getNullLocation _clang_getNumCompletionChunks +_clang_getRange +_clang_getRangeEnd +_clang_getRangeStart +_clang_getTranslationUnitCursor _clang_getTranslationUnitSpelling +_clang_isCursorDefinition _clang_isDeclaration -_clang_isDefinition +_clang_isExpression _clang_isInvalid _clang_isReference -_clang_loadDeclaration -_clang_loadTranslationUnit +_clang_isStatement +_clang_isTranslationUnit _clang_setUseExternalASTGeneration +_clang_visitChildren diff --git a/tools/CIndex/CIndexCodeCompletion.cpp b/tools/CIndex/CIndexCodeCompletion.cpp index f70479b..f3b60dc 100644 --- a/tools/CIndex/CIndexCodeCompletion.cpp +++ b/tools/CIndex/CIndexCodeCompletion.cpp @@ -221,35 +221,10 @@ CXCodeCompleteResults *clang_codeComplete(CXIndex CIdx, argv.push_back("-Xclang"); argv.push_back("-code-completion-macros"); + // Remap any unsaved files to temporary files. std::vector<std::string> RemapArgs; - for (unsigned i = 0; i != num_unsaved_files; ++i) { - char tmpFile[L_tmpnam]; - char *tmpFileName = tmpnam(tmpFile); - - // Write the contents of this unsaved file into the temporary file. - llvm::sys::Path SavedFile(tmpFileName); - std::string ErrorInfo; - llvm::raw_fd_ostream OS(SavedFile.c_str(), ErrorInfo); - if (!ErrorInfo.empty()) - continue; - - OS.write(unsaved_files[i].Contents, unsaved_files[i].Length); - OS.close(); - if (OS.has_error()) { - SavedFile.eraseFromDisk(); - continue; - } - - // Remap the file. - std::string RemapArg = unsaved_files[i].Filename; - RemapArg += ';'; - RemapArg += tmpFileName; - RemapArgs.push_back("-Xclang"); - RemapArgs.push_back("-remap-file"); - RemapArgs.push_back("-Xclang"); - RemapArgs.push_back(RemapArg); - TemporaryFiles.push_back(SavedFile); - } + if (RemapFiles(num_unsaved_files, unsaved_files, RemapArgs, TemporaryFiles)) + return 0; // The pointers into the elements of RemapArgs are stable because we // won't be adding anything to RemapArgs after this point. diff --git a/tools/CIndex/CIndexUSRs.cpp b/tools/CIndex/CIndexUSRs.cpp index 549c650..fd605fb 100644 --- a/tools/CIndex/CIndexUSRs.cpp +++ b/tools/CIndex/CIndexUSRs.cpp @@ -12,56 +12,11 @@ //===----------------------------------------------------------------------===// #include "CIndexer.h" +#include "CXCursor.h" #include "clang/AST/DeclVisitor.h" #include "llvm/ADT/SmallString.h" #include "llvm/Support/raw_ostream.h" -// Some notes on CXEntity: -// -// - Since the 'ordinary' namespace includes functions, data, typedefs, -// ObjC interfaces, thecurrent algorithm is a bit naive (resulting in one -// entity for 2 different types). For example: -// -// module1.m: @interface Foo @end Foo *x; -// module2.m: void Foo(int); -// -// - Since the unique name spans translation units, static data/functions -// within a CXTranslationUnit are *not* currently represented by entities. -// As a result, there will be no entity for the following: -// -// module.m: static void Foo() { } -// - -static inline Entity GetEntity(const CXEntity &E) { - return Entity::getFromOpaquePtr(E.data); -} - -static inline ASTUnit *GetTranslationUnit(CXTranslationUnit TU) { - return (ASTUnit*) TU; -} - -static inline ASTContext &GetASTContext(CXTranslationUnit TU) { - return GetTranslationUnit(TU)->getASTContext(); -} - -static inline CXEntity NullCXEntity() { - CXEntity CE; - CE.index = NULL; - CE.data = NULL; - return CE; -} - -static inline CXEntity MakeEntity(CXIndex CIdx, const Entity &E) { - CXEntity CE; - CE.index = CIdx; - CE.data = E.getAsOpaquePtr(); - return CE; -} - -static inline Program &GetProgram(CXIndex CIdx) { - return ((CIndexer*) CIdx)->getProgram(); -} - //===----------------------------------------------------------------------===// // USR generation. //===----------------------------------------------------------------------===// @@ -69,18 +24,22 @@ static inline Program &GetProgram(CXIndex CIdx) { namespace { class USRGenerator : public DeclVisitor<USRGenerator> { llvm::raw_ostream &Out; + bool IgnoreResults; public: - USRGenerator(llvm::raw_ostream &out) : Out(out) {} + USRGenerator(llvm::raw_ostream &out) : Out(out), IgnoreResults(false) {} + + bool ignoreResults() const { return IgnoreResults; } void VisitBlockDecl(BlockDecl *D); void VisitDeclContext(DeclContext *D); + void VisitFieldDecl(FieldDecl *D); void VisitFunctionDecl(FunctionDecl *D); void VisitNamedDecl(NamedDecl *D); void VisitNamespaceDecl(NamespaceDecl *D); void VisitObjCContainerDecl(ObjCContainerDecl *CD); void VisitObjCMethodDecl(ObjCMethodDecl *MD); void VisitObjCPropertyDecl(ObjCPropertyDecl *D); - void VisitRecordDecl(RecordDecl *D); + void VisitTagDecl(TagDecl *D); void VisitTypedefDecl(TypedefDecl *D); }; } // end anonymous namespace @@ -96,6 +55,17 @@ void USRGenerator::VisitDeclContext(DeclContext *DC) { Visit(D); } +void USRGenerator::VisitFieldDecl(FieldDecl *D) { + const std::string &s = D->getNameAsString(); + if (s.empty()) { + // Bit fields can be anonymous. + IgnoreResults = true; + return; + } + VisitDeclContext(D->getDeclContext()); + Out << "@^FI^" << s; +} + void USRGenerator::VisitFunctionDecl(FunctionDecl *D) { VisitDeclContext(D->getDeclContext()); Out << "@F^" << D->getNameAsString(); @@ -113,17 +83,6 @@ void USRGenerator::VisitNamespaceDecl(NamespaceDecl *D) { Out << "@N^" << D->getNameAsString(); } -void USRGenerator::VisitRecordDecl(RecordDecl *D) { - VisitDeclContext(D->getDeclContext()); - Out << "@S^"; - // FIXME: Better support for anonymous structures. - const std::string &s = D->getNameAsString(); - if (s.empty()) - Out << "^anon"; - else - Out << s; -} - void USRGenerator::VisitObjCMethodDecl(ObjCMethodDecl *D) { Visit(cast<Decl>(D->getDeclContext())); Out << (D->isInstanceMethod() ? "(im)" : "(cm)"); @@ -141,13 +100,13 @@ void USRGenerator::VisitObjCContainerDecl(ObjCContainerDecl *D) { case Decl::ObjCCategory: { ObjCCategoryDecl *CD = cast<ObjCCategoryDecl>(D); Out << "objc(cy)" << CD->getClassInterface()->getName() - << '_' << CD->getName(); + << '^' << CD->getName(); break; } case Decl::ObjCCategoryImpl: { ObjCCategoryImplDecl *CD = cast<ObjCCategoryImplDecl>(D); Out << "objc(cy)" << CD->getClassInterface()->getName() - << '_' << CD->getName(); + << '^' << CD->getName(); break; } case Decl::ObjCProtocol: @@ -161,6 +120,27 @@ void USRGenerator::VisitObjCPropertyDecl(ObjCPropertyDecl *D) { Out << "(py)" << D->getName(); } +void USRGenerator::VisitTagDecl(TagDecl *D) { + VisitDeclContext(D->getDeclContext()); + switch (D->getTagKind()) { + case TagDecl::TK_struct: Out << "@S^"; break; + case TagDecl::TK_class: Out << "@C^"; break; + case TagDecl::TK_union: Out << "@U^"; break; + case TagDecl::TK_enum: Out << "@E^"; break; + } + + // FIXME: Better support for anonymous structures and enums. + const std::string &s = D->getNameAsString(); + if (s.empty()) { + if (TypedefDecl *TD = D->getTypedefForAnonDecl()) + Out << "^anontd^" << TD->getNameAsString(); + else + Out << "^anon"; + } + else + Out << s; +} + void USRGenerator::VisitTypedefDecl(TypedefDecl *D) { DeclContext *DC = D->getDeclContext(); if (NamedDecl *DCN = dyn_cast<NamedDecl>(DC)) @@ -168,36 +148,32 @@ void USRGenerator::VisitTypedefDecl(TypedefDecl *D) { Out << "typedef@" << D->getName(); } -extern "C" { - -/// clang_getDeclaration() maps from a CXEntity to the matching CXDecl (if any) -/// in a specified translation unit. -CXDecl clang_getDeclaration(CXEntity CE, CXTranslationUnit TU) { - return (CXDecl) GetEntity(CE).getDecl(GetASTContext(TU)); -} - - -CXEntity clang_getEntityFromDecl(CXIndex CIdx, CXDecl CE) { - if (Decl *D = (Decl *) CE) - return MakeEntity(CIdx, Entity::get(D, GetProgram(CIdx))); - return NullCXEntity(); -} - // FIXME: This is a skeleton implementation. It will be overhauled. -CXString clang_getDeclUSR(CXDecl D) { - assert(D && "Null CXDecl passed to clang_getDeclUSR()"); +static CXString ConstructUSR(Decl *D) { llvm::SmallString<1024> StrBuf; { llvm::raw_svector_ostream Out(StrBuf); USRGenerator UG(Out); UG.Visit(static_cast<Decl*>(D)); + if (UG.ignoreResults()) + return CIndexer::createCXString(NULL); } if (StrBuf.empty()) return CIndexer::createCXString(NULL); - + // Return a copy of the string that must be disposed by the caller. return CIndexer::createCXString(StrBuf.c_str(), true); } + +extern "C" { + +CXString clang_getCursorUSR(CXCursor C) { + if (Decl *D = cxcursor::getCursorDecl(C)) + return ConstructUSR(D); + + return CIndexer::createCXString(NULL); +} + } // end extern "C" diff --git a/tools/CIndex/CIndexer.cpp b/tools/CIndex/CIndexer.cpp index f26c8ce..53636a4 100644 --- a/tools/CIndex/CIndexer.cpp +++ b/tools/CIndex/CIndexer.cpp @@ -94,3 +94,40 @@ std::string CIndexer::getClangResourcesPath() { return P.str(); } + +bool clang::RemapFiles(unsigned num_unsaved_files, + struct CXUnsavedFile *unsaved_files, + std::vector<std::string> &RemapArgs, + std::vector<llvm::sys::Path> &TemporaryFiles) { + for (unsigned i = 0; i != num_unsaved_files; ++i) { + char tmpFile[L_tmpnam]; + char *tmpFileName = tmpnam(tmpFile); + + // Write the contents of this unsaved file into the temporary file. + llvm::sys::Path SavedFile(tmpFileName); + std::string ErrorInfo; + llvm::raw_fd_ostream OS(SavedFile.c_str(), ErrorInfo); + if (!ErrorInfo.empty()) + return true; + + OS.write(unsaved_files[i].Contents, unsaved_files[i].Length); + OS.close(); + if (OS.has_error()) { + SavedFile.eraseFromDisk(); + return true; + } + + // Remap the file. + std::string RemapArg = unsaved_files[i].Filename; + RemapArg += ';'; + RemapArg += tmpFileName; + RemapArgs.push_back("-Xclang"); + RemapArgs.push_back("-remap-file"); + RemapArgs.push_back("-Xclang"); + RemapArgs.push_back(RemapArg); + TemporaryFiles.push_back(SavedFile); + } + + return false; +} + diff --git a/tools/CIndex/CIndexer.h b/tools/CIndex/CIndexer.h index 4f3cd8b..d01454f 100644 --- a/tools/CIndex/CIndexer.h +++ b/tools/CIndex/CIndexer.h @@ -16,13 +16,10 @@ #define LLVM_CLANG_CINDEXER_H #include "clang-c/Index.h" -#include "clang/Index/ASTLocation.h" -#include "clang/Index/Indexer.h" -#include "clang/Index/Program.h" -#include "clang/Index/Utils.h" #include "clang/Frontend/CompilerInstance.h" #include "clang/Frontend/ASTUnit.h" #include "llvm/System/Path.h" +#include <vector> using namespace clang; @@ -34,7 +31,7 @@ public: virtual void HandleDiagnostic(Diagnostic::Level, const DiagnosticInfo &) {} }; -class CIndexer : public Indexer { +class CIndexer { DiagnosticOptions DiagOpts; IgnoreDiagnosticsClient IgnoreDiagClient; llvm::OwningPtr<Diagnostic> TextDiags; @@ -46,16 +43,12 @@ class CIndexer : public Indexer { llvm::sys::Path ClangPath; public: - explicit CIndexer(Program *prog) : Indexer(*prog), - IgnoreDiags(&IgnoreDiagClient), - UseExternalASTGeneration(false), - OnlyLocalDecls(false), - DisplayDiagnostics(false) { + CIndexer() : IgnoreDiags(&IgnoreDiagClient), UseExternalASTGeneration(false), + OnlyLocalDecls(false), DisplayDiagnostics(false) + { TextDiags.reset(CompilerInstance::createDiagnostics(DiagOpts, 0, 0)); } - virtual ~CIndexer() { delete &getProgram(); } - /// \brief Whether we only want to see "local" declarations (that did not /// come from a previous precompiled header). If false, we want to see all /// declarations. @@ -85,4 +78,17 @@ public: static CXString createCXString(const char *String, bool DupString = false); }; +namespace clang { + /** + * \brief Given a set of "unsaved" files, create temporary files and + * construct the clang -cc1 argument list needed to perform the remapping. + * + * \returns true if an error occurred. + */ + bool RemapFiles(unsigned num_unsaved_files, + struct CXUnsavedFile *unsaved_files, + std::vector<std::string> &RemapArgs, + std::vector<llvm::sys::Path> &TemporaryFiles); +} + #endif diff --git a/tools/CIndex/CMakeLists.txt b/tools/CIndex/CMakeLists.txt index 52f847e..730eaaf 100644 --- a/tools/CIndex/CMakeLists.txt +++ b/tools/CIndex/CMakeLists.txt @@ -3,8 +3,7 @@ set(SHARED_LIBRARY TRUE) set(LLVM_NO_RTTI 1) set(LLVM_USED_LIBS - clangIndex - clangFrontend + clangFrontend clangDriver clangSema clangAnalysis @@ -24,6 +23,7 @@ add_clang_library(CIndex CIndexCodeCompletion.cpp CIndexUSRs.cpp CIndexer.cpp + CXCursor.cpp ) if(${CMAKE_SYSTEM_NAME} MATCHES "Darwin") diff --git a/tools/CIndex/CXCursor.cpp b/tools/CIndex/CXCursor.cpp new file mode 100644 index 0000000..63d9bc9 --- /dev/null +++ b/tools/CIndex/CXCursor.cpp @@ -0,0 +1,305 @@ +//===- CXCursor.cpp - Routines for manipulating CXCursors -----------------===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// +// This file defines routines for manipulating CXCursors. It should be the +// only file that has internal knowledge of the encoding of the data in +// CXCursor. +// +//===----------------------------------------------------------------------===// + +#include "CXCursor.h" +#include "clang/Frontend/ASTUnit.h" +#include "clang/AST/Decl.h" +#include "clang/AST/DeclObjC.h" +#include "clang/AST/Expr.h" +#include "llvm/Support/ErrorHandling.h" + +using namespace clang; + +CXCursor cxcursor::MakeCXCursorInvalid(CXCursorKind K) { + assert(K >= CXCursor_FirstInvalid && K <= CXCursor_LastInvalid); + CXCursor C = { K, { 0, 0, 0 } }; + return C; +} + +static CXCursorKind GetCursorKind(Decl *D) { + switch (D->getKind()) { + case Decl::Enum: return CXCursor_EnumDecl; + case Decl::EnumConstant: return CXCursor_EnumConstantDecl; + case Decl::Field: return CXCursor_FieldDecl; + case Decl::Function: + return CXCursor_FunctionDecl; + case Decl::ObjCCategory: return CXCursor_ObjCCategoryDecl; + case Decl::ObjCCategoryImpl: return CXCursor_ObjCCategoryImplDecl; + case Decl::ObjCClass: + // FIXME + return CXCursor_UnexposedDecl; + case Decl::ObjCForwardProtocol: + // FIXME + return CXCursor_UnexposedDecl; + case Decl::ObjCImplementation: return CXCursor_ObjCImplementationDecl; + case Decl::ObjCInterface: return CXCursor_ObjCInterfaceDecl; + case Decl::ObjCIvar: return CXCursor_ObjCIvarDecl; + case Decl::ObjCMethod: + return cast<ObjCMethodDecl>(D)->isInstanceMethod() + ? CXCursor_ObjCInstanceMethodDecl : CXCursor_ObjCClassMethodDecl; + case Decl::ObjCProperty: return CXCursor_ObjCPropertyDecl; + case Decl::ObjCProtocol: return CXCursor_ObjCProtocolDecl; + case Decl::ParmVar: return CXCursor_ParmDecl; + case Decl::Typedef: return CXCursor_TypedefDecl; + case Decl::Var: return CXCursor_VarDecl; + default: + if (TagDecl *TD = dyn_cast<TagDecl>(D)) { + switch (TD->getTagKind()) { + case TagDecl::TK_struct: return CXCursor_StructDecl; + case TagDecl::TK_class: return CXCursor_ClassDecl; + case TagDecl::TK_union: return CXCursor_UnionDecl; + case TagDecl::TK_enum: return CXCursor_EnumDecl; + } + } + + return CXCursor_UnexposedDecl; + } + + llvm_unreachable("Invalid Decl"); + return CXCursor_NotImplemented; +} + +CXCursor cxcursor::MakeCXCursor(Decl *D, ASTUnit *TU) { + CXCursor C = { GetCursorKind(D), { D, 0, TU } }; + return C; +} + +CXCursor cxcursor::MakeCXCursor(Stmt *S, Decl *Parent, ASTUnit *TU) { + CXCursorKind K = CXCursor_NotImplemented; + + switch (S->getStmtClass()) { + case Stmt::NoStmtClass: + break; + + case Stmt::NullStmtClass: + case Stmt::CompoundStmtClass: + case Stmt::CaseStmtClass: + case Stmt::DefaultStmtClass: + case Stmt::LabelStmtClass: + case Stmt::IfStmtClass: + case Stmt::SwitchStmtClass: + case Stmt::WhileStmtClass: + case Stmt::DoStmtClass: + case Stmt::ForStmtClass: + case Stmt::GotoStmtClass: + case Stmt::IndirectGotoStmtClass: + case Stmt::ContinueStmtClass: + case Stmt::BreakStmtClass: + case Stmt::ReturnStmtClass: + case Stmt::DeclStmtClass: + case Stmt::SwitchCaseClass: + case Stmt::AsmStmtClass: + case Stmt::ObjCAtTryStmtClass: + case Stmt::ObjCAtCatchStmtClass: + case Stmt::ObjCAtFinallyStmtClass: + case Stmt::ObjCAtThrowStmtClass: + case Stmt::ObjCAtSynchronizedStmtClass: + case Stmt::ObjCForCollectionStmtClass: + case Stmt::CXXCatchStmtClass: + case Stmt::CXXTryStmtClass: + K = CXCursor_UnexposedStmt; + break; + + case Stmt::ExprClass: + case Stmt::PredefinedExprClass: + case Stmt::IntegerLiteralClass: + case Stmt::FloatingLiteralClass: + case Stmt::ImaginaryLiteralClass: + case Stmt::StringLiteralClass: + case Stmt::CharacterLiteralClass: + case Stmt::ParenExprClass: + case Stmt::UnaryOperatorClass: + case Stmt::SizeOfAlignOfExprClass: + case Stmt::ArraySubscriptExprClass: + case Stmt::CastExprClass: + case Stmt::BinaryOperatorClass: + case Stmt::CompoundAssignOperatorClass: + case Stmt::ConditionalOperatorClass: + case Stmt::ImplicitCastExprClass: + case Stmt::ExplicitCastExprClass: + case Stmt::CStyleCastExprClass: + case Stmt::CompoundLiteralExprClass: + case Stmt::ExtVectorElementExprClass: + case Stmt::InitListExprClass: + case Stmt::DesignatedInitExprClass: + case Stmt::ImplicitValueInitExprClass: + case Stmt::ParenListExprClass: + case Stmt::VAArgExprClass: + case Stmt::AddrLabelExprClass: + case Stmt::StmtExprClass: + case Stmt::TypesCompatibleExprClass: + case Stmt::ChooseExprClass: + case Stmt::GNUNullExprClass: + case Stmt::CXXNamedCastExprClass: + case Stmt::CXXStaticCastExprClass: + case Stmt::CXXDynamicCastExprClass: + case Stmt::CXXReinterpretCastExprClass: + case Stmt::CXXConstCastExprClass: + case Stmt::CXXFunctionalCastExprClass: + case Stmt::CXXTypeidExprClass: + case Stmt::CXXBoolLiteralExprClass: + case Stmt::CXXNullPtrLiteralExprClass: + case Stmt::CXXThisExprClass: + case Stmt::CXXThrowExprClass: + case Stmt::CXXDefaultArgExprClass: + case Stmt::CXXZeroInitValueExprClass: + case Stmt::CXXNewExprClass: + case Stmt::CXXDeleteExprClass: + case Stmt::CXXPseudoDestructorExprClass: + case Stmt::UnresolvedLookupExprClass: + case Stmt::UnaryTypeTraitExprClass: + case Stmt::DependentScopeDeclRefExprClass: + case Stmt::CXXBindTemporaryExprClass: + case Stmt::CXXExprWithTemporariesClass: + case Stmt::CXXUnresolvedConstructExprClass: + case Stmt::CXXDependentScopeMemberExprClass: + case Stmt::UnresolvedMemberExprClass: + case Stmt::ObjCStringLiteralClass: + case Stmt::ObjCEncodeExprClass: + case Stmt::ObjCSelectorExprClass: + case Stmt::ObjCProtocolExprClass: + case Stmt::ObjCImplicitSetterGetterRefExprClass: + case Stmt::ObjCSuperExprClass: + case Stmt::ObjCIsaExprClass: + case Stmt::ShuffleVectorExprClass: + case Stmt::BlockExprClass: + K = CXCursor_UnexposedExpr; + break; + case Stmt::DeclRefExprClass: + case Stmt::BlockDeclRefExprClass: + // FIXME: UnresolvedLookupExpr? + // FIXME: DependentScopeDeclRefExpr? + K = CXCursor_DeclRefExpr; + break; + + case Stmt::MemberExprClass: + case Stmt::ObjCIvarRefExprClass: + case Stmt::ObjCPropertyRefExprClass: + // FIXME: UnresolvedMemberExpr? + // FIXME: CXXDependentScopeMemberExpr? + K = CXCursor_MemberRefExpr; + break; + + case Stmt::CallExprClass: + case Stmt::CXXOperatorCallExprClass: + case Stmt::CXXMemberCallExprClass: + case Stmt::CXXConstructExprClass: + case Stmt::CXXTemporaryObjectExprClass: + // FIXME: CXXUnresolvedConstructExpr + // FIXME: ObjCImplicitSetterGetterRefExpr? + K = CXCursor_CallExpr; + break; + + case Stmt::ObjCMessageExprClass: + K = CXCursor_ObjCMessageExpr; + break; + } + + CXCursor C = { K, { Parent, S, TU } }; + return C; +} + +CXCursor cxcursor::MakeCursorObjCSuperClassRef(ObjCInterfaceDecl *Super, + SourceLocation Loc, + ASTUnit *TU) { + void *RawLoc = reinterpret_cast<void *>(Loc.getRawEncoding()); + CXCursor C = { CXCursor_ObjCSuperClassRef, { Super, RawLoc, TU } }; + return C; +} + +std::pair<ObjCInterfaceDecl *, SourceLocation> +cxcursor::getCursorObjCSuperClassRef(CXCursor C) { + assert(C.kind == CXCursor_ObjCSuperClassRef); + return std::make_pair(static_cast<ObjCInterfaceDecl *>(C.data[0]), + SourceLocation::getFromRawEncoding( + reinterpret_cast<uintptr_t>(C.data[1]))); +} + +CXCursor cxcursor::MakeCursorObjCProtocolRef(ObjCProtocolDecl *Super, + SourceLocation Loc, + ASTUnit *TU) { + void *RawLoc = reinterpret_cast<void *>(Loc.getRawEncoding()); + CXCursor C = { CXCursor_ObjCProtocolRef, { Super, RawLoc, TU } }; + return C; +} + +std::pair<ObjCProtocolDecl *, SourceLocation> +cxcursor::getCursorObjCProtocolRef(CXCursor C) { + assert(C.kind == CXCursor_ObjCProtocolRef); + return std::make_pair(static_cast<ObjCProtocolDecl *>(C.data[0]), + SourceLocation::getFromRawEncoding( + reinterpret_cast<uintptr_t>(C.data[1]))); +} + +CXCursor cxcursor::MakeCursorObjCClassRef(ObjCInterfaceDecl *Class, + SourceLocation Loc, + ASTUnit *TU) { + void *RawLoc = reinterpret_cast<void *>(Loc.getRawEncoding()); + CXCursor C = { CXCursor_ObjCClassRef, { Class, RawLoc, TU } }; + return C; +} + +std::pair<ObjCInterfaceDecl *, SourceLocation> +cxcursor::getCursorObjCClassRef(CXCursor C) { + assert(C.kind == CXCursor_ObjCClassRef); + return std::make_pair(static_cast<ObjCInterfaceDecl *>(C.data[0]), + SourceLocation::getFromRawEncoding( + reinterpret_cast<uintptr_t>(C.data[1]))); +} + +CXCursor cxcursor::MakeCursorTypeRef(TypeDecl *Type, SourceLocation Loc, + ASTUnit *TU) { + void *RawLoc = reinterpret_cast<void *>(Loc.getRawEncoding()); + CXCursor C = { CXCursor_TypeRef, { Type, RawLoc, TU } }; + return C; +} + +std::pair<TypeDecl *, SourceLocation> +cxcursor::getCursorTypeRef(CXCursor C) { + assert(C.kind == CXCursor_TypeRef); + return std::make_pair(static_cast<TypeDecl *>(C.data[0]), + SourceLocation::getFromRawEncoding( + reinterpret_cast<uintptr_t>(C.data[1]))); +} + +Decl *cxcursor::getCursorDecl(CXCursor Cursor) { + return (Decl *)Cursor.data[0]; +} + +Expr *cxcursor::getCursorExpr(CXCursor Cursor) { + return dyn_cast_or_null<Expr>(getCursorStmt(Cursor)); +} + +Stmt *cxcursor::getCursorStmt(CXCursor Cursor) { + if (Cursor.kind == CXCursor_ObjCSuperClassRef || + Cursor.kind == CXCursor_ObjCProtocolRef || + Cursor.kind == CXCursor_ObjCClassRef) + return 0; + + return (Stmt *)Cursor.data[1]; +} + +ASTContext &cxcursor::getCursorContext(CXCursor Cursor) { + return getCursorASTUnit(Cursor)->getASTContext(); +} + +ASTUnit *cxcursor::getCursorASTUnit(CXCursor Cursor) { + return static_cast<ASTUnit *>(Cursor.data[2]); +} + +bool cxcursor::operator==(CXCursor X, CXCursor Y) { + return X.kind == Y.kind && X.data[0] == Y.data[0] && X.data[1] == Y.data[1] && + X.data[2] == Y.data[2]; +} diff --git a/tools/CIndex/CXCursor.h b/tools/CIndex/CXCursor.h new file mode 100644 index 0000000..546dd7f --- /dev/null +++ b/tools/CIndex/CXCursor.h @@ -0,0 +1,88 @@ +//===- CXCursor.h - Routines for manipulating CXCursors -------------------===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// +// This file defines routines for manipulating CXCursors. +// +//===----------------------------------------------------------------------===// + +#ifndef LLVM_CLANG_CXCURSOR_H +#define LLVM_CLANG_CXCursor_H + +#include "clang-c/Index.h" +#include "clang/Basic/SourceLocation.h" +#include <utility> + +namespace clang { + +class ASTContext; +class ASTUnit; +class Decl; +class Expr; +class NamedDecl; +class ObjCInterfaceDecl; +class ObjCProtocolDecl; +class Stmt; +class TypeDecl; + +namespace cxcursor { + +CXCursor MakeCXCursorInvalid(CXCursorKind K); +CXCursor MakeCXCursor(clang::Stmt *S, clang::Decl *Parent, ASTUnit *TU); +CXCursor MakeCXCursor(clang::Decl *D, ASTUnit *TU); + +/// \brief Create an Objective-C superclass reference at the given location. +CXCursor MakeCursorObjCSuperClassRef(ObjCInterfaceDecl *Super, + SourceLocation Loc, + ASTUnit *TU); + +/// \brief Unpack an ObjCSuperClassRef cursor into the interface it references +/// and optionally the location where the reference occurred. +std::pair<ObjCInterfaceDecl *, SourceLocation> + getCursorObjCSuperClassRef(CXCursor C); + +/// \brief Create an Objective-C protocol reference at the given location. +CXCursor MakeCursorObjCProtocolRef(ObjCProtocolDecl *Proto, SourceLocation Loc, + ASTUnit *TU); + +/// \brief Unpack an ObjCProtocolRef cursor into the protocol it references +/// and optionally the location where the reference occurred. +std::pair<ObjCProtocolDecl *, SourceLocation> + getCursorObjCProtocolRef(CXCursor C); + +/// \brief Create an Objective-C class reference at the given location. +CXCursor MakeCursorObjCClassRef(ObjCInterfaceDecl *Class, SourceLocation Loc, + ASTUnit *TU); + +/// \brief Unpack an ObjCClassRef cursor into the class it references +/// and optionally the location where the reference occurred. +std::pair<ObjCInterfaceDecl *, SourceLocation> + getCursorObjCClassRef(CXCursor C); + +/// \brief Create a type reference at the given location. +CXCursor MakeCursorTypeRef(TypeDecl *Type, SourceLocation Loc, ASTUnit *TU); + +/// \brief Unpack a TypeRef cursor into the class it references +/// and optionally the location where the reference occurred. +std::pair<TypeDecl *, SourceLocation> getCursorTypeRef(CXCursor C); + +Decl *getCursorDecl(CXCursor Cursor); +Expr *getCursorExpr(CXCursor Cursor); +Stmt *getCursorStmt(CXCursor Cursor); +ASTContext &getCursorContext(CXCursor Cursor); +ASTUnit *getCursorASTUnit(CXCursor Cursor); + +bool operator==(CXCursor X, CXCursor Y); + +inline bool operator!=(CXCursor X, CXCursor Y) { + return !(X == Y); +} + +}} // end namespace: clang::cxcursor + +#endif diff --git a/tools/CIndex/Makefile b/tools/CIndex/Makefile index 94f0467..7bdbba1 100644 --- a/tools/CIndex/Makefile +++ b/tools/CIndex/Makefile @@ -22,7 +22,7 @@ LINK_LIBS_IN_SHARED = 1 SHARED_LIBRARY = 1 LINK_COMPONENTS := bitreader mc core -USEDLIBS = clangIndex.a clangFrontend.a clangDriver.a clangSema.a \ +USEDLIBS = clangFrontend.a clangDriver.a clangSema.a \ clangAnalysis.a clangAST.a clangParse.a clangLex.a clangBasic.a include $(LEVEL)/Makefile.common diff --git a/tools/CMakeLists.txt b/tools/CMakeLists.txt index 46e4ae9..64c3a21 100644 --- a/tools/CMakeLists.txt +++ b/tools/CMakeLists.txt @@ -1,4 +1,3 @@ add_subdirectory(CIndex) add_subdirectory(c-index-test) add_subdirectory(driver) -add_subdirectory(index-test) diff --git a/tools/Makefile b/tools/Makefile index a30932b..ce3e4cd 100644 --- a/tools/Makefile +++ b/tools/Makefile @@ -8,6 +8,6 @@ ##===----------------------------------------------------------------------===## LEVEL := ../../.. -DIRS := driver index-test CIndex c-index-test +DIRS := driver CIndex c-index-test include $(LEVEL)/Makefile.common diff --git a/tools/c-index-test/c-index-test.c b/tools/c-index-test/c-index-test.c index 01a0d43..4ef3904 100644 --- a/tools/c-index-test/c-index-test.c +++ b/tools/c-index-test/c-index-test.c @@ -4,6 +4,7 @@ #include <stdlib.h> #include <stdio.h> #include <string.h> +#include <assert.h> /******************************************************************************/ /* Utility functions. */ @@ -38,6 +39,99 @@ static unsigned CreateTranslationUnit(CXIndex Idx, const char *file, return 1; } +void free_remapped_files(struct CXUnsavedFile *unsaved_files, + int num_unsaved_files) { + int i; + for (i = 0; i != num_unsaved_files; ++i) { + free((char *)unsaved_files[i].Filename); + free((char *)unsaved_files[i].Contents); + } +} + +int parse_remapped_files(int argc, const char **argv, int start_arg, + struct CXUnsavedFile **unsaved_files, + int *num_unsaved_files) { + int i; + int arg; + int prefix_len = strlen("-remap-file="); + *unsaved_files = 0; + *num_unsaved_files = 0; + + /* Count the number of remapped files. */ + for (arg = start_arg; arg < argc; ++arg) { + if (strncmp(argv[arg], "-remap-file=", prefix_len)) + break; + + ++*num_unsaved_files; + } + + if (*num_unsaved_files == 0) + return 0; + + *unsaved_files + = (struct CXUnsavedFile *)malloc(sizeof(struct CXUnsavedFile) * + *num_unsaved_files); + for (arg = start_arg, i = 0; i != *num_unsaved_files; ++i, ++arg) { + struct CXUnsavedFile *unsaved = *unsaved_files + i; + const char *arg_string = argv[arg] + prefix_len; + int filename_len; + char *filename; + char *contents; + FILE *to_file; + const char *semi = strchr(arg_string, ';'); + if (!semi) { + fprintf(stderr, + "error: -remap-file=from;to argument is missing semicolon\n"); + free_remapped_files(*unsaved_files, i); + *unsaved_files = 0; + *num_unsaved_files = 0; + return -1; + } + + /* Open the file that we're remapping to. */ + to_file = fopen(semi + 1, "r"); + if (!to_file) { + fprintf(stderr, "error: cannot open file %s that we are remapping to\n", + semi + 1); + free_remapped_files(*unsaved_files, i); + *unsaved_files = 0; + *num_unsaved_files = 0; + return -1; + } + + /* Determine the length of the file we're remapping to. */ + fseek(to_file, 0, SEEK_END); + unsaved->Length = ftell(to_file); + fseek(to_file, 0, SEEK_SET); + + /* Read the contents of the file we're remapping to. */ + contents = (char *)malloc(unsaved->Length + 1); + if (fread(contents, 1, unsaved->Length, to_file) != unsaved->Length) { + fprintf(stderr, "error: unexpected %s reading 'to' file %s\n", + (feof(to_file) ? "EOF" : "error"), semi + 1); + fclose(to_file); + free_remapped_files(*unsaved_files, i); + *unsaved_files = 0; + *num_unsaved_files = 0; + return -1; + } + contents[unsaved->Length] = 0; + unsaved->Contents = contents; + + /* Close the file. */ + fclose(to_file); + + /* Copy the file name that we're remapping from. */ + filename_len = semi - arg_string; + filename = (char *)malloc(filename_len + 1); + memcpy(filename, arg_string, filename_len); + filename[filename_len] = 0; + unsaved->Filename = filename; + } + + return 0; +} + /******************************************************************************/ /* Pretty-printing. */ /******************************************************************************/ @@ -46,86 +140,96 @@ static void PrintCursor(CXCursor Cursor) { if (clang_isInvalid(Cursor.kind)) printf("Invalid Cursor => %s", clang_getCursorKindSpelling(Cursor.kind)); else { - CXDecl DeclReferenced; CXString string; + CXCursor Referenced; + unsigned line, column; string = clang_getCursorSpelling(Cursor); printf("%s=%s", clang_getCursorKindSpelling(Cursor.kind), clang_getCString(string)); clang_disposeString(string); - DeclReferenced = clang_getCursorDecl(Cursor); - if (DeclReferenced) - printf(":%d:%d", clang_getDeclLine(DeclReferenced), - clang_getDeclColumn(DeclReferenced)); + + Referenced = clang_getCursorReferenced(Cursor); + if (!clang_equalCursors(Referenced, clang_getNullCursor())) { + CXSourceLocation Loc = clang_getCursorLocation(Referenced); + clang_getInstantiationLocation(Loc, 0, &line, &column); + printf(":%d:%d", line, column); + } + + if (clang_isCursorDefinition(Cursor)) + printf(" (Definition)"); } } static const char* GetCursorSource(CXCursor Cursor) { - const char *source = clang_getCursorSource(Cursor); + CXSourceLocation Loc = clang_getCursorLocation(Cursor); + const char *source; + CXFile file; + clang_getInstantiationLocation(Loc, &file, 0, 0); + source = clang_getFileName(file); if (!source) return "<invalid loc>"; return basename(source); } /******************************************************************************/ -/* Logic for testing clang_loadTranslationUnit(). */ +/* Logic for testing traversal. */ /******************************************************************************/ static const char *FileCheckPrefix = "CHECK"; -static void PrintDeclExtent(CXDecl Dcl) { - CXSourceExtent extent = clang_getDeclExtent(Dcl); - printf(" [Extent=%d:%d:%d:%d]", extent.begin.line, extent.begin.column, - extent.end.line, extent.end.column); -} - -static void DeclVisitor(CXDecl Dcl, CXCursor Cursor, CXClientData Filter) { - if (!Filter || (Cursor.kind == *(enum CXCursorKind *)Filter)) { - CXString string; - printf("// %s: %s:%d:%d: ", FileCheckPrefix, - GetCursorSource(Cursor), - clang_getCursorLine(Cursor), - clang_getCursorColumn(Cursor)); - PrintCursor(Cursor); - - string = clang_getDeclSpelling(Dcl); - printf(" [Context=%s]", clang_getCString(string)); - clang_disposeString(string); - - PrintDeclExtent(clang_getCursorDecl(Cursor)); +static void PrintCursorExtent(CXCursor C) { + CXSourceRange extent = clang_getCursorExtent(C); + CXFile begin_file, end_file; + unsigned begin_line, begin_column, end_line, end_column; + + clang_getInstantiationLocation(clang_getRangeStart(extent), + &begin_file, &begin_line, &begin_column); + clang_getInstantiationLocation(clang_getRangeEnd(extent), + &end_file, &end_line, &end_column); + if (!begin_file || !end_file) + return; - printf("\n"); - } + printf(" [Extent=%d:%d:%d:%d]", begin_line, begin_column, + end_line, end_column); } -static void TranslationUnitVisitor(CXTranslationUnit Unit, CXCursor Cursor, - CXClientData Filter) { - if (!Filter || (Cursor.kind == *(enum CXCursorKind *)Filter)) { - CXString string; +/* Data used by all of the visitors. */ +typedef struct { + CXTranslationUnit TU; + enum CXCursorKind *Filter; +} VisitorData; + + +enum CXChildVisitResult FilteredPrintingVisitor(CXCursor Cursor, + CXCursor Parent, + CXClientData ClientData) { + VisitorData *Data = (VisitorData *)ClientData; + if (!Data->Filter || (Cursor.kind == *(enum CXCursorKind *)Data->Filter)) { + CXSourceLocation Loc = clang_getCursorLocation(Cursor); + unsigned line, column; + clang_getInstantiationLocation(Loc, 0, &line, &column); printf("// %s: %s:%d:%d: ", FileCheckPrefix, - GetCursorSource(Cursor), clang_getCursorLine(Cursor), - clang_getCursorColumn(Cursor)); + GetCursorSource(Cursor), line, column); PrintCursor(Cursor); - string = clang_getTranslationUnitSpelling(Unit); - printf(" [Context=%s]", - basename(clang_getCString(string))); - clang_disposeString(string); - - PrintDeclExtent(Cursor.decl); - - printf("\n"); - - clang_loadDeclaration(Cursor.decl, DeclVisitor, 0); + PrintCursorExtent(Cursor); + printf("\n"); + return CXChildVisit_Recurse; } + + return CXChildVisit_Continue; } -static void FunctionScanVisitor(CXTranslationUnit Unit, CXCursor Cursor, - CXClientData Filter) { +static enum CXChildVisitResult FunctionScanVisitor(CXCursor Cursor, + CXCursor Parent, + CXClientData ClientData) { const char *startBuf, *endBuf; unsigned startLine, startColumn, endLine, endColumn, curLine, curColumn; CXCursor Ref; + VisitorData *Data = (VisitorData *)ClientData; - if (Cursor.kind != CXCursor_FunctionDefn) - return; + if (Cursor.kind != CXCursor_FunctionDecl || + !clang_isCursorDefinition(Cursor)) + return CXChildVisit_Continue; clang_getDefinitionSpellingAndExtent(Cursor, &startBuf, &endBuf, &startLine, &startColumn, @@ -135,6 +239,10 @@ static void FunctionScanVisitor(CXTranslationUnit Unit, CXCursor Cursor, curColumn = startColumn; while (startBuf < endBuf) { + CXSourceLocation Loc; + CXFile file; + const char *source = 0; + if (*startBuf == '\n') { startBuf++; curLine++; @@ -142,47 +250,50 @@ static void FunctionScanVisitor(CXTranslationUnit Unit, CXCursor Cursor, } else if (*startBuf != '\t') curColumn++; - Ref = clang_getCursor(Unit, clang_getCursorSource(Cursor), - curLine, curColumn); - if (Ref.kind == CXCursor_NoDeclFound) { - /* Nothing found here; that's fine. */ - } else if (Ref.kind != CXCursor_FunctionDecl) { - CXString string; - printf("// %s: %s:%d:%d: ", FileCheckPrefix, GetCursorSource(Ref), - curLine, curColumn); - PrintCursor(Ref); - string = clang_getDeclSpelling(Ref.decl); - printf(" [Context:%s]\n", clang_getCString(string)); - clang_disposeString(string); + Loc = clang_getCursorLocation(Cursor); + clang_getInstantiationLocation(Loc, &file, 0, 0); + source = clang_getFileName(file); + if (source) { + CXSourceLocation RefLoc + = clang_getLocation(Data->TU, file, curLine, curColumn); + Ref = clang_getCursor(Data->TU, RefLoc); + if (Ref.kind == CXCursor_NoDeclFound) { + /* Nothing found here; that's fine. */ + } else if (Ref.kind != CXCursor_FunctionDecl) { + printf("// %s: %s:%d:%d: ", FileCheckPrefix, GetCursorSource(Ref), + curLine, curColumn); + PrintCursor(Ref); + printf("\n"); + } } startBuf++; } + + return CXChildVisit_Continue; } /******************************************************************************/ /* USR testing. */ /******************************************************************************/ -static void USRDeclVisitor(CXDecl D, CXCursor C, CXClientData Filter) { - if (!Filter || (C.kind == *(enum CXCursorKind *)Filter)) { - CXString USR = clang_getDeclUSR(C.decl); +enum CXChildVisitResult USRVisitor(CXCursor C, CXCursor parent, + CXClientData ClientData) { + VisitorData *Data = (VisitorData *)ClientData; + if (!Data->Filter || (C.kind == *(enum CXCursorKind *)Data->Filter)) { + CXString USR = clang_getCursorUSR(C); if (!USR.Spelling) { clang_disposeString(USR); - return; + return CXChildVisit_Continue; } printf("// %s: %s %s", FileCheckPrefix, GetCursorSource(C), USR.Spelling); - PrintDeclExtent(C.decl); + PrintCursorExtent(C); printf("\n"); clang_disposeString(USR); - } -} - -static void USRVisitor(CXTranslationUnit Unit, CXCursor Cursor, - CXClientData Filter) { - if (Cursor.decl) { - /* USRDeclVisitor(Unit, Cursor.decl, Cursor, Filter);*/ - clang_loadDeclaration(Cursor.decl, USRDeclVisitor, 0); - } + + return CXChildVisit_Recurse; + } + + return CXChildVisit_Continue; } /******************************************************************************/ @@ -191,10 +302,11 @@ static void USRVisitor(CXTranslationUnit Unit, CXCursor Cursor, static int perform_test_load(CXIndex Idx, CXTranslationUnit TU, const char *filter, const char *prefix, - CXTranslationUnitIterator Visitor) { + CXCursorVisitor Visitor) { enum CXCursorKind K = CXCursor_NotImplemented; enum CXCursorKind *ck = &K; - + VisitorData Data; + if (prefix) FileCheckPrefix = prefix; @@ -211,14 +323,16 @@ static int perform_test_load(CXIndex Idx, CXTranslationUnit TU, return 1; } - clang_loadTranslationUnit(TU, Visitor, ck); + Data.TU = TU; + Data.Filter = ck; + clang_visitChildren(clang_getTranslationUnitCursor(TU), Visitor, &Data); clang_disposeTranslationUnit(TU); return 0; } int perform_test_load_tu(const char *file, const char *filter, const char *prefix, - CXTranslationUnitIterator Visitor) { + CXCursorVisitor Visitor) { CXIndex Idx; CXTranslationUnit TU; Idx = clang_createIndex(/* excludeDeclsFromPCH */ @@ -232,11 +346,15 @@ int perform_test_load_tu(const char *file, const char *filter, } int perform_test_load_source(int argc, const char **argv, const char *filter, - CXTranslationUnitIterator Visitor) { + CXCursorVisitor Visitor) { const char *UseExternalASTs = getenv("CINDEXTEST_USE_EXTERNAL_AST_GENERATION"); CXIndex Idx; CXTranslationUnit TU; + struct CXUnsavedFile *unsaved_files = 0; + int num_unsaved_files = 0; + int result; + Idx = clang_createIndex(/* excludeDeclsFromPCH */ !strcmp(filter, "local") ? 1 : 0, /* displayDiagnostics */ 1); @@ -244,13 +362,22 @@ int perform_test_load_source(int argc, const char **argv, const char *filter, if (UseExternalASTs && strlen(UseExternalASTs)) clang_setUseExternalASTGeneration(Idx, 1); - TU = clang_createTranslationUnitFromSourceFile(Idx, 0, argc, argv); + if (parse_remapped_files(argc, argv, 0, &unsaved_files, &num_unsaved_files)) + return -1; + + TU = clang_createTranslationUnitFromSourceFile(Idx, 0, + argc - num_unsaved_files, + argv + num_unsaved_files, + num_unsaved_files, + unsaved_files); if (!TU) { fprintf(stderr, "Unable to load translation unit!\n"); return 1; } - return perform_test_load(Idx, TU, filter, NULL, Visitor); + result = perform_test_load(Idx, TU, filter, NULL, Visitor); + free_remapped_files(unsaved_files, num_unsaved_files); + return result; } /******************************************************************************/ @@ -277,6 +404,7 @@ static int perform_file_scan(const char *ast_file, const char *source_file, FILE *fp; unsigned line; CXCursor prevCursor; + CXFile file; unsigned printed; unsigned start_line, start_col, last_line, last_col; size_t i; @@ -301,6 +429,7 @@ static int perform_file_scan(const char *ast_file, const char *source_file, start_line = last_line = 1; start_col = last_col = 1; + file = clang_getFile(TU, source_file); while (!feof(fp)) { size_t len = 0; int c; @@ -315,7 +444,7 @@ static int perform_file_scan(const char *ast_file, const char *source_file, for (i = 0; i < len ; ++i) { CXCursor cursor; - cursor = clang_getCursor(TU, source_file, line, i+1); + cursor = clang_getCursor(TU, clang_getLocation(TU, file, line, i+1)); if (!clang_equalCursors(cursor, prevCursor) && prevCursor.kind != CXCursor_InvalidFile) { @@ -454,99 +583,6 @@ void print_completion_result(CXCompletionResult *completion_result, fprintf(file, "\n"); } -void free_remapped_files(struct CXUnsavedFile *unsaved_files, - int num_unsaved_files) { - int i; - for (i = 0; i != num_unsaved_files; ++i) { - free((char *)unsaved_files[i].Filename); - free((char *)unsaved_files[i].Contents); - } -} - -int parse_remapped_files(int argc, const char **argv, int start_arg, - struct CXUnsavedFile **unsaved_files, - int *num_unsaved_files) { - int i; - int arg; - int prefix_len = strlen("-remap-file="); - *unsaved_files = 0; - *num_unsaved_files = 0; - - /* Count the number of remapped files. */ - for (arg = start_arg; arg < argc; ++arg) { - if (strncmp(argv[arg], "-remap-file=", prefix_len)) - break; - - ++*num_unsaved_files; - } - - if (*num_unsaved_files == 0) - return 0; - - *unsaved_files - = (struct CXUnsavedFile *)malloc(sizeof(struct CXUnsavedFile) * - *num_unsaved_files); - for (arg = start_arg, i = 0; i != *num_unsaved_files; ++i, ++arg) { - struct CXUnsavedFile *unsaved = *unsaved_files + i; - const char *arg_string = argv[arg] + prefix_len; - int filename_len; - char *filename; - char *contents; - FILE *to_file; - const char *semi = strchr(arg_string, ';'); - if (!semi) { - fprintf(stderr, - "error: -remap-file=from;to argument is missing semicolon\n"); - free_remapped_files(*unsaved_files, i); - *unsaved_files = 0; - *num_unsaved_files = 0; - return -1; - } - - /* Open the file that we're remapping to. */ - to_file = fopen(semi + 1, "r"); - if (!to_file) { - fprintf(stderr, "error: cannot open file %s that we are remapping to\n", - semi + 1); - free_remapped_files(*unsaved_files, i); - *unsaved_files = 0; - *num_unsaved_files = 0; - return -1; - } - - /* Determine the length of the file we're remapping to. */ - fseek(to_file, 0, SEEK_END); - unsaved->Length = ftell(to_file); - fseek(to_file, 0, SEEK_SET); - - /* Read the contents of the file we're remapping to. */ - contents = (char *)malloc(unsaved->Length + 1); - if (fread(contents, 1, unsaved->Length, to_file) != unsaved->Length) { - fprintf(stderr, "error: unexpected %s reading 'to' file %s\n", - (feof(to_file) ? "EOF" : "error"), semi + 1); - fclose(to_file); - free_remapped_files(*unsaved_files, i); - *unsaved_files = 0; - *num_unsaved_files = 0; - return -1; - } - contents[unsaved->Length] = 0; - unsaved->Contents = contents; - - /* Close the file. */ - fclose(to_file); - - /* Copy the file name that we're remapping from. */ - filename_len = semi - arg_string; - filename = (char *)malloc(filename_len + 1); - memcpy(filename, arg_string, filename_len); - filename[filename_len] = 0; - unsaved->Filename = filename; - } - - return 0; -} - int perform_code_completion(int argc, const char **argv) { const char *input = argv[1]; char *filename = 0; @@ -586,13 +622,80 @@ int perform_code_completion(int argc, const char **argv) { return 0; } +typedef struct { + char *filename; + unsigned line; + unsigned column; +} CursorSourceLocation; + +int inspect_cursor_at(int argc, const char **argv) { + CXIndex CIdx; + int errorCode; + struct CXUnsavedFile *unsaved_files = 0; + int num_unsaved_files = 0; + CXTranslationUnit TU; + CXCursor Cursor; + CursorSourceLocation *Locations = 0; + unsigned NumLocations = 0, Loc; + + /* Count the number of locations. */ + while (strstr(argv[NumLocations+1], "-cursor-at=") == argv[NumLocations+1]) + ++NumLocations; + + /* Parse the locations. */ + assert(NumLocations > 0 && "Unable to count locations?"); + Locations = (CursorSourceLocation *)malloc( + NumLocations * sizeof(CursorSourceLocation)); + for (Loc = 0; Loc < NumLocations; ++Loc) { + const char *input = argv[Loc + 1] + strlen("-cursor-at="); + if ((errorCode = parse_file_line_column(input, &Locations[Loc].filename, + &Locations[Loc].line, + &Locations[Loc].column))) + return errorCode; + } + + if (parse_remapped_files(argc, argv, NumLocations + 1, &unsaved_files, + &num_unsaved_files)) + return -1; + + CIdx = clang_createIndex(0, 1); + TU = clang_createTranslationUnitFromSourceFile(CIdx, argv[argc - 1], + argc - num_unsaved_files - 2 - NumLocations, + argv + num_unsaved_files + 1 + NumLocations, + num_unsaved_files, + unsaved_files); + if (!TU) { + fprintf(stderr, "unable to parse input\n"); + return -1; + } + + for (Loc = 0; Loc < NumLocations; ++Loc) { + CXFile file = clang_getFile(TU, Locations[Loc].filename); + if (!file) + continue; + + Cursor = clang_getCursor(TU, + clang_getLocation(TU, file, Locations[Loc].line, + Locations[Loc].column)); + PrintCursor(Cursor); + printf("\n"); + free(Locations[Loc].filename); + } + + clang_disposeTranslationUnit(TU); + clang_disposeIndex(CIdx); + free(Locations); + free_remapped_files(unsaved_files, num_unsaved_files); + return 0; +} + /******************************************************************************/ /* Command line processing. */ /******************************************************************************/ -static CXTranslationUnitIterator GetVisitor(const char *s) { +static CXCursorVisitor GetVisitor(const char *s) { if (s[0] == '\0') - return TranslationUnitVisitor; + return FilteredPrintingVisitor; if (strcmp(s, "-usrs") == 0) return USRVisitor; return NULL; @@ -601,6 +704,7 @@ static CXTranslationUnitIterator GetVisitor(const char *s) { static void print_usage(void) { fprintf(stderr, "usage: c-index-test -code-completion-at=<site> <compiler arguments>\n" + " c-index-test -cursor-at=<site> <compiler arguments>\n" " c-index-test -test-file-scan <AST file> <source file> " "[FileCheck prefix]\n" " c-index-test -test-load-tu <AST file> <symbol filter> " @@ -608,7 +712,8 @@ static void print_usage(void) { " c-index-test -test-load-tu-usrs <AST file> <symbol filter> " "[FileCheck prefix]\n" " c-index-test -test-load-source <symbol filter> {<args>}*\n" - " c-index-test -test-load-source-usrs <symbol filter> {<args>}*\n\n" + " c-index-test -test-load-source-usrs <symbol filter> {<args>}*\n\n"); + fprintf(stderr, " <symbol filter> values:\n%s", " all - load all symbols, including those from PCH\n" " local - load all symbols except those in PCH\n" @@ -623,13 +728,15 @@ static void print_usage(void) { int main(int argc, const char **argv) { if (argc > 2 && strstr(argv[1], "-code-completion-at=") == argv[1]) return perform_code_completion(argc, argv); + if (argc > 2 && strstr(argv[1], "-cursor-at=") == argv[1]) + return inspect_cursor_at(argc, argv); else if (argc >= 4 && strncmp(argv[1], "-test-load-tu", 13) == 0) { - CXTranslationUnitIterator I = GetVisitor(argv[1] + 13); + CXCursorVisitor I = GetVisitor(argv[1] + 13); if (I) return perform_test_load_tu(argv[2], argv[3], argc >= 5 ? argv[4] : 0, I); } else if (argc >= 4 && strncmp(argv[1], "-test-load-source", 17) == 0) { - CXTranslationUnitIterator I = GetVisitor(argv[1] + 17); + CXCursorVisitor I = GetVisitor(argv[1] + 17); if (I) return perform_test_load_source(argc - 3, argv + 3, argv[2], I); } diff --git a/tools/driver/CMakeLists.txt b/tools/driver/CMakeLists.txt index 0815554..90fb09c 100644 --- a/tools/driver/CMakeLists.txt +++ b/tools/driver/CMakeLists.txt @@ -44,4 +44,4 @@ install(TARGETS clang RUNTIME DESTINATION bin) # Create the clang++ symlink at installation time. -install(CODE "execute_process(COMMAND \"${CMAKE_COMMAND}\" -E ${CLANGXX_LINK_OR_COPY} \"${CMAKE_INSTALL_PREFIX}/bin/clang${CMAKE_EXECUTABLE_SUFFIX}\" \"${CMAKE_INSTALL_PREFIX}/bin/clang++${CMAKE_EXECUTABLE_SUFFIX}\")") +install(CODE "execute_process(COMMAND \"${CMAKE_COMMAND}\" -E ${CLANGXX_LINK_OR_COPY} \"${CMAKE_INSTALL_PREFIX}/bin/clang${CMAKE_EXECUTABLE_SUFFIX}\" \"\$ENV{DESTDIR}/\${CMAKE_INSTALL_PREFIX}/bin/clang++${CMAKE_EXECUTABLE_SUFFIX}\")") diff --git a/tools/driver/Makefile b/tools/driver/Makefile index 7dab2ac..6ec8291 100644 --- a/tools/driver/Makefile +++ b/tools/driver/Makefile @@ -9,7 +9,9 @@ LEVEL = ../../../.. TOOLNAME = clang +ifndef CLANG_IS_PRODUCTION TOOLALIAS = clang++ +endif CPPFLAGS += -I$(PROJ_SRC_DIR)/../../include -I$(PROJ_OBJ_DIR)/../../include CXXFLAGS = -fno-rtti diff --git a/utils/OptionalTests/Extra/README.txt b/utils/OptionalTests/Extra/README.txt new file mode 100644 index 0000000..565241b --- /dev/null +++ b/utils/OptionalTests/Extra/README.txt @@ -0,0 +1,3 @@ +This directory is for extra unit style tests following the structure of +clang/tests, but which are not portable or not suitable for inclusion in the +regular test suite. diff --git a/utils/OptionalTests/Extra/Runtime/darwin-clang_rt.c b/utils/OptionalTests/Extra/Runtime/darwin-clang_rt.c new file mode 100644 index 0000000..d22c0bd --- /dev/null +++ b/utils/OptionalTests/Extra/Runtime/darwin-clang_rt.c @@ -0,0 +1,338 @@ +/* This file tests that we can succesfully call each compiler-rt function. It is + designed to check that the runtime libraries are available for linking and + that they contain the expected contents. It is not designed to test the + correctness of the individual functions in compiler-rt. + + This test is assumed to be run on a 10.6 machine. The two environment + variables below should be set to 10.4 and 10.5 machines which can be directly + ssh/rsync'd to in order to actually test the executables can run on the + desired targets. +*/ + +// RUN: export TENFOUR_X86_MACHINE=localhost +// RUN: export TENFIVE_X86_MACHINE=localhost +// RUN: export ARM_MACHINE=localhost +// RUN: export ARM_SYSROOT=$(xcodebuild -sdk iphoneos -version Path) + +// RUN: echo iPhoneOS, ARM, v6, thumb +// RUN: %clang -isysroot $ARM_SYSROOT -arch armv6 -mthumb -c %s -o %t.o +// RUN: %clang -isysroot $ARM_SYSROOT -arch armv6 -mthumb -v -Wl,-t,-v -o %t %t.o 1>&2 +// RUN: rsync -arv %t $ARM_MACHINE:/tmp/a.out +// RUN: ssh $ARM_MACHINE /tmp/a.out +// RUN: echo + +// RUN: echo iPhoneOS, ARM, v6, no-thumb +// RUN: %clang -isysroot $ARM_SYSROOT -arch armv6 -mno-thumb -c %s -o %t.o +// RUN: %clang -isysroot $ARM_SYSROOT -arch armv6 -mno-thumb -v -Wl,-t,-v -o %t %t.o 1>&2 +// RUN: rsync -arv %t $ARM_MACHINE:/tmp/a.out +// RUN: ssh $ARM_MACHINE /tmp/a.out +// RUN: echo + +// RUN: echo iPhoneOS, ARM, v7, thumb +// RUN: %clang -isysroot $ARM_SYSROOT -arch armv7 -mthumb -c %s -o %t.o +// RUN: %clang -isysroot $ARM_SYSROOT -arch armv7 -mthumb -v -Wl,-t,-v -o %t %t.o 1>&2 +// RUN: rsync -arv %t $ARM_MACHINE:/tmp/a.out +// RUN: ssh $ARM_MACHINE /tmp/a.out +// RUN: echo + +// RUN: echo iPhoneOS, ARM, v7, no-thumb +// RUN: %clang -isysroot $ARM_SYSROOT -arch armv7 -mno-thumb -c %s -o %t.o +// RUN: %clang -isysroot $ARM_SYSROOT -arch armv7 -mno-thumb -v -Wl,-t,-v -o %t %t.o 1>&2 +// RUN: rsync -arv %t $ARM_MACHINE:/tmp/a.out +// RUN: ssh $ARM_MACHINE /tmp/a.out +// RUN: echo + +// RUN: echo 10.4, i386 +// RUN: %clang -arch i386 -mmacosx-version-min=10.4 -c %s -o %t.o +// RUN: %clang -arch i386 -mmacosx-version-min=10.4 -v -Wl,-t,-v -o %t %t.o 1>&2 +// RUN: %t +// RUN: echo + +// RUN: rsync -arv %t $TENFOUR_X86_MACHINE:/tmp/a.out +// RUN: ssh $TENFOUR_X86_MACHINE /tmp/a.out +// RUN: echo + +// RUX: rsync -arv %t $TENFIVE_X86_MACHINE:/tmp/a.out +// RUX: ssh $TENFIVE_X86_MACHINE /tmp/a.out +// RUN: echo + +// RUN: echo 10.5, i386 +// RUN: %clang -arch i386 -mmacosx-version-min=10.5 -c %s -o %t.o +// RUN: %clang -arch i386 -mmacosx-version-min=10.5 -v -Wl,-t,-v -o %t %t.o 1>&2 +// RUN: %t +// RUN: echo + +// RUN: rsync -arv %t $TENFIVE_X86_MACHINE:/tmp/a.out +// RUN: ssh $TENFIVE_X86_MACHINE /tmp/a.out +// RUN: echo + +// RUN: echo 10.6, i386 +// RUN: %clang -arch i386 -mmacosx-version-min=10.6 -c %s -o %t.o +// RUN: %clang -arch i386 -mmacosx-version-min=10.6 -v -Wl,-t,-v -o %t %t.o 1>&2 +// RUN: %t +// RUN: echo + +// RUN: echo 10.4, x86_64 +// RUN: %clang -arch x86_64 -mmacosx-version-min=10.4 -c %s -o %t.o +// RUN: %clang -arch x86_64 -mmacosx-version-min=10.4 -v -Wl,-t,-v -o %t %t.o 1>&2 +// RUN: %t +// RUN: echo + +// RUN: rsync -arv %t $TENFOUR_X86_MACHINE:/tmp/a.out +// RUN: ssh $TENFOUR_X86_MACHINE /tmp/a.out +// RUN: echo + +// RUN: rsync -arv %t $TENFIVE_X86_MACHINE:/tmp/a.out +// RUN: ssh $TENFIVE_X86_MACHINE /tmp/a.out +// RUN: echo + +// RUN: echo 10.5, x86_64 +// RUN: %clang -arch x86_64 -mmacosx-version-min=10.5 -c %s -o %t.o +// RUN: %clang -arch x86_64 -mmacosx-version-min=10.5 -v -Wl,-t,-v -o %t %t.o 1>&2 +// RUN: %t +// RUN: echo + +// RUN: rsync -arv %t $TENFIVE_X86_MACHINE:/tmp/a.out +// RUN: ssh $TENFIVE_X86_MACHINE /tmp/a.out +// RUN: echo + +// RUN: echo 10.6, x86_64 +// RUN: %clang -arch x86_64 -mmacosx-version-min=10.6 -c %s -o %t.o +// RUN: %clang -arch x86_64 -mmacosx-version-min=10.6 -v -Wl,-t,-v -o %t %t.o 1>&2 +// RUN: %t +// RUN: echo + +#include <assert.h> +#include <stdio.h> +#include <sys/utsname.h> + +typedef int si_int; +typedef unsigned su_int; + +typedef long long di_int; +typedef unsigned long long du_int; + +// Integral bit manipulation + +di_int __ashldi3(di_int a, si_int b); // a << b +di_int __ashrdi3(di_int a, si_int b); // a >> b arithmetic (sign fill) +di_int __lshrdi3(di_int a, si_int b); // a >> b logical (zero fill) + +si_int __clzsi2(si_int a); // count leading zeros +si_int __clzdi2(di_int a); // count leading zeros +si_int __ctzsi2(si_int a); // count trailing zeros +si_int __ctzdi2(di_int a); // count trailing zeros + +si_int __ffsdi2(di_int a); // find least significant 1 bit + +si_int __paritysi2(si_int a); // bit parity +si_int __paritydi2(di_int a); // bit parity + +si_int __popcountsi2(si_int a); // bit population +si_int __popcountdi2(di_int a); // bit population + +// Integral arithmetic + +di_int __negdi2 (di_int a); // -a +di_int __muldi3 (di_int a, di_int b); // a * b +di_int __divdi3 (di_int a, di_int b); // a / b signed +du_int __udivdi3 (du_int a, du_int b); // a / b unsigned +di_int __moddi3 (di_int a, di_int b); // a % b signed +du_int __umoddi3 (du_int a, du_int b); // a % b unsigned +du_int __udivmoddi4(du_int a, du_int b, du_int* rem); // a / b, *rem = a % b + +// Integral arithmetic with trapping overflow + +si_int __absvsi2(si_int a); // abs(a) +di_int __absvdi2(di_int a); // abs(a) + +si_int __negvsi2(si_int a); // -a +di_int __negvdi2(di_int a); // -a + +si_int __addvsi3(si_int a, si_int b); // a + b +di_int __addvdi3(di_int a, di_int b); // a + b + +si_int __subvsi3(si_int a, si_int b); // a - b +di_int __subvdi3(di_int a, di_int b); // a - b + +si_int __mulvsi3(si_int a, si_int b); // a * b +di_int __mulvdi3(di_int a, di_int b); // a * b + +// Integral comparison: a < b -> 0 +// a == b -> 1 +// a > b -> 2 + +si_int __cmpdi2 (di_int a, di_int b); +si_int __ucmpdi2(du_int a, du_int b); + +// Integral / floating point conversion + +di_int __fixsfdi( float a); +di_int __fixdfdi( double a); +di_int __fixxfdi(long double a); + +su_int __fixunssfsi( float a); +su_int __fixunsdfsi( double a); +su_int __fixunsxfsi(long double a); + +du_int __fixunssfdi( float a); +du_int __fixunsdfdi( double a); +du_int __fixunsxfdi(long double a); + +float __floatdisf(di_int a); +double __floatdidf(di_int a); +long double __floatdixf(di_int a); + +float __floatundisf(du_int a); +double __floatundidf(du_int a); +long double __floatundixf(du_int a); + +// Floating point raised to integer power + +float __powisf2( float a, si_int b); // a ^ b +double __powidf2( double a, si_int b); // a ^ b +long double __powixf2(long double a, si_int b); // a ^ b + +// Complex arithmetic + +// (a + ib) * (c + id) + + float _Complex __mulsc3( float a, float b, float c, float d); + double _Complex __muldc3(double a, double b, double c, double d); +long double _Complex __mulxc3(long double a, long double b, + long double c, long double d); + +// (a + ib) / (c + id) + + float _Complex __divsc3( float a, float b, float c, float d); + double _Complex __divdc3(double a, double b, double c, double d); +long double _Complex __divxc3(long double a, long double b, + long double c, long double d); + +#ifndef __arm +#define HAS_LONG_DOUBLE +#endif + +int main(int argc, char **argv) { + du_int du_tmp; + struct utsname name; +#ifdef __ENVIRONMENT_MAC_OS_X_VERSION_MIN_REQUIRED__ + const char *target_name = "OS X"; + unsigned target_version = __ENVIRONMENT_MAC_OS_X_VERSION_MIN_REQUIRED__; + unsigned target_maj = target_version / 100; + unsigned target_min = (target_version / 10) % 10; + unsigned target_micro = target_version % 10; +#else + const char *target_name = "iPhoneOS"; + unsigned target_version = __ENVIRONMENT_IPHONE_OS_VERSION_MIN_REQUIRED__; + unsigned target_maj = target_version / 10000; + unsigned target_min = (target_version / 100) % 100; + unsigned target_micro = target_version % 100; +#endif + + if (uname(&name)) + return 1; + + fprintf(stderr, "%s: clang_rt test:\n", argv[0]); + fprintf(stderr, " target : %s %d.%d.%d\n\n", target_name, + target_maj, target_min, target_micro); + fprintf(stderr, " sysname : %s\n", name.sysname); + fprintf(stderr, " nodename: %s\n", name.nodename); + fprintf(stderr, " release : %s\n", name.release); + fprintf(stderr, " version : %s\n", name.version); + fprintf(stderr, " machine : %s\n", name.machine); + + assert(__ashldi3(1, 1) == 2); + assert(__ashrdi3(2, 1) == 1); + assert(__lshrdi3(2, 1) == 1); + assert(__clzsi2(1) == 31); + assert(__clzdi2(1) == 63); + assert(__ctzsi2(2) == 1); + assert(__ctzdi2(2) == 1); + assert(__ffsdi2(12) == 3); + assert(__paritysi2(13) == 1); + assert(__paritydi2(13) == 1); + assert(__popcountsi2(13) == 3); + assert(__popcountdi2(13) == 3); + assert(__negdi2(3) == -3); + assert(__muldi3(2,2) == 4); + assert(__divdi3(-4,2) == -2); + assert(__udivdi3(4,2) == 2); + assert(__moddi3(3,2) == 1); + assert(__umoddi3(3,2) == 1); + assert(__udivmoddi4(5,2,&du_tmp) == 2 && du_tmp == 1); + assert(__absvsi2(-2) == 2); + assert(__absvdi2(-2) == 2); + assert(__negvsi2(2) == -2); + assert(__negvdi2(2) == -2); + assert(__addvsi3(2, 3) == 5); + assert(__addvdi3(2, 3) == 5); + assert(__subvsi3(2, 3) == -1); + assert(__subvdi3(2, 3) == -1); + assert(__mulvsi3(2, 3) == 6); + assert(__mulvdi3(2, 3) == 6); + assert(__cmpdi2(3, 2) == 2); + assert(__ucmpdi2(3, 2) == 2); + assert(__fixsfdi(2.0) == 2); + assert(__fixdfdi(2.0) == 2); + assert(__fixunssfsi(2.0) == 2); + assert(__fixunsdfsi(2.0) == 2); + assert(__fixunssfdi(2.0) == 2); + assert(__fixunsdfdi(2.0) == 2); + assert(__floatdisf(2) == 2.0); + assert(__floatdidf(2) == 2.0); + assert(__floatundisf(2) == 2.0); + assert(__floatundidf(2) == 2.0); + assert(__powisf2(2.0, 2) == 4.0); + assert(__powidf2(2.0, 2) == 4.0); + + // FIXME: Clang/LLVM seems to be miscompiling _Complex currently, probably an + // ABI issue. +#ifndef __arm + { + _Complex float a = __mulsc3(1.0, 2.0, 4.0, 8.0); + _Complex float b = (-12.0 + 16.0j); + fprintf(stderr, "a: (%f + %f), b: (%f + %f)\n", + __real a, __imag a, __real b, __imag b); + } + assert(__mulsc3(1.0, 2.0, 4.0, 8.0) == (-12.0 + 16.0j)); + assert(__muldc3(1.0, 2.0, 4.0, 8.0) == (-12.0 + 16.0j)); + assert(__divsc3(1.0, 2.0, 4.0, 8.0) == (0.25 + 0j)); + assert(__divdc3(1.0, 2.0, 4.0, 8.0) == (0.25 + 0j)); +#endif + +#ifdef HAS_LONG_DOUBLE + assert(__divxc3(1.0, 2.0, 4.0, 8.0) == (0.25 + 0j)); + assert(__fixunsxfdi(2.0) == 2); + assert(__fixunsxfsi(2.0) == 2); + assert(__fixxfdi(2.0) == 2); + assert(__floatdixf(2) == 2.0); + assert(__floatundixf(2) == 2); + assert(__mulxc3(1.0, 2.0, 4.0, 8.0) == (-12.0 + 16.0j)); + assert(__powixf2(2.0, 2) == 4.0); +#endif + + // Test some calls which are used on armv6/thumb. The calls/prototypes are + // fake, it would be nice to test correctness, but mostly we just want to + // make sure we resolve symbols correctly. +#if defined(__arm) && defined(__ARM_ARCH_6K__) && defined(__thumb__) + if (argc == 100) { + extern void __restore_vfp_d8_d15_regs(void), __save_vfp_d8_d15_regs(void); + extern void __switch8(void), __switchu8(void), + __switch16(void), __switch32(void); + extern void __addsf3vfp(void); + + __addsf3vfp(); + __restore_vfp_d8_d15_regs(); + __save_vfp_d8_d15_regs(); + __switch8(); + __switchu8(); + __switch16(); + __switch32(); + } +#endif + + fprintf(stderr, " OK!\n"); + + return 0; +} diff --git a/utils/OptionalTests/README.txt b/utils/OptionalTests/README.txt new file mode 100644 index 0000000..4ffdb3b --- /dev/null +++ b/utils/OptionalTests/README.txt @@ -0,0 +1,4 @@ +This is a dumping ground for additional tests which do not fit cleanly into the +clang regression tests. For example, tests which are not portable, require +additional software or configuration, take an excessive time to run, or are +flaky can be kept here. diff --git a/utils/OptionalTests/lit.cfg b/utils/OptionalTests/lit.cfg new file mode 100644 index 0000000..592c424 --- /dev/null +++ b/utils/OptionalTests/lit.cfg @@ -0,0 +1,26 @@ +# -*- Python -*- + +# Configuration file for the 'lit' test runner. + +# Load the main clang test config so we can leech its clang finding logic. +lit.load_config(config, os.path.join(os.path.dirname(__file__), + '..', '..', 'test', 'lit.cfg')) +assert config.clang, "Failed to set clang!?" + +# name: The name of this test suite. +config.name = 'Clang-Opt-Tests' + +# suffixes: A list of file extensions to treat as test files. +config.suffixes = [] + +# Reset these from the Clang config. + +# test_source_root: The root path where tests are located. +config.test_source_root = os.path.dirname(__file__) + +# test_exec_root: The root path where tests should be run. +clang_obj_root = getattr(config, 'clang_obj_root', None) +if clang_obj_root is not None: + config.test_exec_root = os.path.join(clang_obj_root, 'utils', + 'OptionalTests') + diff --git a/www/analyzer/scan-build.html b/www/analyzer/scan-build.html index 92a4c3e..fd05af0 100644 --- a/www/analyzer/scan-build.html +++ b/www/analyzer/scan-build.html @@ -81,7 +81,7 @@ built using <tt>xcodebuild</tt>.<p> $ <span class="code_highlight">scan-build</span> <i>[scan-build options]</i> <span class="code_highlight"><command></span> <i>[command options]</i> </pre> -<p>Operationally, <tt>scan-build</tt> literally runs <command> with all of the +<p>Operationally, <tt>scan-build</tt> literally runs <command> with all of the subsequent options passed to it. For example, one can pass <nobr><tt>-j4</tt></nobr> to <tt>make</tt> get a parallel build over 4 cores:</p> diff --git a/www/hacking.html b/www/hacking.html index ec9cd97..3bbc0ea 100644 --- a/www/hacking.html +++ b/www/hacking.html @@ -19,6 +19,7 @@ on Clang for developers who are new to the Clang and/or LLVM codebases.</p> <ul> + <li><a href="#style">Coding Standards</a></li> <li><a href="#docs">Developer Documentation</a></li> <li><a href="#debugging">Debugging</a></li> <li><a href="#testing">Testing</a></li> @@ -31,6 +32,27 @@ </ul> <!--=====================================================================--> + <h2 id="docs">Coding Standards</h2> + <!--=====================================================================--> + + <p>Clang follows the + LLVM <a href="http://llvm.org/docs/CodingStandards.html">Coding + Standards</a>. When submitting patches, please take care to follow these standards + and to match the style of the code to that present in Clang (for example, in + terms of indentation, bracing, and statement spacing).</p> + + <p>Clang has a few additional coding standards:</p> + <ul> + <li><i>cstdio is forbidden</i>: library code should not output diagnostics + or other information using <tt>cstdio</tt>; debugging routines should + use <tt>llvm::errs()</tt>. Other uses of <tt>cstdio</tt> impose behavior + upon clients and block integrating Clang as a library. Libraries should + support <tt>raw_ostream</tt> based interfaces for textual + output. See <a href="http://llvm.org/docs/CodingStandards.html#ll_raw_ostream">Coding + Standards</a>.</li> + </ul> + + <!--=====================================================================--> <h2 id="docs">Developer Documentation</h2> <!--=====================================================================--> |