diff --git a/NOTES.txt b/NOTES.txt index dc7a9bc0e754..beceb7d1ccce 100644 --- a/NOTES.txt +++ b/NOTES.txt @@ -17,7 +17,7 @@ Creating and using a PTH file for performance measurement (use a release-asserts build). $ clang -ccc-pch-is-pth -x objective-c-header INPUTS/Cocoa_h.m -o /tmp/tokencache -$ clang-cc -token-cache /tmp/tokencache INPUTS/Cocoa_h.m +$ clang -cc1 -token-cache /tmp/tokencache INPUTS/Cocoa_h.m //===---------------------------------------------------------------------===// diff --git a/TODO.txt b/TODO.txt index 7ceb0da15b36..067f07b9d323 100644 --- a/TODO.txt +++ b/TODO.txt @@ -65,7 +65,6 @@ More ideas for code modification hints: - If no member of a given name is found in a class/struct, search through the names of entities that do exist in the class and suggest the closest candidate. e.g., if I write "DS.setTypeSpecType", it would suggest "DS.SetTypeSpecType" (edit distance = 1). - If a class member is defined out-of-line but isn't in the class declaration (and there are no close matches!), provide the option to add an in-class declaration. - Fix-it hints for the inclusion of headers when needed for particular features (e.g., for typeid) - - Change "foo.bar" to "foo->bar" when "foo" is a pointer. //===---------------------------------------------------------------------===// diff --git a/clang.xcodeproj/project.pbxproj b/clang.xcodeproj/project.pbxproj index 1ad7019aa00b..850cfd792f6a 100644 --- a/clang.xcodeproj/project.pbxproj +++ b/clang.xcodeproj/project.pbxproj @@ -37,13 +37,14 @@ 1A6B6CD410693FC900BB4A8F /* CodeCompleteConsumer.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 1A6B6CD110693FC900BB4A8F /* CodeCompleteConsumer.cpp */; }; 1A6B6CD510693FC900BB4A8F /* SemaCodeComplete.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 1A6B6CD210693FC900BB4A8F /* SemaCodeComplete.cpp */; }; 1A6B6E9A1069833600BB4A8F /* CGExprCXX.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 1A6B6E991069833600BB4A8F /* CGExprCXX.cpp */; }; - 1A6C01F7108128710072DEE4 /* CGRtti.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 1A6C01F6108128710072DEE4 /* CGRtti.cpp */; }; + 1A6C01F7108128710072DEE4 /* CGRTTI.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 1A6C01F6108128710072DEE4 /* CGRTTI.cpp */; }; 1A6FE7090FD6F85800E00CA9 /* CGTemporaries.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 1A6FE7080FD6F85800E00CA9 /* CGTemporaries.cpp */; }; 1A701B640F7C8FE400FEC4D1 /* SemaAccess.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 1A701B630F7C8FE400FEC4D1 /* SemaAccess.cpp */; }; 1A7342480C7B57D500122F56 /* CGObjC.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 1A7342470C7B57D500122F56 /* CGObjC.cpp */; }; 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 */; }; + 1A986AB710D0746D00A8EA9E /* CGDeclCXX.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 1A986AB610D0746D00A8EA9E /* CGDeclCXX.cpp */; }; 1AA1D91810125DE30078DEBC /* RecordLayoutBuilder.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 1AA1D91610125DE30078DEBC /* RecordLayoutBuilder.cpp */; }; 1ABC36940C7A4BDC006DB0AB /* CGBuiltin.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 1ABC36930C7A4BDC006DB0AB /* CGBuiltin.cpp */; }; 1ADD795410A90C6100741BBA /* TypePrinter.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 1ADD795110A90C6100741BBA /* TypePrinter.cpp */; }; @@ -53,7 +54,6 @@ 1AE4EE3E103B89ED00888A23 /* StmtProfile.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 1AE4EE3D103B89ED00888A23 /* StmtProfile.cpp */; }; 1AE4EE40103B8A0A00888A23 /* TargetABIInfo.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 1AE4EE3F103B8A0A00888A23 /* TargetABIInfo.cpp */; }; 1AF1B50F109A4FB800AFAFAC /* CGException.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 1AF1B50E109A4FB800AFAFAC /* CGException.cpp */; }; - 1AFEF4070F8A6B2300476F2B /* clang-cc.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 1AFEF4050F8A6B2300476F2B /* clang-cc.cpp */; }; 1AFF8AE31012BFC900D248DA /* CGRecordLayoutBuilder.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 1AFF8AE11012BFC900D248DA /* CGRecordLayoutBuilder.cpp */; }; 3507E4C20E27FE2D00FB7B57 /* CheckObjCInstMethSignature.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 3507E4C10E27FE2D00FB7B57 /* CheckObjCInstMethSignature.cpp */; }; 352246E70F5C6BE000D0D279 /* HTMLDiagnostics.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 352246E10F5C6BE000D0D279 /* HTMLDiagnostics.cpp */; }; @@ -279,6 +279,7 @@ DEF7D9F70C9C8B1A0001F598 /* Rewriter.h in CopyFiles */ = {isa = PBXBuildFile; fileRef = DEF7D9F60C9C8B1A0001F598 /* Rewriter.h */; }; DEF7D9F90C9C8B1D0001F598 /* Rewriter.cpp in Sources */ = {isa = PBXBuildFile; fileRef = DEF7D9F80C9C8B1D0001F598 /* Rewriter.cpp */; }; DEFFECA70DB1546600B4E7C3 /* DeltaTree.cpp in Sources */ = {isa = PBXBuildFile; fileRef = DEFFECA60DB1546600B4E7C3 /* DeltaTree.cpp */; }; + E16B523510D30B2400430AC9 /* cc1_main.cpp in Sources */ = {isa = PBXBuildFile; fileRef = E16B523410D30B2400430AC9 /* cc1_main.cpp */; }; /* End PBXBuildFile section */ /* Begin PBXCopyFilesBuildPhase section */ @@ -379,7 +380,7 @@ 1A6B6CD210693FC900BB4A8F /* SemaCodeComplete.cpp */ = {isa = PBXFileReference; fileEncoding = 4; indentWidth = 2; lastKnownFileType = sourcecode.cpp.cpp; name = SemaCodeComplete.cpp; path = lib/Sema/SemaCodeComplete.cpp; sourceTree = ""; tabWidth = 2; }; 1A6B6CD310693FC900BB4A8F /* SemaTemplate.h */ = {isa = PBXFileReference; fileEncoding = 4; indentWidth = 2; lastKnownFileType = sourcecode.c.h; name = SemaTemplate.h; path = lib/Sema/SemaTemplate.h; sourceTree = ""; tabWidth = 2; }; 1A6B6E991069833600BB4A8F /* CGExprCXX.cpp */ = {isa = PBXFileReference; fileEncoding = 4; indentWidth = 2; lastKnownFileType = sourcecode.cpp.cpp; name = CGExprCXX.cpp; path = lib/CodeGen/CGExprCXX.cpp; sourceTree = ""; tabWidth = 2; }; - 1A6C01F6108128710072DEE4 /* CGRtti.cpp */ = {isa = PBXFileReference; fileEncoding = 4; indentWidth = 2; lastKnownFileType = sourcecode.cpp.cpp; name = CGRtti.cpp; path = lib/CodeGen/CGRtti.cpp; sourceTree = ""; tabWidth = 2; }; + 1A6C01F6108128710072DEE4 /* CGRTTI.cpp */ = {isa = PBXFileReference; fileEncoding = 4; indentWidth = 2; lastKnownFileType = sourcecode.cpp.cpp; name = CGRTTI.cpp; path = lib/CodeGen/CGRTTI.cpp; sourceTree = ""; tabWidth = 2; }; 1A6FE7080FD6F85800E00CA9 /* CGTemporaries.cpp */ = {isa = PBXFileReference; fileEncoding = 4; indentWidth = 2; lastKnownFileType = sourcecode.cpp.cpp; name = CGTemporaries.cpp; path = lib/CodeGen/CGTemporaries.cpp; sourceTree = ""; tabWidth = 2; }; 1A7019E90F79BC1100FEC4D1 /* DiagnosticAnalysisKinds.td */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text; path = DiagnosticAnalysisKinds.td; sourceTree = ""; }; 1A7019EA0F79BC1100FEC4D1 /* DiagnosticASTKinds.td */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text; path = DiagnosticASTKinds.td; sourceTree = ""; }; @@ -396,6 +397,7 @@ 1A81AA5D108278A20094E50B /* CGVtable.h */ = {isa = PBXFileReference; fileEncoding = 4; indentWidth = 2; lastKnownFileType = sourcecode.c.h; name = CGVtable.h; path = lib/CodeGen/CGVtable.h; sourceTree = ""; tabWidth = 2; }; 1A869A6E0BA2164C008DA07A /* LiteralSupport.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = LiteralSupport.h; sourceTree = ""; }; 1A869AA70BA21ABA008DA07A /* LiteralSupport.cpp */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.cpp.cpp; path = LiteralSupport.cpp; sourceTree = ""; }; + 1A986AB610D0746D00A8EA9E /* CGDeclCXX.cpp */ = {isa = PBXFileReference; fileEncoding = 4; indentWidth = 2; lastKnownFileType = sourcecode.cpp.cpp; name = CGDeclCXX.cpp; path = lib/CodeGen/CGDeclCXX.cpp; sourceTree = ""; tabWidth = 2; }; 1AA1D91610125DE30078DEBC /* RecordLayoutBuilder.cpp */ = {isa = PBXFileReference; fileEncoding = 4; indentWidth = 2; lastKnownFileType = sourcecode.cpp.cpp; name = RecordLayoutBuilder.cpp; path = lib/AST/RecordLayoutBuilder.cpp; sourceTree = ""; tabWidth = 2; }; 1AA1D91710125DE30078DEBC /* RecordLayoutBuilder.h */ = {isa = PBXFileReference; fileEncoding = 4; indentWidth = 2; lastKnownFileType = sourcecode.c.h; name = RecordLayoutBuilder.h; path = lib/AST/RecordLayoutBuilder.h; sourceTree = ""; tabWidth = 2; }; 1AB290021045858B00FE33D8 /* PartialDiagnostic.h */ = {isa = PBXFileReference; fileEncoding = 4; indentWidth = 2; lastKnownFileType = sourcecode.c.h; path = PartialDiagnostic.h; sourceTree = ""; tabWidth = 2; }; @@ -408,7 +410,6 @@ 1AE4EE3D103B89ED00888A23 /* StmtProfile.cpp */ = {isa = PBXFileReference; fileEncoding = 4; indentWidth = 2; lastKnownFileType = sourcecode.cpp.cpp; name = StmtProfile.cpp; path = lib/AST/StmtProfile.cpp; sourceTree = ""; tabWidth = 2; }; 1AE4EE3F103B8A0A00888A23 /* TargetABIInfo.cpp */ = {isa = PBXFileReference; fileEncoding = 4; indentWidth = 2; lastKnownFileType = sourcecode.cpp.cpp; name = TargetABIInfo.cpp; path = lib/CodeGen/TargetABIInfo.cpp; sourceTree = ""; tabWidth = 2; }; 1AF1B50E109A4FB800AFAFAC /* CGException.cpp */ = {isa = PBXFileReference; fileEncoding = 4; indentWidth = 2; lastKnownFileType = sourcecode.cpp.cpp; name = CGException.cpp; path = lib/CodeGen/CGException.cpp; sourceTree = ""; tabWidth = 2; }; - 1AFEF4050F8A6B2300476F2B /* clang-cc.cpp */ = {isa = PBXFileReference; fileEncoding = 4; indentWidth = 2; lastKnownFileType = sourcecode.cpp.cpp; name = "clang-cc.cpp"; path = "tools/clang-cc/clang-cc.cpp"; sourceTree = ""; tabWidth = 2; }; 1AFF8AE11012BFC900D248DA /* CGRecordLayoutBuilder.cpp */ = {isa = PBXFileReference; fileEncoding = 4; indentWidth = 2; lastKnownFileType = sourcecode.cpp.cpp; name = CGRecordLayoutBuilder.cpp; path = lib/CodeGen/CGRecordLayoutBuilder.cpp; sourceTree = ""; tabWidth = 2; }; 1AFF8AE21012BFC900D248DA /* CGRecordLayoutBuilder.h */ = {isa = PBXFileReference; fileEncoding = 4; indentWidth = 2; lastKnownFileType = sourcecode.c.h; name = CGRecordLayoutBuilder.h; path = lib/CodeGen/CGRecordLayoutBuilder.h; sourceTree = ""; tabWidth = 2; }; 3507E4C10E27FE2D00FB7B57 /* CheckObjCInstMethSignature.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = CheckObjCInstMethSignature.cpp; path = lib/Analysis/CheckObjCInstMethSignature.cpp; sourceTree = ""; }; @@ -807,6 +808,7 @@ DEF7D9F80C9C8B1D0001F598 /* Rewriter.cpp */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.cpp.cpp; name = Rewriter.cpp; path = lib/Rewrite/Rewriter.cpp; sourceTree = ""; }; DEFFECA30DB093D100B4E7C3 /* DeltaTree.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = DeltaTree.h; path = clang/Rewrite/DeltaTree.h; sourceTree = ""; }; DEFFECA60DB1546600B4E7C3 /* DeltaTree.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = DeltaTree.cpp; path = lib/Rewrite/DeltaTree.cpp; sourceTree = ""; }; + E16B523410D30B2400430AC9 /* cc1_main.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = cc1_main.cpp; path = tools/driver/cc1_main.cpp; sourceTree = ""; }; /* End PBXFileReference section */ /* Begin PBXFrameworksBuildPhase section */ @@ -1268,13 +1270,14 @@ 1A4C41BE105B4C0B0047B5E7 /* CGClass.cpp */, 1A5D5E570E5E81010023C059 /* CGCXX.cpp */, 1A649E1E0F9599DA005B965E /* CGCXX.h */, - 1A6B6E991069833600BB4A8F /* CGExprCXX.cpp */, 35A3E7000DD3874400757F74 /* CGDebugInfo.cpp */, 35A3E7010DD3874400757F74 /* CGDebugInfo.h */, DE4264FB0C113592005A861D /* CGDecl.cpp */, + 1A986AB610D0746D00A8EA9E /* CGDeclCXX.cpp */, 1AF1B50E109A4FB800AFAFAC /* CGException.cpp */, DE4772FB0C10EAEC002239E8 /* CGExpr.cpp */, DEF2EFF20C6CDD74000C4259 /* CGExprAgg.cpp */, + 1A6B6E991069833600BB4A8F /* CGExprCXX.cpp */, DE224FF70C7AA98800D370A5 /* CGExprComplex.cpp */, 1A376A2C0D4AED9B002A1C52 /* CGExprConstant.cpp */, DE22526F0C7E82D000D370A5 /* CGExprScalar.cpp */, @@ -1284,7 +1287,7 @@ 3552E7580E520DD7003A8CA5 /* CGObjCMac.cpp */, 1AFF8AE11012BFC900D248DA /* CGRecordLayoutBuilder.cpp */, 1AFF8AE21012BFC900D248DA /* CGRecordLayoutBuilder.h */, - 1A6C01F6108128710072DEE4 /* CGRtti.cpp */, + 1A6C01F6108128710072DEE4 /* CGRTTI.cpp */, DE4772F90C10EAE5002239E8 /* CGStmt.cpp */, 1A6FE7080FD6F85800E00CA9 /* CGTemporaries.cpp */, 35475B230E7997680000BFE4 /* CGValue.h */, @@ -1539,23 +1542,15 @@ 90F9EFA8104ABDC400D09A15 /* c-index-test */, 9012911E104812DA0083456D /* CIndex */, 90FD6DB4103D9763005F5B73 /* index-test */, - DEDFE6200F7B3AE90035BD10 /* clang-cc */, DEDFE6210F7B3AF10035BD10 /* clang */, ); name = Tools; sourceTree = ""; }; - DEDFE6200F7B3AE90035BD10 /* clang-cc */ = { - isa = PBXGroup; - children = ( - 1AFEF4050F8A6B2300476F2B /* clang-cc.cpp */, - ); - name = "clang-cc"; - sourceTree = ""; - }; DEDFE6210F7B3AF10035BD10 /* clang */ = { isa = PBXGroup; children = ( + E16B523410D30B2400430AC9 /* cc1_main.cpp */, DEDFE6450F7B3B4E0035BD10 /* driver.cpp */, ); name = clang; @@ -1872,7 +1867,6 @@ 1A701B640F7C8FE400FEC4D1 /* SemaAccess.cpp in Sources */, 906BF4B00F83BA2E001071FA /* ConvertUTF.c in Sources */, DEDFF8880F848CF80035BD10 /* TemplateName.cpp in Sources */, - 1AFEF4070F8A6B2300476F2B /* clang-cc.cpp in Sources */, DEF165710F8FB34D0098507F /* PCHWriter.cpp in Sources */, DEF165750F8FB3510098507F /* PCHReader.cpp in Sources */, DEF168400F9548DC0098507F /* FixItRewriter.cpp in Sources */, @@ -1927,12 +1921,14 @@ 1A6B6CD510693FC900BB4A8F /* SemaCodeComplete.cpp in Sources */, 1A6B6E9A1069833600BB4A8F /* CGExprCXX.cpp in Sources */, 1A535ED9107BC45E000C3AE7 /* CXXInheritance.cpp in Sources */, - 1A6C01F7108128710072DEE4 /* CGRtti.cpp in Sources */, + 1A6C01F7108128710072DEE4 /* CGRTTI.cpp in Sources */, 1A81AA19108144F40094E50B /* CGVtable.cpp in Sources */, 1AF1B50F109A4FB800AFAFAC /* CGException.cpp in Sources */, 1ADD795410A90C6100741BBA /* TypePrinter.cpp in Sources */, 1ADD795510A90C6100741BBA /* TypeLoc.cpp in Sources */, 1ADD795610A90C6100741BBA /* TemplateBase.cpp in Sources */, + 1A986AB710D0746D00A8EA9E /* CGDeclCXX.cpp in Sources */, + E16B523510D30B2400430AC9 /* cc1_main.cpp in Sources */, ); runOnlyForDeploymentPostprocessing = 0; }; diff --git a/docs/BlockImplementation.txt b/docs/BlockImplementation.txt index b2ad40576b5e..c420455979cf 100644 --- a/docs/BlockImplementation.txt +++ b/docs/BlockImplementation.txt @@ -292,7 +292,7 @@ would be rewritten to be: int flags; //refcount; int size; int captured_i; - } i = { NULL, &i, 0, sizeof(struct _block_byref_i), 11; + } i = { NULL, &i, 0, sizeof(struct _block_byref_i), 11 }; i.forwarding->captured_i = 11; diff --git a/docs/LanguageExtensions.html b/docs/LanguageExtensions.html index 1c892fd23a5a..414d9c89e59b 100644 --- a/docs/LanguageExtensions.html +++ b/docs/LanguageExtensions.html @@ -23,6 +23,11 @@ td {
  • Include File Checking Macros
  • Builtin Macros
  • Vectors and Extended Vectors
  • +
  • Checks for Standard Language Features
  • +
  • Blocks
  • Function Overloading in C
  • Builtin Functions @@ -193,6 +198,23 @@ href="#__builtin_shufflevector">__builtin_shufflevector.

    Query for this feature with __has_feature(attribute_ext_vector_type).

    + +

    Checks for Standard Language Features

    + + +

    The __has_feature macro can be used to query if certain standard language features are +enabled. Those features are listed here.

    + +

    C++ exceptions

    + +

    Use __has_feature(cxx_exceptions) to determine if C++ exceptions have been enabled. For +example, compiling code with -fexceptions enables C++ exceptions.

    + +

    C++ RTTI

    + +

    Use __has_feature(cxx_rtti) to determine if C++ RTTI has been enabled. For example, +compiling code with -fno-rtti disables the use of RTTI.

    +

    Blocks

    diff --git a/docs/PCHInternals.html b/docs/PCHInternals.html index b34b6a29ccbc..e21ec5e90df3 100644 --- a/docs/PCHInternals.html +++ b/docs/PCHInternals.html @@ -26,7 +26,7 @@

    Table of Contents

    • Using Precompiled Headers with - clang-cc
    • + clang
    • Design Philosophy
    • Precompiled Header Contents
        @@ -44,15 +44,15 @@ Points
      -

      Using Precompiled Headers with clang-cc

      +

      Using Precompiled Headers with clang

      -

      The low-level Clang compiler, clang-cc, supports two command -line options for generating and using PCH files.

      +

      The Clang compiler frontend, clang -cc1, supports two command line +options for generating and using PCH files.

      -

      To generate PCH files using clang-cc, use the option +

      To generate PCH files using clang -cc1, use the option -emit-pch: -

       $ clang-cc test.h -emit-pch -o test.h.pch 
      +
       $ clang -cc1 test.h -emit-pch -o test.h.pch 

      This option is transparently used by clang when generating PCH files. The resulting PCH file contains the serialized form of the @@ -61,7 +61,7 @@ semantic analysis. The PCH file can then be used as a prefix header with the -include-pch option:

      -  $ clang-cc -include-pch test.h.pch test.c -o test.s
      +  $ clang -cc1 -include-pch test.h.pch test.c -o test.s
       

      Design Philosophy

      diff --git a/docs/PTHInternals.html b/docs/PTHInternals.html index 832d3b0a9788..279d47968be5 100644 --- a/docs/PTHInternals.html +++ b/docs/PTHInternals.html @@ -23,38 +23,38 @@ implementation. If you are interested in the end-user view, please see the User's Manual.

      -

      Using Pretokenized Headers with clang-cc (Low-level Interface)

      +

      Using Pretokenized Headers with clang (Low-level Interface)

      -

      The low-level Clang compiler tool, clang-cc, supports three command -line options for generating and using PTH files.

      +

      The Clang compiler frontend, clang -cc1, supports three command line +options for generating and using PTH files.

      -

      To generate PTH files using clang-cc, use the option +

      To generate PTH files using clang -cc1, use the option -emit-pth: -

       $ clang-cc test.h -emit-pth -o test.h.pth 
      +
       $ clang -cc1 test.h -emit-pth -o test.h.pth 

      This option is transparently used by clang when generating PTH files. Similarly, PTH files can be used as prefix headers using the -include-pth option:

      -  $ clang-cc -include-pth test.h.pth test.c -o test.s
      +  $ clang -cc1 -include-pth test.h.pth test.c -o test.s
       

      Alternatively, Clang's PTH files can be used as a raw "token-cache" (or "content" cache) of the source included by the original header file. This means that the contents of the PTH file are searched as substitutes -for any source files that are used by clang-cc to process a +for any source files that are used by clang -cc1 to process a source file. This is done by specifying the -token-cache option:

         $ cat test.h
         #include <stdio.h>
      -  $ clang-cc -emit-pth test.h -o test.h.pth
      +  $ clang -cc1 -emit-pth test.h -o test.h.pth
         $ cat test.c
         #include "test.h"
      -  $ clang-cc test.c -o test -token-cache test.h.pth
      +  $ clang -cc1 test.c -o test -token-cache test.h.pth
       

      In this example the contents of stdio.h (and the files it includes) @@ -117,7 +117,7 @@ PTH file needs to be generated during a build instead of several.

    • Reduced memory pressure: Similar to GCC, Clang reads PTH files via the use of memory mapping (i.e., mmap). Clang, however, memory maps PTH files as read-only, meaning that multiple -invocations of clang-cc can share the same pages in memory from a +invocations of clang -cc1 can share the same pages in memory from a memory-mapped PTH file. In comparison, GCC also memory maps its PCH files but also modifies those pages in memory, incurring the copy-on-write costs. The read-only nature of PTH can greatly reduce memory pressure for builds involving @@ -160,7 +160,7 @@ optimizations to speed up the processing of header files:

      • stat caching: PTH files cache information obtained via -calls to stat that clang-cc uses to resolve which files are +calls to stat that clang -cc1 uses to resolve which files are included by #include directives. This greatly reduces the overhead involved in context-switching to the kernel to resolve included files.

      • diff --git a/docs/UsersManual.html b/docs/UsersManual.html index cfaa071083bc..b5aa6a8dcd70 100644 --- a/docs/UsersManual.html +++ b/docs/UsersManual.html @@ -40,6 +40,7 @@ td {
      • Controlling Diagnostics via Pragmas
    • Precompiled Headers
    • +
    • Controlling Code Generation
  • C Language Features @@ -562,6 +563,29 @@ at the time of PCH use requires one of the PCH optimizations, stat() caching, to be disabled. However, this change is only likely to affect PCH files that reference a large number of headers.

    + +

    Controlling Code Generation

    + + +

    Clang provides a number of ways to control code generation. The options are listed below.

    + + +
    -fcatch-undefined-behavior: Turn +on runtime code generation to check for undefined behavior.
    + +
    This option, which defaults to off, controls whether or not Clang +adds runtime checks for undefined runtime behavior. If the check fails, +__builtin_trap() is used to indicate failure. +The checks are: +

    +

  • Subscripting where the static type of one operand is decayed from an + array type and the other operand is greater than the size of the array or + less than zero.
  • +
  • Shift operators where the amount shifted is greater or equal to the + promoted bit-width of the left-hand-side or less than zero.
  • +

    +
    +

    C Language Features

    diff --git a/docs/libIndex.html b/docs/libIndex.html index 5693de80a868..e722ee14d4a2 100644 --- a/docs/libIndex.html +++ b/docs/libIndex.html @@ -211,8 +211,8 @@ void bar_func(void) { You first get AST files out of t1.c and t2.c:
    -$ clang-cc -emit-pch t1.c -o t1.ast
    -$ clang-cc -emit-pch t2.c -o t2.ast
    +$ clang -emit-ast t1.c -o t1.ast
    +$ clang -emit-ast t2.c -o t2.ast
     

    diff --git a/include/clang-c/Index.h b/include/clang-c/Index.h index 85f7a6a31bcb..4e768097c402 100644 --- a/include/clang-c/Index.h +++ b/include/clang-c/Index.h @@ -104,6 +104,34 @@ enum CXCursorKind { CXCursor_LastInvalid = 72 }; +/** + * \brief Provides the contents of a file that has not yet been saved to disk. + * + * Each CXUnsavedFile instance provides the name of a file on the + * system along with the current contents of that file that have not + * yet been saved to disk. + */ +struct CXUnsavedFile { + /** + * \brief The file whose contents have not yet been saved. + * + * This file must already exist in the file system. + */ + const char *Filename; + + /** + * \brief A null-terminated buffer containing the unsaved contents + * of this file. + */ + const char *Contents; + + /** + * \brief The length of the unsaved contents of this buffer, not + * counting the NULL at the end of the buffer. + */ + unsigned long Length; +}; + /* A cursor into the CXTranslationUnit. */ typedef struct { @@ -174,8 +202,22 @@ CINDEX_LINKAGE void clang_disposeString(CXString string); */ CINDEX_LINKAGE CXIndex clang_createIndex(int excludeDeclarationsFromPCH, int displayDiagnostics); -CINDEX_LINKAGE void clang_disposeIndex(CXIndex); -CINDEX_LINKAGE CXString clang_getTranslationUnitSpelling(CXTranslationUnit CTUnit); +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. + * + * Note: This is for debugging purposes only, and may be removed at a later + * date. + * + * \param index - The index to update. + * \param value - The new flag value. + */ +CINDEX_LINKAGE void clang_setUseExternalASTGeneration(CXIndex index, + int value); /* * \brief Create a translation unit from an AST file (-emit-ast). @@ -183,6 +225,7 @@ CINDEX_LINKAGE CXString clang_getTranslationUnitSpelling(CXTranslationUnit CTUni CINDEX_LINKAGE CXTranslationUnit clang_createTranslationUnit( CXIndex, const char *ast_filename ); + /** * \brief Destroy the specified CXTranslationUnit object. */ @@ -192,20 +235,25 @@ CINDEX_LINKAGE void clang_disposeTranslationUnit(CXTranslationUnit); * \brief Return the CXTranslationUnit for a given source file and the provided * command line arguments one would pass to the compiler. * - * Note: The 'source_filename' argument is optional. If the caller provides a NULL pointer, - * the name of the source file is expected to reside in the specified command line arguments. + * Note: The 'source_filename' argument is optional. If the caller provides a + * NULL pointer, the name of the source file is expected to reside in the + * specified command line arguments. * - * Note: When encountered in 'clang_command_line_args', the following options are ignored: + * Note: When encountered in 'clang_command_line_args', the following options + * are ignored: * * '-c' * '-emit-ast' * '-fsyntax-only' * '-o ' (both '-o' and '' are ignored) * + * + * \param source_filename - The name of the source file to load, or NULL if the + * source file is included in clang_command_line_args. */ CINDEX_LINKAGE CXTranslationUnit clang_createTranslationUnitFromSourceFile( - CXIndex CIdx, - const char *source_filename /* specify NULL if the source file is in clang_command_line_args */, + CXIndex CIdx, + const char *source_filename, int num_clang_command_line_args, const char **clang_command_line_args ); @@ -225,13 +273,14 @@ CINDEX_LINKAGE CXTranslationUnit clang_createTranslationUnitFromSourceFile( } static void usage { clang_loadTranslationUnit(CXTranslationUnit, printObjCInterfaceNames); - } + } */ typedef void *CXClientData; typedef void (*CXTranslationUnitIterator)(CXTranslationUnit, CXCursor, CXClientData); -CINDEX_LINKAGE void clang_loadTranslationUnit(CXTranslationUnit, CXTranslationUnitIterator, - CXClientData); +CINDEX_LINKAGE void clang_loadTranslationUnit(CXTranslationUnit, + CXTranslationUnitIterator, + CXClientData); /* Usage: clang_loadDeclaration(). Will load the declaration, issuing a @@ -292,8 +341,9 @@ CINDEX_LINKAGE CXFile clang_getDeclSourceFile(CXDecl); Usage: clang_getCursor() will translate a source/line/column position into an AST cursor (to derive semantic information from the source code). */ -CINDEX_LINKAGE CXCursor clang_getCursor(CXTranslationUnit, const char *source_name, - unsigned line, unsigned column); +CINDEX_LINKAGE CXCursor clang_getCursor(CXTranslationUnit, + const char *source_name, + unsigned line, unsigned column); CINDEX_LINKAGE CXCursor clang_getNullCursor(void); @@ -606,11 +656,11 @@ clang_getNumCompletionChunks(CXCompletionString completion_string); * \param CIdx the \c CXIndex instance that will be used to perform code * completion. * - * \param source_filename the name of the source file that should be parsed - * to perform code-completion. This source file must be the same as or - * include the filename described by \p complete_filename, or no code-completion - * results will be produced. NOTE: One can also specify NULL for this argument if - * the source file is included in command_line_args. + * \param source_filename the name of the source file that should be parsed to + * perform code-completion. This source file must be the same as or include the + * filename described by \p complete_filename, or no code-completion results + * will be produced. NOTE: One can also specify NULL for this argument if the + * source file is included in command_line_args. * * \param num_command_line_args the number of command-line arguments stored in * \p command_line_args. @@ -621,6 +671,13 @@ clang_getNumCompletionChunks(CXCompletionString completion_string); * includes, etc., but should not include any information specific to * code completion. * + * \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. + * * \param complete_filename the name of the source file where code completion * should be performed. In many cases, this name will be the same as the * source filename. However, the completion filename may also be a file @@ -643,6 +700,8 @@ CINDEX_LINKAGE void clang_codeComplete(CXIndex CIdx, const char *source_filename, int num_command_line_args, const char **command_line_args, + unsigned num_unsaved_files, + struct CXUnsavedFile *unsaved_files, const char *complete_filename, unsigned complete_line, unsigned complete_column, diff --git a/include/clang/AST/ASTContext.h b/include/clang/AST/ASTContext.h index 4f29e5d8a618..3fc5aabde32c 100644 --- a/include/clang/AST/ASTContext.h +++ b/include/clang/AST/ASTContext.h @@ -45,6 +45,8 @@ namespace clang { class SourceManager; class TargetInfo; // Decls + class CXXMethodDecl; + class CXXRecordDecl; class Decl; class FieldDecl; class ObjCIvarDecl; @@ -57,6 +59,7 @@ namespace clang { class TypeDecl; class TypedefDecl; class UsingDecl; + class UsingShadowDecl; namespace Builtin { class Context; } @@ -105,6 +108,9 @@ class ASTContext { llvm::DenseMap ASTRecordLayouts; llvm::DenseMap ObjCLayouts; + /// KeyFunctions - A cache mapping from CXXRecordDecls to key functions. + llvm::DenseMap KeyFunctions; + /// \brief Mapping from ObjCContainers to their ObjCImplementations. llvm::DenseMap ObjCImpls; @@ -183,8 +189,10 @@ class ASTContext { llvm::DenseMap InstantiatedFromStaticDataMember; - /// \brief Keeps track of the UnresolvedUsingDecls from which UsingDecls - /// where created during instantiation. + /// \brief Keeps track of the declaration from which a UsingDecl was + /// created during instantiation. The source declaration is always + /// a UsingDecl, an UnresolvedUsingValueDecl, or an + /// UnresolvedUsingTypenameDecl. /// /// For example: /// \code @@ -203,8 +211,10 @@ class ASTContext { /// /// This mapping will contain an entry that maps from the UsingDecl in /// B to the UnresolvedUsingDecl in B. - llvm::DenseMap - InstantiatedFromUnresolvedUsingDecl; + llvm::DenseMap InstantiatedFromUsingDecl; + + llvm::DenseMap + InstantiatedFromUsingShadowDecl; llvm::DenseMap InstantiatedFromUnnamedFieldDecl; @@ -282,14 +292,18 @@ class ASTContext { void setInstantiatedFromStaticDataMember(VarDecl *Inst, VarDecl *Tmpl, TemplateSpecializationKind TSK); - /// \brief If this using decl is instantiated from an unresolved using decl, + /// \brief If the given using decl is an instantiation of a + /// (possibly unresolved) using decl from a template instantiation, /// return it. - NamedDecl *getInstantiatedFromUnresolvedUsingDecl(UsingDecl *UUD); + NamedDecl *getInstantiatedFromUsingDecl(UsingDecl *Inst); - /// \brief Note that the using decl \p Inst is an instantiation of - /// the unresolved using decl \p Tmpl of a class template. - void setInstantiatedFromUnresolvedUsingDecl(UsingDecl *Inst, NamedDecl *Tmpl); + /// \brief Remember that the using decl \p Inst is an instantiation + /// of the using decl \p Pattern of a class template. + void setInstantiatedFromUsingDecl(UsingDecl *Inst, NamedDecl *Pattern); + void setInstantiatedFromUsingShadowDecl(UsingShadowDecl *Inst, + UsingShadowDecl *Pattern); + UsingShadowDecl *getInstantiatedFromUsingShadowDecl(UsingShadowDecl *Inst); FieldDecl *getInstantiatedFromUnnamedFieldDecl(FieldDecl *Field); @@ -380,9 +394,10 @@ class ASTContext { /// equivalent to calling T.withConst(). QualType getConstType(QualType T) { return T.withConst(); } - /// getNoReturnType - Add the noreturn attribute to the given type which must - /// be a FunctionType or a pointer to an allowable type or a BlockPointer. - QualType getNoReturnType(QualType T); + /// getNoReturnType - Add or remove the noreturn attribute to the given type + /// which must be a FunctionType or a pointer to an allowable type or a + /// BlockPointer. + QualType getNoReturnType(QualType T, bool AddNoReturn = true); /// getComplexType - Return the uniqued reference to the type for a complex /// number with the specified element type. @@ -569,7 +584,7 @@ class ASTContext { /// getSizeType - Return the unique type for "size_t" (C99 7.17), defined /// in . The sizeof operator requires this (C99 6.5.3.4p4). - QualType getSizeType() const; + CanQualType getSizeType() const; /// getWCharType - In C++, this returns the unique wchar_t type. In C99, this /// returns a type compatible with the type defined in as defined @@ -735,12 +750,12 @@ class ASTContext { DeclarationName getNameForTemplate(TemplateName Name); + TemplateName getOverloadedTemplateName(NamedDecl * const *Begin, + NamedDecl * const *End); + TemplateName getQualifiedTemplateName(NestedNameSpecifier *NNS, bool TemplateKeyword, TemplateDecl *Template); - TemplateName getQualifiedTemplateName(NestedNameSpecifier *NNS, - bool TemplateKeyword, - OverloadedFunctionDecl *Template); TemplateName getDependentTemplateName(NestedNameSpecifier *NNS, const IdentifierInfo *Name); @@ -843,6 +858,13 @@ class ASTContext { const ASTRecordLayout & getASTObjCImplementationLayout(const ObjCImplementationDecl *D); + /// getKeyFunction - Get the key function for the given record decl. + /// The key function is, according to the Itanium C++ ABI section 5.2.3: + /// + /// ...the first non-pure virtual function that is not inline at the point + /// of class definition. + const CXXMethodDecl *getKeyFunction(const CXXRecordDecl *RD); + void CollectObjCIvars(const ObjCInterfaceDecl *OI, llvm::SmallVectorImpl &Fields); @@ -1108,9 +1130,9 @@ class ASTContext { void setObjCImplementation(ObjCCategoryDecl *CatD, ObjCCategoryImplDecl *ImplD); - /// \brief Allocate an uninitialized DeclaratorInfo. + /// \brief Allocate an uninitialized TypeSourceInfo. /// - /// The caller should initialize the memory held by DeclaratorInfo using + /// The caller should initialize the memory held by TypeSourceInfo using /// the TypeLoc wrappers. /// /// \param T the type that will be the basis for type source info. This type @@ -1119,13 +1141,13 @@ class ASTContext { /// /// \param Size the size of the type info to create, or 0 if the size /// should be calculated based on the type. - DeclaratorInfo *CreateDeclaratorInfo(QualType T, unsigned Size = 0); + TypeSourceInfo *CreateTypeSourceInfo(QualType T, unsigned Size = 0); - /// \brief Allocate a DeclaratorInfo where all locations have been + /// \brief Allocate a TypeSourceInfo where all locations have been /// initialized to a given location, which defaults to the empty /// location. - DeclaratorInfo * - getTrivialDeclaratorInfo(QualType T, SourceLocation Loc = SourceLocation()); + TypeSourceInfo * + getTrivialTypeSourceInfo(QualType T, SourceLocation Loc = SourceLocation()); private: ASTContext(const ASTContext&); // DO NOT IMPLEMENT diff --git a/include/clang/AST/CanonicalType.h b/include/clang/AST/CanonicalType.h index 9b1187770f6a..af8d23692e19 100644 --- a/include/clang/AST/CanonicalType.h +++ b/include/clang/AST/CanonicalType.h @@ -172,6 +172,12 @@ inline bool operator!=(CanQual x, CanQual y) { /// \brief Represents a canonical, potentially-qualified type. typedef CanQual CanQualType; +inline const DiagnosticBuilder &operator<<(const DiagnosticBuilder &DB, + CanQualType T) { + DB << static_cast(T); + return DB; +} + //----------------------------------------------------------------------------// // Internal proxy classes used by canonical types //----------------------------------------------------------------------------// diff --git a/include/clang/AST/Decl.h b/include/clang/AST/Decl.h index f7944771efce..ff2b30227860 100644 --- a/include/clang/AST/Decl.h +++ b/include/clang/AST/Decl.h @@ -35,17 +35,17 @@ class TypeLoc; /// /// A client can read the relevant info using TypeLoc wrappers, e.g: /// @code -/// TypeLoc TL = DeclaratorInfo->getTypeLoc(); +/// TypeLoc TL = TypeSourceInfo->getTypeLoc(); /// if (PointerLoc *PL = dyn_cast(&TL)) /// PL->getStarLoc().print(OS, SrcMgr); /// @endcode /// -class DeclaratorInfo { +class TypeSourceInfo { QualType Ty; // Contains a memory block after the class, used for type source information, // allocated by ASTContext. friend class ASTContext; - DeclaratorInfo(QualType ty) : Ty(ty) { } + TypeSourceInfo(QualType ty) : Ty(ty) { } public: /// \brief Return the type wrapped by this type source info. QualType getType() const { return Ty; } @@ -322,18 +322,18 @@ class ValueDecl : public NamedDecl { }; /// \brief Represents a ValueDecl that came out of a declarator. -/// Contains type source information through DeclaratorInfo. +/// Contains type source information through TypeSourceInfo. class DeclaratorDecl : public ValueDecl { - DeclaratorInfo *DeclInfo; + TypeSourceInfo *DeclInfo; protected: DeclaratorDecl(Kind DK, DeclContext *DC, SourceLocation L, - DeclarationName N, QualType T, DeclaratorInfo *DInfo) - : ValueDecl(DK, DC, L, N, T), DeclInfo(DInfo) {} + DeclarationName N, QualType T, TypeSourceInfo *TInfo) + : ValueDecl(DK, DC, L, N, T), DeclInfo(TInfo) {} public: - DeclaratorInfo *getDeclaratorInfo() const { return DeclInfo; } - void setDeclaratorInfo(DeclaratorInfo *DInfo) { DeclInfo = DInfo; } + TypeSourceInfo *getTypeSourceInfo() const { return DeclInfo; } + void setTypeSourceInfo(TypeSourceInfo *TInfo) { DeclInfo = TInfo; } SourceLocation getTypeSpecStartLoc() const; @@ -348,15 +348,23 @@ class DeclaratorDecl : public ValueDecl { /// which it was evaluated (if any), and whether or not the statement /// is an integral constant expression (if known). struct EvaluatedStmt { - EvaluatedStmt() : WasEvaluated(false), CheckedICE(false), IsICE(false) { } + EvaluatedStmt() : WasEvaluated(false), IsEvaluating(false), CheckedICE(false), + CheckingICE(false), IsICE(false) { } /// \brief Whether this statement was already evaluated. bool WasEvaluated : 1; + /// \brief Whether this statement is being evaluated. + bool IsEvaluating : 1; + /// \brief Whether we already checked whether this statement was an /// integral constant expression. bool CheckedICE : 1; + /// \brief Whether we are checking whether this statement is an + /// integral constant expression. + bool CheckingICE : 1; + /// \brief Whether this statement is an integral constant /// expression. Only valid if CheckedICE is true. bool IsICE : 1; @@ -432,8 +440,8 @@ class VarDecl : public DeclaratorDecl, public Redeclarable { friend class StmtIteratorBase; protected: VarDecl(Kind DK, DeclContext *DC, SourceLocation L, IdentifierInfo *Id, - QualType T, DeclaratorInfo *DInfo, StorageClass SC) - : DeclaratorDecl(DK, DC, L, Id, T, DInfo), Init(), + QualType T, TypeSourceInfo *TInfo, StorageClass SC) + : DeclaratorDecl(DK, DC, L, Id, T, TInfo), Init(), ThreadSpecified(false), HasCXXDirectInit(false), DeclaredInCondition(false) { SClass = SC; @@ -453,7 +461,7 @@ class VarDecl : public DeclaratorDecl, public Redeclarable { static VarDecl *Create(ASTContext &C, DeclContext *DC, SourceLocation L, IdentifierInfo *Id, - QualType T, DeclaratorInfo *DInfo, StorageClass S); + QualType T, TypeSourceInfo *TInfo, StorageClass S); virtual ~VarDecl(); virtual void Destroy(ASTContext& C); @@ -504,23 +512,45 @@ class VarDecl : public DeclaratorDecl, public Redeclarable { void setInit(ASTContext &C, Expr *I); - /// \brief Note that constant evaluation has computed the given - /// value for this variable's initializer. - void setEvaluatedValue(ASTContext &C, const APValue &Value) const { + EvaluatedStmt *EnsureEvaluatedStmt() const { EvaluatedStmt *Eval = Init.dyn_cast(); if (!Eval) { Stmt *S = Init.get(); - Eval = new (C) EvaluatedStmt; + Eval = new (getASTContext()) EvaluatedStmt; Eval->Value = S; Init = Eval; } + return Eval; + } + /// \brief Check whether we are in the process of checking whether the + /// initializer can be evaluated. + bool isEvaluatingValue() const { + if (EvaluatedStmt *Eval = Init.dyn_cast()) + return Eval->IsEvaluating; + + return false; + } + + /// \brief Note that we now are checking whether the initializer can be + /// evaluated. + void setEvaluatingValue() const { + EvaluatedStmt *Eval = EnsureEvaluatedStmt(); + Eval->IsEvaluating = true; + } + + /// \brief Note that constant evaluation has computed the given + /// value for this variable's initializer. + void setEvaluatedValue(const APValue &Value) const { + EvaluatedStmt *Eval = EnsureEvaluatedStmt(); + Eval->IsEvaluating = false; Eval->WasEvaluated = true; Eval->Evaluated = Value; } /// \brief Return the already-evaluated value of this variable's - /// initializer, or NULL if the value is not yet known. + /// initializer, or NULL if the value is not yet known. Returns pointer + /// to untyped APValue if the value could not be evaluated. APValue *getEvaluatedValue() const { if (EvaluatedStmt *Eval = Init.dyn_cast()) if (Eval->WasEvaluated) @@ -548,17 +578,27 @@ class VarDecl : public DeclaratorDecl, public Redeclarable { return Init.get()->IsICE; } + /// \brief Check whether we are in the process of checking the initializer + /// is an integral constant expression. + bool isCheckingICE() const { + if (EvaluatedStmt *Eval = Init.dyn_cast()) + return Eval->CheckingICE; + + return false; + } + + /// \brief Note that we now are checking whether the initializer is an + /// integral constant expression. + void setCheckingICE() const { + EvaluatedStmt *Eval = EnsureEvaluatedStmt(); + Eval->CheckingICE = true; + } + /// \brief Note that we now know whether the initializer is an /// integral constant expression. - void setInitKnownICE(ASTContext &C, bool IsICE) const { - EvaluatedStmt *Eval = Init.dyn_cast(); - if (!Eval) { - Stmt *S = Init.get(); - Eval = new (C) EvaluatedStmt; - Eval->Value = S; - Init = Eval; - } - + void setInitKnownICE(bool IsICE) const { + EvaluatedStmt *Eval = EnsureEvaluatedStmt(); + Eval->CheckingICE = false; Eval->CheckedICE = true; Eval->IsICE = IsICE; } @@ -712,7 +752,7 @@ class ImplicitParamDecl : public VarDecl { protected: ImplicitParamDecl(Kind DK, DeclContext *DC, SourceLocation L, IdentifierInfo *Id, QualType Tw) - : VarDecl(DK, DC, L, Id, Tw, /*DInfo=*/0, VarDecl::None) {} + : VarDecl(DK, DC, L, Id, Tw, /*TInfo=*/0, VarDecl::None) {} public: static ImplicitParamDecl *Create(ASTContext &C, DeclContext *DC, SourceLocation L, IdentifierInfo *Id, @@ -739,16 +779,16 @@ class ParmVarDecl : public VarDecl { protected: ParmVarDecl(Kind DK, DeclContext *DC, SourceLocation L, - IdentifierInfo *Id, QualType T, DeclaratorInfo *DInfo, + IdentifierInfo *Id, QualType T, TypeSourceInfo *TInfo, StorageClass S, Expr *DefArg) - : VarDecl(DK, DC, L, Id, T, DInfo, S), objcDeclQualifier(OBJC_TQ_None) { + : VarDecl(DK, DC, L, Id, T, TInfo, S), objcDeclQualifier(OBJC_TQ_None) { setDefaultArg(DefArg); } public: static ParmVarDecl *Create(ASTContext &C, DeclContext *DC, SourceLocation L,IdentifierInfo *Id, - QualType T, DeclaratorInfo *DInfo, + QualType T, TypeSourceInfo *TInfo, StorageClass S, Expr *DefArg); ObjCDeclQualifier getObjCDeclQualifier() const { @@ -822,8 +862,8 @@ class ParmVarDecl : public VarDecl { } QualType getOriginalType() const { - if (getDeclaratorInfo()) - return getDeclaratorInfo()->getType(); + if (getTypeSourceInfo()) + return getTypeSourceInfo()->getType(); return getType(); } @@ -907,9 +947,9 @@ class FunctionDecl : public DeclaratorDecl, public DeclContext, protected: FunctionDecl(Kind DK, DeclContext *DC, SourceLocation L, - DeclarationName N, QualType T, DeclaratorInfo *DInfo, + DeclarationName N, QualType T, TypeSourceInfo *TInfo, StorageClass S, bool isInline) - : DeclaratorDecl(DK, DC, L, N, T, DInfo), + : DeclaratorDecl(DK, DC, L, N, T, TInfo), DeclContext(DK), ParamInfo(0), Body(), SClass(S), IsInline(isInline), @@ -936,7 +976,7 @@ class FunctionDecl : public DeclaratorDecl, public DeclContext, static FunctionDecl *Create(ASTContext &C, DeclContext *DC, SourceLocation L, DeclarationName N, QualType T, - DeclaratorInfo *DInfo, + TypeSourceInfo *TInfo, StorageClass S = None, bool isInline = false, bool hasWrittenPrototype = true); @@ -1272,15 +1312,15 @@ class FieldDecl : public DeclaratorDecl { Expr *BitWidth; protected: FieldDecl(Kind DK, DeclContext *DC, SourceLocation L, - IdentifierInfo *Id, QualType T, DeclaratorInfo *DInfo, + IdentifierInfo *Id, QualType T, TypeSourceInfo *TInfo, Expr *BW, bool Mutable) - : DeclaratorDecl(DK, DC, L, Id, T, DInfo), Mutable(Mutable), BitWidth(BW) { + : DeclaratorDecl(DK, DC, L, Id, T, TInfo), Mutable(Mutable), BitWidth(BW) { } public: static FieldDecl *Create(ASTContext &C, DeclContext *DC, SourceLocation L, IdentifierInfo *Id, QualType T, - DeclaratorInfo *DInfo, Expr *BW, bool Mutable); + TypeSourceInfo *TInfo, Expr *BW, bool Mutable); /// isMutable - Determines whether this field is mutable (C++ only). bool isMutable() const { return Mutable; } @@ -1383,28 +1423,28 @@ class TypeDecl : public NamedDecl { class TypedefDecl : public TypeDecl { /// UnderlyingType - This is the type the typedef is set to. - DeclaratorInfo *DInfo; + TypeSourceInfo *TInfo; TypedefDecl(DeclContext *DC, SourceLocation L, - IdentifierInfo *Id, DeclaratorInfo *DInfo) - : TypeDecl(Typedef, DC, L, Id), DInfo(DInfo) {} + IdentifierInfo *Id, TypeSourceInfo *TInfo) + : TypeDecl(Typedef, DC, L, Id), TInfo(TInfo) {} virtual ~TypedefDecl() {} public: static TypedefDecl *Create(ASTContext &C, DeclContext *DC, SourceLocation L, IdentifierInfo *Id, - DeclaratorInfo *DInfo); + TypeSourceInfo *TInfo); - DeclaratorInfo *getTypeDeclaratorInfo() const { - return DInfo; + TypeSourceInfo *getTypeSourceInfo() const { + return TInfo; } QualType getUnderlyingType() const { - return DInfo->getType(); + return TInfo->getType(); } - void setTypeDeclaratorInfo(DeclaratorInfo *newType) { - DInfo = newType; + void setTypeSourceInfo(TypeSourceInfo *newType) { + TInfo = newType; } // Implement isa/cast/dyncast/etc. @@ -1554,6 +1594,12 @@ class EnumDecl : public TagDecl { /// have a different type than this does. QualType IntegerType; + /// PromotionType - The integer type that values of this type should + /// promote to. In C, enumerators are generally of an integer type + /// directly, but gcc-style large enumerators (and all enumerators + /// in C++) are of the enum type instead. + QualType PromotionType; + /// \brief If the enumeration was instantiated from an enumeration /// within a class or function template, this pointer refers to the /// enumeration declared within the template. @@ -1583,7 +1629,8 @@ class EnumDecl : public TagDecl { /// declaration as being defined; it's enumerators have already been /// added (via DeclContext::addDecl). NewType is the new underlying /// type of the enumeration type. - void completeDefinition(ASTContext &C, QualType NewType); + void completeDefinition(ASTContext &C, QualType NewType, + QualType PromotionType); // enumerator_iterator - Iterates through the enumerators of this // enumeration. @@ -1597,6 +1644,13 @@ class EnumDecl : public TagDecl { return enumerator_iterator(this->decls_end()); } + /// getPromotionType - Return the integer type that enumerators + /// should promote to. + QualType getPromotionType() const { return PromotionType; } + + /// \brief Set the promotion type. + void setPromotionType(QualType T) { PromotionType = T; } + /// getIntegerType - Return the integer type this enum decl corresponds to. /// This returns a null qualtype for an enum forward definition. QualType getIntegerType() const { return IntegerType; } diff --git a/include/clang/AST/DeclBase.h b/include/clang/AST/DeclBase.h index e1f948fdd550..497f86347a86 100644 --- a/include/clang/AST/DeclBase.h +++ b/include/clang/AST/DeclBase.h @@ -91,7 +91,7 @@ class Decl { IDNS_Ordinary = 0x8, IDNS_ObjCProtocol = 0x10, IDNS_ObjCImplementation = 0x20, - IDNS_ObjCCategoryImpl = 0x40, + IDNS_ObjCCategoryName = 0x40, IDNS_OrdinaryFriend = 0x80, IDNS_TagFriend = 0x100, IDNS_Using = 0x200 @@ -916,6 +916,9 @@ class DeclContext { /// only happens with friends. void addHiddenDecl(Decl *D); + /// @brief Removes a declaration from this context. + void removeDecl(Decl *D); + /// lookup_iterator - An iterator that provides access to the results /// of looking up a name within this context. typedef NamedDecl **lookup_iterator; @@ -1003,6 +1006,8 @@ class DeclContext { static bool classof(const Name##Decl *D) { return true; } #include "clang/AST/DeclNodes.def" + void dumpDeclContext() const; + private: void LoadLexicalDeclsFromExternalStorage() const; void LoadVisibleDeclsFromExternalStorage() const; diff --git a/include/clang/AST/DeclCXX.h b/include/clang/AST/DeclCXX.h index 990403e7dc2e..5507e99e45a9 100644 --- a/include/clang/AST/DeclCXX.h +++ b/include/clang/AST/DeclCXX.h @@ -88,108 +88,6 @@ namespace llvm { namespace clang { -/// OverloadedFunctionDecl - An instance of this class represents a -/// set of overloaded functions. All of the functions have the same -/// name and occur within the same scope. -/// -/// An OverloadedFunctionDecl has no ownership over the FunctionDecl -/// nodes it contains. Rather, the FunctionDecls are owned by the -/// enclosing scope (which also owns the OverloadedFunctionDecl -/// node). OverloadedFunctionDecl is used primarily to store a set of -/// overloaded functions for name lookup. -class OverloadedFunctionDecl : public NamedDecl { -protected: - OverloadedFunctionDecl(DeclContext *DC, DeclarationName N) - : NamedDecl(OverloadedFunction, DC, SourceLocation(), N) { } - - /// Functions - the set of overloaded functions contained in this - /// overload set. - llvm::SmallVector Functions; - - // FIXME: This should go away when we stop using - // OverloadedFunctionDecl to store conversions in CXXRecordDecl. - friend class CXXRecordDecl; - -public: - typedef llvm::SmallVector::iterator function_iterator; - typedef llvm::SmallVector::const_iterator - function_const_iterator; - - static OverloadedFunctionDecl *Create(ASTContext &C, DeclContext *DC, - DeclarationName N); - - /// \brief Add a new overloaded function or function template to the set - /// of overloaded function templates. - void addOverload(AnyFunctionDecl F); - - function_iterator function_begin() { return Functions.begin(); } - function_iterator function_end() { return Functions.end(); } - function_const_iterator function_begin() const { return Functions.begin(); } - function_const_iterator function_end() const { return Functions.end(); } - - /// \brief Returns the number of overloaded functions stored in - /// this set. - unsigned size() const { return Functions.size(); } - - // Implement isa/cast/dyncast/etc. - static bool classof(const Decl *D) { - return D->getKind() == OverloadedFunction; - } - static bool classof(const OverloadedFunctionDecl *D) { return true; } -}; - -/// \brief Provides uniform iteration syntax for an overload set, function, -/// or function template. -class OverloadIterator { - /// \brief An overloaded function set, function declaration, or - /// function template declaration. - NamedDecl *D; - - /// \brief If the declaration is an overloaded function set, this is the - /// iterator pointing to the current position within that overloaded - /// function set. - OverloadedFunctionDecl::function_iterator Iter; - -public: - typedef AnyFunctionDecl value_type; - typedef value_type reference; - typedef NamedDecl *pointer; - typedef int difference_type; - typedef std::forward_iterator_tag iterator_category; - - OverloadIterator() : D(0) { } - - OverloadIterator(FunctionDecl *FD) : D(FD) { } - OverloadIterator(FunctionTemplateDecl *FTD) - : D(reinterpret_cast(FTD)) { } - OverloadIterator(OverloadedFunctionDecl *Ovl) - : D(Ovl), Iter(Ovl->function_begin()) { } - - OverloadIterator(NamedDecl *ND); - - reference operator*() const; - - pointer operator->() const { return (**this).get(); } - - OverloadIterator &operator++(); - - OverloadIterator operator++(int) { - OverloadIterator Temp(*this); - ++(*this); - return Temp; - } - - bool Equals(const OverloadIterator &Other) const; -}; - -inline bool operator==(const OverloadIterator &X, const OverloadIterator &Y) { - return X.Equals(Y); -} - -inline bool operator!=(const OverloadIterator &X, const OverloadIterator &Y) { - return !(X == Y); -} - /// CXXBaseSpecifier - A base class of a C++ class. /// /// Each CXXBaseSpecifier represents a single, direct base class (or @@ -210,6 +108,7 @@ class CXXBaseSpecifier { /// Range - The source code range that covers the full base /// specifier, including the "virtual" (if present) and access /// specifier (if present). + // FIXME: Move over to a TypeLoc! SourceRange Range; /// Virtual - Whether this is a virtual base class or not. @@ -635,6 +534,10 @@ class CXXRecordDecl : public RecordDecl { /// [dcl.init.aggr]). void setAggregate(bool Agg) { Aggregate = Agg; } + /// setMethodAsVirtual - Make input method virtual and set the necesssary + /// special function bits and other bits accordingly. + void setMethodAsVirtual(FunctionDecl *Method); + /// isPOD - Whether this class is a POD-type (C++ [class]p4), which is a class /// that is an aggregate that has no non-static non-POD data members, no /// reference data members, no user-defined copy assignment operator and no @@ -753,7 +656,7 @@ class CXXRecordDecl : public RecordDecl { /// \brief Determine whether this particular class is a specialization or /// instantiation of a class template or member class of a class template, /// and how it was instantiated or specialized. - TemplateSpecializationKind getTemplateSpecializationKind(); + TemplateSpecializationKind getTemplateSpecializationKind() const; /// \brief Set the kind of specialization or template instantiation this is. void setTemplateSpecializationKind(TemplateSpecializationKind TSK); @@ -762,7 +665,7 @@ class CXXRecordDecl : public RecordDecl { CXXConstructorDecl *getDefaultConstructor(ASTContext &Context); /// getDestructor - Returns the destructor decl for this class. - const CXXDestructorDecl *getDestructor(ASTContext &Context); + CXXDestructorDecl *getDestructor(ASTContext &Context); /// isLocalClass - If the class is a local class [class.local], returns /// the enclosing function declaration. @@ -802,6 +705,30 @@ class CXXRecordDecl : public RecordDecl { /// \todo add a separate paramaeter to configure IsDerivedFrom, rather than /// tangling input and output in \p Paths bool isDerivedFrom(CXXRecordDecl *Base, CXXBasePaths &Paths) const; + + /// \brief Determine whether this class is provably not derived from + /// the type \p Base. + bool isProvablyNotDerivedFrom(const CXXRecordDecl *Base) const; + + /// \brief Function type used by forallBases() as a callback. + /// + /// \param Base the definition of the base class + /// + /// \returns true if this base matched the search criteria + typedef bool ForallBasesCallback(const CXXRecordDecl *BaseDefinition, + void *UserData); + + /// \brief Determines if the given callback holds for all the direct + /// or indirect base classes of this type. + /// + /// The class itself does not count as a base class. This routine + /// returns false if the class has non-computable base classes. + /// + /// \param AllowShortCircuit if false, forces the callback to be called + /// for every base class, even if a dependent or non-matching base was + /// found. + bool forallBases(ForallBasesCallback *BaseMatches, void *UserData, + bool AllowShortCircuit = true) const; /// \brief Function type used by lookupInBases() to determine whether a /// specific base class subobject matches the lookup criteria. @@ -902,15 +829,15 @@ class CXXRecordDecl : public RecordDecl { class CXXMethodDecl : public FunctionDecl { protected: CXXMethodDecl(Kind DK, CXXRecordDecl *RD, SourceLocation L, - DeclarationName N, QualType T, DeclaratorInfo *DInfo, + DeclarationName N, QualType T, TypeSourceInfo *TInfo, bool isStatic, bool isInline) - : FunctionDecl(DK, RD, L, N, T, DInfo, (isStatic ? Static : None), + : FunctionDecl(DK, RD, L, N, T, TInfo, (isStatic ? Static : None), isInline) {} public: static CXXMethodDecl *Create(ASTContext &C, CXXRecordDecl *RD, SourceLocation L, DeclarationName N, - QualType T, DeclaratorInfo *DInfo, + QualType T, TypeSourceInfo *TInfo, bool isStatic = false, bool isInline = false); @@ -968,6 +895,8 @@ class CXXMethodDecl : public FunctionDecl { return getType()->getAs()->getTypeQuals(); } + bool hasInlineBody() const; + // Implement isa/cast/dyncast/etc. static bool classof(const Decl *D) { return D->getKind() >= CXXMethod && D->getKind() <= CXXConversion; @@ -990,12 +919,13 @@ class CXXMethodDecl : public FunctionDecl { /// }; /// @endcode class CXXBaseOrMemberInitializer { - /// BaseOrMember - This points to the entity being initialized, - /// which is either a base class (a Type) or a non-static data - /// member. When the low bit is 1, it's a base - /// class; when the low bit is 0, it's a member. - uintptr_t BaseOrMember; - + /// \brief Either the base class name (stored as a TypeSourceInfo*) or the + /// field being initialized. + llvm::PointerUnion BaseOrMember; + + /// \brief The source location for the field name. + SourceLocation MemberLocation; + /// Args - The arguments used to initialize the base or member. Stmt **Args; unsigned NumArgs; @@ -1020,8 +950,8 @@ class CXXBaseOrMemberInitializer { /// and AnonUnionMember holds field decl for au_i1. llvm::PointerUnion CtorOrAnonUnion; - /// IdLoc - Location of the id in ctor-initializer list. - SourceLocation IdLoc; + /// LParenLoc - Location of the left paren of the ctor-initializer. + SourceLocation LParenLoc; /// RParenLoc - Location of the right paren of the ctor-initializer. SourceLocation RParenLoc; @@ -1029,18 +959,22 @@ class CXXBaseOrMemberInitializer { public: /// CXXBaseOrMemberInitializer - Creates a new base-class initializer. explicit - CXXBaseOrMemberInitializer(QualType BaseType, Expr **Args, unsigned NumArgs, - CXXConstructorDecl *C, - SourceLocation L, SourceLocation R); + CXXBaseOrMemberInitializer(ASTContext &Context, + TypeSourceInfo *TInfo, CXXConstructorDecl *C, + SourceLocation L, + Expr **Args, unsigned NumArgs, + SourceLocation R); /// CXXBaseOrMemberInitializer - Creates a new member initializer. explicit - CXXBaseOrMemberInitializer(FieldDecl *Member, Expr **Args, unsigned NumArgs, - CXXConstructorDecl *C, - SourceLocation L, SourceLocation R); + CXXBaseOrMemberInitializer(ASTContext &Context, + FieldDecl *Member, SourceLocation MemberLoc, + CXXConstructorDecl *C, SourceLocation L, + Expr **Args, unsigned NumArgs, + SourceLocation R); - /// ~CXXBaseOrMemberInitializer - Destroy the base or member initializer. - ~CXXBaseOrMemberInitializer(); + /// \brief Destroy the base or member initializer. + void Destroy(ASTContext &Context); /// arg_iterator - Iterates through the member initialization /// arguments. @@ -1050,54 +984,54 @@ class CXXBaseOrMemberInitializer { /// arguments. typedef ConstExprIterator const_arg_iterator; - /// getBaseOrMember - get the generic 'member' representing either the field - /// or a base class. - void* getBaseOrMember() const { return reinterpret_cast(BaseOrMember); } - /// isBaseInitializer - Returns true when this initializer is /// initializing a base class. - bool isBaseInitializer() const { return (BaseOrMember & 0x1) != 0; } + bool isBaseInitializer() const { return BaseOrMember.is(); } /// isMemberInitializer - Returns true when this initializer is /// initializing a non-static data member. - bool isMemberInitializer() const { return (BaseOrMember & 0x1) == 0; } + bool isMemberInitializer() const { return BaseOrMember.is(); } - /// getBaseClass - If this is a base class initializer, returns the - /// type used to specify the initializer. The resulting type will be - /// a class type or a typedef of a class type. If this is not a base - /// class initializer, returns NULL. - Type *getBaseClass() { - if (isBaseInitializer()) - return reinterpret_cast(BaseOrMember & ~0x01); - else - return 0; + /// If this is a base class initializer, returns the type of the + /// base class with location information. Otherwise, returns an NULL + /// type location. + TypeLoc getBaseClassLoc() const; + + /// If this is a base class initializer, returns the type of the base class. + /// Otherwise, returns NULL. + const Type *getBaseClass() const; + Type *getBaseClass(); + + /// \brief Returns the declarator information for a base class initializer. + TypeSourceInfo *getBaseClassInfo() const { + return BaseOrMember.dyn_cast(); } - - /// getBaseClass - If this is a base class initializer, returns the - /// type used to specify the initializer. The resulting type will be - /// a class type or a typedef of a class type. If this is not a base - /// class initializer, returns NULL. - const Type *getBaseClass() const { - if (isBaseInitializer()) - return reinterpret_cast(BaseOrMember & ~0x01); - else - return 0; - } - + /// getMember - If this is a member initializer, returns the /// declaration of the non-static data member being /// initialized. Otherwise, returns NULL. FieldDecl *getMember() { if (isMemberInitializer()) - return reinterpret_cast(BaseOrMember); + return BaseOrMember.get(); else return 0; } - void setMember(FieldDecl * anonUnionField) { - BaseOrMember = reinterpret_cast(anonUnionField); + SourceLocation getMemberLocation() const { + return MemberLocation; } + void setMember(FieldDecl *Member) { + assert(isMemberInitializer()); + BaseOrMember = Member; + } + + /// \brief Determine the source location of the initializer. + SourceLocation getSourceLocation() const; + + /// \brief Determine the source range covering the entire initializer. + SourceRange getSourceRange() const; + FieldDecl *getAnonUnionMember() const { return CtorOrAnonUnion.dyn_cast(); } @@ -1109,7 +1043,7 @@ class CXXBaseOrMemberInitializer { return CtorOrAnonUnion.dyn_cast(); } - SourceLocation getSourceLocation() const { return IdLoc; } + SourceLocation getLParenLoc() const { return LParenLoc; } SourceLocation getRParenLoc() const { return RParenLoc; } /// arg_begin() - Retrieve an iterator to the first initializer argument. @@ -1155,9 +1089,9 @@ class CXXConstructorDecl : public CXXMethodDecl { unsigned NumBaseOrMemberInitializers; CXXConstructorDecl(CXXRecordDecl *RD, SourceLocation L, - DeclarationName N, QualType T, DeclaratorInfo *DInfo, + DeclarationName N, QualType T, TypeSourceInfo *TInfo, bool isExplicit, bool isInline, bool isImplicitlyDeclared) - : CXXMethodDecl(CXXConstructor, RD, L, N, T, DInfo, false, isInline), + : CXXMethodDecl(CXXConstructor, RD, L, N, T, TInfo, false, isInline), Explicit(isExplicit), ImplicitlyDefined(false), BaseOrMemberInitializers(0), NumBaseOrMemberInitializers(0) { setImplicit(isImplicitlyDeclared); @@ -1167,7 +1101,7 @@ class CXXConstructorDecl : public CXXMethodDecl { public: static CXXConstructorDecl *Create(ASTContext &C, CXXRecordDecl *RD, SourceLocation L, DeclarationName N, - QualType T, DeclaratorInfo *DInfo, + QualType T, TypeSourceInfo *TInfo, bool isExplicit, bool isInline, bool isImplicitlyDeclared); @@ -1294,7 +1228,7 @@ class CXXDestructorDecl : public CXXMethodDecl { CXXDestructorDecl(CXXRecordDecl *RD, SourceLocation L, DeclarationName N, QualType T, bool isInline, bool isImplicitlyDeclared) - : CXXMethodDecl(CXXDestructor, RD, L, N, T, /*DInfo=*/0, false, isInline), + : CXXMethodDecl(CXXDestructor, RD, L, N, T, /*TInfo=*/0, false, isInline), ImplicitlyDefined(false), OperatorDelete(0) { setImplicit(isImplicitlyDeclared); } @@ -1349,15 +1283,15 @@ class CXXConversionDecl : public CXXMethodDecl { bool Explicit : 1; CXXConversionDecl(CXXRecordDecl *RD, SourceLocation L, - DeclarationName N, QualType T, DeclaratorInfo *DInfo, + DeclarationName N, QualType T, TypeSourceInfo *TInfo, bool isInline, bool isExplicit) - : CXXMethodDecl(CXXConversion, RD, L, N, T, DInfo, false, isInline), + : CXXMethodDecl(CXXConversion, RD, L, N, T, TInfo, false, isInline), Explicit(isExplicit) { } public: static CXXConversionDecl *Create(ASTContext &C, CXXRecordDecl *RD, SourceLocation L, DeclarationName N, - QualType T, DeclaratorInfo *DInfo, + QualType T, TypeSourceInfo *TInfo, bool isInline, bool isExplicit); /// isExplicit - Whether this is an explicit conversion operator diff --git a/include/clang/AST/DeclContextInternals.h b/include/clang/AST/DeclContextInternals.h index c2b48cee36f4..32405ee81260 100644 --- a/include/clang/AST/DeclContextInternals.h +++ b/include/clang/AST/DeclContextInternals.h @@ -131,6 +131,25 @@ struct StoredDeclsList { return DK == DK_DeclID || DK == DK_ID_Vector; } + void remove(NamedDecl *D) { + assert(!isNull() && "removing from empty list"); + if (NamedDecl *Singleton = getAsDecl()) { + assert(Singleton == D && "list is different singleton"); + (void)Singleton; + Data = 0; + return; + } + + VectorTy &Vec = *getAsVector(); + VectorTy::iterator I = std::find(Vec.begin(), Vec.end(), + reinterpret_cast(D)); + assert(I != Vec.end() && "list does not contain decl"); + Vec.erase(I); + + assert(std::find(Vec.begin(), Vec.end(), reinterpret_cast(D)) + == Vec.end() && "list still contains decl"); + } + /// getLookupResult - Return an array of all the decls that this list /// represents. DeclContext::lookup_result getLookupResult(ASTContext &Context) { @@ -200,11 +219,37 @@ struct StoredDeclsList { } VectorTy &Vec = *getAsVector(); - if (isa(D) || - D->getIdentifierNamespace() == Decl::IDNS_Tag) + + // Using directives end up in a special entry which contains only + // other using directives, so all this logic is wasted for them. + // But avoiding the logic wastes time in the far-more-common case + // that we're *not* adding a new using directive. + + // Tag declarations always go at the end of the list so that an + // iterator which points at the first tag will start a span of + // decls that only contains tags. + if (D->getIdentifierNamespace() == Decl::IDNS_Tag) Vec.push_back(reinterpret_cast(D)); - else if (reinterpret_cast(Vec.back()) - ->getIdentifierNamespace() == Decl::IDNS_Tag) { + + // Resolved using declarations go at the front of the list so that + // they won't show up in other lookup results. Unresolved using + // declarations (which are always in IDNS_Using | IDNS_Ordinary) + // follow that so that the using declarations will be contiguous. + else if (D->getIdentifierNamespace() & Decl::IDNS_Using) { + VectorTy::iterator I = Vec.begin(); + if (D->getIdentifierNamespace() != Decl::IDNS_Using) { + while (I != Vec.end() && + reinterpret_cast(*I) + ->getIdentifierNamespace() == Decl::IDNS_Using) + ++I; + } + Vec.insert(I, reinterpret_cast(D)); + + // All other declarations go at the end of the list, but before any + // tag declarations. But we can be clever about tag declarations + // because there can only ever be one in a scope. + } else if (reinterpret_cast(Vec.back()) + ->getIdentifierNamespace() == Decl::IDNS_Tag) { uintptr_t TagD = Vec.back(); Vec.back() = reinterpret_cast(D); Vec.push_back(TagD); diff --git a/include/clang/AST/DeclNodes.def b/include/clang/AST/DeclNodes.def index ec1b3b055cab..082299c41f50 100644 --- a/include/clang/AST/DeclNodes.def +++ b/include/clang/AST/DeclNodes.def @@ -75,7 +75,6 @@ DECL(TranslationUnit, Decl) ABSTRACT_DECL(Named, Decl) - DECL(OverloadedFunction, NamedDecl) DECL(Namespace, NamedDecl) DECL(UsingDirective, NamedDecl) DECL(NamespaceAlias, NamedDecl) @@ -143,7 +142,7 @@ DECL_CONTEXT_BASE(ObjCContainer) LAST_DECL_CONTEXT(Block) // Declaration ranges -DECL_RANGE(Named, OverloadedFunction, ObjCCompatibleAlias) +DECL_RANGE(Named, Namespace, ObjCCompatibleAlias) DECL_RANGE(ObjCContainer, ObjCContainer, ObjCImplementation) DECL_RANGE(Field, Field, ObjCAtDefsField) DECL_RANGE(Type, Typedef, TemplateTypeParm) diff --git a/include/clang/AST/DeclObjC.h b/include/clang/AST/DeclObjC.h index 897776cdb9b8..fd8c3ef7fc55 100644 --- a/include/clang/AST/DeclObjC.h +++ b/include/clang/AST/DeclObjC.h @@ -578,14 +578,14 @@ class ObjCIvarDecl : public FieldDecl { private: ObjCIvarDecl(DeclContext *DC, SourceLocation L, IdentifierInfo *Id, - QualType T, DeclaratorInfo *DInfo, AccessControl ac, Expr *BW) - : FieldDecl(ObjCIvar, DC, L, Id, T, DInfo, BW, /*Mutable=*/false), + QualType T, TypeSourceInfo *TInfo, AccessControl ac, Expr *BW) + : FieldDecl(ObjCIvar, DC, L, Id, T, TInfo, BW, /*Mutable=*/false), DeclAccess(ac) {} public: static ObjCIvarDecl *Create(ASTContext &C, DeclContext *DC, SourceLocation L, IdentifierInfo *Id, QualType T, - DeclaratorInfo *DInfo, + TypeSourceInfo *TInfo, AccessControl ac, Expr *BW = NULL); void setAccessControl(AccessControl ac) { DeclAccess = ac; } @@ -612,7 +612,7 @@ class ObjCAtDefsFieldDecl : public FieldDecl { ObjCAtDefsFieldDecl(DeclContext *DC, SourceLocation L, IdentifierInfo *Id, QualType T, Expr *BW) : FieldDecl(ObjCAtDefsField, DC, L, Id, T, - /*DInfo=*/0, // FIXME: Do ObjCAtDefs have declarators ? + /*TInfo=*/0, // FIXME: Do ObjCAtDefs have declarators ? BW, /*Mutable=*/false) {} public: diff --git a/include/clang/AST/DeclTemplate.h b/include/clang/AST/DeclTemplate.h index 3ecc4bb52b4c..d8b004a049ce 100644 --- a/include/clang/AST/DeclTemplate.h +++ b/include/clang/AST/DeclTemplate.h @@ -573,7 +573,7 @@ class TemplateTypeParmDecl : public TypeDecl { bool ParameterPack : 1; /// \brief The default template argument, if any. - DeclaratorInfo *DefaultArgument; + TypeSourceInfo *DefaultArgument; TemplateTypeParmDecl(DeclContext *DC, SourceLocation L, IdentifierInfo *Id, bool Typename, QualType Type, bool ParameterPack) @@ -601,7 +601,7 @@ class TemplateTypeParmDecl : public TypeDecl { QualType getDefaultArgument() const { return DefaultArgument->getType(); } /// \brief Retrieves the default argument's source information, if any. - DeclaratorInfo *getDefaultArgumentInfo() const { return DefaultArgument; } + TypeSourceInfo *getDefaultArgumentInfo() const { return DefaultArgument; } /// \brief Retrieves the location of the default argument declaration. SourceLocation getDefaultArgumentLoc() const; @@ -613,7 +613,7 @@ class TemplateTypeParmDecl : public TypeDecl { /// \brief Set the default argument for this template parameter, and /// whether that default argument was inherited from another /// declaration. - void setDefaultArgument(DeclaratorInfo *DefArg, bool Inherited) { + void setDefaultArgument(TypeSourceInfo *DefArg, bool Inherited) { DefaultArgument = DefArg; InheritedDefault = Inherited; } @@ -652,15 +652,15 @@ class NonTypeTemplateParmDecl NonTypeTemplateParmDecl(DeclContext *DC, SourceLocation L, unsigned D, unsigned P, IdentifierInfo *Id, QualType T, - DeclaratorInfo *DInfo) - : VarDecl(NonTypeTemplateParm, DC, L, Id, T, DInfo, VarDecl::None), + TypeSourceInfo *TInfo) + : VarDecl(NonTypeTemplateParm, DC, L, Id, T, TInfo, VarDecl::None), TemplateParmPosition(D, P), DefaultArgument(0) { } public: static NonTypeTemplateParmDecl * Create(ASTContext &C, DeclContext *DC, SourceLocation L, unsigned D, - unsigned P, IdentifierInfo *Id, QualType T, DeclaratorInfo *DInfo); + unsigned P, IdentifierInfo *Id, QualType T, TypeSourceInfo *TInfo); using TemplateParmPosition::getDepth; using TemplateParmPosition::getPosition; diff --git a/include/clang/AST/DeclarationName.h b/include/clang/AST/DeclarationName.h index 676bd2ca7336..fcb4ae52e7eb 100644 --- a/include/clang/AST/DeclarationName.h +++ b/include/clang/AST/DeclarationName.h @@ -387,10 +387,11 @@ struct DenseMapInfo { isEqual(clang::DeclarationName LHS, clang::DeclarationName RHS) { return LHS == RHS; } - - static inline bool isPod() { return true; } }; +template <> +struct isPodLike { static const bool value = true; }; + } // end namespace llvm #endif diff --git a/include/clang/AST/Expr.h b/include/clang/AST/Expr.h index 7cf9aabc6d6f..469598ff3723 100644 --- a/include/clang/AST/Expr.h +++ b/include/clang/AST/Expr.h @@ -309,6 +309,15 @@ class Expr : public Stmt { /// ParenExpr or CastExprs, returning their operand. Expr *IgnoreParenNoopCasts(ASTContext &Ctx); + /// \brief Determine whether this expression is a default function argument. + /// + /// Default arguments are implicitly generated in the abstract syntax tree + /// by semantic analysis for function calls, object constructions, etc. in + /// C++. Default arguments are represented by \c CXXDefaultArgExpr nodes; + /// this routine also looks through any implicit casts to determine whether + /// the expression is a default argument. + bool isDefaultArgument() const; + const Expr* IgnoreParens() const { return const_cast(this)->IgnoreParens(); } @@ -389,7 +398,7 @@ class DeclRefExpr : public Expr { // indicate whether (1) the declaration's name was explicitly qualified and // (2) the declaration's name was followed by an explicit template // argument list. - llvm::PointerIntPair DecoratedD; + llvm::PointerIntPair DecoratedD; // Loc - The location of the declaration name itself. SourceLocation Loc; @@ -427,7 +436,7 @@ class DeclRefExpr : public Expr { } DeclRefExpr(NestedNameSpecifier *Qualifier, SourceRange QualifierRange, - NamedDecl *D, SourceLocation NameLoc, + ValueDecl *D, SourceLocation NameLoc, const TemplateArgumentListInfo *TemplateArgs, QualType T); @@ -436,13 +445,13 @@ class DeclRefExpr : public Expr { /// declaration reference expression. void computeDependence(); - DeclRefExpr(StmtClass SC, NamedDecl *d, QualType t, SourceLocation l) : + DeclRefExpr(StmtClass SC, ValueDecl *d, QualType t, SourceLocation l) : Expr(SC, t, false, false), DecoratedD(d, 0), Loc(l) { computeDependence(); } public: - DeclRefExpr(NamedDecl *d, QualType t, SourceLocation l) : + DeclRefExpr(ValueDecl *d, QualType t, SourceLocation l) : Expr(DeclRefExprClass, t, false, false), DecoratedD(d, 0), Loc(l) { computeDependence(); } @@ -454,14 +463,14 @@ class DeclRefExpr : public Expr { static DeclRefExpr *Create(ASTContext &Context, NestedNameSpecifier *Qualifier, SourceRange QualifierRange, - NamedDecl *D, + ValueDecl *D, SourceLocation NameLoc, QualType T, const TemplateArgumentListInfo *TemplateArgs = 0); - NamedDecl *getDecl() { return DecoratedD.getPointer(); } - const NamedDecl *getDecl() const { return DecoratedD.getPointer(); } - void setDecl(NamedDecl *NewD) { DecoratedD.setPointer(NewD); } + ValueDecl *getDecl() { return DecoratedD.getPointer(); } + const ValueDecl *getDecl() const { return DecoratedD.getPointer(); } + void setDecl(ValueDecl *NewD) { DecoratedD.setPointer(NewD); } SourceLocation getLocation() const { return Loc; } void setLocation(SourceLocation L) { Loc = L; } @@ -686,11 +695,6 @@ class FloatingLiteral : public Expr { SourceLocation getLocation() const { return Loc; } void setLocation(SourceLocation L) { Loc = L; } - // FIXME: The logic for computing the value of a predefined expr should go - // into a method here that takes the inner-most code decl (a block, function - // or objc method) that the expr lives in. This would allow sema and codegen - // to be consistent for things like sizeof(__func__) etc. - virtual SourceRange getSourceRange() const { return SourceRange(Loc); } static bool classof(const Stmt *T) { @@ -975,7 +979,7 @@ class SizeOfAlignOfExpr : public Expr { bool isSizeof : 1; // true if sizeof, false if alignof. bool isType : 1; // true if operand is a type, false if an expression union { - DeclaratorInfo *Ty; + TypeSourceInfo *Ty; Stmt *Ex; } Argument; SourceLocation OpLoc, RParenLoc; @@ -984,15 +988,15 @@ class SizeOfAlignOfExpr : public Expr { virtual void DoDestroy(ASTContext& C); public: - SizeOfAlignOfExpr(bool issizeof, DeclaratorInfo *DInfo, + SizeOfAlignOfExpr(bool issizeof, TypeSourceInfo *TInfo, QualType resultType, SourceLocation op, SourceLocation rp) : Expr(SizeOfAlignOfExprClass, resultType, false, // Never type-dependent (C++ [temp.dep.expr]p3). // Value-dependent if the argument is type-dependent. - DInfo->getType()->isDependentType()), + TInfo->getType()->isDependentType()), isSizeof(issizeof), isType(true), OpLoc(op), RParenLoc(rp) { - Argument.Ty = DInfo; + Argument.Ty = TInfo; } SizeOfAlignOfExpr(bool issizeof, Expr *E, @@ -1017,7 +1021,7 @@ class SizeOfAlignOfExpr : public Expr { QualType getArgumentType() const { return getArgumentTypeInfo()->getType(); } - DeclaratorInfo *getArgumentTypeInfo() const { + TypeSourceInfo *getArgumentTypeInfo() const { assert(isArgumentType() && "calling getArgumentType() when arg is expr"); return Argument.Ty; } @@ -1030,8 +1034,8 @@ class SizeOfAlignOfExpr : public Expr { } void setArgument(Expr *E) { Argument.Ex = E; isType = false; } - void setArgument(DeclaratorInfo *DInfo) { - Argument.Ty = DInfo; + void setArgument(TypeSourceInfo *TInfo) { + Argument.Ty = TInfo; isType = true; } @@ -1252,7 +1256,7 @@ class MemberExpr : public Expr { /// MemberDecl - This is the decl being referenced by the field/member name. /// In X.F, this is the decl referenced by F. - NamedDecl *MemberDecl; + ValueDecl *MemberDecl; /// MemberLoc - This is the location of the member name. SourceLocation MemberLoc; @@ -1305,12 +1309,12 @@ class MemberExpr : public Expr { } MemberExpr(Expr *base, bool isarrow, NestedNameSpecifier *qual, - SourceRange qualrange, NamedDecl *memberdecl, SourceLocation l, + SourceRange qualrange, ValueDecl *memberdecl, SourceLocation l, const TemplateArgumentListInfo *targs, QualType ty); public: - MemberExpr(Expr *base, bool isarrow, NamedDecl *memberdecl, SourceLocation l, - QualType ty) + MemberExpr(Expr *base, bool isarrow, ValueDecl *memberdecl, + SourceLocation l, QualType ty) : Expr(MemberExprClass, ty, base->isTypeDependent(), base->isValueDependent()), Base(base), MemberDecl(memberdecl), MemberLoc(l), IsArrow(isarrow), @@ -1323,7 +1327,7 @@ class MemberExpr : public Expr { static MemberExpr *Create(ASTContext &C, Expr *base, bool isarrow, NestedNameSpecifier *qual, SourceRange qualrange, - NamedDecl *memberdecl, + ValueDecl *memberdecl, SourceLocation l, const TemplateArgumentListInfo *targs, QualType ty); @@ -1335,8 +1339,8 @@ class MemberExpr : public Expr { /// /// The returned declaration will either be a FieldDecl or (in C++) /// a CXXMethodDecl. - NamedDecl *getMemberDecl() const { return MemberDecl; } - void setMemberDecl(NamedDecl *D) { MemberDecl = D; } + ValueDecl *getMemberDecl() const { return MemberDecl; } + void setMemberDecl(ValueDecl *D) { MemberDecl = D; } /// \brief Determines whether this member expression actually had /// a C++ nested-name-specifier prior to the name of the member, e.g., @@ -1576,7 +1580,14 @@ class CastExpr : public Expr { CK_FloatingCast, /// CK_MemberPointerToBoolean - Member pointer to boolean - CK_MemberPointerToBoolean + CK_MemberPointerToBoolean, + + /// CK_AnyPointerToObjCPointerCast - Casting any pointer to objective-c + /// pointer + CK_AnyPointerToObjCPointerCast, + /// CK_AnyPointerToBlockPointerCast - Casting any pointer to block + /// pointer + CK_AnyPointerToBlockPointerCast }; @@ -1607,6 +1618,14 @@ class CastExpr : public Expr { const Expr *getSubExpr() const { return cast(Op); } void setSubExpr(Expr *E) { Op = E; } + /// \brief Retrieve the cast subexpression as it was written in the source + /// code, looking through any implicit casts or other intermediate nodes + /// introduced by semantic analysis. + Expr *getSubExprAsWritten(); + const Expr *getSubExprAsWritten() const { + return const_cast(this)->getSubExprAsWritten(); + } + static bool classof(const Stmt *T) { StmtClass SC = T->getStmtClass(); if (SC >= CXXNamedCastExprClass && SC <= CXXFunctionalCastExprClass) diff --git a/include/clang/AST/ExprCXX.h b/include/clang/AST/ExprCXX.h index 23844ce5d967..00ea202abde7 100644 --- a/include/clang/AST/ExprCXX.h +++ b/include/clang/AST/ExprCXX.h @@ -527,6 +527,7 @@ class CXXConstructExpr : public Expr { const_arg_iterator arg_begin() const { return Args; } const_arg_iterator arg_end() const { return Args + NumArgs; } + Expr **getArgs() const { return reinterpret_cast(Args); } unsigned getNumArgs() const { return NumArgs; } /// getArg - Return the specified argument. @@ -1410,18 +1411,26 @@ class CXXUnresolvedConstructExpr : public Expr { /// \brief Represents a C++ member access expression where the actual /// member referenced could not be resolved because the base /// expression or the member name was dependent. +/// +/// Like UnresolvedMemberExprs, these can be either implicit or +/// explicit accesses. It is only possible to get one of these with +/// an implicit access if a qualifier is provided. class CXXDependentScopeMemberExpr : public Expr { /// \brief The expression for the base pointer or class reference, - /// e.g., the \c x in x.f. + /// e.g., the \c x in x.f. Can be null in implicit accesses. Stmt *Base; + /// \brief The type of the base expression. Never null, even for + /// implicit accesses. + QualType BaseType; + /// \brief Whether this member expression used the '->' operator or /// the '.' operator. bool IsArrow : 1; /// \brief Whether this member expression has explicitly-specified template /// arguments. - bool HasExplicitTemplateArgumentList : 1; + bool HasExplicitTemplateArgs : 1; /// \brief The location of the '->' or '.' operator. SourceLocation OperatorLoc; @@ -1452,9 +1461,7 @@ class CXXDependentScopeMemberExpr : public Expr { /// \brief Retrieve the explicit template argument list that followed the /// member template name, if any. ExplicitTemplateArgumentList *getExplicitTemplateArgumentList() { - if (!HasExplicitTemplateArgumentList) - return 0; - + assert(HasExplicitTemplateArgs); return reinterpret_cast(this + 1); } @@ -1466,7 +1473,7 @@ class CXXDependentScopeMemberExpr : public Expr { } CXXDependentScopeMemberExpr(ASTContext &C, - Expr *Base, bool IsArrow, + Expr *Base, QualType BaseType, bool IsArrow, SourceLocation OperatorLoc, NestedNameSpecifier *Qualifier, SourceRange QualifierRange, @@ -1477,7 +1484,8 @@ class CXXDependentScopeMemberExpr : public Expr { public: CXXDependentScopeMemberExpr(ASTContext &C, - Expr *Base, bool IsArrow, + Expr *Base, QualType BaseType, + bool IsArrow, SourceLocation OperatorLoc, NestedNameSpecifier *Qualifier, SourceRange QualifierRange, @@ -1485,15 +1493,15 @@ class CXXDependentScopeMemberExpr : public Expr { DeclarationName Member, SourceLocation MemberLoc) : Expr(CXXDependentScopeMemberExprClass, C.DependentTy, true, true), - Base(Base), IsArrow(IsArrow), HasExplicitTemplateArgumentList(false), - OperatorLoc(OperatorLoc), + Base(Base), BaseType(BaseType), IsArrow(IsArrow), + HasExplicitTemplateArgs(false), OperatorLoc(OperatorLoc), Qualifier(Qualifier), QualifierRange(QualifierRange), FirstQualifierFoundInScope(FirstQualifierFoundInScope), Member(Member), MemberLoc(MemberLoc) { } static CXXDependentScopeMemberExpr * Create(ASTContext &C, - Expr *Base, bool IsArrow, + Expr *Base, QualType BaseType, bool IsArrow, SourceLocation OperatorLoc, NestedNameSpecifier *Qualifier, SourceRange QualifierRange, @@ -1502,11 +1510,21 @@ class CXXDependentScopeMemberExpr : public Expr { SourceLocation MemberLoc, const TemplateArgumentListInfo *TemplateArgs); + /// \brief True if this is an implicit access, i.e. one in which the + /// member being accessed was not written in the source. The source + /// location of the operator is invalid in this case. + bool isImplicitAccess() const { return Base == 0; } + /// \brief Retrieve the base object of this member expressions, /// e.g., the \c x in \c x.m. - Expr *getBase() { return cast(Base); } + Expr *getBase() const { + assert(!isImplicitAccess()); + return cast(Base); + } void setBase(Expr *E) { Base = E; } + QualType getBaseType() const { return BaseType; } + /// \brief Determine whether this member expression used the '->' /// operator; otherwise, it used the '.' operator. bool isArrow() const { return IsArrow; } @@ -1551,60 +1569,59 @@ class CXXDependentScopeMemberExpr : public Expr { /// \brief Determines whether this member expression actually had a C++ /// template argument list explicitly specified, e.g., x.f. - bool hasExplicitTemplateArgumentList() const { - return HasExplicitTemplateArgumentList; + bool hasExplicitTemplateArgs() const { + return HasExplicitTemplateArgs; } /// \brief Copies the template arguments (if present) into the given /// structure. void copyTemplateArgumentsInto(TemplateArgumentListInfo &List) const { - if (hasExplicitTemplateArgumentList()) - getExplicitTemplateArgumentList()->copyInto(List); + assert(HasExplicitTemplateArgs); + getExplicitTemplateArgumentList()->copyInto(List); } /// \brief Retrieve the location of the left angle bracket following the /// member name ('<'), if any. SourceLocation getLAngleLoc() const { - if (!HasExplicitTemplateArgumentList) - return SourceLocation(); - + assert(HasExplicitTemplateArgs); return getExplicitTemplateArgumentList()->LAngleLoc; } /// \brief Retrieve the template arguments provided as part of this /// template-id. const TemplateArgumentLoc *getTemplateArgs() const { - if (!HasExplicitTemplateArgumentList) - return 0; - + assert(HasExplicitTemplateArgs); return getExplicitTemplateArgumentList()->getTemplateArgs(); } /// \brief Retrieve the number of template arguments provided as part of this /// template-id. unsigned getNumTemplateArgs() const { - if (!HasExplicitTemplateArgumentList) - return 0; - + assert(HasExplicitTemplateArgs); return getExplicitTemplateArgumentList()->NumTemplateArgs; } /// \brief Retrieve the location of the right angle bracket following the /// template arguments ('>'). SourceLocation getRAngleLoc() const { - if (!HasExplicitTemplateArgumentList) - return SourceLocation(); - + assert(HasExplicitTemplateArgs); return getExplicitTemplateArgumentList()->RAngleLoc; } virtual SourceRange getSourceRange() const { - if (HasExplicitTemplateArgumentList) - return SourceRange(Base->getSourceRange().getBegin(), - getRAngleLoc()); + SourceRange Range; + if (!isImplicitAccess()) + Range.setBegin(Base->getSourceRange().getBegin()); + else if (getQualifier()) + Range.setBegin(getQualifierRange().getBegin()); + else + Range.setBegin(MemberLoc); - return SourceRange(Base->getSourceRange().getBegin(), - MemberLoc); + if (hasExplicitTemplateArgs()) + Range.setEnd(getRAngleLoc()); + else + Range.setEnd(MemberLoc); + return Range; } static bool classof(const Stmt *T) { @@ -1618,17 +1635,31 @@ class CXXDependentScopeMemberExpr : public Expr { }; /// \brief Represents a C++ member access expression for which lookup -/// produced a set of overloaded functions. These are replaced with -/// MemberExprs in the final AST. +/// produced a set of overloaded functions. +/// +/// The member access may be explicit or implicit: +/// struct A { +/// int a, b; +/// int explicitAccess() { return this->a + this->A::b; } +/// int implicitAccess() { return a + A::b; } +/// }; +/// +/// In the final AST, an explicit access always becomes a MemberExpr. +/// An implicit access may become either a MemberExpr or a +/// DeclRefExpr, depending on whether the member is static. class UnresolvedMemberExpr : public Expr { /// The results. These are undesugared, which is to say, they may /// include UsingShadowDecls. UnresolvedSet Results; /// \brief The expression for the base pointer or class reference, - /// e.g., the \c x in x.f. + /// e.g., the \c x in x.f. This can be null if this is an 'unbased' + /// member expression Stmt *Base; + /// \brief The type of the base expression; never null. + QualType BaseType; + /// \brief Whether this member expression used the '->' operator or /// the '.' operator. bool IsArrow : 1; @@ -1672,7 +1703,7 @@ class UnresolvedMemberExpr : public Expr { UnresolvedMemberExpr(QualType T, bool Dependent, bool HasUnresolvedUsing, - Expr *Base, bool IsArrow, + Expr *Base, QualType BaseType, bool IsArrow, SourceLocation OperatorLoc, NestedNameSpecifier *Qualifier, SourceRange QualifierRange, @@ -1683,7 +1714,7 @@ class UnresolvedMemberExpr : public Expr { public: static UnresolvedMemberExpr * Create(ASTContext &C, bool Dependent, bool HasUnresolvedUsing, - Expr *Base, bool IsArrow, + Expr *Base, QualType BaseType, bool IsArrow, SourceLocation OperatorLoc, NestedNameSpecifier *Qualifier, SourceRange QualifierRange, @@ -1704,11 +1735,21 @@ class UnresolvedMemberExpr : public Expr { unsigned getNumDecls() const { return Results.size(); } + /// \brief True if this is an implicit access, i.e. one in which the + /// member being accessed was not written in the source. The source + /// location of the operator is invalid in this case. + bool isImplicitAccess() const { return Base == 0; } + /// \brief Retrieve the base object of this member expressions, /// e.g., the \c x in \c x.m. - Expr *getBase() { return cast(Base); } + Expr *getBase() { + assert(!isImplicitAccess()); + return cast(Base); + } void setBase(Expr *E) { Base = E; } + QualType getBaseType() const { return BaseType; } + /// \brief Determine whether this member expression used the '->' /// operator; otherwise, it used the '.' operator. bool isArrow() const { return IsArrow; } @@ -1772,7 +1813,14 @@ class UnresolvedMemberExpr : public Expr { } virtual SourceRange getSourceRange() const { - SourceRange Range = Base->getSourceRange(); + SourceRange Range; + if (!isImplicitAccess()) + Range.setBegin(Base->getSourceRange().getBegin()); + else if (getQualifier()) + Range.setBegin(getQualifierRange().getBegin()); + else + Range.setBegin(MemberLoc); + if (hasExplicitTemplateArgs()) Range.setEnd(getRAngleLoc()); else diff --git a/include/clang/AST/RecordLayout.h b/include/clang/AST/RecordLayout.h index 5d2973ea9dab..a8334b694080 100644 --- a/include/clang/AST/RecordLayout.h +++ b/include/clang/AST/RecordLayout.h @@ -119,13 +119,6 @@ class ASTRecordLayout { /// VBaseOffsets - Contains a map from vbase classes to their offset. /// FIXME: This should really use a SmallPtrMap, once we have one in LLVM :) llvm::DenseMap VBaseOffsets; - - /// KeyFunction - The key function, according to the Itanium C++ ABI, - /// section 5.2.3: - /// - /// ...the first non-pure virtual function that is not inline at the point - /// of class definition. - const CXXMethodDecl *KeyFunction; }; /// CXXInfo - If the record layout is for a C++ record, this will have @@ -154,8 +147,7 @@ class ASTRecordLayout { const std::pair *bases, unsigned numbases, const std::pair *vbases, - unsigned numvbases, - const CXXMethodDecl *KeyFunction) + unsigned numvbases) : Size(size), DataSize(datasize), FieldOffsets(0), Alignment(alignment), FieldCount(fieldcount), CXXInfo(new CXXRecordLayoutInfo) { if (FieldCount > 0) { @@ -171,7 +163,6 @@ class ASTRecordLayout { CXXInfo->BaseOffsets[bases[i].first] = bases[i].second; for (unsigned i = 0; i != numvbases; ++i) CXXInfo->VBaseOffsets[vbases[i].first] = vbases[i].second; - CXXInfo->KeyFunction = KeyFunction; } ~ASTRecordLayout() { @@ -254,13 +245,6 @@ class ASTRecordLayout { return CXXInfo->VBaseOffsets[VBase]; } - /// getKeyFunction - Get the key function. - const CXXMethodDecl *getKeyFunction() const { - assert(CXXInfo && "Record layout does not have C++ specific info!"); - - return CXXInfo->KeyFunction; - } - primary_base_info_iterator primary_base_begin() const { assert(CXXInfo && "Record layout does not have C++ specific info!"); diff --git a/include/clang/AST/StmtCXX.h b/include/clang/AST/StmtCXX.h index 64eea2429c5d..09ea4ca2101b 100644 --- a/include/clang/AST/StmtCXX.h +++ b/include/clang/AST/StmtCXX.h @@ -68,10 +68,11 @@ class CXXTryStmt : public Stmt { Stmt **handlers, unsigned numHandlers); virtual SourceRange getSourceRange() const { - return SourceRange(TryLoc, Stmts.back()->getLocEnd()); + return SourceRange(getTryLoc(), getEndLoc()); } SourceLocation getTryLoc() const { return TryLoc; } + SourceLocation getEndLoc() const { return Stmts.back()->getLocEnd(); } CompoundStmt *getTryBlock() { return llvm::cast(Stmts[0]); } const CompoundStmt *getTryBlock() const { diff --git a/include/clang/AST/TemplateBase.h b/include/clang/AST/TemplateBase.h index b46b3dc5d2d2..fe037992ad2f 100644 --- a/include/clang/AST/TemplateBase.h +++ b/include/clang/AST/TemplateBase.h @@ -29,7 +29,7 @@ namespace clang { class Decl; class Expr; -class DeclaratorInfo; +class TypeSourceInfo; /// \brief Represents a template argument within a class template /// specialization. @@ -267,7 +267,7 @@ struct TemplateArgumentLocInfo { private: union { Expr *Expression; - DeclaratorInfo *Declarator; + TypeSourceInfo *Declarator; struct { unsigned QualifierRange[2]; unsigned TemplateNameLoc; @@ -277,7 +277,7 @@ struct TemplateArgumentLocInfo { #ifndef NDEBUG enum Kind { K_None, - K_DeclaratorInfo, + K_TypeSourceInfo, K_Expression, K_Template } Kind; @@ -291,10 +291,10 @@ struct TemplateArgumentLocInfo { #endif {} - TemplateArgumentLocInfo(DeclaratorInfo *DInfo) - : Declarator(DInfo) + TemplateArgumentLocInfo(TypeSourceInfo *TInfo) + : Declarator(TInfo) #ifndef NDEBUG - , Kind(K_DeclaratorInfo) + , Kind(K_TypeSourceInfo) #endif {} @@ -316,8 +316,8 @@ struct TemplateArgumentLocInfo { Template.TemplateNameLoc = TemplateNameLoc.getRawEncoding(); } - DeclaratorInfo *getAsDeclaratorInfo() const { - assert(Kind == K_DeclaratorInfo); + TypeSourceInfo *getAsTypeSourceInfo() const { + assert(Kind == K_TypeSourceInfo); return Declarator; } @@ -342,7 +342,7 @@ struct TemplateArgumentLocInfo { void validateForArgument(const TemplateArgument &Arg) { switch (Arg.getKind()) { case TemplateArgument::Type: - assert(Kind == K_DeclaratorInfo); + assert(Kind == K_TypeSourceInfo); break; case TemplateArgument::Expression: case TemplateArgument::Declaration: @@ -356,7 +356,7 @@ struct TemplateArgumentLocInfo { assert(Kind == K_None); break; case TemplateArgument::Null: - llvm::llvm_unreachable("source info for null template argument?"); + llvm_unreachable("source info for null template argument?"); } } #endif @@ -376,8 +376,8 @@ class TemplateArgumentLoc { : Argument(Argument), LocInfo(Opaque) { } - TemplateArgumentLoc(const TemplateArgument &Argument, DeclaratorInfo *DInfo) - : Argument(Argument), LocInfo(DInfo) { + TemplateArgumentLoc(const TemplateArgument &Argument, TypeSourceInfo *TInfo) + : Argument(Argument), LocInfo(TInfo) { assert(Argument.getKind() == TemplateArgument::Type); } @@ -412,9 +412,9 @@ class TemplateArgumentLoc { return LocInfo; } - DeclaratorInfo *getSourceDeclaratorInfo() const { + TypeSourceInfo *getTypeSourceInfo() const { assert(Argument.getKind() == TemplateArgument::Type); - return LocInfo.getAsDeclaratorInfo(); + return LocInfo.getAsTypeSourceInfo(); } Expr *getSourceExpression() const { diff --git a/include/clang/AST/TemplateName.h b/include/clang/AST/TemplateName.h index 8ef8fb51416c..aafe96381192 100644 --- a/include/clang/AST/TemplateName.h +++ b/include/clang/AST/TemplateName.h @@ -31,7 +31,34 @@ struct PrintingPolicy; class QualifiedTemplateName; class NamedDecl; class TemplateDecl; -class OverloadedFunctionDecl; + +/// \brief A structure for storing the information associated with an +/// overloaded template name. +class OverloadedTemplateStorage { + union { + unsigned Size; + NamedDecl *Storage[1]; + }; + + friend class ASTContext; + + OverloadedTemplateStorage(unsigned Size) : Size(Size) {} + + NamedDecl **getStorage() { + return &Storage[1]; + } + NamedDecl * const *getStorage() const { + return &Storage[1]; + } + +public: + typedef NamedDecl *const *iterator; + + unsigned size() const { return Size; } + + iterator begin() const { return getStorage(); } + iterator end() const { return getStorage() + size(); } +}; /// \brief Represents a C++ template name within the type system. /// @@ -61,7 +88,8 @@ class OverloadedFunctionDecl; /// specifier in the typedef. "apply" is a nested template, and can /// only be understood in the context of class TemplateName { - typedef llvm::PointerUnion4 StorageType; @@ -74,8 +102,8 @@ class TemplateName { public: TemplateName() : Storage() { } explicit TemplateName(TemplateDecl *Template) : Storage(Template) { } - explicit TemplateName(OverloadedFunctionDecl *FunctionTemplates) - : Storage(FunctionTemplates) { } + explicit TemplateName(OverloadedTemplateStorage *Storage) + : Storage(Storage) { } explicit TemplateName(QualifiedTemplateName *Qual) : Storage(Qual) { } explicit TemplateName(DependentTemplateName *Dep) : Storage(Dep) { } @@ -98,7 +126,9 @@ class TemplateName { /// name refers to, if known. If the template name does not refer to a /// specific set of function templates because it is a dependent name or /// refers to a single template, returns NULL. - OverloadedFunctionDecl *getAsOverloadedFunctionDecl() const; + OverloadedTemplateStorage *getAsOverloadedTemplate() const { + return Storage.dyn_cast(); + } /// \brief Retrieve the underlying qualified template name /// structure, if any. @@ -166,19 +196,14 @@ class QualifiedTemplateName : public llvm::FoldingSetNode { /// \brief The template declaration or set of overloaded function templates /// that this qualified name refers to. - NamedDecl *Template; + TemplateDecl *Template; friend class ASTContext; QualifiedTemplateName(NestedNameSpecifier *NNS, bool TemplateKeyword, TemplateDecl *Template) : Qualifier(NNS, TemplateKeyword? 1 : 0), - Template(reinterpret_cast(Template)) { } - - QualifiedTemplateName(NestedNameSpecifier *NNS, bool TemplateKeyword, - OverloadedFunctionDecl *Template) - : Qualifier(NNS, TemplateKeyword? 1 : 0), - Template(reinterpret_cast(Template)) { } + Template(Template) { } public: /// \brief Return the nested name specifier that qualifies this name. @@ -188,26 +213,20 @@ class QualifiedTemplateName : public llvm::FoldingSetNode { /// keyword. bool hasTemplateKeyword() const { return Qualifier.getInt(); } - /// \brief The template declaration or set of overloaded functions that - /// that qualified name refers to. - NamedDecl *getDecl() const { return Template; } + /// \brief The template declaration that this qualified name refers + /// to. + TemplateDecl *getDecl() const { return Template; } /// \brief The template declaration to which this qualified name - /// refers, or NULL if this qualified name refers to a set of overloaded - /// function templates. - TemplateDecl *getTemplateDecl() const; - - /// \brief The set of overloaded function tempaltes to which this qualified - /// name refers, or NULL if this qualified name refers to a single - /// template declaration. - OverloadedFunctionDecl *getOverloadedFunctionDecl() const; + /// refers. + TemplateDecl *getTemplateDecl() const { return Template; } void Profile(llvm::FoldingSetNodeID &ID) { - Profile(ID, getQualifier(), hasTemplateKeyword(), getDecl()); + Profile(ID, getQualifier(), hasTemplateKeyword(), getTemplateDecl()); } static void Profile(llvm::FoldingSetNodeID &ID, NestedNameSpecifier *NNS, - bool TemplateKeyword, NamedDecl *Template) { + bool TemplateKeyword, TemplateDecl *Template) { ID.AddPointer(NNS); ID.AddBoolean(TemplateKeyword); ID.AddPointer(Template); diff --git a/include/clang/AST/Type.h b/include/clang/AST/Type.h index 349487f8794b..d22a646ece5b 100644 --- a/include/clang/AST/Type.h +++ b/include/clang/AST/Type.h @@ -35,7 +35,9 @@ namespace clang { TypeAlignmentInBits = 3, TypeAlignment = 1 << TypeAlignmentInBits }; - class Type; class ExtQuals; + class Type; + class ExtQuals; + class QualType; } namespace llvm { @@ -59,6 +61,9 @@ namespace llvm { } enum { NumLowBitsAvailable = clang::TypeAlignmentInBits }; }; + + template <> + struct isPodLike { static const bool value = true; }; } namespace clang { @@ -76,6 +81,7 @@ namespace clang { class ObjCInterfaceDecl; class ObjCProtocolDecl; class ObjCMethodDecl; + class UnresolvedUsingTypenameDecl; class Expr; class Stmt; class SourceLocation; @@ -791,6 +797,10 @@ class Type { /// isPODType - Return true if this is a plain-old-data type (C++ 3.9p10). bool isPODType() const; + /// isLiteralType - Return true if this is a literal type + /// (C++0x [basic.types]p10) + bool isLiteralType() const; + /// isVariablyModifiedType (C99 6.7.5.2p2) - Return true for variable array /// types that have a non-constant expression. This does not include "[]". bool isVariablyModifiedType() const; @@ -808,8 +818,9 @@ class Type { bool isBooleanType() const; bool isCharType() const; bool isWideCharType() const; + bool isAnyCharacterType() const; bool isIntegralType() const; - + /// Floating point categories. bool isRealFloatingType() const; // C99 6.2.5p10 (float, double, long double) /// isComplexType() does *not* include complex integers (a GCC extension). @@ -1859,6 +1870,38 @@ class FunctionProtoType : public FunctionType, public llvm::FoldingSetNode { }; +/// \brief Represents the dependent type named by a dependently-scoped +/// typename using declaration, e.g. +/// using typename Base::foo; +/// Template instantiation turns these into the underlying type. +class UnresolvedUsingType : public Type { + UnresolvedUsingTypenameDecl *Decl; + + UnresolvedUsingType(UnresolvedUsingTypenameDecl *D) + : Type(UnresolvedUsing, QualType(), true), Decl(D) {} + friend class ASTContext; // ASTContext creates these. +public: + + UnresolvedUsingTypenameDecl *getDecl() const { return Decl; } + + bool isSugared() const { return false; } + QualType desugar() const { return QualType(this, 0); } + + static bool classof(const Type *T) { + return T->getTypeClass() == UnresolvedUsing; + } + static bool classof(const UnresolvedUsingType *) { return true; } + + void Profile(llvm::FoldingSetNodeID &ID) { + return Profile(ID, Decl); + } + static void Profile(llvm::FoldingSetNodeID &ID, + UnresolvedUsingTypenameDecl *D) { + ID.AddPointer(D); + } +}; + + class TypedefType : public Type { TypedefDecl *Decl; protected: diff --git a/include/clang/AST/TypeLoc.h b/include/clang/AST/TypeLoc.h index f08ca6bf469b..a9b7f7e94337 100644 --- a/include/clang/AST/TypeLoc.h +++ b/include/clang/AST/TypeLoc.h @@ -19,7 +19,7 @@ namespace clang { class ParmVarDecl; - class DeclaratorInfo; + class TypeSourceInfo; class UnqualTypeLoc; // Predeclare all the type nodes. @@ -340,16 +340,20 @@ class InheritingConcreteTypeLoc : public Base { } }; + struct TypeSpecLocInfo { SourceLocation NameLoc; }; /// \brief A reasonable base class for TypeLocs that correspond to /// types that are written as a type-specifier. -template -class TypeSpecTypeLoc - : public ConcreteTypeLoc { +class TypeSpecTypeLoc : public ConcreteTypeLoc { public: + enum { LocalDataSize = sizeof(TypeSpecLocInfo) }; + SourceLocation getNameLoc() const { return this->getLocalData()->NameLoc; } @@ -362,31 +366,79 @@ class TypeSpecTypeLoc void initializeLocal(SourceLocation Loc) { setNameLoc(Loc); } + + static bool classof(const TypeLoc *TL); + static bool classof(const TypeSpecTypeLoc *TL) { return true; } }; + /// \brief Wrapper for source info for typedefs. -class TypedefTypeLoc : public TypeSpecTypeLoc { +class TypedefTypeLoc : public InheritingConcreteTypeLoc { public: TypedefDecl *getTypedefDecl() const { return getTypePtr()->getDecl(); } }; +/// \brief Wrapper for source info for unresolved typename using decls. +class UnresolvedUsingTypeLoc : + public InheritingConcreteTypeLoc { +public: + UnresolvedUsingTypenameDecl *getDecl() const { + return getTypePtr()->getDecl(); + } +}; + +/// \brief Wrapper for source info for tag types. Note that this only +/// records source info for the name itself; a type written 'struct foo' +/// should be represented as an ElaboratedTypeLoc. We currently +/// only do that when C++ is enabled because of the expense of +/// creating an ElaboratedType node for so many type references in C. +class TagTypeLoc : public InheritingConcreteTypeLoc { +public: + TagDecl *getDecl() const { return getTypePtr()->getDecl(); } +}; + +/// \brief Wrapper for source info for record types. +class RecordTypeLoc : public InheritingConcreteTypeLoc { +public: + RecordDecl *getDecl() const { return getTypePtr()->getDecl(); } +}; + +/// \brief Wrapper for source info for enum types. +class EnumTypeLoc : public InheritingConcreteTypeLoc { +public: + EnumDecl *getDecl() const { return getTypePtr()->getDecl(); } +}; /// \brief Wrapper for source info for builtin types. -class BuiltinTypeLoc : public TypeSpecTypeLoc { +class BuiltinTypeLoc : public InheritingConcreteTypeLoc { }; /// \brief Wrapper for template type parameters. -class TemplateTypeParmTypeLoc : public TypeSpecTypeLoc { +class TemplateTypeParmTypeLoc : + public InheritingConcreteTypeLoc { }; /// \brief Wrapper for substituted template type parameters. class SubstTemplateTypeParmTypeLoc : - public TypeSpecTypeLoc { + public InheritingConcreteTypeLoc { }; @@ -889,7 +941,7 @@ class TemplateSpecializationTypeLoc : assert(size == Loc.getFullDataSize()); // We're potentially copying Expr references here. We don't - // bother retaining them because DeclaratorInfos live forever, so + // bother retaining them because TypeSourceInfos live forever, so // as long as the Expr was retained when originally written into // the TypeLoc, we're okay. memcpy(Data, Loc.Data, size); @@ -916,7 +968,7 @@ class TemplateSpecializationTypeLoc : break; case TemplateArgument::Type: - Info = TemplateArgumentLocInfo((DeclaratorInfo*) 0); + Info = TemplateArgumentLocInfo((TypeSourceInfo*) 0); break; case TemplateArgument::Template: @@ -944,63 +996,84 @@ class TemplateSpecializationTypeLoc : } }; -// None of these types have proper implementations yet. +//===----------------------------------------------------------------------===// +// +// All of these need proper implementations. +// +//===----------------------------------------------------------------------===// -class VectorTypeLoc : public TypeSpecTypeLoc { +// FIXME: size expression and attribute locations (or keyword if we +// ever fully support altivec syntax). +class VectorTypeLoc : public InheritingConcreteTypeLoc { }; +// FIXME: size expression and attribute locations. class ExtVectorTypeLoc : public InheritingConcreteTypeLoc { }; +// FIXME: attribute locations. // For some reason, this isn't a subtype of VectorType. class DependentSizedExtVectorTypeLoc : - public TypeSpecTypeLoc { + public InheritingConcreteTypeLoc { }; -class FixedWidthIntTypeLoc : public TypeSpecTypeLoc { +// FIXME: I'm not sure how you actually specify these; with attributes? +class FixedWidthIntTypeLoc : + public InheritingConcreteTypeLoc { }; -class ComplexTypeLoc : public TypeSpecTypeLoc { +// FIXME: location of the '_Complex' keyword. +class ComplexTypeLoc : public InheritingConcreteTypeLoc { }; -class TypeOfExprTypeLoc : public TypeSpecTypeLoc { +// FIXME: location of the 'typeof' and parens (the expression is +// carried by the type). +class TypeOfExprTypeLoc : public InheritingConcreteTypeLoc { }; -class TypeOfTypeLoc : public TypeSpecTypeLoc { +// FIXME: location of the 'typeof' and parens; also the TypeSourceInfo +// for the inner type, or (maybe) just express that inline to the TypeLoc. +class TypeOfTypeLoc : public InheritingConcreteTypeLoc { }; -class DecltypeTypeLoc : public TypeSpecTypeLoc { +// FIXME: location of the 'decltype' and parens. +class DecltypeTypeLoc : public InheritingConcreteTypeLoc { }; -class TagTypeLoc : public TypeSpecTypeLoc { +// FIXME: location of the tag keyword. +class ElaboratedTypeLoc : public InheritingConcreteTypeLoc { }; -class RecordTypeLoc : public InheritingConcreteTypeLoc { +// FIXME: locations for the nested name specifier; at the very least, +// a SourceRange. +class QualifiedNameTypeLoc : + public InheritingConcreteTypeLoc { }; -class EnumTypeLoc : public InheritingConcreteTypeLoc { -}; - -class ElaboratedTypeLoc : public TypeSpecTypeLoc { -}; - -class QualifiedNameTypeLoc : public TypeSpecTypeLoc { -}; - -class TypenameTypeLoc : public TypeSpecTypeLoc { +// FIXME: locations for the typename keyword and nested name specifier. +class TypenameTypeLoc : public InheritingConcreteTypeLoc { }; } diff --git a/include/clang/AST/TypeLocBuilder.h b/include/clang/AST/TypeLocBuilder.h index 00e2b7f83219..c3b1c68b1fb6 100644 --- a/include/clang/AST/TypeLocBuilder.h +++ b/include/clang/AST/TypeLocBuilder.h @@ -59,9 +59,35 @@ class TypeLocBuilder { grow(Requested); } - /// Pushes space for a new TypeLoc onto the given type. Invalidates + /// Pushes space for a typespec TypeLoc. Invalidates any TypeLocs + /// previously retrieved from this builder. + TypeSpecTypeLoc pushTypeSpec(QualType T) { + size_t LocalSize = TypeSpecTypeLoc::LocalDataSize; + return cast(pushImpl(T, LocalSize)); + } + + + /// Pushes space for a new TypeLoc of the given type. Invalidates /// any TypeLocs previously retrieved from this builder. template TyLocType push(QualType T) { + size_t LocalSize = cast(TypeLoc(T, 0)).getLocalDataSize(); + return cast(pushImpl(T, LocalSize)); + } + + /// Creates a TypeSourceInfo for the given type. + TypeSourceInfo *getTypeSourceInfo(ASTContext& Context, QualType T) { +#ifndef NDEBUG + assert(T == LastTy && "type doesn't match last type pushed!"); +#endif + + size_t FullDataSize = Capacity - Index; + TypeSourceInfo *DI = Context.CreateTypeSourceInfo(T, FullDataSize); + memcpy(DI->getTypeLoc().getOpaqueData(), &Buffer[Index], FullDataSize); + return DI; + } + +private: + TypeLoc pushImpl(QualType T, size_t LocalSize) { #ifndef NDEBUG QualType TLast = TypeLoc(T, 0).getNextTypeLoc().getType(); assert(TLast == LastTy && @@ -69,8 +95,6 @@ class TypeLocBuilder { LastTy = T; #endif - size_t LocalSize = cast(TypeLoc(T, 0)).getLocalDataSize(); - // If we need to grow, grow by a factor of 2. if (LocalSize > Index) { size_t RequiredCapacity = Capacity + (LocalSize - Index); @@ -82,22 +106,9 @@ class TypeLocBuilder { Index -= LocalSize; - return cast(TypeLoc(T, &Buffer[Index])); + return TypeLoc(T, &Buffer[Index]); } - /// Creates a DeclaratorInfo for the given type. - DeclaratorInfo *getDeclaratorInfo(ASTContext& Context, QualType T) { -#ifndef NDEBUG - assert(T == LastTy && "type doesn't match last type pushed!"); -#endif - - size_t FullDataSize = Capacity - Index; - DeclaratorInfo *DI = Context.CreateDeclaratorInfo(T, FullDataSize); - memcpy(DI->getTypeLoc().getOpaqueData(), &Buffer[Index], FullDataSize); - return DI; - } - - private: /// Grow to the given capacity. void grow(size_t NewCapacity) { assert(NewCapacity > Capacity); diff --git a/include/clang/AST/TypeLocVisitor.h b/include/clang/AST/TypeLocVisitor.h index a62bb3f853bc..95ec175a53a4 100644 --- a/include/clang/AST/TypeLocVisitor.h +++ b/include/clang/AST/TypeLocVisitor.h @@ -33,7 +33,7 @@ class TypeLocVisitor { case TypeLoc::CLASS: DISPATCH(CLASS##TypeLoc); #include "clang/AST/TypeLocNodes.def" } - llvm::llvm_unreachable("unexpected type loc class!"); + llvm_unreachable("unexpected type loc class!"); } RetTy Visit(UnqualTypeLoc TyLoc) { diff --git a/include/clang/AST/TypeNodes.def b/include/clang/AST/TypeNodes.def index c2721236af02..b9d37992a670 100644 --- a/include/clang/AST/TypeNodes.def +++ b/include/clang/AST/TypeNodes.def @@ -71,6 +71,7 @@ TYPE(ExtVector, VectorType) ABSTRACT_TYPE(Function, Type) TYPE(FunctionProto, FunctionType) TYPE(FunctionNoProto, FunctionType) +DEPENDENT_TYPE(UnresolvedUsing, Type) NON_CANONICAL_TYPE(Typedef, Type) NON_CANONICAL_TYPE(TypeOfExpr, Type) NON_CANONICAL_TYPE(TypeOf, Type) diff --git a/include/clang/AST/TypeOrdering.h b/include/clang/AST/TypeOrdering.h index 652f4f70bd16..1a050d29c860 100644 --- a/include/clang/AST/TypeOrdering.h +++ b/include/clang/AST/TypeOrdering.h @@ -50,13 +50,6 @@ namespace llvm { static bool isEqual(clang::QualType LHS, clang::QualType RHS) { return LHS == RHS; } - - static bool isPod() { - // QualType isn't *technically* a POD type. However, we can get - // away with calling it a POD type since its copy constructor, - // copy assignment operator, and destructor are all trivial. - return true; - } }; } diff --git a/include/clang/Analysis/PathDiagnostic.h b/include/clang/Analysis/PathDiagnostic.h index cad702cbdb2e..970b523e1b43 100644 --- a/include/clang/Analysis/PathDiagnostic.h +++ b/include/clang/Analysis/PathDiagnostic.h @@ -179,9 +179,7 @@ class PathDiagnosticPiece { PathDiagnosticPiece& operator=(const PathDiagnosticPiece &P); protected: - PathDiagnosticPiece(const std::string& s, Kind k, DisplayHint hint = Below); - - PathDiagnosticPiece(const char* s, Kind k, DisplayHint hint = Below); + PathDiagnosticPiece(llvm::StringRef s, Kind k, DisplayHint hint = Below); PathDiagnosticPiece(Kind k, DisplayHint hint = Below); @@ -242,7 +240,7 @@ class PathDiagnosticSpotPiece : public PathDiagnosticPiece { PathDiagnosticLocation Pos; public: PathDiagnosticSpotPiece(const PathDiagnosticLocation &pos, - const std::string& s, + llvm::StringRef s, PathDiagnosticPiece::Kind k, bool addPosRange = true) : PathDiagnosticPiece(s, k), Pos(pos) { @@ -261,11 +259,7 @@ class PathDiagnosticEventPiece : public PathDiagnosticSpotPiece { public: PathDiagnosticEventPiece(const PathDiagnosticLocation &pos, - const std::string& s, bool addPosRange = true) - : PathDiagnosticSpotPiece(pos, s, Event, addPosRange) {} - - PathDiagnosticEventPiece(const PathDiagnosticLocation &pos, const char* s, - bool addPosRange = true) + llvm::StringRef s, bool addPosRange = true) : PathDiagnosticSpotPiece(pos, s, Event, addPosRange) {} ~PathDiagnosticEventPiece(); @@ -280,14 +274,7 @@ class PathDiagnosticControlFlowPiece : public PathDiagnosticPiece { public: PathDiagnosticControlFlowPiece(const PathDiagnosticLocation &startPos, const PathDiagnosticLocation &endPos, - const std::string& s) - : PathDiagnosticPiece(s, ControlFlow) { - LPairs.push_back(PathDiagnosticLocationPair(startPos, endPos)); - } - - PathDiagnosticControlFlowPiece(const PathDiagnosticLocation &startPos, - const PathDiagnosticLocation &endPos, - const char* s) + llvm::StringRef s) : PathDiagnosticPiece(s, ControlFlow) { LPairs.push_back(PathDiagnosticLocationPair(startPos, endPos)); } @@ -384,22 +371,19 @@ class PathDiagnostic : public llvm::FoldingSetNode { public: PathDiagnostic(); - PathDiagnostic(const char* bugtype, const char* desc, const char* category); - - PathDiagnostic(const std::string& bugtype, const std::string& desc, - const std::string& category); + PathDiagnostic(llvm::StringRef bugtype, llvm::StringRef desc, + llvm::StringRef category); ~PathDiagnostic(); - const std::string& getDescription() const { return Desc; } - const std::string& getBugType() const { return BugType; } - const std::string& getCategory() const { return Category; } + llvm::StringRef getDescription() const { return Desc; } + llvm::StringRef getBugType() const { return BugType; } + llvm::StringRef getCategory() const { return Category; } typedef std::deque::const_iterator meta_iterator; meta_iterator meta_begin() const { return OtherDesc.begin(); } meta_iterator meta_end() const { return OtherDesc.end(); } - void addMeta(const std::string& s) { OtherDesc.push_back(s); } - void addMeta(const char* s) { OtherDesc.push_back(s); } + void addMeta(llvm::StringRef s) { OtherDesc.push_back(s); } PathDiagnosticLocation getLocation() const { assert(Size > 0 && "getLocation() requires a non-empty PathDiagnostic."); diff --git a/include/clang/Analysis/PathSensitive/AnalysisContext.h b/include/clang/Analysis/PathSensitive/AnalysisContext.h index 8b1a329c0335..abc33b778482 100644 --- a/include/clang/Analysis/PathSensitive/AnalysisContext.h +++ b/include/clang/Analysis/PathSensitive/AnalysisContext.h @@ -15,9 +15,10 @@ #ifndef LLVM_CLANG_ANALYSIS_ANALYSISCONTEXT_H #define LLVM_CLANG_ANALYSIS_ANALYSISCONTEXT_H -#include "clang/AST/Stmt.h" +#include "clang/AST/Decl.h" #include "llvm/ADT/OwningPtr.h" #include "llvm/ADT/FoldingSet.h" +#include "llvm/ADT/PointerUnion.h" #include "llvm/ADT/DenseMap.h" #include "llvm/Support/Allocator.h" @@ -29,7 +30,10 @@ class CFG; class LiveVariables; class ParentMap; class ImplicitParamDecl; - +class LocationContextManager; +class BlockDataRegion; +class StackFrameContext; + /// AnalysisContext contains the context data for the function or method under /// analysis. class AnalysisContext { @@ -78,7 +82,7 @@ class AnalysisContextManager { class LocationContext : public llvm::FoldingSetNode { public: - enum ContextKind { StackFrame, Scope }; + enum ContextKind { StackFrame, Scope, Block }; private: ContextKind Kind; @@ -91,7 +95,7 @@ class LocationContext : public llvm::FoldingSetNode { : Kind(k), Ctx(ctx), Parent(parent) {} public: - virtual ~LocationContext() {} + virtual ~LocationContext(); ContextKind getKind() const { return Kind; } @@ -114,36 +118,42 @@ class LocationContext : public llvm::FoldingSetNode { const ImplicitParamDecl *getSelfDecl() const { return Ctx->getSelfDecl(); } + + const StackFrameContext *getCurrentStackFrame() const; + const StackFrameContext * + getStackFrameForDeclContext(const DeclContext *DC) const; - virtual void Profile(llvm::FoldingSetNodeID &ID) { - Profile(ID, Kind, Ctx, Parent); - } - - static void Profile(llvm::FoldingSetNodeID &ID, ContextKind k, - AnalysisContext *ctx, const LocationContext *parent); + virtual void Profile(llvm::FoldingSetNodeID &ID) = 0; static bool classof(const LocationContext*) { return true; } + +public: + static void ProfileCommon(llvm::FoldingSetNodeID &ID, + ContextKind ck, + AnalysisContext *ctx, + const LocationContext *parent, + const void* data); }; class StackFrameContext : public LocationContext { const Stmt *CallSite; -public: + friend class LocationContextManager; StackFrameContext(AnalysisContext *ctx, const LocationContext *parent, const Stmt *s) : LocationContext(StackFrame, ctx, parent), CallSite(s) {} + +public: + ~StackFrameContext() {} + + const Stmt *getCallSite() const { return CallSite; } + + void Profile(llvm::FoldingSetNodeID &ID); - virtual ~StackFrameContext() {} - - - Stmt const *getCallSite() const { return CallSite; } - - virtual void Profile(llvm::FoldingSetNodeID &ID) { - Profile(ID, getAnalysisContext(), getParent(), CallSite); - } - static void Profile(llvm::FoldingSetNodeID &ID, AnalysisContext *ctx, - const LocationContext *parent, const Stmt *s); + const LocationContext *parent, const Stmt *s) { + ProfileCommon(ID, StackFrame, ctx, parent, s); + } static bool classof(const LocationContext* Ctx) { return Ctx->getKind() == StackFrame; @@ -152,41 +162,91 @@ class StackFrameContext : public LocationContext { class ScopeContext : public LocationContext { const Stmt *Enter; - -public: + + friend class LocationContextManager; ScopeContext(AnalysisContext *ctx, const LocationContext *parent, const Stmt *s) : LocationContext(Scope, ctx, parent), Enter(s) {} - - virtual ~ScopeContext() {} - virtual void Profile(llvm::FoldingSetNodeID &ID) { - Profile(ID, getAnalysisContext(), getParent(), Enter); - } +public: + ~ScopeContext() {} + + void Profile(llvm::FoldingSetNodeID &ID); static void Profile(llvm::FoldingSetNodeID &ID, AnalysisContext *ctx, - const LocationContext *parent, const Stmt *s); + const LocationContext *parent, const Stmt *s) { + ProfileCommon(ID, Scope, ctx, parent, s); + } static bool classof(const LocationContext* Ctx) { return Ctx->getKind() == Scope; } }; +class BlockInvocationContext : public LocationContext { + llvm::PointerUnion Data; + + friend class LocationContextManager; + + BlockInvocationContext(AnalysisContext *ctx, const LocationContext *parent, + const BlockDataRegion *br) + : LocationContext(Block, ctx, parent), Data(br) {} + + BlockInvocationContext(AnalysisContext *ctx, const LocationContext *parent, + const BlockDecl *bd) + : LocationContext(Block, ctx, parent), Data(bd) {} + +public: + ~BlockInvocationContext() {} + + const BlockDataRegion *getBlockRegion() const { + return Data.is() ? + Data.get() : 0; + } + + const BlockDecl *getBlockDecl() const; + + void Profile(llvm::FoldingSetNodeID &ID); + + static void Profile(llvm::FoldingSetNodeID &ID, AnalysisContext *ctx, + const LocationContext *parent, const BlockDataRegion *br){ + ProfileCommon(ID, Block, ctx, parent, br); + } + + static void Profile(llvm::FoldingSetNodeID &ID, AnalysisContext *ctx, + const LocationContext *parent, const BlockDecl *bd) { + ProfileCommon(ID, Block, ctx, parent, bd); + } + + static bool classof(const LocationContext* Ctx) { + return Ctx->getKind() == Block; + } +}; + class LocationContextManager { llvm::FoldingSet Contexts; - public: ~LocationContextManager(); - StackFrameContext *getStackFrame(AnalysisContext *ctx, - const LocationContext *parent, - const Stmt *s); + const StackFrameContext *getStackFrame(AnalysisContext *ctx, + const LocationContext *parent, + const Stmt *s); - ScopeContext *getScope(AnalysisContext *ctx, const LocationContext *parent, - const Stmt *s); + const ScopeContext *getScope(AnalysisContext *ctx, + const LocationContext *parent, + const Stmt *s); + + const BlockInvocationContext * + getBlockInvocation(AnalysisContext *ctx, const LocationContext *parent, + const BlockDataRegion *BR); /// Discard all previously created LocationContext objects. void clear(); +private: + template + const LOC *getLocationContext(AnalysisContext *ctx, + const LocationContext *parent, + const DATA *d); }; } // end clang namespace diff --git a/include/clang/Analysis/PathSensitive/AnalysisManager.h b/include/clang/Analysis/PathSensitive/AnalysisManager.h index 18eae9ac9f14..9ef5cce1002b 100644 --- a/include/clang/Analysis/PathSensitive/AnalysisManager.h +++ b/include/clang/Analysis/PathSensitive/AnalysisManager.h @@ -56,8 +56,7 @@ class AnalysisManager : public BugReporterData { const LangOptions &lang, PathDiagnosticClient *pd, StoreManagerCreator storemgr, ConstraintManagerCreator constraintmgr, - bool displayProgress, bool vizdot, bool vizubi, - bool purge, bool eager, bool trim) + bool vizdot, bool vizubi, bool purge, bool eager, bool trim) : Ctx(ctx), Diags(diags), LangInfo(lang), PD(pd), CreateStoreMgr(storemgr), CreateConstraintMgr(constraintmgr), @@ -132,7 +131,7 @@ class AnalysisManager : public BugReporterData { } // Get the top level stack frame. - StackFrameContext *getStackFrame(Decl const *D) { + const StackFrameContext *getStackFrame(Decl const *D) { return LocCtxMgr.getStackFrame(AnaCtxMgr.getContext(D), 0, 0); } diff --git a/include/clang/Analysis/PathSensitive/BugType.h b/include/clang/Analysis/PathSensitive/BugType.h index 4f1523a5440d..b75a8189e54c 100644 --- a/include/clang/Analysis/PathSensitive/BugType.h +++ b/include/clang/Analysis/PathSensitive/BugType.h @@ -14,6 +14,7 @@ #ifndef LLVM_CLANG_ANALYSIS_BUGTYPE #define LLVM_CLANG_ANALYSIS_BUGTYPE +#include "clang/Analysis/PathSensitive/BugReporter.h" #include #include diff --git a/include/clang/Analysis/PathSensitive/Checker.h b/include/clang/Analysis/PathSensitive/Checker.h index 91a4b6d1b1eb..a625a7a25690 100644 --- a/include/clang/Analysis/PathSensitive/Checker.h +++ b/include/clang/Analysis/PathSensitive/Checker.h @@ -39,7 +39,7 @@ class CheckerContext { SaveAndRestore OldTag; SaveAndRestore OldPointKind; SaveOr OldHasGen; - const GRState *state; + const GRState *ST; const Stmt *statement; const unsigned size; bool DoneEvaluating; // FIXME: This is not a permanent API change. @@ -53,22 +53,14 @@ class CheckerContext { OldTag(B.Tag, tag), OldPointKind(B.PointKind, K), OldHasGen(B.HasGeneratedNode), - state(st), statement(stmt), size(Dst.size()), - DoneEvaluating(false) {} + ST(st), statement(stmt), size(Dst.size()) {} ~CheckerContext(); - - // FIXME: This were added to support CallAndMessageChecker to indicating - // to GRExprEngine to "stop evaluating" a message expression under certain - // cases. This is *not* meant to be a permanent API change, and was added - // to aid in the transition of removing logic for checks from GRExprEngine. - void setDoneEvaluating() { - DoneEvaluating = true; + + GRExprEngine &getEngine() { + return Eng; } - bool isDoneEvaluating() const { - return DoneEvaluating; - } - + ConstraintManager &getConstraintManager() { return Eng.getConstraintManager(); } @@ -80,7 +72,7 @@ class CheckerContext { ExplodedNodeSet &getNodeSet() { return Dst; } GRStmtNodeBuilder &getNodeBuilder() { return B; } ExplodedNode *&getPredecessor() { return Pred; } - const GRState *getState() { return state ? state : B.GetState(Pred); } + const GRState *getState() { return ST ? ST : B.GetState(Pred); } ASTContext &getASTContext() { return Eng.getContext(); @@ -98,6 +90,10 @@ class CheckerContext { return Eng.getValueManager(); } + SValuator &getSValuator() { + return Eng.getSValuator(); + } + ExplodedNode *GenerateNode(bool autoTransition = true) { assert(statement && "Only transitions with statements currently supported"); ExplodedNode *N = GenerateNodeImpl(statement, getState(), false); @@ -115,6 +111,15 @@ class CheckerContext { return N; } + ExplodedNode *GenerateNode(const GRState *state, ExplodedNode *pred, + bool autoTransition = true) { + assert(statement && "Only transitions with statements currently supported"); + ExplodedNode *N = GenerateNodeImpl(statement, state, pred, false); + if (N && autoTransition) + addTransition(N); + return N; + } + ExplodedNode *GenerateNode(const GRState *state, bool autoTransition = true) { assert(statement && "Only transitions with statements currently supported"); ExplodedNode *N = GenerateNodeImpl(statement, state, false); @@ -138,8 +143,7 @@ class CheckerContext { void addTransition(const GRState *state) { assert(state); - if (state != getState() || - (state && state != B.GetState(Pred))) + if (state != getState() || (ST && ST != B.GetState(Pred))) GenerateNode(state, true); else Dst.Add(Pred); @@ -157,7 +161,14 @@ class CheckerContext { node->markAsSink(); return node; } - + + ExplodedNode *GenerateNodeImpl(const Stmt* stmt, const GRState *state, + ExplodedNode *pred, bool markAsSink) { + ExplodedNode *node = B.generateNode(stmt, state, pred); + if (markAsSink && node) + node->markAsSink(); + return node; + } }; class Checker { @@ -165,7 +176,7 @@ class Checker { friend class GRExprEngine; // FIXME: Remove the 'tag' option. - bool GR_Visit(ExplodedNodeSet &Dst, + void GR_Visit(ExplodedNodeSet &Dst, GRStmtNodeBuilder &Builder, GRExprEngine &Eng, const Stmt *S, @@ -177,7 +188,22 @@ class Checker { _PreVisit(C, S); else _PostVisit(C, S); - return C.isDoneEvaluating(); + } + + bool GR_EvalNilReceiver(ExplodedNodeSet &Dst, GRStmtNodeBuilder &Builder, + GRExprEngine &Eng, const ObjCMessageExpr *ME, + ExplodedNode *Pred, const GRState *state, void *tag) { + CheckerContext C(Dst, Builder, Eng, Pred, tag, ProgramPoint::PostStmtKind, + ME, state); + return EvalNilReceiver(C, ME); + } + + bool GR_EvalCallExpr(ExplodedNodeSet &Dst, GRStmtNodeBuilder &Builder, + GRExprEngine &Eng, const CallExpr *CE, + ExplodedNode *Pred, void *tag) { + CheckerContext C(Dst, Builder, Eng, Pred, tag, ProgramPoint::PostStmtKind, + CE); + return EvalCallExpr(C, CE); } // FIXME: Remove the 'tag' option. @@ -231,6 +257,14 @@ class Checker { virtual void VisitBranchCondition(GRBranchNodeBuilder &Builder, GRExprEngine &Eng, Stmt *Condition, void *tag) {} + + virtual bool EvalNilReceiver(CheckerContext &C, const ObjCMessageExpr *ME) { + return false; + } + + virtual bool EvalCallExpr(CheckerContext &C, const CallExpr *CE) { + return false; + } }; } // end clang namespace diff --git a/include/clang/Analysis/PathSensitive/GRExprEngine.h b/include/clang/Analysis/PathSensitive/GRExprEngine.h index a7302c0602ec..8b20a823c6a1 100644 --- a/include/clang/Analysis/PathSensitive/GRExprEngine.h +++ b/include/clang/Analysis/PathSensitive/GRExprEngine.h @@ -209,8 +209,17 @@ class GRExprEngine : public GRSubEngine { protected: /// CheckerVisit - Dispatcher for performing checker-specific logic /// at specific statements. - bool CheckerVisit(Stmt *S, ExplodedNodeSet &Dst, ExplodedNodeSet &Src, + void CheckerVisit(Stmt *S, ExplodedNodeSet &Dst, ExplodedNodeSet &Src, bool isPrevisit); + + bool CheckerEvalCall(const CallExpr *CE, + ExplodedNodeSet &Dst, + ExplodedNode *Pred); + + void CheckerEvalNilReceiver(const ObjCMessageExpr *ME, + ExplodedNodeSet &Dst, + const GRState *state, + ExplodedNode *Pred); void CheckerVisitBind(const Stmt *AssignE, const Stmt *StoreE, ExplodedNodeSet &Dst, ExplodedNodeSet &Src, @@ -272,6 +281,13 @@ class GRExprEngine : public GRSubEngine { void VisitDeclRefExpr(DeclRefExpr* DR, ExplodedNode* Pred, ExplodedNodeSet& Dst, bool asLValue); + /// VisitBlockDeclRefExpr - Transfer function logic for BlockDeclRefExprs. + void VisitBlockDeclRefExpr(BlockDeclRefExpr* DR, ExplodedNode* Pred, + ExplodedNodeSet& Dst, bool asLValue); + + void VisitCommonDeclRefExpr(Expr* DR, const NamedDecl *D,ExplodedNode* Pred, + ExplodedNodeSet& Dst, bool asLValue); + /// VisitDeclStmt - Transfer function logic for DeclStmts. void VisitDeclStmt(DeclStmt* DS, ExplodedNode* Pred, ExplodedNodeSet& Dst); @@ -358,9 +374,10 @@ class GRExprEngine : public GRSubEngine { } protected: - void EvalObjCMessageExpr(ExplodedNodeSet& Dst, ObjCMessageExpr* ME, ExplodedNode* Pred) { + void EvalObjCMessageExpr(ExplodedNodeSet& Dst, ObjCMessageExpr* ME, + ExplodedNode* Pred, const GRState *state) { assert (Builder && "GRStmtNodeBuilder must be defined."); - getTF().EvalObjCMessageExpr(Dst, *this, *Builder, ME, Pred); + getTF().EvalObjCMessageExpr(Dst, *this, *Builder, ME, Pred, state); } const GRState* MarkBranch(const GRState* St, Stmt* Terminator, diff --git a/include/clang/Analysis/PathSensitive/GRState.h b/include/clang/Analysis/PathSensitive/GRState.h index d8bc2411750f..421ebbf9bd5e 100644 --- a/include/clang/Analysis/PathSensitive/GRState.h +++ b/include/clang/Analysis/PathSensitive/GRState.h @@ -217,6 +217,7 @@ class GRState : public llvm::FoldingSetNode { /// for the compound literal and 'BegInit' and 'EndInit' represent an /// array of initializer values. const GRState* bindCompoundLiteral(const CompoundLiteralExpr* CL, + const LocationContext *LC, SVal V) const; const GRState *BindExpr(const Stmt *S, SVal V, bool Invalidate = true) const; @@ -237,7 +238,8 @@ class GRState : public llvm::FoldingSetNode { /// Get the lvalue for a StringLiteral. SVal getLValue(const StringLiteral *literal) const; - SVal getLValue(const CompoundLiteralExpr *literal) const; + SVal getLValue(const CompoundLiteralExpr *literal, + const LocationContext *LC) const; /// Get the lvalue for an ivar reference. SVal getLValue(const ObjCIvarDecl *decl, SVal base) const; @@ -609,9 +611,10 @@ inline const GRState *GRState::AssumeInBound(DefinedOrUnknownSVal Idx, cast(UpperBound), Assumption); } -inline const GRState *GRState::bindCompoundLiteral(const CompoundLiteralExpr* CL, - SVal V) const { - return getStateManager().StoreMgr->BindCompoundLiteral(this, CL, V); +inline const GRState * +GRState::bindCompoundLiteral(const CompoundLiteralExpr* CL, + const LocationContext *LC, SVal V) const { + return getStateManager().StoreMgr->BindCompoundLiteral(this, CL, LC, V); } inline const GRState *GRState::bindDecl(const VarRegion* VR, SVal IVal) const { @@ -639,8 +642,9 @@ inline SVal GRState::getLValue(const StringLiteral *literal) const { return getStateManager().StoreMgr->getLValueString(literal); } -inline SVal GRState::getLValue(const CompoundLiteralExpr *literal) const { - return getStateManager().StoreMgr->getLValueCompoundLiteral(literal); +inline SVal GRState::getLValue(const CompoundLiteralExpr *literal, + const LocationContext *LC) const { + return getStateManager().StoreMgr->getLValueCompoundLiteral(literal, LC); } inline SVal GRState::getLValue(const ObjCIvarDecl *D, SVal Base) const { diff --git a/include/clang/Analysis/PathSensitive/GRTransferFuncs.h b/include/clang/Analysis/PathSensitive/GRTransferFuncs.h index 40c1ed3224f4..2594618c16db 100644 --- a/include/clang/Analysis/PathSensitive/GRTransferFuncs.h +++ b/include/clang/Analysis/PathSensitive/GRTransferFuncs.h @@ -47,7 +47,8 @@ class GRTransferFuncs { GRExprEngine& Engine, GRStmtNodeBuilder& Builder, ObjCMessageExpr* ME, - ExplodedNode* Pred) {} + ExplodedNode* Pred, + const GRState *state) {} // Stores. diff --git a/include/clang/Analysis/PathSensitive/MemRegion.h b/include/clang/Analysis/PathSensitive/MemRegion.h index ed964978a44a..2fe5ea0cf3ab 100644 --- a/include/clang/Analysis/PathSensitive/MemRegion.h +++ b/include/clang/Analysis/PathSensitive/MemRegion.h @@ -35,6 +35,7 @@ namespace clang { class MemRegionManager; class MemSpaceRegion; class LocationContext; +class StackFrameContext; class VarRegion; //===----------------------------------------------------------------------===// @@ -45,22 +46,37 @@ class VarRegion; class MemRegion : public llvm::FoldingSetNode { friend class MemRegionManager; public: - enum Kind { MemSpaceRegionKind, - SymbolicRegionKind, - AllocaRegionKind, - // Typed regions. - BEG_TYPED_REGIONS, - FunctionTextRegionKind, - BlockTextRegionKind, - BlockDataRegionKind, - CompoundLiteralRegionKind, - StringRegionKind, ElementRegionKind, - // Decl Regions. - BEG_DECL_REGIONS, - VarRegionKind, FieldRegionKind, - ObjCIvarRegionKind, ObjCObjectRegionKind, - END_DECL_REGIONS, - END_TYPED_REGIONS }; + enum Kind { + // Memory spaces. + BEG_MEMSPACES, + GenericMemSpaceRegionKind = BEG_MEMSPACES, + StackLocalsSpaceRegionKind, + StackArgumentsSpaceRegionKind, + HeapSpaceRegionKind, + UnknownSpaceRegionKind, + GlobalsSpaceRegionKind, + END_MEMSPACES = GlobalsSpaceRegionKind, + // Untyped regions. + SymbolicRegionKind, + AllocaRegionKind, + // Typed regions. + BEG_TYPED_REGIONS, + FunctionTextRegionKind = BEG_TYPED_REGIONS, + BlockTextRegionKind, + BlockDataRegionKind, + CompoundLiteralRegionKind, + StringRegionKind, + ElementRegionKind, + // Decl Regions. + BEG_DECL_REGIONS, + VarRegionKind = BEG_DECL_REGIONS, + FieldRegionKind, + ObjCIvarRegionKind, + ObjCObjectRegionKind, + END_DECL_REGIONS = ObjCObjectRegionKind, + END_TYPED_REGIONS = END_DECL_REGIONS + }; + private: const Kind kind; @@ -111,25 +127,102 @@ class MemRegion : public llvm::FoldingSetNode { /// MemSpaceRegion - A memory region that represents and "memory space"; /// for example, the set of global variables, the stack frame, etc. class MemSpaceRegion : public MemRegion { - friend class MemRegionManager; - protected: + friend class MemRegionManager; + MemRegionManager *Mgr; - MemSpaceRegion(MemRegionManager *mgr) : MemRegion(MemSpaceRegionKind), - Mgr(mgr) {} - - MemRegionManager* getMemRegionManager() const { - return Mgr; + MemSpaceRegion(MemRegionManager *mgr, Kind k = GenericMemSpaceRegionKind) + : MemRegion(k), Mgr(mgr) { + assert(classof(this)); } + MemRegionManager* getMemRegionManager() const { return Mgr; } + public: - void Profile(llvm::FoldingSetNodeID& ID) const; - bool isBoundable() const { return false; } + + void Profile(llvm::FoldingSetNodeID &ID) const; - static bool classof(const MemRegion* R) { - return R->getKind() == MemSpaceRegionKind; + static bool classof(const MemRegion *R) { + Kind k = R->getKind(); + return k >= BEG_MEMSPACES && k <= END_MEMSPACES; + } +}; + +class GlobalsSpaceRegion : public MemSpaceRegion { + friend class MemRegionManager; + + GlobalsSpaceRegion(MemRegionManager *mgr) + : MemSpaceRegion(mgr, GlobalsSpaceRegionKind) {} +public: + static bool classof(const MemRegion *R) { + return R->getKind() == GlobalsSpaceRegionKind; + } +}; + +class HeapSpaceRegion : public MemSpaceRegion { + friend class MemRegionManager; + + HeapSpaceRegion(MemRegionManager *mgr) + : MemSpaceRegion(mgr, HeapSpaceRegionKind) {} +public: + static bool classof(const MemRegion *R) { + return R->getKind() == HeapSpaceRegionKind; + } +}; + +class UnknownSpaceRegion : public MemSpaceRegion { + friend class MemRegionManager; + UnknownSpaceRegion(MemRegionManager *mgr) + : MemSpaceRegion(mgr, UnknownSpaceRegionKind) {} +public: + static bool classof(const MemRegion *R) { + return R->getKind() == UnknownSpaceRegionKind; + } +}; + +class StackSpaceRegion : public MemSpaceRegion { +private: + const StackFrameContext *SFC; + +protected: + StackSpaceRegion(MemRegionManager *mgr, Kind k, const StackFrameContext *sfc) + : MemSpaceRegion(mgr, k), SFC(sfc) { + assert(classof(this)); + } + +public: + const StackFrameContext *getStackFrame() const { return SFC; } + + void Profile(llvm::FoldingSetNodeID &ID) const; + + static bool classof(const MemRegion *R) { + Kind k = R->getKind(); + return k >= StackLocalsSpaceRegionKind && + k <= StackArgumentsSpaceRegionKind; + } +}; + +class StackLocalsSpaceRegion : public StackSpaceRegion { +private: + friend class MemRegionManager; + StackLocalsSpaceRegion(MemRegionManager *mgr, const StackFrameContext *sfc) + : StackSpaceRegion(mgr, StackLocalsSpaceRegionKind, sfc) {} +public: + static bool classof(const MemRegion *R) { + return R->getKind() == StackLocalsSpaceRegionKind; + } +}; + +class StackArgumentsSpaceRegion : public StackSpaceRegion { +private: + friend class MemRegionManager; + StackArgumentsSpaceRegion(MemRegionManager *mgr, const StackFrameContext *sfc) + : StackSpaceRegion(mgr, StackArgumentsSpaceRegionKind, sfc) {} +public: + static bool classof(const MemRegion *R) { + return R->getKind() == StackArgumentsSpaceRegionKind; } }; @@ -149,7 +242,7 @@ class SubRegion : public MemRegion { bool isSubRegionOf(const MemRegion* R) const; static bool classof(const MemRegion* R) { - return R->getKind() > MemSpaceRegionKind; + return R->getKind() > END_MEMSPACES; } }; @@ -237,7 +330,7 @@ class TypedRegion : public SubRegion { static bool classof(const MemRegion* R) { unsigned k = R->getKind(); - return k > BEG_TYPED_REGIONS && k < END_TYPED_REGIONS; + return k >= BEG_TYPED_REGIONS && k <= END_TYPED_REGIONS; } }; @@ -295,12 +388,17 @@ class FunctionTextRegion : public CodeTextRegion { /// like a closure a block captures the values of externally referenced /// variables. class BlockTextRegion : public CodeTextRegion { + friend class MemRegionManager; + const BlockDecl *BD; + AnalysisContext *AC; CanQualType locTy; -public: - BlockTextRegion(const BlockDecl *bd, CanQualType lTy, const MemRegion* sreg) - : CodeTextRegion(sreg, BlockTextRegionKind), BD(bd), locTy(lTy) {} - + + BlockTextRegion(const BlockDecl *bd, CanQualType lTy, + AnalysisContext *ac, const MemRegion* sreg) + : CodeTextRegion(sreg, BlockTextRegionKind), BD(bd), AC(ac), locTy(lTy) {} + +public: QualType getLocationType(ASTContext &C) const { return locTy; } @@ -308,13 +406,16 @@ class BlockTextRegion : public CodeTextRegion { const BlockDecl *getDecl() const { return BD; } + + AnalysisContext *getAnalysisContext() const { return AC; } virtual void dumpToStream(llvm::raw_ostream& os) const; void Profile(llvm::FoldingSetNodeID& ID) const; static void ProfileRegion(llvm::FoldingSetNodeID& ID, const BlockDecl *BD, - CanQualType, const MemRegion*); + CanQualType, const AnalysisContext*, + const MemRegion*); static bool classof(const MemRegion* R) { return R->getKind() == BlockTextRegionKind; @@ -329,18 +430,45 @@ class BlockTextRegion : public CodeTextRegion { /// variables. /// BlockDataRegion - A region that represents code texts of blocks (closures). class BlockDataRegion : public SubRegion { + friend class MemRegionManager; const BlockTextRegion *BC; - const LocationContext *LC; + const LocationContext *LC; // Can be null */ void *ReferencedVars; -public: - BlockDataRegion(const BlockTextRegion *bc, - const LocationContext *lc, + + BlockDataRegion(const BlockTextRegion *bc, const LocationContext *lc, const MemRegion *sreg) : SubRegion(sreg, BlockDataRegionKind), BC(bc), LC(lc), ReferencedVars(0) {} +public: const BlockTextRegion *getCodeRegion() const { return BC; } - typedef const MemRegion * const * referenced_vars_iterator; + const BlockDecl *getDecl() const { return BC->getDecl(); } + + class referenced_vars_iterator { + const MemRegion * const *R; + public: + explicit referenced_vars_iterator(const MemRegion * const *r) : R(r) {} + + operator const MemRegion * const *() const { + return R; + } + + const VarRegion* operator*() const { + return cast(*R); + } + + bool operator==(const referenced_vars_iterator &I) const { + return I.R == R; + } + bool operator!=(const referenced_vars_iterator &I) const { + return I.R != R; + } + referenced_vars_iterator& operator++() { + ++R; + return *this; + } + }; + referenced_vars_iterator referenced_vars_begin() const; referenced_vars_iterator referenced_vars_end() const; @@ -348,9 +476,8 @@ class BlockDataRegion : public SubRegion { void Profile(llvm::FoldingSetNodeID& ID) const; - static void ProfileRegion(llvm::FoldingSetNodeID& ID, - const BlockTextRegion *BC, - const LocationContext *LC, const MemRegion *); + static void ProfileRegion(llvm::FoldingSetNodeID&, const BlockTextRegion *, + const LocationContext *, const MemRegion *); static bool classof(const MemRegion* R) { return R->getKind() == BlockDataRegionKind; @@ -473,25 +600,20 @@ class DeclRegion : public TypedRegion { static bool classof(const MemRegion* R) { unsigned k = R->getKind(); - return k > BEG_DECL_REGIONS && k < END_DECL_REGIONS; + return k >= BEG_DECL_REGIONS && k <= END_DECL_REGIONS; } }; class VarRegion : public DeclRegion { friend class MemRegionManager; - // Data. - const LocationContext *LC; - // Constructors and private methods. - VarRegion(const VarDecl* vd, const LocationContext *lC, const MemRegion* sReg) - : DeclRegion(vd, sReg, VarRegionKind), LC(lC) {} + VarRegion(const VarDecl* vd, const MemRegion* sReg) + : DeclRegion(vd, sReg, VarRegionKind) {} static void ProfileRegion(llvm::FoldingSetNodeID& ID, const VarDecl* VD, - const LocationContext *LC, const MemRegion *superRegion) { DeclRegion::ProfileRegion(ID, VD, superRegion, VarRegionKind); - ID.AddPointer(LC); } void Profile(llvm::FoldingSetNodeID& ID) const; @@ -499,8 +621,8 @@ class VarRegion : public DeclRegion { public: const VarDecl *getDecl() const { return cast(D); } - const LocationContext *getLocationContext() const { return LC; } - + const StackFrameContext *getStackFrame() const; + QualType getValueType(ASTContext& C) const { // FIXME: We can cache this if needed. return C.getCanonicalType(getDecl()->getType()); @@ -647,17 +769,24 @@ class MemRegionManager { llvm::BumpPtrAllocator& A; llvm::FoldingSet Regions; - MemSpaceRegion *globals; - MemSpaceRegion *stack; - MemSpaceRegion *stackArguments; - MemSpaceRegion *heap; - MemSpaceRegion *unknown; + GlobalsSpaceRegion *globals; + + const StackFrameContext *cachedStackLocalsFrame; + StackLocalsSpaceRegion *cachedStackLocalsRegion; + + const StackFrameContext *cachedStackArgumentsFrame; + StackArgumentsSpaceRegion *cachedStackArgumentsRegion; + + HeapSpaceRegion *heap; + UnknownSpaceRegion *unknown; MemSpaceRegion *code; public: MemRegionManager(ASTContext &c, llvm::BumpPtrAllocator& a) - : C(c), A(a), globals(0), stack(0), stackArguments(0), heap(0), - unknown(0), code(0) {} + : C(c), A(a), globals(0), + cachedStackLocalsFrame(0), cachedStackLocalsRegion(0), + cachedStackArgumentsFrame(0), cachedStackArgumentsRegion(0), + heap(0), unknown(0), code(0) {} ~MemRegionManager(); @@ -665,52 +794,60 @@ class MemRegionManager { llvm::BumpPtrAllocator &getAllocator() { return A; } - /// getStackRegion - Retrieve the memory region associated with the - /// current stack frame. - MemSpaceRegion *getStackRegion(); + /// getStackLocalsRegion - Retrieve the memory region associated with the + /// specified stack frame. + const StackLocalsSpaceRegion * + getStackLocalsRegion(const StackFrameContext *STC); /// getStackArgumentsRegion - Retrieve the memory region associated with - /// function/method arguments of the current stack frame. - MemSpaceRegion *getStackArgumentsRegion(); + /// function/method arguments of the specified stack frame. + const StackArgumentsSpaceRegion * + getStackArgumentsRegion(const StackFrameContext *STC); /// getGlobalsRegion - Retrieve the memory region associated with /// all global variables. - MemSpaceRegion *getGlobalsRegion(); + const GlobalsSpaceRegion *getGlobalsRegion(); /// getHeapRegion - Retrieve the memory region associated with the /// generic "heap". - MemSpaceRegion *getHeapRegion(); + const HeapSpaceRegion *getHeapRegion(); /// getUnknownRegion - Retrieve the memory region associated with unknown /// memory space. - MemSpaceRegion *getUnknownRegion(); + const MemSpaceRegion *getUnknownRegion(); - MemSpaceRegion *getCodeRegion(); + const MemSpaceRegion *getCodeRegion(); /// getAllocaRegion - Retrieve a region associated with a call to alloca(). - AllocaRegion *getAllocaRegion(const Expr* Ex, unsigned Cnt); + const AllocaRegion *getAllocaRegion(const Expr* Ex, unsigned Cnt, + const LocationContext *LC); /// getCompoundLiteralRegion - Retrieve the region associated with a /// given CompoundLiteral. - CompoundLiteralRegion* - getCompoundLiteralRegion(const CompoundLiteralExpr* CL); + const CompoundLiteralRegion* + getCompoundLiteralRegion(const CompoundLiteralExpr* CL, + const LocationContext *LC); /// getSymbolicRegion - Retrieve or create a "symbolic" memory region. - SymbolicRegion* getSymbolicRegion(SymbolRef sym); + const SymbolicRegion* getSymbolicRegion(SymbolRef sym); - StringRegion* getStringRegion(const StringLiteral* Str); + const StringRegion* getStringRegion(const StringLiteral* Str); /// getVarRegion - Retrieve or create the memory region associated with /// a specified VarDecl and LocationContext. - VarRegion* getVarRegion(const VarDecl *D, const LocationContext *LC); + const VarRegion* getVarRegion(const VarDecl *D, const LocationContext *LC); + /// getVarRegion - Retrieve or create the memory region associated with + /// a specified VarDecl and super region. + const VarRegion* getVarRegion(const VarDecl *D, const MemRegion *superR); + /// getElementRegion - Retrieve the memory region associated with the /// associated element type, index, and super region. - ElementRegion *getElementRegion(QualType elementType, SVal Idx, + const ElementRegion *getElementRegion(QualType elementType, SVal Idx, const MemRegion *superRegion, ASTContext &Ctx); - ElementRegion *getElementRegionWithSuper(const ElementRegion *ER, + const ElementRegion *getElementRegionWithSuper(const ElementRegion *ER, const MemRegion *superRegion) { return getElementRegion(ER->getElementType(), ER->getIndex(), superRegion, ER->getContext()); @@ -720,31 +857,44 @@ class MemRegionManager { /// a specified FieldDecl. 'superRegion' corresponds to the containing /// memory region (which typically represents the memory representing /// a structure or class). - FieldRegion *getFieldRegion(const FieldDecl* fd, - const MemRegion* superRegion); + const FieldRegion *getFieldRegion(const FieldDecl* fd, + const MemRegion* superRegion); - FieldRegion *getFieldRegionWithSuper(const FieldRegion *FR, - const MemRegion *superRegion) { + const FieldRegion *getFieldRegionWithSuper(const FieldRegion *FR, + const MemRegion *superRegion) { return getFieldRegion(FR->getDecl(), superRegion); } /// getObjCObjectRegion - Retrieve or create the memory region associated with /// the instance of a specified Objective-C class. - ObjCObjectRegion* getObjCObjectRegion(const ObjCInterfaceDecl* ID, - const MemRegion* superRegion); + const ObjCObjectRegion* getObjCObjectRegion(const ObjCInterfaceDecl* ID, + const MemRegion* superRegion); /// getObjCIvarRegion - Retrieve or create the memory region associated with /// a specified Objective-c instance variable. 'superRegion' corresponds /// to the containing region (which typically represents the Objective-C /// object). - ObjCIvarRegion *getObjCIvarRegion(const ObjCIvarDecl* ivd, - const MemRegion* superRegion); + const ObjCIvarRegion *getObjCIvarRegion(const ObjCIvarDecl* ivd, + const MemRegion* superRegion); - FunctionTextRegion *getFunctionTextRegion(const FunctionDecl *FD); - BlockTextRegion *getBlockTextRegion(const BlockDecl *BD, CanQualType locTy); - BlockDataRegion *getBlockDataRegion(const BlockTextRegion *bc, - const LocationContext *lc); + const FunctionTextRegion *getFunctionTextRegion(const FunctionDecl *FD); + const BlockTextRegion *getBlockTextRegion(const BlockDecl *BD, + CanQualType locTy, + AnalysisContext *AC); + + /// getBlockDataRegion - Get the memory region associated with an instance + /// of a block. Unlike many other MemRegions, the LocationContext* + /// argument is allowed to be NULL for cases where we have no known + /// context. + const BlockDataRegion *getBlockDataRegion(const BlockTextRegion *bc, + const LocationContext *lc = NULL); + bool isGlobalsRegion(const MemRegion* R) { + assert(R); + return R == globals; + } + +private: template RegionTy* getRegion(const A1 a1); @@ -758,13 +908,15 @@ class MemRegionManager { RegionTy* getSubRegion(const A1 a1, const A2 a2, const MemRegion* superRegion); - bool isGlobalsRegion(const MemRegion* R) { - assert(R); - return R == globals; - } - -private: - MemSpaceRegion* LazyAllocate(MemSpaceRegion*& region); + template + RegionTy* getSubRegion(const A1 a1, const A2 a2, const A3 a3, + const MemRegion* superRegion); + + template + const REG* LazyAllocate(REG*& region); + + template + const REG* LazyAllocate(REG*& region, ARG a); }; //===----------------------------------------------------------------------===// @@ -774,157 +926,6 @@ class MemRegionManager { inline ASTContext& MemRegion::getContext() const { return getMemRegionManager()->getContext(); } - -template struct MemRegionManagerTrait; - -template -RegionTy* MemRegionManager::getRegion(const A1 a1) { - - const typename MemRegionManagerTrait::SuperRegionTy *superRegion = - MemRegionManagerTrait::getSuperRegion(*this, a1); - - llvm::FoldingSetNodeID ID; - RegionTy::ProfileRegion(ID, a1, superRegion); - void* InsertPos; - RegionTy* R = cast_or_null(Regions.FindNodeOrInsertPos(ID, - InsertPos)); - - if (!R) { - R = (RegionTy*) A.Allocate(); - new (R) RegionTy(a1, superRegion); - Regions.InsertNode(R, InsertPos); - } - - return R; -} - -template -RegionTy* MemRegionManager::getSubRegion(const A1 a1, - const MemRegion *superRegion) { - llvm::FoldingSetNodeID ID; - RegionTy::ProfileRegion(ID, a1, superRegion); - void* InsertPos; - RegionTy* R = cast_or_null(Regions.FindNodeOrInsertPos(ID, - InsertPos)); - - if (!R) { - R = (RegionTy*) A.Allocate(); - new (R) RegionTy(a1, superRegion); - Regions.InsertNode(R, InsertPos); - } - - return R; -} - -template -RegionTy* MemRegionManager::getRegion(const A1 a1, const A2 a2) { - - const typename MemRegionManagerTrait::SuperRegionTy *superRegion = - MemRegionManagerTrait::getSuperRegion(*this, a1, a2); - - llvm::FoldingSetNodeID ID; - RegionTy::ProfileRegion(ID, a1, a2, superRegion); - void* InsertPos; - RegionTy* R = cast_or_null(Regions.FindNodeOrInsertPos(ID, - InsertPos)); - - if (!R) { - R = (RegionTy*) A.Allocate(); - new (R) RegionTy(a1, a2, superRegion); - Regions.InsertNode(R, InsertPos); - } - - return R; -} - -template -RegionTy* MemRegionManager::getSubRegion(const A1 a1, const A2 a2, - const MemRegion *superRegion) { - - llvm::FoldingSetNodeID ID; - RegionTy::ProfileRegion(ID, a1, a2, superRegion); - void* InsertPos; - RegionTy* R = cast_or_null(Regions.FindNodeOrInsertPos(ID, - InsertPos)); - - if (!R) { - R = (RegionTy*) A.Allocate(); - new (R) RegionTy(a1, a2, superRegion); - Regions.InsertNode(R, InsertPos); - } - - return R; -} - -//===----------------------------------------------------------------------===// -// Traits for constructing regions. -//===----------------------------------------------------------------------===// - -template <> struct MemRegionManagerTrait { - typedef MemRegion SuperRegionTy; - static const SuperRegionTy* getSuperRegion(MemRegionManager& MRMgr, - const Expr *, unsigned) { - return MRMgr.getStackRegion(); - } -}; - -template <> struct MemRegionManagerTrait { - typedef MemRegion SuperRegionTy; - static const SuperRegionTy* getSuperRegion(MemRegionManager& MRMgr, - const CompoundLiteralExpr *CL) { - - return CL->isFileScope() ? MRMgr.getGlobalsRegion() - : MRMgr.getStackRegion(); - } -}; - -template <> struct MemRegionManagerTrait { - typedef MemSpaceRegion SuperRegionTy; - static const SuperRegionTy* getSuperRegion(MemRegionManager& MRMgr, - const StringLiteral*) { - return MRMgr.getGlobalsRegion(); - } -}; - -template <> struct MemRegionManagerTrait { - typedef MemRegion SuperRegionTy; - static const SuperRegionTy* getSuperRegion(MemRegionManager &MRMgr, - const VarDecl *D, - const LocationContext *LC) { - - // FIXME: Make stack regions have a location context? - - if (D->hasLocalStorage()) { - return isa(D) || isa(D) - ? MRMgr.getStackArgumentsRegion() : MRMgr.getStackRegion(); - } - - return MRMgr.getGlobalsRegion(); - } -}; - -template <> struct MemRegionManagerTrait { - typedef MemRegion SuperRegionTy; - static const SuperRegionTy* getSuperRegion(MemRegionManager& MRMgr, - SymbolRef) { - return MRMgr.getUnknownRegion(); - } -}; - -template<> struct MemRegionManagerTrait { - typedef MemSpaceRegion SuperRegionTy; - static const SuperRegionTy* getSuperRegion(MemRegionManager& MRMgr, - const FunctionDecl*) { - return MRMgr.getCodeRegion(); - } -}; -template<> struct MemRegionManagerTrait { - typedef MemSpaceRegion SuperRegionTy; - static const SuperRegionTy* getSuperRegion(MemRegionManager& MRMgr, - const BlockDecl*, CanQualType) { - return MRMgr.getCodeRegion(); - } -}; } // end clang namespace diff --git a/include/clang/Analysis/PathSensitive/Store.h b/include/clang/Analysis/PathSensitive/Store.h index 55fa83d9ecc3..648710f7ad12 100644 --- a/include/clang/Analysis/PathSensitive/Store.h +++ b/include/clang/Analysis/PathSensitive/Store.h @@ -73,8 +73,9 @@ class StoreManager { /// for the compound literal and 'BegInit' and 'EndInit' represent an /// array of initializer values. virtual const GRState *BindCompoundLiteral(const GRState *state, - const CompoundLiteralExpr* cl, - SVal v) = 0; + const CompoundLiteralExpr* cl, + const LocationContext *LC, + SVal v) = 0; /// getInitialStore - Returns the initial "empty" store representing the /// value bindings upon entry to an analyzed function. @@ -93,7 +94,8 @@ class StoreManager { virtual SVal getLValueString(const StringLiteral* sl) = 0; - virtual SVal getLValueCompoundLiteral(const CompoundLiteralExpr* cl) = 0; + SVal getLValueCompoundLiteral(const CompoundLiteralExpr* cl, + const LocationContext *LC); virtual SVal getLValueIvar(const ObjCIvarDecl* decl, SVal base) = 0; @@ -147,6 +149,12 @@ class StoreManager { const MemRegion *R, const Expr *E, unsigned Count, InvalidatedSymbols *IS) = 0; + + virtual const GRState *InvalidateRegions(const GRState *state, + const MemRegion * const *Begin, + const MemRegion * const *End, + const Expr *E, unsigned Count, + InvalidatedSymbols *IS); // FIXME: Make out-of-line. virtual const GRState *setExtent(const GRState *state, diff --git a/include/clang/Analysis/PathSensitive/SymbolManager.h b/include/clang/Analysis/PathSensitive/SymbolManager.h index 167a102e94ec..8eb319647953 100644 --- a/include/clang/Analysis/PathSensitive/SymbolManager.h +++ b/include/clang/Analysis/PathSensitive/SymbolManager.h @@ -28,10 +28,12 @@ namespace llvm { } namespace clang { - class MemRegion; - class TypedRegion; class ASTContext; class BasicValueFactory; + class MemRegion; + class TypedRegion; + class VarRegion; + class StackFrameContext; } namespace clang { @@ -332,10 +334,13 @@ class SymbolReaper { SetTy TheDead; LiveVariables& Liveness; SymbolManager& SymMgr; + const StackFrameContext *CurrentStackFrame; public: - SymbolReaper(LiveVariables& liveness, SymbolManager& symmgr) - : Liveness(liveness), SymMgr(symmgr) {} + SymbolReaper(LiveVariables& liveness, SymbolManager& symmgr, + const StackFrameContext *currentStackFrame) + : Liveness(liveness), SymMgr(symmgr), CurrentStackFrame(currentStackFrame) + {} ~SymbolReaper() {} @@ -345,10 +350,8 @@ class SymbolReaper { return Liveness.isLive(Loc, ExprVal); } - bool isLive(const Stmt* Loc, const VarDecl* VD) const { - return Liveness.isLive(Loc, VD); - } - + bool isLive(const Stmt* Loc, const VarRegion *VR) const; + void markLive(SymbolRef sym); bool maybeDead(SymbolRef sym); diff --git a/include/clang/Analysis/ProgramPoint.h b/include/clang/Analysis/ProgramPoint.h index 78827dfabe2f..5abe1abd5d39 100644 --- a/include/clang/Analysis/ProgramPoint.h +++ b/include/clang/Analysis/ProgramPoint.h @@ -333,10 +333,11 @@ static bool isEqual(const clang::ProgramPoint& L, return L == R; } -static bool isPod() { - return true; -} }; + +template <> +struct isPodLike { static const bool value = true; }; + } // end namespace llvm #endif diff --git a/include/clang/Analysis/Support/BumpVector.h b/include/clang/Analysis/Support/BumpVector.h index b23a80ed481a..48851d0f2637 100644 --- a/include/clang/Analysis/Support/BumpVector.h +++ b/include/clang/Analysis/Support/BumpVector.h @@ -166,7 +166,7 @@ class BumpVector { private: /// grow - double the size of the allocated memory, guaranteeing space for at /// least one more element or MinSize if specified. - void grow(BumpVectorContext &C, size_type MinSize = 0); + void grow(BumpVectorContext &C, size_type MinSize = 1); void construct_range(T *S, T *E, const T &Elt) { for (; S != E; ++S) diff --git a/include/clang/Basic/Builtins.def b/include/clang/Basic/Builtins.def index 98c703d94e92..e700cdeb5d6c 100644 --- a/include/clang/Basic/Builtins.def +++ b/include/clang/Basic/Builtins.def @@ -118,51 +118,51 @@ BUILTIN(__builtin_powf, "fff" , "nc") BUILTIN(__builtin_powl, "LdLdLd", "nc") // Standard unary libc/libm functions with double/float/long double variants: -BUILTIN(__builtin_acos , "dd" , "nc") -BUILTIN(__builtin_acosf, "ff" , "nc") -BUILTIN(__builtin_acosl, "LdLd", "nc") -BUILTIN(__builtin_asin , "dd" , "nc") -BUILTIN(__builtin_asinf, "ff" , "nc") -BUILTIN(__builtin_asinl, "LdLd", "nc") -BUILTIN(__builtin_atan , "dd" , "nc") -BUILTIN(__builtin_atanf, "ff" , "nc") -BUILTIN(__builtin_atanl, "LdLd", "nc") -BUILTIN(__builtin_ceil , "dd" , "nc") -BUILTIN(__builtin_ceilf, "ff" , "nc") -BUILTIN(__builtin_ceill, "LdLd", "nc") -BUILTIN(__builtin_cos , "dd" , "nc") -BUILTIN(__builtin_cosf, "ff" , "nc") -BUILTIN(__builtin_cosh , "dd" , "nc") -BUILTIN(__builtin_coshf, "ff" , "nc") -BUILTIN(__builtin_coshl, "LdLd", "nc") -BUILTIN(__builtin_cosl, "LdLd", "nc") -BUILTIN(__builtin_exp , "dd" , "nc") -BUILTIN(__builtin_expf, "ff" , "nc") -BUILTIN(__builtin_expl, "LdLd", "nc") -BUILTIN(__builtin_floor , "dd" , "nc") -BUILTIN(__builtin_floorf, "ff" , "nc") -BUILTIN(__builtin_floorl, "LdLd", "nc") -BUILTIN(__builtin_log , "dd" , "nc") -BUILTIN(__builtin_log10 , "dd" , "nc") -BUILTIN(__builtin_log10f, "ff" , "nc") -BUILTIN(__builtin_log10l, "LdLd", "nc") -BUILTIN(__builtin_logf, "ff" , "nc") -BUILTIN(__builtin_logl, "LdLd", "nc") -BUILTIN(__builtin_sin , "dd" , "nc") -BUILTIN(__builtin_sinf, "ff" , "nc") -BUILTIN(__builtin_sinh , "dd" , "nc") -BUILTIN(__builtin_sinhf, "ff" , "nc") -BUILTIN(__builtin_sinhl, "LdLd", "nc") -BUILTIN(__builtin_sinl, "LdLd", "nc") -BUILTIN(__builtin_sqrt , "dd" , "nc") -BUILTIN(__builtin_sqrtf, "ff" , "nc") -BUILTIN(__builtin_sqrtl, "LdLd", "nc") -BUILTIN(__builtin_tan , "dd" , "nc") -BUILTIN(__builtin_tanf, "ff" , "nc") -BUILTIN(__builtin_tanh , "dd" , "nc") -BUILTIN(__builtin_tanhf, "ff" , "nc") -BUILTIN(__builtin_tanhl, "LdLd", "nc") -BUILTIN(__builtin_tanl, "LdLd", "nc") +BUILTIN(__builtin_acos , "dd" , "Fnc") +BUILTIN(__builtin_acosf, "ff" , "Fnc") +BUILTIN(__builtin_acosl, "LdLd", "Fnc") +BUILTIN(__builtin_asin , "dd" , "Fnc") +BUILTIN(__builtin_asinf, "ff" , "Fnc") +BUILTIN(__builtin_asinl, "LdLd", "Fnc") +BUILTIN(__builtin_atan , "dd" , "Fnc") +BUILTIN(__builtin_atanf, "ff" , "Fnc") +BUILTIN(__builtin_atanl, "LdLd", "Fnc") +BUILTIN(__builtin_ceil , "dd" , "Fnc") +BUILTIN(__builtin_ceilf, "ff" , "Fnc") +BUILTIN(__builtin_ceill, "LdLd", "Fnc") +BUILTIN(__builtin_cos , "dd" , "Fnc") +BUILTIN(__builtin_cosf, "ff" , "Fnc") +BUILTIN(__builtin_cosh , "dd" , "Fnc") +BUILTIN(__builtin_coshf, "ff" , "Fnc") +BUILTIN(__builtin_coshl, "LdLd", "Fnc") +BUILTIN(__builtin_cosl, "LdLd", "Fnc") +BUILTIN(__builtin_exp , "dd" , "Fnc") +BUILTIN(__builtin_expf, "ff" , "Fnc") +BUILTIN(__builtin_expl, "LdLd", "Fnc") +BUILTIN(__builtin_floor , "dd" , "Fnc") +BUILTIN(__builtin_floorf, "ff" , "Fnc") +BUILTIN(__builtin_floorl, "LdLd", "Fnc") +BUILTIN(__builtin_log , "dd" , "Fnc") +BUILTIN(__builtin_log10 , "dd" , "Fnc") +BUILTIN(__builtin_log10f, "ff" , "Fnc") +BUILTIN(__builtin_log10l, "LdLd", "Fnc") +BUILTIN(__builtin_logf, "ff" , "Fnc") +BUILTIN(__builtin_logl, "LdLd", "Fnc") +BUILTIN(__builtin_sin , "dd" , "Fnc") +BUILTIN(__builtin_sinf, "ff" , "Fnc") +BUILTIN(__builtin_sinh , "dd" , "Fnc") +BUILTIN(__builtin_sinhf, "ff" , "Fnc") +BUILTIN(__builtin_sinhl, "LdLd", "Fnc") +BUILTIN(__builtin_sinl, "LdLd", "Fnc") +BUILTIN(__builtin_sqrt , "dd" , "Fnc") +BUILTIN(__builtin_sqrtf, "ff" , "Fnc") +BUILTIN(__builtin_sqrtl, "LdLd", "Fnc") +BUILTIN(__builtin_tan , "dd" , "Fnc") +BUILTIN(__builtin_tanf, "ff" , "Fnc") +BUILTIN(__builtin_tanh , "dd" , "Fnc") +BUILTIN(__builtin_tanhf, "ff" , "Fnc") +BUILTIN(__builtin_tanhl, "LdLd", "Fnc") +BUILTIN(__builtin_tanl, "LdLd", "Fnc") // C99 complex builtins BUILTIN(__builtin_cabs, "dXd", "Fnc") diff --git a/include/clang/Basic/BuiltinsX86.def b/include/clang/Basic/BuiltinsX86.def index bbf42ee8c7fe..6315c16dd80a 100644 --- a/include/clang/Basic/BuiltinsX86.def +++ b/include/clang/Basic/BuiltinsX86.def @@ -250,7 +250,7 @@ BUILTIN(__builtin_ia32_pmaddwd128, "V8sV8sV8s", "") BUILTIN(__builtin_ia32_monitor, "vv*UiUi", "") BUILTIN(__builtin_ia32_mwait, "vUiUi", "") BUILTIN(__builtin_ia32_lddqu, "V16ccC*", "") -BUILTIN(__builtin_ia32_palignr128, "V2LLiV2LLiV2LLic", "") +BUILTIN(__builtin_ia32_palignr128, "V16cV16cV16cc", "") BUILTIN(__builtin_ia32_palignr, "V1LLiV1LLiV1LLic", "") BUILTIN(__builtin_ia32_insertps128, "V4fV4fV4fi", "") diff --git a/include/clang/Basic/Diagnostic.h b/include/clang/Basic/Diagnostic.h index 00a5bc6e937d..b2523f28d5e0 100644 --- a/include/clang/Basic/Diagnostic.h +++ b/include/clang/Basic/Diagnostic.h @@ -238,7 +238,6 @@ class Diagnostic { DiagnosticClient *getClient() { return Client; } const DiagnosticClient *getClient() const { return Client; } - /// pushMappings - Copies the current DiagMappings and pushes the new copy /// onto the top of the stack. void pushMappings(); @@ -319,7 +318,7 @@ class Diagnostic { /// getCustomDiagID - Return an ID for a diagnostic with the specified message /// and level. If this is the first request for this diagnosic, it is /// registered and created, otherwise the existing ID is returned. - unsigned getCustomDiagID(Level L, const char *Message); + unsigned getCustomDiagID(Level L, llvm::StringRef Message); /// ConvertArgToString - This method converts a diagnostic argument (as an diff --git a/include/clang/Basic/DiagnosticCommonKinds.td b/include/clang/Basic/DiagnosticCommonKinds.td index 9a342b592ca5..f319cf231a26 100644 --- a/include/clang/Basic/DiagnosticCommonKinds.td +++ b/include/clang/Basic/DiagnosticCommonKinds.td @@ -26,8 +26,8 @@ def note_type_being_defined : Note< /// e.g. to specify the '(' when we expected a ')'. def note_matching : Note<"to match this '%0'">; -def note_using_decl : Note<"using">; -def note_also_found_decl : Note<"also found">; +def note_using : Note<"using">; +def note_also_found : Note<"also found">; // Parse && Lex def err_expected_colon : Error<"expected ':'">; diff --git a/include/clang/Basic/DiagnosticDriverKinds.td b/include/clang/Basic/DiagnosticDriverKinds.td index 3f7d114dda60..efbc787ef0ee 100644 --- a/include/clang/Basic/DiagnosticDriverKinds.td +++ b/include/clang/Basic/DiagnosticDriverKinds.td @@ -60,6 +60,8 @@ def err_drv_I_dash_not_supported : Error< def err_drv_unknown_argument : Error<"unknown argument: '%0'">; def err_drv_invalid_value : Error<"invalid value '%1' in '%0'">; def err_drv_invalid_int_value : Error<"invalid integral value '%1' in '%0'">; +def err_drv_invalid_remap_file : Error< + "invalid option '%0' not of the form ;">; def warn_drv_input_file_unused : Warning< "%0: '%1' input unused when '%2' is present">; @@ -70,7 +72,7 @@ def warn_drv_unused_argument : Warning< def warn_drv_pipe_ignored_with_save_temps : Warning< "-pipe ignored because -save-temps specified">; def warn_drv_not_using_clang_cpp : Warning< - "not using the clang prepreprocessor due to user override">; + "not using the clang preprocessor due to user override">; def warn_drv_not_using_clang_cxx : Warning< "not using the clang compiler for C++ inputs">; def warn_drv_not_using_clang_arch : Warning< diff --git a/include/clang/Basic/DiagnosticFrontendKinds.td b/include/clang/Basic/DiagnosticFrontendKinds.td index cbc287c58c89..252900d18b3f 100644 --- a/include/clang/Basic/DiagnosticFrontendKinds.td +++ b/include/clang/Basic/DiagnosticFrontendKinds.td @@ -15,8 +15,8 @@ def err_fe_error_reading_stdin : Error<"error reading stdin">; def err_fe_error_backend : Error<"error in backend: %0">, DefaultFatal; def err_fe_invalid_ast_file : Error<"invalid AST file: '%0'">, DefaultFatal; def err_fe_invalid_ast_action : Error<"invalid action for AST input">, DefaultFatal; -def err_fe_invalid_code_complete_file - : Error<"cannot locate code-completion file %0">, DefaultFatal; +def err_fe_invalid_code_complete_file : Error< + "cannot locate code-completion file %0">, DefaultFatal; def err_fe_stdout_binary : Error<"unable to change standard output to binary">, DefaultFatal; def err_fe_dependency_file_requires_MT : Error< @@ -29,6 +29,36 @@ def err_fe_unable_to_find_fixit_file : Error< "FIX-IT could not find file '%0'">; def err_fe_invalid_plugin_name : Error< "unable to find plugin '%0'">; +def err_fe_expected_compiler_job : Error< + "unable to handle compilation, expected exactly one compiler job in '%0'">; +def err_fe_expected_clang_command : Error< + "expected a clang compiler command">; +def err_fe_remap_missing_to_file : Error< + "could not remap file '%0' to the contents of file '%1'">, DefaultFatal; +def err_fe_remap_missing_from_file : Error< + "could not remap from missing file '%0'">, DefaultFatal; +def err_fe_unable_to_load_pch : Error< + "unable to load PCH file">; +def err_fe_unable_to_load_plugin : Error< + "unable to load plugin '%0': '%1'">; +def err_fe_unable_to_create_target : Error< + "unable to create target: '%0'">; +def err_fe_unable_to_interface_with_target : Error< + "unable to interface with target machine">; +def err_fe_unable_to_read_pch_file : Error< + "unable to read PCH file: '%0'">; +def err_fe_not_a_pch_file : Error< + "input is not a PCH file: '%0'">; +def err_fe_pch_malformed_block : Error< + "malformed block record in PCH file: '%0'">; +def err_fe_pch_error_at_end_block : Error< + "error at end of module block in PCH file: '%0'">; +def err_fe_unable_to_open_output : Error< + "unable to open output file '%0': '%1'">; +def err_fe_pth_file_has_no_source_header : Error< + "PTH file '%0' does not designate an original source header file for -include-pth">; +def warn_fe_macro_contains_embedded_newline : Warning< + "macro '%0' contains embedded newline, text after the newline is ignored.">; def err_verify_bogus_characters : Error< "bogus characters before '{{' in expected string">; @@ -45,6 +75,8 @@ def note_fixit_in_macro : Note< def note_fixit_failed : Note< "FIX-IT unable to apply suggested code changes">; def note_fixit_unfixed_error : Note<"FIX-IT detected an error it cannot fix">; +def note_fixit_main_file_unchanged : Note< + "main file unchanged">; def warn_fixit_no_changes : Note< "FIX-IT detected errors it could not fix; no output will be generated">; diff --git a/include/clang/Basic/DiagnosticGroups.td b/include/clang/Basic/DiagnosticGroups.td index c1c833cf5c66..761478abd3d4 100644 --- a/include/clang/Basic/DiagnosticGroups.td +++ b/include/clang/Basic/DiagnosticGroups.td @@ -113,6 +113,7 @@ def Reorder : DiagGroup<"reorder">; def UndeclaredSelector : DiagGroup<"undeclared-selector">; def SuperSubClassMismatch : DiagGroup<"super-class-method-mismatch">; def : DiagGroup<"variadic-macros">; +def VariadicMacros : DiagGroup<"variadic-macros">; def VectorConversions : DiagGroup<"vector-conversions">; // clang specific def VolatileRegisterVar : DiagGroup<"volatile-register-var">; def : DiagGroup<"write-strings">; diff --git a/include/clang/Basic/DiagnosticLexKinds.td b/include/clang/Basic/DiagnosticLexKinds.td index 39123d9b371a..d8b5f2dad3c9 100644 --- a/include/clang/Basic/DiagnosticLexKinds.td +++ b/include/clang/Basic/DiagnosticLexKinds.td @@ -51,6 +51,9 @@ def err_empty_character : Error<"empty character constant">; def err_unterminated_block_comment : Error<"unterminated /* comment">; def err_invalid_character_to_charify : Error< "invalid argument to convert to character">; + +def err_conflict_marker : Error<"version control conflict marker in file">; + def ext_multichar_character_literal : ExtWarn< "multi-character character constant">, InGroup; def ext_four_char_character_literal : Extension< @@ -150,9 +153,10 @@ def ext_pp_comma_expr : Extension<"comma operator in operand of #if">; def ext_pp_bad_vaargs_use : Extension< "__VA_ARGS__ can only appear in the expansion of a C99 variadic macro">; def ext_pp_macro_redef : ExtWarn<"%0 macro redefined">; -def ext_variadic_macro : Extension<"variadic macros were introduced in C99">; +def ext_variadic_macro : Extension<"variadic macros were introduced in C99">, + InGroup; def ext_named_variadic_macro : Extension< - "named variadic macros are a GNU extension">; + "named variadic macros are a GNU extension">, InGroup; def ext_embedded_directive : Extension< "embedding a directive within macro arguments is not portable">; def ext_missing_varargs_arg : Extension< @@ -160,18 +164,11 @@ def ext_missing_varargs_arg : Extension< def ext_empty_fnmacro_arg : Extension< "empty macro arguments were standardized in C99">; -def ext_pp_base_file : Extension<"__BASE_FILE__ is a language extension">; -def ext_pp_include_level : Extension< - "__INCLUDE_LEVEL__ is a language extension">; -def ext_pp_timestamp : Extension<"__TIMESTAMP__ is a language extension">; -def ext_pp_counter : Extension< - "__COUNTER__ is a language extension">; - def err_pp_invalid_directive : Error<"invalid preprocessing directive">; 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'">, DefaultFatal; + "error opening file '%0': %1">, DefaultFatal; 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 ">; diff --git a/include/clang/Basic/DiagnosticParseKinds.td b/include/clang/Basic/DiagnosticParseKinds.td index 43107044720e..bf188cf14f91 100644 --- a/include/clang/Basic/DiagnosticParseKinds.td +++ b/include/clang/Basic/DiagnosticParseKinds.td @@ -166,6 +166,8 @@ def err_use_of_tag_name_without_tag : Error< "use of tagged type %0 without '%1' tag">; def err_expected_ident_in_using : Error< "expected an identifier in using directive">; +def err_unexected_colon_in_nested_name_spec : Error< + "unexpected ':' in nested name specifier">; /// Objective-C parser diagnostics def err_objc_no_attributes_on_category : Error< diff --git a/include/clang/Basic/DiagnosticSemaKinds.td b/include/clang/Basic/DiagnosticSemaKinds.td index a0e03fed1600..a890323e6c0d 100644 --- a/include/clang/Basic/DiagnosticSemaKinds.td +++ b/include/clang/Basic/DiagnosticSemaKinds.td @@ -105,7 +105,11 @@ def err_using_typename_non_type : Error< "'typename' keyword used on a non-type">; def err_using_dependent_value_is_type : Error< "dependent using declaration resolved to type without 'typename'">; -def err_using_decl_nested_name_specifier_is_not_a_base_class : Error< +def err_using_decl_nested_name_specifier_is_not_class : Error< + "using declaration in class refers into '%0', which is not a class">; +def err_using_decl_nested_name_specifier_is_current_class : Error< + "using declaration refers to its own class">; +def err_using_decl_nested_name_specifier_is_not_base_class : Error< "using declaration refers into '%0', which is not a base class of %1">; def err_using_decl_can_not_refer_to_class_member : Error< "using declaration can not refer to class member">; @@ -117,8 +121,17 @@ def err_using_decl_destructor : Error< "using declaration can not refer to a destructor">; def err_using_decl_template_id : Error< "using declaration can not refer to a template specialization">; -def note_using_decl_target : Note< - "target of using declaration">; +def note_using_decl_target : Note<"target of using declaration">; +def note_using_decl_conflict : Note<"conflicting declaration">; +def err_using_decl_redeclaration : Error<"redeclaration of using decl">; +def err_using_decl_conflict : Error< + "target of using declaration conflicts with declaration already in scope">; +def err_using_decl_conflict_reverse : Error< + "declaration conflicts with target of using declaration already in scope">; +def note_using_decl : Note<"%select{|previous }0using declaration">; + +def warn_access_decl_deprecated : Warning< + "access declarations are deprecated; use using declarations instead">; def err_invalid_thread : Error< "'__thread' is only allowed on variable declarations">; @@ -186,7 +199,6 @@ def warn_pragma_pack_invalid_alignment : Warning< "expected #pragma pack parameter to be '1', '2', '4', '8', or '16'">; // Follow the MSVC implementation. def warn_pragma_pack_show : Warning<"value of #pragma pack(show) == %0">; -// FIXME: Dehardcode. def warn_pragma_pack_pop_identifer_and_alignment : Warning< "specifying both a name and alignment to 'pop' is undefined">; def warn_pragma_pack_pop_failed : Warning<"#pragma pack(pop, ...) failed: %0">; @@ -441,7 +453,8 @@ def err_implicit_object_parameter_init : Error< "of type %1">; def note_field_decl : Note<"member is declared here">; -def note_previous_class_decl : Note< +def note_bitfield_decl : Note<"bit-field is declared here">; +def note_previous_decl : Note< "%0 declared here">; def note_member_synthesized_at : Note< "implicit default %select{constructor|copy constructor|" @@ -521,14 +534,35 @@ def err_lvalue_to_rvalue_ambig_ref : Error<"rvalue reference cannot bind to lval def err_not_reference_to_const_init : Error< "non-const lvalue reference to type %0 cannot be initialized " "with a %1 of type %2">; +def err_lvalue_reference_bind_to_temporary : Error< + "non-const lvalue reference to type %0 cannot bind to a temporary of type " + "%1">; +def err_lvalue_reference_bind_to_unrelated : Error< + "non-const lvalue reference to type %0 cannot bind to a value of unrelated " + "type %1">; +def err_reference_bind_drops_quals : Error< + "binding of reference to type %0 to a value of type %1 drops qualifiers">; +def err_reference_bind_failed : Error< + "reference to type %0 could not bind to an %select{rvalue|lvalue}1 of type " + "%2">; +def err_reference_bind_init_list : Error< + "reference to type %0 cannot bind to an initializer list">; +def err_init_list_bad_dest_type : Error< + "%select{|non-aggregate }0type %1 cannot be initialized with an initializer " + "list">; + // FIXME: passing in an English string as %1! def err_reference_init_drops_quals : Error< "initialization of reference to type %0 with a %1 of type %2 drops " "qualifiers">; +def err_reference_bind_to_bitfield : Error< + "%select{non-const|volatile}0 reference cannot bind to bit-field %1">; def err_reference_var_requires_init : Error< "declaration of reference variable %0 requires an initializer">; def err_const_var_requires_init : Error< "declaration of const variable '%0' requires an initializer">; +def err_reference_has_multiple_inits : Error< + "reference cannot be initialized with multiple values">; def err_init_non_aggr_init_list : Error< "initialization of non-aggregate type %0 with an initializer list">; def err_init_reference_member_uninitialized : Error< @@ -934,6 +968,11 @@ def err_template_variable_noparams : Error< "extraneous 'template<>' in declaration of variable %0">; def err_template_tag_noparams : Error< "extraneous 'template<>' in declaration of %0 %1">; +def err_template_decl_ref : Error< + "cannot refer to class template %0 without a template argument list">; + +def err_typedef_in_def_scope : Error< + "cannot use typedef %0 in scope specifier for out-of-line declaration">; // C++ Template Argument Lists def err_template_arg_list_different_arity : Error< @@ -1261,7 +1300,10 @@ def warn_missing_prototype : Warning< "no previous prototype for function %0">, InGroup>, DefaultIgnore; def err_redefinition : Error<"redefinition of %0">; - +def err_definition_of_implicitly_declared_member : Error< + "definition of implicitly declared %select{constructor|copy constructor|" + "copy assignment operator|destructor}1">; + def warn_redefinition_of_typedef : Warning< "redefinition of typedef %0 is invalid in C">, InGroup >, DefaultError; @@ -1515,6 +1557,8 @@ def err_typecheck_member_reference_ivar : Error< "%0 does not have a member named %1">; def err_typecheck_member_reference_arrow : Error< "member reference type %0 is not a pointer">; +def err_typecheck_member_reference_suggestion : Error< + "member reference type %0 is %select{a|not a}1 pointer; maybe you meant to use '%select{->|.}1'?">; def err_typecheck_member_reference_type : Error< "cannot refer to type member %0 with '%select{.|->}1'">; def err_typecheck_member_reference_unknown : Error< @@ -1564,6 +1608,9 @@ def warn_tentative_incomplete_array : Warning< def err_typecheck_incomplete_array_needs_initializer : Error< "definition of variable with array type needs an explicit size " "or an initializer">; +def err_array_init_not_init_list : Error< + "array initializater must be an initializer " + "list%select{| or string literal}0">; def err_realimag_invalid_type : Error<"invalid type %0 to %1 operator">; def err_typecheck_sclass_fscope : Error< @@ -1649,6 +1696,7 @@ def warn_printf_nonliteral : Warning< def err_unexpected_interface : Error< "unexpected interface name %0: expected expression">; +def err_ref_non_value : Error<"%0 does not refer to a value">; def err_property_not_found : Error< "property %0 not found on object of type %1">; def ext_gnu_void_ptr : Extension< @@ -1849,7 +1897,10 @@ def err_typecheck_bool_condition : Error< def err_typecheck_ambiguous_condition : Error< "conversion from %0 to %1 is ambiguous">; def err_typecheck_nonviable_condition : Error< - "no viable conversion from %0 to %1 is possible">; + "no viable conversion from %0 to %1">; +def err_typecheck_deleted_function : Error< + "conversion function from %0 to %1 invokes a deleted function">; + def err_expected_class_or_namespace : Error<"expected a class or namespace">; def err_invalid_declarator_scope : Error< "definition or redeclaration of %0 not in a namespace enclosing %1">; @@ -1963,7 +2014,8 @@ def err_cannot_pass_objc_interface_to_vararg : Error< def warn_cannot_pass_non_pod_arg_to_vararg : Warning< "cannot pass object of non-POD type %0 through variadic " - "%select{function|block|method|constructor}1; call will abort at runtime">; + "%select{function|block|method|constructor}1; call will abort at runtime">, + InGroup>, DefaultError; def err_typecheck_call_invalid_ordered_compare : Error< "ordered compare requires two args of floating point type (%0 and %1)">; @@ -2047,12 +2099,6 @@ def err_overload_expr_requires_non_zero_constant : Error< def err_overload_incorrect_fntype : Error< "argument is not a function, or has wrong number of parameters">; -// FIXME: PASSING TYPES AS STRING. -def err_overload_no_match : Error< - "no matching overload found for arguments of type '%0'">; -def err_overload_multiple_match : Error< - "more than one matching function found in __builtin_overload">; - // C++ member initializers. def err_only_constructors_take_base_inits : Error< "only constructors take base initializers">; @@ -2176,10 +2222,6 @@ def err_operator_overload_needs_class_or_enum : Error< def err_operator_overload_variadic : Error<"overloaded %0 cannot be variadic">; def err_operator_overload_static : Error< "overloaded %0 cannot be a static member function">; -def err_operator_new_param_type : Error< - "%0 takes type size_t (%1) as first parameter">; -def err_operator_new_result_type : Error< - "%0 must return type %1">; def err_operator_overload_default_arg : Error< "parameter of overloaded %0 cannot have a default argument">; def err_operator_overload_must_be : Error< @@ -2192,6 +2234,31 @@ def err_operator_overload_post_incdec_must_be_int : Error< "parameter of overloaded post-%select{increment|decrement}1 operator must " "have type 'int' (not %0)">; +// C++ allocation and deallocation functions. +def err_operator_new_delete_declared_in_namespace : Error< + "%0 cannot be declared inside a namespace">; +def err_operator_new_delete_declared_static : Error< + "%0 cannot be declared static in global scope">; +def err_operator_new_delete_invalid_result_type : Error< + "%0 must return type %1">; +def err_operator_new_delete_dependent_result_type : Error< + "%0 cannot have a dependent return type; use %1 instead">; +def err_operator_new_delete_too_few_parameters : Error< + "%0 must have at least one parameter.">; +def err_operator_new_delete_template_too_few_parameters : Error< + "%0 template must have at least two parameters.">; + +def err_operator_new_dependent_param_type : Error< + "%0 cannot take a dependent type as first parameter; " + "use size_t (%1) instead">; +def err_operator_new_param_type : Error< + "%0 takes type size_t (%1) as first parameter">; +def err_operator_new_default_arg: Error< + "parameter of %0 cannot have a default argument">; +def err_operator_delete_dependent_param_type : Error< + "%0 cannot take a dependent type as first parameter; use %1 instead">; +def err_operator_delete_param_type : Error< + "%0 takes type %1 as first parameter">; // C++ conversion functions def err_conv_function_not_member : Error< @@ -2371,7 +2438,9 @@ def err_altivec_empty_initializer : Error<"expected initializer">; def err_stack_const_level : Error< "level argument for a stack address builtin must be constant">; -def err_prefetch_invalid_argument : Error< +def err_prefetch_invalid_arg_type : Error< + "argument to __builtin_prefetch must be of integer type">; +def err_prefetch_invalid_arg_ice : Error< "argument to __builtin_prefetch must be a constant integer">; def err_argument_invalid_range : Error< "argument should be a value from %0 to %1">; diff --git a/include/clang/Basic/FileManager.h b/include/clang/Basic/FileManager.h index 5e7ac4f3c859..d0e0118d99d6 100644 --- a/include/clang/Basic/FileManager.h +++ b/include/clang/Basic/FileManager.h @@ -14,6 +14,7 @@ #ifndef LLVM_CLANG_FILEMANAGER_H #define LLVM_CLANG_FILEMANAGER_H +#include "llvm/ADT/SmallVector.h" #include "llvm/ADT/StringMap.h" #include "llvm/ADT/StringRef.h" #include "llvm/ADT/OwningPtr.h" @@ -151,6 +152,9 @@ class FileManager { /// unsigned NextFileUID; + /// \brief The virtual files that we have allocated. + llvm::SmallVector VirtualFileEntries; + // Statistics. unsigned NumDirLookups, NumFileLookups; unsigned NumDirCacheMisses, NumFileCacheMisses; @@ -199,6 +203,11 @@ class FileManager { const FileEntry *getFile(const char *FilenameStart, const char *FilenameEnd); + /// \brief Retrieve a file entry for a "virtual" file that acts as + /// if there were a file with the given name on disk. The file + /// itself is not accessed. + const FileEntry *getVirtualFile(const llvm::StringRef &Filename, + off_t Size, time_t ModificationTime); void PrintStats() const; }; diff --git a/include/clang/Basic/IdentifierTable.h b/include/clang/Basic/IdentifierTable.h index 53939500e72a..75a7b8192c5a 100644 --- a/include/clang/Basic/IdentifierTable.h +++ b/include/clang/Basic/IdentifierTable.h @@ -532,9 +532,11 @@ struct DenseMapInfo { static bool isEqual(clang::Selector LHS, clang::Selector RHS) { return LHS == RHS; } - - static bool isPod() { return true; } }; + +template <> +struct isPodLike { static const bool value = true; }; + // Provide PointerLikeTypeTraits for IdentifierInfo pointers, which // are not guaranteed to be 8-byte aligned. diff --git a/include/clang/Basic/LangOptions.h b/include/clang/Basic/LangOptions.h index a16a27103b67..e17279e2664a 100644 --- a/include/clang/Basic/LangOptions.h +++ b/include/clang/Basic/LangOptions.h @@ -46,7 +46,7 @@ class LangOptions { unsigned LaxVectorConversions : 1; unsigned AltiVec : 1; // Support AltiVec-style vector initializers. unsigned Exceptions : 1; // Support exception handling. - unsigned Rtti : 1; // Support rtti information. + unsigned RTTI : 1; // Support RTTI information. unsigned NeXTRuntime : 1; // Use NeXT runtime. unsigned Freestanding : 1; // Freestanding implementation @@ -92,6 +92,7 @@ class LangOptions { unsigned ElideConstructors : 1; // Whether C++ copy constructors should be // elided if possible. + unsigned CatchUndefined :1; // Generate code to check for undefined ops. private: unsigned GC : 2; // Objective-C Garbage Collection modes. We // declare this enum as unsigned because MSVC @@ -125,7 +126,7 @@ class LangOptions { CXXOperatorNames = PascalStrings = WritableStrings = 0; Exceptions = Freestanding = NoBuiltin = 0; NeXTRuntime = 1; - Rtti = 1; + RTTI = 1; LaxVectorConversions = 1; HeinousExtensions = 0; AltiVec = OpenCL = StackProtector = 0; @@ -160,6 +161,7 @@ class LangOptions { CharIsSigned = 1; ShortWChar = 0; + CatchUndefined = 0; } GCMode getGCMode() const { return (GCMode) GC; } diff --git a/include/clang/Basic/PartialDiagnostic.h b/include/clang/Basic/PartialDiagnostic.h index 9960d5beb5c1..ae11a755cce4 100644 --- a/include/clang/Basic/PartialDiagnostic.h +++ b/include/clang/Basic/PartialDiagnostic.h @@ -51,11 +51,11 @@ class PartialDiagnostic { /// This is used when the argument is not an std::string. The specific value /// is mangled into an intptr_t and the intepretation depends on exactly /// what sort of argument kind it is. - mutable intptr_t DiagArgumentsVal[MaxArguments]; + intptr_t DiagArgumentsVal[MaxArguments]; /// DiagRanges - The list of ranges added to this diagnostic. It currently /// only support 10 ranges, could easily be extended if needed. - mutable const SourceRange *DiagRanges[10]; + SourceRange DiagRanges[10]; }; /// DiagID - The diagnostic ID. @@ -81,25 +81,40 @@ class PartialDiagnostic { assert(DiagStorage->NumDiagRanges < llvm::array_lengthof(DiagStorage->DiagRanges) && "Too many arguments to diagnostic!"); - DiagStorage->DiagRanges[DiagStorage->NumDiagRanges++] = &R; + DiagStorage->DiagRanges[DiagStorage->NumDiagRanges++] = R; } - void operator=(const PartialDiagnostic &); // DO NOT IMPLEMENT - public: PartialDiagnostic(unsigned DiagID) : DiagID(DiagID), DiagStorage(0) { } PartialDiagnostic(const PartialDiagnostic &Other) - : DiagID(Other.DiagID), DiagStorage(Other.DiagStorage) { - Other.DiagID = 0; - Other.DiagStorage = 0; + : DiagID(Other.DiagID), DiagStorage(0) + { + if (Other.DiagStorage) + DiagStorage = new Storage(*Other.DiagStorage); + } + + PartialDiagnostic &operator=(const PartialDiagnostic &Other) { + DiagID = Other.DiagID; + if (Other.DiagStorage) { + if (DiagStorage) + *DiagStorage = *Other.DiagStorage; + else + DiagStorage = new Storage(*Other.DiagStorage); + } else { + delete DiagStorage; + DiagStorage = 0; + } + + return *this; } ~PartialDiagnostic() { delete DiagStorage; } + unsigned getDiagID() const { return DiagID; } void Emit(const DiagnosticBuilder &DB) const { @@ -114,7 +129,7 @@ class PartialDiagnostic { // Add all ranges. for (unsigned i = 0, e = DiagStorage->NumDiagRanges; i != e; ++i) - DB.AddSourceRange(*DiagStorage->DiagRanges[i]); + DB.AddSourceRange(DiagStorage->DiagRanges[i]); } friend const PartialDiagnostic &operator<<(const PartialDiagnostic &PD, diff --git a/include/clang/Basic/SourceLocation.h b/include/clang/Basic/SourceLocation.h index 28cf2db9bc25..36baf5feecce 100644 --- a/include/clang/Basic/SourceLocation.h +++ b/include/clang/Basic/SourceLocation.h @@ -21,6 +21,7 @@ namespace llvm { class MemoryBuffer; class raw_ostream; template struct DenseMapInfo; + template struct isPodLike; } namespace clang { @@ -296,9 +297,12 @@ namespace llvm { static bool isEqual(clang::FileID LHS, clang::FileID RHS) { return LHS == RHS; } - - static bool isPod() { return true; } }; + + template <> + struct isPodLike { static const bool value = true; }; + template <> + struct isPodLike { static const bool value = true; }; } // end namespace llvm diff --git a/include/clang/Basic/SourceManager.h b/include/clang/Basic/SourceManager.h index 7e9ac531017e..b4cf959dc551 100644 --- a/include/clang/Basic/SourceManager.h +++ b/include/clang/Basic/SourceManager.h @@ -54,9 +54,6 @@ namespace SrcMgr { /// file. This is owned by the ContentCache object. mutable const llvm::MemoryBuffer *Buffer; - /// The line and column at which we should truncate the file. - unsigned TruncateAtLine, TruncateAtColumn; - public: /// Reference to the file entry. This reference does not own /// the FileEntry object. It is possible for this to be NULL if @@ -72,13 +69,10 @@ namespace SrcMgr { /// if SourceLineCache is non-null. unsigned NumLines; - /// FirstFID - First FileID that was created for this ContentCache. - /// Represents the first source inclusion of the file associated with this - /// ContentCache. - mutable FileID FirstFID; - - /// getBuffer - Returns the memory buffer for the associated content. - const llvm::MemoryBuffer *getBuffer() const; + /// getBuffer - Returns the memory buffer for the associated content. If + /// there is an error opening this buffer the first time, this manufactures + /// a temporary buffer and returns a non-empty error string. + const llvm::MemoryBuffer *getBuffer(std::string *ErrorStr = 0) const; /// getSize - Returns the size of the content encapsulated by this /// ContentCache. This can be the size of the source file or the size of an @@ -96,28 +90,19 @@ namespace SrcMgr { Buffer = B; } - /// \brief Truncate this file at the given line and column. - /// - /// \param Line the line on which to truncate the current file (1-based). - /// \param Column the column at which to truncate the current file. - /// (1-based). - void truncateAt(unsigned Line, unsigned Column); - - /// \brief Determines whether the file was artificially truncated with - /// truncateAt(). - bool isTruncated() const { return TruncateAtLine && TruncateAtColumn; } - + /// \brief Replace the existing buffer (which will be deleted) + /// with the given buffer. + void replaceBuffer(const llvm::MemoryBuffer *B); + ContentCache(const FileEntry *Ent = 0) - : Buffer(0), TruncateAtLine(0), TruncateAtColumn(0), Entry(Ent), - SourceLineCache(0), NumLines(0) {} + : Buffer(0), Entry(Ent), SourceLineCache(0), NumLines(0) {} ~ContentCache(); /// The copy ctor does not allow copies where source object has either /// a non-NULL Buffer or SourceLineCache. Ownership of allocated memory /// is not transfered, so this is a logical error. - ContentCache(const ContentCache &RHS) - : Buffer(0), TruncateAtLine(0), TruncateAtColumn(0), SourceLineCache(0) { + ContentCache(const ContentCache &RHS) : Buffer(0), SourceLineCache(0) { Entry = RHS.Entry; assert (RHS.Buffer == 0 && RHS.SourceLineCache == 0 @@ -347,19 +332,13 @@ class SourceManager { mutable FileID LastRFIDForBeforeTUCheck; mutable bool LastResForBeforeTUCheck; - // Keep track of the file/line/column that we should truncate. - const FileEntry *TruncateFile; - unsigned TruncateAtLine; - unsigned TruncateAtColumn; - // SourceManager doesn't support copy construction. explicit SourceManager(const SourceManager&); void operator=(const SourceManager&); public: SourceManager() - : ExternalSLocEntries(0), LineTable(0), NumLinearScans(0), - NumBinaryProbes(0), TruncateFile(0), TruncateAtLine(0), - TruncateAtColumn(0) { + : ExternalSLocEntries(0), LineTable(0), NumLinearScans(0), + NumBinaryProbes(0) { clearIDTables(); } ~SourceManager(); @@ -428,14 +407,30 @@ class SourceManager { unsigned PreallocatedID = 0, unsigned Offset = 0); + /// \brief Retrieve the memory buffer associated with the given file. + const llvm::MemoryBuffer *getMemoryBufferForFile(const FileEntry *File); + + /// \brief Override the contents of the given source file by providing an + /// already-allocated buffer. + /// + /// \param SourceFile the source file whose contents will be override. + /// + /// \param Buffer the memory buffer whose contents will be used as the + /// data in the given source file. + /// + /// \returns true if an error occurred, false otherwise. + bool overrideFileContents(const FileEntry *SourceFile, + const llvm::MemoryBuffer *Buffer); + //===--------------------------------------------------------------------===// // FileID manipulation methods. //===--------------------------------------------------------------------===// - /// getBuffer - Return the buffer for the specified FileID. - /// - const llvm::MemoryBuffer *getBuffer(FileID FID) const { - return getSLocEntry(FID).getFile().getContentCache()->getBuffer(); + /// getBuffer - Return the buffer for the specified FileID. If there is an + /// error opening this buffer the first time, this manufactures a temporary + /// buffer and returns a non-empty error string. + const llvm::MemoryBuffer *getBuffer(FileID FID, std::string *Error = 0) const{ + return getSLocEntry(FID).getFile().getContentCache()->getBuffer(Error); } /// getFileEntryForID - Returns the FileEntry record for the provided FileID. @@ -669,12 +664,6 @@ class SourceManager { /// \returns true if LHS source location comes before RHS, false otherwise. bool isBeforeInTranslationUnit(SourceLocation LHS, SourceLocation RHS) const; - /// \brief Truncate the given file at the specified line/column. - void truncateFileAt(const FileEntry *Entry, unsigned Line, unsigned Column); - - /// \brief Determine whether this file was truncated. - bool isTruncatedFile(FileID FID) const; - // Iterators over FileInfos. typedef llvm::DenseMap ::const_iterator fileinfo_iterator; diff --git a/include/clang/Basic/TokenKinds.def b/include/clang/Basic/TokenKinds.def index 99422332a788..bb022f11759d 100644 --- a/include/clang/Basic/TokenKinds.def +++ b/include/clang/Basic/TokenKinds.def @@ -324,6 +324,8 @@ KEYWORD(__is_enum , KEYCXX) KEYWORD(__is_pod , KEYCXX) KEYWORD(__is_polymorphic , KEYCXX) KEYWORD(__is_union , KEYCXX) +// Tentative name - there's no implementation of std::is_literal_type yet. +KEYWORD(__is_literal , KEYCXX) // FIXME: Add MS's traits, too. // Apple Extension. diff --git a/include/clang/Basic/TypeTraits.h b/include/clang/Basic/TypeTraits.h index 2a2eacc4caac..36b830069f86 100644 --- a/include/clang/Basic/TypeTraits.h +++ b/include/clang/Basic/TypeTraits.h @@ -32,7 +32,8 @@ namespace clang { UTT_IsEnum, UTT_IsPOD, UTT_IsPolymorphic, - UTT_IsUnion + UTT_IsUnion, + UTT_IsLiteral }; } diff --git a/include/clang/Driver/CC1Options.td b/include/clang/Driver/CC1Options.td index b34fe0340a55..a9566f3f9d47 100644 --- a/include/clang/Driver/CC1Options.td +++ b/include/clang/Driver/CC1Options.td @@ -55,7 +55,7 @@ def analysis_CheckerCFRef : Flag<"-checker-cfref">, def analysis_WarnSizeofPointer : Flag<"-warn-sizeof-pointer">, HelpText<"Warn about unintended use of sizeof() on pointer expressions">; def analysis_InlineCall : Flag<"-inline-call">, - HelpText<"Experimental transfer function inling callees when its definition is available.">; + HelpText<"Experimental transfer function inlining callees when its definition is available.">; def analyzer_store : Separate<"-analyzer-store">, HelpText<"Source Code Analysis - Abstract Memory Store Models">; @@ -73,6 +73,8 @@ def analyzer_output_EQ : Joined<"-analyzer-output=">, def analyzer_opt_analyze_headers : Flag<"-analyzer-opt-analyze-headers">, HelpText<"Force the static analyzer to analyze functions defined in header files">; +def analyzer_opt_analyze_nested_blocks : Flag<"-analyzer-opt-analyze-nested-blocks">, + HelpText<"Analyze the definitions of blocks in addition to functions">; def analyzer_display_progress : Flag<"-analyzer-display-progress">, HelpText<"Emit verbose output about the analyzer's progress">; def analyzer_experimental_checks : Flag<"-analyzer-experimental-checks">, @@ -103,6 +105,8 @@ def disable_llvm_optzns : Flag<"-disable-llvm-optzns">, def disable_red_zone : Flag<"-disable-red-zone">, HelpText<"Do not emit code that uses the red zone.">; def g : Flag<"-g">, HelpText<"Generate source level debug information">; +def fcatch_undefined_behavior : Flag<"-fcatch-undefined-behavior">, + HelpText<"Generate runtime checks for undefined behavior.">; def fno_common : Flag<"-fno-common">, HelpText<"Compile common globals like normal definitions">; def no_implicit_float : Flag<"-no-implicit-float">, @@ -117,13 +121,13 @@ def mdebug_pass : Separate<"-mdebug-pass">, HelpText<"Enable additional debug output">; def mdisable_fp_elim : Flag<"-mdisable-fp-elim">, HelpText<"Disable frame pointer elimination optimization">; -def mfloat_abi : Flag<"-mfloat-abi">, +def mfloat_abi : Separate<"-mfloat-abi">, HelpText<"The float ABI to use">; def mlimit_float_precision : Separate<"-mlimit-float-precision">, HelpText<"Limit float precision to the given value">; def mno_zero_initialized_in_bss : Flag<"-mno-zero-initialized-in-bss">, HelpText<"Do not put zero initialized data in the BSS">; -def msoft_float : Separate<"-msoft-float">, +def msoft_float : Flag<"-msoft-float">, HelpText<"Use software floating point">; def mrelocation_model : Separate<"-mrelocation-model">, HelpText<"The relocation model to use">; @@ -149,7 +153,7 @@ def MP : Flag<"-MP">, //===----------------------------------------------------------------------===// def dump_build_information : Separate<"-dump-build-information">, - MetaVarName<"filename">, + MetaVarName<"">, HelpText<"output a dump of some build information to a file">; def fno_show_column : Flag<"-fno-show-column">, HelpText<"Do not include column number on diagnostics">; @@ -172,7 +176,7 @@ def fdiagnostics_print_source_range_info : Flag<"-fdiagnostics-print-source-rang HelpText<"Print source range spans in numeric form">; def fdiagnostics_show_option : Flag<"-fdiagnostics-show-option">, HelpText<"Print diagnostic name with mappable diagnostics">; -def fmessage_length : Separate<"-fmessage-length">, MetaVarName<"N">, +def fmessage_length : Separate<"-fmessage-length">, MetaVarName<"">, HelpText<"Format message diagnostics so that they fit within N columns or fewer, when possible.">; def fcolor_diagnostics : Flag<"-fcolor-diagnostics">, HelpText<"Use colors in diagnostics">; @@ -185,28 +189,45 @@ def verify : Flag<"-verify">, // Frontend Options //===----------------------------------------------------------------------===// +// This isn't normally used, it is just here so we can parse a +// CompilerInvocation out of a driver-derived argument vector. +def cc1 : Flag<"-cc1">; + def code_completion_at : Separate<"-code-completion-at">, - MetaVarName<"file:line:column">, + MetaVarName<"::">, HelpText<"Dump code-completion information at a location">; +def remap_file : Separate<"-remap-file">, + MetaVarName<";">, + HelpText<"Replace the contents of the file with the contents of the file">; def code_completion_at_EQ : Joined<"-code-completion-at=">, Alias; def no_code_completion_debug_printer : Flag<"-no-code-completion-debug-printer">, - HelpText<"Don't the \"debug\" code-completion print">; + HelpText<"Don't use the \"debug\" code-completion print">; def code_completion_macros : Flag<"-code-completion-macros">, HelpText<"Include macros in code-completion results">; def disable_free : Flag<"-disable-free">, HelpText<"Disable freeing of memory on exit">; def empty_input_only : Flag<"-empty-input-only">, HelpText<"Force running on an empty input file">; +def help : Flag<"-help">, + HelpText<"Print this help text">; +def _help : Flag<"--help">, Alias; def x : Separate<"-x">, HelpText<"Input language type">; def cxx_inheritance_view : Separate<"-cxx-inheritance-view">, - MetaVarName<"class name">, + MetaVarName<"">, HelpText<"View C++ inheritance for a specified class">; -def fixit_at : Separate<"-fixit-at">, MetaVarName<"source-location">, +def fixit_at : Separate<"-fixit-at">, MetaVarName<"">, HelpText<"Perform Fix-It modifications at the given source location">; -def o : Separate<"-o">, MetaVarName<"path">, HelpText<"Specify output file">; +def o : Separate<"-o">, MetaVarName<"">, HelpText<"Specify output file">; +def load : Separate<"-load">, MetaVarName<"">, + HelpText<"Load the named plugin (dynamic shared object)">; def plugin : Separate<"-plugin">, HelpText<"Use the named plugin action (use \"help\" to list available options)">; +def resource_dir : Separate<"-resource-dir">, + HelpText<"The directory which holds the compiler resource files">; +def version : Flag<"-version">, + HelpText<"Print the compiler version">; +def _version : Flag<"--version">, Alias; def Action_Group : OptionGroup<"">; let Group = Action_Group in { @@ -313,7 +334,7 @@ def fno_signed_char : Flag<"-fno-signed-char">, def fno_operator_names : Flag<"-fno-operator-names">, HelpText<"Do not treat C++ operator name keywords as synonyms for operators">; def fconstant_string_class : Separate<"-fconstant-string-class">, - MetaVarName<"class name">, + MetaVarName<"">, HelpText<"Specify the class to use for constant Objective-C string objects.">; def fobjc_gc : Flag<"-fobjc-gc">, HelpText<"Enable Objective-C garbage collection">; @@ -326,7 +347,7 @@ def fobjc_nonfragile_abi : Flag<"-fobjc-nonfragile-abi">, def ftrapv : Flag<"-ftrapv">, HelpText<"Trap on integer overflow">; def pic_level : Separate<"-pic-level">, - HelpText<"-Value for __PIC__">; + HelpText<"Value for __PIC__">; def pthread : Flag<"-pthread">, HelpText<"Support POSIX threads in generated code">; def fpascal_strings : Flag<"-fpascal-strings">, @@ -356,23 +377,24 @@ def nostdinc : Flag<"-nostdinc">, HelpText<"Disable standard #include directories">; def nobuiltininc : Flag<"-nobuiltininc">, HelpText<"Disable builtin #include directories">; -def F : JoinedOrSeparate<"-F">, MetaVarName<"directory">, +def F : JoinedOrSeparate<"-F">, MetaVarName<"">, HelpText<"Add directory to framework include search path">; -def I : JoinedOrSeparate<"-I">, MetaVarName<"directory">, +def I : JoinedOrSeparate<"-I">, MetaVarName<"">, HelpText<"Add directory to include search path">; -def idirafter : Separate<"-idirafter">, MetaVarName<"directory">, +def idirafter : JoinedOrSeparate<"-idirafter">, MetaVarName<"">, HelpText<"Add directory to AFTER include search path">; -def iquote : Separate<"-iquote">, MetaVarName<"directory">, +def iquote : JoinedOrSeparate<"-iquote">, MetaVarName<"">, HelpText<"Add directory to QUOTE include search path">; -def isystem : Separate<"-isystem">, MetaVarName<"directory">, +def isystem : JoinedOrSeparate<"-isystem">, MetaVarName<"">, HelpText<"Add directory to SYSTEM include search path">; -def iprefix : Separate<"-iprefix">, MetaVarName<"prefix">, +def iprefix : JoinedOrSeparate<"-iprefix">, MetaVarName<"">, HelpText<"Set the -iwithprefix/-iwithprefixbefore prefix">; -def iwithprefix : Separate<"-iwithprefix">, MetaVarName<"dir">, +def iwithprefix : JoinedOrSeparate<"-iwithprefix">, MetaVarName<"">, HelpText<"Set directory to SYSTEM include search path with prefix">; -def iwithprefixbefore : Separate<"-iwithprefixbefore">, MetaVarName<"dir">, +def iwithprefixbefore : JoinedOrSeparate<"-iwithprefixbefore">, + MetaVarName<"">, HelpText<"Set directory to include search path with prefix">; -def isysroot : Separate<"-isysroot">, MetaVarName<"dir">, +def isysroot : JoinedOrSeparate<"-isysroot">, MetaVarName<"">, HelpText<"Set the system root directory (usually /)">; def v : Flag<"-v">, HelpText<"Enable verbose output">; @@ -380,21 +402,21 @@ def v : Flag<"-v">, HelpText<"Enable verbose output">; // Preprocessor Options //===----------------------------------------------------------------------===// -def D : JoinedOrSeparate<"-D">, MetaVarName<"macro">, +def D : JoinedOrSeparate<"-D">, MetaVarName<"">, HelpText<"Predefine the specified macro">; -def include_ : Separate<"-include">, MetaVarName<"file">, EnumName<"include">, +def include_ : JoinedOrSeparate<"-include">, MetaVarName<"">, EnumName<"include">, HelpText<"Include file before parsing">; -def imacros : Separate<"-imacros">, MetaVarName<"file">, +def imacros : JoinedOrSeparate<"-imacros">, MetaVarName<"">, HelpText<"Include macros from file before parsing">; -def include_pch : Separate<"-include-pch">, MetaVarName<"file">, +def include_pch : Separate<"-include-pch">, MetaVarName<"">, HelpText<"Include precompiled header file">; -def include_pth : Separate<"-include-pth">, MetaVarName<"file">, +def include_pth : Separate<"-include-pth">, MetaVarName<"">, HelpText<"Include file before parsing">; -def token_cache : Separate<"-token-cache">, MetaVarName<"path">, +def token_cache : Separate<"-token-cache">, MetaVarName<"">, HelpText<"Use specified token cache file">; -def U : JoinedOrSeparate<"-U">, MetaVarName<"macro">, +def U : JoinedOrSeparate<"-U">, MetaVarName<"">, HelpText<"Undefine the specified macro">; -def undef : Flag<"-undef">, MetaVarName<"macro">, +def undef : Flag<"-undef">, MetaVarName<"">, HelpText<"undef all system defines">; //===----------------------------------------------------------------------===// diff --git a/include/clang/Driver/Driver.h b/include/clang/Driver/Driver.h index d3ab1153371a..8933619b2c25 100644 --- a/include/clang/Driver/Driver.h +++ b/include/clang/Driver/Driver.h @@ -15,6 +15,7 @@ #include "clang/Driver/Phases.h" #include "clang/Driver/Util.h" +#include "llvm/ADT/StringRef.h" #include "llvm/ADT/Triple.h" #include "llvm/System/Path.h" // FIXME: Kill when CompilationInfo // lands. @@ -112,9 +113,9 @@ class Driver { std::list ResultFiles; public: - Driver(const char *_Name, const char *_Dir, - const char *_DefaultHostTriple, - const char *_DefaultImageName, + Driver(llvm::StringRef _Name, llvm::StringRef _Dir, + llvm::StringRef _DefaultHostTriple, + llvm::StringRef _DefaultImageName, bool IsProduction, Diagnostic &_Diags); ~Driver(); diff --git a/include/clang/Driver/Job.h b/include/clang/Driver/Job.h index 906d73128b7d..74ca083417a6 100644 --- a/include/clang/Driver/Job.h +++ b/include/clang/Driver/Job.h @@ -22,7 +22,8 @@ using llvm::dyn_cast_or_null; namespace clang { namespace driver { - class Command; +class Command; +class Tool; class Job { public: @@ -55,6 +56,9 @@ class Command : public Job { /// Source - The action which caused the creation of this job. const Action &Source; + /// Tool - The tool which caused the creation of this job. + const Tool &Creator; + /// The executable to run. const char *Executable; @@ -63,12 +67,15 @@ class Command : public Job { ArgStringList Arguments; public: - Command(const Action &_Source, const char *_Executable, + Command(const Action &_Source, const Tool &_Creator, const char *_Executable, const ArgStringList &_Arguments); /// getSource - Return the Action which caused the creation of this job. const Action &getSource() const { return Source; } + /// getCreator - Return the Tool which caused the creation of this job. + const Tool &getCreator() const { return Creator; } + const char *getExecutable() const { return Executable; } const ArgStringList &getArguments() const { return Arguments; } diff --git a/include/clang/Driver/OptParser.td b/include/clang/Driver/OptParser.td index f5b6980d8f6a..a9f4289fc86e 100644 --- a/include/clang/Driver/OptParser.td +++ b/include/clang/Driver/OptParser.td @@ -77,11 +77,17 @@ def RenderSeparate : OptionFlag; // lines that use it. def Unsupported : OptionFlag; +// HelpHidden - The option should not be displayed in --help, even if it has +// help text. Clients *can* use this in conjuction with the OptTable::PrintHelp +// arguments to implement hidden help groups. +def HelpHidden : OptionFlag; + // Define the option group class. class OptionGroup { string EnumName = ?; // Uses the def name if undefined. string Name = name; + string HelpText = ?; OptionGroup Group = ?; } diff --git a/include/clang/Driver/OptTable.h b/include/clang/Driver/OptTable.h index faaeba69e2e6..edae75c9f057 100644 --- a/include/clang/Driver/OptTable.h +++ b/include/clang/Driver/OptTable.h @@ -13,17 +13,22 @@ #include "clang/Driver/OptSpecifier.h" #include +namespace llvm { + class raw_ostream; +} + namespace clang { namespace driver { namespace options { enum DriverFlag { DriverOption = (1 << 0), - LinkerInput = (1 << 1), - NoArgumentUnused = (1 << 2), - RenderAsInput = (1 << 3), - RenderJoined = (1 << 4), - RenderSeparate = (1 << 5), - Unsupported = (1 << 6) + HelpHidden = (1 << 1), + LinkerInput = (1 << 2), + NoArgumentUnused = (1 << 3), + RenderAsInput = (1 << 4), + RenderJoined = (1 << 5), + RenderSeparate = (1 << 6), + Unsupported = (1 << 7) }; } @@ -113,6 +118,17 @@ namespace options { return getInfo(id).Kind; } + /// getOptionGroupID - Get the group id for the given option. + unsigned getOptionGroupID(OptSpecifier id) const { + return getInfo(id).GroupID; + } + + /// isOptionHelpHidden - Should the help for the given option be hidden by + /// default. + bool isOptionHelpHidden(OptSpecifier id) const { + return getInfo(id).Flags & options::HelpHidden; + } + /// getOptionHelpText - Get the help text to use to describe this option. const char *getOptionHelpText(OptSpecifier id) const { return getInfo(id).HelpText; @@ -156,6 +172,15 @@ namespace options { const char **ArgEnd, unsigned &MissingArgIndex, unsigned &MissingArgCount) const; + + /// PrintHelp - Render the help text for an option table. + /// + /// \param OS - The stream to write the help text to. + /// \param Name - The name to use in the usage line. + /// \param Title - The title to use in the usage line. + /// \param ShowHidden - Whether help-hidden arguments should be shown. + void PrintHelp(llvm::raw_ostream &OS, const char *Name, + const char *Title, bool ShowHidden = false) const; }; } } diff --git a/include/clang/Driver/Options.td b/include/clang/Driver/Options.td index ace1a3c16add..3592fc946846 100644 --- a/include/clang/Driver/Options.td +++ b/include/clang/Driver/Options.td @@ -61,6 +61,55 @@ def clang_ignored_m_Group : OptionGroup<"">, // = => _EQ // C++ => CXX +// Developer Driver Options + +def ccc_Group : OptionGroup<"">; +def ccc_driver_Group : OptionGroup<"">, + Group, HelpText<"DRIVER OPTIONS">; +def ccc_debug_Group : OptionGroup<"">, + Group, HelpText<"DEBUG/DEVELOPMENT OPTIONS">; + +class CCCDriverOpt : Group, Flags<[DriverOption, HelpHidden]>; +def ccc_cxx : Flag<"-ccc-cxx">, CCCDriverOpt, + HelpText<"Act as a C++ driver">; +def ccc_echo : Flag<"-ccc-echo">, CCCDriverOpt, + HelpText<"Echo commands before running them">; +def ccc_gcc_name : Separate<"-ccc-gcc-name">, CCCDriverOpt, + HelpText<"Name for native GCC compiler">, + MetaVarName<"">; +def ccc_clang_cxx : Flag<"-ccc-clang-cxx">, CCCDriverOpt, + HelpText<"Enable the clang compiler for C++">; +def ccc_no_clang_cxx : Flag<"-ccc-no-clang-cxx">, CCCDriverOpt, + HelpText<"Disable the clang compiler for C++">; +def ccc_no_clang : Flag<"-ccc-no-clang">, CCCDriverOpt, + HelpText<"Disable the clang compiler">; +def ccc_no_clang_cpp : Flag<"-ccc-no-clang-cpp">, CCCDriverOpt, + HelpText<"Disable the clang preprocessor">; +def ccc_clang_archs : Separate<"-ccc-clang-archs">, CCCDriverOpt, + HelpText<"Comma separate list of architectures to use the clang compiler for">, + MetaVarName<"">; +def ccc_pch_is_pch : Flag<"-ccc-pch-is-pch">, CCCDriverOpt, + HelpText<"Use lazy PCH for precompiled headers">; +def ccc_pch_is_pth : Flag<"-ccc-pch-is-pth">, CCCDriverOpt, + HelpText<"Use pretokenized headers for precompiled headers">; + +class CCCDebugOpt : Group, Flags<[DriverOption, HelpHidden]>; +def ccc_host_triple : Separate<"-ccc-host-triple">, CCCDebugOpt, + HelpText<"Simulate running on the given target">; +def ccc_install_dir : Separate<"-ccc-install-dir">, CCCDebugOpt, + HelpText<"Simulate installation in the given directory">; +def ccc_print_options : Flag<"-ccc-print-options">, CCCDebugOpt, + HelpText<"Dump parsed command line arguments">; +def ccc_print_phases : Flag<"-ccc-print-phases">, CCCDebugOpt, + HelpText<"Dump list of actions to perform">; +def ccc_print_bindings : Flag<"-ccc-print-bindings">, CCCDebugOpt, + HelpText<"Show bindings of tools to actions">; + +// Make sure all other -ccc- options are rejected. +def ccc_ : Joined<"-ccc-">, Group, Flags<[Unsupported]>; + +// Standard Options + def _HASH_HASH_HASH : Flag<"-###">, Flags<[DriverOption]>, HelpText<"Print the commands to run for this compilation">; def A : JoinedOrSeparate<"-A">; @@ -187,6 +236,8 @@ def fbootclasspath_EQ : Joined<"-fbootclasspath=">, Group; def fbuiltin_strcat : Flag<"-fbuiltin-strcat">, Group; def fbuiltin_strcpy : Flag<"-fbuiltin-strcpy">, Group; def fbuiltin : Flag<"-fbuiltin">, Group; +def fcatch_undefined_behavior : Flag<"-fcatch-undefined-behavior">, + Group, HelpText<"Generate runtime checks for undefined behavior.">; def fclasspath_EQ : Joined<"-fclasspath=">, Group; def fcolor_diagnostics : Flag<"-fcolor-diagnostics">, Group; def fcommon : Flag<"-fcommon">, Group; @@ -277,6 +328,9 @@ def fprofile_arcs : Flag<"-fprofile-arcs">, Group; def fprofile_generate : Flag<"-fprofile-generate">, Group; def framework : Separate<"-framework">, Flags<[LinkerInput]>; def frtti : Flag<"-frtti">, Group; +def fsched_interblock : Flag<"-fsched-interblock">, Group; +def fshort_enums : Flag<"-fshort-enums">, Group; +def freorder_blocks : Flag<"-freorder-blocks">, Group; def fshort_wchar : Flag<"-fshort-wchar">, Group; def fshow_source_location : Flag<"-fshow-source-location">, Group; def fsigned_bitfields : Flag<"-fsigned-bitfields">, Group; @@ -315,7 +369,7 @@ def init : Separate<"-init">; def install__name : Separate<"-install_name">; def iprefix : JoinedOrSeparate<"-iprefix">, Group; def iquote : JoinedOrSeparate<"-iquote">, Group; -def isysroot : JoinedOrSeparate<"-isysroot">, Group; +def isysroot : JoinedOrSeparate<"-isysroot">, Group; def isystem : JoinedOrSeparate<"-isystem">, Group; def iwithprefixbefore : JoinedOrSeparate<"-iwithprefixbefore">, Group; def iwithprefix : JoinedOrSeparate<"-iwithprefix">, Group; @@ -373,6 +427,8 @@ def multiply__defined : Separate<"-multiply_defined">; def mwarn_nonportable_cfstrings : Flag<"-mwarn-nonportable-cfstrings">, Group; def m_Separate : Separate<"-m">, Group; def m_Joined : Joined<"-m">, Group; +def no_canonical_prefixes : Flag<"-no-canonical-prefixes">, Flags<[DriverOption, HelpHidden]>, + HelpText<"Use relative instead of canonical paths">; def no_cpp_precomp : Flag<"-no-cpp-precomp">; def no_integrated_cpp : Flag<"-no-integrated-cpp">, Flags<[DriverOption]>; def no__dead__strip__inits__and__terms : Flag<"-no_dead_strip_inits_and_terms">; diff --git a/include/clang/Frontend/ASTConsumers.h b/include/clang/Frontend/ASTConsumers.h index 26efa9745600..20bf83ee0456 100644 --- a/include/clang/Frontend/ASTConsumers.h +++ b/include/clang/Frontend/ASTConsumers.h @@ -94,9 +94,9 @@ ASTConsumer *CreateHTMLPrinter(llvm::raw_ostream *OS, Preprocessor &PP, bool SyntaxHighlight = true, bool HighlightMacros = true); -// PCH generator: generates a precompiled header file; this file can be -// used later with the PCHReader (clang-cc option -include-pch) -// to speed up compile times. +// PCH generator: generates a precompiled header file; this file can be used +// later with the PCHReader (clang -cc1 option -include-pch) to speed up compile +// times. ASTConsumer *CreatePCHGenerator(const Preprocessor &PP, llvm::raw_ostream *OS, const char *isysroot = 0); diff --git a/include/clang/Frontend/ASTUnit.h b/include/clang/Frontend/ASTUnit.h index 04dc5ed8cc56..f18972ab3445 100644 --- a/include/clang/Frontend/ASTUnit.h +++ b/include/clang/Frontend/ASTUnit.h @@ -16,10 +16,11 @@ #include "clang/Basic/SourceManager.h" #include "llvm/ADT/OwningPtr.h" -#include "clang/Frontend/TextDiagnosticBuffer.h" #include "clang/Basic/FileManager.h" #include "clang/Index/ASTLocation.h" #include +#include +#include namespace clang { class ASTContext; @@ -32,14 +33,12 @@ class HeaderSearch; class Preprocessor; class SourceManager; class TargetInfo; -class TextDiagnosticBuffer; using namespace idx; /// \brief Utility class for loading a ASTContext from a PCH file. /// class ASTUnit { - Diagnostic Diags; FileManager FileMgr; SourceManager SourceMgr; @@ -48,22 +47,39 @@ class ASTUnit { llvm::OwningPtr PP; llvm::OwningPtr Ctx; bool tempFile; - + // OnlyLocalDecls - when true, walking this AST should only visit declarations // that come from the AST itself, not from included precompiled headers. // FIXME: This is temporary; eventually, CIndex will always do this. bool OnlyLocalDecls; - + + /// Track whether the main file was loaded from an AST or not. + bool MainFileIsAST; + + /// Track the top-level decls which appeared in an ASTUnit which was loaded + /// from a source file. + // + // FIXME: This is just an optimization hack to avoid deserializing large parts + // of a PCH file when using the Index library on an ASTUnit loaded from + // source. In the long term we should make the Index library use efficient and + // more scalable search mechanisms. + std::vector TopLevelDecls; + + /// The name of the original source file used to generate this ASTUnit. + std::string OriginalSourceFile; + // Critical optimization when using clang_getCursor(). ASTLocation LastLoc; - + ASTUnit(const ASTUnit&); // DO NOT IMPLEMENT ASTUnit &operator=(const ASTUnit &); // DO NOT IMPLEMENT public: - ASTUnit(DiagnosticClient *diagClient = NULL); + ASTUnit(bool MainFileIsAST); ~ASTUnit(); + bool isMainFileAST() const { return MainFileIsAST; } + const SourceManager &getSourceManager() const { return SourceMgr; } SourceManager &getSourceManager() { return SourceMgr; } @@ -73,37 +89,38 @@ class ASTUnit { const ASTContext &getASTContext() const { return *Ctx.get(); } ASTContext &getASTContext() { return *Ctx.get(); } - const Diagnostic &getDiagnostic() const { return Diags; } - Diagnostic &getDiagnostic() { return Diags; } - const FileManager &getFileManager() const { return FileMgr; } FileManager &getFileManager() { return FileMgr; } - + const std::string &getOriginalSourceFileName(); const std::string &getPCHFileName(); void unlinkTemporaryFile() { tempFile = true; } - + bool getOnlyLocalDecls() const { return OnlyLocalDecls; } - + void setLastASTLocation(ASTLocation ALoc) { LastLoc = ALoc; } ASTLocation getLastASTLocation() const { return LastLoc; } - + + std::vector &getTopLevelDecls() { + assert(!isMainFileAST() && "Invalid call for AST based ASTUnit!"); + return TopLevelDecls; + } + const std::vector &getTopLevelDecls() const { + assert(!isMainFileAST() && "Invalid call for AST based ASTUnit!"); + return TopLevelDecls; + } + /// \brief Create a ASTUnit from a PCH file. /// /// \param Filename - The PCH file to load. /// - /// \param DiagClient - The diagnostics client to use. Specify NULL - /// to use a default client that emits warnings/errors to standard error. - /// The ASTUnit objects takes ownership of this object. - /// - /// \param ErrMsg - Error message to report if the PCH file could not be - /// loaded. + /// \param Diags - The diagnostics engine to use for reporting errors; its + /// lifetime is expected to extend past that of the returned ASTUnit. /// /// \returns - The initialized ASTUnit or null if the PCH failed to load. static ASTUnit *LoadFromPCHFile(const std::string &Filename, - std::string *ErrMsg = 0, - DiagnosticClient *DiagClient = NULL, + Diagnostic &Diags, bool OnlyLocalDecls = false, bool UseBumpAllocator = false); @@ -113,15 +130,35 @@ class ASTUnit { /// \param CI - The compiler invocation to use; it must have exactly one input /// source file. /// - /// \param Diags - The diagnostics engine to use for reporting errors. + /// \param Diags - The diagnostics engine to use for reporting errors; its + /// lifetime is expected to extend past that of the returned ASTUnit. // // FIXME: Move OnlyLocalDecls, UseBumpAllocator to setters on the ASTUnit, we // shouldn't need to specify them at construction time. static ASTUnit *LoadFromCompilerInvocation(const CompilerInvocation &CI, Diagnostic &Diags, - bool OnlyLocalDecls = false, - bool UseBumpAllocator = false); + bool OnlyLocalDecls = false); + /// LoadFromCommandLine - Create an ASTUnit from a vector of command line + /// arguments, which must specify exactly one source file. + /// + /// \param ArgBegin - The beginning of the argument vector. + /// + /// \param ArgEnd - The end of the argument vector. + /// + /// \param Diags - The diagnostics engine to use for reporting errors; its + /// lifetime is expected to extend past that of the returned ASTUnit. + /// + /// \param ResourceFilesPath - The path to the compiler resource files. + // + // FIXME: Move OnlyLocalDecls, UseBumpAllocator to setters on the ASTUnit, we + // shouldn't need to specify them at construction time. + static ASTUnit *LoadFromCommandLine(const char **ArgBegin, + const char **ArgEnd, + Diagnostic &Diags, + llvm::StringRef ResourceFilesPath, + bool OnlyLocalDecls = false, + bool UseBumpAllocator = false); }; } // namespace clang diff --git a/include/clang/Frontend/AnalysisConsumer.h b/include/clang/Frontend/AnalysisConsumer.h index 24fed6e76ac1..f55e5dc04055 100644 --- a/include/clang/Frontend/AnalysisConsumer.h +++ b/include/clang/Frontend/AnalysisConsumer.h @@ -62,6 +62,7 @@ class AnalyzerOptions { std::string AnalyzeSpecificFunction; unsigned AnalyzeAll : 1; unsigned AnalyzerDisplayProgress : 1; + unsigned AnalyzeNestedBlocks : 1; unsigned EagerlyAssume : 1; unsigned PurgeDead : 1; unsigned TrimGraph : 1; @@ -76,6 +77,7 @@ class AnalyzerOptions { AnalysisDiagOpt = PD_HTML; AnalyzeAll = 0; AnalyzerDisplayProgress = 0; + AnalyzeNestedBlocks = 0; EagerlyAssume = 0; PurgeDead = 1; TrimGraph = 0; diff --git a/include/clang/Frontend/CompilerInstance.h b/include/clang/Frontend/CompilerInstance.h index d7e7d991f379..18ec429db7e8 100644 --- a/include/clang/Frontend/CompilerInstance.h +++ b/include/clang/Frontend/CompilerInstance.h @@ -222,7 +222,7 @@ class CompilerInstance { void setDiagnostics(Diagnostic *Value); DiagnosticClient &getDiagnosticClient() const { - assert(Target && "Compiler instance has no diagnostic client!"); + assert(DiagClient && "Compiler instance has no diagnostic client!"); return *DiagClient; } @@ -419,9 +419,13 @@ class CompilerInstance { /// logging information. /// /// Note that this creates an unowned DiagnosticClient, if using directly the - /// caller is responsible for releaseing the returned Diagnostic's client + /// caller is responsible for releasing the returned Diagnostic's client /// eventually. /// + /// \param Opts - The diagnostic options; note that the created text + /// diagnostic object contains a reference to these options and its lifetime + /// must extend past that of the diagnostic engine. + /// /// \return The new object on success, or null on failure. static Diagnostic *createDiagnostics(const DiagnosticOptions &Opts, int Argc, char **Argv); @@ -482,12 +486,16 @@ class CompilerInstance { /// Create the default output file (from the invocation's options) and add it /// to the list of tracked output files. + /// + /// \return - Null on error. llvm::raw_fd_ostream * createDefaultOutputFile(bool Binary = true, llvm::StringRef BaseInput = "", llvm::StringRef Extension = ""); /// Create a new output file and add it to the list of tracked output files, /// optionally deriving the output path name. + /// + /// \return - Null on error. llvm::raw_fd_ostream * createOutputFile(llvm::StringRef OutputPath, bool Binary = true, llvm::StringRef BaseInput = "", diff --git a/include/clang/Frontend/CompilerInvocation.h b/include/clang/Frontend/CompilerInvocation.h index e7c51aabba59..f5a9053ceb64 100644 --- a/include/clang/Frontend/CompilerInvocation.h +++ b/include/clang/Frontend/CompilerInvocation.h @@ -82,15 +82,19 @@ class CompilerInvocation { /// \param Res [out] - The resulting invocation. /// \param ArgBegin - The first element in the argument vector. /// \param ArgEnd - The last element in the argument vector. + /// \param Diags - The diagnostic engine to use for errors. + static void CreateFromArgs(CompilerInvocation &Res, const char **ArgBegin, + const char **ArgEnd, Diagnostic &Diags); + + /// GetBuiltinIncludePath - Get the directory where the compiler headers + /// reside, relative to the compiler binary (found by the passed in + /// arguments). + /// /// \param Argv0 - The program path (from argv[0]), for finding the builtin /// compiler path. /// \param MainAddr - The address of main (or some other function in the main /// executable), for finding the builtin compiler path. - /// \param Diags - The diagnostic engine to use for errors. - static void CreateFromArgs(CompilerInvocation &Res, const char **ArgBegin, - const char **ArgEnd, const char *Argv0, - void *MainAddr, - Diagnostic &Diags); + static std::string GetResourcesPath(const char *Argv0, void *MainAddr); /// toArgs - Convert the CompilerInvocation to a list of strings suitable for /// passing to CreateFromArgs. diff --git a/include/clang/Frontend/FrontendOptions.h b/include/clang/Frontend/FrontendOptions.h index c1ec8e70f1c6..36fea7f71337 100644 --- a/include/clang/Frontend/FrontendOptions.h +++ b/include/clang/Frontend/FrontendOptions.h @@ -77,12 +77,14 @@ class FrontendOptions { unsigned RelocatablePCH : 1; ///< When generating PCH files, /// instruct the PCH writer to create /// relocatable PCH files. + unsigned ShowHelp : 1; ///< Show the -help text. unsigned ShowMacrosInCodeCompletion : 1; ///< Show macros in code completion /// results. unsigned ShowStats : 1; ///< Show frontend performance /// metrics and statistics. unsigned ShowTimers : 1; ///< Show timers for individual /// actions. + unsigned ShowVersion : 1; ///< Show the -version text. /// The input files and their types. std::vector > Inputs; @@ -105,6 +107,9 @@ class FrontendOptions { /// The name of the action to run when using a plugin action. std::string ActionName; + /// The list of plugins to load. + std::vector Plugins; + public: FrontendOptions() { DebugCodeCompletionPrinter = 1; @@ -113,9 +118,11 @@ class FrontendOptions { ProgramAction = frontend::ParseSyntaxOnly; ActionName = ""; RelocatablePCH = 0; + ShowHelp = 0; ShowMacrosInCodeCompletion = 0; ShowStats = 0; ShowTimers = 0; + ShowVersion = 0; } /// getInputKindForExtension - Return the appropriate input kind for a file diff --git a/include/clang/Frontend/HeaderSearchOptions.h b/include/clang/Frontend/HeaderSearchOptions.h index 67129775ac8d..690408547c0d 100644 --- a/include/clang/Frontend/HeaderSearchOptions.h +++ b/include/clang/Frontend/HeaderSearchOptions.h @@ -61,9 +61,12 @@ class HeaderSearchOptions { std::string CXXEnvIncPath; std::string ObjCXXEnvIncPath; - /// If non-empty, the path to the compiler builtin include directory, which - /// will be searched following the user and environment includes. - std::string BuiltinIncludePath; + /// The directory which holds the compiler resource files (builtin includes, + /// etc.). + std::string ResourceDir; + + /// Include the compiler builtin includes. + unsigned UseBuiltinIncludes : 1; /// Include the system standard include search directories. unsigned UseStandardIncludes : 1; @@ -73,7 +76,8 @@ class HeaderSearchOptions { public: HeaderSearchOptions(llvm::StringRef _Sysroot = "/") - : Sysroot(_Sysroot), UseStandardIncludes(true), Verbose(false) {} + : Sysroot(_Sysroot), UseBuiltinIncludes(true), + UseStandardIncludes(true), Verbose(false) {} /// AddPath - Add the \arg Path path to the specified \arg Group list. void AddPath(llvm::StringRef Path, frontend::IncludeDirGroup Group, diff --git a/include/clang/Frontend/PCHBitCodes.h b/include/clang/Frontend/PCHBitCodes.h index 98463c308e51..c8c49c83f940 100644 --- a/include/clang/Frontend/PCHBitCodes.h +++ b/include/clang/Frontend/PCHBitCodes.h @@ -404,7 +404,9 @@ namespace clang { /// \brief An ElaboratedType record. TYPE_ELABORATED = 24, /// \brief A SubstTemplateTypeParmType record. - TYPE_SUBST_TEMPLATE_TYPE_PARM = 25 + TYPE_SUBST_TEMPLATE_TYPE_PARM = 25, + /// \brief An UnresolvedUsingType record. + TYPE_UNRESOLVED_USING = 26 }; /// \brief The type IDs for special types constructed by semantic diff --git a/include/clang/Frontend/PCHReader.h b/include/clang/Frontend/PCHReader.h index 85861fab4a22..7e2c65690fd6 100644 --- a/include/clang/Frontend/PCHReader.h +++ b/include/clang/Frontend/PCHReader.h @@ -530,7 +530,8 @@ class PCHReader /// \brief Retrieve the name of the original source file name /// directly from the PCH file, without actually loading the PCH /// file. - static std::string getOriginalSourceFile(const std::string &PCHFileName); + static std::string getOriginalSourceFile(const std::string &PCHFileName, + Diagnostic &Diags); /// \brief Returns the suggested contents of the predefines buffer, /// which contains a (typically-empty) subset of the predefines @@ -552,7 +553,7 @@ class PCHReader const RecordData &Record, unsigned &Idx); /// \brief Reads a declarator info from the given record. - virtual DeclaratorInfo *GetDeclaratorInfo(const RecordData &Record, + virtual TypeSourceInfo *GetTypeSourceInfo(const RecordData &Record, unsigned &Idx); /// \brief Resolve a type ID into a type, potentially building a new @@ -625,6 +626,9 @@ class PCHReader /// tree. virtual void InitializeSema(Sema &S); + /// \brief Inform the semantic consumer that Sema is no longer available. + virtual void ForgetSema() { SemaObj = 0; } + /// \brief Retrieve the IdentifierInfo for the named identifier. /// /// This routine builds a new IdentifierInfo for the given identifier. If any diff --git a/include/clang/Frontend/PCHWriter.h b/include/clang/Frontend/PCHWriter.h index b520f4be1d31..212130e2ea62 100644 --- a/include/clang/Frontend/PCHWriter.h +++ b/include/clang/Frontend/PCHWriter.h @@ -44,7 +44,6 @@ class TargetInfo; /// DenseMap. This uses the standard pointer hash function. struct UnsafeQualTypeDenseMapInfo { static inline bool isEqual(QualType A, QualType B) { return A == B; } - static inline bool isPod() { return true; } static inline QualType getEmptyKey() { return QualType::getFromOpaquePtr((void*) 1); } @@ -274,7 +273,7 @@ class PCHWriter { void AddTypeRef(QualType T, RecordData &Record); /// \brief Emits a reference to a declarator info. - void AddDeclaratorInfo(DeclaratorInfo *DInfo, RecordData &Record); + void AddTypeSourceInfo(TypeSourceInfo *TInfo, RecordData &Record); /// \brief Emits a template argument location. void AddTemplateArgumentLoc(const TemplateArgumentLoc &Arg, diff --git a/include/clang/Frontend/PreprocessorOptions.h b/include/clang/Frontend/PreprocessorOptions.h index f0c1d3c2c38d..c43a1feb8c05 100644 --- a/include/clang/Frontend/PreprocessorOptions.h +++ b/include/clang/Frontend/PreprocessorOptions.h @@ -13,6 +13,7 @@ #include "llvm/ADT/StringRef.h" #include #include +#include #include namespace clang { @@ -41,6 +42,21 @@ class PreprocessorOptions { /// If given, a PTH cache file to use for speeding up header parsing. std::string TokenCache; + /// \brief The set of file remappings, which take existing files on + /// the system (the first part of each pair) and gives them the + /// contents of other files on the system (the second part of each + /// pair). + std::vector > RemappedFiles; + + typedef std::vector >::const_iterator + remapped_file_iterator; + remapped_file_iterator remapped_file_begin() const { + return RemappedFiles.begin(); + } + remapped_file_iterator remapped_file_end() const { + return RemappedFiles.end(); + } + public: PreprocessorOptions() : UsePredefines(true) {} @@ -50,6 +66,9 @@ class PreprocessorOptions { void addMacroUndef(llvm::StringRef Name) { Macros.push_back(std::make_pair(Name, true)); } + void addRemappedFile(llvm::StringRef From, llvm::StringRef To) { + RemappedFiles.push_back(std::make_pair(From, To)); + } }; } // end namespace clang diff --git a/include/clang/Analysis/CallGraph.h b/include/clang/Index/CallGraph.h similarity index 100% rename from include/clang/Analysis/CallGraph.h rename to include/clang/Index/CallGraph.h diff --git a/include/clang/Index/Entity.h b/include/clang/Index/Entity.h index 4533a1a0ac08..c2aab62e23f2 100644 --- a/include/clang/Index/Entity.h +++ b/include/clang/Index/Entity.h @@ -134,9 +134,10 @@ struct DenseMapInfo { isEqual(clang::idx::Entity LHS, clang::idx::Entity RHS) { return LHS == RHS; } - - static inline bool isPod() { return true; } }; + +template <> +struct isPodLike { static const bool value = true; }; } // end namespace llvm diff --git a/include/clang/Index/GlobalSelector.h b/include/clang/Index/GlobalSelector.h index 51f98267f356..9cd83a8595b9 100644 --- a/include/clang/Index/GlobalSelector.h +++ b/include/clang/Index/GlobalSelector.h @@ -90,9 +90,10 @@ struct DenseMapInfo { isEqual(clang::idx::GlobalSelector LHS, clang::idx::GlobalSelector RHS) { return LHS == RHS; } - - static inline bool isPod() { return true; } }; + +template <> +struct isPodLike { static const bool value = true;}; } // end namespace llvm diff --git a/include/clang/Lex/Lexer.h b/include/clang/Lex/Lexer.h index 52bf194883df..fc65b1fc5449 100644 --- a/include/clang/Lex/Lexer.h +++ b/include/clang/Lex/Lexer.h @@ -38,8 +38,8 @@ class Lexer : public PreprocessorLexer { const char *BufferEnd; // End of the buffer. SourceLocation FileLoc; // Location for start of file. LangOptions Features; // Features enabled by this language (cache). - bool Is_PragmaLexer; // True if lexer for _Pragma handling. - bool IsEofCodeCompletion; // True if EOF is treated as a code-completion. + bool Is_PragmaLexer : 1; // True if lexer for _Pragma handling. + bool IsInConflictMarker : 1; // True if in a VCS conflict marker '<<<<<<<' //===--------------------------------------------------------------------===// // Context-specific lexing flags set by the preprocessor. @@ -180,15 +180,6 @@ class Lexer : public PreprocessorLexer { ExtendedTokenMode = Mode ? 1 : 0; } - /// \brief Specify that end-of-file is to be considered a code-completion - /// token. - /// - /// When in this mode, the end-of-file token will be immediately preceded - /// by a code-completion token. - void SetEofIsCodeCompletion(bool Val = true) { - IsEofCodeCompletion = Val; - } - const char *getBufferStart() const { return BufferStart; } /// ReadToEndOfLine - Read the rest of the current preprocessor line as an @@ -379,6 +370,9 @@ class Lexer : public PreprocessorLexer { bool SkipBCPLComment (Token &Result, const char *CurPtr); bool SkipBlockComment (Token &Result, const char *CurPtr); bool SaveBCPLComment (Token &Result, const char *CurPtr); + + bool IsStartOfConflictMarker(const char *CurPtr); + bool HandleEndOfConflictMarker(const char *CurPtr); }; diff --git a/include/clang/Lex/Preprocessor.h b/include/clang/Lex/Preprocessor.h index edd34b718969..7c838ff86243 100644 --- a/include/clang/Lex/Preprocessor.h +++ b/include/clang/Lex/Preprocessor.h @@ -91,12 +91,14 @@ class Preprocessor { bool KeepMacroComments : 1; // State that changes while the preprocessor runs: - bool DisableMacroExpansion : 1; // True if macro expansion is disabled. bool InMacroArgs : 1; // True if parsing fn macro invocation args. /// Whether the preprocessor owns the header search object. bool OwnsHeaderSearch : 1; + /// DisableMacroExpansion - True if macro expansion is disabled. + bool DisableMacroExpansion : 1; + /// Identifiers - This is mapping/lookup information for all identifiers in /// the program, including program keywords. mutable IdentifierTable Identifiers; @@ -121,6 +123,9 @@ class Preprocessor { /// with this preprocessor. std::vector CommentHandlers; + /// \brief The file that we're performing code-completion for, if any. + const FileEntry *CodeCompletionFile; + /// CurLexer - This is the current top of the stack that we're lexing from if /// not expanding a macro and we are lexing directly from source code. /// Only one of CurLexer, CurPTHLexer, or CurTokenLexer will be non-null. @@ -134,7 +139,7 @@ class Preprocessor { /// CurPPLexer - This is the current top of the stack what we're lexing from /// if not expanding a macro. This is an alias for either CurLexer or /// CurPTHLexer. - PreprocessorLexer* CurPPLexer; + PreprocessorLexer *CurPPLexer; /// CurLookup - The DirectoryLookup structure used to find the current /// FileEntry, if CurLexer is non-null and if applicable. This allows us to @@ -171,8 +176,14 @@ class Preprocessor { llvm::DenseMap Macros; /// MICache - A "freelist" of MacroInfo objects that can be reused for quick - /// allocation. + /// allocation. + /// FIXME: why not use a singly linked list? std::vector MICache; + + /// MacroArgCache - This is a "freelist" of MacroArg objects that can be + /// reused for quick allocation. + MacroArgs *MacroArgCache; + friend class MacroArgs; // Various statistics we track for performance analysis. unsigned NumDirectives, NumIncluded, NumDefined, NumUndefined, NumPragma; @@ -330,8 +341,9 @@ class Preprocessor { /// EnterSourceFile - Add a source file to the top of the include stack and /// start lexing tokens from it instead of the current buffer. Return true - /// on failure. - bool EnterSourceFile(FileID CurFileID, const DirectoryLookup *Dir); + /// and fill in ErrorStr with the error information on failure. + bool EnterSourceFile(FileID CurFileID, const DirectoryLookup *Dir, + std::string &ErrorStr); /// EnterMacro - Add a Macro to the top of the include stack and start lexing /// tokens from it instead of the current buffer. Args specifies the @@ -484,6 +496,27 @@ class Preprocessor { CachedTokens[CachedLexPos-1] = Tok; } + /// \brief Specify the point at which code-completion will be performed. + /// + /// \param File the file in which code completion should occur. If + /// this file is included multiple times, code-completion will + /// perform completion the first time it is included. If NULL, this + /// function clears out the code-completion point. + /// + /// \param Line the line at which code completion should occur + /// (1-based). + /// + /// \param Column the column at which code completion should occur + /// (1-based). + /// + /// \returns true if an error occurred, false otherwise. + bool SetCodeCompletionPoint(const FileEntry *File, + unsigned Line, unsigned Column); + + /// \brief Determine if this source location refers into the file + /// for which we are performing code completion. + bool isCodeCompletionFile(SourceLocation FileLoc) const; + /// Diag - Forwarding function for diagnostics. This emits a diagnostic at /// the specified Token's location, translating the token's start /// position in the current buffer into a SourcePosition object for rendering. diff --git a/include/clang/Parse/Action.h b/include/clang/Parse/Action.h index fc56cc68476e..b7540f9993d0 100644 --- a/include/clang/Parse/Action.h +++ b/include/clang/Parse/Action.h @@ -334,6 +334,20 @@ class Action : public ActionBase { bool EnteringContext) { return 0; } + + /// IsInvalidUnlessNestedName - This method is used for error recovery + /// purposes to determine whether the specified identifier is only valid as + /// a nested name specifier, for example a namespace name. It is + /// conservatively correct to always return false from this method. + /// + /// The arguments are the same as those passed to ActOnCXXNestedNameSpecifier. + virtual bool IsInvalidUnlessNestedName(Scope *S, + const CXXScopeSpec &SS, + IdentifierInfo &II, + TypeTy *ObjectType, + bool EnteringContext) { + return false; + } /// ActOnCXXNestedNameSpecifier - Called during parsing of a /// nested-name-specifier that involves a template-id, e.g., @@ -351,8 +365,19 @@ class Action : public ActionBase { return 0; } + /// ShouldEnterDeclaratorScope - Called when a C++ scope specifier + /// is parsed as part of a declarator-id to determine whether a scope + /// should be entered. + /// + /// \param S the current scope + /// \param SS the scope being entered + /// \param isFriendDeclaration whether this is a friend declaration + virtual bool ShouldEnterDeclaratorScope(Scope *S, const CXXScopeSpec &SS) { + return false; + } + /// ActOnCXXEnterDeclaratorScope - Called when a C++ scope specifier (global - /// scope or nested-name-specifier) is parsed, part of a declarator-id. + /// scope or nested-name-specifier) is parsed as part of a declarator-id. /// After this method is called, according to [C++ 3.4.3p3], names should be /// looked up in the declarator-id's scope, until the declarator is parsed and /// ActOnCXXExitDeclaratorScope is called. @@ -1250,6 +1275,10 @@ class Action : public ActionBase { /// /// \param AS the currently-active access specifier. /// + /// \param HasUsingKeyword true if this was declared with an + /// explicit 'using' keyword (i.e. if this is technically a using + /// declaration, not an access declaration) + /// /// \param UsingLoc the location of the 'using' keyword. /// /// \param SS the nested-name-specifier that precedes the name. @@ -1267,6 +1296,7 @@ class Action : public ActionBase { /// \returns a representation of the using declaration. virtual DeclPtrTy ActOnUsingDeclaration(Scope *CurScope, AccessSpecifier AS, + bool HasUsingKeyword, SourceLocation UsingLoc, const CXXScopeSpec &SS, UnqualifiedId &Name, @@ -2394,6 +2424,24 @@ class Action : public ActionBase { /// \param S the scope in which the operator keyword occurs. virtual void CodeCompleteOperatorName(Scope *S) { } + /// \brief Code completion after the '@' at the top level. + /// + /// \param S the scope in which the '@' occurs. + /// + /// \param ObjCImpDecl the Objective-C implementation or category + /// implementation. + /// + /// \param InInterface whether we are in an Objective-C interface or + /// protocol. + virtual void CodeCompleteObjCAtDirective(Scope *S, DeclPtrTy ObjCImpDecl, + bool InInterface) { } + + /// \brief Code completion after the '@' in a statement. + virtual void CodeCompleteObjCAtStatement(Scope *S) { } + + /// \brief Code completion after the '@' in an expression. + virtual void CodeCompleteObjCAtExpression(Scope *S) { } + /// \brief Code completion for an ObjC property decl. /// /// This code completion action is invoked when the code-completion token is diff --git a/include/clang/Parse/DeclSpec.h b/include/clang/Parse/DeclSpec.h index fe899b3fdb17..b766890b7023 100644 --- a/include/clang/Parse/DeclSpec.h +++ b/include/clang/Parse/DeclSpec.h @@ -27,6 +27,40 @@ namespace clang { class Declarator; struct TemplateIdAnnotation; +/// CXXScopeSpec - Represents a C++ nested-name-specifier or a global scope +/// specifier. +class CXXScopeSpec { + SourceRange Range; + void *ScopeRep; + +public: + CXXScopeSpec() : Range(), ScopeRep() { } + + const SourceRange &getRange() const { return Range; } + void setRange(const SourceRange &R) { Range = R; } + void setBeginLoc(SourceLocation Loc) { Range.setBegin(Loc); } + void setEndLoc(SourceLocation Loc) { Range.setEnd(Loc); } + SourceLocation getBeginLoc() const { return Range.getBegin(); } + SourceLocation getEndLoc() const { return Range.getEnd(); } + + ActionBase::CXXScopeTy *getScopeRep() const { return ScopeRep; } + void setScopeRep(ActionBase::CXXScopeTy *S) { ScopeRep = S; } + + bool isEmpty() const { return !Range.isValid(); } + bool isNotEmpty() const { return !isEmpty(); } + + /// isInvalid - An error occured during parsing of the scope specifier. + bool isInvalid() const { return isNotEmpty() && ScopeRep == 0; } + + /// isSet - A scope specifier was resolved to a valid C++ scope. + bool isSet() const { return ScopeRep != 0; } + + void clear() { + Range = SourceRange(); + ScopeRep = 0; + } +}; + /// DeclSpec - This class captures information about "declaration specifiers", /// which encompasses storage-class-specifiers, type-specifiers, /// type-qualifiers, and function-specifiers. @@ -143,6 +177,9 @@ class DeclSpec { // attributes. AttributeList *AttrList; + // Scope specifier for the type spec, if applicable. + CXXScopeSpec TypeScope; + // List of protocol qualifiers for objective-c classes. Used for // protocol-qualified interfaces "NString" and protocol-qualified id // "id". @@ -211,6 +248,8 @@ class DeclSpec { TST getTypeSpecType() const { return (TST)TypeSpecType; } bool isTypeSpecOwned() const { return TypeSpecOwned; } void *getTypeRep() const { return TypeRep; } + CXXScopeSpec &getTypeSpecScope() { return TypeScope; } + const CXXScopeSpec &getTypeSpecScope() const { return TypeScope; } const SourceRange &getSourceRange() const { return Range; } SourceLocation getTypeSpecWidthLoc() const { return TSWLoc; } @@ -436,40 +475,6 @@ class ObjCDeclSpec { IdentifierInfo *SetterName; // setter name of NULL if no setter }; -/// CXXScopeSpec - Represents a C++ nested-name-specifier or a global scope -/// specifier. -class CXXScopeSpec { - SourceRange Range; - void *ScopeRep; - -public: - CXXScopeSpec() : Range(), ScopeRep() { } - - const SourceRange &getRange() const { return Range; } - void setRange(const SourceRange &R) { Range = R; } - void setBeginLoc(SourceLocation Loc) { Range.setBegin(Loc); } - void setEndLoc(SourceLocation Loc) { Range.setEnd(Loc); } - SourceLocation getBeginLoc() const { return Range.getBegin(); } - SourceLocation getEndLoc() const { return Range.getEnd(); } - - ActionBase::CXXScopeTy *getScopeRep() const { return ScopeRep; } - void setScopeRep(ActionBase::CXXScopeTy *S) { ScopeRep = S; } - - bool isEmpty() const { return !Range.isValid(); } - bool isNotEmpty() const { return !isEmpty(); } - - /// isInvalid - An error occured during parsing of the scope specifier. - bool isInvalid() const { return isNotEmpty() && ScopeRep == 0; } - - /// isSet - A scope specifier was resolved to a valid C++ scope. - bool isSet() const { return ScopeRep != 0; } - - void clear() { - Range = SourceRange(); - ScopeRep = 0; - } -}; - /// \brief Represents a C++ unqualified-id that has been parsed. class UnqualifiedId { private: diff --git a/include/clang/Parse/Parser.h b/include/clang/Parse/Parser.h index 81a80ebcbc61..e47de506fd1f 100644 --- a/include/clang/Parse/Parser.h +++ b/include/clang/Parse/Parser.h @@ -30,6 +30,7 @@ namespace clang { class DiagnosticBuilder; class Parser; class PragmaUnusedHandler; + class ColonProtectionRAIIObject; /// PrettyStackTraceParserEntry - If a crash happens while the parser is active, /// an entry is printed for it. @@ -47,6 +48,7 @@ class PrettyStackTraceParserEntry : public llvm::PrettyStackTraceEntry { /// class Parser { friend class PragmaUnusedHandler; + friend class ColonProtectionRAIIObject; PrettyStackTraceParserEntry CrashInfo; Preprocessor &PP; @@ -90,26 +92,16 @@ class Parser { /// template argument list, where the '>' closes the template /// argument list. bool GreaterThanIsOperator; + + /// ColonIsSacred - When this is false, we aggressively try to recover from + /// code like "foo : bar" as if it were a typo for "foo :: bar". This is not + /// safe in case statements and a few other things. This is managed by the + /// ColonProtectionRAIIObject RAII object. + bool ColonIsSacred; /// The "depth" of the template parameters currently being parsed. unsigned TemplateParameterDepth; - /// \brief RAII object that makes '>' behave either as an operator - /// or as the closing angle bracket for a template argument list. - struct GreaterThanIsOperatorScope { - bool &GreaterThanIsOperator; - bool OldGreaterThanIsOperator; - - GreaterThanIsOperatorScope(bool >IO, bool Val) - : GreaterThanIsOperator(GTIO), OldGreaterThanIsOperator(GTIO) { - GreaterThanIsOperator = Val; - } - - ~GreaterThanIsOperatorScope() { - GreaterThanIsOperator = OldGreaterThanIsOperator; - } - }; - public: Parser(Preprocessor &PP, Action &Actions); ~Parser(); @@ -759,7 +751,10 @@ class Parser { bool isStartOfFunctionDefinition(); DeclGroupPtrTy ParseDeclarationOrFunctionDefinition(AttributeList *Attr, AccessSpecifier AS = AS_none); - + DeclGroupPtrTy ParseDeclarationOrFunctionDefinition(ParsingDeclSpec &DS, + AttributeList *Attr, + AccessSpecifier AS = AS_none); + DeclPtrTy ParseFunctionDefinition(ParsingDeclarator &D, const ParsedTemplateInfo &TemplateInfo = ParsedTemplateInfo()); void ParseKNRParamDeclarations(Declarator &D); @@ -1087,6 +1082,7 @@ class Parser { private: virtual void _anchor(); }; + struct ObjCPropertyCallback; void ParseStructDeclaration(DeclSpec &DS, FieldCallback &Callback); @@ -1288,7 +1284,7 @@ class Parser { tok::TokenKind *After = 0); DeclPtrTy ParseNamespace(unsigned Context, SourceLocation &DeclEnd); - DeclPtrTy ParseLinkage(unsigned Context); + DeclPtrTy ParseLinkage(ParsingDeclSpec &DS, unsigned Context); DeclPtrTy ParseUsingDirectiveOrDeclaration(unsigned Context, SourceLocation &DeclEnd, CXX0XAttributeList Attrs); diff --git a/include/clang/Sema/ExternalSemaSource.h b/include/clang/Sema/ExternalSemaSource.h index 05c56451b218..d27e29281b5a 100644 --- a/include/clang/Sema/ExternalSemaSource.h +++ b/include/clang/Sema/ExternalSemaSource.h @@ -34,6 +34,9 @@ class ExternalSemaSource : public ExternalASTSource { /// tree. virtual void InitializeSema(Sema &S) {} + /// \brief Inform the semantic consumer that Sema is no longer available. + virtual void ForgetSema() {} + /// \brief Load the contents of the global method pool for a given /// selector. /// diff --git a/include/clang/Sema/SemaConsumer.h b/include/clang/Sema/SemaConsumer.h index b213daf8a39e..3689a6e7a820 100644 --- a/include/clang/Sema/SemaConsumer.h +++ b/include/clang/Sema/SemaConsumer.h @@ -34,6 +34,9 @@ namespace clang { /// tree. virtual void InitializeSema(Sema &S) {} + /// \brief Inform the semantic consumer that Sema is no longer available. + virtual void ForgetSema() {} + // isa/cast/dyn_cast support static bool classof(const ASTConsumer *Consumer) { return Consumer->SemaConsumer; diff --git a/lib/AST/ASTContext.cpp b/lib/AST/ASTContext.cpp index 6c9ecf089b98..cc7055dc68b8 100644 --- a/lib/AST/ASTContext.cpp +++ b/lib/AST/ASTContext.cpp @@ -260,24 +260,40 @@ ASTContext::setInstantiatedFromStaticDataMember(VarDecl *Inst, VarDecl *Tmpl, } NamedDecl * -ASTContext::getInstantiatedFromUnresolvedUsingDecl(UsingDecl *UUD) { +ASTContext::getInstantiatedFromUsingDecl(UsingDecl *UUD) { llvm::DenseMap::const_iterator Pos - = InstantiatedFromUnresolvedUsingDecl.find(UUD); - if (Pos == InstantiatedFromUnresolvedUsingDecl.end()) + = InstantiatedFromUsingDecl.find(UUD); + if (Pos == InstantiatedFromUsingDecl.end()) return 0; return Pos->second; } void -ASTContext::setInstantiatedFromUnresolvedUsingDecl(UsingDecl *UD, - NamedDecl *UUD) { - assert((isa(UUD) || - isa(UUD)) && - "original declaration is not an unresolved using decl"); - assert(!InstantiatedFromUnresolvedUsingDecl[UD] && - "Already noted what using decl what instantiated from"); - InstantiatedFromUnresolvedUsingDecl[UD] = UUD; +ASTContext::setInstantiatedFromUsingDecl(UsingDecl *Inst, NamedDecl *Pattern) { + assert((isa(Pattern) || + isa(Pattern) || + isa(Pattern)) && + "pattern decl is not a using decl"); + assert(!InstantiatedFromUsingDecl[Inst] && "pattern already exists"); + InstantiatedFromUsingDecl[Inst] = Pattern; +} + +UsingShadowDecl * +ASTContext::getInstantiatedFromUsingShadowDecl(UsingShadowDecl *Inst) { + llvm::DenseMap::const_iterator Pos + = InstantiatedFromUsingShadowDecl.find(Inst); + if (Pos == InstantiatedFromUsingShadowDecl.end()) + return 0; + + return Pos->second; +} + +void +ASTContext::setInstantiatedFromUsingShadowDecl(UsingShadowDecl *Inst, + UsingShadowDecl *Pattern) { + assert(!InstantiatedFromUsingShadowDecl[Inst] && "pattern already exists"); + InstantiatedFromUsingShadowDecl[Inst] = Pattern; } FieldDecl *ASTContext::getInstantiatedFromUnnamedFieldDecl(FieldDecl *Field) { @@ -711,10 +727,6 @@ ASTContext::getTypeInfo(const Type *T) { break; } case Type::MemberPointer: { - // FIXME: This is ABI dependent. We use the Itanium C++ ABI. - // http://www.codesourcery.com/public/cxx-abi/abi.html#member-pointers - // If we ever want to support other ABIs this needs to be abstracted. - QualType Pointee = cast(T)->getPointeeType(); std::pair PtrDiffInfo = getTypeInfo(getPointerDiffType()); @@ -997,31 +1009,31 @@ void ASTContext::setObjCImplementation(ObjCCategoryDecl *CatD, ObjCImpls[CatD] = ImplD; } -/// \brief Allocate an uninitialized DeclaratorInfo. +/// \brief Allocate an uninitialized TypeSourceInfo. /// -/// The caller should initialize the memory held by DeclaratorInfo using +/// The caller should initialize the memory held by TypeSourceInfo using /// the TypeLoc wrappers. /// /// \param T the type that will be the basis for type source info. This type /// should refer to how the declarator was written in source code, not to /// what type semantic analysis resolved the declarator to. -DeclaratorInfo *ASTContext::CreateDeclaratorInfo(QualType T, +TypeSourceInfo *ASTContext::CreateTypeSourceInfo(QualType T, unsigned DataSize) { if (!DataSize) DataSize = TypeLoc::getFullDataSizeForType(T); else assert(DataSize == TypeLoc::getFullDataSizeForType(T) && - "incorrect data size provided to CreateDeclaratorInfo!"); + "incorrect data size provided to CreateTypeSourceInfo!"); - DeclaratorInfo *DInfo = - (DeclaratorInfo*)BumpAlloc.Allocate(sizeof(DeclaratorInfo) + DataSize, 8); - new (DInfo) DeclaratorInfo(T); - return DInfo; + TypeSourceInfo *TInfo = + (TypeSourceInfo*)BumpAlloc.Allocate(sizeof(TypeSourceInfo) + DataSize, 8); + new (TInfo) TypeSourceInfo(T); + return TInfo; } -DeclaratorInfo *ASTContext::getTrivialDeclaratorInfo(QualType T, +TypeSourceInfo *ASTContext::getTrivialTypeSourceInfo(QualType T, SourceLocation L) { - DeclaratorInfo *DI = CreateDeclaratorInfo(T); + TypeSourceInfo *DI = CreateTypeSourceInfo(T); DI->getTypeLoc().initialize(L); return DI; } @@ -1092,6 +1104,20 @@ const ASTRecordLayout &ASTContext::getASTRecordLayout(const RecordDecl *D) { return *NewEntry; } +const CXXMethodDecl *ASTContext::getKeyFunction(const CXXRecordDecl *RD) { + RD = cast(RD->getDefinition(*this)); + assert(RD && "Cannot get key function for forward declarations!"); + + const CXXMethodDecl *&Entry = KeyFunctions[RD]; + if (!Entry) + Entry = ASTRecordLayoutBuilder::ComputeKeyFunction(RD); + else + assert(Entry == ASTRecordLayoutBuilder::ComputeKeyFunction(RD) && + "Key function changed!"); + + return Entry; +} + //===----------------------------------------------------------------------===// // Type creation/memoization methods //===----------------------------------------------------------------------===// @@ -1174,32 +1200,42 @@ QualType ASTContext::getObjCGCQualType(QualType T, return getExtQualType(TypeNode, Quals); } -QualType ASTContext::getNoReturnType(QualType T) { +QualType ASTContext::getNoReturnType(QualType T, bool AddNoReturn) { QualType ResultType; - if (T->isPointerType()) { - QualType Pointee = T->getAs()->getPointeeType(); - ResultType = getNoReturnType(Pointee); + if (const PointerType *Pointer = T->getAs()) { + QualType Pointee = Pointer->getPointeeType(); + ResultType = getNoReturnType(Pointee, AddNoReturn); + if (ResultType == Pointee) + return T; + ResultType = getPointerType(ResultType); - } else if (T->isBlockPointerType()) { - QualType Pointee = T->getAs()->getPointeeType(); - ResultType = getNoReturnType(Pointee); + } else if (const BlockPointerType *BlockPointer + = T->getAs()) { + QualType Pointee = BlockPointer->getPointeeType(); + ResultType = getNoReturnType(Pointee, AddNoReturn); + if (ResultType == Pointee) + return T; + ResultType = getBlockPointerType(ResultType); - } else { - assert (T->isFunctionType() - && "can't noreturn qualify non-pointer to function or block type"); - - if (const FunctionNoProtoType *FNPT = T->getAs()) { - ResultType = getFunctionNoProtoType(FNPT->getResultType(), true); + } else if (const FunctionType *F = T->getAs()) { + if (F->getNoReturnAttr() == AddNoReturn) + return T; + + if (const FunctionNoProtoType *FNPT = dyn_cast(F)) { + ResultType = getFunctionNoProtoType(FNPT->getResultType(), AddNoReturn); } else { - const FunctionProtoType *F = T->getAs(); + const FunctionProtoType *FPT = cast(F); ResultType - = getFunctionType(F->getResultType(), F->arg_type_begin(), - F->getNumArgs(), F->isVariadic(), F->getTypeQuals(), - F->hasExceptionSpec(), F->hasAnyExceptionSpec(), - F->getNumExceptions(), F->exception_begin(), true); + = getFunctionType(FPT->getResultType(), FPT->arg_type_begin(), + FPT->getNumArgs(), FPT->isVariadic(), + FPT->getTypeQuals(), + FPT->hasExceptionSpec(), FPT->hasAnyExceptionSpec(), + FPT->getNumExceptions(), FPT->exception_begin(), + AddNoReturn); } - } - + } else + return T; + return getQualifiedType(ResultType, T.getLocalQualifiers()); } @@ -1766,6 +1802,9 @@ QualType ASTContext::getTypeDeclType(TypeDecl *Decl, TypeDecl* PrevDecl) { Decl->TypeForDecl = PrevDecl->TypeForDecl; else Decl->TypeForDecl = new (*this, TypeAlignment) EnumType(Enum); + } else if (UnresolvedUsingTypenameDecl *Using = + dyn_cast(Decl)) { + Decl->TypeForDecl = new (*this, TypeAlignment) UnresolvedUsingType(Using); } else assert(false && "TypeDecl without a type?"); @@ -2238,7 +2277,7 @@ QualType ASTContext::getTagDeclType(const TagDecl *Decl) { /// getSizeType - Return the unique type for "size_t" (C99 7.17), the result /// of the sizeof operator (C99 6.5.3.4p4). The value is target dependent and /// needs to agree with the definition in . -QualType ASTContext::getSizeType() const { +CanQualType ASTContext::getSizeType() const { return getFromTargetType(Target.getSizeType()); } @@ -2354,8 +2393,9 @@ DeclarationName ASTContext::getNameForTemplate(TemplateName Name) { } } - assert(Name.getAsOverloadedFunctionDecl()); - return Name.getAsOverloadedFunctionDecl()->getDeclName(); + OverloadedTemplateStorage *Storage = Name.getAsOverloadedTemplate(); + assert(Storage); + return (*Storage->begin())->getDeclName(); } TemplateName ASTContext::getCanonicalTemplateName(TemplateName Name) { @@ -2364,27 +2404,7 @@ TemplateName ASTContext::getCanonicalTemplateName(TemplateName Name) { if (TemplateDecl *Template = Name.getAsTemplateDecl()) return TemplateName(cast(Template->getCanonicalDecl())); - // If this template name refers to a set of overloaded function templates, - /// the canonical template name merely stores the set of function templates. - if (OverloadedFunctionDecl *Ovl = Name.getAsOverloadedFunctionDecl()) { - OverloadedFunctionDecl *CanonOvl = 0; - for (OverloadedFunctionDecl::function_iterator F = Ovl->function_begin(), - FEnd = Ovl->function_end(); - F != FEnd; ++F) { - Decl *Canon = F->get()->getCanonicalDecl(); - if (CanonOvl || Canon != F->get()) { - if (!CanonOvl) - CanonOvl = OverloadedFunctionDecl::Create(*this, - Ovl->getDeclContext(), - Ovl->getDeclName()); - - CanonOvl->addOverload( - AnyFunctionDecl::getFromNamedDecl(cast(Canon))); - } - } - - return TemplateName(CanonOvl? CanonOvl : Ovl); - } + assert(!Name.getAsOverloadedTemplate()); DependentTemplateName *DTN = Name.getAsDependentTemplateName(); assert(DTN && "Non-dependent template names must refer to template decls."); @@ -2651,7 +2671,7 @@ int ASTContext::getFloatingTypeOrder(QualType LHS, QualType RHS) { unsigned ASTContext::getIntegerRank(Type *T) { assert(T->isCanonicalUnqualified() && "T should be canonicalized"); if (EnumType* ET = dyn_cast(T)) - T = ET->getDecl()->getIntegerType().getTypePtr(); + T = ET->getDecl()->getPromotionType().getTypePtr(); if (T->isSpecificBuiltinType(BuiltinType::WChar)) T = getFromTargetType(Target.getWCharType()).getTypePtr(); @@ -2732,6 +2752,8 @@ QualType ASTContext::isPromotableBitField(Expr *E) { QualType ASTContext::getPromotedIntegerType(QualType Promotable) { assert(!Promotable.isNull()); assert(Promotable->isPromotableIntegerType()); + if (const EnumType *ET = Promotable->getAs()) + return ET->getDecl()->getPromotionType(); if (Promotable->isSignedIntegerType()) return IntTy; uint64_t PromotableSize = getTypeSize(Promotable); @@ -2812,7 +2834,7 @@ QualType ASTContext::getCFConstantStringType() { for (unsigned i = 0; i < 4; ++i) { FieldDecl *Field = FieldDecl::Create(*this, CFConstantStringTypeDecl, SourceLocation(), 0, - FieldTypes[i], /*DInfo=*/0, + FieldTypes[i], /*TInfo=*/0, /*BitWidth=*/0, /*Mutable=*/false); CFConstantStringTypeDecl->addDecl(Field); @@ -2848,7 +2870,7 @@ QualType ASTContext::getObjCFastEnumerationStateType() { FieldDecl *Field = FieldDecl::Create(*this, ObjCFastEnumerationStateTypeDecl, SourceLocation(), 0, - FieldTypes[i], /*DInfo=*/0, + FieldTypes[i], /*TInfo=*/0, /*BitWidth=*/0, /*Mutable=*/false); ObjCFastEnumerationStateTypeDecl->addDecl(Field); @@ -2884,7 +2906,7 @@ QualType ASTContext::getBlockDescriptorType() { T, SourceLocation(), &Idents.get(FieldNames[i]), - FieldTypes[i], /*DInfo=*/0, + FieldTypes[i], /*TInfo=*/0, /*BitWidth=*/0, /*Mutable=*/false); T->addDecl(Field); @@ -2931,7 +2953,7 @@ QualType ASTContext::getBlockDescriptorExtendedType() { T, SourceLocation(), &Idents.get(FieldNames[i]), - FieldTypes[i], /*DInfo=*/0, + FieldTypes[i], /*TInfo=*/0, /*BitWidth=*/0, /*Mutable=*/false); T->addDecl(Field); @@ -3009,7 +3031,7 @@ QualType ASTContext::BuildByRefType(const char *DeclName, QualType Ty) { continue; FieldDecl *Field = FieldDecl::Create(*this, T, SourceLocation(), &Idents.get(FieldNames[i]), - FieldTypes[i], /*DInfo=*/0, + FieldTypes[i], /*TInfo=*/0, /*BitWidth=*/0, /*Mutable=*/false); T->addDecl(Field); } @@ -3052,7 +3074,7 @@ QualType ASTContext::getBlockParmType( for (size_t i = 0; i < 5; ++i) { FieldDecl *Field = FieldDecl::Create(*this, T, SourceLocation(), &Idents.get(FieldNames[i]), - FieldTypes[i], /*DInfo=*/0, + FieldTypes[i], /*TInfo=*/0, /*BitWidth=*/0, /*Mutable=*/false); T->addDecl(Field); } @@ -3072,7 +3094,7 @@ QualType ASTContext::getBlockParmType( FieldType); FieldDecl *Field = FieldDecl::Create(*this, T, SourceLocation(), - Name, FieldType, /*DInfo=*/0, + Name, FieldType, /*TInfo=*/0, /*BitWidth=*/0, /*Mutable=*/false); T->addDecl(Field); } @@ -3690,6 +3712,29 @@ void ASTContext::setObjCConstantStringInterface(ObjCInterfaceDecl *Decl) { ObjCConstantStringType = getObjCInterfaceType(Decl); } +/// \brief Retrieve the template name that corresponds to a non-empty +/// lookup. +TemplateName ASTContext::getOverloadedTemplateName(NamedDecl * const *Begin, + NamedDecl * const *End) { + unsigned size = End - Begin; + assert(size > 1 && "set is not overloaded!"); + + void *memory = Allocate(sizeof(OverloadedTemplateStorage) + + size * sizeof(FunctionTemplateDecl*)); + OverloadedTemplateStorage *OT = new(memory) OverloadedTemplateStorage(size); + + NamedDecl **Storage = OT->getStorage(); + for (NamedDecl * const *I = Begin; I != End; ++I) { + NamedDecl *D = *I; + assert(isa(D) || + (isa(D) && + isa(D->getUnderlyingDecl()))); + *Storage++ = D; + } + + return TemplateName(OT); +} + /// \brief Retrieve the template name that represents a qualified /// template name such as \c std::vector. TemplateName ASTContext::getQualifiedTemplateName(NestedNameSpecifier *NNS, @@ -3709,25 +3754,6 @@ TemplateName ASTContext::getQualifiedTemplateName(NestedNameSpecifier *NNS, return TemplateName(QTN); } -/// \brief Retrieve the template name that represents a qualified -/// template name such as \c std::vector. -TemplateName ASTContext::getQualifiedTemplateName(NestedNameSpecifier *NNS, - bool TemplateKeyword, - OverloadedFunctionDecl *Template) { - llvm::FoldingSetNodeID ID; - QualifiedTemplateName::Profile(ID, NNS, TemplateKeyword, Template); - - void *InsertPos = 0; - QualifiedTemplateName *QTN = - QualifiedTemplateNames.FindNodeOrInsertPos(ID, InsertPos); - if (!QTN) { - QTN = new (*this,4) QualifiedTemplateName(NNS, TemplateKeyword, Template); - QualifiedTemplateNames.InsertNode(QTN, InsertPos); - } - - return TemplateName(QTN); -} - /// \brief Retrieve the template name that represents a dependent /// template name such as \c MetaFun::template apply. TemplateName ASTContext::getDependentTemplateName(NestedNameSpecifier *NNS, @@ -4334,6 +4360,8 @@ QualType ASTContext::mergeTypes(QualType LHS, QualType RHS) { if (LHSClass != RHSClass) { // C99 6.7.2.2p4: Each enumerated type shall be compatible with char, // a signed integer type, or an unsigned integer type. + // Compatibility is based on the underlying type, not the promotion + // type. if (const EnumType* ETy = LHS->getAs()) { if (ETy->getDecl()->getIntegerType() == RHSCan.getUnqualifiedType()) return RHS; @@ -4493,6 +4521,8 @@ unsigned ASTContext::getIntWidth(QualType T) { if (FixedWidthIntType *FWIT = dyn_cast(T)) { return FWIT->getWidth(); } + if (EnumType *ET = dyn_cast(T)) + T = ET->getDecl()->getIntegerType(); // For builtin types, just use the standard type sizing method return (unsigned)getTypeSize(T); } diff --git a/lib/AST/CXXInheritance.cpp b/lib/AST/CXXInheritance.cpp index 023bca436339..92a58b76d878 100644 --- a/lib/AST/CXXInheritance.cpp +++ b/lib/AST/CXXInheritance.cpp @@ -90,6 +90,57 @@ bool CXXRecordDecl::isDerivedFrom(CXXRecordDecl *Base, CXXBasePaths &Paths) cons return lookupInBases(&FindBaseClass, Base->getCanonicalDecl(), Paths); } +static bool BaseIsNot(const CXXRecordDecl *Base, void *OpaqueTarget) { + // OpaqueTarget is a CXXRecordDecl*. + return Base->getCanonicalDecl() != (const CXXRecordDecl*) OpaqueTarget; +} + +bool CXXRecordDecl::isProvablyNotDerivedFrom(const CXXRecordDecl *Base) const { + return forallBases(BaseIsNot, (void*) Base->getCanonicalDecl()); +} + +bool CXXRecordDecl::forallBases(ForallBasesCallback *BaseMatches, + void *OpaqueData, + bool AllowShortCircuit) const { + ASTContext &Context = getASTContext(); + llvm::SmallVector Queue; + + const CXXRecordDecl *Record = this; + bool AllMatches = true; + while (true) { + for (CXXRecordDecl::base_class_const_iterator + I = Record->bases_begin(), E = Record->bases_end(); I != E; ++I) { + const RecordType *Ty = I->getType()->getAs(); + if (!Ty) { + if (AllowShortCircuit) return false; + AllMatches = false; + continue; + } + + CXXRecordDecl *Base = + cast_or_null(Ty->getDecl()->getDefinition(Context)); + if (!Base) { + if (AllowShortCircuit) return false; + AllMatches = false; + continue; + } + + Queue.push_back(Base); + if (!BaseMatches(Base, OpaqueData)) { + if (AllowShortCircuit) return false; + AllMatches = false; + continue; + } + } + + if (Queue.empty()) break; + Record = Queue.back(); // not actually a queue. + Queue.pop_back(); + } + + return AllMatches; +} + bool CXXRecordDecl::lookupInBases(BaseMatchesCallback *BaseMatches, void *UserData, CXXBasePaths &Paths) const { diff --git a/lib/AST/Decl.cpp b/lib/AST/Decl.cpp index 572d76ff72d2..4d0d4225ce73 100644 --- a/lib/AST/Decl.cpp +++ b/lib/AST/Decl.cpp @@ -38,7 +38,7 @@ void Attr::Destroy(ASTContext &C) { } /// \brief Return the TypeLoc wrapper for the type source info. -TypeLoc DeclaratorInfo::getTypeLoc() const { +TypeLoc TypeSourceInfo::getTypeLoc() const { return TypeLoc(Ty, (void*)(this + 1)); } @@ -86,17 +86,17 @@ const char *VarDecl::getStorageClassSpecifierString(StorageClass SC) { ParmVarDecl *ParmVarDecl::Create(ASTContext &C, DeclContext *DC, SourceLocation L, IdentifierInfo *Id, - QualType T, DeclaratorInfo *DInfo, + QualType T, TypeSourceInfo *TInfo, StorageClass S, Expr *DefArg) { - return new (C) ParmVarDecl(ParmVar, DC, L, Id, T, DInfo, S, DefArg); + return new (C) ParmVarDecl(ParmVar, DC, L, Id, T, TInfo, S, DefArg); } SourceRange ParmVarDecl::getDefaultArgRange() const { if (const Expr *E = getInit()) return E->getSourceRange(); - if (const Expr *E = getUninstantiatedDefaultArg()) - return E->getSourceRange(); + if (hasUninstantiatedDefaultArg()) + return getUninstantiatedDefaultArg()->getSourceRange(); return SourceRange(); } @@ -136,11 +136,11 @@ bool VarDecl::isExternC() const { FunctionDecl *FunctionDecl::Create(ASTContext &C, DeclContext *DC, SourceLocation L, DeclarationName N, QualType T, - DeclaratorInfo *DInfo, + TypeSourceInfo *TInfo, StorageClass S, bool isInline, bool hasWrittenPrototype) { FunctionDecl *New - = new (C) FunctionDecl(Function, DC, L, N, T, DInfo, S, isInline); + = new (C) FunctionDecl(Function, DC, L, N, T, TInfo, S, isInline); New->HasWrittenPrototype = hasWrittenPrototype; return New; } @@ -151,8 +151,8 @@ BlockDecl *BlockDecl::Create(ASTContext &C, DeclContext *DC, SourceLocation L) { FieldDecl *FieldDecl::Create(ASTContext &C, DeclContext *DC, SourceLocation L, IdentifierInfo *Id, QualType T, - DeclaratorInfo *DInfo, Expr *BW, bool Mutable) { - return new (C) FieldDecl(Decl::Field, DC, L, Id, T, DInfo, BW, Mutable); + TypeSourceInfo *TInfo, Expr *BW, bool Mutable) { + return new (C) FieldDecl(Decl::Field, DC, L, Id, T, TInfo, BW, Mutable); } bool FieldDecl::isAnonymousStructOrUnion() const { @@ -179,8 +179,8 @@ void EnumConstantDecl::Destroy(ASTContext& C) { TypedefDecl *TypedefDecl::Create(ASTContext &C, DeclContext *DC, SourceLocation L, IdentifierInfo *Id, - DeclaratorInfo *DInfo) { - return new (C) TypedefDecl(DC, L, Id, DInfo); + TypeSourceInfo *TInfo) { + return new (C) TypedefDecl(DC, L, Id, TInfo); } EnumDecl *EnumDecl::Create(ASTContext &C, DeclContext *DC, SourceLocation L, @@ -195,9 +195,12 @@ void EnumDecl::Destroy(ASTContext& C) { Decl::Destroy(C); } -void EnumDecl::completeDefinition(ASTContext &C, QualType NewType) { +void EnumDecl::completeDefinition(ASTContext &C, + QualType NewType, + QualType NewPromotionType) { assert(!isDefinition() && "Cannot redefine enums!"); IntegerType = NewType; + PromotionType = NewPromotionType; TagDecl::completeDefinition(); } @@ -535,9 +538,9 @@ SourceLocation DeclaratorDecl::getTypeSpecStartLoc() const { //===----------------------------------------------------------------------===// VarDecl *VarDecl::Create(ASTContext &C, DeclContext *DC, SourceLocation L, - IdentifierInfo *Id, QualType T, DeclaratorInfo *DInfo, + IdentifierInfo *Id, QualType T, TypeSourceInfo *TInfo, StorageClass S) { - return new (C) VarDecl(Var, DC, L, Id, T, DInfo, S); + return new (C) VarDecl(Var, DC, L, Id, T, TInfo, S); } void VarDecl::Destroy(ASTContext& C) { @@ -838,8 +841,20 @@ unsigned FunctionDecl::getMinRequiredArguments() const { } bool FunctionDecl::isInlined() const { - if (isInlineSpecified() || (isa(this) && !isOutOfLine())) + // FIXME: This is not enough. Consider: + // + // inline void f(); + // void f() { } + // + // f is inlined, but does not have inline specified. + // To fix this we should add an 'inline' flag to FunctionDecl. + if (isInlineSpecified()) return true; + + if (isa(this)) { + if (!isOutOfLine() || getCanonicalDecl()->isInlineSpecified()) + return true; + } switch (getTemplateSpecializationKind()) { case TSK_Undeclared: @@ -1199,7 +1214,7 @@ TagDecl* TagDecl::getDefinition(ASTContext& C) const { TagDecl::TagKind TagDecl::getTagKindForTypeSpec(unsigned TypeSpec) { switch (TypeSpec) { - default: llvm::llvm_unreachable("unexpected type specifier"); + default: llvm_unreachable("unexpected type specifier"); case DeclSpec::TST_struct: return TK_struct; case DeclSpec::TST_class: return TK_class; case DeclSpec::TST_union: return TK_union; diff --git a/lib/AST/DeclBase.cpp b/lib/AST/DeclBase.cpp index 2dcd80b01fcc..3afb4e44f3eb 100644 --- a/lib/AST/DeclBase.cpp +++ b/lib/AST/DeclBase.cpp @@ -190,7 +190,6 @@ unsigned Decl::getIdentifierNamespaceForKind(Kind DeclKind) { case CXXConstructor: case CXXDestructor: case CXXConversion: - case OverloadedFunction: case Typedef: case EnumConstant: case Var: @@ -199,7 +198,6 @@ unsigned Decl::getIdentifierNamespaceForKind(Kind DeclKind) { case NonTypeTemplateParm: case ObjCMethod: case ObjCContainer: - case ObjCCategory: case ObjCInterface: case ObjCProperty: case ObjCCompatibleAlias: @@ -221,8 +219,9 @@ unsigned Decl::getIdentifierNamespaceForKind(Kind DeclKind) { case ObjCImplementation: return IDNS_ObjCImplementation; + case ObjCCategory: case ObjCCategoryImpl: - return IDNS_ObjCCategoryImpl; + return IDNS_ObjCCategoryName; case Field: case ObjCAtDefsField: @@ -637,6 +636,46 @@ bool DeclContext::decls_empty() const { return !FirstDecl; } +void DeclContext::removeDecl(Decl *D) { + assert(D->getLexicalDeclContext() == this && + "decl being removed from non-lexical context"); + assert((D->NextDeclInContext || D == LastDecl) && + "decl is not in decls list"); + + // Remove D from the decl chain. This is O(n) but hopefully rare. + if (D == FirstDecl) { + if (D == LastDecl) + FirstDecl = LastDecl = 0; + else + FirstDecl = D->NextDeclInContext; + } else { + for (Decl *I = FirstDecl; true; I = I->NextDeclInContext) { + assert(I && "decl not found in linked list"); + if (I->NextDeclInContext == D) { + I->NextDeclInContext = D->NextDeclInContext; + if (D == LastDecl) LastDecl = I; + break; + } + } + } + + // Mark that D is no longer in the decl chain. + D->NextDeclInContext = 0; + + // Remove D from the lookup table if necessary. + if (isa(D)) { + NamedDecl *ND = cast(D); + + void *OpaqueMap = getPrimaryContext()->LookupPtr; + if (!OpaqueMap) return; + + StoredDeclsMap *Map = static_cast(OpaqueMap); + StoredDeclsMap::iterator Pos = Map->find(ND->getDeclName()); + assert(Pos != Map->end() && "no lookup entry for decl"); + Pos->second.remove(ND); + } +} + void DeclContext::addHiddenDecl(Decl *D) { assert(D->getLexicalDeclContext() == this && "Decl inserted into wrong lexical context"); @@ -742,6 +781,9 @@ void DeclContext::makeDeclVisibleInContext(NamedDecl *D, bool Recoverable) { // from being visible? if (isa(D)) return; + if (FunctionDecl *FD = dyn_cast(D)) + if (FD->isFunctionTemplateSpecialization()) + return; DeclContext *PrimaryContext = getPrimaryContext(); if (PrimaryContext != this) { diff --git a/lib/AST/DeclCXX.cpp b/lib/AST/DeclCXX.cpp index 40019880074a..292a3ed630ca 100644 --- a/lib/AST/DeclCXX.cpp +++ b/lib/AST/DeclCXX.cpp @@ -15,6 +15,7 @@ #include "clang/AST/DeclTemplate.h" #include "clang/AST/ASTContext.h" #include "clang/AST/Expr.h" +#include "clang/AST/TypeLoc.h" #include "clang/Basic/IdentifierTable.h" #include "llvm/ADT/STLExtras.h" #include "llvm/ADT/SmallPtrSet.h" @@ -438,6 +439,18 @@ void CXXRecordDecl::addConversionFunction(FunctionTemplateDecl *ConvDecl) { Conversions.addDecl(ConvDecl); } + +void CXXRecordDecl::setMethodAsVirtual(FunctionDecl *Method) { + Method->setVirtualAsWritten(true); + setAggregate(false); + setPOD(false); + setEmpty(false); + setPolymorphic(true); + setHasTrivialConstructor(false); + setHasTrivialCopyConstructor(false); + setHasTrivialCopyAssignment(false); +} + CXXRecordDecl *CXXRecordDecl::getInstantiatedFromMemberClass() const { if (MemberSpecializationInfo *MSInfo = getMemberSpecializationInfo()) return cast(MSInfo->getInstantiatedFrom()); @@ -459,8 +472,8 @@ CXXRecordDecl::setInstantiationOfMemberClass(CXXRecordDecl *RD, = new (getASTContext()) MemberSpecializationInfo(RD, TSK); } -TemplateSpecializationKind CXXRecordDecl::getTemplateSpecializationKind() { - if (ClassTemplateSpecializationDecl *Spec +TemplateSpecializationKind CXXRecordDecl::getTemplateSpecializationKind() const{ + if (const ClassTemplateSpecializationDecl *Spec = dyn_cast(this)) return Spec->getSpecializationKind(); @@ -507,8 +520,7 @@ CXXRecordDecl::getDefaultConstructor(ASTContext &Context) { return 0; } -const CXXDestructorDecl * -CXXRecordDecl::getDestructor(ASTContext &Context) { +CXXDestructorDecl *CXXRecordDecl::getDestructor(ASTContext &Context) { QualType ClassType = Context.getTypeDeclType(this); DeclarationName Name @@ -519,7 +531,7 @@ CXXRecordDecl::getDestructor(ASTContext &Context) { llvm::tie(I, E) = lookup(Name); assert(I != E && "Did not find a destructor!"); - const CXXDestructorDecl *Dtor = cast(*I); + CXXDestructorDecl *Dtor = cast(*I); assert(++I == E && "Found more than one destructor!"); return Dtor; @@ -528,9 +540,9 @@ CXXRecordDecl::getDestructor(ASTContext &Context) { CXXMethodDecl * CXXMethodDecl::Create(ASTContext &C, CXXRecordDecl *RD, SourceLocation L, DeclarationName N, - QualType T, DeclaratorInfo *DInfo, + QualType T, TypeSourceInfo *TInfo, bool isStatic, bool isInline) { - return new (C) CXXMethodDecl(CXXMethod, RD, L, N, T, DInfo, + return new (C) CXXMethodDecl(CXXMethod, RD, L, N, T, TInfo, isStatic, isInline); } @@ -577,6 +589,8 @@ typedef llvm::DenseMapisCanonicalDecl() && "Method is not canonical!"); + // FIXME: The CXXMethodDecl dtor needs to remove and free the entry. if (!OverriddenMethods) @@ -630,55 +644,107 @@ QualType CXXMethodDecl::getThisType(ASTContext &C) const { return C.getPointerType(ClassTy); } -CXXBaseOrMemberInitializer:: -CXXBaseOrMemberInitializer(QualType BaseType, Expr **Args, unsigned NumArgs, - CXXConstructorDecl *C, - SourceLocation L, SourceLocation R) - : Args(0), NumArgs(0), CtorOrAnonUnion(), IdLoc(L), RParenLoc(R) { - BaseOrMember = reinterpret_cast(BaseType.getTypePtr()); - assert((BaseOrMember & 0x01) == 0 && "Invalid base class type pointer"); - BaseOrMember |= 0x01; +static bool MethodHasBody(const CXXMethodDecl *MD, const FunctionDecl *&fn) { + // Simple case: function has a body + if (MD->getBody(fn)) + return true; - if (NumArgs > 0) { - this->NumArgs = NumArgs; - // FIXME. Allocation via Context - this->Args = new Stmt*[NumArgs]; - for (unsigned Idx = 0; Idx < NumArgs; ++Idx) - this->Args[Idx] = Args[Idx]; - } - CtorOrAnonUnion = C; + // Complex case: function is an instantiation of a function which has a + // body, but the definition hasn't been instantiated. + const FunctionDecl *PatternDecl = MD->getTemplateInstantiationPattern(); + if (PatternDecl && PatternDecl->getBody(fn)) + return true; + + return false; +} + +bool CXXMethodDecl::hasInlineBody() const { + const FunctionDecl *fn; + return MethodHasBody(this, fn) && !fn->isOutOfLine(); } CXXBaseOrMemberInitializer:: -CXXBaseOrMemberInitializer(FieldDecl *Member, Expr **Args, unsigned NumArgs, - CXXConstructorDecl *C, - SourceLocation L, SourceLocation R) - : Args(0), NumArgs(0), CtorOrAnonUnion(), IdLoc(L), RParenLoc(R) { - BaseOrMember = reinterpret_cast(Member); - assert((BaseOrMember & 0x01) == 0 && "Invalid member pointer"); - +CXXBaseOrMemberInitializer(ASTContext &Context, + TypeSourceInfo *TInfo, CXXConstructorDecl *C, + SourceLocation L, + Expr **Args, unsigned NumArgs, + SourceLocation R) + : BaseOrMember(TInfo), Args(0), NumArgs(0), CtorOrAnonUnion(C), + LParenLoc(L), RParenLoc(R) +{ if (NumArgs > 0) { this->NumArgs = NumArgs; - this->Args = new Stmt*[NumArgs]; + this->Args = new (Context) Stmt*[NumArgs]; for (unsigned Idx = 0; Idx < NumArgs; ++Idx) this->Args[Idx] = Args[Idx]; } - CtorOrAnonUnion = C; } -CXXBaseOrMemberInitializer::~CXXBaseOrMemberInitializer() { - delete [] Args; +CXXBaseOrMemberInitializer:: +CXXBaseOrMemberInitializer(ASTContext &Context, + FieldDecl *Member, SourceLocation MemberLoc, + CXXConstructorDecl *C, SourceLocation L, + Expr **Args, unsigned NumArgs, + SourceLocation R) + : BaseOrMember(Member), MemberLocation(MemberLoc), Args(0), NumArgs(0), + CtorOrAnonUnion(C), LParenLoc(L), RParenLoc(R) +{ + if (NumArgs > 0) { + this->NumArgs = NumArgs; + this->Args = new (Context) Stmt*[NumArgs]; + for (unsigned Idx = 0; Idx < NumArgs; ++Idx) + this->Args[Idx] = Args[Idx]; + } +} + +void CXXBaseOrMemberInitializer::Destroy(ASTContext &Context) { + for (unsigned I = 0; I != NumArgs; ++I) + Args[I]->Destroy(Context); + Context.Deallocate(Args); + this->~CXXBaseOrMemberInitializer(); +} + +TypeLoc CXXBaseOrMemberInitializer::getBaseClassLoc() const { + if (isBaseInitializer()) + return BaseOrMember.get()->getTypeLoc(); + else + return TypeLoc(); +} + +Type *CXXBaseOrMemberInitializer::getBaseClass() { + if (isBaseInitializer()) + return BaseOrMember.get()->getType().getTypePtr(); + else + return 0; +} + +const Type *CXXBaseOrMemberInitializer::getBaseClass() const { + if (isBaseInitializer()) + return BaseOrMember.get()->getType().getTypePtr(); + else + return 0; +} + +SourceLocation CXXBaseOrMemberInitializer::getSourceLocation() const { + if (isMemberInitializer()) + return getMemberLocation(); + + return getBaseClassLoc().getSourceRange().getBegin(); +} + +SourceRange CXXBaseOrMemberInitializer::getSourceRange() const { + return SourceRange(getSourceLocation(), getRParenLoc()); } CXXConstructorDecl * CXXConstructorDecl::Create(ASTContext &C, CXXRecordDecl *RD, SourceLocation L, DeclarationName N, - QualType T, DeclaratorInfo *DInfo, + QualType T, TypeSourceInfo *TInfo, bool isExplicit, bool isInline, bool isImplicitlyDeclared) { assert(N.getNameKind() == DeclarationName::CXXConstructorName && "Name must refer to a constructor"); - return new (C) CXXConstructorDecl(RD, L, N, T, DInfo, isExplicit, isInline, + return new (C) CXXConstructorDecl(RD, L, N, T, TInfo, isExplicit, isInline, isImplicitlyDeclared); } @@ -790,69 +856,11 @@ CXXConstructorDecl::Destroy(ASTContext& C) { CXXConversionDecl * CXXConversionDecl::Create(ASTContext &C, CXXRecordDecl *RD, SourceLocation L, DeclarationName N, - QualType T, DeclaratorInfo *DInfo, + QualType T, TypeSourceInfo *TInfo, bool isInline, bool isExplicit) { assert(N.getNameKind() == DeclarationName::CXXConversionFunctionName && "Name must refer to a conversion function"); - return new (C) CXXConversionDecl(RD, L, N, T, DInfo, isInline, isExplicit); -} - -OverloadedFunctionDecl * -OverloadedFunctionDecl::Create(ASTContext &C, DeclContext *DC, - DeclarationName N) { - return new (C) OverloadedFunctionDecl(DC, N); -} - -OverloadIterator::OverloadIterator(NamedDecl *ND) : D(0) { - if (!ND) - return; - - if (isa(ND) || isa(ND)) - D = ND; - else if (OverloadedFunctionDecl *Ovl = dyn_cast(ND)) { - if (Ovl->size() != 0) { - D = ND; - Iter = Ovl->function_begin(); - } - } -} - -void OverloadedFunctionDecl::addOverload(AnyFunctionDecl F) { - Functions.push_back(F); - this->setLocation(F.get()->getLocation()); -} - -OverloadIterator::reference OverloadIterator::operator*() const { - if (FunctionDecl *FD = dyn_cast(D)) - return FD; - - if (FunctionTemplateDecl *FTD = dyn_cast(D)) - return FTD; - - assert(isa(D)); - return *Iter; -} - -OverloadIterator &OverloadIterator::operator++() { - if (isa(D) || isa(D)) { - D = 0; - return *this; - } - - if (++Iter == cast(D)->function_end()) - D = 0; - - return *this; -} - -bool OverloadIterator::Equals(const OverloadIterator &Other) const { - if (!D || !Other.D) - return D == Other.D; - - if (D != Other.D) - return false; - - return !isa(D) || Iter == Other.Iter; + return new (C) CXXConversionDecl(RD, L, N, T, TInfo, isInline, isExplicit); } FriendDecl *FriendDecl::Create(ASTContext &C, DeclContext *DC, diff --git a/lib/AST/DeclObjC.cpp b/lib/AST/DeclObjC.cpp index c33720f5633a..2506f27e6f8c 100644 --- a/lib/AST/DeclObjC.cpp +++ b/lib/AST/DeclObjC.cpp @@ -501,9 +501,9 @@ bool ObjCInterfaceDecl::ClassImplementsProtocol(ObjCProtocolDecl *lProto, ObjCIvarDecl *ObjCIvarDecl::Create(ASTContext &C, DeclContext *DC, SourceLocation L, IdentifierInfo *Id, - QualType T, DeclaratorInfo *DInfo, + QualType T, TypeSourceInfo *TInfo, AccessControl ac, Expr *BW) { - return new (C) ObjCIvarDecl(DC, L, Id, T, DInfo, ac, BW); + return new (C) ObjCIvarDecl(DC, L, Id, T, TInfo, ac, BW); } diff --git a/lib/AST/DeclPrinter.cpp b/lib/AST/DeclPrinter.cpp index a5982cfd97f1..32ac53d85be8 100644 --- a/lib/AST/DeclPrinter.cpp +++ b/lib/AST/DeclPrinter.cpp @@ -52,7 +52,6 @@ namespace { void VisitVarDecl(VarDecl *D); void VisitParmVarDecl(ParmVarDecl *D); void VisitFileScopeAsmDecl(FileScopeAsmDecl *D); - void VisitOverloadedFunctionDecl(OverloadedFunctionDecl *D); void VisitNamespaceDecl(NamespaceDecl *D); void VisitUsingDirectiveDecl(UsingDirectiveDecl *D); void VisitNamespaceAliasDecl(NamespaceAliasDecl *D); @@ -149,6 +148,17 @@ void Decl::printGroup(Decl** Begin, unsigned NumDecls, } } +void DeclContext::dumpDeclContext() const { + // Get the translation unit + const DeclContext *DC = this; + while (!DC->isTranslationUnit()) + DC = DC->getParent(); + + ASTContext &Ctx = cast(DC)->getASTContext(); + DeclPrinter Printer(llvm::errs(), Ctx, Ctx.PrintingPolicy, 0); + Printer.VisitDeclContext(const_cast(this), /*Indent=*/false); +} + void Decl::dump() const { print(llvm::errs()); } @@ -362,6 +372,24 @@ void DeclPrinter::VisitFunctionDecl(FunctionDecl *D) { } Proto += ")"; + + if (FT && FT->hasExceptionSpec()) { + Proto += " throw("; + if (FT->hasAnyExceptionSpec()) + Proto += "..."; + else + for (unsigned I = 0, N = FT->getNumExceptions(); I != N; ++I) { + if (I) + Proto += ", "; + + + std::string ExceptionType; + FT->getExceptionType(I).getAsStringInternal(ExceptionType, SubPolicy); + Proto += ExceptionType; + } + Proto += ")"; + } + if (D->hasAttr()) Proto += " __attribute((noreturn))"; if (CXXConstructorDecl *CDecl = dyn_cast(D)) { @@ -488,11 +516,6 @@ void DeclPrinter::VisitFileScopeAsmDecl(FileScopeAsmDecl *D) { //---------------------------------------------------------------------------- // C++ declarations //---------------------------------------------------------------------------- -void DeclPrinter::VisitOverloadedFunctionDecl(OverloadedFunctionDecl *D) { - assert(false && - "OverloadedFunctionDecls aren't really decls and are never printed"); -} - void DeclPrinter::VisitNamespaceDecl(NamespaceDecl *D) { Out << "namespace " << D->getNameAsString() << " {\n"; VisitDeclContext(D); diff --git a/lib/AST/DeclTemplate.cpp b/lib/AST/DeclTemplate.cpp index 902339e1efcf..75b3975322b2 100644 --- a/lib/AST/DeclTemplate.cpp +++ b/lib/AST/DeclTemplate.cpp @@ -262,8 +262,8 @@ NonTypeTemplateParmDecl * NonTypeTemplateParmDecl::Create(ASTContext &C, DeclContext *DC, SourceLocation L, unsigned D, unsigned P, IdentifierInfo *Id, QualType T, - DeclaratorInfo *DInfo) { - return new (C) NonTypeTemplateParmDecl(DC, L, D, P, Id, T, DInfo); + TypeSourceInfo *TInfo) { + return new (C) NonTypeTemplateParmDecl(DC, L, D, P, Id, T, TInfo); } SourceLocation NonTypeTemplateParmDecl::getDefaultArgumentLoc() const { diff --git a/lib/AST/DeclarationName.cpp b/lib/AST/DeclarationName.cpp index 3471657b6523..0ce03c214054 100644 --- a/lib/AST/DeclarationName.cpp +++ b/lib/AST/DeclarationName.cpp @@ -338,7 +338,7 @@ void DeclarationName::setFETokenInfo(void *T) { DeclarationName DeclarationName::getUsingDirectiveName() { // Single instance of DeclarationNameExtra for using-directive - static DeclarationNameExtra UDirExtra = + static const DeclarationNameExtra UDirExtra = { DeclarationNameExtra::CXXUsingDirective }; uintptr_t Ptr = reinterpret_cast(&UDirExtra); diff --git a/lib/AST/Expr.cpp b/lib/AST/Expr.cpp index 624a620b9fbb..139e04b2ed5e 100644 --- a/lib/AST/Expr.cpp +++ b/lib/AST/Expr.cpp @@ -110,7 +110,7 @@ void DeclRefExpr::computeDependence() { DeclRefExpr::DeclRefExpr(NestedNameSpecifier *Qualifier, SourceRange QualifierRange, - NamedDecl *D, SourceLocation NameLoc, + ValueDecl *D, SourceLocation NameLoc, const TemplateArgumentListInfo *TemplateArgs, QualType T) : Expr(DeclRefExprClass, T, false, false), @@ -118,7 +118,6 @@ DeclRefExpr::DeclRefExpr(NestedNameSpecifier *Qualifier, (Qualifier? HasQualifierFlag : 0) | (TemplateArgs ? HasExplicitTemplateArgumentListFlag : 0)), Loc(NameLoc) { - assert(!isa(D)); if (Qualifier) { NameQualifier *NQ = getNameQualifier(); NQ->NNS = Qualifier; @@ -134,7 +133,7 @@ DeclRefExpr::DeclRefExpr(NestedNameSpecifier *Qualifier, DeclRefExpr *DeclRefExpr::Create(ASTContext &Context, NestedNameSpecifier *Qualifier, SourceRange QualifierRange, - NamedDecl *D, + ValueDecl *D, SourceLocation NameLoc, QualType T, const TemplateArgumentListInfo *TemplateArgs) { @@ -204,7 +203,8 @@ std::string PredefinedExpr::ComputeName(ASTContext &Context, IdentType IT, } Proto += ")"; - AFT->getResultType().getAsStringInternal(Proto, Policy); + if (!isa(FD) && !isa(FD)) + AFT->getResultType().getAsStringInternal(Proto, Policy); Out << Proto; @@ -471,7 +471,7 @@ QualType CallExpr::getCallReturnType() const { } MemberExpr::MemberExpr(Expr *base, bool isarrow, NestedNameSpecifier *qual, - SourceRange qualrange, NamedDecl *memberdecl, + SourceRange qualrange, ValueDecl *memberdecl, SourceLocation l, const TemplateArgumentListInfo *targs, QualType ty) : Expr(MemberExprClass, ty, @@ -494,7 +494,7 @@ MemberExpr::MemberExpr(Expr *base, bool isarrow, NestedNameSpecifier *qual, MemberExpr *MemberExpr::Create(ASTContext &C, Expr *base, bool isarrow, NestedNameSpecifier *qual, SourceRange qualrange, - NamedDecl *memberdecl, + ValueDecl *memberdecl, SourceLocation l, const TemplateArgumentListInfo *targs, QualType ty) { @@ -558,12 +558,40 @@ const char *CastExpr::getCastKindName() const { return "FloatingCast"; case CastExpr::CK_MemberPointerToBoolean: return "MemberPointerToBoolean"; + case CastExpr::CK_AnyPointerToObjCPointerCast: + return "AnyPointerToObjCPointerCast"; + case CastExpr::CK_AnyPointerToBlockPointerCast: + return "AnyPointerToBlockPointerCast"; } assert(0 && "Unhandled cast kind!"); return 0; } +Expr *CastExpr::getSubExprAsWritten() { + Expr *SubExpr = 0; + CastExpr *E = this; + do { + SubExpr = E->getSubExpr(); + + // Skip any temporary bindings; they're implicit. + if (CXXBindTemporaryExpr *Binder = dyn_cast(SubExpr)) + SubExpr = Binder->getSubExpr(); + + // Conversions by constructor and conversion functions have a + // subexpression describing the call; strip it off. + if (E->getCastKind() == CastExpr::CK_ConstructorConversion) + SubExpr = cast(SubExpr)->getArg(0); + else if (E->getCastKind() == CastExpr::CK_UserDefinedConversion) + SubExpr = cast(SubExpr)->getImplicitObjectArgument(); + + // If the subexpression we're left with is an implicit cast, look + // through that, too. + } while ((E = dyn_cast(SubExpr))); + + return SubExpr; +} + /// getOpcodeStr - Turn an Opcode enum value into the punctuation char it /// corresponds to, e.g. "<<=". const char *BinaryOperator::getOpcodeStr(Opcode Op) { @@ -944,8 +972,7 @@ static bool DeclCanBeLvalue(const NamedDecl *Decl, ASTContext &Ctx) { return isa(Decl) || isa(Decl) || // C++ 3.10p2: An lvalue refers to an object or function. (Ctx.getLangOptions().CPlusPlus && - (isa(Decl) || isa(Decl) || - isa(Decl))); + (isa(Decl) || isa(Decl))); } /// isLvalue - C99 6.3.2.1: an lvalue is an expression with an object type or an @@ -982,6 +1009,7 @@ Expr::isLvalueResult Expr::isLvalue(ASTContext &Ctx) const { // Check whether the expression can be sanely treated like an l-value Expr::isLvalueResult Expr::isLvalueInternal(ASTContext &Ctx) const { switch (getStmtClass()) { + case ObjCIsaExprClass: case StringLiteralClass: // C99 6.5.1p4 case ObjCEncodeExprClass: // @encode behaves like its string in every way. return LV_Valid; @@ -1343,6 +1371,13 @@ Expr *Expr::IgnoreParenNoopCasts(ASTContext &Ctx) { } } +bool Expr::isDefaultArgument() const { + const Expr *E = this; + while (const ImplicitCastExpr *ICE = dyn_cast(E)) + E = ICE->getSubExprAsWritten(); + + return isa(E); +} /// hasAnyTypeDependentArguments - Determines if any of the expressions /// in Exprs is type-dependent. @@ -1598,13 +1633,18 @@ static ICEDiag CheckICE(const Expr* E, ASTContext &Ctx) { // constant expression (5.19). In that case, the member can appear // in integral constant expressions. if (Def->isOutOfLine()) { - Dcl->setInitKnownICE(Ctx, false); + Dcl->setInitKnownICE(false); return ICEDiag(2, cast(E)->getLocation()); } - + + if (Dcl->isCheckingICE()) { + return ICEDiag(2, cast(E)->getLocation()); + } + + Dcl->setCheckingICE(); ICEDiag Result = CheckICE(Init, Ctx); // Cache the result of the ICE test. - Dcl->setInitKnownICE(Ctx, Result.Val == 0); + Dcl->setInitKnownICE(Result.Val == 0); return Result; } } @@ -1804,7 +1844,7 @@ bool Expr::isIntegerConstantExpr(llvm::APSInt &Result, ASTContext &Ctx, } EvalResult EvalResult; if (!Evaluate(EvalResult, Ctx)) - llvm::llvm_unreachable("ICE cannot be evaluated!"); + llvm_unreachable("ICE cannot be evaluated!"); assert(!EvalResult.HasSideEffects && "ICE with side effects!"); assert(EvalResult.Val.isInt() && "ICE that isn't integer!"); Result = EvalResult.Val.getInt(); diff --git a/lib/AST/ExprCXX.cpp b/lib/AST/ExprCXX.cpp index d1a0390a0a68..a9f96adae137 100644 --- a/lib/AST/ExprCXX.cpp +++ b/lib/AST/ExprCXX.cpp @@ -199,6 +199,7 @@ bool UnaryTypeTraitExpr::EvaluateTrait(ASTContext& C) const { switch(UTT) { default: assert(false && "Unknown type trait or not implemented"); case UTT_IsPOD: return QueriedType->isPODType(); + case UTT_IsLiteral: return QueriedType->isLiteralType(); case UTT_IsClass: // Fallthrough case UTT_IsUnion: if (const RecordType *Record = QueriedType->getAs()) { @@ -518,7 +519,8 @@ Stmt::child_iterator CXXUnresolvedConstructExpr::child_end() { } CXXDependentScopeMemberExpr::CXXDependentScopeMemberExpr(ASTContext &C, - Expr *Base, bool IsArrow, + Expr *Base, QualType BaseType, + bool IsArrow, SourceLocation OperatorLoc, NestedNameSpecifier *Qualifier, SourceRange QualifierRange, @@ -527,8 +529,8 @@ CXXDependentScopeMemberExpr::CXXDependentScopeMemberExpr(ASTContext &C, SourceLocation MemberLoc, const TemplateArgumentListInfo *TemplateArgs) : Expr(CXXDependentScopeMemberExprClass, C.DependentTy, true, true), - Base(Base), IsArrow(IsArrow), - HasExplicitTemplateArgumentList(TemplateArgs), + Base(Base), BaseType(BaseType), IsArrow(IsArrow), + HasExplicitTemplateArgs(TemplateArgs != 0), OperatorLoc(OperatorLoc), Qualifier(Qualifier), QualifierRange(QualifierRange), FirstQualifierFoundInScope(FirstQualifierFoundInScope), @@ -539,7 +541,7 @@ CXXDependentScopeMemberExpr::CXXDependentScopeMemberExpr(ASTContext &C, CXXDependentScopeMemberExpr * CXXDependentScopeMemberExpr::Create(ASTContext &C, - Expr *Base, bool IsArrow, + Expr *Base, QualType BaseType, bool IsArrow, SourceLocation OperatorLoc, NestedNameSpecifier *Qualifier, SourceRange QualifierRange, @@ -548,22 +550,22 @@ CXXDependentScopeMemberExpr::Create(ASTContext &C, SourceLocation MemberLoc, const TemplateArgumentListInfo *TemplateArgs) { if (!TemplateArgs) - return new (C) CXXDependentScopeMemberExpr(C, Base, IsArrow, OperatorLoc, - Qualifier, QualifierRange, - FirstQualifierFoundInScope, - Member, MemberLoc); + return new (C) CXXDependentScopeMemberExpr(C, Base, BaseType, + IsArrow, OperatorLoc, + Qualifier, QualifierRange, + FirstQualifierFoundInScope, + Member, MemberLoc); std::size_t size = sizeof(CXXDependentScopeMemberExpr); if (TemplateArgs) size += ExplicitTemplateArgumentList::sizeFor(*TemplateArgs); void *Mem = C.Allocate(size, llvm::alignof()); - return new (Mem) CXXDependentScopeMemberExpr(C, Base, IsArrow, OperatorLoc, - Qualifier, QualifierRange, - FirstQualifierFoundInScope, - Member, - MemberLoc, - TemplateArgs); + return new (Mem) CXXDependentScopeMemberExpr(C, Base, BaseType, + IsArrow, OperatorLoc, + Qualifier, QualifierRange, + FirstQualifierFoundInScope, + Member, MemberLoc, TemplateArgs); } Stmt::child_iterator CXXDependentScopeMemberExpr::child_begin() { @@ -571,12 +573,15 @@ Stmt::child_iterator CXXDependentScopeMemberExpr::child_begin() { } Stmt::child_iterator CXXDependentScopeMemberExpr::child_end() { + if (isImplicitAccess()) + return child_iterator(&Base); return child_iterator(&Base + 1); } UnresolvedMemberExpr::UnresolvedMemberExpr(QualType T, bool Dependent, bool HasUnresolvedUsing, - Expr *Base, bool IsArrow, + Expr *Base, QualType BaseType, + bool IsArrow, SourceLocation OperatorLoc, NestedNameSpecifier *Qualifier, SourceRange QualifierRange, @@ -584,7 +589,8 @@ UnresolvedMemberExpr::UnresolvedMemberExpr(QualType T, bool Dependent, SourceLocation MemberLoc, const TemplateArgumentListInfo *TemplateArgs) : Expr(UnresolvedMemberExprClass, T, Dependent, Dependent), - Base(Base), IsArrow(IsArrow), HasUnresolvedUsing(HasUnresolvedUsing), + Base(Base), BaseType(BaseType), IsArrow(IsArrow), + HasUnresolvedUsing(HasUnresolvedUsing), HasExplicitTemplateArgs(TemplateArgs != 0), OperatorLoc(OperatorLoc), Qualifier(Qualifier), QualifierRange(QualifierRange), @@ -596,7 +602,7 @@ UnresolvedMemberExpr::UnresolvedMemberExpr(QualType T, bool Dependent, UnresolvedMemberExpr * UnresolvedMemberExpr::Create(ASTContext &C, bool Dependent, bool HasUnresolvedUsing, - Expr *Base, bool IsArrow, + Expr *Base, QualType BaseType, bool IsArrow, SourceLocation OperatorLoc, NestedNameSpecifier *Qualifier, SourceRange QualifierRange, @@ -610,8 +616,8 @@ UnresolvedMemberExpr::Create(ASTContext &C, bool Dependent, void *Mem = C.Allocate(size, llvm::alignof()); return new (Mem) UnresolvedMemberExpr( Dependent ? C.DependentTy : C.OverloadTy, - Dependent, HasUnresolvedUsing, Base, IsArrow, - OperatorLoc, Qualifier, QualifierRange, + Dependent, HasUnresolvedUsing, Base, BaseType, + IsArrow, OperatorLoc, Qualifier, QualifierRange, Member, MemberLoc, TemplateArgs); } @@ -620,5 +626,7 @@ Stmt::child_iterator UnresolvedMemberExpr::child_begin() { } Stmt::child_iterator UnresolvedMemberExpr::child_end() { + if (isImplicitAccess()) + return child_iterator(&Base); return child_iterator(&Base + 1); } diff --git a/lib/AST/ExprConstant.cpp b/lib/AST/ExprConstant.cpp index a20e1cc6f56b..13831dc1f52c 100644 --- a/lib/AST/ExprConstant.cpp +++ b/lib/AST/ExprConstant.cpp @@ -848,16 +848,8 @@ static bool EvaluateInteger(const Expr* E, APSInt &Result, EvalInfo &Info) { bool IntExprEvaluator::CheckReferencedDecl(const Expr* E, const Decl* D) { // Enums are integer constant exprs. - if (const EnumConstantDecl *ECD = dyn_cast(D)) { - // FIXME: This is an ugly hack around the fact that enums don't set their - // signedness consistently; see PR3173. - APSInt SI = ECD->getInitVal(); - SI.setIsUnsigned(!E->getType()->isSignedIntegerType()); - // FIXME: This is an ugly hack around the fact that enums don't - // set their width (!?!) consistently; see PR3173. - SI.extOrTrunc(Info.Ctx.getIntWidth(E->getType())); - return Success(SI, E); - } + if (const EnumConstantDecl *ECD = dyn_cast(D)) + return Success(ECD->getInitVal(), E); // In C++, const, non-volatile integers initialized with ICEs are ICEs. // In C, they can also be folded, although they are not ICEs. @@ -866,15 +858,24 @@ bool IntExprEvaluator::CheckReferencedDecl(const Expr* E, const Decl* D) { if (const VarDecl *VD = dyn_cast(D)) { const VarDecl *Def = 0; if (const Expr *Init = VD->getDefinition(Def)) { - if (APValue *V = VD->getEvaluatedValue()) - return Success(V->getInt(), E); - + if (APValue *V = VD->getEvaluatedValue()) { + if (V->isInt()) + return Success(V->getInt(), E); + return Error(E->getLocStart(), diag::note_invalid_subexpr_in_ice, E); + } + + if (VD->isEvaluatingValue()) + return Error(E->getLocStart(), diag::note_invalid_subexpr_in_ice, E); + + VD->setEvaluatingValue(); + if (Visit(const_cast(Init))) { // Cache the evaluated value in the variable declaration. - VD->setEvaluatedValue(Info.Ctx, Result); + VD->setEvaluatedValue(Result); return true; } + VD->setEvaluatedValue(APValue()); return false; } } @@ -1506,6 +1507,7 @@ class FloatExprEvaluator bool VisitFloatingLiteral(const FloatingLiteral *E); bool VisitCastExpr(CastExpr *E); bool VisitCXXZeroInitValueExpr(CXXZeroInitValueExpr *E); + bool VisitConditionalOperator(ConditionalOperator *E); bool VisitChooseExpr(const ChooseExpr *E) { return Visit(E->getChosenSubExpr(Info.Ctx)); } @@ -1513,8 +1515,7 @@ class FloatExprEvaluator { return Visit(E->getSubExpr()); } // FIXME: Missing: __real__/__imag__, array subscript of vector, - // member of vector, ImplicitValueInitExpr, - // conditional ?: + // member of vector, ImplicitValueInitExpr }; } // end anonymous namespace @@ -1547,16 +1548,10 @@ bool FloatExprEvaluator::VisitCallExpr(const CallExpr *E) { if (!S->isWide()) { const llvm::fltSemantics &Sem = Info.Ctx.getFloatTypeSemantics(E->getType()); - llvm::SmallString<16> s; - s.append(S->getStrData(), S->getStrData() + S->getByteLength()); - s += '\0'; - long l; - char *endp; - l = strtol(&s[0], &endp, 0); - if (endp != s.end()-1) + unsigned Type = 0; + if (!S->getString().empty() && S->getString().getAsInteger(0, Type)) return false; - unsigned type = (unsigned int)l;; - Result = llvm::APFloat::getNaN(Sem, false, type); + Result = llvm::APFloat::getNaN(Sem, false, Type); return true; } } @@ -1673,6 +1668,14 @@ bool FloatExprEvaluator::VisitCXXZeroInitValueExpr(CXXZeroInitValueExpr *E) { return true; } +bool FloatExprEvaluator::VisitConditionalOperator(ConditionalOperator *E) { + bool Cond; + if (!HandleConversionToBool(E->getCond(), Cond, Info)) + return false; + + return Visit(Cond ? E->getTrueExpr() : E->getFalseExpr()); +} + //===----------------------------------------------------------------------===// // Complex Evaluation (for float and integer) //===----------------------------------------------------------------------===// diff --git a/lib/AST/RecordLayoutBuilder.cpp b/lib/AST/RecordLayoutBuilder.cpp index 326a1dcd270a..c914f3f82e8e 100644 --- a/lib/AST/RecordLayoutBuilder.cpp +++ b/lib/AST/RecordLayoutBuilder.cpp @@ -663,31 +663,6 @@ void ASTRecordLayoutBuilder::UpdateAlignment(unsigned NewAlignment) { Alignment = NewAlignment; } -static const CXXMethodDecl *GetKeyFunction(const CXXRecordDecl *RD) { - if (!RD->isDynamicClass()) - return 0; - - for (CXXRecordDecl::method_iterator I = RD->method_begin(), - E = RD->method_end(); I != E; ++I) { - const CXXMethodDecl *MD = *I; - - if (!MD->isVirtual()) - continue; - - if (MD->isPure()) - continue; - - const FunctionDecl *fn; - if (MD->getBody(fn) && !fn->isOutOfLine()) - continue; - - // We found it. - return MD; - } - - return 0; -} - const ASTRecordLayout * ASTRecordLayoutBuilder::ComputeLayout(ASTContext &Ctx, const RecordDecl *D) { @@ -711,8 +686,6 @@ ASTRecordLayoutBuilder::ComputeLayout(ASTContext &Ctx, uint64_t NonVirtualSize = IsPODForThePurposeOfLayout ? DataSize : Builder.NonVirtualSize; - const CXXMethodDecl *KeyFunction = GetKeyFunction(cast(D)); - return new ASTRecordLayout(Builder.Size, Builder.Alignment, DataSize, Builder.FieldOffsets.data(), Builder.FieldOffsets.size(), @@ -722,8 +695,7 @@ ASTRecordLayoutBuilder::ComputeLayout(ASTContext &Ctx, Builder.Bases.data(), Builder.Bases.size(), Builder.VBases.data(), - Builder.VBases.size(), - KeyFunction); + Builder.VBases.size()); } const ASTRecordLayout * @@ -739,3 +711,51 @@ ASTRecordLayoutBuilder::ComputeLayout(ASTContext &Ctx, Builder.FieldOffsets.data(), Builder.FieldOffsets.size()); } + +const CXXMethodDecl * +ASTRecordLayoutBuilder::ComputeKeyFunction(const CXXRecordDecl *RD) { + assert(RD->isDynamicClass() && "Class does not have any virtual methods!"); + + // If a class isnt' polymorphic it doesn't have a key function. + if (!RD->isPolymorphic()) + return 0; + + // A class template specialization or instantation does not have a key + // function. + if (RD->getTemplateSpecializationKind() != TSK_Undeclared) + return 0; + + // A class inside an anonymous namespace doesn't have a key function. (Or + // at least, there's no point to assigning a key function to such a class; + // this doesn't affect the ABI.) + if (RD->isInAnonymousNamespace()) + return 0; + + for (CXXRecordDecl::method_iterator I = RD->method_begin(), + E = RD->method_end(); I != E; ++I) { + const CXXMethodDecl *MD = *I; + + if (!MD->isVirtual()) + continue; + + if (MD->isPure()) + continue; + + if (MD->isInlineSpecified()) + continue; + + // Ignore implicit member functions, they are always marked as inline, but + // they don't have a body until they're defined. + if (MD->isImplicit()) + continue; + + if (MD->hasInlineBody()) + continue; + + // We found it. + return MD; + } + + return 0; +} + diff --git a/lib/AST/RecordLayoutBuilder.h b/lib/AST/RecordLayoutBuilder.h index 69e0498917c7..d4171d3cc9a9 100644 --- a/lib/AST/RecordLayoutBuilder.h +++ b/lib/AST/RecordLayoutBuilder.h @@ -151,6 +151,7 @@ class ASTRecordLayoutBuilder { static const ASTRecordLayout *ComputeLayout(ASTContext &Ctx, const ObjCInterfaceDecl *D, const ObjCImplementationDecl *Impl); + static const CXXMethodDecl *ComputeKeyFunction(const CXXRecordDecl *RD); }; } // end namespace clang diff --git a/lib/AST/StmtDumper.cpp b/lib/AST/StmtDumper.cpp index bbe6a7120141..ae76526b7939 100644 --- a/lib/AST/StmtDumper.cpp +++ b/lib/AST/StmtDumper.cpp @@ -17,7 +17,7 @@ #include "clang/AST/DeclCXX.h" #include "clang/AST/PrettyPrinter.h" #include "clang/Basic/SourceManager.h" -#include +#include "llvm/Support/raw_ostream.h" using namespace clang; //===----------------------------------------------------------------------===// @@ -27,7 +27,7 @@ using namespace clang; namespace { class StmtDumper : public StmtVisitor { SourceManager *SM; - FILE *F; + llvm::raw_ostream &OS; unsigned IndentLevel; /// MaxDepth - When doing a normal dump (not dumpAll) we only want to dump @@ -41,8 +41,8 @@ namespace { unsigned LastLocLine; public: - StmtDumper(SourceManager *sm, FILE *f, unsigned maxDepth) - : SM(sm), F(f), IndentLevel(0-1), MaxDepth(maxDepth) { + StmtDumper(SourceManager *sm, llvm::raw_ostream &os, unsigned maxDepth) + : SM(sm), OS(os), IndentLevel(0-1), MaxDepth(maxDepth) { LastLocFilename = ""; LastLocLine = ~0U; } @@ -62,15 +62,15 @@ namespace { Stmt::child_iterator CI = S->child_begin(), CE = S->child_end(); if (CI != CE) { while (CI != CE) { - fprintf(F, "\n"); + OS << '\n'; DumpSubTree(*CI++); } } - fprintf(F, ")"); + OS << ')'; } } else { Indent(); - fprintf(F, "<<>>"); + OS << "<<>>"; } --IndentLevel; } @@ -79,27 +79,28 @@ namespace { void Indent() const { for (int i = 0, e = IndentLevel; i < e; ++i) - fprintf(F, " "); + OS << " "; } void DumpType(QualType T) { - fprintf(F, "'%s'", T.getAsString().c_str()); + OS << "'" << T.getAsString() << "'"; if (!T.isNull()) { // If the type is sugared, also dump a (shallow) desugared type. QualType Simplified = T.getDesugaredType(); if (Simplified != T) - fprintf(F, ":'%s'", Simplified.getAsString().c_str()); + OS << ":'" << Simplified.getAsString() << "'"; } } void DumpStmt(const Stmt *Node) { Indent(); - fprintf(F, "(%s %p", Node->getStmtClassName(), (void*)Node); + OS << "(" << Node->getStmtClassName() + << " " << (void*)Node; DumpSourceRange(Node); } void DumpExpr(const Expr *Node) { DumpStmt(Node); - fprintf(F, " "); + OS << ' '; DumpType(Node->getType()); } void DumpSourceRange(const Stmt *Node); @@ -138,6 +139,7 @@ namespace { void VisitCXXConstructExpr(CXXConstructExpr *Node); void VisitCXXBindTemporaryExpr(CXXBindTemporaryExpr *Node); void VisitCXXExprWithTemporaries(CXXExprWithTemporaries *Node); + void VisitUnresolvedLookupExpr(UnresolvedLookupExpr *Node); void DumpCXXTemporary(CXXTemporary *Temporary); // ObjC @@ -161,7 +163,7 @@ void StmtDumper::DumpLocation(SourceLocation Loc) { SourceLocation SpellingLoc = SM->getSpellingLoc(Loc); if (SpellingLoc.isInvalid()) { - fprintf(stderr, ""); + OS << ""; return; } @@ -170,15 +172,16 @@ void StmtDumper::DumpLocation(SourceLocation Loc) { PresumedLoc PLoc = SM->getPresumedLoc(SpellingLoc); if (strcmp(PLoc.getFilename(), LastLocFilename) != 0) { - fprintf(stderr, "%s:%u:%u", PLoc.getFilename(), PLoc.getLine(), - PLoc.getColumn()); + OS << PLoc.getFilename() << ':' << PLoc.getLine() + << ':' << PLoc.getColumn(); LastLocFilename = PLoc.getFilename(); LastLocLine = PLoc.getLine(); } else if (PLoc.getLine() != LastLocLine) { - fprintf(stderr, "line:%u:%u", PLoc.getLine(), PLoc.getColumn()); + OS << "line" << ':' << PLoc.getLine() + << ':' << PLoc.getColumn(); LastLocLine = PLoc.getLine(); } else { - fprintf(stderr, "col:%u", PLoc.getColumn()); + OS << "col" << ':' << PLoc.getColumn(); } } @@ -190,13 +193,13 @@ void StmtDumper::DumpSourceRange(const Stmt *Node) { // location. SourceRange R = Node->getSourceRange(); - fprintf(stderr, " <"); + OS << " <"; DumpLocation(R.getBegin()); if (R.getBegin() != R.getEnd()) { - fprintf(stderr, ", "); + OS << ", "; DumpLocation(R.getEnd()); } - fprintf(stderr, ">"); + OS << ">"; // @@ -215,31 +218,30 @@ void StmtDumper::DumpDeclarator(Decl *D) { // FIXME: Need to complete/beautify this... this code simply shows the // nodes are where they need to be. if (TypedefDecl *localType = dyn_cast(D)) { - fprintf(F, "\"typedef %s %s\"", - localType->getUnderlyingType().getAsString().c_str(), - localType->getNameAsString().c_str()); + OS << "\"typedef " << localType->getUnderlyingType().getAsString() + << " " << localType->getNameAsString() << "\""; } else if (ValueDecl *VD = dyn_cast(D)) { - fprintf(F, "\""); + OS << "\""; // Emit storage class for vardecls. if (VarDecl *V = dyn_cast(VD)) { if (V->getStorageClass() != VarDecl::None) - fprintf(F, "%s ", - VarDecl::getStorageClassSpecifierString(V->getStorageClass())); + OS << VarDecl::getStorageClassSpecifierString(V->getStorageClass()) + << " "; } std::string Name = VD->getNameAsString(); VD->getType().getAsStringInternal(Name, PrintingPolicy(VD->getASTContext().getLangOptions())); - fprintf(F, "%s", Name.c_str()); + OS << Name; // If this is a vardecl with an initializer, emit it. if (VarDecl *V = dyn_cast(VD)) { if (V->getInit()) { - fprintf(F, " =\n"); + OS << " =\n"; DumpSubTree(V->getInit()); } } - fprintf(F, "\""); + OS << '"'; } else if (TagDecl *TD = dyn_cast(D)) { // print a free standing tag decl (e.g. "struct x;"). const char *tagname; @@ -247,7 +249,7 @@ void StmtDumper::DumpDeclarator(Decl *D) { tagname = II->getNameStart(); else tagname = ""; - fprintf(F, "\"%s %s;\"", TD->getKindName(), tagname); + OS << '"' << TD->getKindName() << ' ' << tagname << ";\""; // FIXME: print tag bodies. } else if (UsingDirectiveDecl *UD = dyn_cast(D)) { // print using-directive decl (e.g. "using namespace x;") @@ -256,7 +258,7 @@ void StmtDumper::DumpDeclarator(Decl *D) { ns = II->getNameStart(); else ns = ""; - fprintf(F, "\"%s %s;\"",UD->getDeclKindName(), ns); + OS << '"' << UD->getDeclKindName() << ns << ";\""; } else { assert(0 && "Unexpected decl"); } @@ -264,28 +266,29 @@ void StmtDumper::DumpDeclarator(Decl *D) { void StmtDumper::VisitDeclStmt(DeclStmt *Node) { DumpStmt(Node); - fprintf(F,"\n"); + OS << "\n"; for (DeclStmt::decl_iterator DI = Node->decl_begin(), DE = Node->decl_end(); DI != DE; ++DI) { Decl* D = *DI; ++IndentLevel; Indent(); - fprintf(F, "%p ", (void*) D); + OS << (void*) D << " "; DumpDeclarator(D); if (DI+1 != DE) - fprintf(F,"\n"); + OS << "\n"; --IndentLevel; } } void StmtDumper::VisitLabelStmt(LabelStmt *Node) { DumpStmt(Node); - fprintf(F, " '%s'", Node->getName()); + OS << " '" << Node->getName() << "'"; } void StmtDumper::VisitGotoStmt(GotoStmt *Node) { DumpStmt(Node); - fprintf(F, " '%s':%p", Node->getLabel()->getName(), (void*)Node->getLabel()); + OS << " '" << Node->getLabel()->getName() + << "':" << (void*)Node->getLabel(); } //===----------------------------------------------------------------------===// @@ -298,129 +301,130 @@ void StmtDumper::VisitExpr(Expr *Node) { void StmtDumper::VisitCastExpr(CastExpr *Node) { DumpExpr(Node); - fprintf(F, " <%s>", Node->getCastKindName()); + OS << " <" << Node->getCastKindName() << ">"; } void StmtDumper::VisitImplicitCastExpr(ImplicitCastExpr *Node) { VisitCastExpr(Node); if (Node->isLvalueCast()) - fprintf(F, " lvalue"); + OS << " lvalue"; } void StmtDumper::VisitDeclRefExpr(DeclRefExpr *Node) { DumpExpr(Node); - fprintf(F, " "); + OS << " "; switch (Node->getDecl()->getKind()) { - default: fprintf(F,"Decl"); break; - case Decl::Function: fprintf(F,"FunctionDecl"); break; - case Decl::Var: fprintf(F,"Var"); break; - case Decl::ParmVar: fprintf(F,"ParmVar"); break; - case Decl::EnumConstant: fprintf(F,"EnumConstant"); break; - case Decl::Typedef: fprintf(F,"Typedef"); break; - case Decl::Record: fprintf(F,"Record"); break; - case Decl::Enum: fprintf(F,"Enum"); break; - case Decl::CXXRecord: fprintf(F,"CXXRecord"); break; - case Decl::ObjCInterface: fprintf(F,"ObjCInterface"); break; - case Decl::ObjCClass: fprintf(F,"ObjCClass"); break; + default: OS << "Decl"; break; + case Decl::Function: OS << "FunctionDecl"; break; + case Decl::Var: OS << "Var"; break; + case Decl::ParmVar: OS << "ParmVar"; break; + case Decl::EnumConstant: OS << "EnumConstant"; break; + case Decl::Typedef: OS << "Typedef"; break; + case Decl::Record: OS << "Record"; break; + case Decl::Enum: OS << "Enum"; break; + case Decl::CXXRecord: OS << "CXXRecord"; break; + case Decl::ObjCInterface: OS << "ObjCInterface"; break; + case Decl::ObjCClass: OS << "ObjCClass"; break; } - fprintf(F, "='%s' %p", Node->getDecl()->getNameAsString().c_str(), - (void*)Node->getDecl()); + OS << "='" << Node->getDecl()->getNameAsString() + << "' " << (void*)Node->getDecl(); +} + +void StmtDumper::VisitUnresolvedLookupExpr(UnresolvedLookupExpr *Node) { + DumpExpr(Node); + OS << " ("; + if (!Node->requiresADL()) OS << "no "; + OS << "ADL) = '" << Node->getName().getAsString() << "'"; + + UnresolvedLookupExpr::decls_iterator + I = Node->decls_begin(), E = Node->decls_end(); + if (I == E) OS << " empty"; + for (; I != E; ++I) + OS << " " << (void*) *I; } void StmtDumper::VisitObjCIvarRefExpr(ObjCIvarRefExpr *Node) { DumpExpr(Node); - fprintf(F, " %sDecl='%s' %p", Node->getDecl()->getDeclKindName(), - Node->getDecl()->getNameAsString().c_str(), (void*)Node->getDecl()); + OS << " " << Node->getDecl()->getDeclKindName() + << "Decl='" << Node->getDecl()->getNameAsString() + << "' " << (void*)Node->getDecl(); if (Node->isFreeIvar()) - fprintf(F, " isFreeIvar"); + OS << " isFreeIvar"; } void StmtDumper::VisitPredefinedExpr(PredefinedExpr *Node) { DumpExpr(Node); switch (Node->getIdentType()) { default: assert(0 && "unknown case"); - case PredefinedExpr::Func: fprintf(F, " __func__"); break; - case PredefinedExpr::Function: fprintf(F, " __FUNCTION__"); break; - case PredefinedExpr::PrettyFunction: fprintf(F, " __PRETTY_FUNCTION__");break; + case PredefinedExpr::Func: OS << " __func__"; break; + case PredefinedExpr::Function: OS << " __FUNCTION__"; break; + case PredefinedExpr::PrettyFunction: OS << " __PRETTY_FUNCTION__";break; } } void StmtDumper::VisitCharacterLiteral(CharacterLiteral *Node) { DumpExpr(Node); - fprintf(F, " %d", Node->getValue()); + OS << Node->getValue(); } void StmtDumper::VisitIntegerLiteral(IntegerLiteral *Node) { DumpExpr(Node); bool isSigned = Node->getType()->isSignedIntegerType(); - fprintf(F, " %s", Node->getValue().toString(10, isSigned).c_str()); + OS << " " << Node->getValue().toString(10, isSigned); } void StmtDumper::VisitFloatingLiteral(FloatingLiteral *Node) { DumpExpr(Node); - fprintf(F, " %f", Node->getValueAsApproximateDouble()); + OS << " " << Node->getValueAsApproximateDouble(); } void StmtDumper::VisitStringLiteral(StringLiteral *Str) { DumpExpr(Str); // FIXME: this doesn't print wstrings right. - fprintf(F, " %s\"", Str->isWide() ? "L" : ""); - - for (unsigned i = 0, e = Str->getByteLength(); i != e; ++i) { - switch (char C = Str->getStrData()[i]) { - default: - if (isprint(C)) - fputc(C, F); - else - fprintf(F, "\\%03o", C); - break; - // Handle some common ones to make dumps prettier. - case '\\': fprintf(F, "\\\\"); break; - case '"': fprintf(F, "\\\""); break; - case '\n': fprintf(F, "\\n"); break; - case '\t': fprintf(F, "\\t"); break; - case '\a': fprintf(F, "\\a"); break; - case '\b': fprintf(F, "\\b"); break; - } - } - fprintf(F, "\""); + OS << " "; + if (Str->isWide()) + OS << "L"; + OS << '"'; + OS.write_escaped(llvm::StringRef(Str->getStrData(), + Str->getByteLength())); + OS << '"'; } void StmtDumper::VisitUnaryOperator(UnaryOperator *Node) { DumpExpr(Node); - fprintf(F, " %s '%s'", Node->isPostfix() ? "postfix" : "prefix", - UnaryOperator::getOpcodeStr(Node->getOpcode())); + OS << " " << (Node->isPostfix() ? "postfix" : "prefix") + << " '" << UnaryOperator::getOpcodeStr(Node->getOpcode()) << "'"; } void StmtDumper::VisitSizeOfAlignOfExpr(SizeOfAlignOfExpr *Node) { DumpExpr(Node); - fprintf(F, " %s ", Node->isSizeOf() ? "sizeof" : "alignof"); + OS << " " << (Node->isSizeOf() ? "sizeof" : "alignof") << " "; if (Node->isArgumentType()) DumpType(Node->getArgumentType()); } void StmtDumper::VisitMemberExpr(MemberExpr *Node) { DumpExpr(Node); - fprintf(F, " %s%s %p", Node->isArrow() ? "->" : ".", - Node->getMemberDecl()->getNameAsString().c_str(), - (void*)Node->getMemberDecl()); + OS << " " << (Node->isArrow() ? "->" : ".") + << Node->getMemberDecl()->getNameAsString() << " " + << (void*)Node->getMemberDecl(); } void StmtDumper::VisitExtVectorElementExpr(ExtVectorElementExpr *Node) { DumpExpr(Node); - fprintf(F, " %s", Node->getAccessor().getNameStart()); + OS << " " << Node->getAccessor().getNameStart(); } void StmtDumper::VisitBinaryOperator(BinaryOperator *Node) { DumpExpr(Node); - fprintf(F, " '%s'", BinaryOperator::getOpcodeStr(Node->getOpcode())); + OS << " '" << BinaryOperator::getOpcodeStr(Node->getOpcode()) << "'"; } void StmtDumper::VisitCompoundAssignOperator(CompoundAssignOperator *Node) { DumpExpr(Node); - fprintf(F, " '%s' ComputeLHSTy=", - BinaryOperator::getOpcodeStr(Node->getOpcode())); + OS << " '" << BinaryOperator::getOpcodeStr(Node->getOpcode()) + << "' ComputeLHSTy="; DumpType(Node->getComputationLHSType()); - fprintf(F, " ComputeResultTy="); + OS << " ComputeResultTy="; DumpType(Node->getComputationResultType()); } @@ -428,14 +432,15 @@ void StmtDumper::VisitCompoundAssignOperator(CompoundAssignOperator *Node) { void StmtDumper::VisitAddrLabelExpr(AddrLabelExpr *Node) { DumpExpr(Node); - fprintf(F, " %s %p", Node->getLabel()->getName(), (void*)Node->getLabel()); + OS << " " << Node->getLabel()->getName() + << " " << (void*)Node->getLabel(); } void StmtDumper::VisitTypesCompatibleExpr(TypesCompatibleExpr *Node) { DumpExpr(Node); - fprintf(F, " "); + OS << " "; DumpType(Node->getArgType1()); - fprintf(F, " "); + OS << " "; DumpType(Node->getArgType2()); } @@ -445,36 +450,35 @@ void StmtDumper::VisitTypesCompatibleExpr(TypesCompatibleExpr *Node) { void StmtDumper::VisitCXXNamedCastExpr(CXXNamedCastExpr *Node) { DumpExpr(Node); - fprintf(F, " %s<%s> <%s>", Node->getCastName(), - Node->getTypeAsWritten().getAsString().c_str(), - Node->getCastKindName()); + OS << " " << Node->getCastName() + << "<" << Node->getTypeAsWritten().getAsString() << ">" + << " <" << Node->getCastKindName() << ">"; } void StmtDumper::VisitCXXBoolLiteralExpr(CXXBoolLiteralExpr *Node) { DumpExpr(Node); - fprintf(F, " %s", Node->getValue() ? "true" : "false"); + OS << " " << (Node->getValue() ? "true" : "false"); } void StmtDumper::VisitCXXThisExpr(CXXThisExpr *Node) { DumpExpr(Node); - fprintf(F, " this"); + OS << " this"; } void StmtDumper::VisitCXXFunctionalCastExpr(CXXFunctionalCastExpr *Node) { DumpExpr(Node); - fprintf(F, " functional cast to %s", - Node->getTypeAsWritten().getAsString().c_str()); + OS << " functional cast to " << Node->getTypeAsWritten().getAsString(); } void StmtDumper::VisitCXXConstructExpr(CXXConstructExpr *Node) { DumpExpr(Node); if (Node->isElidable()) - fprintf(F, " elidable"); + OS << " elidable"; } void StmtDumper::VisitCXXBindTemporaryExpr(CXXBindTemporaryExpr *Node) { DumpExpr(Node); - fprintf(F, " "); + OS << " "; DumpCXXTemporary(Node->getTemporary()); } @@ -482,7 +486,7 @@ void StmtDumper::VisitCXXExprWithTemporaries(CXXExprWithTemporaries *Node) { DumpExpr(Node); ++IndentLevel; for (unsigned i = 0, e = Node->getNumTemporaries(); i != e; ++i) { - fprintf(F, "\n"); + OS << "\n"; Indent(); DumpCXXTemporary(Node->getTemporary(i)); } @@ -490,7 +494,7 @@ void StmtDumper::VisitCXXExprWithTemporaries(CXXExprWithTemporaries *Node) { } void StmtDumper::DumpCXXTemporary(CXXTemporary *Temporary) { - fprintf(F, "(CXXTemporary %p)", (void *)Temporary); + OS << "(CXXTemporary " << (void *)Temporary << ")"; } //===----------------------------------------------------------------------===// @@ -499,37 +503,34 @@ void StmtDumper::DumpCXXTemporary(CXXTemporary *Temporary) { void StmtDumper::VisitObjCMessageExpr(ObjCMessageExpr* Node) { DumpExpr(Node); - fprintf(F, " selector=%s", Node->getSelector().getAsString().c_str()); - IdentifierInfo* clsName = Node->getClassName(); - if (clsName) fprintf(F, " class=%s", clsName->getNameStart()); + OS << " selector=" << Node->getSelector().getAsString(); + if (IdentifierInfo *clsName = Node->getClassName()) + OS << " class=" << clsName->getNameStart(); } void StmtDumper::VisitObjCEncodeExpr(ObjCEncodeExpr *Node) { DumpExpr(Node); - - fprintf(F, " "); + OS << " "; DumpType(Node->getEncodedType()); } void StmtDumper::VisitObjCSelectorExpr(ObjCSelectorExpr *Node) { DumpExpr(Node); - fprintf(F, " "); - fprintf(F, "%s", Node->getSelector().getAsString().c_str()); + OS << " " << Node->getSelector().getAsString(); } void StmtDumper::VisitObjCProtocolExpr(ObjCProtocolExpr *Node) { DumpExpr(Node); - fprintf(F, " "); - fprintf(F, "%s", Node->getProtocol()->getNameAsString().c_str()); + OS << " " << Node->getProtocol()->getNameAsString(); } void StmtDumper::VisitObjCPropertyRefExpr(ObjCPropertyRefExpr *Node) { DumpExpr(Node); - fprintf(F, " Kind=PropertyRef Property=\"%s\"", - Node->getProperty()->getNameAsString().c_str()); + OS << " Kind=PropertyRef Property=\"" + << Node->getProperty()->getNameAsString() << "\""; } void StmtDumper::VisitObjCImplicitSetterGetterRefExpr( @@ -538,14 +539,19 @@ void StmtDumper::VisitObjCImplicitSetterGetterRefExpr( ObjCMethodDecl *Getter = Node->getGetterMethod(); ObjCMethodDecl *Setter = Node->getSetterMethod(); - fprintf(F, " Kind=MethodRef Getter=\"%s\" Setter=\"%s\"", - Getter->getSelector().getAsString().c_str(), - Setter ? Setter->getSelector().getAsString().c_str() : "(null)"); + OS << " Kind=MethodRef Getter=\"" + << Getter->getSelector().getAsString() + << "\" Setter=\""; + if (Setter) + OS << Setter->getSelector().getAsString(); + else + OS << "(null)"; + OS << "\""; } void StmtDumper::VisitObjCSuperExpr(ObjCSuperExpr *Node) { DumpExpr(Node); - fprintf(F, " super"); + OS << " super"; } //===----------------------------------------------------------------------===// @@ -556,30 +562,30 @@ void StmtDumper::VisitObjCSuperExpr(ObjCSuperExpr *Node) { /// specified node and a few nodes underneath it, but not the whole subtree. /// This is useful in a debugger. void Stmt::dump(SourceManager &SM) const { - StmtDumper P(&SM, stderr, 4); + StmtDumper P(&SM, llvm::errs(), 4); P.DumpSubTree(const_cast(this)); - fprintf(stderr, "\n"); + llvm::errs() << "\n"; } /// dump - This does a local dump of the specified AST fragment. It dumps the /// specified node and a few nodes underneath it, but not the whole subtree. /// This is useful in a debugger. void Stmt::dump() const { - StmtDumper P(0, stderr, 4); + StmtDumper P(0, llvm::errs(), 4); P.DumpSubTree(const_cast(this)); - fprintf(stderr, "\n"); + llvm::errs() << "\n"; } /// dumpAll - This does a dump of the specified AST fragment and all subtrees. void Stmt::dumpAll(SourceManager &SM) const { - StmtDumper P(&SM, stderr, ~0U); + StmtDumper P(&SM, llvm::errs(), ~0U); P.DumpSubTree(const_cast(this)); - fprintf(stderr, "\n"); + llvm::errs() << "\n"; } /// dumpAll - This does a dump of the specified AST fragment and all subtrees. void Stmt::dumpAll() const { - StmtDumper P(0, stderr, ~0U); + StmtDumper P(0, llvm::errs(), ~0U); P.DumpSubTree(const_cast(this)); - fprintf(stderr, "\n"); + llvm::errs() << "\n"; } diff --git a/lib/AST/StmtPrinter.cpp b/lib/AST/StmtPrinter.cpp index 205ea0d182d4..a7e42af04d81 100644 --- a/lib/AST/StmtPrinter.cpp +++ b/lib/AST/StmtPrinter.cpp @@ -1145,17 +1145,19 @@ StmtPrinter::VisitCXXUnresolvedConstructExpr( void StmtPrinter::VisitCXXDependentScopeMemberExpr( CXXDependentScopeMemberExpr *Node) { - PrintExpr(Node->getBase()); - OS << (Node->isArrow() ? "->" : "."); + if (!Node->isImplicitAccess()) { + PrintExpr(Node->getBase()); + OS << (Node->isArrow() ? "->" : "."); + } if (NestedNameSpecifier *Qualifier = Node->getQualifier()) Qualifier->print(OS, Policy); - else if (Node->hasExplicitTemplateArgumentList()) + else if (Node->hasExplicitTemplateArgs()) // FIXME: Track use of "template" keyword explicitly? OS << "template "; OS << Node->getMember().getAsString(); - if (Node->hasExplicitTemplateArgumentList()) { + if (Node->hasExplicitTemplateArgs()) { OS << TemplateSpecializationType::PrintTemplateArgumentList( Node->getTemplateArgs(), Node->getNumTemplateArgs(), @@ -1164,8 +1166,10 @@ void StmtPrinter::VisitCXXDependentScopeMemberExpr( } void StmtPrinter::VisitUnresolvedMemberExpr(UnresolvedMemberExpr *Node) { - PrintExpr(Node->getBase()); - OS << (Node->isArrow() ? "->" : "."); + if (!Node->isImplicitAccess()) { + PrintExpr(Node->getBase()); + OS << (Node->isArrow() ? "->" : "."); + } if (NestedNameSpecifier *Qualifier = Node->getQualifier()) Qualifier->print(OS, Policy); diff --git a/lib/AST/StmtProfile.cpp b/lib/AST/StmtProfile.cpp index d832a4649e75..e2d772b7dd12 100644 --- a/lib/AST/StmtProfile.cpp +++ b/lib/AST/StmtProfile.cpp @@ -554,18 +554,24 @@ StmtProfiler::VisitCXXUnresolvedConstructExpr(CXXUnresolvedConstructExpr *S) { void StmtProfiler::VisitCXXDependentScopeMemberExpr(CXXDependentScopeMemberExpr *S) { - VisitExpr(S); - ID.AddBoolean(S->isArrow()); + ID.AddBoolean(S->isImplicitAccess()); + if (!S->isImplicitAccess()) { + VisitExpr(S); + ID.AddBoolean(S->isArrow()); + } VisitNestedNameSpecifier(S->getQualifier()); VisitName(S->getMember()); - ID.AddBoolean(S->hasExplicitTemplateArgumentList()); - if (S->hasExplicitTemplateArgumentList()) + ID.AddBoolean(S->hasExplicitTemplateArgs()); + if (S->hasExplicitTemplateArgs()) VisitTemplateArguments(S->getTemplateArgs(), S->getNumTemplateArgs()); } void StmtProfiler::VisitUnresolvedMemberExpr(UnresolvedMemberExpr *S) { - VisitExpr(S); - ID.AddBoolean(S->isArrow()); + ID.AddBoolean(S->isImplicitAccess()); + if (!S->isImplicitAccess()) { + VisitExpr(S); + ID.AddBoolean(S->isArrow()); + } VisitNestedNameSpecifier(S->getQualifier()); VisitName(S->getMemberName()); ID.AddBoolean(S->hasExplicitTemplateArgs()); @@ -653,13 +659,6 @@ void StmtProfiler::VisitDecl(Decl *D) { ID.AddInteger(TTP->getIndex()); return; } - - if (OverloadedFunctionDecl *Ovl = dyn_cast(D)) { - // The Itanium C++ ABI mangles references to a set of overloaded - // functions using just the function name, so we do the same here. - VisitName(Ovl->getDeclName()); - return; - } } ID.AddPointer(D? D->getCanonicalDecl() : 0); diff --git a/lib/AST/TemplateBase.cpp b/lib/AST/TemplateBase.cpp index f341b45fb971..e9b17256415f 100644 --- a/lib/AST/TemplateBase.cpp +++ b/lib/AST/TemplateBase.cpp @@ -102,7 +102,7 @@ SourceRange TemplateArgumentLoc::getSourceRange() const { return getSourceDeclExpression()->getSourceRange(); case TemplateArgument::Type: - return getSourceDeclaratorInfo()->getTypeLoc().getFullSourceRange(); + return getTypeSourceInfo()->getTypeLoc().getFullSourceRange(); case TemplateArgument::Template: if (getTemplateQualifierRange().isValid()) diff --git a/lib/AST/TemplateName.cpp b/lib/AST/TemplateName.cpp index 5b4cf0ad94f6..b56c0cebfa58 100644 --- a/lib/AST/TemplateName.cpp +++ b/lib/AST/TemplateName.cpp @@ -29,25 +29,14 @@ TemplateDecl *TemplateName::getAsTemplateDecl() const { return 0; } -OverloadedFunctionDecl *TemplateName::getAsOverloadedFunctionDecl() const { - if (OverloadedFunctionDecl *Ovl - = Storage.dyn_cast()) - return Ovl; - - if (QualifiedTemplateName *QTN = getAsQualifiedTemplateName()) - return QTN->getOverloadedFunctionDecl(); - - return 0; -} - bool TemplateName::isDependent() const { if (TemplateDecl *Template = getAsTemplateDecl()) { return isa(Template) || Template->getDeclContext()->isDependentContext(); } - if (OverloadedFunctionDecl *Ovl = getAsOverloadedFunctionDecl()) - return Ovl->getDeclContext()->isDependentContext(); + assert(!getAsOverloadedTemplate() && + "overloaded templates shouldn't survive to here"); return true; } @@ -57,9 +46,6 @@ TemplateName::print(llvm::raw_ostream &OS, const PrintingPolicy &Policy, bool SuppressNNS) const { if (TemplateDecl *Template = Storage.dyn_cast()) OS << Template->getNameAsString(); - else if (OverloadedFunctionDecl *Ovl - = Storage.dyn_cast()) - OS << Ovl->getNameAsString(); else if (QualifiedTemplateName *QTN = getAsQualifiedTemplateName()) { if (!SuppressNNS) QTN->getQualifier()->print(OS, Policy); @@ -84,13 +70,3 @@ void TemplateName::dump() const { LO.Bool = true; print(llvm::errs(), PrintingPolicy(LO)); } - -TemplateDecl *QualifiedTemplateName::getTemplateDecl() const { - return dyn_cast(Template); -} - -OverloadedFunctionDecl * -QualifiedTemplateName::getOverloadedFunctionDecl() const { - return dyn_cast(Template); -} - diff --git a/lib/AST/Type.cpp b/lib/AST/Type.cpp index 5a2434da3c37..687beaea08c2 100644 --- a/lib/AST/Type.cpp +++ b/lib/AST/Type.cpp @@ -434,6 +434,18 @@ bool Type::isWideCharType() const { return false; } +/// \brief Determine whether this type is any of the built-in character +/// types. +bool Type::isAnyCharacterType() const { + if (const BuiltinType *BT = dyn_cast(CanonicalType)) + return (BT->getKind() >= BuiltinType::Char_U && + BT->getKind() <= BuiltinType::Char32) || + (BT->getKind() >= BuiltinType::Char_S && + BT->getKind() <= BuiltinType::WChar); + + return false; +} + /// isSignedIntegerType - Return true if this is an integer type that is /// signed, according to C99 6.2.5p4 [char, signed char, short, int, long..], /// an enum decl which has a signed representation, or a vector of signed @@ -639,6 +651,40 @@ bool Type::isPODType() const { } } +bool Type::isLiteralType() const { + if (isIncompleteType()) + return false; + + // C++0x [basic.types]p10: + // A type is a literal type if it is: + switch (CanonicalType->getTypeClass()) { + // We're whitelisting + default: return false; + + // -- a scalar type + case Builtin: + case Complex: + case Pointer: + case MemberPointer: + case Vector: + case ExtVector: + case ObjCObjectPointer: + case Enum: + return true; + + // -- a class type with ... + case Record: + // FIXME: Do the tests + return false; + + // -- an array of literal type + // Extension: variable arrays cannot be literal types, since they're + // runtime-sized. + case ConstantArray: + return cast(CanonicalType)->getElementType()->isLiteralType(); + } +} + bool Type::isPromotableIntegerType() const { if (const BuiltinType *BT = getAs()) switch (BT->getKind()) { diff --git a/lib/AST/TypeLoc.cpp b/lib/AST/TypeLoc.cpp index 50a512028e96..3ccb7a9cc613 100644 --- a/lib/AST/TypeLoc.cpp +++ b/lib/AST/TypeLoc.cpp @@ -94,3 +94,32 @@ void TypeLoc::initializeImpl(TypeLoc TL, SourceLocation Loc) { TypeLocInitializer(Loc).Visit(TL); } while ((TL = TL.getNextTypeLoc())); } + +namespace { + struct TSTChecker : public TypeLocVisitor { + // Overload resolution does the real work for us. + static bool isTypeSpec(TypeSpecTypeLoc _) { return true; } + static bool isTypeSpec(TypeLoc _) { return false; } + +#define ABSTRACT_TYPELOC(CLASS, PARENT) +#define TYPELOC(CLASS, PARENT) \ + bool Visit##CLASS##TypeLoc(CLASS##TypeLoc TyLoc) { \ + return isTypeSpec(TyLoc); \ + } +#include "clang/AST/TypeLocNodes.def" + }; +} + + +/// \brief Determines if the given type loc corresponds to a +/// TypeSpecTypeLoc. Since there is not actually a TypeSpecType in +/// the type hierarchy, this is made somewhat complicated. +/// +/// There are a lot of types that currently use TypeSpecTypeLoc +/// because it's a convenient base class. Ideally we would not accept +/// those here, but ideally we would have better implementations for +/// them. +bool TypeSpecTypeLoc::classof(const TypeLoc *TL) { + if (TL->getType().hasLocalQualifiers()) return false; + return TSTChecker().Visit(*TL); +} diff --git a/lib/AST/TypePrinter.cpp b/lib/AST/TypePrinter.cpp index 562e830b367e..4a2b95617290 100644 --- a/lib/AST/TypePrinter.cpp +++ b/lib/AST/TypePrinter.cpp @@ -242,12 +242,13 @@ void TypePrinter::PrintDependentSizedExtVector( void TypePrinter::PrintVector(const VectorType *T, std::string &S) { // FIXME: We prefer to print the size directly here, but have no way // to get the size of the type. - S += " __attribute__((__vector_size__("; - S += llvm::utostr_32(T->getNumElements()); // convert back to bytes. + Print(T->getElementType(), S); + std::string V = "__attribute__((__vector_size__("; + V += llvm::utostr_32(T->getNumElements()); // convert back to bytes. std::string ET; Print(T->getElementType(), ET); - S += " * sizeof(" + ET + "))))"; - Print(T->getElementType(), S); + V += " * sizeof(" + ET + ")))) "; + S = V + S; } void TypePrinter::PrintExtVector(const ExtVectorType *T, std::string &S) { @@ -284,6 +285,23 @@ void TypePrinter::PrintFunctionProto(const FunctionProtoType *T, } S += ")"; + + if (T->hasExceptionSpec()) { + S += " throw("; + if (T->hasAnyExceptionSpec()) + S += "..."; + else + for (unsigned I = 0, N = T->getNumExceptions(); I != N; ++I) { + if (I) + S += ", "; + + std::string ExceptionType; + Print(T->getExceptionType(I), ExceptionType); + S += ExceptionType; + } + S += ")"; + } + if (T->getNoReturnAttr()) S += " __attribute__((noreturn))"; Print(T->getResultType(), S); @@ -302,6 +320,15 @@ void TypePrinter::PrintFunctionNoProto(const FunctionNoProtoType *T, Print(T->getResultType(), S); } +void TypePrinter::PrintUnresolvedUsing(const UnresolvedUsingType *T, + std::string &S) { + IdentifierInfo *II = T->getDecl()->getIdentifier(); + if (S.empty()) + S = II->getName().str(); + else + S = II->getName().str() + ' ' + S; +} + void TypePrinter::PrintTypedef(const TypedefType *T, std::string &S) { if (!S.empty()) // Prefix the basic type, e.g. 'typedefname X'. S = ' ' + S; @@ -683,9 +710,8 @@ void QualType::dump(const char *msg) const { LangOptions LO; getAsStringInternal(R, PrintingPolicy(LO)); if (msg) - fprintf(stderr, "%s: %s\n", msg, R.c_str()); - else - fprintf(stderr, "%s\n", R.c_str()); + llvm::errs() << msg << ": "; + llvm::errs() << R << "\n"; } void QualType::dump() const { dump(""); diff --git a/lib/Analysis/AnalysisContext.cpp b/lib/Analysis/AnalysisContext.cpp index 339e2c93cea9..05e5196c5b97 100644 --- a/lib/Analysis/AnalysisContext.cpp +++ b/lib/Analysis/AnalysisContext.cpp @@ -13,6 +13,7 @@ //===----------------------------------------------------------------------===// #include "clang/Analysis/PathSensitive/AnalysisContext.h" +#include "clang/Analysis/PathSensitive/MemRegion.h" #include "clang/Analysis/Analyses/LiveVariables.h" #include "clang/Analysis/CFG.h" #include "clang/AST/Decl.h" @@ -35,8 +36,10 @@ Stmt *AnalysisContext::getBody() { return FD->getBody(); else if (const ObjCMethodDecl *MD = dyn_cast(D)) return MD->getBody(); + else if (const BlockDecl *BD = dyn_cast(D)) + return BD->getBody(); - llvm::llvm_unreachable("unknown code decl"); + llvm_unreachable("unknown code decl"); } const ImplicitParamDecl *AnalysisContext::getSelfDecl() const { @@ -80,73 +83,113 @@ AnalysisContext *AnalysisContextManager::getContext(const Decl *D) { return AC; } -void LocationContext::Profile(llvm::FoldingSetNodeID &ID, ContextKind k, - AnalysisContext *ctx, - const LocationContext *parent) { - ID.AddInteger(k); +const BlockDecl *BlockInvocationContext::getBlockDecl() const { + return Data.is() ? + Data.get()->getDecl() + : Data.get(); +} + +//===----------------------------------------------------------------------===// +// FoldingSet profiling. +//===----------------------------------------------------------------------===// + +void LocationContext::ProfileCommon(llvm::FoldingSetNodeID &ID, + ContextKind ck, + AnalysisContext *ctx, + const LocationContext *parent, + const void* data) { + ID.AddInteger(ck); ID.AddPointer(ctx); ID.AddPointer(parent); + ID.AddPointer(data); } -void StackFrameContext::Profile(llvm::FoldingSetNodeID &ID,AnalysisContext *ctx, - const LocationContext *parent, const Stmt *s) { - LocationContext::Profile(ID, StackFrame, ctx, parent); - ID.AddPointer(s); +void StackFrameContext::Profile(llvm::FoldingSetNodeID &ID) { + Profile(ID, getAnalysisContext(), getParent(), CallSite); } -void ScopeContext::Profile(llvm::FoldingSetNodeID &ID, AnalysisContext *ctx, - const LocationContext *parent, const Stmt *s) { - LocationContext::Profile(ID, Scope, ctx, parent); - ID.AddPointer(s); +void ScopeContext::Profile(llvm::FoldingSetNodeID &ID) { + Profile(ID, getAnalysisContext(), getParent(), Enter); } -LocationContextManager::~LocationContextManager() { - clear(); +void BlockInvocationContext::Profile(llvm::FoldingSetNodeID &ID) { + if (const BlockDataRegion *BR = getBlockRegion()) + Profile(ID, getAnalysisContext(), getParent(), BR); + else + Profile(ID, getAnalysisContext(), getParent(), + Data.get()); } -void LocationContextManager::clear() { - for (llvm::FoldingSet::iterator I = Contexts.begin(), - E = Contexts.end(); I != E; ) { - LocationContext *LC = &*I; - ++I; - delete LC; - } +//===----------------------------------------------------------------------===// +// LocationContext creation. +//===----------------------------------------------------------------------===// + +template +const LOC* +LocationContextManager::getLocationContext(AnalysisContext *ctx, + const LocationContext *parent, + const DATA *d) { + llvm::FoldingSetNodeID ID; + LOC::Profile(ID, ctx, parent, d); + void *InsertPos; - Contexts.clear(); + LOC *L = cast_or_null(Contexts.FindNodeOrInsertPos(ID, InsertPos)); + + if (!L) { + L = new LOC(ctx, parent, d); + Contexts.InsertNode(L, InsertPos); + } + return L; } -StackFrameContext* +const StackFrameContext* LocationContextManager::getStackFrame(AnalysisContext *ctx, const LocationContext *parent, const Stmt *s) { - llvm::FoldingSetNodeID ID; - StackFrameContext::Profile(ID, ctx, parent, s); - void *InsertPos; - - StackFrameContext *f = - cast_or_null(Contexts.FindNodeOrInsertPos(ID, InsertPos)); - if (!f) { - f = new StackFrameContext(ctx, parent, s); - Contexts.InsertNode(f, InsertPos); - } - return f; + return getLocationContext(ctx, parent, s); } -ScopeContext *LocationContextManager::getScope(AnalysisContext *ctx, - const LocationContext *parent, - const Stmt *s) { - llvm::FoldingSetNodeID ID; - ScopeContext::Profile(ID, ctx, parent, s); - void *InsertPos; +const ScopeContext * +LocationContextManager::getScope(AnalysisContext *ctx, + const LocationContext *parent, + const Stmt *s) { + return getLocationContext(ctx, parent, s); +} - ScopeContext *scope = - cast_or_null(Contexts.FindNodeOrInsertPos(ID, InsertPos)); +const BlockInvocationContext * +LocationContextManager::getBlockInvocation(AnalysisContext *ctx, + const LocationContext *parent, + const BlockDataRegion *BR) { + return getLocationContext(ctx, + parent, + BR); +} - if (!scope) { - scope = new ScopeContext(ctx, parent, s); - Contexts.InsertNode(scope, InsertPos); +//===----------------------------------------------------------------------===// +// LocationContext methods. +//===----------------------------------------------------------------------===// + +const StackFrameContext *LocationContext::getCurrentStackFrame() const { + const LocationContext *LC = this; + while (LC) { + if (const StackFrameContext *SFC = dyn_cast(LC)) + return SFC; + LC = LC->getParent(); } - return scope; + return NULL; +} + +const StackFrameContext * +LocationContext::getStackFrameForDeclContext(const DeclContext *DC) const { + const LocationContext *LC = this; + while (LC) { + if (const StackFrameContext *SFC = dyn_cast(LC)) { + if (cast(SFC->getDecl()) == DC) + return SFC; + } + LC = LC->getParent(); + } + return NULL; } //===----------------------------------------------------------------------===// @@ -220,3 +263,21 @@ AnalysisContextManager::~AnalysisContextManager() { for (ContextMap::iterator I = Contexts.begin(), E = Contexts.end(); I!=E; ++I) delete I->second; } + +LocationContext::~LocationContext() {} + +LocationContextManager::~LocationContextManager() { + clear(); +} + +void LocationContextManager::clear() { + for (llvm::FoldingSet::iterator I = Contexts.begin(), + E = Contexts.end(); I != E; ) { + LocationContext *LC = &*I; + ++I; + delete LC; + } + + Contexts.clear(); +} + diff --git a/lib/Analysis/BasicStore.cpp b/lib/Analysis/BasicStore.cpp index 45fc11a534a5..a38aaa7eb268 100644 --- a/lib/Analysis/BasicStore.cpp +++ b/lib/Analysis/BasicStore.cpp @@ -68,14 +68,14 @@ class BasicStoreManager : public StoreManager { } const GRState *BindCompoundLiteral(const GRState *state, - const CompoundLiteralExpr* cl, + const CompoundLiteralExpr*, + const LocationContext*, SVal val) { return state; } SVal getLValueVar(const VarDecl *VD, const LocationContext *LC); SVal getLValueString(const StringLiteral *S); - SVal getLValueCompoundLiteral(const CompoundLiteralExpr *CL); SVal getLValueIvar(const ObjCIvarDecl* D, SVal Base); SVal getLValueField(const FieldDecl *D, SVal Base); SVal getLValueElement(QualType elementType, SVal Offset, SVal Base); @@ -130,10 +130,6 @@ SVal BasicStoreManager::getLValueString(const StringLiteral* S) { return ValMgr.makeLoc(MRMgr.getStringRegion(S)); } -SVal BasicStoreManager::getLValueCompoundLiteral(const CompoundLiteralExpr* CL){ - return ValMgr.makeLoc(MRMgr.getCompoundLiteralRegion(CL)); -} - SVal BasicStoreManager::getLValueIvar(const ObjCIvarDecl* D, SVal Base) { if (Base.isUnknownOrUndef()) @@ -368,7 +364,7 @@ BasicStoreManager::RemoveDeadBindings(GRState &state, Stmt* Loc, // Iterate over the variable bindings. for (BindingsTy::iterator I=B.begin(), E=B.end(); I!=E ; ++I) { if (const VarRegion *VR = dyn_cast(I.getKey())) { - if (SymReaper.isLive(Loc, VR->getDecl())) + if (SymReaper.isLive(Loc, VR)) RegionRoots.push_back(VR); else continue; diff --git a/lib/Analysis/BugReporter.cpp b/lib/Analysis/BugReporter.cpp index c26a60af9c85..e6482698dd43 100644 --- a/lib/Analysis/BugReporter.cpp +++ b/lib/Analysis/BugReporter.cpp @@ -204,10 +204,19 @@ PathDiagnosticBuilder::ExecutionContinues(llvm::raw_string_ostream& os, os << "Execution continues on line " << getSourceManager().getInstantiationLineNumber(Loc.asLocation()) << '.'; - else - os << "Execution jumps to the end of the " - << (isa(N->getLocationContext()->getDecl()) ? - "method" : "function") << '.'; + else { + os << "Execution jumps to the end of the "; + const Decl *D = N->getLocationContext()->getDecl(); + if (isa(D)) + os << "method"; + else if (isa(D)) + os << "function"; + else { + assert(isa(D)); + os << "anonymous block"; + } + os << '.'; + } return Loc; } diff --git a/lib/Analysis/BuiltinFunctionChecker.cpp b/lib/Analysis/BuiltinFunctionChecker.cpp new file mode 100644 index 000000000000..a89ad2164b30 --- /dev/null +++ b/lib/Analysis/BuiltinFunctionChecker.cpp @@ -0,0 +1,76 @@ +//=== BuiltinFunctionChecker.cpp --------------------------------*- C++ -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// +// This checker evaluates clang builtin functions. +// +//===----------------------------------------------------------------------===// + +#include "GRExprEngineInternalChecks.h" +#include "clang/Analysis/PathSensitive/Checker.h" +#include "clang/Basic/Builtins.h" +#include "llvm/ADT/StringSwitch.h" + +using namespace clang; + +namespace { + +class BuiltinFunctionChecker : public Checker { +public: + static void *getTag() { static int tag = 0; return &tag; } + virtual bool EvalCallExpr(CheckerContext &C, const CallExpr *CE); +}; + +} + +void clang::RegisterBuiltinFunctionChecker(GRExprEngine &Eng) { + Eng.registerCheck(new BuiltinFunctionChecker()); +} + +bool BuiltinFunctionChecker::EvalCallExpr(CheckerContext &C,const CallExpr *CE){ + const GRState *state = C.getState(); + const Expr *Callee = CE->getCallee(); + SVal L = state->getSVal(Callee); + const FunctionDecl *FD = L.getAsFunctionDecl(); + + if (!FD) + return false; + + unsigned id = FD->getBuiltinID(); + + if (!id) + return false; + + switch (id) { + case Builtin::BI__builtin_expect: { + // For __builtin_expect, just return the value of the subexpression. + assert (CE->arg_begin() != CE->arg_end()); + SVal X = state->getSVal(*(CE->arg_begin())); + C.GenerateNode(state->BindExpr(CE, X)); + return true; + } + + case Builtin::BI__builtin_alloca: { + // FIXME: Refactor into StoreManager itself? + MemRegionManager& RM = C.getStoreManager().getRegionManager(); + const MemRegion* R = + RM.getAllocaRegion(CE, C.getNodeBuilder().getCurrentBlockCount(), + C.getPredecessor()->getLocationContext()); + + // Set the extent of the region in bytes. This enables us to use the + // SVal of the argument directly. If we save the extent in bits, we + // cannot represent values like symbol*8. + SVal Extent = state->getSVal(*(CE->arg_begin())); + state = C.getStoreManager().setExtent(state, R, Extent); + C.GenerateNode(state->BindExpr(CE, loc::MemRegionVal(R))); + return true; + } + } + + return false; +} diff --git a/lib/Analysis/CFG.cpp b/lib/Analysis/CFG.cpp index c97692f57082..e1a1e72c2043 100644 --- a/lib/Analysis/CFG.cpp +++ b/lib/Analysis/CFG.cpp @@ -87,7 +87,6 @@ class CFGBuilder { CFGBlock *VisitAddrLabelExpr(AddrLabelExpr *A, bool alwaysAdd); CFGBlock *VisitBinaryOperator(BinaryOperator *B, bool alwaysAdd); CFGBlock *VisitBlockExpr(BlockExpr* E, bool alwaysAdd); - CFGBlock *VisitBlockDeclRefExpr(BlockDeclRefExpr* E, bool alwaysAdd); CFGBlock *VisitBreakStmt(BreakStmt *B); CFGBlock *VisitCallExpr(CallExpr *C, bool alwaysAdd); CFGBlock *VisitCaseStmt(CaseStmt *C); @@ -95,7 +94,9 @@ class CFGBuilder { CFGBlock *VisitCompoundStmt(CompoundStmt *C); CFGBlock *VisitConditionalOperator(ConditionalOperator *C); CFGBlock *VisitContinueStmt(ContinueStmt *C); + CFGBlock *VisitCXXCatchStmt(CXXCatchStmt *S) { return NYS(); } CFGBlock *VisitCXXThrowExpr(CXXThrowExpr *T); + CFGBlock *VisitCXXTryStmt(CXXTryStmt *S) { return NYS(); } CFGBlock *VisitDeclStmt(DeclStmt *DS); CFGBlock *VisitDeclSubExpr(Decl* D); CFGBlock *VisitDefaultStmt(DefaultStmt *D); @@ -292,9 +293,6 @@ CFGBlock* CFGBuilder::Visit(Stmt * S, bool alwaysAdd) { case Stmt::BlockExprClass: return VisitBlockExpr(cast(S), alwaysAdd); - case Stmt::BlockDeclRefExprClass: - return VisitBlockDeclRefExpr(cast(S), alwaysAdd); - case Stmt::BreakStmtClass: return VisitBreakStmt(cast(S)); @@ -468,12 +466,6 @@ CFGBlock *CFGBuilder::VisitBlockExpr(BlockExpr *E, bool alwaysAdd) { return Block; } -CFGBlock *CFGBuilder::VisitBlockDeclRefExpr(BlockDeclRefExpr* E, - bool alwaysAdd) { - // FIXME - return NYS(); -} - CFGBlock *CFGBuilder::VisitBreakStmt(BreakStmt *B) { // "break" is a control-flow statement. Thus we stop processing the current // block. diff --git a/lib/Analysis/CFRefCount.cpp b/lib/Analysis/CFRefCount.cpp index b95f981275e6..9639ad98fa69 100644 --- a/lib/Analysis/CFRefCount.cpp +++ b/lib/Analysis/CFRefCount.cpp @@ -675,11 +675,9 @@ template <> struct DenseMapInfo { RHS.getSelector()); } - static bool isPod() { - return DenseMapInfo::isPod() && - DenseMapInfo::isPod(); - } }; +template <> +struct isPodLike { static const bool value = true; }; } // end llvm namespace namespace { @@ -1984,8 +1982,9 @@ class CFRefCount : public GRTransferFuncs { Expr* Ex, Expr* Receiver, const RetainSummary& Summ, + const MemRegion *Callee, ExprIterator arg_beg, ExprIterator arg_end, - ExplodedNode* Pred); + ExplodedNode* Pred, const GRState *state); virtual void EvalCall(ExplodedNodeSet& Dst, GRExprEngine& Eng, @@ -1998,7 +1997,8 @@ class CFRefCount : public GRTransferFuncs { GRExprEngine& Engine, GRStmtNodeBuilder& Builder, ObjCMessageExpr* ME, - ExplodedNode* Pred); + ExplodedNode* Pred, + const GRState *state); bool EvalObjCMessageExprAux(ExplodedNodeSet& Dst, GRExprEngine& Engine, @@ -2776,11 +2776,9 @@ void CFRefCount::EvalSummary(ExplodedNodeSet& Dst, Expr* Ex, Expr* Receiver, const RetainSummary& Summ, + const MemRegion *Callee, ExprIterator arg_beg, ExprIterator arg_end, - ExplodedNode* Pred) { - - // Get the state. - const GRState *state = Builder.GetState(Pred); + ExplodedNode* Pred, const GRState *state) { // Evaluate the effect of the arguments. RefVal::Kind hasErr = (RefVal::Kind) 0; @@ -2788,6 +2786,8 @@ void CFRefCount::EvalSummary(ExplodedNodeSet& Dst, Expr* ErrorExpr = NULL; SymbolRef ErrorSym = 0; + llvm::SmallVector RegionsToInvalidate; + for (ExprIterator I = arg_beg; I != arg_end; ++I, ++idx) { SVal V = state->getSValAsScalarOrLoc(*I); SymbolRef Sym = V.getAsLocSymbol(); @@ -2810,16 +2810,8 @@ void CFRefCount::EvalSummary(ExplodedNodeSet& Dst, continue; // Invalidate the value of the variable passed by reference. - - // FIXME: We can have collisions on the conjured symbol if the - // expression *I also creates conjured symbols. We probably want - // to identify conjured symbols by an expression pair: the enclosing - // expression (the context) and the expression itself. This should - // disambiguate conjured symbols. - unsigned Count = Builder.getCurrentBlockCount(); - StoreManager& StoreMgr = Eng.getStateManager().getStoreManager(); - const MemRegion *R = MR->getRegion(); + // Are we dealing with an ElementRegion? If the element type is // a basic integer type (e.g., char, int) and the underying region // is a variable region then strip off the ElementRegion. @@ -2843,14 +2835,11 @@ void CFRefCount::EvalSummary(ExplodedNodeSet& Dst, } // FIXME: What about layers of ElementRegions? } - - StoreManager::InvalidatedSymbols IS; - state = StoreMgr.InvalidateRegion(state, R, *I, Count, &IS); - for (StoreManager::InvalidatedSymbols::iterator I = IS.begin(), - E = IS.end(); I!=E; ++I) { - // Remove any existing reference-count binding. - state = state->remove(*I); - } + + // Mark this region for invalidation. We batch invalidate regions + // below for efficiency. + RegionsToInvalidate.push_back(R); + continue; } else { // Nuke all other arguments passed by reference. @@ -2866,6 +2855,36 @@ void CFRefCount::EvalSummary(ExplodedNodeSet& Dst, goto tryAgain; } } + + // Block calls result in all captured values passed-via-reference to be + // invalidated. + if (const BlockDataRegion *BR = dyn_cast_or_null(Callee)) { + RegionsToInvalidate.push_back(BR); + } + + // Invalidate regions we designed for invalidation use the batch invalidation + // API. + if (!RegionsToInvalidate.empty()) { + // FIXME: We can have collisions on the conjured symbol if the + // expression *I also creates conjured symbols. We probably want + // to identify conjured symbols by an expression pair: the enclosing + // expression (the context) and the expression itself. This should + // disambiguate conjured symbols. + unsigned Count = Builder.getCurrentBlockCount(); + StoreManager& StoreMgr = Eng.getStateManager().getStoreManager(); + + + StoreManager::InvalidatedSymbols IS; + state = StoreMgr.InvalidateRegions(state, RegionsToInvalidate.data(), + RegionsToInvalidate.data() + + RegionsToInvalidate.size(), + Ex, Count, &IS); + for (StoreManager::InvalidatedSymbols::iterator I = IS.begin(), + E = IS.end(); I!=E; ++I) { + // Remove any existing reference-count binding. + state = state->remove(*I); + } + } // Evaluate the effect on the message receiver. if (!ErrorExpr && Receiver) { @@ -3012,35 +3031,24 @@ void CFRefCount::EvalCall(ExplodedNodeSet& Dst, } assert(Summ); - EvalSummary(Dst, Eng, Builder, CE, 0, *Summ, - CE->arg_begin(), CE->arg_end(), Pred); + EvalSummary(Dst, Eng, Builder, CE, 0, *Summ, L.getAsRegion(), + CE->arg_begin(), CE->arg_end(), Pred, Builder.GetState(Pred)); } void CFRefCount::EvalObjCMessageExpr(ExplodedNodeSet& Dst, GRExprEngine& Eng, GRStmtNodeBuilder& Builder, ObjCMessageExpr* ME, - ExplodedNode* Pred) { - // FIXME: Since we moved the nil check into a checker, we could get nil - // receiver here. Need a better way to check such case. - if (Expr* Receiver = ME->getReceiver()) { - const GRState *state = Pred->getState(); - DefinedOrUnknownSVal L=cast(state->getSVal(Receiver)); - if (!state->Assume(L, true)) { - Dst.Add(Pred); - return; - } - } - + ExplodedNode* Pred, + const GRState *state) { RetainSummary *Summ = ME->getReceiver() - ? Summaries.getInstanceMethodSummary(ME, Builder.GetState(Pred), - Pred->getLocationContext()) + ? Summaries.getInstanceMethodSummary(ME, state,Pred->getLocationContext()) : Summaries.getClassMethodSummary(ME); assert(Summ && "RetainSummary is null"); - EvalSummary(Dst, Eng, Builder, ME, ME->getReceiver(), *Summ, - ME->arg_begin(), ME->arg_end(), Pred); + EvalSummary(Dst, Eng, Builder, ME, ME->getReceiver(), *Summ, NULL, + ME->arg_begin(), ME->arg_end(), Pred, state); } namespace { @@ -3671,7 +3679,24 @@ void RetainReleaseChecker::PostVisitBlockExpr(CheckerContext &C, if (I == E) return; - state = state->scanReachableSymbols(I, E).getState(); + // FIXME: For now we invalidate the tracking of all symbols passed to blocks + // via captured variables, even though captured variables result in a copy + // and in implicit increment/decrement of a retain count. + llvm::SmallVector Regions; + const LocationContext *LC = C.getPredecessor()->getLocationContext(); + MemRegionManager &MemMgr = C.getValueManager().getRegionManager(); + + for ( ; I != E; ++I) { + const VarRegion *VR = *I; + if (VR->getSuperRegion() == R) { + VR = MemMgr.getVarRegion(VR->getDecl(), LC); + } + Regions.push_back(VR); + } + + state = + state->scanReachableSymbols(Regions.data(), + Regions.data() + Regions.size()).getState(); C.addTransition(state); } diff --git a/lib/Analysis/CMakeLists.txt b/lib/Analysis/CMakeLists.txt index 409292d451d8..521f1be6ec8b 100644 --- a/lib/Analysis/CMakeLists.txt +++ b/lib/Analysis/CMakeLists.txt @@ -10,10 +10,10 @@ add_clang_library(clangAnalysis BasicValueFactory.cpp BugReporter.cpp BugReporterVisitors.cpp + BuiltinFunctionChecker.cpp CFG.cpp CFRefCount.cpp CallAndMessageChecker.cpp - CallGraph.cpp CallInliner.cpp CastToStructChecker.cpp CheckDeadStores.cpp @@ -37,8 +37,10 @@ add_clang_library(clangAnalysis MallocChecker.cpp ManagerRegistry.cpp MemRegion.cpp + NoReturnFunctionChecker.cpp NSAutoreleasePoolChecker.cpp NSErrorChecker.cpp + OSAtomicChecker.cpp PathDiagnostic.cpp PointerArithChecker.cpp PointerSubChecker.cpp diff --git a/lib/Analysis/CallAndMessageChecker.cpp b/lib/Analysis/CallAndMessageChecker.cpp index d8dd16c57b81..c287354650b8 100644 --- a/lib/Analysis/CallAndMessageChecker.cpp +++ b/lib/Analysis/CallAndMessageChecker.cpp @@ -41,6 +41,7 @@ class CallAndMessageChecker void PreVisitCallExpr(CheckerContext &C, const CallExpr *CE); void PreVisitObjCMessageExpr(CheckerContext &C, const ObjCMessageExpr *ME); + bool EvalNilReceiver(CheckerContext &C, const ObjCMessageExpr *ME); private: void EmitBadCall(BugType *BT, CheckerContext &C, const CallExpr *CE); @@ -148,28 +149,12 @@ void CallAndMessageChecker::PreVisitObjCMessageExpr(CheckerContext &C, } } } +} - // Check if the receiver was nil and then returns a value that may - // be garbage. - if (const Expr *Receiver = ME->getReceiver()) { - DefinedOrUnknownSVal receiverVal = - cast(state->getSVal(Receiver)); - - const GRState *notNullState, *nullState; - llvm::tie(notNullState, nullState) = state->Assume(receiverVal); - - if (nullState && !notNullState) { - HandleNilReceiver(C, nullState, ME); - C.setDoneEvaluating(); // FIXME: eventually remove. - return; - } - - assert(notNullState); - state = notNullState; - } - - // Add a state transition if the state has changed. - C.addTransition(state); +bool CallAndMessageChecker::EvalNilReceiver(CheckerContext &C, + const ObjCMessageExpr *ME) { + HandleNilReceiver(C, C.getState(), ME); + return true; // Nil receiver is not handled elsewhere. } void CallAndMessageChecker::EmitNilReceiverBug(CheckerContext &C, diff --git a/lib/Analysis/CheckDeadStores.cpp b/lib/Analysis/CheckDeadStores.cpp index ad63eb4122b0..db9016fa1e64 100644 --- a/lib/Analysis/CheckDeadStores.cpp +++ b/lib/Analysis/CheckDeadStores.cpp @@ -84,7 +84,8 @@ class DeadStoreObs : public LiveVariables::ObserverTy { const LiveVariables::AnalysisDataTy& AD, const LiveVariables::ValTy& Live) { - if (VD->hasLocalStorage() && !Live(VD, AD) && !VD->getAttr()) + if (VD->hasLocalStorage() && !Live(VD, AD) && + !(VD->getAttr() || VD->getAttr())) Report(VD, dsk, Ex->getSourceRange().getBegin(), Val->getSourceRange()); } @@ -185,6 +186,10 @@ class DeadStoreObs : public LiveVariables::ObserverTy { if (V->hasLocalStorage()) if (Expr* E = V->getInit()) { + // Don't warn on C++ objects (yet) until we can show that their + // constructors/destructors don't have side effects. + if (isa(E)) + return; // A dead initialization is a variable that is dead after it // is initialized. We don't flag warnings for those variables // marked 'unused'. diff --git a/lib/Analysis/CheckSecuritySyntaxOnly.cpp b/lib/Analysis/CheckSecuritySyntaxOnly.cpp index e6ab17a75905..3214101c6485 100644 --- a/lib/Analysis/CheckSecuritySyntaxOnly.cpp +++ b/lib/Analysis/CheckSecuritySyntaxOnly.cpp @@ -23,6 +23,7 @@ class WalkAST : public StmtVisitor { BugReporter &BR; IdentifierInfo *II_gets; IdentifierInfo *II_getpw; + IdentifierInfo *II_mktemp; enum { num_rands = 9 }; IdentifierInfo *II_rand[num_rands]; IdentifierInfo *II_random; @@ -31,7 +32,8 @@ class WalkAST : public StmtVisitor { public: WalkAST(BugReporter &br) : BR(br), - II_gets(0), II_getpw(0), II_rand(), II_random(0), II_setid() {} + II_gets(0), II_getpw(0), II_mktemp(0), + II_rand(), II_random(0), II_setid() {} // Statement visitor methods. void VisitCallExpr(CallExpr *CE); @@ -48,6 +50,7 @@ class WalkAST : public StmtVisitor { void CheckLoopConditionForFloat(const ForStmt *FS); void CheckCall_gets(const CallExpr *CE, const FunctionDecl *FD); void CheckCall_getpw(const CallExpr *CE, const FunctionDecl *FD); + void CheckCall_mktemp(const CallExpr *CE, const FunctionDecl *FD); void CheckCall_rand(const CallExpr *CE, const FunctionDecl *FD); void CheckCall_random(const CallExpr *CE, const FunctionDecl *FD); void CheckUncheckedReturnValue(CallExpr *CE); @@ -79,6 +82,7 @@ void WalkAST::VisitCallExpr(CallExpr *CE) { if (const FunctionDecl *FD = CE->getDirectCallee()) { CheckCall_gets(CE, FD); CheckCall_getpw(CE, FD); + CheckCall_mktemp(CE, FD); CheckCall_rand(CE, FD); CheckCall_random(CE, FD); } @@ -287,6 +291,42 @@ void WalkAST::CheckCall_getpw(const CallExpr *CE, const FunctionDecl *FD) { CE->getLocStart(), &R, 1); } +//===----------------------------------------------------------------------===// +// Check: Any use of 'mktemp' is insecure.It is obsoleted by mkstemp(). +// CWE-377: Insecure Temporary File +//===----------------------------------------------------------------------===// + +void WalkAST::CheckCall_mktemp(const CallExpr *CE, const FunctionDecl *FD) { + if (FD->getIdentifier() != GetIdentifier(II_mktemp, "mktemp")) + return; + + const FunctionProtoType *FPT = dyn_cast(FD->getType()); + if(!FPT) + return; + + // Verify that the funcion takes a single argument. + if (FPT->getNumArgs() != 1) + return; + + // Verify that the argument is Pointer Type. + const PointerType *PT = dyn_cast(FPT->getArgType(0)); + if (!PT) + return; + + // Verify that the argument is a 'char*'. + if (PT->getPointeeType().getUnqualifiedType() != BR.getContext().CharTy) + return; + + // Issue a waring. + SourceRange R = CE->getCallee()->getSourceRange(); + BR.EmitBasicReport("Potential insecure temporary file in call 'mktemp'", + "Security", + "Call to function 'mktemp' is insecure as it always " + "creates or uses insecure temporary file", + CE->getLocStart(), &R, 1); +} + + //===----------------------------------------------------------------------===// // Check: Linear congruent random number generators should not be used // Originally: diff --git a/lib/Analysis/Checker.cpp b/lib/Analysis/Checker.cpp index 0d907e501686..fb9d04d947b7 100644 --- a/lib/Analysis/Checker.cpp +++ b/lib/Analysis/Checker.cpp @@ -24,10 +24,10 @@ CheckerContext::~CheckerContext() { // if we are building sinks or we generated a node and decided to not // add it as a transition. if (Dst.size() == size && !B.BuildSinks && !B.HasGeneratedNode) { - if (state && state != B.GetState(Pred)) { + if (ST && ST != B.GetState(Pred)) { static int autoTransitionTag = 0; B.Tag = &autoTransitionTag; - addTransition(state); + addTransition(ST); } else Dst.Add(Pred); diff --git a/lib/Analysis/GRExprEngine.cpp b/lib/Analysis/GRExprEngine.cpp index 20820d4f3833..51e6a547529f 100644 --- a/lib/Analysis/GRExprEngine.cpp +++ b/lib/Analysis/GRExprEngine.cpp @@ -116,53 +116,91 @@ class MappedBatchAuditor : public GRSimpleAPICheck { // Checker worklist routines. //===----------------------------------------------------------------------===// -bool GRExprEngine::CheckerVisit(Stmt *S, ExplodedNodeSet &Dst, +void GRExprEngine::CheckerVisit(Stmt *S, ExplodedNodeSet &Dst, ExplodedNodeSet &Src, bool isPrevisit) { if (Checkers.empty()) { Dst.insert(Src); - return false; + return; } ExplodedNodeSet Tmp; ExplodedNodeSet *PrevSet = &Src; - bool stopProcessingAfterCurrentChecker = false; - for (CheckersOrdered::iterator I=Checkers.begin(),E=Checkers.end(); I!=E; ++I) - { - ExplodedNodeSet *CurrSet = (I+1 == E) ? &Dst - : (PrevSet == &Tmp) ? &Src : &Tmp; - - CurrSet->clear(); + for (CheckersOrdered::iterator I=Checkers.begin(),E=Checkers.end(); I!=E;++I){ + ExplodedNodeSet *CurrSet = 0; + if (I+1 == E) + CurrSet = &Dst; + else { + CurrSet = (PrevSet == &Tmp) ? &Src : &Tmp; + CurrSet->clear(); + } void *tag = I->first; Checker *checker = I->second; for (ExplodedNodeSet::iterator NI = PrevSet->begin(), NE = PrevSet->end(); - NI != NE; ++NI) { - // FIXME: Halting evaluation of the checkers is something we may - // not support later. The design is still evolving. - if (checker->GR_Visit(*CurrSet, *Builder, *this, S, *NI, - tag, isPrevisit)) { - if (CurrSet != &Dst) - Dst.insert(*CurrSet); - - stopProcessingAfterCurrentChecker = true; - continue; - } - assert(stopProcessingAfterCurrentChecker == false && - "Inconsistent setting of 'stopProcessingAfterCurrentChecker'"); - } - - if (stopProcessingAfterCurrentChecker) - return true; - - // Continue on to the next checker. Update the current NodeSet. + NI != NE; ++NI) + checker->GR_Visit(*CurrSet, *Builder, *this, S, *NI, tag, isPrevisit); PrevSet = CurrSet; } // Don't autotransition. The CheckerContext objects should do this // automatically. - return false; +} + +void GRExprEngine::CheckerEvalNilReceiver(const ObjCMessageExpr *ME, + ExplodedNodeSet &Dst, + const GRState *state, + ExplodedNode *Pred) { + bool Evaluated = false; + ExplodedNodeSet DstTmp; + + for (CheckersOrdered::iterator I=Checkers.begin(),E=Checkers.end();I!=E;++I) { + void *tag = I->first; + Checker *checker = I->second; + + if (checker->GR_EvalNilReceiver(DstTmp, *Builder, *this, ME, Pred, state, + tag)) { + Evaluated = true; + break; + } else + // The checker didn't evaluate the expr. Restore the Dst. + DstTmp.clear(); + } + + if (Evaluated) + Dst.insert(DstTmp); + else + Dst.insert(Pred); +} + +// CheckerEvalCall returns true if one of the checkers processed the node. +// This may return void when all call evaluation logic goes to some checker +// in the future. +bool GRExprEngine::CheckerEvalCall(const CallExpr *CE, + ExplodedNodeSet &Dst, + ExplodedNode *Pred) { + bool Evaluated = false; + ExplodedNodeSet DstTmp; + + for (CheckersOrdered::iterator I=Checkers.begin(),E=Checkers.end();I!=E;++I) { + void *tag = I->first; + Checker *checker = I->second; + + if (checker->GR_EvalCallExpr(DstTmp, *Builder, *this, CE, Pred, tag)) { + Evaluated = true; + break; + } else + // The checker didn't evaluate the expr. Restore the DstTmp set. + DstTmp.clear(); + } + + if (Evaluated) + Dst.insert(DstTmp); + else + Dst.insert(Pred); + + return Evaluated; } // FIXME: This is largely copy-paste from CheckerVisit(). Need to @@ -173,7 +211,7 @@ void GRExprEngine::CheckerVisitBind(const Stmt *AssignE, const Stmt *StoreE, SVal location, SVal val, bool isPrevisit) { if (Checkers.empty()) { - Dst = Src; + Dst.insert(Src); return; } @@ -182,10 +220,14 @@ void GRExprEngine::CheckerVisitBind(const Stmt *AssignE, const Stmt *StoreE, for (CheckersOrdered::iterator I=Checkers.begin(),E=Checkers.end(); I!=E; ++I) { - ExplodedNodeSet *CurrSet = (I+1 == E) ? &Dst - : (PrevSet == &Tmp) ? &Src : &Tmp; + ExplodedNodeSet *CurrSet = 0; + if (I+1 == E) + CurrSet = &Dst; + else { + CurrSet = (PrevSet == &Tmp) ? &Src : &Tmp; + CurrSet->clear(); + } - CurrSet->clear(); void *tag = I->first; Checker *checker = I->second; @@ -227,6 +269,11 @@ static void RegisterInternalChecks(GRExprEngine &Eng) { RegisterUndefinedAssignmentChecker(Eng); RegisterUndefBranchChecker(Eng); RegisterUndefResultChecker(Eng); + + // This is not a checker yet. + RegisterNoReturnFunctionChecker(Eng); + RegisterBuiltinFunctionChecker(Eng); + RegisterOSAtomicChecker(Eng); } GRExprEngine::GRExprEngine(AnalysisManager &mgr) @@ -347,8 +394,9 @@ void GRExprEngine::ProcessStmt(Stmt* S, GRStmtNodeBuilder& builder) { Builder->setAuditor(BatchAuditor.get()); // Create the cleaned state. - SymbolReaper SymReaper(Builder->getBasePredecessor()->getLiveVariables(), - SymMgr); + const ExplodedNode *BasePred = Builder->getBasePredecessor(); + SymbolReaper SymReaper(BasePred->getLiveVariables(), SymMgr, + BasePred->getLocationContext()->getCurrentStackFrame()); CleanedState = AMgr.shouldPurgeDead() ? StateMgr.RemoveDeadBindings(EntryNode->getState(), CurrentStmt, SymReaper) : EntryNode->getState(); @@ -371,16 +419,20 @@ void GRExprEngine::ProcessStmt(Stmt* S, GRStmtNodeBuilder& builder) { CleanedState, SymReaper); if (Checkers.empty()) - Tmp = Tmp2; + Tmp.insert(Tmp2); else { ExplodedNodeSet Tmp3; ExplodedNodeSet *SrcSet = &Tmp2; for (CheckersOrdered::iterator I = Checkers.begin(), E = Checkers.end(); I != E; ++I) { - ExplodedNodeSet *DstSet = (I+1 == E) ? &Tmp - : (SrcSet == &Tmp2) ? &Tmp3 - : &Tmp2; - DstSet->clear(); + ExplodedNodeSet *DstSet = 0; + if (I+1 == E) + DstSet = &Tmp; + else { + DstSet = (SrcSet == &Tmp2) ? &Tmp3 : &Tmp2; + DstSet->clear(); + } + void *tag = I->first; Checker *checker = I->second; for (ExplodedNodeSet::iterator NI = SrcSet->begin(), NE = SrcSet->end(); @@ -441,6 +493,41 @@ void GRExprEngine::Visit(Stmt* S, ExplodedNode* Pred, ExplodedNodeSet& Dst) { } switch (S->getStmtClass()) { + // C++ stuff we don't support yet. + case Stmt::CXXMemberCallExprClass: + case Stmt::CXXNamedCastExprClass: + case Stmt::CXXStaticCastExprClass: + case Stmt::CXXDynamicCastExprClass: + 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::CXXConstructExprClass: + case Stmt::CXXBindTemporaryExprClass: + case Stmt::CXXExprWithTemporariesClass: + case Stmt::CXXTemporaryObjectExprClass: + case Stmt::CXXUnresolvedConstructExprClass: + case Stmt::CXXDependentScopeMemberExprClass: + case Stmt::UnresolvedMemberExprClass: + case Stmt::CXXCatchStmtClass: + case Stmt::CXXTryStmtClass: { + SaveAndRestore OldSink(Builder->BuildSinks); + Builder->BuildSinks = true; + MakeNode(Dst, S, Pred, GetState(Pred)); + break; + } default: // Cases we intentionally have "default" handle: @@ -456,6 +543,10 @@ void GRExprEngine::Visit(Stmt* S, ExplodedNode* Pred, ExplodedNodeSet& Dst) { case Stmt::AsmStmtClass: VisitAsmStmt(cast(S), Pred, Dst); break; + + case Stmt::BlockDeclRefExprClass: + VisitBlockDeclRefExpr(cast(S), Pred, Dst, false); + break; case Stmt::BlockExprClass: VisitBlockExpr(cast(S), Pred, Dst); @@ -627,6 +718,10 @@ void GRExprEngine::VisitLValue(Expr* Ex, ExplodedNode* Pred, VisitArraySubscriptExpr(cast(Ex), Pred, Dst, true); return; + case Stmt::BlockDeclRefExprClass: + VisitBlockDeclRefExpr(cast(Ex), Pred, Dst, true); + return; + case Stmt::DeclRefExprClass: VisitDeclRefExpr(cast(Ex), Pred, Dst, true); return; @@ -1118,9 +1213,20 @@ void GRExprEngine::VisitBlockExpr(BlockExpr *BE, ExplodedNode *Pred, void GRExprEngine::VisitDeclRefExpr(DeclRefExpr *Ex, ExplodedNode *Pred, ExplodedNodeSet &Dst, bool asLValue) { + VisitCommonDeclRefExpr(Ex, Ex->getDecl(), Pred, Dst, asLValue); +} + +void GRExprEngine::VisitBlockDeclRefExpr(BlockDeclRefExpr *Ex, + ExplodedNode *Pred, + ExplodedNodeSet &Dst, bool asLValue) { + VisitCommonDeclRefExpr(Ex, Ex->getDecl(), Pred, Dst, asLValue); +} + +void GRExprEngine::VisitCommonDeclRefExpr(Expr *Ex, const NamedDecl *D, + ExplodedNode *Pred, + ExplodedNodeSet &Dst, bool asLValue) { const GRState *state = GetState(Pred); - const NamedDecl *D = Ex->getDecl(); if (const VarDecl* VD = dyn_cast(D)) { @@ -1354,10 +1460,14 @@ void GRExprEngine::EvalLocation(ExplodedNodeSet &Dst, Stmt *S, for (CheckersOrdered::iterator I=Checkers.begin(),E=Checkers.end(); I!=E; ++I) { - ExplodedNodeSet *CurrSet = (I+1 == E) ? &Dst - : (PrevSet == &Tmp) ? &Src : &Tmp; + ExplodedNodeSet *CurrSet = 0; + if (I+1 == E) + CurrSet = &Dst; + else { + CurrSet = (PrevSet == &Tmp) ? &Src : &Tmp; + CurrSet->clear(); + } - CurrSet->clear(); void *tag = I->first; Checker *checker = I->second; @@ -1375,233 +1485,9 @@ void GRExprEngine::EvalLocation(ExplodedNodeSet &Dst, Stmt *S, } } -//===----------------------------------------------------------------------===// -// Transfer function: OSAtomics. -// -// FIXME: Eventually refactor into a more "plugin" infrastructure. -//===----------------------------------------------------------------------===// - -// Mac OS X: -// http://developer.apple.com/documentation/Darwin/Reference/Manpages/man3 -// atomic.3.html -// -static bool EvalOSAtomicCompareAndSwap(ExplodedNodeSet& Dst, - GRExprEngine& Engine, - GRStmtNodeBuilder& Builder, - CallExpr* CE, ExplodedNode* Pred) { - - // Not enough arguments to match OSAtomicCompareAndSwap? - if (CE->getNumArgs() != 3) - return false; - - ASTContext &C = Engine.getContext(); - Expr *oldValueExpr = CE->getArg(0); - QualType oldValueType = C.getCanonicalType(oldValueExpr->getType()); - - Expr *newValueExpr = CE->getArg(1); - QualType newValueType = C.getCanonicalType(newValueExpr->getType()); - - // Do the types of 'oldValue' and 'newValue' match? - if (oldValueType != newValueType) - return false; - - Expr *theValueExpr = CE->getArg(2); - const PointerType *theValueType = - theValueExpr->getType()->getAs(); - - // theValueType not a pointer? - if (!theValueType) - return false; - - QualType theValueTypePointee = - C.getCanonicalType(theValueType->getPointeeType()).getUnqualifiedType(); - - // The pointee must match newValueType and oldValueType. - if (theValueTypePointee != newValueType) - return false; - - static unsigned magic_load = 0; - static unsigned magic_store = 0; - - const void *OSAtomicLoadTag = &magic_load; - const void *OSAtomicStoreTag = &magic_store; - - // Load 'theValue'. - const GRState *state = Pred->getState(); - ExplodedNodeSet Tmp; - SVal location = state->getSVal(theValueExpr); - // Here we should use the value type of the region as the load type. - const MemRegion *R = location.getAsRegion(); - QualType LoadTy; - if (R) - LoadTy = cast(R)->getValueType(C); - Engine.EvalLoad(Tmp, theValueExpr, Pred, state, location, OSAtomicLoadTag, - LoadTy); - - for (ExplodedNodeSet::iterator I = Tmp.begin(), E = Tmp.end(); - I != E; ++I) { - - ExplodedNode *N = *I; - const GRState *stateLoad = N->getState(); - SVal theValueVal_untested = stateLoad->getSVal(theValueExpr); - SVal oldValueVal_untested = stateLoad->getSVal(oldValueExpr); - - // FIXME: Issue an error. - if (theValueVal_untested.isUndef() || oldValueVal_untested.isUndef()) { - return false; - } - - DefinedOrUnknownSVal theValueVal = - cast(theValueVal_untested); - DefinedOrUnknownSVal oldValueVal = - cast(oldValueVal_untested); - - SValuator &SVator = Engine.getSValuator(); - - // Perform the comparison. - DefinedOrUnknownSVal Cmp = SVator.EvalEQ(stateLoad, theValueVal, - oldValueVal); - - const GRState *stateEqual = stateLoad->Assume(Cmp, true); - - // Were they equal? - if (stateEqual) { - // Perform the store. - ExplodedNodeSet TmpStore; - SVal val = stateEqual->getSVal(newValueExpr); - - // Handle implicit value casts. - if (const TypedRegion *R = - dyn_cast_or_null(location.getAsRegion())) { - llvm::tie(state, val) = SVator.EvalCast(val, state, R->getValueType(C), - newValueExpr->getType()); - } - - Engine.EvalStore(TmpStore, NULL, theValueExpr, N, stateEqual, location, - val, OSAtomicStoreTag); - - // Now bind the result of the comparison. - for (ExplodedNodeSet::iterator I2 = TmpStore.begin(), - E2 = TmpStore.end(); I2 != E2; ++I2) { - ExplodedNode *predNew = *I2; - const GRState *stateNew = predNew->getState(); - SVal Res = Engine.getValueManager().makeTruthVal(true, CE->getType()); - Engine.MakeNode(Dst, CE, predNew, stateNew->BindExpr(CE, Res)); - } - } - - // Were they not equal? - if (const GRState *stateNotEqual = stateLoad->Assume(Cmp, false)) { - SVal Res = Engine.getValueManager().makeTruthVal(false, CE->getType()); - Engine.MakeNode(Dst, CE, N, stateNotEqual->BindExpr(CE, Res)); - } - } - - return true; -} - -static bool EvalOSAtomic(ExplodedNodeSet& Dst, - GRExprEngine& Engine, - GRStmtNodeBuilder& Builder, - CallExpr* CE, SVal L, - ExplodedNode* Pred) { - const FunctionDecl* FD = L.getAsFunctionDecl(); - if (!FD) - return false; - - const char *FName = FD->getNameAsCString(); - - // Check for compare and swap. - if (strncmp(FName, "OSAtomicCompareAndSwap", 22) == 0 || - strncmp(FName, "objc_atomicCompareAndSwap", 25) == 0) - return EvalOSAtomicCompareAndSwap(Dst, Engine, Builder, CE, Pred); - - // FIXME: Other atomics. - return false; -} - //===----------------------------------------------------------------------===// // Transfer function: Function calls. //===----------------------------------------------------------------------===// -static void MarkNoReturnFunction(const FunctionDecl *FD, CallExpr *CE, - const GRState *state, - GRStmtNodeBuilder *Builder) { - if (!FD) - return; - - if (FD->getAttr() || - FD->getAttr()) - Builder->BuildSinks = true; - else { - // HACK: Some functions are not marked noreturn, and don't return. - // Here are a few hardwired ones. If this takes too long, we can - // potentially cache these results. - using llvm::StringRef; - bool BuildSinks - = llvm::StringSwitch(StringRef(FD->getIdentifier()->getName())) - .Case("exit", true) - .Case("panic", true) - .Case("error", true) - .Case("Assert", true) - // FIXME: This is just a wrapper around throwing an exception. - // Eventually inter-procedural analysis should handle this easily. - .Case("ziperr", true) - .Case("assfail", true) - .Case("db_error", true) - .Case("__assert", true) - .Case("__assert_rtn", true) - .Case("__assert_fail", true) - .Case("dtrace_assfail", true) - .Case("yy_fatal_error", true) - .Case("_XCAssertionFailureHandler", true) - .Case("_DTAssertionFailureHandler", true) - .Case("_TSAssertionFailureHandler", true) - .Default(false); - - if (BuildSinks) - Builder->BuildSinks = true; - } -} - -bool GRExprEngine::EvalBuiltinFunction(const FunctionDecl *FD, CallExpr *CE, - ExplodedNode *Pred, - ExplodedNodeSet &Dst) { - if (!FD) - return false; - - unsigned id = FD->getBuiltinID(); - if (!id) - return false; - - const GRState *state = Pred->getState(); - - switch (id) { - case Builtin::BI__builtin_expect: { - // For __builtin_expect, just return the value of the subexpression. - assert (CE->arg_begin() != CE->arg_end()); - SVal X = state->getSVal(*(CE->arg_begin())); - MakeNode(Dst, CE, Pred, state->BindExpr(CE, X)); - return true; - } - - case Builtin::BI__builtin_alloca: { - // FIXME: Refactor into StoreManager itself? - MemRegionManager& RM = getStateManager().getRegionManager(); - const MemRegion* R = - RM.getAllocaRegion(CE, Builder->getCurrentBlockCount()); - - // Set the extent of the region in bytes. This enables us to use the - // SVal of the argument directly. If we save the extent in bits, we - // cannot represent values like symbol*8. - SVal Extent = state->getSVal(*(CE->arg_begin())); - state = getStoreManager().setExtent(state, R, Extent); - MakeNode(Dst, CE, Pred, state->BindExpr(CE, loc::MemRegionVal(R))); - return true; - } - } - - return false; -} void GRExprEngine::VisitCall(CallExpr* CE, ExplodedNode* Pred, CallExpr::arg_iterator AI, @@ -1659,6 +1545,8 @@ void GRExprEngine::VisitCallRec(CallExpr* CE, ExplodedNode* Pred, } // Finally, evaluate the function call. + ExplodedNodeSet DstTmp3; + for (ExplodedNodeSet::iterator DI = DstTmp.begin(), DE = DstTmp.end(); DI != DE; ++DI) { @@ -1667,39 +1555,39 @@ void GRExprEngine::VisitCallRec(CallExpr* CE, ExplodedNode* Pred, // FIXME: Add support for symbolic function calls (calls involving // function pointer values that are symbolic). - - // Check for the "noreturn" attribute. - SaveAndRestore OldSink(Builder->BuildSinks); - const FunctionDecl* FD = L.getAsFunctionDecl(); + ExplodedNodeSet DstChecker; - MarkNoReturnFunction(FD, CE, state, Builder); + // If the callee is processed by a checker, skip the rest logic. + if (CheckerEvalCall(CE, DstChecker, *DI)) + DstTmp3.insert(DstChecker); + else { + for (ExplodedNodeSet::iterator DI_Checker = DstChecker.begin(), + DE_Checker = DstChecker.end(); + DI_Checker != DE_Checker; ++DI_Checker) { - // Evaluate the call. - if (EvalBuiltinFunction(FD, CE, *DI, Dst)) - continue; + // Dispatch to the plug-in transfer function. + unsigned OldSize = DstTmp3.size(); + SaveOr OldHasGen(Builder->HasGeneratedNode); + Pred = *DI_Checker; - // Dispatch to the plug-in transfer function. - SaveOr OldHasGen(Builder->HasGeneratedNode); - Pred = *DI; - - // Dispatch to transfer function logic to handle the call itself. - // FIXME: Allow us to chain together transfer functions. - assert(Builder && "GRStmtNodeBuilder must be defined."); - ExplodedNodeSet DstTmp; + // Dispatch to transfer function logic to handle the call itself. + // FIXME: Allow us to chain together transfer functions. + assert(Builder && "GRStmtNodeBuilder must be defined."); - if (!EvalOSAtomic(DstTmp, *this, *Builder, CE, L, Pred)) - getTF().EvalCall(DstTmp, *this, *Builder, CE, L, Pred); + getTF().EvalCall(DstTmp3, *this, *Builder, CE, L, Pred); - // Handle the case where no nodes where generated. Auto-generate that - // contains the updated state if we aren't generating sinks. - if (!Builder->BuildSinks && DstTmp.empty() && - !Builder->HasGeneratedNode) - MakeNode(DstTmp, CE, Pred, state); - - // Perform the post-condition check of the CallExpr. - CheckerVisit(CE, Dst, DstTmp, false); + // Handle the case where no nodes where generated. Auto-generate that + // contains the updated state if we aren't generating sinks. + if (!Builder->BuildSinks && DstTmp3.size() == OldSize && + !Builder->HasGeneratedNode) + MakeNode(DstTmp3, CE, Pred, state); + } + } } + + // Perform the post-condition check of the CallExpr. + CheckerVisit(CE, Dst, DstTmp3, false); } //===----------------------------------------------------------------------===// @@ -1922,10 +1810,7 @@ void GRExprEngine::VisitObjCMessageExprDispatchHelper(ObjCMessageExpr* ME, ExplodedNodeSet Src, DstTmp; Src.Add(Pred); - if (CheckerVisit(ME, DstTmp, Src, true)) { - Dst.insert(DstTmp); - return; - } + CheckerVisit(ME, DstTmp, Src, true); unsigned size = Dst.size(); @@ -1934,10 +1819,38 @@ void GRExprEngine::VisitObjCMessageExprDispatchHelper(ObjCMessageExpr* ME, Pred = *DI; bool RaisesException = false; - if (ME->getReceiver()) { + if (const Expr *Receiver = ME->getReceiver()) { + const GRState *state = Pred->getState(); + + // Bifurcate the state into nil and non-nil ones. + DefinedOrUnknownSVal receiverVal = + cast(state->getSVal(Receiver)); + + const GRState *notNilState, *nilState; + llvm::tie(notNilState, nilState) = state->Assume(receiverVal); + + // There are three cases: can be nil or non-nil, must be nil, must be + // non-nil. We handle must be nil, and merge the rest two into non-nil. + if (nilState && !notNilState) { + CheckerEvalNilReceiver(ME, Dst, nilState, Pred); + return; + } + + assert(notNilState); + // Check if the "raise" message was sent. if (ME->getSelector() == RaiseSel) RaisesException = true; + + // Check if we raise an exception. For now treat these as sinks. + // Eventually we will want to handle exceptions properly. + SaveAndRestore OldSink(Builder->BuildSinks); + if (RaisesException) + Builder->BuildSinks = true; + + // Dispatch to plug-in transfer function. + SaveOr OldHasGen(Builder->HasGeneratedNode); + EvalObjCMessageExpr(Dst, ME, Pred, notNilState); } else { @@ -1984,17 +1897,17 @@ void GRExprEngine::VisitObjCMessageExprDispatchHelper(ObjCMessageExpr* ME, RaisesException = true; break; } } + + // Check if we raise an exception. For now treat these as sinks. + // Eventually we will want to handle exceptions properly. + SaveAndRestore OldSink(Builder->BuildSinks); + if (RaisesException) + Builder->BuildSinks = true; + + // Dispatch to plug-in transfer function. + SaveOr OldHasGen(Builder->HasGeneratedNode); + EvalObjCMessageExpr(Dst, ME, Pred, Builder->GetState(Pred)); } - - // Check if we raise an exception. For now treat these as sinks. Eventually - // we will want to handle exceptions properly. - SaveAndRestore OldSink(Builder->BuildSinks); - if (RaisesException) - Builder->BuildSinks = true; - - // Dispatch to plug-in transfer function. - SaveOr OldHasGen(Builder->HasGeneratedNode); - EvalObjCMessageExpr(Dst, ME, Pred); } // Handle the case where no nodes where generated. Auto-generate that @@ -2052,10 +1965,12 @@ void GRExprEngine::VisitCompoundLiteralExpr(CompoundLiteralExpr* CL, for (ExplodedNodeSet::iterator I = Tmp.begin(), EI = Tmp.end(); I!=EI; ++I) { const GRState* state = GetState(*I); SVal ILV = state->getSVal(ILE); - state = state->bindCompoundLiteral(CL, ILV); + const LocationContext *LC = (*I)->getLocationContext(); + state = state->bindCompoundLiteral(CL, LC, ILV); - if (asLValue) - MakeNode(Dst, CL, *I, state->BindExpr(CL, state->getLValue(CL))); + if (asLValue) { + MakeNode(Dst, CL, *I, state->BindExpr(CL, state->getLValue(CL, LC))); + } else MakeNode(Dst, CL, *I, state->BindExpr(CL, ILV)); } diff --git a/lib/Analysis/GRExprEngineInternalChecks.h b/lib/Analysis/GRExprEngineInternalChecks.h index 5b7a7572ed7d..e2354ed09888 100644 --- a/lib/Analysis/GRExprEngineInternalChecks.h +++ b/lib/Analysis/GRExprEngineInternalChecks.h @@ -37,5 +37,8 @@ void RegisterUndefinedAssignmentChecker(GRExprEngine &Eng); void RegisterUndefBranchChecker(GRExprEngine &Eng); void RegisterUndefResultChecker(GRExprEngine &Eng); +void RegisterNoReturnFunctionChecker(GRExprEngine &Eng); +void RegisterBuiltinFunctionChecker(GRExprEngine &Eng); +void RegisterOSAtomicChecker(GRExprEngine &Eng); } // end clang namespace #endif diff --git a/lib/Analysis/GRState.cpp b/lib/Analysis/GRState.cpp index a56859dde5bf..7415fa5f67e4 100644 --- a/lib/Analysis/GRState.cpp +++ b/lib/Analysis/GRState.cpp @@ -312,10 +312,10 @@ bool GRState::scanReachableSymbols(const SVal *I, const SVal *E, SymbolVisitor &visitor) const { ScanReachableSymbols S(this, visitor); for ( ; I != E; ++I) { - if (S.scan(*I)) - return true; + if (!S.scan(*I)) + return false; } - return false; + return true; } bool GRState::scanReachableSymbols(const MemRegion * const *I, @@ -323,10 +323,10 @@ bool GRState::scanReachableSymbols(const MemRegion * const *I, SymbolVisitor &visitor) const { ScanReachableSymbols S(this, visitor); for ( ; I != E; ++I) { - if (S.scan(*I)) - return true; + if (!S.scan(*I)) + return false; } - return false; + return true; } //===----------------------------------------------------------------------===// diff --git a/lib/Analysis/MallocChecker.cpp b/lib/Analysis/MallocChecker.cpp index 204c7b320e65..2ed070a170cd 100644 --- a/lib/Analysis/MallocChecker.cpp +++ b/lib/Analysis/MallocChecker.cpp @@ -22,10 +22,11 @@ using namespace clang; namespace { -struct RefState { +class RefState { enum Kind { Allocated, Released, Escaped } K; const Stmt *S; +public: RefState(Kind k, const Stmt *s) : K(k), S(s) {} bool isAllocated() const { return K == Allocated; } @@ -51,19 +52,25 @@ class RegionState {}; class MallocChecker : public CheckerVisitor { BuiltinBug *BT_DoubleFree; BuiltinBug *BT_Leak; - IdentifierInfo *II_malloc; - IdentifierInfo *II_free; + IdentifierInfo *II_malloc, *II_free, *II_realloc; public: - MallocChecker() : BT_DoubleFree(0), BT_Leak(0), II_malloc(0), II_free(0) {} + MallocChecker() + : BT_DoubleFree(0), BT_Leak(0), II_malloc(0), II_free(0), II_realloc(0) {} static void *getTag(); - void PostVisitCallExpr(CheckerContext &C, const CallExpr *CE); + bool EvalCallExpr(CheckerContext &C, const CallExpr *CE); void EvalDeadSymbols(CheckerContext &C,const Stmt *S,SymbolReaper &SymReaper); void EvalEndPath(GREndPathNodeBuilder &B, void *tag, GRExprEngine &Eng); void PreVisitReturnStmt(CheckerContext &C, const ReturnStmt *S); private: void MallocMem(CheckerContext &C, const CallExpr *CE); + const GRState *MallocMemAux(CheckerContext &C, const CallExpr *CE, + const GRState *state); void FreeMem(CheckerContext &C, const CallExpr *CE); + const GRState *FreeMemAux(CheckerContext &C, const CallExpr *CE, + const GRState *state); + + void ReallocMem(CheckerContext &C, const CallExpr *CE); }; } // end anonymous namespace @@ -84,39 +91,71 @@ void *MallocChecker::getTag() { return &x; } -void MallocChecker::PostVisitCallExpr(CheckerContext &C, const CallExpr *CE) { - const FunctionDecl *FD = CE->getDirectCallee(); +bool MallocChecker::EvalCallExpr(CheckerContext &C, const CallExpr *CE) { + const GRState *state = C.getState(); + const Expr *Callee = CE->getCallee(); + SVal L = state->getSVal(Callee); + + const FunctionDecl *FD = L.getAsFunctionDecl(); if (!FD) - return; + return false; ASTContext &Ctx = C.getASTContext(); if (!II_malloc) II_malloc = &Ctx.Idents.get("malloc"); if (!II_free) II_free = &Ctx.Idents.get("free"); + if (!II_realloc) + II_realloc = &Ctx.Idents.get("realloc"); if (FD->getIdentifier() == II_malloc) { MallocMem(C, CE); - return; + return true; } if (FD->getIdentifier() == II_free) { FreeMem(C, CE); - return; + return true; } + + if (FD->getIdentifier() == II_realloc) { + ReallocMem(C, CE); + return true; + } + + return false; } void MallocChecker::MallocMem(CheckerContext &C, const CallExpr *CE) { - const GRState *state = C.getState(); - SVal CallVal = state->getSVal(CE); - SymbolRef Sym = CallVal.getAsLocSymbol(); + const GRState *state = MallocMemAux(C, CE, C.getState()); + C.addTransition(state); +} + +const GRState *MallocChecker::MallocMemAux(CheckerContext &C, + const CallExpr *CE, + const GRState *state) { + unsigned Count = C.getNodeBuilder().getCurrentBlockCount(); + ValueManager &ValMgr = C.getValueManager(); + + SVal RetVal = ValMgr.getConjuredSymbolVal(NULL, CE, CE->getType(), Count); + + state = state->BindExpr(CE, RetVal); + + SymbolRef Sym = RetVal.getAsLocSymbol(); assert(Sym); // Set the symbol's state to Allocated. - C.addTransition(state->set(Sym, RefState::getAllocated(CE))); + return state->set(Sym, RefState::getAllocated(CE)); } void MallocChecker::FreeMem(CheckerContext &C, const CallExpr *CE) { - const GRState *state = C.getState(); + const GRState *state = FreeMemAux(C, CE, C.getState()); + + if (state) + C.addTransition(state); +} + +const GRState *MallocChecker::FreeMemAux(CheckerContext &C, const CallExpr *CE, + const GRState *state) { SVal ArgVal = state->getSVal(CE->getArg(0)); SymbolRef Sym = ArgVal.getAsLocSymbol(); assert(Sym); @@ -136,13 +175,59 @@ void MallocChecker::FreeMem(CheckerContext &C, const CallExpr *CE) { BT_DoubleFree->getDescription(), N); C.EmitReport(R); } - return; + return NULL; } // Normal free. - const GRState *FreedState - = state->set(Sym, RefState::getReleased(CE)); - C.addTransition(FreedState); + return state->set(Sym, RefState::getReleased(CE)); +} + +void MallocChecker::ReallocMem(CheckerContext &C, const CallExpr *CE) { + const GRState *state = C.getState(); + const Expr *Arg0 = CE->getArg(0); + DefinedOrUnknownSVal Arg0Val=cast(state->getSVal(Arg0)); + + ValueManager &ValMgr = C.getValueManager(); + SValuator &SVator = C.getSValuator(); + + DefinedOrUnknownSVal PtrEQ = SVator.EvalEQ(state, Arg0Val, ValMgr.makeNull()); + + // If the ptr is NULL, the call is equivalent to malloc(size). + if (const GRState *stateEqual = state->Assume(PtrEQ, true)) { + // Hack: set the NULL symbolic region to released to suppress false warning. + // In the future we should add more states for allocated regions, e.g., + // CheckedNull, CheckedNonNull. + + SymbolRef Sym = Arg0Val.getAsLocSymbol(); + if (Sym) + stateEqual = stateEqual->set(Sym, RefState::getReleased(CE)); + + const GRState *stateMalloc = MallocMemAux(C, CE, stateEqual); + C.addTransition(stateMalloc); + } + + if (const GRState *stateNotEqual = state->Assume(PtrEQ, false)) { + const Expr *Arg1 = CE->getArg(1); + DefinedOrUnknownSVal Arg1Val = + cast(stateNotEqual->getSVal(Arg1)); + DefinedOrUnknownSVal SizeZero = SVator.EvalEQ(stateNotEqual, Arg1Val, + ValMgr.makeIntValWithPtrWidth(0, false)); + + if (const GRState *stateSizeZero = stateNotEqual->Assume(SizeZero, true)) { + const GRState *stateFree = FreeMemAux(C, CE, stateSizeZero); + if (stateFree) + C.addTransition(stateFree->BindExpr(CE, UndefinedVal(), true)); + } + + if (const GRState *stateSizeNotZero=stateNotEqual->Assume(SizeZero,false)) { + 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); + C.addTransition(stateRealloc); + } + } + } } void MallocChecker::EvalDeadSymbols(CheckerContext &C, const Stmt *S, diff --git a/lib/Analysis/MemRegion.cpp b/lib/Analysis/MemRegion.cpp index af8bd16ee681..bc3a5b704552 100644 --- a/lib/Analysis/MemRegion.cpp +++ b/lib/Analysis/MemRegion.cpp @@ -21,6 +21,110 @@ using namespace clang; +//===----------------------------------------------------------------------===// +// MemRegion Construction. +//===----------------------------------------------------------------------===// + +template struct MemRegionManagerTrait; + +template +RegionTy* MemRegionManager::getRegion(const A1 a1) { + + const typename MemRegionManagerTrait::SuperRegionTy *superRegion = + MemRegionManagerTrait::getSuperRegion(*this, a1); + + llvm::FoldingSetNodeID ID; + RegionTy::ProfileRegion(ID, a1, superRegion); + void* InsertPos; + RegionTy* R = cast_or_null(Regions.FindNodeOrInsertPos(ID, + InsertPos)); + + if (!R) { + R = (RegionTy*) A.Allocate(); + new (R) RegionTy(a1, superRegion); + Regions.InsertNode(R, InsertPos); + } + + return R; +} + +template +RegionTy* MemRegionManager::getSubRegion(const A1 a1, + const MemRegion *superRegion) { + llvm::FoldingSetNodeID ID; + RegionTy::ProfileRegion(ID, a1, superRegion); + void* InsertPos; + RegionTy* R = cast_or_null(Regions.FindNodeOrInsertPos(ID, + InsertPos)); + + if (!R) { + R = (RegionTy*) A.Allocate(); + new (R) RegionTy(a1, superRegion); + Regions.InsertNode(R, InsertPos); + } + + return R; +} + +template +RegionTy* MemRegionManager::getRegion(const A1 a1, const A2 a2) { + + const typename MemRegionManagerTrait::SuperRegionTy *superRegion = + MemRegionManagerTrait::getSuperRegion(*this, a1, a2); + + llvm::FoldingSetNodeID ID; + RegionTy::ProfileRegion(ID, a1, a2, superRegion); + void* InsertPos; + RegionTy* R = cast_or_null(Regions.FindNodeOrInsertPos(ID, + InsertPos)); + + if (!R) { + R = (RegionTy*) A.Allocate(); + new (R) RegionTy(a1, a2, superRegion); + Regions.InsertNode(R, InsertPos); + } + + return R; +} + +template +RegionTy* MemRegionManager::getSubRegion(const A1 a1, const A2 a2, + const MemRegion *superRegion) { + + llvm::FoldingSetNodeID ID; + RegionTy::ProfileRegion(ID, a1, a2, superRegion); + void* InsertPos; + RegionTy* R = cast_or_null(Regions.FindNodeOrInsertPos(ID, + InsertPos)); + + if (!R) { + R = (RegionTy*) A.Allocate(); + new (R) RegionTy(a1, a2, superRegion); + Regions.InsertNode(R, InsertPos); + } + + return R; +} + +template +RegionTy* MemRegionManager::getSubRegion(const A1 a1, const A2 a2, const A3 a3, + const MemRegion *superRegion) { + + llvm::FoldingSetNodeID ID; + RegionTy::ProfileRegion(ID, a1, a2, a3, superRegion); + void* InsertPos; + RegionTy* R = cast_or_null(Regions.FindNodeOrInsertPos(ID, + InsertPos)); + + if (!R) { + R = (RegionTy*) A.Allocate(); + new (R) RegionTy(a1, a2, a3, superRegion); + Regions.InsertNode(R, InsertPos); + } + + return R; +} + //===----------------------------------------------------------------------===// // Object destruction. //===----------------------------------------------------------------------===// @@ -61,10 +165,24 @@ MemRegionManager* SubRegion::getMemRegionManager() const { } while (1); } +const StackFrameContext *VarRegion::getStackFrame() const { + const StackSpaceRegion *SSR = dyn_cast(getMemorySpace()); + return SSR ? SSR->getStackFrame() : NULL; +} + +//===----------------------------------------------------------------------===// +// FoldingSet profiling. +//===----------------------------------------------------------------------===// + void MemSpaceRegion::Profile(llvm::FoldingSetNodeID& ID) const { ID.AddInteger((unsigned)getKind()); } +void StackSpaceRegion::Profile(llvm::FoldingSetNodeID &ID) const { + ID.AddInteger((unsigned)getKind()); + ID.AddPointer(getStackFrame()); +} + void StringRegion::ProfileRegion(llvm::FoldingSetNodeID& ID, const StringLiteral* Str, const MemRegion* superRegion) { @@ -109,7 +227,7 @@ void DeclRegion::Profile(llvm::FoldingSetNodeID& ID) const { } void VarRegion::Profile(llvm::FoldingSetNodeID &ID) const { - VarRegion::ProfileRegion(ID, getDecl(), LC, superRegion); + VarRegion::ProfileRegion(ID, getDecl(), superRegion); } void SymbolicRegion::ProfileRegion(llvm::FoldingSetNodeID& ID, SymbolRef sym, @@ -148,27 +266,29 @@ void FunctionTextRegion::Profile(llvm::FoldingSetNodeID& ID) const { } void BlockTextRegion::ProfileRegion(llvm::FoldingSetNodeID& ID, - const BlockDecl *BD, CanQualType, - const MemRegion*) { + const BlockDecl *BD, CanQualType, + const AnalysisContext *AC, + const MemRegion*) { ID.AddInteger(MemRegion::BlockTextRegionKind); ID.AddPointer(BD); } void BlockTextRegion::Profile(llvm::FoldingSetNodeID& ID) const { - BlockTextRegion::ProfileRegion(ID, BD, locTy, superRegion); + BlockTextRegion::ProfileRegion(ID, BD, locTy, AC, superRegion); } void BlockDataRegion::ProfileRegion(llvm::FoldingSetNodeID& ID, const BlockTextRegion *BC, const LocationContext *LC, - const MemRegion *) { + const MemRegion *sReg) { ID.AddInteger(MemRegion::BlockDataRegionKind); ID.AddPointer(BC); ID.AddPointer(LC); + ID.AddPointer(sReg); } void BlockDataRegion::Profile(llvm::FoldingSetNodeID& ID) const { - BlockDataRegion::ProfileRegion(ID, BC, LC, NULL); + BlockDataRegion::ProfileRegion(ID, BC, LC, getSuperRegion()); } //===----------------------------------------------------------------------===// @@ -249,36 +369,58 @@ void RegionRawOffset::dumpToStream(llvm::raw_ostream& os) const { // MemRegionManager methods. //===----------------------------------------------------------------------===// -MemSpaceRegion* MemRegionManager::LazyAllocate(MemSpaceRegion*& region) { +template +const REG *MemRegionManager::LazyAllocate(REG*& region) { if (!region) { - region = (MemSpaceRegion*) A.Allocate(); - new (region) MemSpaceRegion(this); + region = (REG*) A.Allocate(); + new (region) REG(this); } return region; } -MemSpaceRegion* MemRegionManager::getStackRegion() { - return LazyAllocate(stack); +template +const REG *MemRegionManager::LazyAllocate(REG*& region, ARG a) { + if (!region) { + region = (REG*) A.Allocate(); + new (region) REG(this, a); + } + + return region; } -MemSpaceRegion* MemRegionManager::getStackArgumentsRegion() { - return LazyAllocate(stackArguments); +const StackLocalsSpaceRegion* +MemRegionManager::getStackLocalsRegion(const StackFrameContext *STC) { + assert(STC); + if (STC == cachedStackLocalsFrame) + return cachedStackLocalsRegion; + cachedStackLocalsFrame = STC; + return LazyAllocate(cachedStackLocalsRegion, STC); } -MemSpaceRegion* MemRegionManager::getGlobalsRegion() { +const StackArgumentsSpaceRegion * +MemRegionManager::getStackArgumentsRegion(const StackFrameContext *STC) { + assert(STC); + if (STC == cachedStackArgumentsFrame) + return cachedStackArgumentsRegion; + + cachedStackArgumentsFrame = STC; + return LazyAllocate(cachedStackArgumentsRegion, STC); +} + +const GlobalsSpaceRegion *MemRegionManager::getGlobalsRegion() { return LazyAllocate(globals); } -MemSpaceRegion* MemRegionManager::getHeapRegion() { +const HeapSpaceRegion *MemRegionManager::getHeapRegion() { return LazyAllocate(heap); } -MemSpaceRegion* MemRegionManager::getUnknownRegion() { +const MemSpaceRegion *MemRegionManager::getUnknownRegion() { return LazyAllocate(unknown); } -MemSpaceRegion* MemRegionManager::getCodeRegion() { +const MemSpaceRegion *MemRegionManager::getCodeRegion() { return LazyAllocate(code); } @@ -286,40 +428,79 @@ MemSpaceRegion* MemRegionManager::getCodeRegion() { // Constructing regions. //===----------------------------------------------------------------------===// -StringRegion* MemRegionManager::getStringRegion(const StringLiteral* Str) { - return getRegion(Str); +const StringRegion* MemRegionManager::getStringRegion(const StringLiteral* Str) { + return getSubRegion(Str, getGlobalsRegion()); } -VarRegion* MemRegionManager::getVarRegion(const VarDecl *D, - const LocationContext *LC) { +const VarRegion* MemRegionManager::getVarRegion(const VarDecl *D, + const LocationContext *LC) { + const MemRegion *sReg = 0; - // FIXME: Once we implement scope handling, we will need to properly lookup - // 'D' to the proper LocationContext. For now, just strip down to the - // StackFrame. - while (!isa(LC)) - LC = LC->getParent(); + if (D->hasLocalStorage()) { + // FIXME: Once we implement scope handling, we will need to properly lookup + // 'D' to the proper LocationContext. + const DeclContext *DC = D->getDeclContext(); + const StackFrameContext *STC = LC->getStackFrameForDeclContext(DC); - return getRegion(D, LC); -} - -BlockDataRegion *MemRegionManager::getBlockDataRegion(const BlockTextRegion *BC, - const LocationContext *LC) -{ - // FIXME: Once we implement scope handling, we will need to properly lookup - // 'D' to the proper LocationContext. For now, just strip down to the - // StackFrame. - while (!isa(LC)) - LC = LC->getParent(); + if (!STC) + sReg = getUnknownRegion(); + else { + sReg = isa(D) || isa(D) + ? static_cast(getStackArgumentsRegion(STC)) + : static_cast(getStackLocalsRegion(STC)); + } + } + else { + sReg = getGlobalsRegion(); + } - return getSubRegion(BC, LC, getStackRegion()); + return getSubRegion(D, sReg); } -CompoundLiteralRegion* -MemRegionManager::getCompoundLiteralRegion(const CompoundLiteralExpr* CL) { - return getRegion(CL); +const VarRegion *MemRegionManager::getVarRegion(const VarDecl *D, + const MemRegion *superR) { + return getSubRegion(D, superR); } -ElementRegion* +const BlockDataRegion * +MemRegionManager::getBlockDataRegion(const BlockTextRegion *BC, + const LocationContext *LC) { + const MemRegion *sReg = 0; + + if (LC) { + // FIXME: Once we implement scope handling, we want the parent region + // to be the scope. + const StackFrameContext *STC = LC->getCurrentStackFrame(); + assert(STC); + sReg = getStackLocalsRegion(STC); + } + else { + // We allow 'LC' to be NULL for cases where want BlockDataRegions + // without context-sensitivity. + sReg = getUnknownRegion(); + } + + return getSubRegion(BC, LC, sReg); +} + +const CompoundLiteralRegion* +MemRegionManager::getCompoundLiteralRegion(const CompoundLiteralExpr* CL, + const LocationContext *LC) { + + const MemRegion *sReg = 0; + + if (CL->isFileScope()) + sReg = getGlobalsRegion(); + else { + const StackFrameContext *STC = LC->getCurrentStackFrame(); + assert(STC); + sReg = getStackLocalsRegion(STC); + } + + return getSubRegion(CL, sReg); +} + +const ElementRegion* MemRegionManager::getElementRegion(QualType elementType, SVal Idx, const MemRegion* superRegion, ASTContext& Ctx){ @@ -342,41 +523,47 @@ MemRegionManager::getElementRegion(QualType elementType, SVal Idx, return R; } -FunctionTextRegion * +const FunctionTextRegion * MemRegionManager::getFunctionTextRegion(const FunctionDecl *FD) { - return getRegion(FD); + return getSubRegion(FD, getCodeRegion()); } -BlockTextRegion *MemRegionManager::getBlockTextRegion(const BlockDecl *BD, - CanQualType locTy) { - return getRegion(BD, locTy); +const BlockTextRegion * +MemRegionManager::getBlockTextRegion(const BlockDecl *BD, CanQualType locTy, + AnalysisContext *AC) { + return getSubRegion(BD, locTy, AC, getCodeRegion()); } /// getSymbolicRegion - Retrieve or create a "symbolic" memory region. -SymbolicRegion* MemRegionManager::getSymbolicRegion(SymbolRef sym) { - return getRegion(sym); +const SymbolicRegion *MemRegionManager::getSymbolicRegion(SymbolRef sym) { + return getSubRegion(sym, getUnknownRegion()); } -FieldRegion* MemRegionManager::getFieldRegion(const FieldDecl* d, - const MemRegion* superRegion) { +const FieldRegion * +MemRegionManager::getFieldRegion(const FieldDecl* d, + const MemRegion* superRegion){ return getSubRegion(d, superRegion); } -ObjCIvarRegion* +const ObjCIvarRegion* MemRegionManager::getObjCIvarRegion(const ObjCIvarDecl* d, const MemRegion* superRegion) { return getSubRegion(d, superRegion); } -ObjCObjectRegion* +const ObjCObjectRegion* MemRegionManager::getObjCObjectRegion(const ObjCInterfaceDecl* d, const MemRegion* superRegion) { return getSubRegion(d, superRegion); } -AllocaRegion* MemRegionManager::getAllocaRegion(const Expr* E, unsigned cnt) { - return getRegion(E, cnt); +const AllocaRegion* +MemRegionManager::getAllocaRegion(const Expr* E, unsigned cnt, + const LocationContext *LC) { + const StackFrameContext *STC = LC->getCurrentStackFrame(); + assert(STC); + return getSubRegion(E, cnt, getStackLocalsRegion(STC)); } const MemSpaceRegion *MemRegion::getMemorySpace() const { @@ -392,52 +579,30 @@ const MemSpaceRegion *MemRegion::getMemorySpace() const { } bool MemRegion::hasStackStorage() const { - if (const MemSpaceRegion *MS = getMemorySpace()) { - MemRegionManager *Mgr = getMemRegionManager(); - return MS == Mgr->getStackRegion() || MS == Mgr->getStackArgumentsRegion(); - } - - return false; + return isa(getMemorySpace()); } bool MemRegion::hasHeapStorage() const { - if (const MemSpaceRegion *MS = getMemorySpace()) - return MS == getMemRegionManager()->getHeapRegion(); - - return false; + return isa(getMemorySpace()); } bool MemRegion::hasHeapOrStackStorage() const { - if (const MemSpaceRegion *MS = getMemorySpace()) { - MemRegionManager *Mgr = getMemRegionManager(); - return MS == Mgr->getHeapRegion() - || MS == Mgr->getStackRegion() - || MS == Mgr->getStackArgumentsRegion(); - } - return false; + const MemSpaceRegion *MS = getMemorySpace(); + return isa(MS) || isa(MS); } bool MemRegion::hasGlobalsStorage() const { - if (const MemSpaceRegion *MS = getMemorySpace()) - return MS == getMemRegionManager()->getGlobalsRegion(); - - return false; + return isa(getMemorySpace()); } bool MemRegion::hasParametersStorage() const { - if (const MemSpaceRegion *MS = getMemorySpace()) - return MS == getMemRegionManager()->getStackArgumentsRegion(); - - return false; + return isa(getMemorySpace()); } bool MemRegion::hasGlobalsOrParametersStorage() const { - if (const MemSpaceRegion *MS = getMemorySpace()) { - MemRegionManager *Mgr = getMemRegionManager(); - return MS == Mgr->getGlobalsRegion() - || MS == Mgr->getStackArgumentsRegion(); - } - return false; + const MemSpaceRegion *MS = getMemorySpace(); + return isa(MS) || + isa(MS); } // getBaseRegion strips away all elements and fields, and get the base region @@ -543,7 +708,7 @@ void BlockDataRegion::LazyInitializeReferencedVars() { if (ReferencedVars) return; - AnalysisContext *AC = LC->getAnalysisContext(); + AnalysisContext *AC = getCodeRegion()->getAnalysisContext(); AnalysisContext::referenced_decls_iterator I, E; llvm::tie(I, E) = AC->getReferencedBlockVars(BC->getDecl()); @@ -558,10 +723,25 @@ void BlockDataRegion::LazyInitializeReferencedVars() { typedef BumpVector VarVec; VarVec *BV = (VarVec*) A.Allocate(); - new (BV) VarVec(BC, (E - I) / sizeof(*I)); + new (BV) VarVec(BC, E - I); - for ( ; I != E; ++I) - BV->push_back(MemMgr.getVarRegion(*I, LC), BC); + for ( ; I != E; ++I) { + const VarDecl *VD = *I; + const VarRegion *VR = 0; + + if (!VD->getAttr()) + VR = MemMgr.getVarRegion(VD, this); + else { + if (LC) + VR = MemMgr.getVarRegion(VD, LC); + else { + VR = MemMgr.getVarRegion(VD, MemMgr.getUnknownRegion()); + } + } + + assert(VR); + BV->push_back(VR, BC); + } ReferencedVars = BV; } @@ -573,7 +753,8 @@ BlockDataRegion::referenced_vars_begin() const { BumpVector *Vec = static_cast*>(ReferencedVars); - return Vec == (void*) 0x1 ? NULL : Vec->begin(); + return BlockDataRegion::referenced_vars_iterator(Vec == (void*) 0x1 ? + NULL : Vec->begin()); } BlockDataRegion::referenced_vars_iterator @@ -583,5 +764,6 @@ BlockDataRegion::referenced_vars_end() const { BumpVector *Vec = static_cast*>(ReferencedVars); - return Vec == (void*) 0x1 ? NULL : Vec->end(); + return BlockDataRegion::referenced_vars_iterator(Vec == (void*) 0x1 ? + NULL : Vec->end()); } diff --git a/lib/Analysis/NoReturnFunctionChecker.cpp b/lib/Analysis/NoReturnFunctionChecker.cpp new file mode 100644 index 000000000000..6806273d4b4b --- /dev/null +++ b/lib/Analysis/NoReturnFunctionChecker.cpp @@ -0,0 +1,80 @@ +//=== NoReturnFunctionChecker.cpp -------------------------------*- C++ -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// +// This defines NoReturnFunctionChecker, which evaluates functions that do not +// return to the caller. +// +//===----------------------------------------------------------------------===// + +#include "GRExprEngineInternalChecks.h" +#include "clang/Analysis/PathSensitive/Checker.h" +#include "llvm/ADT/StringSwitch.h" + +using namespace clang; + +namespace { + +class NoReturnFunctionChecker : public Checker { +public: + static void *getTag() { static int tag = 0; return &tag; } + virtual bool EvalCallExpr(CheckerContext &C, const CallExpr *CE); +}; + +} + +void clang::RegisterNoReturnFunctionChecker(GRExprEngine &Eng) { + Eng.registerCheck(new NoReturnFunctionChecker()); +} + +bool NoReturnFunctionChecker::EvalCallExpr(CheckerContext &C, + const CallExpr *CE) { + const GRState *state = C.getState(); + const Expr *Callee = CE->getCallee(); + SVal L = state->getSVal(Callee); + const FunctionDecl *FD = L.getAsFunctionDecl(); + if (!FD) + return false; + + bool BuildSinks = false; + + if (FD->getAttr() || FD->getAttr()) + BuildSinks = true; + else { + // HACK: Some functions are not marked noreturn, and don't return. + // Here are a few hardwired ones. If this takes too long, we can + // potentially cache these results. + using llvm::StringRef; + BuildSinks + = llvm::StringSwitch(StringRef(FD->getIdentifier()->getName())) + .Case("exit", true) + .Case("panic", true) + .Case("error", true) + .Case("Assert", true) + // FIXME: This is just a wrapper around throwing an exception. + // Eventually inter-procedural analysis should handle this easily. + .Case("ziperr", true) + .Case("assfail", true) + .Case("db_error", true) + .Case("__assert", true) + .Case("__assert_rtn", true) + .Case("__assert_fail", true) + .Case("dtrace_assfail", true) + .Case("yy_fatal_error", true) + .Case("_XCAssertionFailureHandler", true) + .Case("_DTAssertionFailureHandler", true) + .Case("_TSAssertionFailureHandler", true) + .Default(false); + } + + if (!BuildSinks) + return false; + + C.GenerateSink(CE); + return true; +} diff --git a/lib/Analysis/OSAtomicChecker.cpp b/lib/Analysis/OSAtomicChecker.cpp new file mode 100644 index 000000000000..5a893458830c --- /dev/null +++ b/lib/Analysis/OSAtomicChecker.cpp @@ -0,0 +1,196 @@ +//=== OSAtomicChecker.cpp - OSAtomic functions evaluator --------*- C++ -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// +// This checker evaluates OSAtomic functions. +// +//===----------------------------------------------------------------------===// + +#include "GRExprEngineInternalChecks.h" +#include "clang/Analysis/PathSensitive/Checker.h" +#include "clang/Basic/Builtins.h" +#include "llvm/ADT/StringSwitch.h" + +using namespace clang; + +namespace { + +class OSAtomicChecker : public Checker { +public: + static void *getTag() { static int tag = 0; return &tag; } + virtual bool EvalCallExpr(CheckerContext &C, const CallExpr *CE); + +private: + bool EvalOSAtomicCompareAndSwap(CheckerContext &C, const CallExpr *CE); +}; + +} + +void clang::RegisterOSAtomicChecker(GRExprEngine &Eng) { + Eng.registerCheck(new OSAtomicChecker()); +} + +bool OSAtomicChecker::EvalCallExpr(CheckerContext &C,const CallExpr *CE) { + const GRState *state = C.getState(); + const Expr *Callee = CE->getCallee(); + SVal L = state->getSVal(Callee); + + const FunctionDecl* FD = L.getAsFunctionDecl(); + if (!FD) + return false; + + const char *FName = FD->getNameAsCString(); + + // Check for compare and swap. + if (strncmp(FName, "OSAtomicCompareAndSwap", 22) == 0 || + strncmp(FName, "objc_atomicCompareAndSwap", 25) == 0) + return EvalOSAtomicCompareAndSwap(C, CE); + + // FIXME: Other atomics. + return false; +} + +bool OSAtomicChecker::EvalOSAtomicCompareAndSwap(CheckerContext &C, + const CallExpr *CE) { + // Not enough arguments to match OSAtomicCompareAndSwap? + if (CE->getNumArgs() != 3) + return false; + + ASTContext &Ctx = C.getASTContext(); + const Expr *oldValueExpr = CE->getArg(0); + QualType oldValueType = Ctx.getCanonicalType(oldValueExpr->getType()); + + const Expr *newValueExpr = CE->getArg(1); + QualType newValueType = Ctx.getCanonicalType(newValueExpr->getType()); + + // Do the types of 'oldValue' and 'newValue' match? + if (oldValueType != newValueType) + return false; + + const Expr *theValueExpr = CE->getArg(2); + const PointerType *theValueType=theValueExpr->getType()->getAs(); + + // theValueType not a pointer? + if (!theValueType) + return false; + + QualType theValueTypePointee = + Ctx.getCanonicalType(theValueType->getPointeeType()).getUnqualifiedType(); + + // The pointee must match newValueType and oldValueType. + if (theValueTypePointee != newValueType) + return false; + + static unsigned magic_load = 0; + static unsigned magic_store = 0; + + const void *OSAtomicLoadTag = &magic_load; + const void *OSAtomicStoreTag = &magic_store; + + // Load 'theValue'. + GRExprEngine &Engine = C.getEngine(); + const GRState *state = C.getState(); + ExplodedNodeSet Tmp; + SVal location = state->getSVal(theValueExpr); + // Here we should use the value type of the region as the load type. + QualType LoadTy; + if (const MemRegion *R = location.getAsRegion()) { + // We must be careful, as SymbolicRegions aren't typed. + const MemRegion *strippedR = R->StripCasts(); + // FIXME: This isn't quite the right solution. One test case in 'test/Analysis/NSString.m' + // is giving the wrong result. + const TypedRegion *typedR = + isa(strippedR) ? cast(R) : + dyn_cast(strippedR); + + if (typedR) { + LoadTy = typedR->getValueType(Ctx); + location = loc::MemRegionVal(typedR); + } + } + Engine.EvalLoad(Tmp, const_cast(theValueExpr), C.getPredecessor(), + state, location, OSAtomicLoadTag, LoadTy); + + if (Tmp.empty()) { + // If no nodes were generated, other checkers must generated sinks. But + // since the builder state was restored, we set it manually to prevent + // auto transition. + // FIXME: there should be a better approach. + C.getNodeBuilder().BuildSinks = true; + return true; + } + + for (ExplodedNodeSet::iterator I = Tmp.begin(), E = Tmp.end(); + I != E; ++I) { + + ExplodedNode *N = *I; + const GRState *stateLoad = N->getState(); + SVal theValueVal_untested = stateLoad->getSVal(theValueExpr); + SVal oldValueVal_untested = stateLoad->getSVal(oldValueExpr); + + // FIXME: Issue an error. + if (theValueVal_untested.isUndef() || oldValueVal_untested.isUndef()) { + return false; + } + + DefinedOrUnknownSVal theValueVal = + cast(theValueVal_untested); + DefinedOrUnknownSVal oldValueVal = + cast(oldValueVal_untested); + + SValuator &SVator = Engine.getSValuator(); + + // Perform the comparison. + DefinedOrUnknownSVal Cmp = SVator.EvalEQ(stateLoad,theValueVal,oldValueVal); + + const GRState *stateEqual = stateLoad->Assume(Cmp, true); + + // Were they equal? + if (stateEqual) { + // Perform the store. + ExplodedNodeSet TmpStore; + SVal val = stateEqual->getSVal(newValueExpr); + + // Handle implicit value casts. + if (const TypedRegion *R = + dyn_cast_or_null(location.getAsRegion())) { + llvm::tie(state, val) = SVator.EvalCast(val, state,R->getValueType(Ctx), + newValueExpr->getType()); + } + + Engine.EvalStore(TmpStore, NULL, const_cast(theValueExpr), N, + stateEqual, location, val, OSAtomicStoreTag); + + if (TmpStore.empty()) { + // If no nodes were generated, other checkers must generated sinks. But + // since the builder state was restored, we set it manually to prevent + // auto transition. + // FIXME: there should be a better approach. + C.getNodeBuilder().BuildSinks = true; + return true; + } + + // Now bind the result of the comparison. + for (ExplodedNodeSet::iterator I2 = TmpStore.begin(), + E2 = TmpStore.end(); I2 != E2; ++I2) { + ExplodedNode *predNew = *I2; + const GRState *stateNew = predNew->getState(); + SVal Res = Engine.getValueManager().makeTruthVal(true, CE->getType()); + C.GenerateNode(stateNew->BindExpr(CE, Res), predNew); + } + } + + // Were they not equal? + if (const GRState *stateNotEqual = stateLoad->Assume(Cmp, false)) { + SVal Res = Engine.getValueManager().makeTruthVal(false, CE->getType()); + C.GenerateNode(stateNotEqual->BindExpr(CE, Res), N); + } + } + + return true; +} diff --git a/lib/Analysis/PathDiagnostic.cpp b/lib/Analysis/PathDiagnostic.cpp index 800496a16142..734570a21e64 100644 --- a/lib/Analysis/PathDiagnostic.cpp +++ b/lib/Analysis/PathDiagnostic.cpp @@ -36,30 +36,16 @@ bool PathDiagnosticMacroPiece::containsEvent() const { return false; } -static size_t GetNumCharsToLastNonPeriod(const char *s) { - const char *start = s; - const char *lastNonPeriod = 0; - - for ( ; *s != '\0' ; ++s) - if (*s != '.') lastNonPeriod = s; - - if (!lastNonPeriod) - return 0; - - return (lastNonPeriod - start) + 1; +static llvm::StringRef StripTrailingDots(llvm::StringRef s) { + for (llvm::StringRef::size_type i = s.size(); i != 0; --i) + if (s[i - 1] != '.') + return s.substr(0, i); + return ""; } -static inline size_t GetNumCharsToLastNonPeriod(const std::string &s) { - return s.empty () ? 0 : GetNumCharsToLastNonPeriod(&s[0]); -} - -PathDiagnosticPiece::PathDiagnosticPiece(const std::string& s, +PathDiagnosticPiece::PathDiagnosticPiece(llvm::StringRef s, Kind k, DisplayHint hint) - : str(s, 0, GetNumCharsToLastNonPeriod(s)), kind(k), Hint(hint) {} - -PathDiagnosticPiece::PathDiagnosticPiece(const char* s, Kind k, - DisplayHint hint) - : str(s, GetNumCharsToLastNonPeriod(s)), kind(k), Hint(hint) {} + : str(StripTrailingDots(s)), kind(k), Hint(hint) {} PathDiagnosticPiece::PathDiagnosticPiece(Kind k, DisplayHint hint) : kind(k), Hint(hint) {} @@ -89,20 +75,12 @@ void PathDiagnostic::resetPath(bool deletePieces) { } -PathDiagnostic::PathDiagnostic(const char* bugtype, const char* desc, - const char* category) +PathDiagnostic::PathDiagnostic(llvm::StringRef bugtype, llvm::StringRef desc, + llvm::StringRef category) : Size(0), - BugType(bugtype, GetNumCharsToLastNonPeriod(bugtype)), - Desc(desc, GetNumCharsToLastNonPeriod(desc)), - Category(category, GetNumCharsToLastNonPeriod(category)) {} - -PathDiagnostic::PathDiagnostic(const std::string& bugtype, - const std::string& desc, - const std::string& category) - : Size(0), - BugType(bugtype, 0, GetNumCharsToLastNonPeriod(bugtype)), - Desc(desc, 0, GetNumCharsToLastNonPeriod(desc)), - Category(category, 0, GetNumCharsToLastNonPeriod(category)) {} + BugType(StripTrailingDots(bugtype)), + Desc(StripTrailingDots(desc)), + Category(StripTrailingDots(category)) {} void PathDiagnosticClient::HandleDiagnostic(Diagnostic::Level DiagLevel, const DiagnosticInfo &Info) { @@ -126,8 +104,7 @@ void PathDiagnosticClient::HandleDiagnostic(Diagnostic::Level DiagLevel, Info.FormatDiagnostic(StrC); PathDiagnosticPiece *P = - new PathDiagnosticEventPiece(Info.getLocation(), - std::string(StrC.begin(), StrC.end())); + new PathDiagnosticEventPiece(Info.getLocation(), StrC.str()); for (unsigned i = 0, e = Info.getNumRanges(); i != e; ++i) P->addRange(Info.getRange(i)); diff --git a/lib/Analysis/RegionStore.cpp b/lib/Analysis/RegionStore.cpp index e645172a5b66..b5eeb1ea1170 100644 --- a/lib/Analysis/RegionStore.cpp +++ b/lib/Analysis/RegionStore.cpp @@ -269,7 +269,15 @@ class RegionStoreManager : public StoreManager { const GRState *InvalidateRegion(const GRState *state, const MemRegion *R, const Expr *E, unsigned Count, - InvalidatedSymbols *IS); + InvalidatedSymbols *IS) { + return RegionStoreManager::InvalidateRegions(state, &R, &R+1, E, Count, IS); + } + + const GRState *InvalidateRegions(const GRState *state, + const MemRegion * const *Begin, + const MemRegion * const *End, + const Expr *E, unsigned Count, + InvalidatedSymbols *IS); private: void RemoveSubRegionBindings(RegionBindings &B, const MemRegion *R, @@ -279,7 +287,9 @@ class RegionStoreManager : public StoreManager { const GRState *Bind(const GRState *state, Loc LV, SVal V); const GRState *BindCompoundLiteral(const GRState *state, - const CompoundLiteralExpr* CL, SVal V); + const CompoundLiteralExpr* CL, + const LocationContext *LC, + SVal V); const GRState *BindDecl(const GRState *ST, const VarRegion *VR, SVal InitVal); @@ -460,16 +470,14 @@ void RegionStoreManager::RemoveSubRegionBindings(RegionBindings &B, B = RBFactory.Remove(B, R); } -const GRState *RegionStoreManager::InvalidateRegion(const GRState *state, - const MemRegion *R, - const Expr *Ex, - unsigned Count, - InvalidatedSymbols *IS) { +const GRState *RegionStoreManager::InvalidateRegions(const GRState *state, + const MemRegion * const *I, + const MemRegion * const *E, + const Expr *Ex, + unsigned Count, + InvalidatedSymbols *IS) { ASTContext& Ctx = StateMgr.getContext(); - // Strip away casts. - R = R->StripCasts(); - // Get the mapping of regions -> subregions. llvm::OwningPtr SubRegions(getRegionStoreSubRegionMap(state->getStore())); @@ -478,10 +486,14 @@ const GRState *RegionStoreManager::InvalidateRegion(const GRState *state, llvm::DenseMap Visited; llvm::SmallVector WorkList; - WorkList.push_back(R); + + for ( ; I != E; ++I) { + // Strip away casts. + WorkList.push_back((*I)->StripCasts()); + } while (!WorkList.empty()) { - R = WorkList.back(); + const MemRegion *R = WorkList.back(); WorkList.pop_back(); // Have we visited this region before? @@ -512,6 +524,19 @@ const GRState *RegionStoreManager::InvalidateRegion(const GRState *state, if (const SymbolicRegion *SR = dyn_cast(R)) IS->insert(SR->getSymbol()); } + + // BlockDataRegion? If so, invalidate captured variables that are passed + // by reference. + if (const BlockDataRegion *BR = dyn_cast(R)) { + for (BlockDataRegion::referenced_vars_iterator + I = BR->referenced_vars_begin(), E = BR->referenced_vars_end() ; + I != E; ++I) { + const VarRegion *VR = *I; + if (VR->getDecl()->getAttr()) + WorkList.push_back(VR); + } + continue; + } // Handle the region itself. if (isa(R) || isa(R) || @@ -592,15 +617,6 @@ SVal RegionStoreManager::getLValueVar(const VarDecl *VD, return loc::MemRegionVal(MRMgr.getVarRegion(VD, LC)); } -/// getLValueCompoundLiteral - Returns an SVal representing the lvalue -/// of a compound literal. Within RegionStore a compound literal -/// has an associated region, and the lvalue of the compound literal -/// is the lvalue of that region. -SVal -RegionStoreManager::getLValueCompoundLiteral(const CompoundLiteralExpr* CL) { - return loc::MemRegionVal(MRMgr.getCompoundLiteralRegion(CL)); -} - SVal RegionStoreManager::getLValueIvar(const ObjCIvarDecl* D, SVal Base) { return getLValueFieldOrIvar(D, Base); } @@ -707,7 +723,12 @@ DefinedOrUnknownSVal RegionStoreManager::getSizeInElements(const GRState *state, const MemRegion *R) { switch (R->getKind()) { - case MemRegion::MemSpaceRegionKind: + case MemRegion::GenericMemSpaceRegionKind: + case MemRegion::StackLocalsSpaceRegionKind: + case MemRegion::StackArgumentsSpaceRegionKind: + case MemRegion::HeapSpaceRegionKind: + case MemRegion::GlobalsSpaceRegionKind: + case MemRegion::UnknownSpaceRegionKind: assert(0 && "Cannot index into a MemSpace"); return UnknownVal(); @@ -752,13 +773,6 @@ DefinedOrUnknownSVal RegionStoreManager::getSizeInElements(const GRState *state, // essentially are arrays of size 1. return ValMgr.makeIntVal(1, false); } - - case MemRegion::BEG_DECL_REGIONS: - case MemRegion::END_DECL_REGIONS: - case MemRegion::BEG_TYPED_REGIONS: - case MemRegion::END_TYPED_REGIONS: - assert(0 && "Infeasible region"); - return UnknownVal(); } assert(0 && "Unreachable"); @@ -797,9 +811,8 @@ SVal RegionStoreManager::ArrayToPointer(Loc Array) { T = AT->getElementType(); SVal ZeroIdx = ValMgr.makeZeroArrayIndex(); - ElementRegion* ER = MRMgr.getElementRegion(T, ZeroIdx, ArrayR, getContext()); - - return loc::MemRegionVal(ER); + return loc::MemRegionVal(MRMgr.getElementRegion(T, ZeroIdx, ArrayR, + getContext())); } //===----------------------------------------------------------------------===// @@ -864,16 +877,14 @@ SVal RegionStoreManager::EvalBinOp(const GRState *state, // Technically this can happen if people do funny things with casts. return UnknownVal(); - case MemRegion::MemSpaceRegionKind: + case MemRegion::GenericMemSpaceRegionKind: + case MemRegion::StackLocalsSpaceRegionKind: + case MemRegion::StackArgumentsSpaceRegionKind: + case MemRegion::HeapSpaceRegionKind: + case MemRegion::GlobalsSpaceRegionKind: + case MemRegion::UnknownSpaceRegionKind: assert(0 && "Cannot perform pointer arithmetic on a MemSpace"); return UnknownVal(); - - case MemRegion::BEG_DECL_REGIONS: - case MemRegion::END_DECL_REGIONS: - case MemRegion::BEG_TYPED_REGIONS: - case MemRegion::END_TYPED_REGIONS: - assert(0 && "Infeasible region"); - return UnknownVal(); } SVal Idx = ER->getIndex(); @@ -1283,7 +1294,8 @@ SVal RegionStoreManager::RetrieveVar(const GRState *state, // Lazily derive a value for the VarRegion. const VarDecl *VD = R->getDecl(); - if (R->hasGlobalsOrParametersStorage()) + if (R->hasGlobalsOrParametersStorage() || + isa(R->getMemorySpace())) return ValMgr.getRegionValueSymbolValOrUnknown(R, VD->getType()); return UndefinedVal(); @@ -1440,11 +1452,11 @@ const GRState *RegionStoreManager::BindDecl(const GRState *ST, // FIXME: this method should be merged into Bind(). const GRState * RegionStoreManager::BindCompoundLiteral(const GRState *state, - const CompoundLiteralExpr* CL, + const CompoundLiteralExpr *CL, + const LocationContext *LC, SVal V) { - - CompoundLiteralRegion* R = MRMgr.getCompoundLiteralRegion(CL); - return Bind(state, loc::MemRegionVal(R), V); + return Bind(state, loc::MemRegionVal(MRMgr.getCompoundLiteralRegion(CL, LC)), + V); } const GRState *RegionStoreManager::setImplicitDefaultValue(const GRState *state, @@ -1497,8 +1509,8 @@ const GRState *RegionStoreManager::BindArray(const GRState *state, break; SVal Idx = ValMgr.makeArrayIndex(i); - ElementRegion* ER = MRMgr.getElementRegion(ElementTy, Idx, R, - getContext()); + const ElementRegion* ER = MRMgr.getElementRegion(ElementTy, Idx, R, + getContext()); SVal V = ValMgr.makeIntVal(str[j], sizeof(char)*8, true); state = Bind(state, loc::MemRegionVal(ER), V); @@ -1526,7 +1538,7 @@ const GRState *RegionStoreManager::BindArray(const GRState *state, break; SVal Idx = ValMgr.makeArrayIndex(i); - ElementRegion* ER = MRMgr.getElementRegion(ElementTy, Idx, R, getContext()); + const ElementRegion *ER = MRMgr.getElementRegion(ElementTy, Idx, R, getContext()); if (CAT->getElementType()->isStructureType()) state = BindStruct(state, ER, *VI); @@ -1677,7 +1689,7 @@ void RegionStoreManager::RemoveDeadBindings(GRState &state, Stmt* Loc, IntermediateVisited.insert(R); if (const VarRegion* VR = dyn_cast(R)) { - if (SymReaper.isLive(Loc, VR->getDecl())) + if (SymReaper.isLive(Loc, VR)) WorkList.push_back(std::make_pair(&state, VR)); continue; } @@ -1753,14 +1765,16 @@ void RegionStoreManager::RemoveDeadBindings(GRState &state, Stmt* Loc, if (const SymbolicRegion *SymR = dyn_cast(R)) SymReaper.markLive(SymR->getSymbol()); - // For BlockDataRegions, enqueue all VarRegions for that are referenced + // For BlockDataRegions, enqueue the VarRegions for variables marked + // with __block (passed-by-reference). // via BlockDeclRefExprs. if (const BlockDataRegion *BD = dyn_cast(R)) { for (BlockDataRegion::referenced_vars_iterator RI = BD->referenced_vars_begin(), RE = BD->referenced_vars_end(); - RI != RE; ++RI) - WorkList.push_back(std::make_pair(state_N, *RI)); - + RI != RE; ++RI) { + if ((*RI)->getDecl()->getAttr()) + WorkList.push_back(std::make_pair(state_N, *RI)); + } // No possible data bindings on a BlockDataRegion. Continue to the // next region in the worklist. continue; @@ -1846,8 +1860,7 @@ GRState const *RegionStoreManager::EnterStackFrame(GRState const *state, // Copy the arg expression value to the arg variables. for (; AI != AE; ++AI, ++PI) { SVal ArgVal = state->getSVal(*AI); - MemRegion *R = MRMgr.getVarRegion(*PI, frame); - state = Bind(state, ValMgr.makeLoc(R), ArgVal); + state = Bind(state, ValMgr.makeLoc(MRMgr.getVarRegion(*PI, frame)), ArgVal); } return state; diff --git a/lib/Analysis/Store.cpp b/lib/Analysis/Store.cpp index 2fd573c4764d..e6ff6e5af47f 100644 --- a/lib/Analysis/Store.cpp +++ b/lib/Analysis/Store.cpp @@ -77,11 +77,12 @@ const MemRegion *StoreManager::CastRegion(const MemRegion *R, QualType CastToTy) // Process region cast according to the kind of the region being cast. switch (R->getKind()) { - case MemRegion::BEG_TYPED_REGIONS: - case MemRegion::MemSpaceRegionKind: - case MemRegion::BEG_DECL_REGIONS: - case MemRegion::END_DECL_REGIONS: - case MemRegion::END_TYPED_REGIONS: { + case MemRegion::GenericMemSpaceRegionKind: + case MemRegion::StackLocalsSpaceRegionKind: + case MemRegion::StackArgumentsSpaceRegionKind: + case MemRegion::HeapSpaceRegionKind: + case MemRegion::UnknownSpaceRegionKind: + case MemRegion::GlobalsSpaceRegionKind: { assert(0 && "Invalid region cast"); break; } @@ -199,9 +200,33 @@ SVal StoreManager::CastRetrievedVal(SVal V, const TypedRegion *R, QualType castTy) { if (castTy.isNull()) return V; - + assert(ValMgr.getContext().hasSameUnqualifiedType(castTy, R->getValueType(ValMgr.getContext()))); return V; } +const GRState *StoreManager::InvalidateRegions(const GRState *state, + const MemRegion * const *I, + const MemRegion * const *End, + const Expr *E, + unsigned Count, + InvalidatedSymbols *IS) { + for ( ; I != End ; ++I) + state = InvalidateRegion(state, *I, E, Count, IS); + + return state; +} + +//===----------------------------------------------------------------------===// +// Common getLValueXXX methods. +//===----------------------------------------------------------------------===// + +/// getLValueCompoundLiteral - Returns an SVal representing the lvalue +/// of a compound literal. Within RegionStore a compound literal +/// has an associated region, and the lvalue of the compound literal +/// is the lvalue of that region. +SVal StoreManager::getLValueCompoundLiteral(const CompoundLiteralExpr* CL, + const LocationContext *LC) { + return loc::MemRegionVal(MRMgr.getCompoundLiteralRegion(CL, LC)); +} diff --git a/lib/Analysis/SymbolManager.cpp b/lib/Analysis/SymbolManager.cpp index 22e110192956..3fe36b064e3d 100644 --- a/lib/Analysis/SymbolManager.cpp +++ b/lib/Analysis/SymbolManager.cpp @@ -220,4 +220,9 @@ bool SymbolReaper::isLive(SymbolRef sym) { return isa(sym); } +bool SymbolReaper::isLive(const Stmt *Loc, const VarRegion *VR) const { + const StackFrameContext *SFC = VR->getStackFrame(); + return SFC == CurrentStackFrame ? Liveness.isLive(Loc, VR->getDecl()) : true; +} + SymbolVisitor::~SymbolVisitor() {} diff --git a/lib/Analysis/ValueManager.cpp b/lib/Analysis/ValueManager.cpp index 22a821149dbb..d09137330cb2 100644 --- a/lib/Analysis/ValueManager.cpp +++ b/lib/Analysis/ValueManager.cpp @@ -14,6 +14,7 @@ //===----------------------------------------------------------------------===// #include "clang/Analysis/PathSensitive/ValueManager.h" +#include "clang/Analysis/PathSensitive/AnalysisContext.h" using namespace clang; using namespace llvm; @@ -138,15 +139,15 @@ ValueManager::getDerivedRegionValueSymbolVal(SymbolRef parentSymbol, } DefinedSVal ValueManager::getFunctionPointer(const FunctionDecl* FD) { - CodeTextRegion *R = MemMgr.getFunctionTextRegion(FD); - return loc::MemRegionVal(R); + return loc::MemRegionVal(MemMgr.getFunctionTextRegion(FD)); } DefinedSVal ValueManager::getBlockPointer(const BlockDecl *D, CanQualType locTy, const LocationContext *LC) { - BlockTextRegion *BC = MemMgr.getBlockTextRegion(D, locTy); - BlockDataRegion *BD = MemMgr.getBlockDataRegion(BC, LC); + const BlockTextRegion *BC = + MemMgr.getBlockTextRegion(D, locTy, LC->getAnalysisContext()); + const BlockDataRegion *BD = MemMgr.getBlockDataRegion(BC, LC); return loc::MemRegionVal(BD); } diff --git a/lib/Basic/Diagnostic.cpp b/lib/Basic/Diagnostic.cpp index fbc731311653..8d0d81326db0 100644 --- a/lib/Basic/Diagnostic.cpp +++ b/lib/Basic/Diagnostic.cpp @@ -163,7 +163,7 @@ namespace clang { return DiagInfo[DiagID-DIAG_UPPER_LIMIT].first; } - unsigned getOrCreateDiagID(Diagnostic::Level L, const char *Message, + unsigned getOrCreateDiagID(Diagnostic::Level L, llvm::StringRef Message, Diagnostic &Diags) { DiagDesc D(L, Message); // Check to see if it already exists. @@ -210,7 +210,7 @@ Diagnostic::Diagnostic(DiagnosticClient *client) : Client(client) { ErrorOccurred = false; FatalErrorOccurred = false; NumDiagnostics = 0; - + NumErrors = 0; CustomDiagInfo = 0; CurDiagID = ~0U; @@ -246,7 +246,7 @@ bool Diagnostic::popMappings() { /// getCustomDiagID - Return an ID for a diagnostic with the specified message /// and level. If this is the first request for this diagnosic, it is /// registered and created, otherwise the existing ID is returned. -unsigned Diagnostic::getCustomDiagID(Level L, const char *Message) { +unsigned Diagnostic::getCustomDiagID(Level L, llvm::StringRef Message) { if (CustomDiagInfo == 0) CustomDiagInfo = new diag::CustomDiagInfo(); return CustomDiagInfo->getOrCreateDiagID(L, Message, *this); diff --git a/lib/Basic/FileManager.cpp b/lib/Basic/FileManager.cpp index ee4309de937b..434ff39e77ec 100644 --- a/lib/Basic/FileManager.cpp +++ b/lib/Basic/FileManager.cpp @@ -147,6 +147,12 @@ FileManager::FileManager() FileManager::~FileManager() { delete &UniqueDirs; delete &UniqueFiles; + for (llvm::SmallVectorImpl::iterator + V = VirtualFileEntries.begin(), + VEnd = VirtualFileEntries.end(); + V != VEnd; + ++V) + delete *V; } void FileManager::addStatCache(StatSysCallCache *statCache, bool AtBeginning) { @@ -184,6 +190,30 @@ void FileManager::removeStatCache(StatSysCallCache *statCache) { assert(false && "Stat cache not found for removal"); } +/// \brief Retrieve the directory that the given file name resides in. +static const DirectoryEntry *getDirectoryFromFile(FileManager &FileMgr, + const char *NameStart, + const char *NameEnd) { + // Figure out what directory it is in. If the string contains a / in it, + // strip off everything after it. + // FIXME: this logic should be in sys::Path. + const char *SlashPos = NameEnd-1; + while (SlashPos >= NameStart && !IS_DIR_SEPARATOR_CHAR(SlashPos[0])) + --SlashPos; + // Ignore duplicate //'s. + while (SlashPos > NameStart && IS_DIR_SEPARATOR_CHAR(SlashPos[-1])) + --SlashPos; + + if (SlashPos < NameStart) { + // Use the current directory if file has no path component. + const char *Name = "."; + return FileMgr.getDirectory(Name, Name+1); + } else if (SlashPos == NameEnd-1) + return 0; // If filename ends with a /, it's a directory. + else + return FileMgr.getDirectory(NameStart, SlashPos); +} + /// getDirectory - Lookup, cache, and verify the specified directory. This /// returns null if the directory doesn't exist. /// @@ -252,33 +282,16 @@ const FileEntry *FileManager::getFile(const char *NameStart, // By default, initialize it to invalid. NamedFileEnt.setValue(NON_EXISTENT_FILE); - // Figure out what directory it is in. If the string contains a / in it, - // strip off everything after it. - // FIXME: this logic should be in sys::Path. - const char *SlashPos = NameEnd-1; - while (SlashPos >= NameStart && !IS_DIR_SEPARATOR_CHAR(SlashPos[0])) - --SlashPos; - // Ignore duplicate //'s. - while (SlashPos > NameStart && IS_DIR_SEPARATOR_CHAR(SlashPos[-1])) - --SlashPos; - - const DirectoryEntry *DirInfo; - if (SlashPos < NameStart) { - // Use the current directory if file has no path component. - const char *Name = "."; - DirInfo = getDirectory(Name, Name+1); - } else if (SlashPos == NameEnd-1) - return 0; // If filename ends with a /, it's a directory. - else - DirInfo = getDirectory(NameStart, SlashPos); - - if (DirInfo == 0) // Directory doesn't exist, file can't exist. - return 0; // Get the null-terminated file name as stored as the key of the // FileEntries map. const char *InterndFileName = NamedFileEnt.getKeyData(); + const DirectoryEntry *DirInfo + = getDirectoryFromFile(*this, NameStart, NameEnd); + if (DirInfo == 0) // Directory doesn't exist, file can't exist. + return 0; + // FIXME: Use the directory info to prune this, before doing the stat syscall. // FIXME: This will reduce the # syscalls. @@ -312,6 +325,44 @@ const FileEntry *FileManager::getFile(const char *NameStart, return &UFE; } +const FileEntry * +FileManager::getVirtualFile(const llvm::StringRef &Filename, + off_t Size, time_t ModificationTime) { + const char *NameStart = Filename.begin(), *NameEnd = Filename.end(); + + ++NumFileLookups; + + // See if there is already an entry in the map. + llvm::StringMapEntry &NamedFileEnt = + FileEntries.GetOrCreateValue(NameStart, NameEnd); + + // See if there is already an entry in the map. + if (NamedFileEnt.getValue()) + return NamedFileEnt.getValue() == NON_EXISTENT_FILE + ? 0 : NamedFileEnt.getValue(); + + ++NumFileCacheMisses; + + // By default, initialize it to invalid. + NamedFileEnt.setValue(NON_EXISTENT_FILE); + + const DirectoryEntry *DirInfo + = getDirectoryFromFile(*this, NameStart, NameEnd); + if (DirInfo == 0) // Directory doesn't exist, file can't exist. + return 0; + + FileEntry *UFE = new FileEntry(); + VirtualFileEntries.push_back(UFE); + NamedFileEnt.setValue(UFE); + + UFE->Name = NamedFileEnt.getKeyData(); + UFE->Size = Size; + UFE->ModTime = ModificationTime; + UFE->Dir = DirInfo; + UFE->UID = NextFileUID++; + return UFE; +} + void FileManager::PrintStats() const { llvm::errs() << "\n*** File Manager Stats:\n"; llvm::errs() << UniqueFiles.size() << " files found, " @@ -327,17 +378,16 @@ void FileManager::PrintStats() const { int MemorizeStatCalls::stat(const char *path, struct stat *buf) { int result = StatSysCallCache::stat(path, buf); - if (result != 0) { - // Cache failed 'stat' results. - struct stat empty; - memset(&empty, 0, sizeof(empty)); - StatCalls[path] = StatResult(result, empty); - } - else if (!S_ISDIR(buf->st_mode) || llvm::sys::Path(path).isAbsolute()) { - // Cache file 'stat' results and directories with absolutely - // paths. + // Do not cache failed stats, it is easy to construct common inconsistent + // situations if we do, and they are not important for PCH performance (which + // currently only needs the stats to construct the initial FileManager + // entries). + if (result != 0) + return result; + + // Cache file 'stat' results and directories with absolutely paths. + if (!S_ISDIR(buf->st_mode) || llvm::sys::Path(path).isAbsolute()) StatCalls[path] = StatResult(result, *buf); - } return result; } diff --git a/lib/Basic/SourceManager.cpp b/lib/Basic/SourceManager.cpp index a85bef0f29ed..354bf7befbb3 100644 --- a/lib/Basic/SourceManager.cpp +++ b/lib/Basic/SourceManager.cpp @@ -41,64 +41,42 @@ unsigned ContentCache::getSizeBytesMapped() const { /// getSize - Returns the size of the content encapsulated by this ContentCache. /// This can be the size of the source file or the size of an arbitrary /// scratch buffer. If the ContentCache encapsulates a source file, that -/// file is not lazily brought in from disk to satisfy this query unless it -/// needs to be truncated due to a truncateAt() call. +/// file is not lazily brought in from disk to satisfy this query. unsigned ContentCache::getSize() const { return Buffer ? Buffer->getBufferSize() : Entry->getSize(); } -const llvm::MemoryBuffer *ContentCache::getBuffer() const { - // Lazily create the Buffer for ContentCaches that wrap files. - if (!Buffer && Entry) { - // FIXME: Should we support a way to not have to do this check over - // and over if we cannot open the file? - Buffer = MemoryBuffer::getFile(Entry->getName(), 0, Entry->getSize()); - if (isTruncated()) - const_cast(this)->truncateAt(TruncateAtLine, - TruncateAtColumn); - } - return Buffer; +void ContentCache::replaceBuffer(const llvm::MemoryBuffer *B) { + assert(B != Buffer); + + delete Buffer; + Buffer = B; } -void ContentCache::truncateAt(unsigned Line, unsigned Column) { - TruncateAtLine = Line; - TruncateAtColumn = Column; - - if (!isTruncated() || !Buffer) - return; - - // Find the byte position of the truncation point. - const char *Position = Buffer->getBufferStart(); - for (unsigned Line = 1; Line < TruncateAtLine; ++Line) { - for (; *Position; ++Position) { - if (*Position != '\r' && *Position != '\n') - continue; - - // Eat \r\n or \n\r as a single line. - if ((Position[1] == '\r' || Position[1] == '\n') && - Position[0] != Position[1]) - ++Position; - ++Position; - break; +const llvm::MemoryBuffer *ContentCache::getBuffer(std::string *ErrorStr) const { + // Lazily create the Buffer for ContentCaches that wrap files. + if (!Buffer && Entry) { + Buffer = MemoryBuffer::getFile(Entry->getName(), ErrorStr,Entry->getSize()); + + // If we were unable to open the file, then we are in an inconsistent + // situation where the content cache referenced a file which no longer + // exists. Most likely, we were using a stat cache with an invalid entry but + // the file could also have been removed during processing. Since we can't + // really deal with this situation, just create an empty buffer. + // + // FIXME: This is definitely not ideal, but our immediate clients can't + // currently handle returning a null entry here. Ideally we should detect + // that we are in an inconsistent situation and error out as quickly as + // possible. + if (!Buffer) { + const llvm::StringRef FillStr("<<>>\n"); + Buffer = MemoryBuffer::getNewMemBuffer(Entry->getSize(), ""); + char *Ptr = const_cast(Buffer->getBufferStart()); + for (unsigned i = 0, e = Entry->getSize(); i != e; ++i) + Ptr[i] = FillStr[i % FillStr.size()]; } } - - for (unsigned Column = 1; Column < TruncateAtColumn; ++Column, ++Position) { - if (!*Position) - break; - - if (*Position == '\t') - Column += 7; - } - - // Truncate the buffer. - if (Position != Buffer->getBufferEnd()) { - MemoryBuffer *TruncatedBuffer - = MemoryBuffer::getMemBufferCopy(Buffer->getBufferStart(), Position, - Buffer->getBufferIdentifier()); - delete Buffer; - Buffer = TruncatedBuffer; - } + return Buffer; } unsigned LineTableInfo::getLineTableFilenameID(const char *Ptr, unsigned Len) { @@ -332,16 +310,6 @@ SourceManager::getOrCreateContentCache(const FileEntry *FileEnt) { EntryAlign = std::max(8U, EntryAlign); Entry = ContentCacheAlloc.Allocate(1, EntryAlign); new (Entry) ContentCache(FileEnt); - - if (FileEnt == TruncateFile) { - // If we had queued up a file truncation request, perform the truncation - // now. - Entry->truncateAt(TruncateAtLine, TruncateAtColumn); - TruncateFile = 0; - TruncateAtLine = 0; - TruncateAtColumn = 0; - } - return Entry; } @@ -413,8 +381,6 @@ FileID SourceManager::createFileID(const ContentCache *File, = SLocEntry::get(Offset, FileInfo::get(IncludePos, File, FileCharacter)); SLocEntryLoaded[PreallocatedID] = true; FileID FID = FileID::get(PreallocatedID); - if (File->FirstFID.isInvalid()) - File->FirstFID = FID; return LastFileIDLookup = FID; } @@ -428,8 +394,6 @@ FileID SourceManager::createFileID(const ContentCache *File, // Set LastFileIDLookup to the newly created file. The next getFileID call is // almost guaranteed to be from that file. FileID FID = FileID::get(SLocEntryTable.size()-1); - if (File->FirstFID.isInvalid()) - File->FirstFID = FID; return LastFileIDLookup = FID; } @@ -461,6 +425,25 @@ SourceLocation SourceManager::createInstantiationLoc(SourceLocation SpellingLoc, return SourceLocation::getMacroLoc(NextOffset-(TokLength+1)); } +const llvm::MemoryBuffer * +SourceManager::getMemoryBufferForFile(const FileEntry *File) { + const SrcMgr::ContentCache *IR = getOrCreateContentCache(File); + if (IR == 0) + return 0; + + return IR->getBuffer(); +} + +bool SourceManager::overrideFileContents(const FileEntry *SourceFile, + const llvm::MemoryBuffer *Buffer) { + const SrcMgr::ContentCache *IR = getOrCreateContentCache(SourceFile); + if (IR == 0) + return true; + + const_cast(IR)->replaceBuffer(Buffer); + return false; +} + /// getBufferData - Return a pointer to the start and end of the source buffer /// data for the specified FileID. std::pair @@ -1007,8 +990,33 @@ SourceLocation SourceManager::getLocation(const FileEntry *SourceFile, if (i < Col-1) return SourceLocation(); - return getLocForStartOfFile(Content->FirstFID). - getFileLocWithOffset(FilePos + Col - 1); + // Find the first file ID that corresponds to the given file. + FileID FirstFID; + + // First, check the main file ID, since it is common to look for a + // location in the main file. + if (!MainFileID.isInvalid()) { + const SLocEntry &MainSLoc = getSLocEntry(MainFileID); + if (MainSLoc.isFile() && MainSLoc.getFile().getContentCache() == Content) + FirstFID = MainFileID; + } + + if (FirstFID.isInvalid()) { + // The location we're looking for isn't in the main file; look + // through all of the source locations. + for (unsigned I = 0, N = sloc_entry_size(); I != N; ++I) { + const SLocEntry &SLoc = getSLocEntry(I); + if (SLoc.isFile() && SLoc.getFile().getContentCache() == Content) { + FirstFID = FileID::get(I); + break; + } + } + } + + if (FirstFID.isInvalid()) + return SourceLocation(); + + return getLocForStartOfFile(FirstFID).getFileLocWithOffset(FilePos + Col - 1); } /// \brief Determines the order of 2 source locations in the translation unit. @@ -1087,52 +1095,20 @@ bool SourceManager::isBeforeInTranslationUnit(SourceLocation LHS, return LastResForBeforeTUCheck = LOffs.second < I->second; } - // No common ancestor. - // Now we are getting into murky waters. Most probably this is because one - // location is in the predefines buffer. + // There is no common ancestor, most probably because one location is in the + // predefines buffer. + // + // FIXME: We should rearrange the external interface so this simply never + // happens; it can't conceptually happen. Also see PR5662. - const FileEntry *LEntry = - getSLocEntry(LOffs.first).getFile().getContentCache()->Entry; - const FileEntry *REntry = - getSLocEntry(ROffs.first).getFile().getContentCache()->Entry; + // If exactly one location is a memory buffer, assume it preceeds the other. + bool LIsMB = !getSLocEntry(LOffs.first).getFile().getContentCache()->Entry; + bool RIsMB = !getSLocEntry(ROffs.first).getFile().getContentCache()->Entry; + if (LIsMB != RIsMB) + return LastResForBeforeTUCheck = LIsMB; - // If the locations are in two memory buffers we give up, we can't answer - // which one should be considered first. - // FIXME: Should there be a way to "include" memory buffers in the translation - // unit ? - assert((LEntry != 0 || REntry != 0) && "Locations in memory buffers."); - (void) REntry; - - // Consider the memory buffer as coming before the file in the translation - // unit. - if (LEntry == 0) - return LastResForBeforeTUCheck = true; - else { - assert(REntry == 0 && "Locations in not #included files ?"); - return LastResForBeforeTUCheck = false; - } -} - -void SourceManager::truncateFileAt(const FileEntry *Entry, unsigned Line, - unsigned Column) { - llvm::DenseMap::iterator FI - = FileInfos.find(Entry); - if (FI != FileInfos.end()) { - FI->second->truncateAt(Line, Column); - return; - } - - // We cannot perform the truncation until we actually see the file, so - // save the truncation information. - assert(TruncateFile == 0 && "Can't queue up multiple file truncations!"); - TruncateFile = Entry; - TruncateAtLine = Line; - TruncateAtColumn = Column; -} - -/// \brief Determine whether this file was truncated. -bool SourceManager::isTruncatedFile(FileID FID) const { - return getSLocEntry(FID).getFile().getContentCache()->isTruncated(); + // Otherwise, just assume FileIDs were created in order. + return LastResForBeforeTUCheck = (LOffs.first < ROffs.first); } /// PrintStats - Print statistics to stderr. diff --git a/lib/CodeGen/CGBlocks.cpp b/lib/CodeGen/CGBlocks.cpp index 2df779ce9f52..9e44db0aa0a7 100644 --- a/lib/CodeGen/CGBlocks.cpp +++ b/lib/CodeGen/CGBlocks.cpp @@ -296,7 +296,7 @@ llvm::Value *CodeGenFunction::BuildBlockLiteralTmp(const BlockExpr *BE) { ++helpersize; continue; } else - E = new (getContext()) DeclRefExpr (cast(VD), + E = new (getContext()) DeclRefExpr (VD, VD->getType(), SourceLocation()); } @@ -1136,36 +1136,38 @@ BlockFunction::GeneratebyrefDestroyHelperFunction(const llvm::Type *T, } llvm::Constant *BlockFunction::BuildbyrefCopyHelper(const llvm::Type *T, - int flag, unsigned Align) { - // All alignments below that of pointer alignment collpase down to just + int Flag, unsigned Align) { + // All alignments below that of pointer alignment collapse down to just // pointer alignment, as we always have at least that much alignment to begin // with. Align /= unsigned(CGF.Target.getPointerAlign(0)/8); + // As an optimization, we only generate a single function of each kind we // might need. We need a different one for each alignment and for each // setting of flags. We mix Align and flag to get the kind. - uint64_t kind = (uint64_t)Align*BLOCK_BYREF_CURRENT_MAX + flag; - llvm::Constant *& Entry = CGM.AssignCache[kind]; + uint64_t Kind = (uint64_t)Align*BLOCK_BYREF_CURRENT_MAX + Flag; + llvm::Constant *&Entry = CGM.AssignCache[Kind]; if (Entry) return Entry; - return Entry=CodeGenFunction(CGM).GeneratebyrefCopyHelperFunction(T, flag); + return Entry = CodeGenFunction(CGM).GeneratebyrefCopyHelperFunction(T, Flag); } llvm::Constant *BlockFunction::BuildbyrefDestroyHelper(const llvm::Type *T, - int flag, + int Flag, unsigned Align) { // All alignments below that of pointer alignment collpase down to just // pointer alignment, as we always have at least that much alignment to begin // with. Align /= unsigned(CGF.Target.getPointerAlign(0)/8); + // As an optimization, we only generate a single function of each kind we // might need. We need a different one for each alignment and for each // setting of flags. We mix Align and flag to get the kind. - uint64_t kind = (uint64_t)Align*BLOCK_BYREF_CURRENT_MAX + flag; - llvm::Constant *& Entry = CGM.DestroyCache[kind]; + uint64_t Kind = (uint64_t)Align*BLOCK_BYREF_CURRENT_MAX + Flag; + llvm::Constant *&Entry = CGM.DestroyCache[Kind]; if (Entry) return Entry; - return Entry=CodeGenFunction(CGM).GeneratebyrefDestroyHelperFunction(T, flag); + return Entry=CodeGenFunction(CGM).GeneratebyrefDestroyHelperFunction(T, Flag); } llvm::Value *BlockFunction::getBlockObjectDispose() { diff --git a/lib/CodeGen/CGBuiltin.cpp b/lib/CodeGen/CGBuiltin.cpp index be4c27ce53ad..c70443245c76 100644 --- a/lib/CodeGen/CGBuiltin.cpp +++ b/lib/CodeGen/CGBuiltin.cpp @@ -204,7 +204,6 @@ RValue CodeGenFunction::EmitBuiltinExpr(const FunctionDecl *FD, return RValue::get(Builder.CreateCall(F, ArgValue, "tmp")); } case Builtin::BI__builtin_object_size: { -#if 1 // We pass this builtin onto the optimizer so that it can // figure out the object size in more complex cases. const llvm::Type *ResType[] = { @@ -214,15 +213,6 @@ RValue CodeGenFunction::EmitBuiltinExpr(const FunctionDecl *FD, return RValue::get(Builder.CreateCall2(F, EmitScalarExpr(E->getArg(0)), EmitScalarExpr(E->getArg(1)))); -#else - // FIXME: Remove after testing. - llvm::APSInt TypeArg = E->getArg(1)->EvaluateAsInt(CGM.getContext()); - const llvm::Type *ResType = ConvertType(E->getType()); - // bool UseSubObject = TypeArg.getZExtValue() & 1; - bool UseMinimum = TypeArg.getZExtValue() & 2; - return RValue::get( - llvm::ConstantInt::get(ResType, UseMinimum ? 0 : -1LL)); -#endif } case Builtin::BI__builtin_prefetch: { Value *Locality, *RW, *Address = EmitScalarExpr(E->getArg(0)); @@ -815,13 +805,44 @@ Value *CodeGenFunction::EmitX86BuiltinExpr(unsigned BuiltinID, Ops[0] = Builder.CreateBitCast(Ops[0], PtrTy); return Builder.CreateStore(Ops[1], Ops[0]); } - case X86::BI__builtin_ia32_palignr128: case X86::BI__builtin_ia32_palignr: { - Function *F = CGM.getIntrinsic(BuiltinID == X86::BI__builtin_ia32_palignr128 ? - Intrinsic::x86_ssse3_palign_r_128 : - Intrinsic::x86_ssse3_palign_r); + Function *F = CGM.getIntrinsic(Intrinsic::x86_ssse3_palign_r); return Builder.CreateCall(F, &Ops[0], &Ops[0] + Ops.size()); } + case X86::BI__builtin_ia32_palignr128: { + unsigned shiftVal = cast(Ops[2])->getZExtValue(); + + // If palignr is shifting the pair of input vectors less than 17 bytes, + // emit a shuffle instruction. + if (shiftVal <= 16) { + const llvm::Type *IntTy = llvm::Type::getInt32Ty(VMContext); + + llvm::SmallVector Indices; + for (unsigned i = 0; i != 16; ++i) + Indices.push_back(llvm::ConstantInt::get(IntTy, shiftVal + i)); + + Value* SV = llvm::ConstantVector::get(Indices.begin(), Indices.size()); + return Builder.CreateShuffleVector(Ops[1], Ops[0], SV, "palignr"); + } + + // If palignr is shifting the pair of input vectors more than 16 but less + // than 32 bytes, emit a logical right shift of the destination. + if (shiftVal < 32) { + const llvm::Type *EltTy = llvm::Type::getInt64Ty(VMContext); + const llvm::Type *VecTy = llvm::VectorType::get(EltTy, 2); + const llvm::Type *IntTy = llvm::Type::getInt32Ty(VMContext); + + Ops[0] = Builder.CreateBitCast(Ops[0], VecTy, "cast"); + Ops[1] = llvm::ConstantInt::get(IntTy, (shiftVal-16) * 8); + + // create i32 constant + llvm::Function *F = CGM.getIntrinsic(Intrinsic::x86_sse2_psrl_dq); + return Builder.CreateCall(F, &Ops[0], &Ops[0] + 2, "palignr"); + } + + // If palignr is shifting the pair of vectors more than 32 bytes, emit zero. + return llvm::Constant::getNullValue(ConvertType(E->getType())); + } } } diff --git a/lib/CodeGen/CGCXX.cpp b/lib/CodeGen/CGCXX.cpp index 34d1c8d984a1..0d11be22201c 100644 --- a/lib/CodeGen/CGCXX.cpp +++ b/lib/CodeGen/CGCXX.cpp @@ -26,168 +26,6 @@ using namespace clang; using namespace CodeGen; -void -CodeGenFunction::EmitCXXGlobalDtorRegistration(llvm::Constant *DtorFn, - llvm::Constant *DeclPtr) { - const llvm::Type *Int8PtrTy = - llvm::Type::getInt8Ty(VMContext)->getPointerTo(); - - std::vector Params; - Params.push_back(Int8PtrTy); - - // Get the destructor function type - const llvm::Type *DtorFnTy = - llvm::FunctionType::get(llvm::Type::getVoidTy(VMContext), Params, false); - DtorFnTy = llvm::PointerType::getUnqual(DtorFnTy); - - Params.clear(); - Params.push_back(DtorFnTy); - Params.push_back(Int8PtrTy); - Params.push_back(Int8PtrTy); - - // Get the __cxa_atexit function type - // extern "C" int __cxa_atexit ( void (*f)(void *), void *p, void *d ); - const llvm::FunctionType *AtExitFnTy = - llvm::FunctionType::get(ConvertType(getContext().IntTy), Params, false); - - llvm::Constant *AtExitFn = CGM.CreateRuntimeFunction(AtExitFnTy, - "__cxa_atexit"); - - llvm::Constant *Handle = CGM.CreateRuntimeVariable(Int8PtrTy, - "__dso_handle"); - llvm::Value *Args[3] = { llvm::ConstantExpr::getBitCast(DtorFn, DtorFnTy), - llvm::ConstantExpr::getBitCast(DeclPtr, Int8PtrTy), - llvm::ConstantExpr::getBitCast(Handle, Int8PtrTy) }; - Builder.CreateCall(AtExitFn, &Args[0], llvm::array_endof(Args)); -} - -void CodeGenFunction::EmitCXXGlobalVarDeclInit(const VarDecl &D, - llvm::Constant *DeclPtr) { - assert(D.hasGlobalStorage() && - "VarDecl must have global storage!"); - - const Expr *Init = D.getInit(); - QualType T = D.getType(); - bool isVolatile = getContext().getCanonicalType(T).isVolatileQualified(); - - if (T->isReferenceType()) { - ErrorUnsupported(Init, "global variable that binds to a reference"); - } else if (!hasAggregateLLVMType(T)) { - llvm::Value *V = EmitScalarExpr(Init); - EmitStoreOfScalar(V, DeclPtr, isVolatile, T); - } else if (T->isAnyComplexType()) { - EmitComplexExprIntoAddr(Init, DeclPtr, isVolatile); - } else { - EmitAggExpr(Init, DeclPtr, isVolatile); - // Avoid generating destructor(s) for initialized objects. - if (!isa(Init)) - return; - const ConstantArrayType *Array = getContext().getAsConstantArrayType(T); - if (Array) - T = getContext().getBaseElementType(Array); - - if (const RecordType *RT = T->getAs()) { - CXXRecordDecl *RD = cast(RT->getDecl()); - if (!RD->hasTrivialDestructor()) { - llvm::Constant *DtorFn; - if (Array) { - DtorFn = CodeGenFunction(CGM).GenerateCXXAggrDestructorHelper( - RD->getDestructor(getContext()), - Array, DeclPtr); - DeclPtr = - llvm::Constant::getNullValue(llvm::Type::getInt8PtrTy(VMContext)); - } - else - DtorFn = CGM.GetAddrOfCXXDestructor(RD->getDestructor(getContext()), - Dtor_Complete); - EmitCXXGlobalDtorRegistration(DtorFn, DeclPtr); - } - } - } -} - -void -CodeGenModule::EmitCXXGlobalInitFunc() { - if (CXXGlobalInits.empty()) - return; - - const llvm::FunctionType *FTy - = llvm::FunctionType::get(llvm::Type::getVoidTy(VMContext), - false); - - // Create our global initialization function. - // FIXME: Should this be tweakable by targets? - llvm::Function *Fn = - llvm::Function::Create(FTy, llvm::GlobalValue::InternalLinkage, - "__cxx_global_initialization", &TheModule); - - CodeGenFunction(*this).GenerateCXXGlobalInitFunc(Fn, - &CXXGlobalInits[0], - CXXGlobalInits.size()); - AddGlobalCtor(Fn); -} - -void CodeGenFunction::GenerateCXXGlobalInitFunc(llvm::Function *Fn, - const VarDecl **Decls, - unsigned NumDecls) { - StartFunction(GlobalDecl(), getContext().VoidTy, Fn, FunctionArgList(), - SourceLocation()); - - for (unsigned i = 0; i != NumDecls; ++i) { - const VarDecl *D = Decls[i]; - - llvm::Constant *DeclPtr = CGM.GetAddrOfGlobalVar(D); - EmitCXXGlobalVarDeclInit(*D, DeclPtr); - } - FinishFunction(); -} - -void -CodeGenFunction::EmitStaticCXXBlockVarDeclInit(const VarDecl &D, - llvm::GlobalVariable *GV) { - // FIXME: This should use __cxa_guard_{acquire,release}? - - assert(!getContext().getLangOptions().ThreadsafeStatics && - "thread safe statics are currently not supported!"); - - llvm::SmallString<256> GuardVName; - CGM.getMangleContext().mangleGuardVariable(&D, GuardVName); - - // Create the guard variable. - llvm::GlobalValue *GuardV = - new llvm::GlobalVariable(CGM.getModule(), llvm::Type::getInt64Ty(VMContext), - false, GV->getLinkage(), - llvm::Constant::getNullValue(llvm::Type::getInt64Ty(VMContext)), - GuardVName.str()); - - // Load the first byte of the guard variable. - const llvm::Type *PtrTy - = llvm::PointerType::get(llvm::Type::getInt8Ty(VMContext), 0); - llvm::Value *V = Builder.CreateLoad(Builder.CreateBitCast(GuardV, PtrTy), - "tmp"); - - // Compare it against 0. - llvm::Value *nullValue - = llvm::Constant::getNullValue(llvm::Type::getInt8Ty(VMContext)); - llvm::Value *ICmp = Builder.CreateICmpEQ(V, nullValue , "tobool"); - - llvm::BasicBlock *InitBlock = createBasicBlock("init"); - llvm::BasicBlock *EndBlock = createBasicBlock("init.end"); - - // If the guard variable is 0, jump to the initializer code. - Builder.CreateCondBr(ICmp, InitBlock, EndBlock); - - EmitBlock(InitBlock); - - EmitCXXGlobalVarDeclInit(D, GV); - - Builder.CreateStore(llvm::ConstantInt::get(llvm::Type::getInt8Ty(VMContext), - 1), - Builder.CreateBitCast(GuardV, PtrTy)); - - EmitBlock(EndBlock); -} - RValue CodeGenFunction::EmitCXXMemberCall(const CXXMethodDecl *MD, llvm::Value *Callee, llvm::Value *This, @@ -241,10 +79,10 @@ static bool canDevirtualizeMemberFunctionCalls(const Expr *Base) { } RValue CodeGenFunction::EmitCXXMemberCallExpr(const CXXMemberCallExpr *CE) { - if (isa(CE->getCallee())) + if (isa(CE->getCallee()->IgnoreParens())) return EmitCXXMemberPointerCallExpr(CE); - const MemberExpr *ME = cast(CE->getCallee()); + const MemberExpr *ME = cast(CE->getCallee()->IgnoreParens()); const CXXMethodDecl *MD = cast(ME->getMemberDecl()); if (MD->isStatic()) { @@ -307,7 +145,8 @@ RValue CodeGenFunction::EmitCXXMemberCallExpr(const CXXMemberCallExpr *CE) { RValue CodeGenFunction::EmitCXXMemberPointerCallExpr(const CXXMemberCallExpr *E) { - const BinaryOperator *BO = cast(E->getCallee()); + const BinaryOperator *BO = + cast(E->getCallee()->IgnoreParens()); const Expr *BaseExpr = BO->getLHS(); const Expr *MemFnExpr = BO->getRHS(); @@ -519,7 +358,7 @@ CodeGenFunction::EmitCXXAggrConstructorCall(const CXXConstructorDecl *D, // C++ [class.temporary]p4: // There are two contexts in which temporaries are destroyed at a different - // point than the end of the full- expression. The first context is when a + // point than the end of the full-expression. The first context is when a // default constructor is called to initialize an element of an array. // If the constructor has one or more default arguments, the destruction of // every temporary created in a default argument expression is sequenced @@ -558,8 +397,9 @@ CodeGenFunction::EmitCXXAggrDestructorCall(const CXXDestructorDecl *D, const ConstantArrayType *CA = dyn_cast(Array); assert(CA && "Do we support VLA for destruction ?"); uint64_t ElementCount = getContext().getConstantArrayElementCount(CA); - llvm::Value* ElementCountPtr = - llvm::ConstantInt::get(llvm::Type::getInt64Ty(VMContext), ElementCount); + + const llvm::Type *SizeLTy = ConvertType(getContext().getSizeType()); + llvm::Value* ElementCountPtr = llvm::ConstantInt::get(SizeLTy, ElementCount); EmitCXXAggrDestructorCall(D, ElementCountPtr, This); } @@ -569,13 +409,14 @@ void CodeGenFunction::EmitCXXAggrDestructorCall(const CXXDestructorDecl *D, llvm::Value *UpperCount, llvm::Value *This) { - llvm::Value *One = llvm::ConstantInt::get(llvm::Type::getInt64Ty(VMContext), - 1); + const llvm::Type *SizeLTy = ConvertType(getContext().getSizeType()); + llvm::Value *One = llvm::ConstantInt::get(SizeLTy, 1); + // Create a temporary for the loop index and initialize it with count of // array elements. - llvm::Value *IndexPtr = CreateTempAlloca(llvm::Type::getInt64Ty(VMContext), - "loop.index"); - // Index = ElementCount; + llvm::Value *IndexPtr = CreateTempAlloca(SizeLTy, "loop.index"); + + // Store the number of elements in the index pointer. Builder.CreateStore(UpperCount, IndexPtr); // Start the loop with a block that tests the condition. @@ -589,7 +430,7 @@ CodeGenFunction::EmitCXXAggrDestructorCall(const CXXDestructorDecl *D, // Generate: if (loop-index != 0 fall to the loop body, // otherwise, go to the block after the for-loop. llvm::Value* zeroConstant = - llvm::Constant::getNullValue(llvm::Type::getInt64Ty(VMContext)); + llvm::Constant::getNullValue(SizeLTy); llvm::Value *Counter = Builder.CreateLoad(IndexPtr); llvm::Value *IsNE = Builder.CreateICmpNE(Counter, zeroConstant, "isne"); @@ -626,7 +467,6 @@ llvm::Constant * CodeGenFunction::GenerateCXXAggrDestructorHelper(const CXXDestructorDecl *D, const ArrayType *Array, llvm::Value *This) { - static int UniqueCount; FunctionArgList Args; ImplicitParamDecl *Dst = ImplicitParamDecl::Create(getContext(), 0, @@ -635,16 +475,15 @@ CodeGenFunction::GenerateCXXAggrDestructorHelper(const CXXDestructorDecl *D, Args.push_back(std::make_pair(Dst, Dst->getType())); llvm::SmallString<16> Name; - llvm::raw_svector_ostream(Name) << "__tcf_" << (++UniqueCount); + llvm::raw_svector_ostream(Name) << "__tcf_" << (++UniqueAggrDestructorCount); QualType R = getContext().VoidTy; const CGFunctionInfo &FI = CGM.getTypes().getFunctionInfo(R, Args); const llvm::FunctionType *FTy = CGM.getTypes().GetFunctionType(FI, false); llvm::Function *Fn = llvm::Function::Create(FTy, llvm::GlobalValue::InternalLinkage, - Name.c_str(), + Name.str(), &CGM.getModule()); - IdentifierInfo *II - = &CGM.getContext().Idents.get(Name.c_str()); + IdentifierInfo *II = &CGM.getContext().Idents.get(Name.str()); FunctionDecl *FD = FunctionDecl::Create(getContext(), getContext().getTranslationUnitDecl(), SourceLocation(), II, R, 0, @@ -691,21 +530,29 @@ CodeGenFunction::EmitCXXConstructorCall(const CXXConstructorDecl *D, EmitCXXMemberCall(D, Callee, This, ArgBeg, ArgEnd); } -void CodeGenFunction::EmitCXXDestructorCall(const CXXDestructorDecl *D, +void CodeGenFunction::EmitCXXDestructorCall(const CXXDestructorDecl *DD, CXXDtorType Type, llvm::Value *This) { - if (D->isVirtual()) { - const llvm::Type *Ty = - CGM.getTypes().GetFunctionType(CGM.getTypes().getFunctionInfo(D), - /*isVariadic=*/false); - - llvm::Value *Callee = BuildVirtualCall(D, Dtor_Deleting, This, Ty); - EmitCXXMemberCall(D, Callee, This, 0, 0); - return; - } - llvm::Value *Callee = CGM.GetAddrOfCXXDestructor(D, Type); + llvm::Value *Callee = CGM.GetAddrOfCXXDestructor(DD, Type); + + CallArgList Args; - EmitCXXMemberCall(D, Callee, This, 0, 0); + // Push the this ptr. + Args.push_back(std::make_pair(RValue::get(This), + DD->getThisType(getContext()))); + + // Add a VTT parameter if necessary. + // FIXME: This should not be a dummy null parameter! + if (Type == Dtor_Base && DD->getParent()->getNumVBases() != 0) { + QualType T = getContext().getPointerType(getContext().VoidPtrTy); + + Args.push_back(std::make_pair(RValue::get(CGM.EmitNullConstant(T)), T)); + } + + // FIXME: We should try to share this code with EmitCXXMemberCall. + + QualType ResultType = DD->getType()->getAs()->getResultType(); + EmitCall(CGM.getTypes().getFunctionInfo(ResultType, Args), Callee, Args, DD); } void @@ -793,9 +640,9 @@ const char *CodeGenModule::getMangledCXXCtorName(const CXXConstructorDecl *D, void CodeGenModule::EmitCXXDestructors(const CXXDestructorDecl *D) { if (D->isVirtual()) - EmitGlobalDefinition(GlobalDecl(D, Dtor_Deleting)); - EmitGlobalDefinition(GlobalDecl(D, Dtor_Complete)); - EmitGlobalDefinition(GlobalDecl(D, Dtor_Base)); + EmitGlobal(GlobalDecl(D, Dtor_Deleting)); + EmitGlobal(GlobalDecl(D, Dtor_Complete)); + EmitGlobal(GlobalDecl(D, Dtor_Base)); } void CodeGenModule::EmitCXXDestructor(const CXXDestructorDecl *D, @@ -829,10 +676,10 @@ const char *CodeGenModule::getMangledCXXDtorName(const CXXDestructorDecl *D, } llvm::Constant * -CodeGenFunction::GenerateThunk(llvm::Function *Fn, const CXXMethodDecl *MD, +CodeGenFunction::GenerateThunk(llvm::Function *Fn, GlobalDecl GD, bool Extern, const ThunkAdjustment &ThisAdjustment) { - return GenerateCovariantThunk(Fn, MD, Extern, + return GenerateCovariantThunk(Fn, GD, Extern, CovariantThunkAdjustment(ThisAdjustment, ThunkAdjustment())); } @@ -875,8 +722,9 @@ CodeGenFunction::DynamicTypeAdjust(llvm::Value *V, llvm::Constant * CodeGenFunction::GenerateCovariantThunk(llvm::Function *Fn, - const CXXMethodDecl *MD, bool Extern, + GlobalDecl GD, bool Extern, const CovariantThunkAdjustment &Adjustment) { + const CXXMethodDecl *MD = cast(GD.getDecl()); QualType ResultType = MD->getType()->getAs()->getResultType(); FunctionArgList Args; @@ -906,7 +754,8 @@ CodeGenFunction::GenerateCovariantThunk(llvm::Function *Fn, const llvm::Type *Ty = CGM.getTypes().GetFunctionType(CGM.getTypes().getFunctionInfo(MD), FPT->isVariadic()); - llvm::Value *Callee = CGM.GetAddrOfFunction(MD, Ty); + llvm::Value *Callee = CGM.GetAddrOfFunction(GD, Ty); + CallArgList CallArgs; bool ShouldAdjustReturnPointer = true; @@ -922,7 +771,7 @@ CodeGenFunction::GenerateCovariantThunk(llvm::Function *Fn, CovariantThunkAdjustment(ThunkAdjustment(), Adjustment.ReturnAdjustment); - Callee = CGM.BuildCovariantThunk(MD, Extern, ReturnAdjustment); + Callee = CGM.BuildCovariantThunk(GD, Extern, ReturnAdjustment); Callee = Builder.CreateBitCast(Callee, OrigTy); ShouldAdjustReturnPointer = false; @@ -938,7 +787,8 @@ CodeGenFunction::GenerateCovariantThunk(llvm::Function *Fn, QualType ArgType = D->getType(); // llvm::Value *Arg = CGF.GetAddrOfLocalVar(Dst); - Expr *Arg = new (getContext()) DeclRefExpr(D, ArgType, SourceLocation()); + Expr *Arg = new (getContext()) DeclRefExpr(D, ArgType.getNonReferenceType(), + SourceLocation()); CallArgs.push_back(std::make_pair(EmitCallArg(Arg, ArgType), ArgType)); } @@ -983,11 +833,117 @@ CodeGenFunction::GenerateCovariantThunk(llvm::Function *Fn, } llvm::Constant * -CodeGenModule::BuildThunk(const CXXMethodDecl *MD, bool Extern, - const ThunkAdjustment &ThisAdjustment) { - +CodeGenModule::GetAddrOfThunk(GlobalDecl GD, + const ThunkAdjustment &ThisAdjustment) { + const CXXMethodDecl *MD = cast(GD.getDecl()); + + // Compute mangled name llvm::SmallString<256> OutName; - getMangleContext().mangleThunk(MD, ThisAdjustment, OutName); + if (const CXXDestructorDecl* DD = dyn_cast(MD)) + getMangleContext().mangleCXXDtorThunk(DD, GD.getDtorType(), ThisAdjustment, + OutName); + else + getMangleContext().mangleThunk(MD, ThisAdjustment, OutName); + OutName += '\0'; + const char* Name = UniqueMangledName(OutName.begin(), OutName.end()); + + // Get function for mangled name + const llvm::Type *Ty = getTypes().GetFunctionTypeForVtable(MD); + return GetOrCreateLLVMFunction(Name, Ty, GlobalDecl()); +} + +llvm::Constant * +CodeGenModule::GetAddrOfCovariantThunk(GlobalDecl GD, + const CovariantThunkAdjustment &Adjustment) { + const CXXMethodDecl *MD = cast(GD.getDecl()); + + // Compute mangled name + llvm::SmallString<256> OutName; + getMangleContext().mangleCovariantThunk(MD, Adjustment, OutName); + OutName += '\0'; + const char* Name = UniqueMangledName(OutName.begin(), OutName.end()); + + // Get function for mangled name + const llvm::Type *Ty = getTypes().GetFunctionTypeForVtable(MD); + return GetOrCreateLLVMFunction(Name, Ty, GlobalDecl()); +} + +void CodeGenModule::BuildThunksForVirtual(GlobalDecl GD) { + CGVtableInfo::AdjustmentVectorTy *AdjPtr = getVtableInfo().getAdjustments(GD); + if (!AdjPtr) + return; + CGVtableInfo::AdjustmentVectorTy &Adj = *AdjPtr; + const CXXMethodDecl *MD = cast(GD.getDecl()); + for (unsigned i = 0; i < Adj.size(); i++) { + GlobalDecl OGD = Adj[i].first; + const CXXMethodDecl *OMD = cast(OGD.getDecl()); + QualType nc_oret = OMD->getType()->getAs()->getResultType(); + CanQualType oret = getContext().getCanonicalType(nc_oret); + QualType nc_ret = MD->getType()->getAs()->getResultType(); + CanQualType ret = getContext().getCanonicalType(nc_ret); + ThunkAdjustment ReturnAdjustment; + if (oret != ret) { + QualType qD = nc_ret->getPointeeType(); + QualType qB = nc_oret->getPointeeType(); + CXXRecordDecl *D = cast(qD->getAs()->getDecl()); + CXXRecordDecl *B = cast(qB->getAs()->getDecl()); + ReturnAdjustment = ComputeThunkAdjustment(D, B); + } + ThunkAdjustment ThisAdjustment = Adj[i].second; + bool Extern = !cast(OMD->getDeclContext())->isInAnonymousNamespace(); + if (!ReturnAdjustment.isEmpty() || !ThisAdjustment.isEmpty()) { + CovariantThunkAdjustment CoAdj(ThisAdjustment, ReturnAdjustment); + llvm::Constant *FnConst; + if (!ReturnAdjustment.isEmpty()) + FnConst = GetAddrOfCovariantThunk(GD, CoAdj); + else + FnConst = GetAddrOfThunk(GD, ThisAdjustment); + if (!isa(FnConst)) { + llvm::Constant *SubExpr = + cast(FnConst)->getOperand(0); + llvm::Function *OldFn = cast(SubExpr); + std::string Name = OldFn->getNameStr(); + GlobalDeclMap.erase(UniqueMangledName(Name.data(), + Name.data() + Name.size() + 1)); + llvm::Constant *NewFnConst; + if (!ReturnAdjustment.isEmpty()) + NewFnConst = GetAddrOfCovariantThunk(GD, CoAdj); + else + NewFnConst = GetAddrOfThunk(GD, ThisAdjustment); + llvm::Function *NewFn = cast(NewFnConst); + NewFn->takeName(OldFn); + llvm::Constant *NewPtrForOldDecl = + llvm::ConstantExpr::getBitCast(NewFn, OldFn->getType()); + OldFn->replaceAllUsesWith(NewPtrForOldDecl); + OldFn->eraseFromParent(); + FnConst = NewFn; + } + llvm::Function *Fn = cast(FnConst); + if (Fn->isDeclaration()) { + llvm::GlobalVariable::LinkageTypes linktype; + linktype = llvm::GlobalValue::WeakAnyLinkage; + if (!Extern) + linktype = llvm::GlobalValue::InternalLinkage; + Fn->setLinkage(linktype); + if (!Features.Exceptions && !Features.ObjCNonFragileABI) + Fn->addFnAttr(llvm::Attribute::NoUnwind); + Fn->setAlignment(2); + CodeGenFunction(*this).GenerateCovariantThunk(Fn, GD, Extern, CoAdj); + } + } + } +} + +llvm::Constant * +CodeGenModule::BuildThunk(GlobalDecl GD, bool Extern, + const ThunkAdjustment &ThisAdjustment) { + const CXXMethodDecl *MD = cast(GD.getDecl()); + llvm::SmallString<256> OutName; + if (const CXXDestructorDecl *D = dyn_cast(MD)) { + getMangleContext().mangleCXXDtorThunk(D, GD.getDtorType(), ThisAdjustment, + OutName); + } else + getMangleContext().mangleThunk(MD, ThisAdjustment, OutName); llvm::GlobalVariable::LinkageTypes linktype; linktype = llvm::GlobalValue::WeakAnyLinkage; @@ -1001,14 +957,15 @@ CodeGenModule::BuildThunk(const CXXMethodDecl *MD, bool Extern, llvm::Function *Fn = llvm::Function::Create(FTy, linktype, OutName.str(), &getModule()); - CodeGenFunction(*this).GenerateThunk(Fn, MD, Extern, ThisAdjustment); + CodeGenFunction(*this).GenerateThunk(Fn, GD, Extern, ThisAdjustment); llvm::Constant *m = llvm::ConstantExpr::getBitCast(Fn, Ptr8Ty); return m; } llvm::Constant * -CodeGenModule::BuildCovariantThunk(const CXXMethodDecl *MD, bool Extern, +CodeGenModule::BuildCovariantThunk(const GlobalDecl &GD, bool Extern, const CovariantThunkAdjustment &Adjustment) { + const CXXMethodDecl *MD = cast(GD.getDecl()); llvm::SmallString<256> OutName; getMangleContext().mangleCovariantThunk(MD, Adjustment, OutName); llvm::GlobalVariable::LinkageTypes linktype; @@ -1453,6 +1410,8 @@ CodeGenFunction::SynthesizeCXXCopyConstructor(const CXXConstructorDecl *Ctor, EmitAggregateCopy(LHS.getAddress(), RHS.getAddress(), Field->getType()); } } + + InitializeVtablePtrs(ClassDecl); FinishFunction(); } @@ -1537,8 +1496,16 @@ void CodeGenFunction::SynthesizeCXXCopyAssignment(const CXXMethodDecl *CD, // Do a built-in assignment of scalar data members. LValue LHS = EmitLValueForField(LoadOfThis, *Field, false, 0); LValue RHS = EmitLValueForField(LoadOfSrc, *Field, false, 0); - RValue RVRHS = EmitLoadOfLValue(RHS, FieldType); - EmitStoreThroughLValue(RVRHS, LHS, FieldType); + if (!hasAggregateLLVMType(Field->getType())) { + RValue RVRHS = EmitLoadOfLValue(RHS, Field->getType()); + EmitStoreThroughLValue(RVRHS, LHS, Field->getType()); + } else if (Field->getType()->isAnyComplexType()) { + ComplexPairTy Pair = LoadComplexFromAddr(RHS.getAddress(), + RHS.isVolatileQualified()); + StoreComplexToAddr(Pair, LHS.getAddress(), LHS.isVolatileQualified()); + } else { + EmitAggregateCopy(LHS.getAddress(), RHS.getAddress(), Field->getType()); + } } // return *this; @@ -1666,8 +1633,7 @@ void CodeGenFunction::EmitCtorPrologue(const CXXConstructorDecl *CD, const CXXRecordDecl *ClassDecl = CD->getParent(); // FIXME: Add vbase initialization - llvm::Value *LoadOfThis = 0; - + for (CXXConstructorDecl::init_const_iterator B = CD->init_begin(), E = CD->init_end(); B != E; ++B) { @@ -1686,18 +1652,28 @@ void CodeGenFunction::EmitCtorPrologue(const CXXConstructorDecl *CD, PopCXXTemporary(); } - // Initialize the vtable pointer - if (ClassDecl->isDynamicClass()) { - if (!LoadOfThis) - LoadOfThis = LoadCXXThis(); - llvm::Value *VtableField; - llvm::Type *Ptr8Ty, *PtrPtr8Ty; - Ptr8Ty = llvm::PointerType::get(llvm::Type::getInt8Ty(VMContext), 0); - PtrPtr8Ty = llvm::PointerType::get(Ptr8Ty, 0); - VtableField = Builder.CreateBitCast(LoadOfThis, PtrPtr8Ty); - llvm::Value *vtable = CGM.getVtableInfo().getVtable(ClassDecl); - Builder.CreateStore(vtable, VtableField); - } + InitializeVtablePtrs(ClassDecl); +} + +void CodeGenFunction::InitializeVtablePtrs(const CXXRecordDecl *ClassDecl) { + if (!ClassDecl->isDynamicClass()) + return; + + // Initialize the vtable pointer. + // FIXME: This needs to initialize secondary vtable pointers too. + llvm::Value *ThisPtr = LoadCXXThis(); + + llvm::Constant *Vtable = CGM.getVtableInfo().getVtable(ClassDecl); + uint64_t AddressPoint = CGM.getVtableInfo().getVtableAddressPoint(ClassDecl); + + llvm::Value *VtableAddressPoint = + Builder.CreateConstInBoundsGEP2_64(Vtable, 0, AddressPoint); + + llvm::Value *VtableField = + Builder.CreateBitCast(ThisPtr, + VtableAddressPoint->getType()->getPointerTo()); + + Builder.CreateStore(VtableAddressPoint, VtableField); } /// EmitDtorEpilogue - Emit all code that comes at the end of class's @@ -1808,9 +1784,12 @@ void CodeGenFunction::EmitDtorEpilogue(const CXXDestructorDecl *DD, } // If we have a deleting destructor, emit a call to the delete operator. - if (DtorType == Dtor_Deleting) + if (DtorType == Dtor_Deleting) { + assert(DD->getOperatorDelete() && + "operator delete missing - EmitDtorEpilogue"); EmitDeleteCall(DD->getOperatorDelete(), LoadCXXThis(), getContext().getTagDeclType(ClassDecl)); + } } void CodeGenFunction::SynthesizeDefaultDestructor(const CXXDestructorDecl *Dtor, diff --git a/lib/CodeGen/CGCall.cpp b/lib/CodeGen/CGCall.cpp index decc73c6d458..4856f5404c1a 100644 --- a/lib/CodeGen/CGCall.cpp +++ b/lib/CodeGen/CGCall.cpp @@ -561,6 +561,9 @@ void CodeGenModule::ConstructAttributeList(const CGFunctionInfo &FI, const ABIArgInfo &AI = it->info; unsigned Attributes = 0; + if (ParamType.isRestrictQualified()) + Attributes |= llvm::Attribute::NoAlias; + switch (AI.getKind()) { case ABIArgInfo::Coerce: break; @@ -764,7 +767,7 @@ void CodeGenFunction::EmitFunctionEpilog(const CGFunctionInfo &FI, ComplexPairTy RT = LoadComplexFromAddr(ReturnValue, false); StoreComplexToAddr(RT, CurFn->arg_begin(), false); } else if (CodeGenFunction::hasAggregateLLVMType(RetTy)) { - EmitAggregateCopy(CurFn->arg_begin(), ReturnValue, RetTy); + // Do nothing; aggregrates get evaluated directly into the destination. } else { EmitStoreOfScalar(Builder.CreateLoad(ReturnValue), CurFn->arg_begin(), false, RetTy); diff --git a/lib/CodeGen/CGClass.cpp b/lib/CodeGen/CGClass.cpp index b3c2b986d190..fd2afe70e00e 100644 --- a/lib/CodeGen/CGClass.cpp +++ b/lib/CodeGen/CGClass.cpp @@ -112,6 +112,42 @@ static llvm::Value *GetCXXBaseClassOffset(CodeGenFunction &CGF, return NonVirtualOffset; } +// FIXME: This probably belongs in CGVtable, but it relies on +// the static function ComputeNonVirtualBaseClassOffset, so we should make that +// a CodeGenModule member function as well. +ThunkAdjustment +CodeGenModule::ComputeThunkAdjustment(const CXXRecordDecl *ClassDecl, + const CXXRecordDecl *BaseClassDecl) { + CXXBasePaths Paths(/*FindAmbiguities=*/false, + /*RecordPaths=*/true, /*DetectVirtual=*/false); + if (!const_cast(ClassDecl)-> + isDerivedFrom(const_cast(BaseClassDecl), Paths)) { + assert(false && "Class must be derived from the passed in base class!"); + return ThunkAdjustment(); + } + + unsigned Start = 0; + uint64_t VirtualOffset = 0; + + const CXXBasePath &Path = Paths.front(); + const CXXRecordDecl *VBase = 0; + for (unsigned i = 0, e = Path.size(); i != e; ++i) { + const CXXBasePathElement& Element = Path[i]; + if (Element.Base->isVirtual()) { + Start = i+1; + QualType VBaseType = Element.Base->getType(); + VBase = cast(VBaseType->getAs()->getDecl()); + } + } + if (VBase) + VirtualOffset = + getVtableInfo().getVirtualBaseOffsetIndex(ClassDecl, BaseClassDecl); + + uint64_t Offset = + ComputeNonVirtualBaseClassOffset(getContext(), Paths, Start); + return ThunkAdjustment(Offset, VirtualOffset); +} + llvm::Value * CodeGenFunction::GetAddressOfBaseClass(llvm::Value *Value, const CXXRecordDecl *ClassDecl, diff --git a/lib/CodeGen/CGDebugInfo.cpp b/lib/CodeGen/CGDebugInfo.cpp index 317da7e46a75..2238c89f8357 100644 --- a/lib/CodeGen/CGDebugInfo.cpp +++ b/lib/CodeGen/CGDebugInfo.cpp @@ -35,8 +35,8 @@ using namespace clang; using namespace clang::CodeGen; -CGDebugInfo::CGDebugInfo(CodeGenModule *m) - : M(m), isMainCompileUnitCreated(false), DebugFactory(M->getModule()), +CGDebugInfo::CGDebugInfo(CodeGenModule &CGM) + : CGM(CGM), isMainCompileUnitCreated(false), DebugFactory(CGM.getModule()), BlockLiteralGenericSet(false) { } @@ -46,7 +46,7 @@ CGDebugInfo::~CGDebugInfo() { void CGDebugInfo::setLocation(SourceLocation Loc) { if (Loc.isValid()) - CurLoc = M->getContext().getSourceManager().getInstantiationLoc(Loc); + CurLoc = CGM.getContext().getSourceManager().getInstantiationLoc(Loc); } /// getContext - Get context info for the decl. @@ -70,7 +70,7 @@ llvm::DIDescriptor CGDebugInfo::getContext(const VarDecl *Decl, llvm::DICompileUnit CGDebugInfo::getOrCreateCompileUnit(SourceLocation Loc) { // Get source file information. const char *FileName = ""; - SourceManager &SM = M->getContext().getSourceManager(); + SourceManager &SM = CGM.getContext().getSourceManager(); unsigned FID = 0; if (Loc.isValid()) { PresumedLoc PLoc = SM.getPresumedLoc(Loc); @@ -84,18 +84,14 @@ llvm::DICompileUnit CGDebugInfo::getOrCreateCompileUnit(SourceLocation Loc) { // Get absolute path name. llvm::sys::Path AbsFileName(FileName); - if (!AbsFileName.isAbsolute()) { - llvm::sys::Path tmp = llvm::sys::Path::GetCurrentDirectory(); - tmp.appendComponent(FileName); - AbsFileName = tmp; - } + AbsFileName.makeAbsolute(); // See if thie compile unit is representing main source file. Each source // file has corresponding compile unit. There is only one main source // file at a time. bool isMain = false; - const LangOptions &LO = M->getLangOptions(); - const CodeGenOptions &CGO = M->getCodeGenOpts(); + const LangOptions &LO = CGM.getLangOptions(); + const CodeGenOptions &CGO = CGM.getCodeGenOpts(); if (isMainCompileUnitCreated == false) { if (!CGO.MainFileName.empty()) { if (AbsFileName.getLast() == CGO.MainFileName) @@ -122,7 +118,7 @@ llvm::DICompileUnit CGDebugInfo::getOrCreateCompileUnit(SourceLocation Loc) { LangTag = llvm::dwarf::DW_LANG_C89; } - std::string Producer = + const char *Producer = #ifdef CLANG_VENDOR CLANG_VENDOR #endif @@ -137,9 +133,9 @@ llvm::DICompileUnit CGDebugInfo::getOrCreateCompileUnit(SourceLocation Loc) { // Create new compile unit. return Unit = DebugFactory.CreateCompileUnit(LangTag, - AbsFileName.getLast().c_str(), - AbsFileName.getDirname().c_str(), - Producer.c_str(), isMain, + AbsFileName.getLast(), + AbsFileName.getDirname(), + Producer, isMain, isOptimized, Flags, RuntimeVers); } @@ -170,13 +166,13 @@ llvm::DIType CGDebugInfo::CreateType(const BuiltinType *BT, case BuiltinType::Double: Encoding = llvm::dwarf::DW_ATE_float; break; } // Bit size, align and offset of the type. - uint64_t Size = M->getContext().getTypeSize(BT); - uint64_t Align = M->getContext().getTypeAlign(BT); + uint64_t Size = CGM.getContext().getTypeSize(BT); + uint64_t Align = CGM.getContext().getTypeAlign(BT); uint64_t Offset = 0; llvm::DIType DbgTy = DebugFactory.CreateBasicType(Unit, - BT->getName(M->getContext().getLangOptions()), + BT->getName(CGM.getContext().getLangOptions()), Unit, 0, Size, Align, Offset, /*flags*/ 0, Encoding); return DbgTy; @@ -189,8 +185,8 @@ llvm::DIType CGDebugInfo::CreateType(const ComplexType *Ty, if (Ty->isComplexIntegerType()) Encoding = llvm::dwarf::DW_ATE_lo_user; - uint64_t Size = M->getContext().getTypeSize(Ty); - uint64_t Align = M->getContext().getTypeAlign(Ty); + uint64_t Size = CGM.getContext().getTypeSize(Ty); + uint64_t Align = CGM.getContext().getTypeAlign(Ty); uint64_t Offset = 0; llvm::DIType DbgTy = @@ -262,8 +258,8 @@ llvm::DIType CGDebugInfo::CreatePointerLikeType(unsigned Tag, // Size is always the size of a pointer. We can't use getTypeSize here // because that does not return the correct value for references. uint64_t Size = - M->getContext().Target.getPointerWidth(PointeeTy.getAddressSpace()); - uint64_t Align = M->getContext().getTypeAlign(Ty); + CGM.getContext().Target.getPointerWidth(PointeeTy.getAddressSpace()); + uint64_t Align = CGM.getContext().getTypeAlign(Ty); return DebugFactory.CreateDerivedType(Tag, Unit, "", llvm::DICompileUnit(), @@ -291,10 +287,10 @@ llvm::DIType CGDebugInfo::CreateType(const BlockPointerType *Ty, llvm::DIType EltTy, DescTy; FieldOffset = 0; - FType = M->getContext().UnsignedLongTy; + FType = CGM.getContext().UnsignedLongTy; FieldTy = CGDebugInfo::getOrCreateType(FType, Unit); - FieldSize = M->getContext().getTypeSize(FType); - FieldAlign = M->getContext().getTypeAlign(FType); + FieldSize = CGM.getContext().getTypeSize(FType); + FieldAlign = CGM.getContext().getTypeAlign(FType); FieldTy = DebugFactory.CreateDerivedType(llvm::dwarf::DW_TAG_member, Unit, "reserved", DefUnit, 0, FieldSize, FieldAlign, @@ -302,10 +298,10 @@ llvm::DIType CGDebugInfo::CreateType(const BlockPointerType *Ty, EltTys.push_back(FieldTy); FieldOffset += FieldSize; - FType = M->getContext().UnsignedLongTy; + FType = CGM.getContext().UnsignedLongTy; FieldTy = CGDebugInfo::getOrCreateType(FType, Unit); - FieldSize = M->getContext().getTypeSize(FType); - FieldAlign = M->getContext().getTypeAlign(FType); + FieldSize = CGM.getContext().getTypeSize(FType); + FieldAlign = CGM.getContext().getTypeAlign(FType); FieldTy = DebugFactory.CreateDerivedType(llvm::dwarf::DW_TAG_member, Unit, "Size", DefUnit, 0, FieldSize, FieldAlign, @@ -323,18 +319,18 @@ llvm::DIType CGDebugInfo::CreateType(const BlockPointerType *Ty, llvm::DIType(), Elements); // Bit size, align and offset of the type. - uint64_t Size = M->getContext().getTypeSize(Ty); - uint64_t Align = M->getContext().getTypeAlign(Ty); + uint64_t Size = CGM.getContext().getTypeSize(Ty); + uint64_t Align = CGM.getContext().getTypeAlign(Ty); DescTy = DebugFactory.CreateDerivedType(llvm::dwarf::DW_TAG_pointer_type, Unit, "", llvm::DICompileUnit(), 0, Size, Align, 0, 0, EltTy); FieldOffset = 0; - FType = M->getContext().getPointerType(M->getContext().VoidTy); + FType = CGM.getContext().getPointerType(CGM.getContext().VoidTy); FieldTy = CGDebugInfo::getOrCreateType(FType, Unit); - FieldSize = M->getContext().getTypeSize(FType); - FieldAlign = M->getContext().getTypeAlign(FType); + FieldSize = CGM.getContext().getTypeSize(FType); + FieldAlign = CGM.getContext().getTypeAlign(FType); FieldTy = DebugFactory.CreateDerivedType(llvm::dwarf::DW_TAG_member, Unit, "__isa", DefUnit, 0, FieldSize, FieldAlign, @@ -342,10 +338,10 @@ llvm::DIType CGDebugInfo::CreateType(const BlockPointerType *Ty, EltTys.push_back(FieldTy); FieldOffset += FieldSize; - FType = M->getContext().IntTy; + FType = CGM.getContext().IntTy; FieldTy = CGDebugInfo::getOrCreateType(FType, Unit); - FieldSize = M->getContext().getTypeSize(FType); - FieldAlign = M->getContext().getTypeAlign(FType); + FieldSize = CGM.getContext().getTypeSize(FType); + FieldAlign = CGM.getContext().getTypeAlign(FType); FieldTy = DebugFactory.CreateDerivedType(llvm::dwarf::DW_TAG_member, Unit, "__flags", DefUnit, 0, FieldSize, FieldAlign, @@ -353,10 +349,10 @@ llvm::DIType CGDebugInfo::CreateType(const BlockPointerType *Ty, EltTys.push_back(FieldTy); FieldOffset += FieldSize; - FType = M->getContext().IntTy; + FType = CGM.getContext().IntTy; FieldTy = CGDebugInfo::getOrCreateType(FType, Unit); - FieldSize = M->getContext().getTypeSize(FType); - FieldAlign = M->getContext().getTypeAlign(FType); + FieldSize = CGM.getContext().getTypeSize(FType); + FieldAlign = CGM.getContext().getTypeAlign(FType); FieldTy = DebugFactory.CreateDerivedType(llvm::dwarf::DW_TAG_member, Unit, "__reserved", DefUnit, 0, FieldSize, FieldAlign, @@ -364,10 +360,10 @@ llvm::DIType CGDebugInfo::CreateType(const BlockPointerType *Ty, EltTys.push_back(FieldTy); FieldOffset += FieldSize; - FType = M->getContext().getPointerType(M->getContext().VoidTy); + FType = CGM.getContext().getPointerType(CGM.getContext().VoidTy); FieldTy = CGDebugInfo::getOrCreateType(FType, Unit); - FieldSize = M->getContext().getTypeSize(FType); - FieldAlign = M->getContext().getTypeAlign(FType); + FieldSize = CGM.getContext().getTypeSize(FType); + FieldAlign = CGM.getContext().getTypeAlign(FType); FieldTy = DebugFactory.CreateDerivedType(llvm::dwarf::DW_TAG_member, Unit, "__FuncPtr", DefUnit, 0, FieldSize, FieldAlign, @@ -375,10 +371,10 @@ llvm::DIType CGDebugInfo::CreateType(const BlockPointerType *Ty, EltTys.push_back(FieldTy); FieldOffset += FieldSize; - FType = M->getContext().getPointerType(M->getContext().VoidTy); + FType = CGM.getContext().getPointerType(CGM.getContext().VoidTy); FieldTy = DescTy; - FieldSize = M->getContext().getTypeSize(Ty); - FieldAlign = M->getContext().getTypeAlign(Ty); + FieldSize = CGM.getContext().getTypeSize(Ty); + FieldAlign = CGM.getContext().getTypeAlign(Ty); FieldTy = DebugFactory.CreateDerivedType(llvm::dwarf::DW_TAG_member, Unit, "__descriptor", DefUnit, 0, FieldSize, FieldAlign, @@ -411,7 +407,7 @@ llvm::DIType CGDebugInfo::CreateType(const TypedefType *Ty, SourceLocation DefLoc = Ty->getDecl()->getLocation(); llvm::DICompileUnit DefUnit = getOrCreateCompileUnit(DefLoc); - SourceManager &SM = M->getContext().getSourceManager(); + SourceManager &SM = CGM.getContext().getSourceManager(); PresumedLoc PLoc = SM.getPresumedLoc(DefLoc); unsigned Line = PLoc.isInvalid() ? 0 : PLoc.getLine(); @@ -464,7 +460,7 @@ llvm::DIType CGDebugInfo::CreateType(const RecordType *Ty, Tag = llvm::dwarf::DW_TAG_class_type; } - SourceManager &SM = M->getContext().getSourceManager(); + SourceManager &SM = CGM.getContext().getSourceManager(); // Get overall information about the record type for the debug info. PresumedLoc PLoc = SM.getPresumedLoc(Decl->getLocation()); @@ -487,7 +483,7 @@ llvm::DIType CGDebugInfo::CreateType(const RecordType *Ty, llvm::DIType(), llvm::DIArray()); // If this is just a forward declaration, return it. - if (!Decl->getDefinition(M->getContext())) + if (!Decl->getDefinition(CGM.getContext())) return FwdDecl; llvm::TrackingVH FwdDeclNode = FwdDecl.getNode(); @@ -498,7 +494,7 @@ llvm::DIType CGDebugInfo::CreateType(const RecordType *Ty, // Convert all the elements. llvm::SmallVector EltTys; - const ASTRecordLayout &RL = M->getContext().getASTRecordLayout(Decl); + const ASTRecordLayout &RL = CGM.getContext().getASTRecordLayout(Decl); unsigned FieldNo = 0; for (RecordDecl::field_iterator I = Decl->field_begin(), @@ -530,12 +526,12 @@ llvm::DIType CGDebugInfo::CreateType(const RecordType *Ty, if (!FType->isIncompleteArrayType()) { // Bit size, align and offset of the type. - FieldSize = M->getContext().getTypeSize(FType); + FieldSize = CGM.getContext().getTypeSize(FType); Expr *BitWidth = Field->getBitWidth(); if (BitWidth) - FieldSize = BitWidth->EvaluateAsInt(M->getContext()).getZExtValue(); + FieldSize = BitWidth->EvaluateAsInt(CGM.getContext()).getZExtValue(); - FieldAlign = M->getContext().getTypeAlign(FType); + FieldAlign = CGM.getContext().getTypeAlign(FType); } uint64_t FieldOffset = RL.getFieldOffset(FieldNo); @@ -554,8 +550,8 @@ llvm::DIType CGDebugInfo::CreateType(const RecordType *Ty, DebugFactory.GetOrCreateArray(EltTys.data(), EltTys.size()); // Bit size, align and offset of the type. - uint64_t Size = M->getContext().getTypeSize(Ty); - uint64_t Align = M->getContext().getTypeAlign(Ty); + uint64_t Size = CGM.getContext().getTypeSize(Ty); + uint64_t Align = CGM.getContext().getTypeAlign(Ty); llvm::DICompositeType RealDecl = DebugFactory.CreateCompositeType(Tag, Unit, Decl->getName(), @@ -575,7 +571,7 @@ llvm::DIType CGDebugInfo::CreateType(const ObjCInterfaceType *Ty, ObjCInterfaceDecl *Decl = Ty->getDecl(); unsigned Tag = llvm::dwarf::DW_TAG_structure_type; - SourceManager &SM = M->getContext().getSourceManager(); + SourceManager &SM = CGM.getContext().getSourceManager(); // Get overall information about the record type for the debug info. llvm::DICompileUnit DefUnit = getOrCreateCompileUnit(Decl->getLocation()); @@ -612,7 +608,7 @@ llvm::DIType CGDebugInfo::CreateType(const ObjCInterfaceType *Ty, ObjCInterfaceDecl *SClass = Decl->getSuperClass(); if (SClass) { llvm::DIType SClassTy = - getOrCreateType(M->getContext().getObjCInterfaceType(SClass), Unit); + getOrCreateType(CGM.getContext().getObjCInterfaceType(SClass), Unit); llvm::DIType InhTag = DebugFactory.CreateDerivedType(llvm::dwarf::DW_TAG_inheritance, Unit, "", llvm::DICompileUnit(), 0, 0, 0, @@ -620,7 +616,7 @@ llvm::DIType CGDebugInfo::CreateType(const ObjCInterfaceType *Ty, EltTys.push_back(InhTag); } - const ASTRecordLayout &RL = M->getContext().getASTObjCInterfaceLayout(Decl); + const ASTRecordLayout &RL = CGM.getContext().getASTObjCInterfaceLayout(Decl); unsigned FieldNo = 0; for (ObjCInterfaceDecl::ivar_iterator I = Decl->ivar_begin(), @@ -648,12 +644,12 @@ llvm::DIType CGDebugInfo::CreateType(const ObjCInterfaceType *Ty, if (!FType->isIncompleteArrayType()) { // Bit size, align and offset of the type. - FieldSize = M->getContext().getTypeSize(FType); + FieldSize = CGM.getContext().getTypeSize(FType); Expr *BitWidth = Field->getBitWidth(); if (BitWidth) - FieldSize = BitWidth->EvaluateAsInt(M->getContext()).getZExtValue(); + FieldSize = BitWidth->EvaluateAsInt(CGM.getContext()).getZExtValue(); - FieldAlign = M->getContext().getTypeAlign(FType); + FieldAlign = CGM.getContext().getTypeAlign(FType); } uint64_t FieldOffset = RL.getFieldOffset(FieldNo); @@ -678,8 +674,8 @@ llvm::DIType CGDebugInfo::CreateType(const ObjCInterfaceType *Ty, DebugFactory.GetOrCreateArray(EltTys.data(), EltTys.size()); // Bit size, align and offset of the type. - uint64_t Size = M->getContext().getTypeSize(Ty); - uint64_t Align = M->getContext().getTypeAlign(Ty); + uint64_t Size = CGM.getContext().getTypeSize(Ty); + uint64_t Align = CGM.getContext().getTypeAlign(Ty); llvm::DICompositeType RealDecl = DebugFactory.CreateCompositeType(Tag, Unit, Decl->getName(), DefUnit, @@ -713,7 +709,7 @@ llvm::DIType CGDebugInfo::CreateType(const EnumType *Ty, SourceLocation DefLoc = Decl->getLocation(); llvm::DICompileUnit DefUnit = getOrCreateCompileUnit(DefLoc); - SourceManager &SM = M->getContext().getSourceManager(); + SourceManager &SM = CGM.getContext().getSourceManager(); PresumedLoc PLoc = SM.getPresumedLoc(DefLoc); unsigned Line = PLoc.isInvalid() ? 0 : PLoc.getLine(); @@ -722,8 +718,8 @@ llvm::DIType CGDebugInfo::CreateType(const EnumType *Ty, uint64_t Size = 0; unsigned Align = 0; if (!Ty->isIncompleteType()) { - Size = M->getContext().getTypeSize(Ty); - Align = M->getContext().getTypeAlign(Ty); + Size = CGM.getContext().getTypeSize(Ty); + Align = CGM.getContext().getTypeAlign(Ty); } llvm::DIType DbgTy = @@ -754,14 +750,14 @@ llvm::DIType CGDebugInfo::CreateType(const ArrayType *Ty, if (const VariableArrayType *VAT = dyn_cast(Ty)) { Size = 0; Align = - M->getContext().getTypeAlign(M->getContext().getBaseElementType(VAT)); + CGM.getContext().getTypeAlign(CGM.getContext().getBaseElementType(VAT)); } else if (Ty->isIncompleteArrayType()) { Size = 0; - Align = M->getContext().getTypeAlign(Ty->getElementType()); + Align = CGM.getContext().getTypeAlign(Ty->getElementType()); } else { // Size and align of the whole array, not the element type. - Size = M->getContext().getTypeSize(Ty); - Align = M->getContext().getTypeAlign(Ty); + Size = CGM.getContext().getTypeSize(Ty); + Align = CGM.getContext().getTypeAlign(Ty); } // Add the dimensions of the array. FIXME: This loses CV qualifiers from @@ -797,6 +793,47 @@ llvm::DIType CGDebugInfo::CreateType(const LValueReferenceType *Ty, Ty, Ty->getPointeeType(), Unit); } +llvm::DIType CGDebugInfo::CreateType(const MemberPointerType *Ty, + llvm::DICompileUnit U) { + QualType PointerDiffTy = CGM.getContext().getPointerDiffType(); + llvm::DIType PointerDiffDITy = getOrCreateType(PointerDiffTy, U); + + if (!Ty->getPointeeType()->isFunctionType()) { + // We have a data member pointer type. + return PointerDiffDITy; + } + + // We have a member function pointer type. Treat it as a struct with two + // ptrdiff_t members. + std::pair Info = CGM.getContext().getTypeInfo(Ty); + + uint64_t FieldOffset = 0; + llvm::DIDescriptor ElementTypes[2]; + + // FIXME: This should probably be a function type instead. + ElementTypes[0] = + DebugFactory.CreateDerivedType(llvm::dwarf::DW_TAG_member, U, + "ptr", llvm::DICompileUnit(), 0, + Info.first, Info.second, FieldOffset, 0, + PointerDiffDITy); + FieldOffset += Info.first; + + ElementTypes[1] = + DebugFactory.CreateDerivedType(llvm::dwarf::DW_TAG_member, U, + "ptr", llvm::DICompileUnit(), 0, + Info.first, Info.second, FieldOffset, 0, + PointerDiffDITy); + + llvm::DIArray Elements = + DebugFactory.GetOrCreateArray(&ElementTypes[0], + llvm::array_lengthof(ElementTypes)); + + return DebugFactory.CreateCompositeType(llvm::dwarf::DW_TAG_structure_type, + U, llvm::StringRef("test"), + llvm::DICompileUnit(), 0, FieldOffset, + 0, 0, 0, llvm::DIType(), Elements); +} + static QualType CanonicalizeTypeForDebugInfo(QualType T) { switch (T->getTypeClass()) { default: @@ -895,25 +932,27 @@ llvm::DIType CGDebugInfo::CreateTypeNode(QualType Ty, case Type::LValueReference: return CreateType(cast(Ty), Unit); + case Type::MemberPointer: + return CreateType(cast(Ty), Unit); } } /// EmitFunctionStart - Constructs the debug code for entering a function - /// "llvm.dbg.func.start.". -void CGDebugInfo::EmitFunctionStart(const char *Name, QualType FnType, +void CGDebugInfo::EmitFunctionStart(llvm::StringRef Name, QualType FnType, llvm::Function *Fn, CGBuilderTy &Builder) { - const char *LinkageName = Name; + llvm::StringRef LinkageName(Name); // Skip the asm prefix if it exists. // // FIXME: This should probably be the unmangled name? if (Name[0] == '\01') - ++Name; + Name = Name.substr(1); // FIXME: Why is this using CurLoc??? llvm::DICompileUnit Unit = getOrCreateCompileUnit(CurLoc); - SourceManager &SM = M->getContext().getSourceManager(); + SourceManager &SM = CGM.getContext().getSourceManager(); unsigned LineNo = SM.getPresumedLoc(CurLoc).getLine(); llvm::DISubprogram SP = @@ -930,7 +969,7 @@ void CGDebugInfo::EmitStopPoint(llvm::Function *Fn, CGBuilderTy &Builder) { if (CurLoc.isInvalid() || CurLoc.isMacroID()) return; // Don't bother if things are the same as last time. - SourceManager &SM = M->getContext().getSourceManager(); + SourceManager &SM = CGM.getContext().getSourceManager(); if (CurLoc == PrevLoc || (SM.getInstantiationLineNumber(CurLoc) == SM.getInstantiationLineNumber(PrevLoc) @@ -982,7 +1021,7 @@ void CGDebugInfo::EmitDeclare(const VarDecl *Decl, unsigned Tag, // Do not emit variable debug information while generating optimized code. // The llvm optimizer and code generator are not yet ready to support // optimized code debugging. - const CodeGenOptions &CGO = M->getCodeGenOpts(); + const CodeGenOptions &CGO = CGM.getCodeGenOpts(); if (CGO.OptimizationLevel) return; @@ -1006,10 +1045,10 @@ void CGDebugInfo::EmitDeclare(const VarDecl *Decl, unsigned Tag, // Build up structure for the byref. See BuildByRefType. FieldOffset = 0; - FType = M->getContext().getPointerType(M->getContext().VoidTy); + FType = CGM.getContext().getPointerType(CGM.getContext().VoidTy); FieldTy = CGDebugInfo::getOrCreateType(FType, Unit); - FieldSize = M->getContext().getTypeSize(FType); - FieldAlign = M->getContext().getTypeAlign(FType); + FieldSize = CGM.getContext().getTypeSize(FType); + FieldAlign = CGM.getContext().getTypeAlign(FType); FieldTy = DebugFactory.CreateDerivedType(llvm::dwarf::DW_TAG_member, Unit, "__isa", DefUnit, 0, FieldSize, FieldAlign, @@ -1017,10 +1056,10 @@ void CGDebugInfo::EmitDeclare(const VarDecl *Decl, unsigned Tag, EltTys.push_back(FieldTy); FieldOffset += FieldSize; - FType = M->getContext().getPointerType(M->getContext().VoidTy); + FType = CGM.getContext().getPointerType(CGM.getContext().VoidTy); FieldTy = CGDebugInfo::getOrCreateType(FType, Unit); - FieldSize = M->getContext().getTypeSize(FType); - FieldAlign = M->getContext().getTypeAlign(FType); + FieldSize = CGM.getContext().getTypeSize(FType); + FieldAlign = CGM.getContext().getTypeAlign(FType); FieldTy = DebugFactory.CreateDerivedType(llvm::dwarf::DW_TAG_member, Unit, "__forwarding", DefUnit, 0, FieldSize, FieldAlign, @@ -1028,10 +1067,10 @@ void CGDebugInfo::EmitDeclare(const VarDecl *Decl, unsigned Tag, EltTys.push_back(FieldTy); FieldOffset += FieldSize; - FType = M->getContext().getFixedWidthIntType(32, true); // Int32Ty; + FType = CGM.getContext().getFixedWidthIntType(32, true); // Int32Ty; FieldTy = CGDebugInfo::getOrCreateType(FType, Unit); - FieldSize = M->getContext().getTypeSize(FType); - FieldAlign = M->getContext().getTypeAlign(FType); + FieldSize = CGM.getContext().getTypeSize(FType); + FieldAlign = CGM.getContext().getTypeAlign(FType); FieldTy = DebugFactory.CreateDerivedType(llvm::dwarf::DW_TAG_member, Unit, "__flags", DefUnit, 0, FieldSize, FieldAlign, @@ -1039,10 +1078,10 @@ void CGDebugInfo::EmitDeclare(const VarDecl *Decl, unsigned Tag, EltTys.push_back(FieldTy); FieldOffset += FieldSize; - FType = M->getContext().getFixedWidthIntType(32, true); // Int32Ty; + FType = CGM.getContext().getFixedWidthIntType(32, true); // Int32Ty; FieldTy = CGDebugInfo::getOrCreateType(FType, Unit); - FieldSize = M->getContext().getTypeSize(FType); - FieldAlign = M->getContext().getTypeAlign(FType); + FieldSize = CGM.getContext().getTypeSize(FType); + FieldAlign = CGM.getContext().getTypeAlign(FType); FieldTy = DebugFactory.CreateDerivedType(llvm::dwarf::DW_TAG_member, Unit, "__size", DefUnit, 0, FieldSize, FieldAlign, @@ -1050,12 +1089,12 @@ void CGDebugInfo::EmitDeclare(const VarDecl *Decl, unsigned Tag, EltTys.push_back(FieldTy); FieldOffset += FieldSize; - bool HasCopyAndDispose = M->BlockRequiresCopying(Type); + bool HasCopyAndDispose = CGM.BlockRequiresCopying(Type); if (HasCopyAndDispose) { - FType = M->getContext().getPointerType(M->getContext().VoidTy); + FType = CGM.getContext().getPointerType(CGM.getContext().VoidTy); FieldTy = CGDebugInfo::getOrCreateType(FType, Unit); - FieldSize = M->getContext().getTypeSize(FType); - FieldAlign = M->getContext().getTypeAlign(FType); + FieldSize = CGM.getContext().getTypeSize(FType); + FieldAlign = CGM.getContext().getTypeAlign(FType); FieldTy = DebugFactory.CreateDerivedType(llvm::dwarf::DW_TAG_member, Unit, "__copy_helper", DefUnit, 0, FieldSize, FieldAlign, @@ -1063,10 +1102,10 @@ void CGDebugInfo::EmitDeclare(const VarDecl *Decl, unsigned Tag, EltTys.push_back(FieldTy); FieldOffset += FieldSize; - FType = M->getContext().getPointerType(M->getContext().VoidTy); + FType = CGM.getContext().getPointerType(CGM.getContext().VoidTy); FieldTy = CGDebugInfo::getOrCreateType(FType, Unit); - FieldSize = M->getContext().getTypeSize(FType); - FieldAlign = M->getContext().getTypeAlign(FType); + FieldSize = CGM.getContext().getTypeSize(FType); + FieldAlign = CGM.getContext().getTypeAlign(FType); FieldTy = DebugFactory.CreateDerivedType(llvm::dwarf::DW_TAG_member, Unit, "__destroy_helper", DefUnit, 0, FieldSize, FieldAlign, @@ -1075,8 +1114,8 @@ void CGDebugInfo::EmitDeclare(const VarDecl *Decl, unsigned Tag, FieldOffset += FieldSize; } - unsigned Align = M->getContext().getDeclAlignInBytes(Decl); - if (Align > M->getContext().Target.getPointerAlign(0) / 8) { + unsigned Align = CGM.getContext().getDeclAlignInBytes(Decl); + if (Align > CGM.getContext().Target.getPointerAlign(0) / 8) { unsigned AlignedOffsetInBytes = llvm::RoundUpToAlignment(FieldOffset/8, Align); unsigned NumPaddingBytes @@ -1084,11 +1123,11 @@ void CGDebugInfo::EmitDeclare(const VarDecl *Decl, unsigned Tag, if (NumPaddingBytes > 0) { llvm::APInt pad(32, NumPaddingBytes); - FType = M->getContext().getConstantArrayType(M->getContext().CharTy, + FType = CGM.getContext().getConstantArrayType(CGM.getContext().CharTy, pad, ArrayType::Normal, 0); FieldTy = CGDebugInfo::getOrCreateType(FType, Unit); - FieldSize = M->getContext().getTypeSize(FType); - FieldAlign = M->getContext().getTypeAlign(FType); + FieldSize = CGM.getContext().getTypeSize(FType); + FieldAlign = CGM.getContext().getTypeAlign(FType); FieldTy = DebugFactory.CreateDerivedType(llvm::dwarf::DW_TAG_member, Unit, "", DefUnit, 0, FieldSize, FieldAlign, @@ -1100,7 +1139,7 @@ void CGDebugInfo::EmitDeclare(const VarDecl *Decl, unsigned Tag, FType = Type; FieldTy = CGDebugInfo::getOrCreateType(FType, Unit); - FieldSize = M->getContext().getTypeSize(FType); + FieldSize = CGM.getContext().getTypeSize(FType); FieldAlign = Align*8; FieldTy = DebugFactory.CreateDerivedType(llvm::dwarf::DW_TAG_member, Unit, @@ -1121,7 +1160,7 @@ void CGDebugInfo::EmitDeclare(const VarDecl *Decl, unsigned Tag, } // Get location information. - SourceManager &SM = M->getContext().getSourceManager(); + SourceManager &SM = CGM.getContext().getSourceManager(); PresumedLoc PLoc = SM.getPresumedLoc(Decl->getLocation()); unsigned Line = 0; unsigned Column = 0; @@ -1158,7 +1197,7 @@ void CGDebugInfo::EmitDeclare(const BlockDeclRefExpr *BDRE, unsigned Tag, // Do not emit variable debug information while generating optimized code. // The llvm optimizer and code generator are not yet ready to support // optimized code debugging. - const CodeGenOptions &CGO = M->getCodeGenOpts(); + const CodeGenOptions &CGO = CGM.getCodeGenOpts(); if (CGO.OptimizationLevel || Builder.GetInsertBlock() == 0) return; @@ -1183,10 +1222,10 @@ void CGDebugInfo::EmitDeclare(const BlockDeclRefExpr *BDRE, unsigned Tag, // Build up structure for the byref. See BuildByRefType. FieldOffset = 0; - FType = M->getContext().getPointerType(M->getContext().VoidTy); + FType = CGM.getContext().getPointerType(CGM.getContext().VoidTy); FieldTy = CGDebugInfo::getOrCreateType(FType, Unit); - FieldSize = M->getContext().getTypeSize(FType); - FieldAlign = M->getContext().getTypeAlign(FType); + FieldSize = CGM.getContext().getTypeSize(FType); + FieldAlign = CGM.getContext().getTypeAlign(FType); FieldTy = DebugFactory.CreateDerivedType(llvm::dwarf::DW_TAG_member, Unit, "__isa", DefUnit, 0, FieldSize, FieldAlign, @@ -1194,10 +1233,10 @@ void CGDebugInfo::EmitDeclare(const BlockDeclRefExpr *BDRE, unsigned Tag, EltTys.push_back(FieldTy); FieldOffset += FieldSize; - FType = M->getContext().getPointerType(M->getContext().VoidTy); + FType = CGM.getContext().getPointerType(CGM.getContext().VoidTy); FieldTy = CGDebugInfo::getOrCreateType(FType, Unit); - FieldSize = M->getContext().getTypeSize(FType); - FieldAlign = M->getContext().getTypeAlign(FType); + FieldSize = CGM.getContext().getTypeSize(FType); + FieldAlign = CGM.getContext().getTypeAlign(FType); FieldTy = DebugFactory.CreateDerivedType(llvm::dwarf::DW_TAG_member, Unit, "__forwarding", DefUnit, 0, FieldSize, FieldAlign, @@ -1205,10 +1244,10 @@ void CGDebugInfo::EmitDeclare(const BlockDeclRefExpr *BDRE, unsigned Tag, EltTys.push_back(FieldTy); FieldOffset += FieldSize; - FType = M->getContext().getFixedWidthIntType(32, true); // Int32Ty; + FType = CGM.getContext().getFixedWidthIntType(32, true); // Int32Ty; FieldTy = CGDebugInfo::getOrCreateType(FType, Unit); - FieldSize = M->getContext().getTypeSize(FType); - FieldAlign = M->getContext().getTypeAlign(FType); + FieldSize = CGM.getContext().getTypeSize(FType); + FieldAlign = CGM.getContext().getTypeAlign(FType); FieldTy = DebugFactory.CreateDerivedType(llvm::dwarf::DW_TAG_member, Unit, "__flags", DefUnit, 0, FieldSize, FieldAlign, @@ -1216,10 +1255,10 @@ void CGDebugInfo::EmitDeclare(const BlockDeclRefExpr *BDRE, unsigned Tag, EltTys.push_back(FieldTy); FieldOffset += FieldSize; - FType = M->getContext().getFixedWidthIntType(32, true); // Int32Ty; + FType = CGM.getContext().getFixedWidthIntType(32, true); // Int32Ty; FieldTy = CGDebugInfo::getOrCreateType(FType, Unit); - FieldSize = M->getContext().getTypeSize(FType); - FieldAlign = M->getContext().getTypeAlign(FType); + FieldSize = CGM.getContext().getTypeSize(FType); + FieldAlign = CGM.getContext().getTypeAlign(FType); FieldTy = DebugFactory.CreateDerivedType(llvm::dwarf::DW_TAG_member, Unit, "__size", DefUnit, 0, FieldSize, FieldAlign, @@ -1227,12 +1266,12 @@ void CGDebugInfo::EmitDeclare(const BlockDeclRefExpr *BDRE, unsigned Tag, EltTys.push_back(FieldTy); FieldOffset += FieldSize; - bool HasCopyAndDispose = M->BlockRequiresCopying(Type); + bool HasCopyAndDispose = CGM.BlockRequiresCopying(Type); if (HasCopyAndDispose) { - FType = M->getContext().getPointerType(M->getContext().VoidTy); + FType = CGM.getContext().getPointerType(CGM.getContext().VoidTy); FieldTy = CGDebugInfo::getOrCreateType(FType, Unit); - FieldSize = M->getContext().getTypeSize(FType); - FieldAlign = M->getContext().getTypeAlign(FType); + FieldSize = CGM.getContext().getTypeSize(FType); + FieldAlign = CGM.getContext().getTypeAlign(FType); FieldTy = DebugFactory.CreateDerivedType(llvm::dwarf::DW_TAG_member, Unit, "__copy_helper", DefUnit, 0, FieldSize, FieldAlign, @@ -1240,10 +1279,10 @@ void CGDebugInfo::EmitDeclare(const BlockDeclRefExpr *BDRE, unsigned Tag, EltTys.push_back(FieldTy); FieldOffset += FieldSize; - FType = M->getContext().getPointerType(M->getContext().VoidTy); + FType = CGM.getContext().getPointerType(CGM.getContext().VoidTy); FieldTy = CGDebugInfo::getOrCreateType(FType, Unit); - FieldSize = M->getContext().getTypeSize(FType); - FieldAlign = M->getContext().getTypeAlign(FType); + FieldSize = CGM.getContext().getTypeSize(FType); + FieldAlign = CGM.getContext().getTypeAlign(FType); FieldTy = DebugFactory.CreateDerivedType(llvm::dwarf::DW_TAG_member, Unit, "__destroy_helper", DefUnit, 0, FieldSize, FieldAlign, @@ -1252,8 +1291,8 @@ void CGDebugInfo::EmitDeclare(const BlockDeclRefExpr *BDRE, unsigned Tag, FieldOffset += FieldSize; } - unsigned Align = M->getContext().getDeclAlignInBytes(Decl); - if (Align > M->getContext().Target.getPointerAlign(0) / 8) { + unsigned Align = CGM.getContext().getDeclAlignInBytes(Decl); + if (Align > CGM.getContext().Target.getPointerAlign(0) / 8) { unsigned AlignedOffsetInBytes = llvm::RoundUpToAlignment(FieldOffset/8, Align); unsigned NumPaddingBytes @@ -1261,11 +1300,11 @@ void CGDebugInfo::EmitDeclare(const BlockDeclRefExpr *BDRE, unsigned Tag, if (NumPaddingBytes > 0) { llvm::APInt pad(32, NumPaddingBytes); - FType = M->getContext().getConstantArrayType(M->getContext().CharTy, + FType = CGM.getContext().getConstantArrayType(CGM.getContext().CharTy, pad, ArrayType::Normal, 0); FieldTy = CGDebugInfo::getOrCreateType(FType, Unit); - FieldSize = M->getContext().getTypeSize(FType); - FieldAlign = M->getContext().getTypeAlign(FType); + FieldSize = CGM.getContext().getTypeSize(FType); + FieldAlign = CGM.getContext().getTypeAlign(FType); FieldTy = DebugFactory.CreateDerivedType(llvm::dwarf::DW_TAG_member, Unit, "", DefUnit, 0, FieldSize, FieldAlign, @@ -1277,7 +1316,7 @@ void CGDebugInfo::EmitDeclare(const BlockDeclRefExpr *BDRE, unsigned Tag, FType = Type; FieldTy = CGDebugInfo::getOrCreateType(FType, Unit); - FieldSize = M->getContext().getTypeSize(FType); + FieldSize = CGM.getContext().getTypeSize(FType); FieldAlign = Align*8; XOffset = FieldOffset; @@ -1299,7 +1338,7 @@ void CGDebugInfo::EmitDeclare(const BlockDeclRefExpr *BDRE, unsigned Tag, } // Get location information. - SourceManager &SM = M->getContext().getSourceManager(); + SourceManager &SM = CGM.getContext().getSourceManager(); PresumedLoc PLoc = SM.getPresumedLoc(Decl->getLocation()); unsigned Line = 0; if (!PLoc.isInvalid()) @@ -1309,7 +1348,7 @@ void CGDebugInfo::EmitDeclare(const BlockDeclRefExpr *BDRE, unsigned Tag, uint64_t offset = CGF->BlockDecls[Decl]; llvm::SmallVector addr; - llvm::LLVMContext &VMContext = M->getLLVMContext(); + llvm::LLVMContext &VMContext = CGM.getLLVMContext(); addr.push_back(llvm::ConstantInt::get(llvm::Type::getInt64Ty(VMContext), llvm::DIFactory::OpDeref)); addr.push_back(llvm::ConstantInt::get(llvm::Type::getInt64Ty(VMContext), @@ -1376,7 +1415,7 @@ void CGDebugInfo::EmitGlobalVariable(llvm::GlobalVariable *Var, // Create global variable debug descriptor. llvm::DICompileUnit Unit = getOrCreateCompileUnit(Decl->getLocation()); - SourceManager &SM = M->getContext().getSourceManager(); + SourceManager &SM = CGM.getContext().getSourceManager(); PresumedLoc PLoc = SM.getPresumedLoc(Decl->getLocation()); unsigned LineNo = PLoc.isInvalid() ? 0 : PLoc.getLine(); @@ -1387,9 +1426,9 @@ void CGDebugInfo::EmitGlobalVariable(llvm::GlobalVariable *Var, llvm::APSInt ConstVal(32); ConstVal = 1; - QualType ET = M->getContext().getAsArrayType(T)->getElementType(); + QualType ET = CGM.getContext().getAsArrayType(T)->getElementType(); - T = M->getContext().getConstantArrayType(ET, ConstVal, + T = CGM.getContext().getConstantArrayType(ET, ConstVal, ArrayType::Normal, 0); } llvm::StringRef DeclName = Decl->getName(); @@ -1405,22 +1444,22 @@ void CGDebugInfo::EmitGlobalVariable(llvm::GlobalVariable *Var, ObjCInterfaceDecl *Decl) { // Create global variable debug descriptor. llvm::DICompileUnit Unit = getOrCreateCompileUnit(Decl->getLocation()); - SourceManager &SM = M->getContext().getSourceManager(); + SourceManager &SM = CGM.getContext().getSourceManager(); PresumedLoc PLoc = SM.getPresumedLoc(Decl->getLocation()); unsigned LineNo = PLoc.isInvalid() ? 0 : PLoc.getLine(); llvm::StringRef Name = Decl->getName(); - QualType T = M->getContext().getObjCInterfaceType(Decl); + QualType T = CGM.getContext().getObjCInterfaceType(Decl); if (T->isIncompleteArrayType()) { // CodeGen turns int[] into int[1] so we'll do the same here. llvm::APSInt ConstVal(32); ConstVal = 1; - QualType ET = M->getContext().getAsArrayType(T)->getElementType(); + QualType ET = CGM.getContext().getAsArrayType(T)->getElementType(); - T = M->getContext().getConstantArrayType(ET, ConstVal, + T = CGM.getContext().getConstantArrayType(ET, ConstVal, ArrayType::Normal, 0); } diff --git a/lib/CodeGen/CGDebugInfo.h b/lib/CodeGen/CGDebugInfo.h index af86e2b263fd..7df2a6247b4c 100644 --- a/lib/CodeGen/CGDebugInfo.h +++ b/lib/CodeGen/CGDebugInfo.h @@ -40,7 +40,7 @@ namespace CodeGen { /// and is responsible for emitting to llvm globals or pass directly to /// the backend. class CGDebugInfo { - CodeGenModule *M; + CodeGenModule &CGM; bool isMainCompileUnitCreated; llvm::DIFactory DebugFactory; @@ -74,12 +74,13 @@ class CGDebugInfo { llvm::DIType CreateType(const EnumType *Ty, llvm::DICompileUnit U); llvm::DIType CreateType(const ArrayType *Ty, llvm::DICompileUnit U); llvm::DIType CreateType(const LValueReferenceType *Ty, llvm::DICompileUnit U); - + llvm::DIType CreateType(const MemberPointerType *Ty, llvm::DICompileUnit U); + llvm::DIType CreatePointerLikeType(unsigned Tag, const Type *Ty, QualType PointeeTy, llvm::DICompileUnit U); public: - CGDebugInfo(CodeGenModule *m); + CGDebugInfo(CodeGenModule &CGM); ~CGDebugInfo(); /// setLocation - Update the current source location. If \arg loc is @@ -92,7 +93,7 @@ class CGDebugInfo { /// EmitFunctionStart - Emit a call to llvm.dbg.function.start to indicate /// start of a new function. - void EmitFunctionStart(const char *Name, QualType FnType, + void EmitFunctionStart(llvm::StringRef Name, QualType FnType, llvm::Function *Fn, CGBuilderTy &Builder); /// EmitRegionStart - Emit a call to llvm.dbg.region.start to indicate start diff --git a/lib/CodeGen/CGDecl.cpp b/lib/CodeGen/CGDecl.cpp index c0472830925d..14ee90d46936 100644 --- a/lib/CodeGen/CGDecl.cpp +++ b/lib/CodeGen/CGDecl.cpp @@ -43,6 +43,7 @@ void CodeGenFunction::EmitDecl(const Decl &D) { case Decl::Using: // using X; [C++] case Decl::UsingShadow: case Decl::UsingDirective: // using namespace X; [C++] + case Decl::StaticAssert: // static_assert(X, ""); [C++0x] // None of these decls require codegen support. return; @@ -85,28 +86,32 @@ void CodeGenFunction::EmitBlockVarDecl(const VarDecl &D) { assert(0 && "Unknown storage class"); } +static std::string GetStaticDeclName(CodeGenFunction &CGF, const VarDecl &D, + const char *Separator) { + CodeGenModule &CGM = CGF.CGM; + if (CGF.getContext().getLangOptions().CPlusPlus) + return CGM.getMangledName(&D); + + std::string ContextName; + if (const FunctionDecl *FD = dyn_cast(CGF.CurFuncDecl)) + ContextName = CGM.getMangledName(FD); + else if (isa(CGF.CurFuncDecl)) + ContextName = CGF.CurFn->getName(); + else + // FIXME: What about in a block?? + assert(0 && "Unknown context for block var decl"); + + return ContextName + Separator + D.getNameAsString(); +} + llvm::GlobalVariable * CodeGenFunction::CreateStaticBlockVarDecl(const VarDecl &D, const char *Separator, - llvm::GlobalValue::LinkageTypes - Linkage) { + llvm::GlobalValue::LinkageTypes Linkage) { QualType Ty = D.getType(); assert(Ty->isConstantSizeType() && "VLAs can't be static"); - std::string Name; - if (getContext().getLangOptions().CPlusPlus) { - Name = CGM.getMangledName(&D); - } else { - std::string ContextName; - if (const FunctionDecl *FD = dyn_cast(CurFuncDecl)) - ContextName = CGM.getMangledName(FD); - else if (isa(CurFuncDecl)) - ContextName = CurFn->getName(); - else - assert(0 && "Unknown context for block var decl"); - - Name = ContextName + Separator + D.getNameAsString(); - } + std::string Name = GetStaticDeclName(*this, D, Separator); const llvm::Type *LTy = CGM.getTypes().ConvertTypeForMem(Ty); llvm::GlobalVariable *GV = @@ -118,6 +123,54 @@ CodeGenFunction::CreateStaticBlockVarDecl(const VarDecl &D, return GV; } +/// AddInitializerToGlobalBlockVarDecl - Add the initializer for 'D' to the +/// global variable that has already been created for it. If the initializer +/// has a different type than GV does, this may free GV and return a different +/// one. Otherwise it just returns GV. +llvm::GlobalVariable * +CodeGenFunction::AddInitializerToGlobalBlockVarDecl(const VarDecl &D, + llvm::GlobalVariable *GV) { + llvm::Constant *Init = CGM.EmitConstantExpr(D.getInit(), D.getType(), this); + + // If constant emission failed, then this should be a C++ static + // initializer. + if (!Init) { + if (!getContext().getLangOptions().CPlusPlus) + CGM.ErrorUnsupported(D.getInit(), "constant l-value expression"); + else + EmitStaticCXXBlockVarDeclInit(D, GV); + return GV; + } + + // The initializer may differ in type from the global. Rewrite + // the global to match the initializer. (We have to do this + // because some types, like unions, can't be completely represented + // in the LLVM type system.) + if (GV->getType() != Init->getType()) { + llvm::GlobalVariable *OldGV = GV; + + GV = new llvm::GlobalVariable(CGM.getModule(), Init->getType(), + OldGV->isConstant(), + OldGV->getLinkage(), Init, "", + 0, D.isThreadSpecified(), + D.getType().getAddressSpace()); + + // Steal the name of the old global + GV->takeName(OldGV); + + // Replace all uses of the old global with the new global + llvm::Constant *NewPtrForOldDecl = + llvm::ConstantExpr::getBitCast(GV, OldGV->getType()); + OldGV->replaceAllUsesWith(NewPtrForOldDecl); + + // Erase the old global, since it is no longer used. + OldGV->eraseFromParent(); + } + + GV->setInitializer(Init); + return GV; +} + void CodeGenFunction::EmitStaticBlockVarDecl(const VarDecl &D) { llvm::Value *&DMEntry = LocalDeclMap[&D]; assert(DMEntry == 0 && "Decl already exists in localdeclmap!"); @@ -135,45 +188,9 @@ void CodeGenFunction::EmitStaticBlockVarDecl(const VarDecl &D) { if (D.getType()->isVariablyModifiedType()) EmitVLASize(D.getType()); - if (D.getInit()) { - llvm::Constant *Init = CGM.EmitConstantExpr(D.getInit(), D.getType(), this); - - // If constant emission failed, then this should be a C++ static - // initializer. - if (!Init) { - if (!getContext().getLangOptions().CPlusPlus) - CGM.ErrorUnsupported(D.getInit(), "constant l-value expression"); - else - EmitStaticCXXBlockVarDeclInit(D, GV); - } else { - // The initializer may differ in type from the global. Rewrite - // the global to match the initializer. (We have to do this - // because some types, like unions, can't be completely represented - // in the LLVM type system.) - if (GV->getType() != Init->getType()) { - llvm::GlobalVariable *OldGV = GV; - - GV = new llvm::GlobalVariable(CGM.getModule(), Init->getType(), - OldGV->isConstant(), - OldGV->getLinkage(), Init, "", - 0, D.isThreadSpecified(), - D.getType().getAddressSpace()); - - // Steal the name of the old global - GV->takeName(OldGV); - - // Replace all uses of the old global with the new global - llvm::Constant *NewPtrForOldDecl = - llvm::ConstantExpr::getBitCast(GV, OldGV->getType()); - OldGV->replaceAllUsesWith(NewPtrForOldDecl); - - // Erase the old global, since it is no longer used. - OldGV->eraseFromParent(); - } - - GV->setInitializer(Init); - } - } + // If this value has an initializer, emit it. + if (D.getInit()) + GV = AddInitializerToGlobalBlockVarDecl(D, GV); // FIXME: Merge attribute handling. if (const AnnotateAttr *AA = D.getAttr()) { @@ -317,32 +334,36 @@ void CodeGenFunction::EmitLocalBlockVarDecl(const VarDecl &D) { bool isByRef = D.hasAttr(); bool needsDispose = false; unsigned Align = 0; + bool IsSimpleConstantInitializer = false; llvm::Value *DeclPtr; if (Ty->isConstantSizeType()) { if (!Target.useGlobalsForAutomaticVariables()) { - // All constant structs and arrays should be global if - // their initializer is constant and if the element type is POD. - if (CGM.getCodeGenOpts().MergeAllConstants) { - if (Ty.isConstant(getContext()) - && (Ty->isArrayType() || Ty->isRecordType()) - && (D.getInit() - && D.getInit()->isConstantInitializer(getContext())) - && Ty->isPODType()) { + // If this value is an array or struct, is POD, and if the initializer is + // a staticly determinable constant, try to optimize it. + if (D.getInit() && !isByRef && + (Ty->isArrayType() || Ty->isRecordType()) && + Ty->isPODType() && + D.getInit()->isConstantInitializer(getContext())) { + // If this variable is marked 'const', emit the value as a global. + if (CGM.getCodeGenOpts().MergeAllConstants && + Ty.isConstant(getContext())) { EmitStaticBlockVarDecl(D); return; } + + IsSimpleConstantInitializer = true; } // A normal fixed sized variable becomes an alloca in the entry block. const llvm::Type *LTy = ConvertTypeForMem(Ty); - Align = getContext().getDeclAlignInBytes(&D); if (isByRef) LTy = BuildByRefType(&D); llvm::AllocaInst *Alloc = CreateTempAlloca(LTy); - Alloc->setName(D.getNameAsString().c_str()); + Alloc->setName(D.getNameAsString()); + Align = getContext().getDeclAlignInBytes(&D); if (isByRef) Align = std::max(Align, unsigned(Target.getPointerAlign(0) / 8)); Alloc->setAlignment(Align); @@ -436,9 +457,48 @@ void CodeGenFunction::EmitLocalBlockVarDecl(const VarDecl &D) { Loc = Builder.CreateStructGEP(DeclPtr, getByRefValueLLVMField(&D), D.getNameAsString()); - bool isVolatile = (getContext().getCanonicalType(D.getType()) - .isVolatileQualified()); - if (Ty->isReferenceType()) { + bool isVolatile = + getContext().getCanonicalType(D.getType()).isVolatileQualified(); + + // If the initializer was a simple constant initializer, we can optimize it + // in various ways. + if (IsSimpleConstantInitializer) { + llvm::Constant *Init = CGM.EmitConstantExpr(D.getInit(),D.getType(),this); + assert(Init != 0 && "Wasn't a simple constant init?"); + + llvm::Value *AlignVal = + llvm::ConstantInt::get(llvm::Type::getInt32Ty(VMContext), Align); + const llvm::Type *IntPtr = + llvm::IntegerType::get(VMContext, LLVMPointerWidth); + llvm::Value *SizeVal = + llvm::ConstantInt::get(IntPtr, getContext().getTypeSizeInBytes(Ty)); + + const llvm::Type *BP = llvm::Type::getInt8PtrTy(VMContext); + if (Loc->getType() != BP) + Loc = Builder.CreateBitCast(Loc, BP, "tmp"); + + // If the initializer is all zeros, codegen with memset. + if (isa(Init)) { + llvm::Value *Zero = + llvm::ConstantInt::get(llvm::Type::getInt8Ty(VMContext), 0); + Builder.CreateCall4(CGM.getMemSetFn(), Loc, Zero, SizeVal, AlignVal); + } else { + // Otherwise, create a temporary global with the initializer then + // memcpy from the global to the alloca. + std::string Name = GetStaticDeclName(*this, D, "."); + llvm::GlobalVariable *GV = + new llvm::GlobalVariable(CGM.getModule(), Init->getType(), true, + llvm::GlobalValue::InternalLinkage, + Init, Name, 0, false, 0); + GV->setAlignment(Align); + + llvm::Value *SrcPtr = GV; + if (SrcPtr->getType() != BP) + SrcPtr = Builder.CreateBitCast(SrcPtr, BP, "tmp"); + + Builder.CreateCall4(CGM.getMemCpyFn(), Loc, SrcPtr, SizeVal, AlignVal); + } + } else if (Ty->isReferenceType()) { RValue RV = EmitReferenceBindingToExpr(Init, Ty, /*IsInitializer=*/true); EmitStoreOfScalar(RV.getScalarVal(), Loc, false, Ty); } else if (!hasAggregateLLVMType(Init->getType())) { @@ -521,19 +581,39 @@ void CodeGenFunction::EmitLocalBlockVarDecl(const VarDecl &D) { if (const ConstantArrayType *Array = getContext().getAsConstantArrayType(Ty)) { - DelayedCleanupBlock Scope(*this); - QualType BaseElementTy = getContext().getBaseElementType(Array); - const llvm::Type *BasePtr = ConvertType(BaseElementTy); - BasePtr = llvm::PointerType::getUnqual(BasePtr); - llvm::Value *BaseAddrPtr = - Builder.CreateBitCast(DeclPtr, BasePtr); - EmitCXXAggrDestructorCall(D, Array, BaseAddrPtr); + { + DelayedCleanupBlock Scope(*this); + QualType BaseElementTy = getContext().getBaseElementType(Array); + const llvm::Type *BasePtr = ConvertType(BaseElementTy); + BasePtr = llvm::PointerType::getUnqual(BasePtr); + llvm::Value *BaseAddrPtr = + Builder.CreateBitCast(DeclPtr, BasePtr); + EmitCXXAggrDestructorCall(D, Array, BaseAddrPtr); - // Make sure to jump to the exit block. - EmitBranch(Scope.getCleanupExitBlock()); + // Make sure to jump to the exit block. + EmitBranch(Scope.getCleanupExitBlock()); + } + if (Exceptions) { + EHCleanupBlock Cleanup(*this); + QualType BaseElementTy = getContext().getBaseElementType(Array); + const llvm::Type *BasePtr = ConvertType(BaseElementTy); + BasePtr = llvm::PointerType::getUnqual(BasePtr); + llvm::Value *BaseAddrPtr = + Builder.CreateBitCast(DeclPtr, BasePtr); + EmitCXXAggrDestructorCall(D, Array, BaseAddrPtr); + } } else { - DelayedCleanupBlock Scope(*this); - EmitCXXDestructorCall(D, Dtor_Complete, DeclPtr); + { + DelayedCleanupBlock Scope(*this); + EmitCXXDestructorCall(D, Dtor_Complete, DeclPtr); + + // Make sure to jump to the exit block. + EmitBranch(Scope.getCleanupExitBlock()); + } + if (Exceptions) { + EHCleanupBlock Cleanup(*this); + EmitCXXDestructorCall(D, Dtor_Complete, DeclPtr); + } } } } @@ -545,8 +625,6 @@ void CodeGenFunction::EmitLocalBlockVarDecl(const VarDecl &D) { llvm::Constant* F = CGM.GetAddrOfFunction(FD); assert(F && "Could not find function!"); - DelayedCleanupBlock scope(*this); - const CGFunctionInfo &Info = CGM.getTypes().getFunctionInfo(FD); // In some cases, the type of the function argument will be different from @@ -556,20 +634,40 @@ void CodeGenFunction::EmitLocalBlockVarDecl(const VarDecl &D) { // // To fix this we insert a bitcast here. QualType ArgTy = Info.arg_begin()->type; - DeclPtr = Builder.CreateBitCast(DeclPtr, ConvertType(ArgTy)); + { + DelayedCleanupBlock scope(*this); - CallArgList Args; - Args.push_back(std::make_pair(RValue::get(DeclPtr), - getContext().getPointerType(D.getType()))); + CallArgList Args; + Args.push_back(std::make_pair(RValue::get(Builder.CreateBitCast(DeclPtr, + ConvertType(ArgTy))), + getContext().getPointerType(D.getType()))); + EmitCall(Info, F, Args); + } + if (Exceptions) { + EHCleanupBlock Cleanup(*this); - EmitCall(Info, F, Args); + CallArgList Args; + Args.push_back(std::make_pair(RValue::get(Builder.CreateBitCast(DeclPtr, + ConvertType(ArgTy))), + getContext().getPointerType(D.getType()))); + EmitCall(Info, F, Args); + } } if (needsDispose && CGM.getLangOptions().getGCMode() != LangOptions::GCOnly) { - DelayedCleanupBlock scope(*this); - llvm::Value *V = Builder.CreateStructGEP(DeclPtr, 1, "forwarding"); - V = Builder.CreateLoad(V); - BuildBlockRelease(V); + { + DelayedCleanupBlock scope(*this); + llvm::Value *V = Builder.CreateStructGEP(DeclPtr, 1, "forwarding"); + V = Builder.CreateLoad(V); + BuildBlockRelease(V); + } + // FIXME: Turn this on and audit the codegen + if (0 && Exceptions) { + EHCleanupBlock Cleanup(*this); + llvm::Value *V = Builder.CreateStructGEP(DeclPtr, 1, "forwarding"); + V = Builder.CreateLoad(V); + BuildBlockRelease(V); + } } } @@ -591,10 +689,8 @@ void CodeGenFunction::EmitParmDecl(const VarDecl &D, llvm::Value *Arg) { const llvm::Type *LTy = ConvertTypeForMem(Ty); if (LTy->isSingleValueType()) { // TODO: Alignment - std::string Name = D.getNameAsString(); - Name += ".addr"; DeclPtr = CreateTempAlloca(LTy); - DeclPtr->setName(Name.c_str()); + DeclPtr->setName(D.getNameAsString() + llvm::StringRef(".addr")); // Store the initial value into the alloca. EmitStoreOfScalar(Arg, DeclPtr, CTy.isVolatileQualified(), Ty); diff --git a/lib/CodeGen/CGDeclCXX.cpp b/lib/CodeGen/CGDeclCXX.cpp new file mode 100644 index 000000000000..0b6ea5a834b1 --- /dev/null +++ b/lib/CodeGen/CGDeclCXX.cpp @@ -0,0 +1,211 @@ +//===--- CGDeclCXX.cpp - Emit LLVM Code for C++ declarations --------------===// +// +// 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 code generation of C++ declarations +// +//===----------------------------------------------------------------------===// + +#include "CodeGenFunction.h" +using namespace clang; +using namespace CodeGen; + +static void EmitDeclInit(CodeGenFunction &CGF, const VarDecl &D, + llvm::Constant *DeclPtr) { + assert(D.hasGlobalStorage() && "VarDecl must have global storage!"); + assert(!D.getType()->isReferenceType() && + "Should not call EmitDeclInit on a reference!"); + + CodeGenModule &CGM = CGF.CGM; + ASTContext &Context = CGF.getContext(); + + const Expr *Init = D.getInit(); + QualType T = D.getType(); + bool isVolatile = Context.getCanonicalType(T).isVolatileQualified(); + + if (!CGF.hasAggregateLLVMType(T)) { + llvm::Value *V = CGF.EmitScalarExpr(Init); + CGF.EmitStoreOfScalar(V, DeclPtr, isVolatile, T); + } else if (T->isAnyComplexType()) { + CGF.EmitComplexExprIntoAddr(Init, DeclPtr, isVolatile); + } else { + CGF.EmitAggExpr(Init, DeclPtr, isVolatile); + + // Avoid generating destructor(s) for initialized objects. + if (!isa(Init)) + return; + + const ConstantArrayType *Array = Context.getAsConstantArrayType(T); + if (Array) + T = Context.getBaseElementType(Array); + + const RecordType *RT = T->getAs(); + if (!RT) + return; + + CXXRecordDecl *RD = cast(RT->getDecl()); + if (RD->hasTrivialDestructor()) + return; + + CXXDestructorDecl *Dtor = RD->getDestructor(Context); + + llvm::Constant *DtorFn; + if (Array) { + DtorFn = + CodeGenFunction(CGM).GenerateCXXAggrDestructorHelper(Dtor, + Array, + DeclPtr); + const llvm::Type *Int8PtrTy = + llvm::Type::getInt8PtrTy(CGM.getLLVMContext()); + DeclPtr = llvm::Constant::getNullValue(Int8PtrTy); + } else + DtorFn = CGM.GetAddrOfCXXDestructor(Dtor, Dtor_Complete); + + CGF.EmitCXXGlobalDtorRegistration(DtorFn, DeclPtr); + } +} + +void CodeGenFunction::EmitCXXGlobalVarDeclInit(const VarDecl &D, + llvm::Constant *DeclPtr) { + + const Expr *Init = D.getInit(); + QualType T = D.getType(); + + if (!T->isReferenceType()) { + EmitDeclInit(*this, D, DeclPtr); + return; + } + + ErrorUnsupported(Init, "global variable that binds to a reference"); +} + +void +CodeGenFunction::EmitCXXGlobalDtorRegistration(llvm::Constant *DtorFn, + llvm::Constant *DeclPtr) { + const llvm::Type *Int8PtrTy = + llvm::Type::getInt8Ty(VMContext)->getPointerTo(); + + std::vector Params; + Params.push_back(Int8PtrTy); + + // Get the destructor function type + const llvm::Type *DtorFnTy = + llvm::FunctionType::get(llvm::Type::getVoidTy(VMContext), Params, false); + DtorFnTy = llvm::PointerType::getUnqual(DtorFnTy); + + Params.clear(); + Params.push_back(DtorFnTy); + Params.push_back(Int8PtrTy); + Params.push_back(Int8PtrTy); + + // Get the __cxa_atexit function type + // extern "C" int __cxa_atexit ( void (*f)(void *), void *p, void *d ); + const llvm::FunctionType *AtExitFnTy = + llvm::FunctionType::get(ConvertType(getContext().IntTy), Params, false); + + llvm::Constant *AtExitFn = CGM.CreateRuntimeFunction(AtExitFnTy, + "__cxa_atexit"); + + llvm::Constant *Handle = CGM.CreateRuntimeVariable(Int8PtrTy, + "__dso_handle"); + llvm::Value *Args[3] = { llvm::ConstantExpr::getBitCast(DtorFn, DtorFnTy), + llvm::ConstantExpr::getBitCast(DeclPtr, Int8PtrTy), + llvm::ConstantExpr::getBitCast(Handle, Int8PtrTy) }; + Builder.CreateCall(AtExitFn, &Args[0], llvm::array_endof(Args)); +} + +void +CodeGenModule::EmitCXXGlobalInitFunc() { + if (CXXGlobalInits.empty()) + return; + + const llvm::FunctionType *FTy + = llvm::FunctionType::get(llvm::Type::getVoidTy(VMContext), + false); + + // Create our global initialization function. + // FIXME: Should this be tweakable by targets? + llvm::Function *Fn = + llvm::Function::Create(FTy, llvm::GlobalValue::InternalLinkage, + "__cxx_global_initialization", &TheModule); + + CodeGenFunction(*this).GenerateCXXGlobalInitFunc(Fn, + &CXXGlobalInits[0], + CXXGlobalInits.size()); + AddGlobalCtor(Fn); +} + +void CodeGenFunction::GenerateCXXGlobalInitFunc(llvm::Function *Fn, + const VarDecl **Decls, + unsigned NumDecls) { + StartFunction(GlobalDecl(), getContext().VoidTy, Fn, FunctionArgList(), + SourceLocation()); + + for (unsigned i = 0; i != NumDecls; ++i) { + const VarDecl *D = Decls[i]; + + llvm::Constant *DeclPtr = CGM.GetAddrOfGlobalVar(D); + EmitCXXGlobalVarDeclInit(*D, DeclPtr); + } + FinishFunction(); +} + +void +CodeGenFunction::EmitStaticCXXBlockVarDeclInit(const VarDecl &D, + llvm::GlobalVariable *GV) { + // FIXME: This should use __cxa_guard_{acquire,release}? + + assert(!getContext().getLangOptions().ThreadsafeStatics && + "thread safe statics are currently not supported!"); + + llvm::SmallString<256> GuardVName; + CGM.getMangleContext().mangleGuardVariable(&D, GuardVName); + + // Create the guard variable. + llvm::GlobalValue *GuardV = + new llvm::GlobalVariable(CGM.getModule(), llvm::Type::getInt64Ty(VMContext), + false, GV->getLinkage(), + llvm::Constant::getNullValue(llvm::Type::getInt64Ty(VMContext)), + GuardVName.str()); + + // Load the first byte of the guard variable. + const llvm::Type *PtrTy + = llvm::PointerType::get(llvm::Type::getInt8Ty(VMContext), 0); + llvm::Value *V = Builder.CreateLoad(Builder.CreateBitCast(GuardV, PtrTy), + "tmp"); + + // Compare it against 0. + llvm::Value *nullValue + = llvm::Constant::getNullValue(llvm::Type::getInt8Ty(VMContext)); + llvm::Value *ICmp = Builder.CreateICmpEQ(V, nullValue , "tobool"); + + llvm::BasicBlock *InitBlock = createBasicBlock("init"); + llvm::BasicBlock *EndBlock = createBasicBlock("init.end"); + + // If the guard variable is 0, jump to the initializer code. + Builder.CreateCondBr(ICmp, InitBlock, EndBlock); + + EmitBlock(InitBlock); + + if (D.getType()->isReferenceType()) { + QualType T = D.getType(); + // We don't want to pass true for IsInitializer here, because a static + // reference to a temporary does not extend its lifetime. + RValue RV = EmitReferenceBindingToExpr(D.getInit(), T, + /*IsInitializer=*/false); + EmitStoreOfScalar(RV.getScalarVal(), GV, /*Volatile=*/false, T); + + } else + EmitDeclInit(*this, D, GV); + + Builder.CreateStore(llvm::ConstantInt::get(llvm::Type::getInt8Ty(VMContext), + 1), + Builder.CreateBitCast(GuardV, PtrTy)); + + EmitBlock(EndBlock); +} diff --git a/lib/CodeGen/CGException.cpp b/lib/CodeGen/CGException.cpp index 420e275becd1..b15b2e9b3b0f 100644 --- a/lib/CodeGen/CGException.cpp +++ b/lib/CodeGen/CGException.cpp @@ -23,58 +23,83 @@ static llvm::Constant *getAllocateExceptionFn(CodeGenFunction &CGF) { // void *__cxa_allocate_exception(size_t thrown_size); const llvm::Type *SizeTy = CGF.ConvertType(CGF.getContext().getSizeType()); std::vector Args(1, SizeTy); - - const llvm::FunctionType *FTy = + + const llvm::FunctionType *FTy = llvm::FunctionType::get(llvm::Type::getInt8PtrTy(CGF.getLLVMContext()), Args, false); - + return CGF.CGM.CreateRuntimeFunction(FTy, "__cxa_allocate_exception"); } +static llvm::Constant *getFreeExceptionFn(CodeGenFunction &CGF) { + // void __cxa_free_exception(void *thrown_exception); + const llvm::Type *Int8PtrTy = llvm::Type::getInt8PtrTy(CGF.getLLVMContext()); + std::vector Args(1, Int8PtrTy); + + const llvm::FunctionType *FTy = + llvm::FunctionType::get(llvm::Type::getVoidTy(CGF.getLLVMContext()), + Args, false); + + return CGF.CGM.CreateRuntimeFunction(FTy, "__cxa_free_exception"); +} + static llvm::Constant *getThrowFn(CodeGenFunction &CGF) { - // void __cxa_throw (void *thrown_exception, std::type_info *tinfo, - // void (*dest) (void *) ); + // void __cxa_throw(void *thrown_exception, std::type_info *tinfo, + // void (*dest) (void *)); const llvm::Type *Int8PtrTy = llvm::Type::getInt8PtrTy(CGF.getLLVMContext()); std::vector Args(3, Int8PtrTy); - - const llvm::FunctionType *FTy = + + const llvm::FunctionType *FTy = llvm::FunctionType::get(llvm::Type::getVoidTy(CGF.getLLVMContext()), Args, false); - + return CGF.CGM.CreateRuntimeFunction(FTy, "__cxa_throw"); } static llvm::Constant *getReThrowFn(CodeGenFunction &CGF) { - // void __cxa_rethrow (); + // void __cxa_rethrow(); - const llvm::FunctionType *FTy = + const llvm::FunctionType *FTy = llvm::FunctionType::get(llvm::Type::getVoidTy(CGF.getLLVMContext()), false); - + return CGF.CGM.CreateRuntimeFunction(FTy, "__cxa_rethrow"); } static llvm::Constant *getBeginCatchFn(CodeGenFunction &CGF) { - // void* __cxa_begin_catch (); + // void* __cxa_begin_catch(); const llvm::Type *Int8PtrTy = llvm::Type::getInt8PtrTy(CGF.getLLVMContext()); std::vector Args(1, Int8PtrTy); - - const llvm::FunctionType *FTy = + + const llvm::FunctionType *FTy = llvm::FunctionType::get(Int8PtrTy, Args, false); - + return CGF.CGM.CreateRuntimeFunction(FTy, "__cxa_begin_catch"); } static llvm::Constant *getEndCatchFn(CodeGenFunction &CGF) { - // void __cxa_end_catch (); + // void __cxa_end_catch(); - const llvm::FunctionType *FTy = + const llvm::FunctionType *FTy = llvm::FunctionType::get(llvm::Type::getVoidTy(CGF.getLLVMContext()), false); - + return CGF.CGM.CreateRuntimeFunction(FTy, "__cxa_end_catch"); } +static llvm::Constant *getUnexpectedFn(CodeGenFunction &CGF) { + // void __cxa_call_unexepcted(void *thrown_exception); + + const llvm::Type *Int8PtrTy = llvm::Type::getInt8PtrTy(CGF.getLLVMContext()); + std::vector Args(1, Int8PtrTy); + + const llvm::FunctionType *FTy = + llvm::FunctionType::get(llvm::Type::getVoidTy(CGF.getLLVMContext()), + Args, false); + + return CGF.CGM.CreateRuntimeFunction(FTy, "__cxa_call_unexpected"); +} + // FIXME: Eventually this will all go into the backend. Set from the target for // now. static int using_sjlj_exceptions = 0; @@ -82,38 +107,64 @@ static int using_sjlj_exceptions = 0; static llvm::Constant *getUnwindResumeOrRethrowFn(CodeGenFunction &CGF) { const llvm::Type *Int8PtrTy = llvm::Type::getInt8PtrTy(CGF.getLLVMContext()); std::vector Args(1, Int8PtrTy); - - const llvm::FunctionType *FTy = + + const llvm::FunctionType *FTy = llvm::FunctionType::get(llvm::Type::getVoidTy(CGF.getLLVMContext()), Args, false); - + if (using_sjlj_exceptions) return CGF.CGM.CreateRuntimeFunction(FTy, "_Unwind_SjLj_Resume"); return CGF.CGM.CreateRuntimeFunction(FTy, "_Unwind_Resume_or_Rethrow"); } +static llvm::Constant *getTerminateFn(CodeGenFunction &CGF) { + // void __terminate(); + + const llvm::FunctionType *FTy = + llvm::FunctionType::get(llvm::Type::getVoidTy(CGF.getLLVMContext()), false); + + return CGF.CGM.CreateRuntimeFunction(FTy, "_ZSt9terminatev"); +} + // CopyObject - Utility to copy an object. Calls copy constructor as necessary. -// N is casted to the right type. -static void CopyObject(CodeGenFunction &CGF, const Expr *E, llvm::Value *N) { +// DestPtr is casted to the right type. +static void CopyObject(CodeGenFunction &CGF, const Expr *E, + llvm::Value *DestPtr, llvm::Value *ExceptionPtrPtr) { QualType ObjectType = E->getType(); // Store the throw exception in the exception object. if (!CGF.hasAggregateLLVMType(ObjectType)) { llvm::Value *Value = CGF.EmitScalarExpr(E); - const llvm::Type *ValuePtrTy = Value->getType()->getPointerTo(0); - - CGF.Builder.CreateStore(Value, CGF.Builder.CreateBitCast(N, ValuePtrTy)); + const llvm::Type *ValuePtrTy = Value->getType()->getPointerTo(); + + CGF.Builder.CreateStore(Value, + CGF.Builder.CreateBitCast(DestPtr, ValuePtrTy)); } else { - const llvm::Type *Ty = CGF.ConvertType(ObjectType)->getPointerTo(0); - const CXXRecordDecl *RD; - RD = cast(ObjectType->getAs()->getDecl()); - llvm::Value *This = CGF.Builder.CreateBitCast(N, Ty); + const llvm::Type *Ty = CGF.ConvertType(ObjectType)->getPointerTo(); + const CXXRecordDecl *RD = + cast(ObjectType->getAs()->getDecl()); + + llvm::Value *This = CGF.Builder.CreateBitCast(DestPtr, Ty); if (RD->hasTrivialCopyConstructor()) { CGF.EmitAggExpr(E, This, false); } else if (CXXConstructorDecl *CopyCtor = RD->getCopyConstructor(CGF.getContext(), 0)) { - // FIXME: region management + llvm::BasicBlock *PrevLandingPad = CGF.getInvokeDest(); + if (CGF.Exceptions) { + CodeGenFunction::EHCleanupBlock Cleanup(CGF); + llvm::Constant *FreeExceptionFn = getFreeExceptionFn(CGF); + + // Load the exception pointer. + llvm::Value *ExceptionPtr = CGF.Builder.CreateLoad(ExceptionPtrPtr); + CGF.Builder.CreateCall(FreeExceptionFn, ExceptionPtr); + } + llvm::Value *Src = CGF.EmitLValue(E).getAddress(); + CGF.setInvokeDest(PrevLandingPad); + + llvm::BasicBlock *TerminateHandler = CGF.getTerminateHandler(); + PrevLandingPad = CGF.getInvokeDest(); + CGF.setInvokeDest(TerminateHandler); // Stolen from EmitClassAggrMemberwiseCopy llvm::Value *Callee = CGF.CGM.GetAddrOfCXXConstructor(CopyCtor, @@ -129,21 +180,22 @@ static void CopyObject(CodeGenFunction &CGF, const Expr *E, llvm::Value *N) { CopyCtor->getType()->getAs()->getResultType(); CGF.EmitCall(CGF.CGM.getTypes().getFunctionInfo(ResultType, CallArgs), Callee, CallArgs, CopyCtor); - // FIXME: region management + CGF.setInvokeDest(PrevLandingPad); } else - CGF.ErrorUnsupported(E, "uncopyable object"); + llvm_unreachable("uncopyable object"); } } // CopyObject - Utility to copy an object. Calls copy constructor as necessary. // N is casted to the right type. static void CopyObject(CodeGenFunction &CGF, QualType ObjectType, - llvm::Value *E, llvm::Value *N) { + bool WasPointer, llvm::Value *E, llvm::Value *N) { // Store the throw exception in the exception object. - if (!CGF.hasAggregateLLVMType(ObjectType)) { + if (WasPointer || !CGF.hasAggregateLLVMType(ObjectType)) { llvm::Value *Value = E; + if (!WasPointer) + Value = CGF.Builder.CreateLoad(Value); const llvm::Type *ValuePtrTy = Value->getType()->getPointerTo(0); - CGF.Builder.CreateStore(Value, CGF.Builder.CreateBitCast(N, ValuePtrTy)); } else { const llvm::Type *Ty = CGF.ConvertType(ObjectType)->getPointerTo(0); @@ -154,7 +206,6 @@ static void CopyObject(CodeGenFunction &CGF, QualType ObjectType, CGF.EmitAggregateCopy(This, E, ObjectType); } else if (CXXConstructorDecl *CopyCtor = RD->getCopyConstructor(CGF.getContext(), 0)) { - // FIXME: region management llvm::Value *Src = E; // Stolen from EmitClassAggrMemberwiseCopy @@ -171,98 +222,96 @@ static void CopyObject(CodeGenFunction &CGF, QualType ObjectType, CopyCtor->getType()->getAs()->getResultType(); CGF.EmitCall(CGF.CGM.getTypes().getFunctionInfo(ResultType, CallArgs), Callee, CallArgs, CopyCtor); - // FIXME: region management } else - llvm::llvm_unreachable("uncopyable object"); + llvm_unreachable("uncopyable object"); } } void CodeGenFunction::EmitCXXThrowExpr(const CXXThrowExpr *E) { if (!E->getSubExpr()) { - Builder.CreateCall(getReThrowFn(*this))->setDoesNotReturn(); + if (getInvokeDest()) { + llvm::BasicBlock *Cont = createBasicBlock("invoke.cont"); + Builder.CreateInvoke(getReThrowFn(*this), Cont, getInvokeDest()) + ->setDoesNotReturn(); + EmitBlock(Cont); + } else + Builder.CreateCall(getReThrowFn(*this))->setDoesNotReturn(); Builder.CreateUnreachable(); // Clear the insertion point to indicate we are in unreachable code. Builder.ClearInsertionPoint(); return; } - + QualType ThrowType = E->getSubExpr()->getType(); - // FIXME: Handle cleanup. - if (!CleanupEntries.empty()){ - ErrorUnsupported(E, "throw expression with cleanup entries"); - return; - } - + // Now allocate the exception object. const llvm::Type *SizeTy = ConvertType(getContext().getSizeType()); uint64_t TypeSize = getContext().getTypeSize(ThrowType) / 8; - + llvm::Constant *AllocExceptionFn = getAllocateExceptionFn(*this); - llvm::Value *ExceptionPtr = - Builder.CreateCall(AllocExceptionFn, + llvm::Value *ExceptionPtr = + Builder.CreateCall(AllocExceptionFn, llvm::ConstantInt::get(SizeTy, TypeSize), "exception"); - - CopyObject(*this, E->getSubExpr(), ExceptionPtr); + llvm::Value *ExceptionPtrPtr = + CreateTempAlloca(ExceptionPtr->getType(), "exception.ptr"); + Builder.CreateStore(ExceptionPtr, ExceptionPtrPtr); + + + CopyObject(*this, E->getSubExpr(), ExceptionPtr, ExceptionPtrPtr); + // Now throw the exception. const llvm::Type *Int8PtrTy = llvm::Type::getInt8PtrTy(getLLVMContext()); - llvm::Constant *TypeInfo = CGM.GenerateRtti(ThrowType); + llvm::Constant *TypeInfo = CGM.GenerateRTTI(ThrowType); llvm::Constant *Dtor = llvm::Constant::getNullValue(Int8PtrTy); - - llvm::CallInst *ThrowCall = - Builder.CreateCall3(getThrowFn(*this), ExceptionPtr, TypeInfo, Dtor); - ThrowCall->setDoesNotReturn(); + + if (getInvokeDest()) { + llvm::BasicBlock *Cont = createBasicBlock("invoke.cont"); + llvm::InvokeInst *ThrowCall = + Builder.CreateInvoke3(getThrowFn(*this), Cont, getInvokeDest(), + ExceptionPtr, TypeInfo, Dtor); + ThrowCall->setDoesNotReturn(); + EmitBlock(Cont); + } else { + llvm::CallInst *ThrowCall = + Builder.CreateCall3(getThrowFn(*this), ExceptionPtr, TypeInfo, Dtor); + ThrowCall->setDoesNotReturn(); + } Builder.CreateUnreachable(); - + // Clear the insertion point to indicate we are in unreachable code. Builder.ClearInsertionPoint(); + + // FIXME: For now, emit a dummy basic block because expr emitters in generally + // are not ready to handle emitting expressions at unreachable points. + EnsureInsertPoint(); } -void CodeGenFunction::EmitCXXTryStmt(const CXXTryStmt &S) { -#if 1 - EmitStmt(S.getTryBlock()); - if (0) { - getBeginCatchFn(*this); - getEndCatchFn(*this); - getUnwindResumeOrRethrowFn(*this); - CopyObject(*this, QualType(), 0, 0); - } -#else - // FIXME: The below is still just a sketch of the code we need. - // Pointer to the personality function +void CodeGenFunction::EmitStartEHSpec(const Decl *D) { + const FunctionDecl* FD = dyn_cast_or_null(D); + if (FD == 0) + return; + const FunctionProtoType *Proto = FD->getType()->getAs(); + if (Proto == 0) + return; + + assert(!Proto->hasAnyExceptionSpec() && "function with parameter pack"); + + if (!Proto->hasExceptionSpec()) + return; + llvm::Constant *Personality = CGM.CreateRuntimeFunction(llvm::FunctionType::get(llvm::Type::getInt32Ty (VMContext), true), "__gxx_personality_v0"); Personality = llvm::ConstantExpr::getBitCast(Personality, PtrToInt8Ty); - - llvm::BasicBlock *PrevLandingPad = getInvokeDest(); - llvm::BasicBlock *TryHandler = createBasicBlock("try.handler"); -#if 0 - llvm::BasicBlock *FinallyBlock = createBasicBlock("finally"); -#endif - llvm::BasicBlock *FinallyRethrow = createBasicBlock("finally.throw"); - llvm::BasicBlock *FinallyEnd = createBasicBlock("finally.end"); - -#if 0 - // Push an EH context entry, used for handling rethrows. - PushCleanupBlock(FinallyBlock); -#endif - - // Emit the statements in the try {} block - setInvokeDest(TryHandler); - - EmitStmt(S.getTryBlock()); - - // Jump to end if there is no exception - EmitBranchThroughCleanup(FinallyEnd); - - // Emit the handlers - EmitBlock(TryHandler); - + llvm::Value *llvm_eh_exception = + CGM.getIntrinsic(llvm::Intrinsic::eh_exception); + llvm::Value *llvm_eh_selector = + CGM.getIntrinsic(llvm::Intrinsic::eh_selector); const llvm::IntegerType *Int8Ty; const llvm::PointerType *PtrToInt8Ty; Int8Ty = llvm::Type::getInt8Ty(VMContext); @@ -270,16 +319,166 @@ void CodeGenFunction::EmitCXXTryStmt(const CXXTryStmt &S) { PtrToInt8Ty = llvm::PointerType::getUnqual(Int8Ty); llvm::Constant *Null = llvm::ConstantPointerNull::get(PtrToInt8Ty); llvm::SmallVector SelectorArgs; + + llvm::BasicBlock *PrevLandingPad = getInvokeDest(); + llvm::BasicBlock *EHSpecHandler = createBasicBlock("ehspec.handler"); + llvm::BasicBlock *Match = createBasicBlock("match"); + llvm::BasicBlock *Unwind = 0; + + assert(PrevLandingPad == 0 && "EHSpec has invoke context"); + (void)PrevLandingPad; + + llvm::BasicBlock *Cont = createBasicBlock("cont"); + + EmitBranchThroughCleanup(Cont); + + // Emit the statements in the try {} block + setInvokeDest(EHSpecHandler); + + EmitBlock(EHSpecHandler); + // Exception object + llvm::Value *Exc = Builder.CreateCall(llvm_eh_exception, "exc"); + llvm::Value *RethrowPtr = CreateTempAlloca(Exc->getType(), "_rethrow"); + + SelectorArgs.push_back(Exc); + SelectorArgs.push_back(Personality); + SelectorArgs.push_back(llvm::ConstantInt::get(llvm::Type::getInt32Ty(VMContext), + Proto->getNumExceptions()+1)); + + for (unsigned i = 0; i < Proto->getNumExceptions(); ++i) { + QualType Ty = Proto->getExceptionType(i); + llvm::Value *EHType + = CGM.GenerateRTTI(Ty.getNonReferenceType()); + SelectorArgs.push_back(EHType); + } + if (Proto->getNumExceptions()) + SelectorArgs.push_back(Null); + + // Find which handler was matched. + llvm::Value *Selector + = Builder.CreateCall(llvm_eh_selector, SelectorArgs.begin(), + SelectorArgs.end(), "selector"); + if (Proto->getNumExceptions()) { + Unwind = createBasicBlock("Unwind"); + + Builder.CreateStore(Exc, RethrowPtr); + Builder.CreateCondBr(Builder.CreateICmpSLT(Selector, + llvm::ConstantInt::get(llvm::Type::getInt32Ty(VMContext), + 0)), + Match, Unwind); + + EmitBlock(Match); + } + Builder.CreateCall(getUnexpectedFn(*this), Exc)->setDoesNotReturn(); + Builder.CreateUnreachable(); + + if (Proto->getNumExceptions()) { + EmitBlock(Unwind); + Builder.CreateCall(getUnwindResumeOrRethrowFn(*this), + Builder.CreateLoad(RethrowPtr)); + Builder.CreateUnreachable(); + } + + EmitBlock(Cont); +} + +void CodeGenFunction::EmitEndEHSpec(const Decl *D) { + const FunctionDecl* FD = dyn_cast_or_null(D); + if (FD == 0) + return; + const FunctionProtoType *Proto = FD->getType()->getAs(); + if (Proto == 0) + return; + + if (!Proto->hasExceptionSpec()) + return; + + setInvokeDest(0); +} + +void CodeGenFunction::EmitCXXTryStmt(const CXXTryStmt &S) { + // Pointer to the personality function + llvm::Constant *Personality = + CGM.CreateRuntimeFunction(llvm::FunctionType::get(llvm::Type::getInt32Ty + (VMContext), + true), + "__gxx_personality_v0"); + Personality = llvm::ConstantExpr::getBitCast(Personality, PtrToInt8Ty); llvm::Value *llvm_eh_exception = CGM.getIntrinsic(llvm::Intrinsic::eh_exception); llvm::Value *llvm_eh_selector = CGM.getIntrinsic(llvm::Intrinsic::eh_selector); + + llvm::BasicBlock *PrevLandingPad = getInvokeDest(); + llvm::BasicBlock *TryHandler = createBasicBlock("try.handler"); + llvm::BasicBlock *FinallyBlock = createBasicBlock("finally"); + llvm::BasicBlock *FinallyRethrow = createBasicBlock("finally.throw"); + llvm::BasicBlock *FinallyEnd = createBasicBlock("finally.end"); + + // Push an EH context entry, used for handling rethrows. + PushCleanupBlock(FinallyBlock); + + // Emit the statements in the try {} block + setInvokeDest(TryHandler); + + // FIXME: We should not have to do this here. The AST should have the member + // initializers under the CXXTryStmt's TryBlock. + if (OuterTryBlock == &S) { + GlobalDecl GD = CurGD; + const FunctionDecl *FD = cast(GD.getDecl()); + + if (const CXXConstructorDecl *CD = dyn_cast(FD)) { + size_t OldCleanupStackSize = CleanupEntries.size(); + EmitCtorPrologue(CD, CurGD.getCtorType()); + EmitStmt(S.getTryBlock()); + + // If any of the member initializers are temporaries bound to references + // make sure to emit their destructors. + EmitCleanupBlocks(OldCleanupStackSize); + } else if (const CXXDestructorDecl *DD = dyn_cast(FD)) { + llvm::BasicBlock *DtorEpilogue = createBasicBlock("dtor.epilogue"); + PushCleanupBlock(DtorEpilogue); + + EmitStmt(S.getTryBlock()); + + CleanupBlockInfo Info = PopCleanupBlock(); + + assert(Info.CleanupBlock == DtorEpilogue && "Block mismatch!"); + EmitBlock(DtorEpilogue); + EmitDtorEpilogue(DD, GD.getDtorType()); + + if (Info.SwitchBlock) + EmitBlock(Info.SwitchBlock); + if (Info.EndBlock) + EmitBlock(Info.EndBlock); + } else + EmitStmt(S.getTryBlock()); + } else + EmitStmt(S.getTryBlock()); + + // Jump to end if there is no exception + EmitBranchThroughCleanup(FinallyEnd); + + llvm::BasicBlock *TerminateHandler = getTerminateHandler(); + + // Emit the handlers + EmitBlock(TryHandler); + + const llvm::IntegerType *Int8Ty; + const llvm::PointerType *PtrToInt8Ty; + Int8Ty = llvm::Type::getInt8Ty(VMContext); + // C string type. Used in lots of places. + PtrToInt8Ty = llvm::PointerType::getUnqual(Int8Ty); + llvm::Constant *Null = llvm::ConstantPointerNull::get(PtrToInt8Ty); + llvm::SmallVector SelectorArgs; llvm::Value *llvm_eh_typeid_for = CGM.getIntrinsic(llvm::Intrinsic::eh_typeid_for); // Exception object llvm::Value *Exc = Builder.CreateCall(llvm_eh_exception, "exc"); llvm::Value *RethrowPtr = CreateTempAlloca(Exc->getType(), "_rethrow"); + llvm::SmallVector Args; + Args.clear(); SelectorArgs.push_back(Exc); SelectorArgs.push_back(Personality); @@ -288,7 +487,8 @@ void CodeGenFunction::EmitCXXTryStmt(const CXXTryStmt &S) { const CXXCatchStmt *C = S.getHandler(i); VarDecl *CatchParam = C->getExceptionDecl(); if (CatchParam) { - llvm::Value *EHType = CGM.GenerateRtti(C->getCaughtType().getNonReferenceType()); + llvm::Value *EHType + = CGM.GenerateRTTI(C->getCaughtType().getNonReferenceType()); SelectorArgs.push_back(EHType); } else { // null indicates catch all @@ -334,27 +534,31 @@ void CodeGenFunction::EmitCXXTryStmt(const CXXTryStmt &S) { llvm::Value *ExcObject = Builder.CreateCall(getBeginCatchFn(*this), Exc); - // Bind the catch parameter if it exists. - if (CatchParam) { - QualType CatchType = CatchParam->getType().getNonReferenceType(); - if (!CatchType.getTypePtr()->isPointerType()) - CatchType = getContext().getPointerType(CatchType); - ExcObject = - Builder.CreateBitCast(ExcObject, ConvertType(CatchType)); - // CatchParam is a ParmVarDecl because of the grammar - // construction used to handle this, but for codegen purposes - // we treat this as a local decl. - EmitLocalBlockVarDecl(*CatchParam); -#if 0 - // FIXME: objects with ctors, references - Builder.CreateStore(ExcObject, GetAddrOfLocalVar(CatchParam)); -#else - CopyObject(*this, CatchParam->getType().getNonReferenceType(), - ExcObject, GetAddrOfLocalVar(CatchParam)); -#endif + { + CleanupScope CatchScope(*this); + // Bind the catch parameter if it exists. + if (CatchParam) { + QualType CatchType = CatchParam->getType().getNonReferenceType(); + setInvokeDest(TerminateHandler); + bool WasPointer = true; + if (!CatchType.getTypePtr()->isPointerType()) { + if (!isa(CatchParam->getType())) + WasPointer = false; + CatchType = getContext().getPointerType(CatchType); + } + ExcObject = Builder.CreateBitCast(ExcObject, ConvertType(CatchType)); + EmitLocalBlockVarDecl(*CatchParam); + // FIXME: we need to do this sooner so that the EH region for the + // cleanup doesn't start until after the ctor completes, use a decl + // init? + CopyObject(*this, CatchParam->getType().getNonReferenceType(), + WasPointer, ExcObject, GetAddrOfLocalVar(CatchParam)); + setInvokeDest(MatchHandler); + } + + EmitStmt(CatchBody); } - EmitStmt(CatchBody); EmitBranchThroughCleanup(FinallyEnd); EmitBlock(MatchHandler); @@ -362,7 +566,7 @@ void CodeGenFunction::EmitCXXTryStmt(const CXXTryStmt &S) { llvm::Value *Exc = Builder.CreateCall(llvm_eh_exception, "exc"); // We are required to emit this call to satisfy LLVM, even // though we don't use the result. - llvm::SmallVector Args; + Args.clear(); Args.push_back(Exc); Args.push_back(Personality); Args.push_back(llvm::ConstantInt::get(llvm::Type::getInt32Ty(VMContext), @@ -375,45 +579,32 @@ void CodeGenFunction::EmitCXXTryStmt(const CXXTryStmt &S) { EmitBlock(MatchEnd); - // Unfortunately, we also have to generate another EH frame here - // in case this throws. - llvm::BasicBlock *MatchEndHandler = - createBasicBlock("match.end.handler"); - llvm::BasicBlock *Cont = createBasicBlock("myinvoke.cont"); + llvm::BasicBlock *Cont = createBasicBlock("invoke.cont"); Builder.CreateInvoke(getEndCatchFn(*this), - Cont, MatchEndHandler, + Cont, TerminateHandler, Args.begin(), Args.begin()); - EmitBlock(Cont); if (Info.SwitchBlock) EmitBlock(Info.SwitchBlock); if (Info.EndBlock) EmitBlock(Info.EndBlock); - EmitBlock(MatchEndHandler); Exc = Builder.CreateCall(llvm_eh_exception, "exc"); - // We are required to emit this call to satisfy LLVM, even - // though we don't use the result. - Args.clear(); - Args.push_back(Exc); - Args.push_back(Personality); - Args.push_back(llvm::ConstantInt::get(llvm::Type::getInt32Ty(VMContext), - 0)); - Builder.CreateCall(llvm_eh_selector, Args.begin(), Args.end()); Builder.CreateStore(Exc, RethrowPtr); EmitBranchThroughCleanup(FinallyRethrow); if (Next) EmitBlock(Next); } - if (!HasCatchAll) + if (!HasCatchAll) { + Builder.CreateStore(Exc, RethrowPtr); EmitBranchThroughCleanup(FinallyRethrow); + } CodeGenFunction::CleanupBlockInfo Info = PopCleanupBlock(); setInvokeDest(PrevLandingPad); -#if 0 EmitBlock(FinallyBlock); if (Info.SwitchBlock) @@ -423,13 +614,122 @@ void CodeGenFunction::EmitCXXTryStmt(const CXXTryStmt &S) { // Branch around the rethrow code. EmitBranch(FinallyEnd); -#endif EmitBlock(FinallyRethrow); - Builder.CreateCall(getUnwindResumeOrRethrowFn(*this), - Builder.CreateLoad(RethrowPtr)); + // FIXME: Eventually we can chain the handlers together and just do a call + // here. + if (getInvokeDest()) { + llvm::BasicBlock *Cont = createBasicBlock("invoke.cont"); + Builder.CreateInvoke(getUnwindResumeOrRethrowFn(*this), Cont, + getInvokeDest(), + Builder.CreateLoad(RethrowPtr)); + EmitBlock(Cont); + } else + Builder.CreateCall(getUnwindResumeOrRethrowFn(*this), + Builder.CreateLoad(RethrowPtr)); + Builder.CreateUnreachable(); EmitBlock(FinallyEnd); -#endif +} + +CodeGenFunction::EHCleanupBlock::~EHCleanupBlock() { + llvm::BasicBlock *Cont1 = CGF.createBasicBlock("cont"); + CGF.EmitBranch(Cont1); + CGF.setInvokeDest(PreviousInvokeDest); + + + CGF.EmitBlock(CleanupHandler); + + llvm::Constant *Personality = + CGF.CGM.CreateRuntimeFunction(llvm::FunctionType::get(llvm::Type::getInt32Ty + (CGF.VMContext), + true), + "__gxx_personality_v0"); + Personality = llvm::ConstantExpr::getBitCast(Personality, CGF.PtrToInt8Ty); + llvm::Value *llvm_eh_exception = + CGF.CGM.getIntrinsic(llvm::Intrinsic::eh_exception); + llvm::Value *llvm_eh_selector = + CGF.CGM.getIntrinsic(llvm::Intrinsic::eh_selector); + + llvm::Value *Exc = CGF.Builder.CreateCall(llvm_eh_exception, "exc"); + const llvm::IntegerType *Int8Ty; + const llvm::PointerType *PtrToInt8Ty; + Int8Ty = llvm::Type::getInt8Ty(CGF.VMContext); + // C string type. Used in lots of places. + PtrToInt8Ty = llvm::PointerType::getUnqual(Int8Ty); + llvm::Constant *Null = llvm::ConstantPointerNull::get(PtrToInt8Ty); + llvm::SmallVector Args; + Args.clear(); + Args.push_back(Exc); + Args.push_back(Personality); + Args.push_back(Null); + CGF.Builder.CreateCall(llvm_eh_selector, Args.begin(), Args.end()); + + CGF.EmitBlock(CleanupEntryBB); + + CGF.EmitBlock(Cont1); + + if (CGF.getInvokeDest()) { + llvm::BasicBlock *Cont = CGF.createBasicBlock("invoke.cont"); + CGF.Builder.CreateInvoke(getUnwindResumeOrRethrowFn(CGF), Cont, + CGF.getInvokeDest(), Exc); + CGF.EmitBlock(Cont); + } else + CGF.Builder.CreateCall(getUnwindResumeOrRethrowFn(CGF), Exc); + + CGF.Builder.CreateUnreachable(); + + CGF.EmitBlock(Cont); + if (CGF.Exceptions) + CGF.setInvokeDest(CleanupHandler); +} + +llvm::BasicBlock *CodeGenFunction::getTerminateHandler() { + if (TerminateHandler) + return TerminateHandler; + + llvm::BasicBlock *Cont = 0; + + if (HaveInsertPoint()) { + Cont = createBasicBlock("cont"); + EmitBranch(Cont); + } + + llvm::Constant *Personality = + CGM.CreateRuntimeFunction(llvm::FunctionType::get(llvm::Type::getInt32Ty + (VMContext), + true), + "__gxx_personality_v0"); + Personality = llvm::ConstantExpr::getBitCast(Personality, PtrToInt8Ty); + llvm::Value *llvm_eh_exception = + CGM.getIntrinsic(llvm::Intrinsic::eh_exception); + llvm::Value *llvm_eh_selector = + CGM.getIntrinsic(llvm::Intrinsic::eh_selector); + + // Set up terminate handler + TerminateHandler = createBasicBlock("terminate.handler"); + EmitBlock(TerminateHandler); + llvm::Value *Exc = Builder.CreateCall(llvm_eh_exception, "exc"); + // We are required to emit this call to satisfy LLVM, even + // though we don't use the result. + llvm::SmallVector Args; + Args.push_back(Exc); + Args.push_back(Personality); + Args.push_back(llvm::ConstantInt::get(llvm::Type::getInt32Ty(VMContext), + 1)); + Builder.CreateCall(llvm_eh_selector, Args.begin(), Args.end()); + llvm::CallInst *TerminateCall = + Builder.CreateCall(getTerminateFn(*this)); + TerminateCall->setDoesNotReturn(); + TerminateCall->setDoesNotThrow(); + Builder.CreateUnreachable(); + + // Clear the insertion point to indicate we are in unreachable code. + Builder.ClearInsertionPoint(); + + if (Cont) + EmitBlock(Cont); + + return TerminateHandler; } diff --git a/lib/CodeGen/CGExpr.cpp b/lib/CodeGen/CGExpr.cpp index 63fca2d4ddab..e6bbfa8063fa 100644 --- a/lib/CodeGen/CGExpr.cpp +++ b/lib/CodeGen/CGExpr.cpp @@ -17,6 +17,8 @@ #include "CGObjCRuntime.h" #include "clang/AST/ASTContext.h" #include "clang/AST/DeclObjC.h" +#include "llvm/Intrinsics.h" +#include "clang/CodeGen/CodeGenOptions.h" #include "llvm/Target/TargetData.h" using namespace clang; using namespace CodeGen; @@ -38,6 +40,21 @@ llvm::AllocaInst *CodeGenFunction::CreateTempAlloca(const llvm::Type *Ty, /// expression and compare the result against zero, returning an Int1Ty value. llvm::Value *CodeGenFunction::EvaluateExprAsBool(const Expr *E) { QualType BoolTy = getContext().BoolTy; + if (E->getType()->isMemberFunctionPointerType()) { + llvm::Value *Ptr = CreateTempAlloca(ConvertType(E->getType())); + EmitAggExpr(E, Ptr, /*VolatileDest=*/false); + + // Get the pointer. + llvm::Value *FuncPtr = Builder.CreateStructGEP(Ptr, 0, "src.ptr"); + FuncPtr = Builder.CreateLoad(FuncPtr); + + llvm::Value *IsNotNull = + Builder.CreateICmpNE(FuncPtr, + llvm::Constant::getNullValue(FuncPtr->getType()), + "tobool"); + + return IsNotNull; + } if (!E->getType()->isAnyComplexType()) return EmitScalarConversion(EmitScalarExpr(E), E->getType(), BoolTy); @@ -137,8 +154,19 @@ RValue CodeGenFunction::EmitReferenceBindingToExpr(const Expr* E, const CXXDestructorDecl *Dtor = ClassDecl->getDestructor(getContext()); - DelayedCleanupBlock scope(*this); - EmitCXXDestructorCall(Dtor, Dtor_Complete, Val.getAggregateAddr()); + { + DelayedCleanupBlock Scope(*this); + EmitCXXDestructorCall(Dtor, Dtor_Complete, + Val.getAggregateAddr()); + + // Make sure to jump to the exit block. + EmitBranch(Scope.getCleanupExitBlock()); + } + if (Exceptions) { + EHCleanupBlock Cleanup(*this); + EmitCXXDestructorCall(Dtor, Dtor_Complete, + Val.getAggregateAddr()); + } } } } @@ -237,6 +265,8 @@ LValue CodeGenFunction::EmitLValue(const Expr *E) { switch (E->getStmtClass()) { default: return EmitUnsupportedLValue(E, "l-value expression"); + case Expr::ObjCIsaExprClass: + return EmitObjCIsaExpr(cast(E)); case Expr::BinaryOperatorClass: return EmitBinaryOperatorLValue(cast(E)); case Expr::CallExprClass: @@ -330,13 +360,8 @@ void CodeGenFunction::EmitStoreOfScalar(llvm::Value *Value, llvm::Value *Addr, if (Ty->isBooleanType()) { // Bool can have different representation in memory than in registers. - const llvm::Type *SrcTy = Value->getType(); const llvm::PointerType *DstPtr = cast(Addr->getType()); - if (DstPtr->getElementType() != SrcTy) { - const llvm::Type *MemTy = - llvm::PointerType::get(SrcTy, DstPtr->getAddressSpace()); - Addr = Builder.CreateBitCast(Addr, MemTy, "storetmp"); - } + Value = Builder.CreateIntCast(Value, DstPtr->getElementType(), false); } Builder.CreateStore(Value, Addr, Volatile); } @@ -408,8 +433,7 @@ RValue CodeGenFunction::EmitLoadOfBitfieldLValue(LValue LV, // Shift to proper location. if (StartBit) - Val = Builder.CreateLShr(Val, llvm::ConstantInt::get(EltTy, StartBit), - "bf.lo"); + Val = Builder.CreateLShr(Val, StartBit, "bf.lo"); // Mask off unused bits. llvm::Constant *LowMask = llvm::ConstantInt::get(VMContext, @@ -431,8 +455,7 @@ RValue CodeGenFunction::EmitLoadOfBitfieldLValue(LValue LV, HighVal = Builder.CreateAnd(HighVal, HighMask, "bf.lo.cleared"); // Shift to proper location and or in to bitfield value. - HighVal = Builder.CreateShl(HighVal, - llvm::ConstantInt::get(EltTy, LowBits)); + HighVal = Builder.CreateShl(HighVal, LowBits); Val = Builder.CreateOr(Val, HighVal, "bf.val"); } @@ -618,8 +641,7 @@ void CodeGenFunction::EmitStoreThroughBitfieldLValue(RValue Src, LValue Dst, // LowVal = (LowVal & InvMask) | (NewVal << StartBit), // with the shift of NewVal implicitly stripping the high bits. llvm::Value *NewLowVal = - Builder.CreateShl(NewVal, llvm::ConstantInt::get(EltTy, StartBit), - "bf.value.lo"); + Builder.CreateShl(NewVal, StartBit, "bf.value.lo"); LowVal = Builder.CreateAnd(LowVal, InvMask, "bf.prev.lo.cleared"); LowVal = Builder.CreateOr(LowVal, NewLowVal, "bf.new.lo"); @@ -645,8 +667,7 @@ void CodeGenFunction::EmitStoreThroughBitfieldLValue(RValue Src, LValue Dst, // where the high bits of NewVal have already been cleared and the // shift stripping the low bits. llvm::Value *NewHighVal = - Builder.CreateLShr(NewVal, llvm::ConstantInt::get(EltTy, LowBits), - "bf.value.high"); + Builder.CreateLShr(NewVal, LowBits, "bf.value.high"); HighVal = Builder.CreateAnd(HighVal, InvMask, "bf.prev.hi.cleared"); HighVal = Builder.CreateOr(HighVal, NewHighVal, "bf.new.hi"); @@ -993,6 +1014,36 @@ LValue CodeGenFunction::EmitPredefinedLValue(const PredefinedExpr *E) { } } +llvm::BasicBlock *CodeGenFunction::getTrapBB() { + const CodeGenOptions &GCO = CGM.getCodeGenOpts(); + + // If we are not optimzing, don't collapse all calls to trap in the function + // to the same call, that way, in the debugger they can see which operation + // did in fact fail. If we are optimizing, we collpase all call to trap down + // to just one per function to save on codesize. + if (GCO.OptimizationLevel + && TrapBB) + return TrapBB; + + llvm::BasicBlock *Cont = 0; + if (HaveInsertPoint()) { + Cont = createBasicBlock("cont"); + EmitBranch(Cont); + } + TrapBB = createBasicBlock("trap"); + EmitBlock(TrapBB); + + llvm::Value *F = CGM.getIntrinsic(llvm::Intrinsic::trap, 0, 0); + llvm::CallInst *TrapCall = Builder.CreateCall(F); + TrapCall->setDoesNotReturn(); + TrapCall->setDoesNotThrow(); + Builder.CreateUnreachable(); + + if (Cont) + EmitBlock(Cont); + return TrapBB; +} + LValue CodeGenFunction::EmitArraySubscriptExpr(const ArraySubscriptExpr *E) { // The index must always be an integer, which is not an aggregate. Emit it. llvm::Value *Idx = EmitScalarExpr(E->getIdx()); @@ -1021,6 +1072,24 @@ LValue CodeGenFunction::EmitArraySubscriptExpr(const ArraySubscriptExpr *E) { llvm::IntegerType::get(VMContext, LLVMPointerWidth), IdxSigned, "idxprom"); + if (CatchUndefined) { + if (const ImplicitCastExpr *ICE = dyn_cast(E->getBase())) { + if (const DeclRefExpr *DRE = dyn_cast(ICE->getSubExpr())) { + if (ICE->getCastKind() == CastExpr::CK_ArrayToPointerDecay) { + if (const ConstantArrayType *CAT + = getContext().getAsConstantArrayType(DRE->getType())) { + llvm::APInt Size = CAT->getSize(); + llvm::BasicBlock *Cont = createBasicBlock("cont"); + Builder.CreateCondBr(Builder.CreateICmpULE(Idx, + llvm::ConstantInt::get(Idx->getType(), Size)), + Cont, getTrapBB()); + EmitBlock(Cont); + } + } + } + } + } + // We know that the pointer points to a type of the correct size, unless the // size is a VLA or Objective-C interface. llvm::Value *Address = 0; @@ -1417,7 +1486,7 @@ RValue CodeGenFunction::EmitCallExpr(const CallExpr *E) { if (const CXXMethodDecl *MD = dyn_cast_or_null(TargetDecl)) return EmitCXXOperatorMemberCallExpr(CE, MD); - if (isa(E->getCallee())) { + if (isa(E->getCallee()->IgnoreParens())) { // C++ [expr.pseudo]p1: // The result shall only be used as the operand for the function call // operator (), and the result of such a call has type void. The only @@ -1436,6 +1505,7 @@ LValue CodeGenFunction::EmitBinaryOperatorLValue(const BinaryOperator *E) { // Comma expressions just emit their LHS then their RHS as an l-value. if (E->getOpcode() == BinaryOperator::Comma) { EmitAnyExpr(E->getLHS()); + EnsureInsertPoint(); return EmitLValue(E->getRHS()); } diff --git a/lib/CodeGen/CGExprAgg.cpp b/lib/CodeGen/CGExprAgg.cpp index d225d907c8ae..2c122ebe13dd 100644 --- a/lib/CodeGen/CGExprAgg.cpp +++ b/lib/CodeGen/CGExprAgg.cpp @@ -120,7 +120,7 @@ class AggExprEmitter : public StmtVisitor { void EmitInitializationToLValue(Expr *E, LValue Address); void EmitNullInitializationToLValue(LValue Address, QualType T); // case Expr::ChooseExprClass: - + void VisitCXXThrowExpr(const CXXThrowExpr *E) { CGF.EmitCXXThrowExpr(E); } }; } // end anonymous namespace. @@ -502,21 +502,16 @@ void AggExprEmitter::EmitNullInitializationToLValue(LValue LV, QualType T) { void AggExprEmitter::VisitInitListExpr(InitListExpr *E) { #if 0 - // FIXME: Disabled while we figure out what to do about - // test/CodeGen/bitfield.c + // FIXME: Assess perf here? Figure out what cases are worth optimizing here + // (Length of globals? Chunks of zeroed-out space?). // // If we can, prefer a copy from a global; this is a lot less code for long // globals, and it's easier for the current optimizers to analyze. - // FIXME: Should we really be doing this? Should we try to avoid cases where - // we emit a global with a lot of zeros? Should we try to avoid short - // globals? - if (E->isConstantInitializer(CGF.getContext(), 0)) { - llvm::Constant* C = CGF.CGM.EmitConstantExpr(E, &CGF); + if (llvm::Constant* C = CGF.CGM.EmitConstantExpr(E, E->getType(), &CGF)) { llvm::GlobalVariable* GV = - new llvm::GlobalVariable(C->getType(), true, - llvm::GlobalValue::InternalLinkage, - C, "", &CGF.CGM.getModule(), 0); - EmitFinalDestCopy(E, LValue::MakeAddr(GV, 0)); + new llvm::GlobalVariable(CGF.CGM.getModule(), C->getType(), true, + llvm::GlobalValue::InternalLinkage, C, ""); + EmitFinalDestCopy(E, LValue::MakeAddr(GV, Qualifiers())); return; } #endif diff --git a/lib/CodeGen/CGExprCXX.cpp b/lib/CodeGen/CGExprCXX.cpp index b982c15683ec..150f11ebf575 100644 --- a/lib/CodeGen/CGExprCXX.cpp +++ b/lib/CodeGen/CGExprCXX.cpp @@ -15,13 +15,8 @@ using namespace clang; using namespace CodeGen; -static uint64_t CalculateCookiePadding(ASTContext &Ctx, const CXXNewExpr *E) { - if (!E->isArray()) - return 0; - - QualType T = E->getAllocatedType(); - - const RecordType *RT = T->getAs(); +static uint64_t CalculateCookiePadding(ASTContext &Ctx, QualType ElementType) { + const RecordType *RT = ElementType->getAs(); if (!RT) return 0; @@ -31,13 +26,59 @@ static uint64_t CalculateCookiePadding(ASTContext &Ctx, const CXXNewExpr *E) { // Check if the class has a trivial destructor. if (RD->hasTrivialDestructor()) { - // FIXME: Check for a two-argument delete. - return 0; - } + // Check if the usual deallocation function takes two arguments. + const CXXMethodDecl *UsualDeallocationFunction = 0; + + DeclarationName OpName = + Ctx.DeclarationNames.getCXXOperatorName(OO_Array_Delete); + DeclContext::lookup_const_iterator Op, OpEnd; + for (llvm::tie(Op, OpEnd) = RD->lookup(OpName); + Op != OpEnd; ++Op) { + const CXXMethodDecl *Delete = cast(*Op); + + if (Delete->isUsualDeallocationFunction()) { + UsualDeallocationFunction = Delete; + break; + } + } + + // No usual deallocation function, we don't need a cookie. + if (!UsualDeallocationFunction) + return 0; + + // The usual deallocation function doesn't take a size_t argument, so we + // don't need a cookie. + if (UsualDeallocationFunction->getNumParams() == 1) + return 0; + + assert(UsualDeallocationFunction->getNumParams() == 2 && + "Unexpected deallocation function type!"); + } - // Padding is the maximum of sizeof(size_t) and alignof(T) + // Padding is the maximum of sizeof(size_t) and alignof(ElementType) return std::max(Ctx.getTypeSize(Ctx.getSizeType()), - static_cast(Ctx.getTypeAlign(T))) / 8; + static_cast(Ctx.getTypeAlign(ElementType))) / 8; +} + +static uint64_t CalculateCookiePadding(ASTContext &Ctx, const CXXNewExpr *E) { + if (!E->isArray()) + return 0; + + // No cookie is required if the new operator being used is + // ::operator new[](size_t, void*). + const FunctionDecl *OperatorNew = E->getOperatorNew(); + if (OperatorNew->getDeclContext()->getLookupContext()->isFileContext()) { + if (OperatorNew->getNumParams() == 2) { + CanQualType ParamType = + Ctx.getCanonicalType(OperatorNew->getParamDecl(1)->getType()); + + if (ParamType == Ctx.VoidPtrTy) + return 0; + } + } + + return CalculateCookiePadding(Ctx, E->getAllocatedType()); + QualType T = E->getAllocatedType(); } static llvm::Value *EmitCXXNewAllocSize(CodeGenFunction &CGF, @@ -237,6 +278,39 @@ llvm::Value *CodeGenFunction::EmitCXXNewExpr(const CXXNewExpr *E) { return NewPtr; } +static std::pair +GetAllocatedObjectPtrAndNumElements(CodeGenFunction &CGF, + llvm::Value *Ptr, QualType DeleteTy) { + QualType SizeTy = CGF.getContext().getSizeType(); + const llvm::Type *SizeLTy = CGF.ConvertType(SizeTy); + + uint64_t DeleteTypeAlign = CGF.getContext().getTypeAlign(DeleteTy); + uint64_t CookiePadding = std::max(CGF.getContext().getTypeSize(SizeTy), + DeleteTypeAlign) / 8; + assert(CookiePadding && "CookiePadding should not be 0."); + + const llvm::Type *Int8PtrTy = llvm::Type::getInt8PtrTy(CGF.getLLVMContext()); + uint64_t CookieOffset = + CookiePadding - CGF.getContext().getTypeSize(SizeTy) / 8; + + llvm::Value *AllocatedObjectPtr = CGF.Builder.CreateBitCast(Ptr, Int8PtrTy); + AllocatedObjectPtr = + CGF.Builder.CreateConstInBoundsGEP1_64(AllocatedObjectPtr, + -CookiePadding); + + llvm::Value *NumElementsPtr = + CGF.Builder.CreateConstInBoundsGEP1_64(AllocatedObjectPtr, + CookieOffset); + NumElementsPtr = + CGF.Builder.CreateBitCast(NumElementsPtr, SizeLTy->getPointerTo()); + + llvm::Value *NumElements = CGF.Builder.CreateLoad(NumElementsPtr); + NumElements = + CGF.Builder.CreateIntCast(NumElements, SizeLTy, /*isSigned=*/false); + + return std::make_pair(AllocatedObjectPtr, NumElements); +} + void CodeGenFunction::EmitDeleteCall(const FunctionDecl *DeleteFD, llvm::Value *Ptr, QualType DeleteTy) { @@ -245,17 +319,37 @@ void CodeGenFunction::EmitDeleteCall(const FunctionDecl *DeleteFD, CallArgList DeleteArgs; + // Check if we need to pass the size to the delete operator. + llvm::Value *Size = 0; + QualType SizeTy; + if (DeleteFTy->getNumArgs() == 2) { + SizeTy = DeleteFTy->getArgType(1); + uint64_t DeleteTypeSize = getContext().getTypeSize(DeleteTy) / 8; + Size = llvm::ConstantInt::get(ConvertType(SizeTy), DeleteTypeSize); + } + + if (DeleteFD->getOverloadedOperator() == OO_Array_Delete && + + CalculateCookiePadding(getContext(), DeleteTy)) { + // We need to get the number of elements in the array from the cookie. + llvm::Value *AllocatedObjectPtr; + llvm::Value *NumElements; + llvm::tie(AllocatedObjectPtr, NumElements) = + GetAllocatedObjectPtrAndNumElements(*this, Ptr, DeleteTy); + + // Multiply the size with the number of elements. + if (Size) + Size = Builder.CreateMul(NumElements, Size); + + Ptr = AllocatedObjectPtr; + } + QualType ArgTy = DeleteFTy->getArgType(0); llvm::Value *DeletePtr = Builder.CreateBitCast(Ptr, ConvertType(ArgTy)); DeleteArgs.push_back(std::make_pair(RValue::get(DeletePtr), ArgTy)); - if (DeleteFTy->getNumArgs() == 2) { - QualType SizeTy = DeleteFTy->getArgType(1); - uint64_t SizeVal = getContext().getTypeSize(DeleteTy) / 8; - llvm::Constant *Size = llvm::ConstantInt::get(ConvertType(SizeTy), - SizeVal); + if (Size) DeleteArgs.push_back(std::make_pair(RValue::get(Size), SizeTy)); - } // Emit the call to delete. EmitCall(CGM.getTypes().getFunctionInfo(DeleteFTy->getResultType(), @@ -300,34 +394,13 @@ void CodeGenFunction::EmitCXXDeleteExpr(const CXXDeleteExpr *E) { if (!RD->hasTrivialDestructor()) { const CXXDestructorDecl *Dtor = RD->getDestructor(getContext()); if (E->isArrayForm()) { - QualType SizeTy = getContext().getSizeType(); - uint64_t CookiePadding = std::max(getContext().getTypeSize(SizeTy), - static_cast(getContext().getTypeAlign(DeleteTy))) / 8; - if (CookiePadding) { - llvm::Type *Ptr8Ty = - llvm::PointerType::get(llvm::Type::getInt8Ty(VMContext), 0); - uint64_t CookieOffset = - CookiePadding - getContext().getTypeSize(SizeTy) / 8; - llvm::Value *AllocatedObjectPtr = - Builder.CreateConstInBoundsGEP1_64( - Builder.CreateBitCast(Ptr, Ptr8Ty), -CookiePadding); - llvm::Value *NumElementsPtr = - Builder.CreateConstInBoundsGEP1_64(AllocatedObjectPtr, - CookieOffset); - NumElementsPtr = Builder.CreateBitCast(NumElementsPtr, - ConvertType(SizeTy)->getPointerTo()); - - llvm::Value *NumElements = - Builder.CreateLoad(NumElementsPtr); - NumElements = - Builder.CreateIntCast(NumElements, - llvm::Type::getInt64Ty(VMContext), false, - "count.tmp"); - EmitCXXAggrDestructorCall(Dtor, NumElements, Ptr); - Ptr = AllocatedObjectPtr; - } - } - else if (Dtor->isVirtual()) { + llvm::Value *AllocatedObjectPtr; + llvm::Value *NumElements; + llvm::tie(AllocatedObjectPtr, NumElements) = + GetAllocatedObjectPtrAndNumElements(*this, Ptr, DeleteTy); + + EmitCXXAggrDestructorCall(Dtor, NumElements, Ptr); + } else if (Dtor->isVirtual()) { const llvm::Type *Ty = CGM.getTypes().GetFunctionType(CGM.getTypes().getFunctionInfo(Dtor), /*isVariadic=*/false); @@ -352,18 +425,10 @@ void CodeGenFunction::EmitCXXDeleteExpr(const CXXDeleteExpr *E) { llvm::Value * CodeGenFunction::EmitCXXTypeidExpr(const CXXTypeidExpr *E) { QualType Ty = E->getType(); const llvm::Type *LTy = ConvertType(Ty)->getPointerTo(); - if (E->isTypeOperand()) { - Ty = E->getTypeOperand(); - CanQualType CanTy = CGM.getContext().getCanonicalType(Ty); - Ty = CanTy.getUnqualifiedType().getNonReferenceType(); - if (const RecordType *RT = Ty->getAs()) { - const CXXRecordDecl *RD = cast(RT->getDecl()); - if (RD->isPolymorphic()) - return Builder.CreateBitCast(CGM.GenerateRttiRef(RD), LTy); - return Builder.CreateBitCast(CGM.GenerateRtti(RD), LTy); - } - return Builder.CreateBitCast(CGM.GenerateRtti(Ty), LTy); - } + + if (E->isTypeOperand()) + return Builder.CreateBitCast(CGM.GetAddrOfRTTI(E->getTypeOperand()), LTy); + Expr *subE = E->getExprOperand(); Ty = subE->getType(); CanQualType CanTy = CGM.getContext().getCanonicalType(Ty); @@ -404,9 +469,9 @@ llvm::Value * CodeGenFunction::EmitCXXTypeidExpr(const CXXTypeidExpr *E) { V = Builder.CreateLoad(V); return V; } - return Builder.CreateBitCast(CGM.GenerateRtti(RD), LTy); + return Builder.CreateBitCast(CGM.GenerateRTTI(RD), LTy); } - return Builder.CreateBitCast(CGM.GenerateRtti(Ty), LTy); + return Builder.CreateBitCast(CGM.GenerateRTTI(Ty), LTy); } llvm::Value *CodeGenFunction::EmitDynamicCast(llvm::Value *V, @@ -485,8 +550,8 @@ llvm::Value *CodeGenFunction::EmitDynamicCast(llvm::Value *V, // FIXME: Calculate better hint. llvm::Value *hint = llvm::ConstantInt::get(PtrDiffTy, -1ULL); - llvm::Value *SrcArg = CGM.GenerateRttiRef(SrcTy); - llvm::Value *DstArg = CGM.GenerateRttiRef(DstTy); + llvm::Value *SrcArg = CGM.GenerateRTTIRef(SrcTy); + llvm::Value *DstArg = CGM.GenerateRTTIRef(DstTy); V = Builder.CreateBitCast(V, PtrToInt8Ty); V = Builder.CreateCall4(CGM.CreateRuntimeFunction(FTy, "__dynamic_cast"), V, SrcArg, DstArg, hint); diff --git a/lib/CodeGen/CGExprConstant.cpp b/lib/CodeGen/CGExprConstant.cpp index 9289f78d557a..d428983f012a 100644 --- a/lib/CodeGen/CGExprConstant.cpp +++ b/lib/CodeGen/CGExprConstant.cpp @@ -167,7 +167,11 @@ class ConstStructBuilder { } // Or in the bits that go into the previous byte. - Tmp |= cast(Elements.back())->getValue(); + if (llvm::ConstantInt *Val = dyn_cast(Elements.back())) + Tmp |= Val->getValue(); + else + assert(isa(Elements.back())); + Elements.back() = llvm::ConstantInt::get(CGM.getLLVMContext(), Tmp); if (FitsCompletelyInPreviousByte) diff --git a/lib/CodeGen/CGExprScalar.cpp b/lib/CodeGen/CGExprScalar.cpp index c1cbecc9fa85..2f31c051a78d 100644 --- a/lib/CodeGen/CGExprScalar.cpp +++ b/lib/CodeGen/CGExprScalar.cpp @@ -167,6 +167,12 @@ class ScalarExprEmitter return CGF.EmitObjCMessageExpr(E).getScalarVal(); } + Value *VisitObjCIsaExpr(ObjCIsaExpr *E) { + LValue LV = CGF.EmitObjCIsaExpr(E); + Value *V = CGF.EmitLoadOfLValue(LV, E->getType()).getScalarVal(); + return V; + } + Value *VisitArraySubscriptExpr(ArraySubscriptExpr *E); Value *VisitShuffleVectorExpr(ShuffleVectorExpr *E); Value *VisitMemberExpr(MemberExpr *E); @@ -257,6 +263,10 @@ class ScalarExprEmitter CGF.EmitCXXDeleteExpr(E); return 0; } + Value *VisitUnaryTypeTraitExpr(const UnaryTypeTraitExpr *E) { + return llvm::ConstantInt::get(Builder.getInt1Ty(), + E->EvaluateTrait(CGF.getContext())); + } Value *VisitCXXPseudoDestructorExpr(const CXXPseudoDestructorExpr *E) { // C++ [expr.pseudo]p1: @@ -798,6 +808,8 @@ Value *ScalarExprEmitter::EmitCastExpr(CastExpr *CE) { //assert(0 && "Unknown cast kind!"); break; + case CastExpr::CK_AnyPointerToObjCPointerCast: + case CastExpr::CK_AnyPointerToBlockPointerCast: case CastExpr::CK_BitCast: { Value *Src = Visit(const_cast(E)); return Builder.CreateBitCast(Src, ConvertType(DestTy)); @@ -943,34 +955,8 @@ Value *ScalarExprEmitter::EmitCastExpr(CastExpr *CE) { case CastExpr::CK_FloatingCast: return EmitScalarConversion(Visit(E), E->getType(), DestTy); - case CastExpr::CK_MemberPointerToBoolean: { - const MemberPointerType* T = E->getType()->getAs(); - - if (T->getPointeeType()->isFunctionType()) { - // We have a member function pointer. - llvm::Value *Ptr = CGF.CreateTempAlloca(ConvertType(E->getType())); - - CGF.EmitAggExpr(E, Ptr, /*VolatileDest=*/false); - - // Get the pointer. - llvm::Value *FuncPtr = Builder.CreateStructGEP(Ptr, 0, "src.ptr"); - FuncPtr = Builder.CreateLoad(FuncPtr); - - llvm::Value *IsNotNull = - Builder.CreateICmpNE(FuncPtr, - llvm::Constant::getNullValue(FuncPtr->getType()), - "tobool"); - - return IsNotNull; - } - - // We have a regular member pointer. - Value *Ptr = Visit(const_cast(E)); - llvm::Value *IsNotNull = - Builder.CreateICmpNE(Ptr, CGF.CGM.EmitNullConstant(E->getType()), - "tobool"); - return IsNotNull; - } + case CastExpr::CK_MemberPointerToBoolean: + return CGF.EvaluateExprAsBool(E); } // Handle cases where the source is an non-complex type. @@ -1540,6 +1526,16 @@ Value *ScalarExprEmitter::EmitShl(const BinOpInfo &Ops) { if (Ops.LHS->getType() != RHS->getType()) RHS = Builder.CreateIntCast(RHS, Ops.LHS->getType(), false, "sh_prom"); + if (CGF.CatchUndefined + && isa(Ops.LHS->getType())) { + unsigned Width = cast(Ops.LHS->getType())->getBitWidth(); + llvm::BasicBlock *Cont = CGF.createBasicBlock("cont"); + CGF.Builder.CreateCondBr(Builder.CreateICmpULT(RHS, + llvm::ConstantInt::get(RHS->getType(), Width)), + Cont, CGF.getTrapBB()); + CGF.EmitBlock(Cont); + } + return Builder.CreateShl(Ops.LHS, RHS, "shl"); } @@ -1550,6 +1546,16 @@ Value *ScalarExprEmitter::EmitShr(const BinOpInfo &Ops) { if (Ops.LHS->getType() != RHS->getType()) RHS = Builder.CreateIntCast(RHS, Ops.LHS->getType(), false, "sh_prom"); + if (CGF.CatchUndefined + && isa(Ops.LHS->getType())) { + unsigned Width = cast(Ops.LHS->getType())->getBitWidth(); + llvm::BasicBlock *Cont = CGF.createBasicBlock("cont"); + CGF.Builder.CreateCondBr(Builder.CreateICmpULT(RHS, + llvm::ConstantInt::get(RHS->getType(), Width)), + Cont, CGF.getTrapBB()); + CGF.EmitBlock(Cont); + } + if (Ops.Ty->isUnsignedIntegerType()) return Builder.CreateLShr(Ops.LHS, RHS, "shr"); return Builder.CreateAShr(Ops.LHS, RHS, "shr"); @@ -1560,7 +1566,34 @@ Value *ScalarExprEmitter::EmitCompare(const BinaryOperator *E,unsigned UICmpOpc, TestAndClearIgnoreResultAssign(); Value *Result; QualType LHSTy = E->getLHS()->getType(); - if (!LHSTy->isAnyComplexType()) { + if (LHSTy->isMemberFunctionPointerType()) { + Value *LHSPtr = CGF.EmitAnyExprToTemp(E->getLHS()).getAggregateAddr(); + Value *RHSPtr = CGF.EmitAnyExprToTemp(E->getRHS()).getAggregateAddr(); + llvm::Value *LHSFunc = Builder.CreateStructGEP(LHSPtr, 0); + LHSFunc = Builder.CreateLoad(LHSFunc); + llvm::Value *RHSFunc = Builder.CreateStructGEP(RHSPtr, 0); + RHSFunc = Builder.CreateLoad(RHSFunc); + Value *ResultF = Builder.CreateICmp((llvm::ICmpInst::Predicate)UICmpOpc, + LHSFunc, RHSFunc, "cmp.func"); + Value *NullPtr = llvm::Constant::getNullValue(LHSFunc->getType()); + Value *ResultNull = Builder.CreateICmp((llvm::ICmpInst::Predicate)UICmpOpc, + LHSFunc, NullPtr, "cmp.null"); + llvm::Value *LHSAdj = Builder.CreateStructGEP(LHSPtr, 1); + LHSAdj = Builder.CreateLoad(LHSAdj); + llvm::Value *RHSAdj = Builder.CreateStructGEP(RHSPtr, 1); + RHSAdj = Builder.CreateLoad(RHSAdj); + Value *ResultA = Builder.CreateICmp((llvm::ICmpInst::Predicate)UICmpOpc, + LHSAdj, RHSAdj, "cmp.adj"); + if (E->getOpcode() == BinaryOperator::EQ) { + Result = Builder.CreateOr(ResultNull, ResultA, "or.na"); + Result = Builder.CreateAnd(Result, ResultF, "and.f"); + } else { + assert(E->getOpcode() == BinaryOperator::NE && + "Member pointer comparison other than == or != ?"); + Result = Builder.CreateAnd(ResultNull, ResultA, "and.na"); + Result = Builder.CreateOr(Result, ResultF, "or.f"); + } + } else if (!LHSTy->isAnyComplexType()) { Value *LHS = Visit(E->getLHS()); Value *RHS = Visit(E->getRHS()); @@ -1868,10 +1901,11 @@ VisitConditionalOperator(const ConditionalOperator *E) { CGF.EmitBlock(ContBlock); - if (!LHS || !RHS) { - assert(E->getType()->isVoidType() && "Non-void value should have a value"); - return 0; - } + // If the LHS or RHS is a throw expression, it will be legitimately null. + if (!LHS) + return RHS; + if (!RHS) + return LHS; // Create a PHI node for the real part. llvm::PHINode *PN = Builder.CreatePHI(LHS->getType(), "cond"); @@ -1976,3 +2010,22 @@ llvm::Value *CodeGenFunction::EmitVector(llvm::Value * const *Vals, return Vec; } + +LValue CodeGenFunction::EmitObjCIsaExpr(const ObjCIsaExpr *E) { + llvm::Value *V; + // object->isa or (*object).isa + // Generate code as for: *(Class*)object + Expr *BaseExpr = E->getBase(); + if (E->isArrow()) + V = ScalarExprEmitter(*this).EmitLoadOfLValue(BaseExpr); + else + V = EmitLValue(BaseExpr).getAddress(); + + // build Class* type + const llvm::Type *ClassPtrTy = ConvertType(E->getType()); + ClassPtrTy = ClassPtrTy->getPointerTo(); + V = Builder.CreateBitCast(V, ClassPtrTy); + LValue LV = LValue::MakeAddr(V, MakeQualifiers(E->getType())); + return LV; +} + diff --git a/lib/CodeGen/CGObjCMac.cpp b/lib/CodeGen/CGObjCMac.cpp index 2e8ab2987db3..fb920f0b09ee 100644 --- a/lib/CodeGen/CGObjCMac.cpp +++ b/lib/CodeGen/CGObjCMac.cpp @@ -28,6 +28,7 @@ #include "llvm/ADT/DenseSet.h" #include "llvm/ADT/SetVector.h" #include "llvm/ADT/SmallString.h" +#include "llvm/ADT/SmallPtrSet.h" #include "llvm/Support/raw_ostream.h" #include "llvm/Target/TargetData.h" #include @@ -905,6 +906,13 @@ class CGObjCCommonMac : public CodeGen::CGObjCRuntime { const ObjCContainerDecl *OCD, const ObjCCommonTypesHelper &ObjCTypes); + /// PushProtocolProperties - Push protocol's property on the input stack. + void PushProtocolProperties(llvm::SmallPtrSet &PropertySet, + std::vector &Properties, + const Decl *Container, + const ObjCProtocolDecl *PROTO, + const ObjCCommonTypesHelper &ObjCTypes); + /// GetProtocolRef - Return a reference to the internal protocol /// description, creating an empty one if it has not been /// defined. The return value has type ProtocolPtrTy. @@ -1793,6 +1801,26 @@ CGObjCMac::EmitProtocolList(llvm::Twine Name, return llvm::ConstantExpr::getBitCast(GV, ObjCTypes.ProtocolListPtrTy); } +void CGObjCCommonMac::PushProtocolProperties(llvm::SmallPtrSet &PropertySet, + std::vector &Properties, + const Decl *Container, + const ObjCProtocolDecl *PROTO, + const ObjCCommonTypesHelper &ObjCTypes) { + std::vector Prop(2); + for (ObjCProtocolDecl::protocol_iterator P = PROTO->protocol_begin(), + E = PROTO->protocol_end(); P != E; ++P) + PushProtocolProperties(PropertySet, Properties, Container, (*P), ObjCTypes); + for (ObjCContainerDecl::prop_iterator I = PROTO->prop_begin(), + E = PROTO->prop_end(); I != E; ++I) { + const ObjCPropertyDecl *PD = *I; + if (!PropertySet.insert(PD->getIdentifier())) + continue; + Prop[0] = GetPropertyName(PD->getIdentifier()); + Prop[1] = GetPropertyTypeString(PD, Container); + Properties.push_back(llvm::ConstantStruct::get(ObjCTypes.PropertyTy, Prop)); + } +} + /* struct _objc_property { const char * const name; @@ -1810,14 +1838,20 @@ llvm::Constant *CGObjCCommonMac::EmitPropertyList(llvm::Twine Name, const ObjCContainerDecl *OCD, const ObjCCommonTypesHelper &ObjCTypes) { std::vector Properties, Prop(2); + llvm::SmallPtrSet PropertySet; for (ObjCContainerDecl::prop_iterator I = OCD->prop_begin(), E = OCD->prop_end(); I != E; ++I) { const ObjCPropertyDecl *PD = *I; + PropertySet.insert(PD->getIdentifier()); Prop[0] = GetPropertyName(PD->getIdentifier()); Prop[1] = GetPropertyTypeString(PD, Container); Properties.push_back(llvm::ConstantStruct::get(ObjCTypes.PropertyTy, Prop)); } + if (const ObjCInterfaceDecl *OID = dyn_cast(OCD)) + for (ObjCInterfaceDecl::protocol_iterator P = OID->protocol_begin(), + E = OID->protocol_end(); P != E; ++P) + PushProtocolProperties(PropertySet, Properties, Container, (*P), ObjCTypes); // Return null for empty list. if (Properties.empty()) @@ -2507,8 +2541,11 @@ void CGObjCMac::EmitTryOrSynchronizedStmt(CodeGen::CodeGenFunction &CGF, // through finally. CGF.PushCleanupBlock(FinallyBlock); - CGF.ObjCEHValueStack.push_back(0); - + if (CGF.ObjCEHValueStack.empty()) + CGF.ObjCEHValueStack.push_back(0); + // If This is a nested @try, caught exception is that of enclosing @try. + else + CGF.ObjCEHValueStack.push_back(CGF.ObjCEHValueStack.back()); // Allocate memory for the exception data and rethrow pointer. llvm::Value *ExceptionData = CGF.CreateTempAlloca(ObjCTypes.ExceptionDataTy, "exceptiondata.ptr"); @@ -4134,23 +4171,19 @@ void CGObjCNonFragileABIMac::FinishNonFragileABIModule() { "\01L_OBJC_LABEL_CLASS_$", "__DATA, __objc_classlist, regular, no_dead_strip"); - bool hasWeakImport = false; for (unsigned i = 0; i < DefinedClasses.size(); i++) { llvm::GlobalValue *IMPLGV = DefinedClasses[i]; if (IMPLGV->getLinkage() != llvm::GlobalValue::ExternalWeakLinkage) continue; IMPLGV->setLinkage(llvm::GlobalValue::ExternalLinkage); - hasWeakImport = true; } - if (hasWeakImport) { - for (unsigned i = 0; i < DefinedMetaClasses.size(); i++) { - llvm::GlobalValue *IMPLGV = DefinedMetaClasses[i]; - if (IMPLGV->getLinkage() != llvm::GlobalValue::ExternalWeakLinkage) - continue; - IMPLGV->setLinkage(llvm::GlobalValue::ExternalLinkage); - } - } + for (unsigned i = 0; i < DefinedMetaClasses.size(); i++) { + llvm::GlobalValue *IMPLGV = DefinedMetaClasses[i]; + if (IMPLGV->getLinkage() != llvm::GlobalValue::ExternalWeakLinkage) + continue; + IMPLGV->setLinkage(llvm::GlobalValue::ExternalLinkage); + } AddModuleClassList(DefinedNonLazyClasses, "\01L_OBJC_LABEL_NONLAZY_CLASS_$", @@ -4437,9 +4470,12 @@ void CGObjCNonFragileABIMac::GenerateClass(const ObjCImplementationDecl *ID) { while (const ObjCInterfaceDecl *Super = Root->getSuperClass()) Root = Super; IsAGV = GetClassGlobal(ObjCMetaClassName + Root->getNameAsString()); + if (Root->hasAttr()) + IsAGV->setLinkage(llvm::GlobalValue::ExternalWeakLinkage); // work on super class metadata symbol. std::string SuperClassName = - ObjCMetaClassName + ID->getClassInterface()->getSuperClass()->getNameAsString(); + ObjCMetaClassName + + ID->getClassInterface()->getSuperClass()->getNameAsString(); SuperClassGV = GetClassGlobal(SuperClassName); if (ID->getClassInterface()->getSuperClass()->hasAttr()) SuperClassGV->setLinkage(llvm::GlobalValue::ExternalWeakLinkage); diff --git a/lib/CodeGen/CGRtti.cpp b/lib/CodeGen/CGRTTI.cpp similarity index 64% rename from lib/CodeGen/CGRtti.cpp rename to lib/CodeGen/CGRTTI.cpp index 43fcb31858f8..02de00e3d7da 100644 --- a/lib/CodeGen/CGRtti.cpp +++ b/lib/CodeGen/CGRTTI.cpp @@ -1,4 +1,4 @@ -//===--- CGCXXRtti.cpp - Emit LLVM Code for C++ RTTI descriptors ----------===// +//===--- CGCXXRTTI.cpp - Emit LLVM Code for C++ RTTI descriptors ----------===// // // The LLVM Compiler Infrastructure // @@ -17,14 +17,35 @@ using namespace clang; using namespace CodeGen; -class RttiBuilder { +namespace { +class RTTIBuilder { CodeGenModule &CGM; // Per-module state. llvm::LLVMContext &VMContext; const llvm::Type *Int8PtrTy; llvm::SmallSet SeenVBase; llvm::SmallSet SeenBase; + + // Type info flags. + enum { + /// TI_Const - Type has const qualifier. + TI_Const = 0x1, + + /// TI_Volatile - Type has volatile qualifier. + TI_Volatile = 0x2, + + /// TI_Restrict - Type has restrict qualifier. + TI_Restrict = 0x4, + + /// TI_Incomplete - Type is incomplete. + TI_Incomplete = 0x8, + + /// TI_ContainingClassIncomplete - Containing class is incomplete. + /// (in pointer to member). + TI_ContainingClassIncomplete = 0x10 + }; + public: - RttiBuilder(CodeGenModule &cgm) + RTTIBuilder(CodeGenModule &cgm) : CGM(cgm), VMContext(cgm.getModule().getContext()), Int8PtrTy(llvm::Type::getInt8PtrTy(VMContext)) { } @@ -47,27 +68,37 @@ class RttiBuilder { return llvm::ConstantExpr::getBitCast(C, Int8PtrTy); } + // FIXME: This should be removed, and clients should pass in the linkage + // directly instead. + static inline llvm::GlobalVariable::LinkageTypes + GetLinkageFromExternFlag(bool Extern) { + if (Extern) + return llvm::GlobalValue::WeakODRLinkage; + + return llvm::GlobalValue::InternalLinkage; + } + + // FIXME: This should be removed, and clients should pass in the linkage + // directly instead. llvm::Constant *BuildName(QualType Ty, bool Hidden, bool Extern) { + return BuildName(Ty, Hidden, GetLinkageFromExternFlag(Extern)); + } + + llvm::Constant *BuildName(QualType Ty, bool Hidden, + llvm::GlobalVariable::LinkageTypes Linkage) { llvm::SmallString<256> OutName; - CGM.getMangleContext().mangleCXXRttiName(Ty, OutName); + CGM.getMangleContext().mangleCXXRTTIName(Ty, OutName); llvm::StringRef Name = OutName.str(); - llvm::GlobalVariable::LinkageTypes linktype; - linktype = llvm::GlobalValue::LinkOnceODRLinkage; - if (!Extern) - linktype = llvm::GlobalValue::InternalLinkage; + llvm::GlobalVariable *OGV = CGM.getModule().getGlobalVariable(Name); + if (OGV && !OGV->isDeclaration()) + return llvm::ConstantExpr::getBitCast(OGV, Int8PtrTy); - llvm::GlobalVariable *GV; - GV = CGM.getModule().getGlobalVariable(Name); - if (GV && !GV->isDeclaration()) - return llvm::ConstantExpr::getBitCast(GV, Int8PtrTy); + llvm::Constant *C = llvm::ConstantArray::get(VMContext, Name.substr(4)); - llvm::Constant *C; - C = llvm::ConstantArray::get(VMContext, Name.substr(4)); - - llvm::GlobalVariable *OGV = GV; - GV = new llvm::GlobalVariable(CGM.getModule(), C->getType(), true, linktype, - C, Name); + llvm::GlobalVariable *GV = + new llvm::GlobalVariable(CGM.getModule(), C->getType(), true, Linkage, + C, Name); if (OGV) { GV->takeName(OGV); llvm::Constant *NewPtr = llvm::ConstantExpr::getBitCast(GV, @@ -94,11 +125,8 @@ class RttiBuilder { llvm::Constant *BuildTypeRef(QualType Ty) { llvm::Constant *C; - if (!CGM.getContext().getLangOptions().Rtti) - return llvm::Constant::getNullValue(Int8PtrTy); - llvm::SmallString<256> OutName; - CGM.getMangleContext().mangleCXXRtti(Ty, OutName); + CGM.getMangleContext().mangleCXXRTTI(Ty, OutName); llvm::StringRef Name = OutName.str(); C = CGM.getModule().getGlobalVariable(Name); @@ -158,19 +186,15 @@ class RttiBuilder { return true; } - llvm::Constant *finish(std::vector &info, + llvm::Constant *finish(llvm::Constant *const *Values, unsigned NumValues, llvm::GlobalVariable *GV, - llvm::StringRef Name, bool Hidden, bool Extern) { - llvm::GlobalVariable::LinkageTypes linktype; - linktype = llvm::GlobalValue::LinkOnceODRLinkage; - if (!Extern) - linktype = llvm::GlobalValue::InternalLinkage; - - llvm::Constant *C; - C = llvm::ConstantStruct::get(VMContext, &info[0], info.size(), false); + llvm::StringRef Name, bool Hidden, + llvm::GlobalVariable::LinkageTypes Linkage) { + llvm::Constant *C = + llvm::ConstantStruct::get(VMContext, Values, NumValues, /*Packed=*/false); llvm::GlobalVariable *OGV = GV; - GV = new llvm::GlobalVariable(CGM.getModule(), C->getType(), true, linktype, + GV = new llvm::GlobalVariable(CGM.getModule(), C->getType(), true, Linkage, C, Name); if (OGV) { GV->takeName(OGV); @@ -185,14 +209,16 @@ class RttiBuilder { } - llvm::Constant *Buildclass_type_info(const CXXRecordDecl *RD) { - if (!CGM.getContext().getLangOptions().Rtti) - return llvm::Constant::getNullValue(Int8PtrTy); - + llvm::Constant * + Buildclass_type_info(const CXXRecordDecl *RD, + llvm::GlobalVariable::LinkageTypes Linkage) { + std::vector info; + assert(info.empty() && "Info vector must be empty!"); + llvm::Constant *C; llvm::SmallString<256> OutName; - CGM.getMangleContext().mangleCXXRtti(CGM.getContext().getTagDeclType(RD), + CGM.getMangleContext().mangleCXXRTTI(CGM.getContext().getTagDeclType(RD), OutName); llvm::StringRef Name = OutName.str(); @@ -201,10 +227,11 @@ class RttiBuilder { if (GV && !GV->isDeclaration()) return llvm::ConstantExpr::getBitCast(GV, Int8PtrTy); - std::vector info; - + // If we're in an anonymous namespace, then we always want internal linkage. + if (RD->isInAnonymousNamespace() || !RD->hasLinkage()) + Linkage = llvm::GlobalVariable::InternalLinkage; + bool Hidden = CGM.getDeclVisibilityMode(RD) == LangOptions::Hidden; - bool Extern = !RD->isInAnonymousNamespace(); bool simple = false; if (RD->getNumBases() == 0) @@ -216,7 +243,7 @@ class RttiBuilder { C = BuildVtableRef("_ZTVN10__cxxabiv121__vmi_class_type_infoE"); info.push_back(C); info.push_back(BuildName(CGM.getContext().getTagDeclType(RD), Hidden, - Extern)); + Linkage)); // If we have no bases, there are no more fields. if (RD->getNumBases()) { @@ -230,7 +257,7 @@ class RttiBuilder { e = RD->bases_end(); i != e; ++i) { const CXXRecordDecl *Base = cast(i->getType()->getAs()->getDecl()); - info.push_back(CGM.GenerateRttiRef(Base)); + info.push_back(CGM.GetAddrOfRTTI(Base)); if (simple) break; int64_t offset; @@ -249,12 +276,12 @@ class RttiBuilder { } } - return finish(info, GV, Name, Hidden, Extern); + return finish(&info[0], info.size(), GV, Name, Hidden, Linkage); } /// - BuildFlags - Build a __flags value for __pbase_type_info. - llvm::Constant *BuildInt(int f) { - return llvm::ConstantInt::get(llvm::Type::getInt32Ty(VMContext), f); + llvm::Constant *BuildInt(unsigned n) { + return llvm::ConstantInt::get(llvm::Type::getInt32Ty(VMContext), n); } bool DecideExtern(QualType Ty) { @@ -266,7 +293,7 @@ class RttiBuilder { return DecideExtern(PT->getPointeeType()); if (const RecordType *RT = Ty->getAs()) if (const CXXRecordDecl *RD = dyn_cast(RT->getDecl())) - return !RD->isInAnonymousNamespace(); + return !RD->isInAnonymousNamespace() && RD->hasLinkage(); return true; } @@ -284,10 +311,13 @@ class RttiBuilder { } llvm::Constant *BuildPointerType(QualType Ty) { + std::vector info; + assert(info.empty() && "Info vector must be empty!"); + llvm::Constant *C; llvm::SmallString<256> OutName; - CGM.getMangleContext().mangleCXXRtti(Ty, OutName); + CGM.getMangleContext().mangleCXXRTTI(Ty, OutName); llvm::StringRef Name = OutName.str(); llvm::GlobalVariable *GV; @@ -295,52 +325,58 @@ class RttiBuilder { if (GV && !GV->isDeclaration()) return llvm::ConstantExpr::getBitCast(GV, Int8PtrTy); - std::vector info; - bool Extern = DecideExtern(Ty); bool Hidden = DecideHidden(Ty); - QualType PTy = Ty->getPointeeType(); - QualType BTy; - bool PtrMem = false; - if (const MemberPointerType *MPT = dyn_cast(Ty)) { - PtrMem = true; - BTy = QualType(MPT->getClass(), 0); - PTy = MPT->getPointeeType(); - } + const MemberPointerType *PtrMemTy = dyn_cast(Ty); + QualType PointeeTy; + + if (PtrMemTy) + PointeeTy = PtrMemTy->getPointeeType(); + else + PointeeTy = Ty->getPointeeType(); - if (PtrMem) + if (PtrMemTy) C = BuildVtableRef("_ZTVN10__cxxabiv129__pointer_to_member_type_infoE"); else C = BuildVtableRef("_ZTVN10__cxxabiv119__pointer_type_infoE"); + info.push_back(C); info.push_back(BuildName(Ty, Hidden, Extern)); - Qualifiers Q = PTy.getQualifiers(); - PTy = CGM.getContext().getCanonicalType(PTy).getUnqualifiedType(); - int flags = 0; - flags += Q.hasConst() ? 0x1 : 0; - flags += Q.hasVolatile() ? 0x2 : 0; - flags += Q.hasRestrict() ? 0x4 : 0; - flags += Ty.getTypePtr()->isIncompleteType() ? 0x8 : 0; - if (PtrMem && BTy.getTypePtr()->isIncompleteType()) - flags += 0x10; - - info.push_back(BuildInt(flags)); + Qualifiers Q = PointeeTy.getQualifiers(); + + PointeeTy = + CGM.getContext().getCanonicalType(PointeeTy).getUnqualifiedType(); + + unsigned Flags = 0; + if (Q.hasConst()) + Flags |= TI_Const; + if (Q.hasVolatile()) + Flags |= TI_Volatile; + if (Q.hasRestrict()) + Flags |= TI_Restrict; + + if (Ty->isIncompleteType()) + Flags |= TI_Incomplete; + + if (PtrMemTy && PtrMemTy->getClass()->isIncompleteType()) + Flags |= TI_ContainingClassIncomplete; + + info.push_back(BuildInt(Flags)); info.push_back(BuildInt(0)); - info.push_back(BuildType(PTy)); + info.push_back(BuildType(PointeeTy)); - if (PtrMem) - info.push_back(BuildType(BTy)); + if (PtrMemTy) + info.push_back(BuildType(QualType(PtrMemTy->getClass(), 0))); // We always generate these as hidden, only the name isn't hidden. - return finish(info, GV, Name, true, Extern); + return finish(&info[0], info.size(), GV, Name, /*Hidden=*/true, + GetLinkageFromExternFlag(Extern)); } llvm::Constant *BuildSimpleType(QualType Ty, const char *vtbl) { - llvm::Constant *C; - llvm::SmallString<256> OutName; - CGM.getMangleContext().mangleCXXRtti(Ty, OutName); + CGM.getMangleContext().mangleCXXRTTI(Ty, OutName); llvm::StringRef Name = OutName.str(); llvm::GlobalVariable *GV; @@ -348,26 +384,26 @@ class RttiBuilder { if (GV && !GV->isDeclaration()) return llvm::ConstantExpr::getBitCast(GV, Int8PtrTy); - std::vector info; - bool Extern = DecideExtern(Ty); bool Hidden = DecideHidden(Ty); - C = BuildVtableRef(vtbl); - info.push_back(C); - info.push_back(BuildName(Ty, Hidden, Extern)); - + llvm::Constant *Info[] = { + BuildVtableRef(vtbl), BuildName(Ty, Hidden, Extern) + }; + // We always generate these as hidden, only the name isn't hidden. - return finish(info, GV, Name, true, Extern); + return finish(&Info[0], llvm::array_lengthof(Info), GV, Name, + /*Hidden=*/true, GetLinkageFromExternFlag(Extern)); } + /// BuildType - Builds the type info for the given type. llvm::Constant *BuildType(QualType Ty) { const clang::Type &Type = *CGM.getContext().getCanonicalType(Ty).getTypePtr(); if (const RecordType *RT = Ty.getTypePtr()->getAs()) if (const CXXRecordDecl *RD = cast(RT->getDecl())) - return Buildclass_type_info(RD); + return BuildClassTypeInfo(RD); switch (Type.getTypeClass()) { default: { @@ -405,22 +441,65 @@ class RttiBuilder { return BuildSimpleType(Ty, "_ZTVN10__cxxabiv116__enum_type_infoE"); } } -}; + + /// BuildClassTypeInfo - Builds the class type info (or a reference to it) + /// for the given record decl. + llvm::Constant *BuildClassTypeInfo(const CXXRecordDecl *RD) { + const CXXMethodDecl *KeyFunction = 0; -llvm::Constant *CodeGenModule::GenerateRttiRef(const CXXRecordDecl *RD) { - RttiBuilder b(*this); + if (RD->isDynamicClass()) + KeyFunction = CGM.getContext().getKeyFunction(RD); + + if (KeyFunction) { + // If the key function is defined in this translation unit, then the RTTI + // related constants should also be emitted here, with external linkage. + if (KeyFunction->getBody()) + return Buildclass_type_info(RD, llvm::GlobalValue::ExternalLinkage); + + // Otherwise, we just want a reference to the type info. + return Buildclass_type_infoRef(RD); + } + + // If there is no key function (or if the record doesn't have any virtual + // member functions or virtual bases), emit the type info with weak_odr + // linkage. + return Buildclass_type_info(RD, llvm::GlobalValue::WeakODRLinkage); + } +}; +} + +llvm::Constant *CodeGenModule::GetAddrOfRTTI(const CXXRecordDecl *RD) { + if (!getContext().getLangOptions().RTTI) { + const llvm::Type *Int8PtrTy = llvm::Type::getInt8PtrTy(VMContext); + return llvm::Constant::getNullValue(Int8PtrTy); + } + + return RTTIBuilder(*this).BuildClassTypeInfo(RD); +} + +llvm::Constant *CodeGenModule::GetAddrOfRTTI(QualType Ty) { + if (!getContext().getLangOptions().RTTI) { + const llvm::Type *Int8PtrTy = llvm::Type::getInt8PtrTy(VMContext); + return llvm::Constant::getNullValue(Int8PtrTy); + } + + return RTTIBuilder(*this).BuildType(Ty); +} + +llvm::Constant *CodeGenModule::GenerateRTTIRef(const CXXRecordDecl *RD) { + RTTIBuilder b(*this); return b.Buildclass_type_infoRef(RD); } -llvm::Constant *CodeGenModule::GenerateRtti(const CXXRecordDecl *RD) { - RttiBuilder b(*this); +llvm::Constant *CodeGenModule::GenerateRTTI(const CXXRecordDecl *RD) { + RTTIBuilder b(*this); - return b.Buildclass_type_info(RD); + return b.Buildclass_type_info(RD, llvm::GlobalValue::ExternalLinkage); } -llvm::Constant *CodeGenModule::GenerateRtti(QualType Ty) { - RttiBuilder b(*this); +llvm::Constant *CodeGenModule::GenerateRTTI(QualType Ty) { + RTTIBuilder b(*this); return b.BuildType(Ty); } diff --git a/lib/CodeGen/CGRecordLayoutBuilder.cpp b/lib/CodeGen/CGRecordLayoutBuilder.cpp index 1a9bc3917092..31784eda5a6b 100644 --- a/lib/CodeGen/CGRecordLayoutBuilder.cpp +++ b/lib/CodeGen/CGRecordLayoutBuilder.cpp @@ -88,8 +88,6 @@ void CGRecordLayoutBuilder::LayoutBitField(const FieldDecl *D, AppendBytes(NumBytesToAppend); - AlignmentAsLLVMStruct = std::max(AlignmentAsLLVMStruct, getTypeAlignment(Ty)); - BitsAvailableInLastField = NextFieldOffsetInBytes * 8 - (FieldOffset + FieldSize); } @@ -247,6 +245,14 @@ void CGRecordLayoutBuilder::AppendTailPadding(uint64_t RecordSize) { uint64_t RecordSizeInBytes = RecordSize / 8; assert(NextFieldOffsetInBytes <= RecordSizeInBytes && "Size mismatch!"); + uint64_t AlignedNextFieldOffset = + llvm::RoundUpToAlignment(NextFieldOffsetInBytes, AlignmentAsLLVMStruct); + + if (AlignedNextFieldOffset == RecordSizeInBytes) { + // We don't need any padding. + return; + } + unsigned NumPadBytes = RecordSizeInBytes - NextFieldOffsetInBytes; AppendBytes(NumPadBytes); } diff --git a/lib/CodeGen/CGVtable.cpp b/lib/CodeGen/CGVtable.cpp index 715aa4c03c10..5283ed9366c3 100644 --- a/lib/CodeGen/CGVtable.cpp +++ b/lib/CodeGen/CGVtable.cpp @@ -26,12 +26,23 @@ class VtableBuilder { public: /// Index_t - Vtable index type. typedef uint64_t Index_t; + typedef std::vector > > + SavedAdjustmentsVectorTy; private: - std::vector &methods; - std::vector submethods; + + // VtableComponents - The components of the vtable being built. + typedef llvm::SmallVector VtableComponentsVectorTy; + VtableComponentsVectorTy VtableComponents; + + const bool BuildVtable; + llvm::Type *Ptr8Ty; - /// Class - The most derived class that this vtable is being built for. - const CXXRecordDecl *Class; + + /// MostDerivedClass - The most derived class that this vtable is being + /// built for. + const CXXRecordDecl *MostDerivedClass; + /// LayoutClass - The most derived class used for virtual base layout /// information. const CXXRecordDecl *LayoutClass; @@ -45,9 +56,7 @@ class VtableBuilder { llvm::Constant *rtti; llvm::LLVMContext &VMContext; CodeGenModule &CGM; // Per-module state. - /// Index - Maps a method decl into a vtable index. Useful for virtual - /// dispatch codegen. - llvm::DenseMap Index; + llvm::DenseMap VCall; llvm::DenseMap VCallOffset; // This is the offset to the nearest virtual base @@ -57,54 +66,93 @@ class VtableBuilder { /// PureVirtualFunction - Points to __cxa_pure_virtual. llvm::Constant *PureVirtualFn; - /// Thunk - Represents a single thunk. - struct Thunk { - Thunk() - : Index(0) { } - - Thunk(uint64_t Index, const ThunkAdjustment &Adjustment) - : Index(Index), Adjustment(Adjustment) { } - - /// Index - The index in the vtable. - uint64_t Index; - - /// Adjustment - The thunk adjustment. - ThunkAdjustment Adjustment; - }; + /// VtableMethods - A data structure for keeping track of methods in a vtable. + /// Can add methods, override methods and iterate in vtable order. + class VtableMethods { + // MethodToIndexMap - Maps from a global decl to the index it has in the + // Methods vector. + llvm::DenseMap MethodToIndexMap; - /// Thunks - The thunks in a vtable. - typedef llvm::DenseMap ThunksMapTy; - ThunksMapTy Thunks; + /// Methods - The methods, in vtable order. + typedef llvm::SmallVector MethodsVectorTy; + MethodsVectorTy Methods; + MethodsVectorTy OrigMethods; - /// CovariantThunk - Represents a single covariant thunk. - struct CovariantThunk { - CovariantThunk() - : Index(0) { } + public: + /// AddMethod - Add a method to the vtable methods. + void AddMethod(GlobalDecl GD) { + assert(!MethodToIndexMap.count(GD) && + "Method has already been added!"); + + MethodToIndexMap[GD] = Methods.size(); + Methods.push_back(GD); + OrigMethods.push_back(GD); + } - CovariantThunk(uint64_t Index, const ThunkAdjustment &ThisAdjustment, - const ThunkAdjustment &ReturnAdjustment, - CanQualType ReturnType) - : Index(Index), Adjustment(ThisAdjustment, ReturnAdjustment), - ReturnType(ReturnType) { } + /// OverrideMethod - Replace a method with another. + void OverrideMethod(GlobalDecl OverriddenGD, GlobalDecl GD) { + llvm::DenseMap::iterator i + = MethodToIndexMap.find(OverriddenGD); + assert(i != MethodToIndexMap.end() && "Did not find entry!"); + + // Get the index of the old decl. + uint64_t Index = i->second; + + // Replace the old decl with the new decl. + Methods[Index] = GD; + + // And add the new. + MethodToIndexMap[GD] = Index; + } + + /// getIndex - Gives the index of a passed in GlobalDecl. Returns false if + /// the index couldn't be found. + bool getIndex(GlobalDecl GD, uint64_t &Index) const { + llvm::DenseMap::const_iterator i + = MethodToIndexMap.find(GD); + + if (i == MethodToIndexMap.end()) + return false; + + Index = i->second; + return true; + } + + GlobalDecl getOrigMethod(uint64_t Index) const { + return OrigMethods[Index]; + } + + MethodsVectorTy::size_type size() const { + return Methods.size(); + } + + void clear() { + MethodToIndexMap.clear(); + Methods.clear(); + OrigMethods.clear(); + } - // Index - The index in the vtable. - uint64_t Index; - - /// Adjustment - The covariant thunk adjustment. - CovariantThunkAdjustment Adjustment; - - /// ReturnType - The return type of the function. - CanQualType ReturnType; + GlobalDecl operator[](uint64_t Index) const { + return Methods[Index]; + } }; - /// CovariantThunks - The covariant thunks in a vtable. - typedef llvm::DenseMap CovariantThunksMapTy; - CovariantThunksMapTy CovariantThunks; + /// Methods - The vtable methods we're currently building. + VtableMethods Methods; - /// PureVirtualMethods - Pure virtual methods. - typedef llvm::DenseSet PureVirtualMethodsSetTy; - PureVirtualMethodsSetTy PureVirtualMethods; + /// ThisAdjustments - For a given index in the vtable, contains the 'this' + /// pointer adjustment needed for a method. + typedef llvm::DenseMap ThisAdjustmentsMapTy; + ThisAdjustmentsMapTy ThisAdjustments; + SavedAdjustmentsVectorTy SavedAdjustments; + + /// BaseReturnTypes - Contains the base return types of methods who have been + /// overridden with methods whose return types require adjustment. Used for + /// generating covariant thunk information. + typedef llvm::DenseMap BaseReturnTypesMapTy; + BaseReturnTypesMapTy BaseReturnTypes; + std::vector VCalls; typedef std::pair CtorVtable_t; @@ -143,21 +191,32 @@ class VtableBuilder { } public: - VtableBuilder(std::vector &meth, const CXXRecordDecl *c, - const CXXRecordDecl *l, uint64_t lo, CodeGenModule &cgm) - : methods(meth), Class(c), LayoutClass(l), LayoutOffset(lo), - BLayout(cgm.getContext().getASTRecordLayout(l)), - rtti(cgm.GenerateRttiRef(c)), VMContext(cgm.getModule().getContext()), - CGM(cgm), PureVirtualFn(0),subAddressPoints(AllocAddressPoint(cgm, l, c)), + VtableBuilder(const CXXRecordDecl *MostDerivedClass, + const CXXRecordDecl *l, uint64_t lo, CodeGenModule &cgm, + bool build) + : BuildVtable(build), MostDerivedClass(MostDerivedClass), LayoutClass(l), + LayoutOffset(lo), BLayout(cgm.getContext().getASTRecordLayout(l)), + rtti(0), VMContext(cgm.getModule().getContext()),CGM(cgm), + PureVirtualFn(0), + subAddressPoints(AllocAddressPoint(cgm, l, MostDerivedClass)), Extern(!l->isInAnonymousNamespace()), - LLVMPointerWidth(cgm.getContext().Target.getPointerWidth(0)) { + LLVMPointerWidth(cgm.getContext().Target.getPointerWidth(0)) { Ptr8Ty = llvm::PointerType::get(llvm::Type::getInt8Ty(VMContext), 0); + if (BuildVtable) + rtti = CGM.GetAddrOfRTTI(MostDerivedClass); } - llvm::DenseMap &getIndex() { return Index; } + // getVtableComponents - Returns a reference to the vtable components. + const VtableComponentsVectorTy &getVtableComponents() const { + return VtableComponents; + } + llvm::DenseMap &getVBIndex() { return VBIndex; } + SavedAdjustmentsVectorTy &getSavedAdjustments() + { return SavedAdjustments; } + llvm::Constant *wrap(Index_t i) { llvm::Constant *m; m = llvm::ConstantInt::get(llvm::Type::getInt64Ty(VMContext), i); @@ -168,8 +227,8 @@ class VtableBuilder { 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) { @@ -249,7 +308,7 @@ class VtableBuilder { qB = qB->getPointeeType(); CXXRecordDecl *D = cast(qD->getAs()->getDecl()); CXXRecordDecl *B = cast(qB->getAs()->getDecl()); - if (D != Class) + if (D != MostDerivedClass) return CGM.getVtableInfo().getVirtualBaseOffsetIndex(D, B); llvm::DenseMap::iterator i; i = VBIndex.find(B); @@ -260,166 +319,19 @@ class VtableBuilder { return 0; } - bool OverrideMethod(GlobalDecl GD, llvm::Constant *m, - bool MorallyVirtual, Index_t OverrideOffset, - Index_t Offset, int64_t CurrentVBaseOffset) { - const CXXMethodDecl *MD = cast(GD.getDecl()); - - const bool isPure = MD->isPure(); - typedef CXXMethodDecl::method_iterator meth_iter; - // FIXME: Should OverrideOffset's be Offset? - - // FIXME: Don't like the nested loops. For very large inheritance - // heirarchies we could have a table on the side with the final overridder - // and just replace each instance of an overridden method once. Would be - // nice to measure the cost/benefit on real code. - - for (meth_iter mi = MD->begin_overridden_methods(), - e = MD->end_overridden_methods(); - mi != e; ++mi) { - GlobalDecl OGD; - - const CXXMethodDecl *OMD = *mi; - if (const CXXDestructorDecl *DD = dyn_cast(OMD)) - OGD = GlobalDecl(DD, GD.getDtorType()); - else - OGD = OMD; - - llvm::Constant *om; - om = WrapAddrOf(OGD); - om = llvm::ConstantExpr::getBitCast(om, Ptr8Ty); - - for (Index_t i = 0, e = submethods.size(); - i != e; ++i) { - // FIXME: begin_overridden_methods might be too lax, covariance */ - if (submethods[i] != om) - continue; - QualType nc_oret = OMD->getType()->getAs()->getResultType(); - CanQualType oret = CGM.getContext().getCanonicalType(nc_oret); - QualType nc_ret = MD->getType()->getAs()->getResultType(); - CanQualType ret = CGM.getContext().getCanonicalType(nc_ret); - ThunkAdjustment ReturnAdjustment; - if (oret != ret) { - // FIXME: calculate offsets for covariance - CovariantThunksMapTy::iterator i = CovariantThunks.find(OMD); - if (i != CovariantThunks.end()) { - oret = i->second.ReturnType; - CovariantThunks.erase(i); - } - // FIXME: Double check oret - Index_t nv = getNVOffset(oret, ret)/8; - ReturnAdjustment = ThunkAdjustment(nv, getVbaseOffset(oret, ret)); - } - Index[GD] = i; - submethods[i] = m; - if (isPure) - PureVirtualMethods.insert(GD); - PureVirtualMethods.erase(OGD); - Thunks.erase(OGD); - if (MorallyVirtual || VCall.count(OGD)) { - Index_t &idx = VCall[OGD]; - if (idx == 0) { - NonVirtualOffset[GD] = -OverrideOffset/8 + CurrentVBaseOffset/8; - VCallOffset[GD] = OverrideOffset/8; - idx = VCalls.size()+1; - 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())); - } 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())); - } - VCall[GD] = idx; - int64_t NonVirtualAdjustment = NonVirtualOffset[GD]; - int64_t VirtualAdjustment = - -((idx + extra + 2) * LLVMPointerWidth / 8); - - // Optimize out virtual adjustments of 0. - if (VCalls[idx-1] == 0) - VirtualAdjustment = 0; - - ThunkAdjustment ThisAdjustment(NonVirtualAdjustment, - VirtualAdjustment); - - // FIXME: Do we always have to build a covariant thunk to save oret, - // which is the containing virtual base class? - if (!ReturnAdjustment.isEmpty()) { - CovariantThunks[GD] = - CovariantThunk(i, ThisAdjustment, ReturnAdjustment, oret); - } else if (!isPure && !ThisAdjustment.isEmpty()) - Thunks[GD] = Thunk(i, ThisAdjustment); - return true; - } - - // FIXME: finish off - int64_t NonVirtualAdjustment = VCallOffset[OGD] - OverrideOffset/8; - - if (NonVirtualAdjustment || !ReturnAdjustment.isEmpty()) { - ThunkAdjustment ThisAdjustment(NonVirtualAdjustment, 0); - - if (!ReturnAdjustment.isEmpty()) { - CovariantThunks[GD] = - CovariantThunk(i, ThisAdjustment, ReturnAdjustment, oret); - } else if (!isPure) - Thunks[GD] = Thunk(i, ThisAdjustment); - } - return true; - } - } - - return false; - } - - void InstallThunks() { - for (ThunksMapTy::const_iterator i = Thunks.begin(), e = Thunks.end(); - i != e; ++i) { - GlobalDecl GD = i->first; - const CXXMethodDecl *MD = cast(GD.getDecl()); - assert(!MD->isPure() && "Can't thunk pure virtual methods!"); - - const Thunk& Thunk = i->second; - assert(Thunk.Index == Index[GD] && "Thunk index mismatch!"); - - submethods[Thunk.Index] = CGM.BuildThunk(MD, Extern, Thunk.Adjustment); - } - Thunks.clear(); - - for (CovariantThunksMapTy::const_iterator i = CovariantThunks.begin(), - e = CovariantThunks.end(); i != e; ++i) { - GlobalDecl GD = i->first; - const CXXMethodDecl *MD = cast(GD.getDecl()); - if (MD->isPure()) - continue; - - const CovariantThunk &Thunk = i->second; - assert(Thunk.Index == Index[GD] && "Thunk index mismatch!"); - submethods[Thunk.Index] = - CGM.BuildCovariantThunk(MD, Extern, Thunk.Adjustment); - } - CovariantThunks.clear(); - - for (PureVirtualMethodsSetTy::iterator i = PureVirtualMethods.begin(), - e = PureVirtualMethods.end(); i != e; ++i) { - GlobalDecl GD = *i; - submethods[Index[GD]] = getPureVirtualFn(); - } - PureVirtualMethods.clear(); - } + bool OverrideMethod(GlobalDecl GD, bool MorallyVirtual, + Index_t OverrideOffset, Index_t Offset, + int64_t CurrentVBaseOffset); + /// AppendMethods - Append the current methods to the vtable. + void AppendMethodsToVtable(); + llvm::Constant *WrapAddrOf(GlobalDecl GD) { const CXXMethodDecl *MD = cast(GD.getDecl()); - if (const CXXDestructorDecl *Dtor = dyn_cast(MD)) - return wrap(CGM.GetAddrOfCXXDestructor(Dtor, GD.getDtorType())); - const llvm::Type *Ty = CGM.getTypes().GetFunctionTypeForVtable(MD); - return wrap(CGM.GetAddrOfFunction(MD, Ty)); + return wrap(CGM.GetAddrOfFunction(GD, Ty)); } void OverrideMethods(Path_t *Path, bool MorallyVirtual, int64_t Offset, @@ -438,15 +350,15 @@ class VtableBuilder { if (const CXXDestructorDecl *DD = dyn_cast(MD)) { // Override both the complete and the deleting destructor. GlobalDecl CompDtor(DD, Dtor_Complete); - OverrideMethod(CompDtor, WrapAddrOf(CompDtor), MorallyVirtual, - OverrideOffset, Offset, CurrentVBaseOffset); - + OverrideMethod(CompDtor, MorallyVirtual, OverrideOffset, Offset, + CurrentVBaseOffset); + GlobalDecl DeletingDtor(DD, Dtor_Deleting); - OverrideMethod(DeletingDtor, WrapAddrOf(DeletingDtor), MorallyVirtual, - OverrideOffset, Offset, CurrentVBaseOffset); + OverrideMethod(DeletingDtor, MorallyVirtual, OverrideOffset, Offset, + CurrentVBaseOffset); } else { - OverrideMethod(MD, WrapAddrOf(MD), MorallyVirtual, OverrideOffset, - Offset, CurrentVBaseOffset); + OverrideMethod(MD, MorallyVirtual, OverrideOffset, Offset, + CurrentVBaseOffset); } } } @@ -454,24 +366,20 @@ class VtableBuilder { void AddMethod(const GlobalDecl GD, bool MorallyVirtual, Index_t Offset, int64_t CurrentVBaseOffset) { - llvm::Constant *m = WrapAddrOf(GD); - // If we can find a previously allocated slot for this, reuse it. - if (OverrideMethod(GD, m, MorallyVirtual, Offset, Offset, + if (OverrideMethod(GD, MorallyVirtual, Offset, Offset, CurrentVBaseOffset)) return; - const CXXMethodDecl *MD = cast(GD.getDecl()); - - // else allocate a new slot. - Index[GD] = submethods.size(); - submethods.push_back(m); + // 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])); - if (MD->isPure()) - PureVirtualMethods.insert(GD); + + VCallOffset[GD] = Offset/8; if (MorallyVirtual) { - VCallOffset[GD] = Offset/8; Index_t &idx = VCall[GD]; // Allocate the first one, after that, we reuse the previous one. if (idx == 0) { @@ -530,16 +438,19 @@ class VtableBuilder { #define D(X) void insertVCalls(int InsertionPoint) { - llvm::Constant *e = 0; D1(printf("============= combining vbase/vcall\n")); D(VCalls.insert(VCalls.begin(), 673)); D(VCalls.push_back(672)); - methods.insert(methods.begin() + InsertionPoint, VCalls.size(), e); - // The vcalls come first... - for (std::vector::reverse_iterator i = VCalls.rbegin(), - e = VCalls.rend(); - i != e; ++i) - methods[InsertionPoint++] = wrap((0?600:0) + *i); + + VtableComponents.insert(VtableComponents.begin() + InsertionPoint, + VCalls.size(), 0); + if (BuildVtable) { + // The vcalls come first... + for (std::vector::reverse_iterator i = VCalls.rbegin(), + e = VCalls.rend(); + i != e; ++i) + VtableComponents[InsertionPoint++] = wrap((0?600:0) + *i); + } VCalls.clear(); VCall.clear(); } @@ -570,11 +481,13 @@ class VtableBuilder { } - Index_t end(const CXXRecordDecl *RD, const ASTRecordLayout &Layout, - const CXXRecordDecl *PrimaryBase, bool PrimaryBaseWasVirtual, - bool MorallyVirtual, int64_t Offset, bool ForVirtualBase, - int64_t CurrentVBaseOffset, - Path_t *Path) { + Index_t FinishGenerateVtable(const CXXRecordDecl *RD, + const ASTRecordLayout &Layout, + const CXXRecordDecl *PrimaryBase, + bool PrimaryBaseWasVirtual, + bool MorallyVirtual, int64_t Offset, + bool ForVirtualBase, int64_t CurrentVBaseOffset, + Path_t *Path) { bool alloc = false; if (Path == 0) { alloc = true; @@ -584,21 +497,22 @@ class VtableBuilder { StartNewTable(); extra = 0; bool DeferVCalls = MorallyVirtual || ForVirtualBase; - int VCallInsertionPoint = methods.size(); + 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(); - methods.push_back(wrap(-((Offset-LayoutOffset)/8))); - methods.push_back(rtti); - Index_t AddressPoint = methods.size(); + // Add the offset to top. + VtableComponents.push_back(BuildVtable ? wrap(-((Offset-LayoutOffset)/8)) : 0); + + // Add the RTTI information. + VtableComponents.push_back(rtti); + + Index_t AddressPoint = VtableComponents.size(); - InstallThunks(); - D1(printf("============= combining methods\n")); - methods.insert(methods.end(), submethods.begin(), submethods.end()); - submethods.clear(); + AppendMethodsToVtable(); // and then the non-virtual bases. NonVirtualBases(RD, Layout, PrimaryBase, PrimaryBaseWasVirtual, @@ -635,17 +549,11 @@ class VtableBuilder { const bool PrimaryBaseWasVirtual = Layout.getPrimaryBaseWasVirtual(); // vtables are composed from the chain of primaries. - if (PrimaryBase) { + if (PrimaryBase && !PrimaryBaseWasVirtual) { D1(printf(" doing primaries for %s most derived %s\n", RD->getNameAsCString(), Class->getNameAsCString())); - - int BaseCurrentVBaseOffset = CurrentVBaseOffset; - if (PrimaryBaseWasVirtual) - BaseCurrentVBaseOffset = BLayout.getVBaseClassOffset(PrimaryBase); - - if (!PrimaryBaseWasVirtual) - Primaries(PrimaryBase, PrimaryBaseWasVirtual|MorallyVirtual, Offset, - updateVBIndex, current_vbindex, BaseCurrentVBaseOffset); + Primaries(PrimaryBase, PrimaryBaseWasVirtual|MorallyVirtual, Offset, + updateVBIndex, current_vbindex, CurrentVBaseOffset); } D1(printf(" doing vcall entries for %s most derived %s\n", @@ -702,7 +610,8 @@ class VtableBuilder { // Construction vtable don't need parts that have no virtual bases and // aren't morally virtual. - if ((LayoutClass != Class) && RD->getNumVBases() == 0 && !MorallyVirtual) + if ((LayoutClass != MostDerivedClass) && + RD->getNumVBases() == 0 && !MorallyVirtual) return 0; const ASTRecordLayout &Layout = CGM.getContext().getASTRecordLayout(RD); @@ -722,8 +631,9 @@ class VtableBuilder { if (Path) OverrideMethods(Path, MorallyVirtual, Offset, CurrentVBaseOffset); - return end(RD, Layout, PrimaryBase, PrimaryBaseWasVirtual, MorallyVirtual, - Offset, ForVirtualBase, CurrentVBaseOffset, Path); + return FinishGenerateVtable(RD, Layout, PrimaryBase, PrimaryBaseWasVirtual, + MorallyVirtual, Offset, ForVirtualBase, + CurrentVBaseOffset, Path); } void GenerateVtableForVBases(const CXXRecordDecl *RD, @@ -770,8 +680,7 @@ class VtableBuilder { delete Path; } }; - -} +} // end anonymous namespace /// TypeConversionRequiresAdjustment - Returns whether conversion from a /// derived type to a base type requires adjustment. @@ -790,18 +699,18 @@ TypeConversionRequiresAdjustment(ASTContext &Ctx, // If we found a virtual base we always want to require adjustment. if (Paths.getDetectedVirtual()) return true; - + const CXXBasePath &Path = Paths.front(); for (size_t Start = 0, End = Path.size(); Start != End; ++Start) { const CXXBasePathElement &Element = Path[Start]; - + // Check the base class offset. const ASTRecordLayout &Layout = Ctx.getASTRecordLayout(Element.Class); const RecordType *BaseType = Element.Base->getType()->getAs(); const CXXRecordDecl *Base = cast(BaseType->getDecl()); - + if (Layout.getBaseClassOffset(Base) != 0) { // This requires an adjustment. return true; @@ -825,7 +734,7 @@ TypeConversionRequiresAdjustment(ASTContext &Ctx, // No adjustment needed. return false; } - + if (const ReferenceType *RT = dyn_cast(CanDerivedType)) { CanDerivedType = RT->getPointeeType(); CanBaseType = cast(CanBaseType)->getPointeeType(); @@ -835,21 +744,190 @@ TypeConversionRequiresAdjustment(ASTContext &Ctx, } else { assert(false && "Unexpected return type!"); } - + if (CanDerivedType == CanBaseType) { // No adjustment needed. return false; } const CXXRecordDecl *DerivedDecl = - cast(cast(CanDerivedType)->getDecl()); - + cast(cast(CanDerivedType)->getDecl()); + const CXXRecordDecl *BaseDecl = - cast(cast(CanBaseType)->getDecl()); - + cast(cast(CanBaseType)->getDecl()); + return TypeConversionRequiresAdjustment(Ctx, DerivedDecl, BaseDecl); } +bool VtableBuilder::OverrideMethod(GlobalDecl GD, bool MorallyVirtual, + Index_t OverrideOffset, Index_t Offset, + int64_t CurrentVBaseOffset) { + const CXXMethodDecl *MD = cast(GD.getDecl()); + + const bool isPure = MD->isPure(); + + // FIXME: Should OverrideOffset's be Offset? + + for (CXXMethodDecl::method_iterator mi = MD->begin_overridden_methods(), + e = MD->end_overridden_methods(); mi != e; ++mi) { + GlobalDecl OGD; + + const CXXMethodDecl *OMD = *mi; + if (const CXXDestructorDecl *DD = dyn_cast(OMD)) + OGD = GlobalDecl(DD, GD.getDtorType()); + else + OGD = OMD; + + // Check whether this is the method being overridden in this section of + // the vtable. + uint64_t Index; + if (!Methods.getIndex(OGD, Index)) + continue; + + // Get the original method, which we should be computing thunks, etc, + // against. + OGD = Methods.getOrigMethod(Index); + OMD = cast(OGD.getDecl()); + + QualType ReturnType = + MD->getType()->getAs()->getResultType(); + QualType OverriddenReturnType = + OMD->getType()->getAs()->getResultType(); + + // Check if we need a return type adjustment. + if (TypeConversionRequiresAdjustment(CGM.getContext(), ReturnType, + OverriddenReturnType)) { + CanQualType &BaseReturnType = BaseReturnTypes[Index]; + + // Insert the base return type. + if (BaseReturnType.isNull()) + BaseReturnType = + CGM.getContext().getCanonicalType(OverriddenReturnType); + } + + Methods.OverrideMethod(OGD, GD); + + ThisAdjustments.erase(Index); + if (MorallyVirtual || VCall.count(OGD)) { + Index_t &idx = VCall[OGD]; + if (idx == 0) { + NonVirtualOffset[GD] = -OverrideOffset/8 + CurrentVBaseOffset/8; + VCallOffset[GD] = OverrideOffset/8; + idx = VCalls.size()+1; + 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())); + } 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())); + } + VCall[GD] = idx; + int64_t NonVirtualAdjustment = NonVirtualOffset[GD]; + int64_t VirtualAdjustment = + -((idx + extra + 2) * LLVMPointerWidth / 8); + + // Optimize out virtual adjustments of 0. + if (VCalls[idx-1] == 0) + VirtualAdjustment = 0; + + ThunkAdjustment ThisAdjustment(NonVirtualAdjustment, + VirtualAdjustment); + + if (!isPure && !ThisAdjustment.isEmpty()) { + ThisAdjustments[Index] = ThisAdjustment; + SavedAdjustments.push_back( + std::make_pair(GD, std::make_pair(OGD, ThisAdjustment))); + } + return true; + } + + int64_t NonVirtualAdjustment = -VCallOffset[OGD] + OverrideOffset/8; + + if (NonVirtualAdjustment) { + ThunkAdjustment ThisAdjustment(NonVirtualAdjustment, 0); + + if (!isPure) { + ThisAdjustments[Index] = ThisAdjustment; + SavedAdjustments.push_back( + std::make_pair(GD, std::make_pair(OGD, ThisAdjustment))); + } + } + return true; + } + + return false; +} + +void VtableBuilder::AppendMethodsToVtable() { + if (!BuildVtable) { + VtableComponents.insert(VtableComponents.end(), Methods.size(), + (llvm::Constant *)0); + ThisAdjustments.clear(); + BaseReturnTypes.clear(); + Methods.clear(); + return; + } + + // Reserve room in the vtable for our new methods. + VtableComponents.reserve(VtableComponents.size() + Methods.size()); + + for (unsigned i = 0, e = Methods.size(); i != e; ++i) { + GlobalDecl GD = Methods[i]; + const CXXMethodDecl *MD = cast(GD.getDecl()); + + // Get the 'this' pointer adjustment. + ThunkAdjustment ThisAdjustment = ThisAdjustments.lookup(i); + + // Construct the return type adjustment. + ThunkAdjustment ReturnAdjustment; + + QualType BaseReturnType = BaseReturnTypes.lookup(i); + if (!BaseReturnType.isNull() && !MD->isPure()) { + QualType DerivedType = + MD->getType()->getAs()->getResultType(); + + int64_t NonVirtualAdjustment = + getNVOffset(BaseReturnType, DerivedType) / 8; + + int64_t VirtualAdjustment = + getVbaseOffset(BaseReturnType, DerivedType); + + ReturnAdjustment = ThunkAdjustment(NonVirtualAdjustment, + VirtualAdjustment); + } + + llvm::Constant *Method = 0; + if (!ReturnAdjustment.isEmpty()) { + // Build a covariant thunk. + CovariantThunkAdjustment Adjustment(ThisAdjustment, ReturnAdjustment); + Method = wrap(CGM.GetAddrOfCovariantThunk(GD, Adjustment)); + } else if (!ThisAdjustment.isEmpty()) { + // Build a "regular" thunk. + Method = wrap(CGM.GetAddrOfThunk(GD, ThisAdjustment)); + } else if (MD->isPure()) { + // We have a pure virtual method. + Method = getPureVirtualFn(); + } else { + // We have a good old regular method. + Method = WrapAddrOf(GD); + } + + // Add the method to the vtable. + VtableComponents.push_back(Method); + } + + + ThisAdjustments.clear(); + BaseReturnTypes.clear(); + + Methods.clear(); +} + void CGVtableInfo::ComputeMethodVtableIndices(const CXXRecordDecl *RD) { // Itanium C++ ABI 2.5.2: @@ -874,7 +952,15 @@ void CGVtableInfo::ComputeMethodVtableIndices(const CXXRecordDecl *RD) { // we need to start counting at the end of the primary base's vtable. CurrentIndex = getNumVirtualFunctionPointers(PrimaryBase); } - + + // Collect all the primary bases, so we can check whether methods override + // a method from the base. + llvm::SmallPtrSet PrimaryBases; + for (ASTRecordLayout::primary_base_info_iterator + I = Layout.primary_base_begin(), E = Layout.primary_base_end(); + I != E; ++I) + PrimaryBases.insert((*I).getBase()); + const CXXDestructorDecl *ImplicitVirtualDtor = 0; for (CXXRecordDecl::method_iterator i = RD->method_begin(), @@ -895,7 +981,7 @@ void CGVtableInfo::ComputeMethodVtableIndices(const CXXRecordDecl *RD) { assert(OverriddenMD->isCanonicalDecl() && "Should have the canonical decl of the overridden RD!"); - if (OverriddenRD == PrimaryBase) { + if (PrimaryBases.count(OverriddenRD)) { // Check if converting from the return type of the method to the // return type of the overridden method requires conversion. QualType ReturnType = @@ -993,6 +1079,33 @@ uint64_t CGVtableInfo::getMethodVtableIndex(GlobalDecl GD) { return I->second; } +CGVtableInfo::AdjustmentVectorTy* +CGVtableInfo::getAdjustments(GlobalDecl GD) { + SavedAdjustmentsTy::iterator I = SavedAdjustments.find(GD); + if (I != SavedAdjustments.end()) + return &I->second; + + const CXXRecordDecl *RD = cast(GD.getDecl()->getDeclContext()); + if (!SavedAdjustmentRecords.insert(RD).second) + return 0; + + VtableBuilder b(RD, RD, 0, CGM, false); + D1(printf("vtable %s\n", RD->getNameAsCString())); + b.GenerateVtableForBase(RD); + b.GenerateVtableForVBases(RD); + + for (VtableBuilder::SavedAdjustmentsVectorTy::iterator + i = b.getSavedAdjustments().begin(), + e = b.getSavedAdjustments().end(); i != e; i++) + SavedAdjustments[i->first].push_back(i->second); + + I = SavedAdjustments.find(GD); + if (I != SavedAdjustments.end()) + return &I->second; + + return 0; +} + int64_t CGVtableInfo::getVirtualBaseOffsetIndex(const CXXRecordDecl *RD, const CXXRecordDecl *VBase) { ClassPairTy ClassPair(RD, VBase); @@ -1002,10 +1115,9 @@ int64_t CGVtableInfo::getVirtualBaseOffsetIndex(const CXXRecordDecl *RD, if (I != VirtualBaseClassIndicies.end()) return I->second; - std::vector methods; // FIXME: This seems expensive. Can we do a partial job to get // just this data. - VtableBuilder b(methods, RD, RD, 0, CGM); + VtableBuilder b(RD, RD, 0, CGM, false); D1(printf("vtable %s\n", RD->getNameAsCString())); b.GenerateVtableForBase(RD); b.GenerateVtableForVBases(RD); @@ -1024,30 +1136,38 @@ int64_t CGVtableInfo::getVirtualBaseOffsetIndex(const CXXRecordDecl *RD, return I->second; } -llvm::Constant *CodeGenModule::GenerateVtable(const CXXRecordDecl *LayoutClass, - const CXXRecordDecl *RD, - uint64_t Offset) { +uint64_t CGVtableInfo::getVtableAddressPoint(const CXXRecordDecl *RD) { + uint64_t AddressPoint = + (*(*(CGM.AddressPoints[RD]))[RD])[std::make_pair(RD, 0)]; + + return AddressPoint; +} + +llvm::GlobalVariable * +CGVtableInfo::GenerateVtable(llvm::GlobalVariable::LinkageTypes Linkage, + bool GenerateDefinition, + const CXXRecordDecl *LayoutClass, + const CXXRecordDecl *RD, uint64_t Offset) { llvm::SmallString<256> OutName; if (LayoutClass != RD) - getMangleContext().mangleCXXCtorVtable(LayoutClass, Offset/8, RD, OutName); + CGM.getMangleContext().mangleCXXCtorVtable(LayoutClass, Offset / 8, + RD, OutName); else - getMangleContext().mangleCXXVtable(RD, OutName); + CGM.getMangleContext().mangleCXXVtable(RD, OutName); llvm::StringRef Name = OutName.str(); - std::vector methods; - llvm::Type *Ptr8Ty=llvm::PointerType::get(llvm::Type::getInt8Ty(VMContext),0); int64_t AddressPoint; - llvm::GlobalVariable *GV = getModule().getGlobalVariable(Name); - if (GV && AddressPoints[LayoutClass] && !GV->isDeclaration()) { - AddressPoint=(*(*(AddressPoints[LayoutClass]))[RD])[std::make_pair(RD, + llvm::GlobalVariable *GV = CGM.getModule().getGlobalVariable(Name); + if (GV && CGM.AddressPoints[LayoutClass] && !GV->isDeclaration()) { + AddressPoint=(*(*(CGM.AddressPoints[LayoutClass]))[RD])[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; } else { - VtableBuilder b(methods, RD, LayoutClass, Offset, *this); + VtableBuilder b(RD, LayoutClass, Offset, CGM, GenerateDefinition); D1(printf("vtable %s\n", RD->getNameAsCString())); // First comes the vtables for all the non-virtual bases... @@ -1056,59 +1176,34 @@ llvm::Constant *CodeGenModule::GenerateVtable(const CXXRecordDecl *LayoutClass, // then the vtables for all the virtual bases. b.GenerateVtableForVBases(RD, Offset); - bool CreateDefinition = true; - if (LayoutClass != RD) - CreateDefinition = true; - else { - const ASTRecordLayout &Layout = - getContext().getASTRecordLayout(LayoutClass); - - if (const CXXMethodDecl *KeyFunction = Layout.getKeyFunction()) { - if (!KeyFunction->getBody()) { - // If there is a KeyFunction, and it isn't defined, just build a - // reference to the vtable. - CreateDefinition = false; - } - } - } + llvm::Constant *Init = 0; + const llvm::Type *Int8PtrTy = llvm::Type::getInt8PtrTy(CGM.getLLVMContext()); + llvm::ArrayType *ArrayType = + llvm::ArrayType::get(Int8PtrTy, b.getVtableComponents().size()); + + if (GenerateDefinition) + Init = llvm::ConstantArray::get(ArrayType, &b.getVtableComponents()[0], + b.getVtableComponents().size()); - llvm::Constant *C = 0; - llvm::Type *type = Ptr8Ty; - llvm::GlobalVariable::LinkageTypes linktype - = llvm::GlobalValue::ExternalLinkage; - if (CreateDefinition) { - llvm::ArrayType *ntype = llvm::ArrayType::get(Ptr8Ty, methods.size()); - C = llvm::ConstantArray::get(ntype, methods); - linktype = llvm::GlobalValue::LinkOnceODRLinkage; - if (LayoutClass->isInAnonymousNamespace()) - linktype = llvm::GlobalValue::InternalLinkage; - type = ntype; - } llvm::GlobalVariable *OGV = GV; - GV = new llvm::GlobalVariable(getModule(), type, true, linktype, C, Name); + + GV = new llvm::GlobalVariable(CGM.getModule(), ArrayType, + /*isConstant=*/true, Linkage, Init, Name); + CGM.setGlobalVisibility(GV, RD); + if (OGV) { GV->takeName(OGV); - llvm::Constant *NewPtr = llvm::ConstantExpr::getBitCast(GV, - OGV->getType()); + llvm::Constant *NewPtr = + llvm::ConstantExpr::getBitCast(GV, OGV->getType()); OGV->replaceAllUsesWith(NewPtr); OGV->eraseFromParent(); } - bool Hidden = getDeclVisibilityMode(RD) == LangOptions::Hidden; - if (Hidden) - GV->setVisibility(llvm::GlobalVariable::HiddenVisibility); } - llvm::Constant *vtable = llvm::ConstantExpr::getBitCast(GV, Ptr8Ty); - llvm::Constant *AddressPointC; - uint32_t LLVMPointerWidth = getContext().Target.getPointerWidth(0); - AddressPointC = llvm::ConstantInt::get(llvm::Type::getInt64Ty(VMContext), - AddressPoint*LLVMPointerWidth/8); - vtable = llvm::ConstantExpr::getInBoundsGetElementPtr(vtable, &AddressPointC, - 1); - - assert(vtable->getType() == Ptr8Ty); - return vtable; + + return GV; } +namespace { class VTTBuilder { /// Inits - The list of values built for the VTT. std::vector &Inits; @@ -1125,12 +1220,13 @@ class VTTBuilder { llvm::LLVMContext &VMContext; /// BuildVtablePtr - Build up a referene to the given secondary vtable - llvm::Constant *BuildVtablePtr(llvm::Constant *vtbl, - const CXXRecordDecl *VtblClass, + llvm::Constant *BuildVtablePtr(llvm::Constant *Vtable, + const CXXRecordDecl *VtableClass, const CXXRecordDecl *RD, uint64_t Offset) { - int64_t AddressPoint; - AddressPoint = (*AddressPoints[VtblClass])[std::make_pair(RD, 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) @@ -1138,12 +1234,17 @@ class VTTBuilder { 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)); - uint32_t LLVMPointerWidth = CGM.getContext().Target.getPointerWidth(0); - llvm::Constant *init; - init = llvm::ConstantInt::get(llvm::Type::getInt64Ty(VMContext), - AddressPoint*LLVMPointerWidth/8); - init = llvm::ConstantExpr::getInBoundsGetElementPtr(vtbl, &init, 1); - return init; + + 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 @@ -1180,8 +1281,11 @@ class VTTBuilder { init = BuildVtablePtr(vtbl, VtblClass, RD, Offset); else { init = CGM.getVtableInfo().getCtorVtable(Class, Base, BaseOffset); - subvtbl = dyn_cast(init->getOperand(0)); + + subvtbl = init; subVtblClass = Base; + + init = BuildVtablePtr(init, Class, Base, BaseOffset); } Inits.push_back(init); } @@ -1195,25 +1299,26 @@ class VTTBuilder { if (RD->getNumVBases() == 0 && !MorallyVirtual) return; - llvm::Constant *init; - const CXXRecordDecl *VtblClass; + llvm::Constant *Vtable; + const CXXRecordDecl *VtableClass; // First comes the primary virtual table pointer... if (MorallyVirtual) { - init = BuildVtablePtr(ClassVtbl, Class, RD, Offset); - VtblClass = Class; + Vtable = ClassVtbl; + VtableClass = Class; } else { - init = CGM.getVtableInfo().getCtorVtable(Class, RD, Offset); - VtblClass = RD; + Vtable = CGM.getVtableInfo().getCtorVtable(Class, RD, Offset); + VtableClass = RD; } - llvm::Constant *vtbl = dyn_cast(init->getOperand(0)); - Inits.push_back(init); + + llvm::Constant *Init = BuildVtablePtr(Vtable, VtableClass, RD, Offset); + Inits.push_back(Init); // then the secondary VTTs.... SecondaryVTTs(RD, Offset, MorallyVirtual); // and last the secondary vtable pointers. - Secondary(RD, vtbl, VtblClass, Offset, MorallyVirtual); + Secondary(RD, Vtable, VtableClass, Offset, MorallyVirtual); } /// SecondaryVTTs - Add the secondary VTTs to Inits. The secondary VTTs are @@ -1248,6 +1353,7 @@ class VTTBuilder { VirtualVTTs(Base); } } + public: VTTBuilder(std::vector &inits, const CXXRecordDecl *c, CodeGenModule &cgm) @@ -1258,8 +1364,7 @@ class VTTBuilder { // First comes the primary virtual table pointer for the complete class... ClassVtbl = CGM.getVtableInfo().getVtable(Class); - Inits.push_back(ClassVtbl); - ClassVtbl = dyn_cast(ClassVtbl->getOperand(0)); + Inits.push_back(BuildVtablePtr(ClassVtbl, Class, Class, 0)); // then the secondary VTTs... SecondaryVTTs(Class); @@ -1271,98 +1376,116 @@ class VTTBuilder { VirtualVTTs(Class); } }; +} -llvm::Constant *CodeGenModule::GenerateVTT(const CXXRecordDecl *RD) { +llvm::GlobalVariable * +CGVtableInfo::GenerateVTT(llvm::GlobalVariable::LinkageTypes Linkage, + const CXXRecordDecl *RD) { // Only classes that have virtual bases need a VTT. if (RD->getNumVBases() == 0) return 0; llvm::SmallString<256> OutName; - getMangleContext().mangleCXXVTT(RD, OutName); + CGM.getMangleContext().mangleCXXVTT(RD, OutName); llvm::StringRef Name = OutName.str(); - llvm::GlobalVariable::LinkageTypes linktype; - linktype = llvm::GlobalValue::LinkOnceODRLinkage; - if (RD->isInAnonymousNamespace()) - linktype = llvm::GlobalValue::InternalLinkage; - std::vector inits; - llvm::Type *Ptr8Ty=llvm::PointerType::get(llvm::Type::getInt8Ty(VMContext),0); D1(printf("vtt %s\n", RD->getNameAsCString())); - VTTBuilder b(inits, RD, *this); + std::vector inits; + VTTBuilder b(inits, RD, CGM); - llvm::Constant *C; - llvm::ArrayType *type = llvm::ArrayType::get(Ptr8Ty, inits.size()); - C = llvm::ConstantArray::get(type, inits); - llvm::GlobalVariable *vtt = new llvm::GlobalVariable(getModule(), type, true, - linktype, C, Name); - bool Hidden = getDeclVisibilityMode(RD) == LangOptions::Hidden; - if (Hidden) - vtt->setVisibility(llvm::GlobalVariable::HiddenVisibility); - return llvm::ConstantExpr::getBitCast(vtt, Ptr8Ty); + const llvm::Type *Int8PtrTy = llvm::Type::getInt8PtrTy(CGM.getLLVMContext()); + const llvm::ArrayType *Type = llvm::ArrayType::get(Int8PtrTy, inits.size()); + + llvm::Constant *Init = llvm::ConstantArray::get(Type, inits); + + llvm::GlobalVariable *VTT = + new llvm::GlobalVariable(CGM.getModule(), Type, /*isConstant=*/true, + Linkage, Init, Name); + CGM.setGlobalVisibility(VTT, RD); + + return VTT; } -void CGVtableInfo::GenerateClassData(const CXXRecordDecl *RD) { - Vtables[RD] = CGM.GenerateVtable(RD, RD); - CGM.GenerateRtti(RD); - CGM.GenerateVTT(RD); -} - -llvm::Constant *CGVtableInfo::getVtable(const CXXRecordDecl *RD) { - llvm::Constant *&vtbl = Vtables[RD]; - if (vtbl) - return vtbl; - vtbl = CGM.GenerateVtable(RD, RD); - - bool CreateDefinition = true; - - const ASTRecordLayout &Layout = CGM.getContext().getASTRecordLayout(RD); - if (const CXXMethodDecl *KeyFunction = Layout.getKeyFunction()) { - if (!KeyFunction->getBody()) { - // If there is a KeyFunction, and it isn't defined, just build a - // reference to the vtable. - CreateDefinition = false; - } +void CGVtableInfo::GenerateClassData(llvm::GlobalVariable::LinkageTypes Linkage, + const CXXRecordDecl *RD) { + llvm::GlobalVariable *&Vtable = Vtables[RD]; + if (Vtable) { + assert(Vtable->getInitializer() && "Vtable doesn't have a definition!"); + return; } - - if (CreateDefinition) { - CGM.GenerateRtti(RD); - CGM.GenerateVTT(RD); - } - return vtbl; + + Vtable = GenerateVtable(Linkage, /*GenerateDefinition=*/true, RD, RD, 0); + GenerateVTT(Linkage, RD); } -llvm::Constant *CGVtableInfo::getCtorVtable(const CXXRecordDecl *LayoutClass, - const CXXRecordDecl *RD, - uint64_t Offset) { - return CGM.GenerateVtable(LayoutClass, RD, Offset); +llvm::GlobalVariable *CGVtableInfo::getVtable(const CXXRecordDecl *RD) { + llvm::GlobalVariable *Vtable = Vtables.lookup(RD); + + if (!Vtable) + Vtable = GenerateVtable(llvm::GlobalValue::ExternalLinkage, + /*GenerateDefinition=*/false, RD, RD, 0); + + return Vtable; +} + +llvm::GlobalVariable * +CGVtableInfo::getCtorVtable(const CXXRecordDecl *LayoutClass, + const CXXRecordDecl *RD, uint64_t Offset) { + return GenerateVtable(llvm::GlobalValue::InternalLinkage, + /*GenerateDefinition=*/true, + LayoutClass, RD, Offset); } void CGVtableInfo::MaybeEmitVtable(GlobalDecl GD) { const CXXMethodDecl *MD = cast(GD.getDecl()); const CXXRecordDecl *RD = MD->getParent(); - const ASTRecordLayout &Layout = CGM.getContext().getASTRecordLayout(RD); + // If the class doesn't have a vtable we don't need to emit one. + if (!RD->isDynamicClass()) + return; // Get the key function. - const CXXMethodDecl *KeyFunction = Layout.getKeyFunction(); + const CXXMethodDecl *KeyFunction = CGM.getContext().getKeyFunction(RD); - if (!KeyFunction) { - // If there's no key function, we don't want to emit the vtable here. - return; + if (KeyFunction) { + // We don't have the right key function. + if (KeyFunction->getCanonicalDecl() != MD->getCanonicalDecl()) + return; + + // If the key function is a destructor, we only want to emit the vtable + // once, so do it for the complete destructor. + if (isa(MD) && GD.getDtorType() != Dtor_Complete) + return; + } else { + // If there is no key function, we only want to emit the vtable if we are + // emitting a constructor. + if (!isa(MD) || GD.getCtorType() != Ctor_Complete) + return; } - // Check if we have the key function. - if (KeyFunction->getCanonicalDecl() != MD->getCanonicalDecl()) - return; + llvm::GlobalVariable::LinkageTypes Linkage; + if (RD->isInAnonymousNamespace() || !RD->hasLinkage()) + Linkage = llvm::GlobalVariable::InternalLinkage; + else if (KeyFunction && !MD->isInlined()) + Linkage = llvm::GlobalVariable::ExternalLinkage; + else + Linkage = llvm::GlobalVariable::WeakODRLinkage; - // If the key function is a destructor, we only want to emit the vtable once, - // so do it for the complete destructor. - if (isa(MD) && GD.getDtorType() != Dtor_Complete) - return; - // Emit the data. - GenerateClassData(RD); + GenerateClassData(Linkage, RD); + + for (CXXRecordDecl::method_iterator i = RD->method_begin(), + e = RD->method_end(); i != e; ++i) { + if ((*i)->isVirtual() && ((*i)->hasInlineBody() || (*i)->isImplicit())) { + if (const CXXDestructorDecl *DD = dyn_cast(*i)) { + CGM.BuildThunksForVirtual(GlobalDecl(DD, Dtor_Complete)); + CGM.BuildThunksForVirtual(GlobalDecl(DD, Dtor_Deleting)); + } else { + CGM.BuildThunksForVirtual(GlobalDecl(*i)); + } + } + } } diff --git a/lib/CodeGen/CGVtable.h b/lib/CodeGen/CGVtable.h index 5c2b74c9dd86..eed5b64085b0 100644 --- a/lib/CodeGen/CGVtable.h +++ b/lib/CodeGen/CGVtable.h @@ -15,12 +15,10 @@ #define CLANG_CODEGEN_CGVTABLE_H #include "llvm/ADT/DenseMap.h" +#include "llvm/ADT/DenseSet.h" +#include "llvm/GlobalVariable.h" #include "GlobalDecl.h" -namespace llvm { - class Constant; -} - namespace clang { class CXXRecordDecl; @@ -64,6 +62,11 @@ class CovariantThunkAdjustment { }; class CGVtableInfo { +public: + typedef std::vector > + AdjustmentVectorTy; + +private: CodeGenModule &CGM; /// MethodVtableIndices - Contains the index (relative to the vtable address @@ -79,12 +82,17 @@ class CGVtableInfo { typedef llvm::DenseMap VirtualBaseClassIndiciesTy; VirtualBaseClassIndiciesTy VirtualBaseClassIndicies; - llvm::DenseMap Vtables; + /// Vtables - All the vtables which have been defined. + llvm::DenseMap Vtables; /// NumVirtualFunctionPointers - Contains the number of virtual function /// pointers in the vtable for a given record decl. llvm::DenseMap NumVirtualFunctionPointers; + typedef llvm::DenseMap SavedAdjustmentsTy; + SavedAdjustmentsTy SavedAdjustments; + llvm::DenseSet SavedAdjustmentRecords; + /// getNumVirtualFunctionPointers - Return the number of virtual function /// pointers in the vtable for a given record decl. uint64_t getNumVirtualFunctionPointers(const CXXRecordDecl *RD); @@ -94,8 +102,19 @@ class CGVtableInfo { /// GenerateClassData - Generate all the class data requires to be generated /// upon definition of a KeyFunction. This includes the vtable, the /// rtti data structure and the VTT. - void GenerateClassData(const CXXRecordDecl *RD); - + /// + /// \param Linkage - The desired linkage of the vtable, the RTTI and the VTT. + void GenerateClassData(llvm::GlobalVariable::LinkageTypes Linkage, + const CXXRecordDecl *RD); + + llvm::GlobalVariable * + GenerateVtable(llvm::GlobalVariable::LinkageTypes Linkage, + bool GenerateDefinition, const CXXRecordDecl *LayoutClass, + const CXXRecordDecl *RD, uint64_t Offset); + + llvm::GlobalVariable *GenerateVTT(llvm::GlobalVariable::LinkageTypes Linkage, + const CXXRecordDecl *RD); + public: CGVtableInfo(CodeGenModule &CGM) : CGM(CGM) { } @@ -113,9 +132,17 @@ class CGVtableInfo { int64_t getVirtualBaseOffsetIndex(const CXXRecordDecl *RD, const CXXRecordDecl *VBase); - llvm::Constant *getVtable(const CXXRecordDecl *RD); - llvm::Constant *getCtorVtable(const CXXRecordDecl *RD, - const CXXRecordDecl *Class, uint64_t Offset); + AdjustmentVectorTy *getAdjustments(GlobalDecl GD); + + /// getVtableAddressPoint - returns the address point of the vtable for the + /// given record decl. + /// FIXME: This should return a list of address points. + uint64_t getVtableAddressPoint(const CXXRecordDecl *RD); + + llvm::GlobalVariable *getVtable(const CXXRecordDecl *RD); + llvm::GlobalVariable *getCtorVtable(const CXXRecordDecl *RD, + const CXXRecordDecl *Class, + uint64_t Offset); void MaybeEmitVtable(GlobalDecl GD); diff --git a/lib/CodeGen/CMakeLists.txt b/lib/CodeGen/CMakeLists.txt index 92814169d0ab..3c264847402e 100644 --- a/lib/CodeGen/CMakeLists.txt +++ b/lib/CodeGen/CMakeLists.txt @@ -8,6 +8,7 @@ add_clang_library(clangCodeGen CGCXX.cpp CGDebugInfo.cpp CGDecl.cpp + CGDeclCXX.cpp CGException.cpp CGExpr.cpp CGExprAgg.cpp @@ -19,7 +20,7 @@ add_clang_library(clangCodeGen CGObjCGNU.cpp CGObjCMac.cpp CGRecordLayoutBuilder.cpp - CGRtti.cpp + CGRTTI.cpp CGStmt.cpp CGTemporaries.cpp CGVtable.cpp diff --git a/lib/CodeGen/CodeGenFunction.cpp b/lib/CodeGen/CodeGenFunction.cpp index 6e0a77ca1b0b..28df9e4d7861 100644 --- a/lib/CodeGen/CodeGenFunction.cpp +++ b/lib/CodeGen/CodeGenFunction.cpp @@ -19,6 +19,7 @@ #include "clang/AST/ASTContext.h" #include "clang/AST/Decl.h" #include "clang/AST/DeclCXX.h" +#include "clang/AST/StmtCXX.h" #include "llvm/Target/TargetData.h" using namespace clang; using namespace CodeGen; @@ -30,9 +31,12 @@ CodeGenFunction::CodeGenFunction(CodeGenModule &cgm) DebugInfo(0), IndirectBranch(0), SwitchInsn(0), CaseRangeBlock(0), InvokeDest(0), CXXThisDecl(0), CXXVTTDecl(0), - ConditionalBranchLevel(0) { + ConditionalBranchLevel(0), TerminateHandler(0), TrapBB(0), + UniqueAggrDestructorCount(0) { LLVMIntTy = ConvertType(getContext().IntTy); LLVMPointerWidth = Target.getPointerWidth(0); + Exceptions = getContext().getLangOptions().Exceptions; + CatchUndefined = getContext().getLangOptions().CatchUndefined; } ASTContext &CodeGenFunction::getContext() const { @@ -130,6 +134,7 @@ void CodeGenFunction::FinishFunction(SourceLocation EndLoc) { } EmitFunctionEpilog(*CurFnInfo, ReturnValue); + EmitEndEHSpec(CurCodeDecl); // If someone did an indirect goto, emit the indirect goto block at the end of // the function. @@ -179,9 +184,6 @@ void CodeGenFunction::StartFunction(GlobalDecl GD, QualType RetTy, AllocaInsertPt->setName("allocapt"); ReturnBlock = createBasicBlock("return"); - ReturnValue = 0; - if (!RetTy->isVoidType()) - ReturnValue = CreateTempAlloca(ConvertType(RetTy), "retval"); Builder.SetInsertPoint(EntryBB); @@ -195,15 +197,26 @@ void CodeGenFunction::StartFunction(GlobalDecl GD, QualType RetTy, DI->EmitFunctionStart(CGM.getMangledName(GD), FnType, CurFn, Builder); } else { // Just use LLVM function name. - - // FIXME: Remove unnecessary conversion to std::string when API settles. - DI->EmitFunctionStart(std::string(Fn->getName()).c_str(), - FnType, CurFn, Builder); + DI->EmitFunctionStart(Fn->getName(), FnType, CurFn, Builder); } } // FIXME: Leaked. CurFnInfo = &CGM.getTypes().getFunctionInfo(FnRetTy, Args); + + if (RetTy->isVoidType()) { + // Void type; nothing to return. + ReturnValue = 0; + } else if (CurFnInfo->getReturnInfo().getKind() == ABIArgInfo::Indirect && + hasAggregateLLVMType(CurFnInfo->getReturnType())) { + // Indirect aggregate return; emit returned value directly into sret slot. + // This reduces code size, and is also affects correctness in C++. + ReturnValue = CurFn->arg_begin(); + } else { + ReturnValue = CreateTempAlloca(ConvertType(RetTy), "retval"); + } + + EmitStartEHSpec(CurCodeDecl); EmitFunctionProlog(*CurFnInfo, CurFn, Args); // If any of the arguments have a variably modified type, make sure to @@ -245,6 +258,8 @@ void CodeGenFunction::GenerateCode(GlobalDecl GD, FunctionArgList Args; + CurGD = GD; + OuterTryBlock = 0; if (const CXXMethodDecl *MD = dyn_cast(FD)) { if (MD->isInstance()) { // Create the implicit 'this' decl. @@ -276,7 +291,6 @@ void CodeGenFunction::GenerateCode(GlobalDecl GD, FProto->getArgType(i))); } - // FIXME: Support CXXTryStmt here, too. if (const CompoundStmt *S = FD->getCompoundBody()) { StartFunction(GD, FD->getResultType(), Fn, Args, S->getLBracLoc()); @@ -341,6 +355,13 @@ void CodeGenFunction::GenerateCode(GlobalDecl GD, } else { assert(false && "Cannot synthesize unknown implicit function"); } + } else if (const Stmt *S = FD->getBody()) { + if (const CXXTryStmt *TS = dyn_cast(S)) { + OuterTryBlock = TS; + StartFunction(GD, FD->getResultType(), Fn, Args, TS->getTryLoc()); + EmitStmt(TS); + FinishFunction(TS->getEndLoc()); + } } // Destroy the 'this' declaration. @@ -606,8 +627,11 @@ llvm::Value* CodeGenFunction::EmitVAListRef(const Expr* E) { } void CodeGenFunction::PushCleanupBlock(llvm::BasicBlock *CleanupEntryBlock, - llvm::BasicBlock *CleanupExitBlock) { - CleanupEntries.push_back(CleanupEntry(CleanupEntryBlock, CleanupExitBlock)); + llvm::BasicBlock *CleanupExitBlock, + llvm::BasicBlock *PreviousInvokeDest, + bool EHOnly) { + CleanupEntries.push_back(CleanupEntry(CleanupEntryBlock, CleanupExitBlock, + PreviousInvokeDest, EHOnly)); } void CodeGenFunction::EmitCleanupBlocks(size_t OldCleanupStackSize) { @@ -629,6 +653,10 @@ CodeGenFunction::CleanupBlockInfo CodeGenFunction::PopCleanupBlock() { std::vector BranchFixups; std::swap(BranchFixups, CE.BranchFixups); + bool EHOnly = CE.EHOnly; + + setInvokeDest(CE.PreviousInvokeDest); + CleanupEntries.pop_back(); // Check if any branch fixups pointed to the scope we just popped. If so, @@ -663,8 +691,9 @@ CodeGenFunction::CleanupBlockInfo CodeGenFunction::PopCleanupBlock() { Builder.SetInsertPoint(SwitchBlock); - llvm::Value *DestCodePtr = CreateTempAlloca(llvm::Type::getInt32Ty(VMContext), - "cleanup.dst"); + llvm::Value *DestCodePtr + = CreateTempAlloca(llvm::Type::getInt32Ty(VMContext), + "cleanup.dst"); llvm::Value *DestCode = Builder.CreateLoad(DestCodePtr, "tmp"); // Create a switch instruction to determine where to jump next. @@ -710,15 +739,16 @@ CodeGenFunction::CleanupBlockInfo CodeGenFunction::PopCleanupBlock() { new llvm::StoreInst(ID, DestCodePtr, BI); } else { // We need to jump through another cleanup block. Create a pad block - // with a branch instruction that jumps to the final destination and - // add it as a branch fixup to the current cleanup scope. + // with a branch instruction that jumps to the final destination and add + // it as a branch fixup to the current cleanup scope. // Create the pad block. llvm::BasicBlock *CleanupPad = createBasicBlock("cleanup.pad", CurFn); // Create a unique case ID. - llvm::ConstantInt *ID = llvm::ConstantInt::get(llvm::Type::getInt32Ty(VMContext), - SI->getNumSuccessors()); + llvm::ConstantInt *ID + = llvm::ConstantInt::get(llvm::Type::getInt32Ty(VMContext), + SI->getNumSuccessors()); // Store the jump destination before the branch instruction. new llvm::StoreInst(ID, DestCodePtr, BI); @@ -744,12 +774,19 @@ CodeGenFunction::CleanupBlockInfo CodeGenFunction::PopCleanupBlock() { BlockScopes.erase(Blocks[i]); } - return CleanupBlockInfo(CleanupEntryBlock, SwitchBlock, EndBlock); + return CleanupBlockInfo(CleanupEntryBlock, SwitchBlock, EndBlock, EHOnly); } void CodeGenFunction::EmitCleanupBlock() { CleanupBlockInfo Info = PopCleanupBlock(); + if (Info.EHOnly) { + // FIXME: Add this to the exceptional edge + if (Info.CleanupBlock->getNumUses() == 0) + delete Info.CleanupBlock; + return; + } + llvm::BasicBlock *CurBB = Builder.GetInsertBlock(); if (CurBB && !CurBB->getTerminator() && Info.CleanupBlock->getNumUses() == 0) { diff --git a/lib/CodeGen/CodeGenFunction.h b/lib/CodeGen/CodeGenFunction.h index 7f3204587a95..12e636c89702 100644 --- a/lib/CodeGen/CodeGenFunction.h +++ b/lib/CodeGen/CodeGenFunction.h @@ -88,11 +88,17 @@ class CodeGenFunction : public BlockFunction { QualType FnRetTy; llvm::Function *CurFn; + /// CurGD - The GlobalDecl for the current function being compiled. + GlobalDecl CurGD; + /// OuterTryBlock - This is the address of the outter most try block, 0 + /// otherwise. + const Stmt *OuterTryBlock; + /// ReturnBlock - Unified return block. llvm::BasicBlock *ReturnBlock; /// ReturnValue - The temporary alloca to hold the return value. This is null /// iff the function has no return value. - llvm::Instruction *ReturnValue; + llvm::Value *ReturnValue; /// AllocaInsertPoint - This is an instruction in the entry block before which /// we prefer to insert allocas. @@ -101,6 +107,8 @@ class CodeGenFunction : public BlockFunction { const llvm::Type *LLVMIntTy; uint32_t LLVMPointerWidth; + bool Exceptions; + bool CatchUndefined; public: /// ObjCEHValueStack - Stack of Objective-C exception values, used for /// rethrows. @@ -109,7 +117,12 @@ class CodeGenFunction : public BlockFunction { /// PushCleanupBlock - Push a new cleanup entry on the stack and set the /// passed in block as the cleanup block. void PushCleanupBlock(llvm::BasicBlock *CleanupEntryBlock, - llvm::BasicBlock *CleanupExitBlock = 0); + llvm::BasicBlock *CleanupExitBlock, + llvm::BasicBlock *PreviousInvokeDest, + bool EHOnly = false); + void PushCleanupBlock(llvm::BasicBlock *CleanupEntryBlock) { + PushCleanupBlock(CleanupEntryBlock, 0, getInvokeDest(), false); + } /// CleanupBlockInfo - A struct representing a popped cleanup block. struct CleanupBlockInfo { @@ -123,14 +136,43 @@ class CodeGenFunction : public BlockFunction { /// EndBlock - the default destination for the switch instruction. llvm::BasicBlock *EndBlock; + /// EHOnly - True iff this cleanup should only be performed on the + /// exceptional edge. + bool EHOnly; + CleanupBlockInfo(llvm::BasicBlock *cb, llvm::BasicBlock *sb, - llvm::BasicBlock *eb) - : CleanupBlock(cb), SwitchBlock(sb), EndBlock(eb) {} + llvm::BasicBlock *eb, bool ehonly = false) + : CleanupBlock(cb), SwitchBlock(sb), EndBlock(eb), EHOnly(ehonly) {} + }; + + /// EHCleanupBlock - RAII object that will create a cleanup block for the + /// exceptional edge and set the insert point to that block. When destroyed, + /// it creates the cleanup edge and sets the insert point to the previous + /// block. + class EHCleanupBlock { + CodeGenFunction& CGF; + llvm::BasicBlock *Cont; + llvm::BasicBlock *CleanupHandler; + llvm::BasicBlock *CleanupEntryBB; + llvm::BasicBlock *PreviousInvokeDest; + public: + EHCleanupBlock(CodeGenFunction &cgf) + : CGF(cgf), Cont(CGF.createBasicBlock("cont")), + CleanupHandler(CGF.createBasicBlock("ehcleanup")), + CleanupEntryBB(CGF.createBasicBlock("ehcleanup.rest")), + PreviousInvokeDest(CGF.getInvokeDest()) { + CGF.EmitBranch(Cont); + llvm::BasicBlock *TerminateHandler = CGF.getTerminateHandler(); + CGF.Builder.SetInsertPoint(CleanupEntryBB); + CGF.setInvokeDest(TerminateHandler); + } + ~EHCleanupBlock(); }; /// PopCleanupBlock - Will pop the cleanup entry on the stack, process all /// branch fixups and return a block info struct with the switch block and end - /// block. + /// block. This will also reset the invoke handler to the previous value + /// from when the cleanup block was created. CleanupBlockInfo PopCleanupBlock(); /// DelayedCleanupBlock - RAII object that will create a cleanup block and set @@ -141,11 +183,15 @@ class CodeGenFunction : public BlockFunction { llvm::BasicBlock *CurBB; llvm::BasicBlock *CleanupEntryBB; llvm::BasicBlock *CleanupExitBB; + llvm::BasicBlock *CurInvokeDest; + bool EHOnly; public: - DelayedCleanupBlock(CodeGenFunction &cgf) + DelayedCleanupBlock(CodeGenFunction &cgf, bool ehonly = false) : CGF(cgf), CurBB(CGF.Builder.GetInsertBlock()), - CleanupEntryBB(CGF.createBasicBlock("cleanup")), CleanupExitBB(0) { + CleanupEntryBB(CGF.createBasicBlock("cleanup")), CleanupExitBB(0), + CurInvokeDest(CGF.getInvokeDest()), + EHOnly(ehonly) { CGF.Builder.SetInsertPoint(CleanupEntryBB); } @@ -156,7 +202,8 @@ class CodeGenFunction : public BlockFunction { } ~DelayedCleanupBlock() { - CGF.PushCleanupBlock(CleanupEntryBB, CleanupExitBB); + CGF.PushCleanupBlock(CleanupEntryBB, CleanupExitBB, CurInvokeDest, + EHOnly); // FIXME: This is silly, move this into the builder. if (CurBB) CGF.Builder.SetInsertPoint(CurBB); @@ -303,10 +350,21 @@ class CodeGenFunction : public BlockFunction { /// inserted into the current function yet. std::vector BranchFixups; + /// PreviousInvokeDest - The invoke handler from the start of the cleanup + /// region. + llvm::BasicBlock *PreviousInvokeDest; + + /// EHOnly - Perform this only on the exceptional edge, not the main edge. + bool EHOnly; + explicit CleanupEntry(llvm::BasicBlock *CleanupEntryBlock, - llvm::BasicBlock *CleanupExitBlock) - : CleanupEntryBlock(CleanupEntryBlock), - CleanupExitBlock(CleanupExitBlock) {} + llvm::BasicBlock *CleanupExitBlock, + llvm::BasicBlock *PreviousInvokeDest, + bool ehonly) + : CleanupEntryBlock(CleanupEntryBlock), + CleanupExitBlock(CleanupExitBlock), + PreviousInvokeDest(PreviousInvokeDest), + EHOnly(ehonly) {} }; /// CleanupEntries - Stack of cleanup entries. @@ -365,7 +423,11 @@ class CodeGenFunction : public BlockFunction { /// getByrefValueFieldNumber - Given a declaration, returns the LLVM field /// number that holds the value. unsigned getByRefValueLLVMField(const ValueDecl *VD) const; - + + llvm::BasicBlock *TerminateHandler; + llvm::BasicBlock *TrapBB; + + int UniqueAggrDestructorCount; public: CodeGenFunction(CodeGenModule &cgm); @@ -441,16 +503,18 @@ class CodeGenFunction : public BlockFunction { const ThunkAdjustment &Adjustment); /// GenerateThunk - Generate a thunk for the given method - llvm::Constant *GenerateThunk(llvm::Function *Fn, const CXXMethodDecl *MD, + llvm::Constant *GenerateThunk(llvm::Function *Fn, GlobalDecl GD, bool Extern, const ThunkAdjustment &ThisAdjustment); llvm::Constant * - GenerateCovariantThunk(llvm::Function *Fn, const CXXMethodDecl *MD, + GenerateCovariantThunk(llvm::Function *Fn, GlobalDecl GD, bool Extern, const CovariantThunkAdjustment &Adjustment); void EmitCtorPrologue(const CXXConstructorDecl *CD, CXXCtorType Type); + void InitializeVtablePtrs(const CXXRecordDecl *ClassDecl); + void SynthesizeCXXCopyConstructor(const CXXConstructorDecl *Ctor, CXXCtorType Type, llvm::Function *Fn, @@ -487,6 +551,15 @@ class CodeGenFunction : public BlockFunction { /// given temporary. void EmitFunctionEpilog(const CGFunctionInfo &FI, llvm::Value *ReturnValue); + /// EmitStartEHSpec - Emit the start of the exception spec. + void EmitStartEHSpec(const Decl *D); + + /// EmitEndEHSpec - Emit the end of the exception spec. + void EmitEndEHSpec(const Decl *D); + + /// getTerminateHandler - Return a handler that just calls terminate. + llvm::BasicBlock *getTerminateHandler(); + const llvm::Type *ConvertTypeForMem(QualType T); const llvm::Type *ConvertType(QualType T); @@ -903,6 +976,7 @@ class CodeGenFunction : public BlockFunction { LValue EmitArraySubscriptExpr(const ArraySubscriptExpr *E); LValue EmitExtVectorElementExpr(const ExtVectorElementExpr *E); LValue EmitMemberExpr(const MemberExpr *E); + LValue EmitObjCIsaExpr(const ObjCIsaExpr *E); LValue EmitCompoundLiteralLValue(const CompoundLiteralExpr *E); LValue EmitConditionalOperatorLValue(const ConditionalOperator *E); LValue EmitCastLValue(const CastExpr *E); @@ -1059,9 +1133,18 @@ class CodeGenFunction : public BlockFunction { /// CreateStaticBlockVarDecl - Create a zero-initialized LLVM global for a /// static block var decl. - llvm::GlobalVariable * CreateStaticBlockVarDecl(const VarDecl &D, - const char *Separator, + llvm::GlobalVariable *CreateStaticBlockVarDecl(const VarDecl &D, + const char *Separator, llvm::GlobalValue::LinkageTypes Linkage); + + /// AddInitializerToGlobalBlockVarDecl - Add the initializer for 'D' to the + /// global variable that has already been created for it. If the initializer + /// has a different type than GV does, this may free GV and return a different + /// one. Otherwise it just returns GV. + llvm::GlobalVariable * + AddInitializerToGlobalBlockVarDecl(const VarDecl &D, + llvm::GlobalVariable *GV); + /// EmitStaticCXXBlockVarDeclInit - Create the initializer for a C++ runtime /// initialized static block var decl. @@ -1112,6 +1195,10 @@ class CodeGenFunction : public BlockFunction { /// try to simplify the codegen of the conditional based on the branch. void EmitBranchOnBoolExpr(const Expr *Cond, llvm::BasicBlock *TrueBlock, llvm::BasicBlock *FalseBlock); + + /// getTrapBB - Create a basic block that will call the trap intrinsic. We'll + /// generate a branch around the created basic block as necessary. + llvm::BasicBlock* getTrapBB(); private: void EmitReturnOfRValue(RValue RV, QualType Ty); diff --git a/lib/CodeGen/CodeGenModule.cpp b/lib/CodeGen/CodeGenModule.cpp index 4b3b122b71cf..761f34309bd6 100644 --- a/lib/CodeGen/CodeGenModule.cpp +++ b/lib/CodeGen/CodeGenModule.cpp @@ -56,7 +56,7 @@ CodeGenModule::CodeGenModule(ASTContext &C, const CodeGenOptions &CGO, Runtime = CreateMacObjCRuntime(*this); // If debug info generation is enabled, create the CGDebugInfo object. - DebugInfo = CodeGenOpts.DebugInfo ? new CGDebugInfo(this) : 0; + DebugInfo = CodeGenOpts.DebugInfo ? new CGDebugInfo(*this) : 0; } CodeGenModule::~CodeGenModule() { @@ -256,9 +256,18 @@ GetLinkageForFunction(ASTContext &Context, const FunctionDecl *FD, // The kind of external linkage this function will have, if it is not // inline or static. CodeGenModule::GVALinkage External = CodeGenModule::GVA_StrongExternal; - if (Context.getLangOptions().CPlusPlus && - FD->getTemplateSpecializationKind() == TSK_ImplicitInstantiation) - External = CodeGenModule::GVA_TemplateInstantiation; + if (Context.getLangOptions().CPlusPlus) { + TemplateSpecializationKind TSK = FD->getTemplateSpecializationKind(); + + if (TSK == TSK_ExplicitInstantiationDefinition) { + // If a function has been explicitly instantiated, then it should + // always have strong external linkage. + return CodeGenModule::GVA_StrongExternal; + } + + if (TSK == TSK_ImplicitInstantiation) + External = CodeGenModule::GVA_TemplateInstantiation; + } if (!FD->isInlined()) return External; @@ -522,6 +531,16 @@ bool CodeGenModule::MayDeferGeneration(const ValueDecl *Global) { FD->hasAttr()) return false; + // The key function for a class must never be deferred. + if (const CXXMethodDecl *MD = dyn_cast(Global)) { + const CXXRecordDecl *RD = MD->getParent(); + if (MD->isOutOfLine() && RD->isDynamicClass()) { + const CXXMethodDecl *KeyFunction = getContext().getKeyFunction(RD); + if (KeyFunction == MD->getCanonicalDecl()) + return false; + } + } + GVALinkage Linkage = GetLinkageForFunction(getContext(), FD, Features); // static, static inline, always_inline, and extern inline functions can @@ -576,11 +595,17 @@ void CodeGenModule::EmitGlobal(GlobalDecl GD) { const VarDecl *VD = cast(Global); assert(VD->isFileVarDecl() && "Cannot emit local var decl as global."); - // In C++, if this is marked "extern", defer code generation. - if (getLangOptions().CPlusPlus && !VD->getInit() && - (VD->getStorageClass() == VarDecl::Extern || - VD->isExternC())) - return; + if (getLangOptions().CPlusPlus && !VD->getInit()) { + // In C++, if this is marked "extern", defer code generation. + if (VD->getStorageClass() == VarDecl::Extern || VD->isExternC()) + return; + + // If this is a declaration of an explicit specialization of a static + // data member in a class template, don't emit it. + if (VD->isStaticDataMember() && + VD->getTemplateSpecializationKind() == TSK_ExplicitSpecialization) + return; + } // In C, if this isn't a definition, defer code generation. if (!getLangOptions().CPlusPlus && !VD->getInit()) @@ -615,8 +640,19 @@ void CodeGenModule::EmitGlobalDefinition(GlobalDecl GD) { Context.getSourceManager(), "Generating code for declaration"); - if (isa(D)) + if (const CXXMethodDecl *MD = dyn_cast(D)) { getVtableInfo().MaybeEmitVtable(GD); + if (MD->isVirtual() && MD->isOutOfLine() && + (!isa(D) || GD.getDtorType() != Dtor_Base)) { + if (isa(D)) { + GlobalDecl CanonGD(cast(D->getCanonicalDecl()), + GD.getDtorType()); + BuildThunksForVirtual(CanonGD); + } else { + BuildThunksForVirtual(MD->getCanonicalDecl()); + } + } + } if (const CXXConstructorDecl *CD = dyn_cast(D)) EmitCXXConstructor(CD, GD.getCtorType()); @@ -724,6 +760,17 @@ CodeGenModule::CreateRuntimeFunction(const llvm::FunctionType *FTy, return GetOrCreateLLVMFunction(Name, FTy, GlobalDecl()); } +static bool DeclIsConstantGlobal(ASTContext &Context, const VarDecl *D) { + if (!D->getType().isConstant(Context)) + return false; + if (Context.getLangOptions().CPlusPlus && + Context.getBaseElementType(D->getType())->getAs()) { + // FIXME: We should do something fancier here! + return false; + } + return true; +} + /// GetOrCreateLLVMGlobal - If the specified mangled name is not in the module, /// create and return an llvm GlobalVariable with the specified type. If there /// is something in the module with the specified name, return it potentially @@ -767,7 +814,7 @@ llvm::Constant *CodeGenModule::GetOrCreateLLVMGlobal(const char *MangledName, if (D) { // FIXME: This code is overly simple and should be merged with other global // handling. - GV->setConstant(D->getType().isConstant(Context)); + GV->setConstant(DeclIsConstantGlobal(Context, D)); // FIXME: Merge with other attribute handling code. if (D->getStorageClass() == VarDecl::PrivateExtern) @@ -844,7 +891,7 @@ GetLinkageForVariable(ASTContext &Context, const VarDecl *VD) { return CodeGenModule::GVA_StrongExternal; case TSK_ExplicitInstantiationDeclaration: - llvm::llvm_unreachable("Variable should not be instantiated"); + llvm_unreachable("Variable should not be instantiated"); // Fall through to treat this like any other instantiation. case TSK_ImplicitInstantiation: @@ -942,11 +989,8 @@ void CodeGenModule::EmitGlobalVarDefinition(const VarDecl *D) { // If it is safe to mark the global 'constant', do so now. GV->setConstant(false); - if (D->getType().isConstant(Context)) { - // FIXME: In C++, if the variable has a non-trivial ctor/dtor or any mutable - // members, it cannot be declared "LLVM const". + if (DeclIsConstantGlobal(Context, D)) GV->setConstant(true); - } GV->setAlignment(getContext().getDeclAlignInBytes(D)); @@ -1226,13 +1270,8 @@ llvm::Value *CodeGenModule::getBuiltinLibFunction(const FunctionDecl *FD, if (Context.BuiltinInfo.isLibFunction(BuiltinID)) Name += 10; - // Get the type for the builtin. - ASTContext::GetBuiltinTypeError Error; - QualType Type = Context.GetBuiltinType(BuiltinID, Error); - assert(Error == ASTContext::GE_None && "Can't get builtin type"); - const llvm::FunctionType *Ty = - cast(getTypes().ConvertType(Type)); + cast(getTypes().ConvertType(FD->getType())); // Unique the name through the identifier table. Name = getContext().Idents.get(Name).getNameStart(); @@ -1658,14 +1697,13 @@ void CodeGenModule::EmitTopLevelDecl(Decl *D) { case Decl::FileScopeAsm: { FileScopeAsmDecl *AD = cast(D); - std::string AsmString(AD->getAsmString()->getStrData(), - AD->getAsmString()->getByteLength()); + llvm::StringRef AsmString = AD->getAsmString()->getString(); const std::string &S = getModule().getModuleInlineAsm(); if (S.empty()) getModule().setModuleInlineAsm(AsmString); else - getModule().setModuleInlineAsm(S + '\n' + AsmString); + getModule().setModuleInlineAsm(S + '\n' + AsmString.str()); break; } diff --git a/lib/CodeGen/CodeGenModule.h b/lib/CodeGen/CodeGenModule.h index 78bc4ed845d8..cc7ec9c30160 100644 --- a/lib/CodeGen/CodeGenModule.h +++ b/lib/CodeGen/CodeGenModule.h @@ -212,34 +212,38 @@ class CodeGenModule : public BlockModule { llvm::Constant *GetAddrOfFunction(GlobalDecl GD, const llvm::Type *Ty = 0); - /// GenerateVtable - Generate the vtable for the given type. LayoutClass is - /// the class to use for the virtual base layout information. For - /// non-construction vtables, this is always the same as RD. Offset is the - /// offset in bits for the RD object in the LayoutClass, if we're generating a - /// construction vtable, otherwise 0. - llvm::Constant *GenerateVtable(const CXXRecordDecl *LayoutClass, - const CXXRecordDecl *RD, - uint64_t Offset=0); + /// GetAddrOfRTTI - Get the address of the RTTI structure for the given type. + llvm::Constant *GetAddrOfRTTI(QualType Ty); - /// GenerateVTT - Generate the VTT for the given type. - llvm::Constant *GenerateVTT(const CXXRecordDecl *RD); + /// GetAddrOfRTTI - Get the address of the RTTI structure for the given record + /// decl. + llvm::Constant *GetAddrOfRTTI(const CXXRecordDecl *RD); - /// GenerateRtti - Generate the rtti information for the given type. - llvm::Constant *GenerateRtti(const CXXRecordDecl *RD); - /// GenerateRttiRef - Generate a reference to the rtti information for the + /// GenerateRTTI - Generate the rtti information for the given type. + llvm::Constant *GenerateRTTI(const CXXRecordDecl *RD); + + /// GenerateRTTIRef - Generate a reference to the rtti information for the /// given type. - llvm::Constant *GenerateRttiRef(const CXXRecordDecl *RD); - /// GenerateRttiNonClass - Generate the rtti information for the given + llvm::Constant *GenerateRTTIRef(const CXXRecordDecl *RD); + + /// GenerateRTTI - Generate the rtti information for the given /// non-class type. - llvm::Constant *GenerateRtti(QualType Ty); + llvm::Constant *GenerateRTTI(QualType Ty); + + llvm::Constant *GetAddrOfThunk(GlobalDecl GD, + const ThunkAdjustment &ThisAdjustment); + llvm::Constant *GetAddrOfCovariantThunk(GlobalDecl GD, + const CovariantThunkAdjustment &ThisAdjustment); + void BuildThunksForVirtual(GlobalDecl GD); + void BuildThunksForVirtualRecursive(GlobalDecl GD, GlobalDecl BaseOGD); /// BuildThunk - Build a thunk for the given method. - llvm::Constant *BuildThunk(const CXXMethodDecl *MD, bool Extern, + llvm::Constant *BuildThunk(GlobalDecl GD, bool Extern, const ThunkAdjustment &ThisAdjustment); /// BuildCoVariantThunk - Build a thunk for the given method llvm::Constant * - BuildCovariantThunk(const CXXMethodDecl *MD, bool Extern, + BuildCovariantThunk(const GlobalDecl &GD, bool Extern, const CovariantThunkAdjustment &Adjustment); typedef std::pair CtorVtable_t; @@ -252,6 +256,11 @@ class CodeGenModule : public BlockModule { llvm::Constant *GetCXXBaseClassOffset(const CXXRecordDecl *ClassDecl, const CXXRecordDecl *BaseClassDecl); + /// ComputeThunkAdjustment - Returns the two parts required to compute the + /// offset for an object. + ThunkAdjustment ComputeThunkAdjustment(const CXXRecordDecl *ClassDecl, + const CXXRecordDecl *BaseClassDecl); + /// GetStringForStringLiteral - Return the appropriate bytes for a string /// literal, properly padded to match the literal type. If only the address of /// a constant is needed consider using GetAddrOfConstantStringLiteral. diff --git a/lib/CodeGen/CodeGenTypes.cpp b/lib/CodeGen/CodeGenTypes.cpp index c89879fdb6c4..cd3575c132ce 100644 --- a/lib/CodeGen/CodeGenTypes.cpp +++ b/lib/CodeGen/CodeGenTypes.cpp @@ -379,13 +379,13 @@ const llvm::Type *CodeGenTypes::ConvertNewType(QualType T) { // If we ever want to support other ABIs this needs to be abstracted. QualType ETy = cast(Ty).getPointeeType(); + const llvm::Type *PtrDiffTy = + ConvertTypeRecursive(Context.getPointerDiffType()); if (ETy->isFunctionType()) { - return llvm::StructType::get(TheModule.getContext(), - ConvertType(Context.getPointerDiffType()), - ConvertType(Context.getPointerDiffType()), + return llvm::StructType::get(TheModule.getContext(), PtrDiffTy, PtrDiffTy, NULL); } else - return ConvertType(Context.getPointerDiffType()); + return PtrDiffTy; } case Type::TemplateSpecialization: diff --git a/lib/CodeGen/GlobalDecl.h b/lib/CodeGen/GlobalDecl.h index b812020f2aa4..b054312a0185 100644 --- a/lib/CodeGen/GlobalDecl.h +++ b/lib/CodeGen/GlobalDecl.h @@ -96,15 +96,14 @@ namespace llvm { return LHS == RHS; } - static bool isPod() { - // GlobalDecl isn't *technically* a POD type. However, we can get - // away with calling it a POD type since its copy constructor, - // copy assignment operator, and destructor are all trivial. - return true; - } - }; -} + // GlobalDecl isn't *technically* a POD type. However, its copy constructor, + // copy assignment operator, and destructor are all trivial. + template <> + struct isPodLike { + static const bool value = true; + }; +} // end namespace llvm #endif diff --git a/lib/CodeGen/Mangle.cpp b/lib/CodeGen/Mangle.cpp index d6f7808c4073..90cc89445e46 100644 --- a/lib/CodeGen/Mangle.cpp +++ b/lib/CodeGen/Mangle.cpp @@ -89,8 +89,6 @@ class CXXNameMangler { void addSubstitution(QualType T); void addSubstitution(uintptr_t Ptr); - bool mangleFunctionDecl(const FunctionDecl *FD); - void mangleName(const TemplateDecl *TD, const TemplateArgument *TemplateArgs, unsigned NumTemplateArgs); @@ -99,7 +97,7 @@ class CXXNameMangler { void mangleUnscopedTemplateName(const TemplateDecl *ND); void mangleSourceName(const IdentifierInfo *II); void mangleLocalName(const NamedDecl *ND); - void mangleNestedName(const NamedDecl *ND); + void mangleNestedName(const NamedDecl *ND, const DeclContext *DC); void mangleNestedName(const TemplateDecl *TD, const TemplateArgument *TemplateArgs, unsigned NumTemplateArgs); @@ -108,6 +106,8 @@ class CXXNameMangler { void mangleOperatorName(OverloadedOperatorKind OO, unsigned Arity); void mangleQualifiers(Qualifiers Quals); + void mangleObjCMethodName(const ObjCMethodDecl *MD); + // Declare manglers for every type class. #define ABSTRACT_TYPE(CLASS, PARENT) #define NON_CANONICAL_TYPE(CLASS, PARENT) @@ -117,6 +117,8 @@ class CXXNameMangler { void mangleType(const TagType*); void mangleBareFunctionType(const FunctionType *T, bool MangleReturnType); + + void mangleIntegerLiteral(QualType T, const llvm::APSInt &Value); void mangleExpression(const Expr *E); void mangleCXXCtorType(CXXCtorType T); void mangleCXXDtorType(CXXDtorType T); @@ -169,11 +171,19 @@ bool MangleContext::shouldMangleDeclName(const NamedDecl *D) { isInExternCSystemHeader(D->getLocation())) return false; - // C functions, "main", and variables at global scope are not - // mangled. - if ((FD && FD->isMain()) || - (!FD && D->getDeclContext()->isTranslationUnit()) || - isInCLinkageSpecification(D)) + // Variables at global scope are not mangled. + if (!FD) { + const DeclContext *DC = D->getDeclContext(); + // Check for extern variable declared locally. + if (isa(DC) && D->hasLinkage()) + while (!DC->isNamespace() && !DC->isTranslationUnit()) + DC = DC->getParent(); + if (DC->isTranslationUnit()) + return false; + } + + // C functions and "main" are not mangled. + if ((FD && FD->isMain()) || isInCLinkageSpecification(D)) return false; return true; @@ -241,14 +251,32 @@ void CXXNameMangler::mangleFunctionEncoding(const FunctionDecl *FD) { mangleBareFunctionType(FT, MangleReturnType); } -static bool isStdNamespace(const NamespaceDecl *NS) { +/// isStd - Return whether a given namespace is the 'std' namespace. +static bool isStd(const NamespaceDecl *NS) { const IdentifierInfo *II = NS->getOriginalNamespace()->getIdentifier(); return II && II->isStr("std"); } +static const DeclContext *IgnoreLinkageSpecDecls(const DeclContext *DC) { + while (isa(DC)) { + assert(cast(DC)->getLanguage() == + LinkageSpecDecl::lang_cxx && "Unexpected linkage decl!"); + DC = DC->getParent(); + } + + return DC; +} + +// isStdNamespace - Return whether a given decl context is a toplevel 'std' +// namespace. static bool isStdNamespace(const DeclContext *DC) { - return DC->isNamespace() && DC->getParent()->isTranslationUnit() && - isStdNamespace(cast(DC)); + if (!DC->isNamespace()) + return false; + + if (!IgnoreLinkageSpecDecls(DC->getParent())->isTranslationUnit()) + return false; + + return isStd(cast(DC)); } static const TemplateDecl * @@ -278,6 +306,13 @@ void CXXNameMangler::mangleName(const NamedDecl *ND) { // ::= // const DeclContext *DC = ND->getDeclContext(); + + // If this is an extern variable declared locally, the relevant DeclContext + // is that of the containing namespace, or the translation unit. + if (isa(DC) && ND->hasLinkage()) + while (!DC->isNamespace() && !DC->isTranslationUnit()) + DC = DC->getParent(); + while (isa(DC)) DC = DC->getParent(); @@ -294,22 +329,17 @@ void CXXNameMangler::mangleName(const NamedDecl *ND) { return; } - if (isa(DC)) { + if (isa(DC) || isa(DC)) { mangleLocalName(ND); return; } - mangleNestedName(ND); + mangleNestedName(ND, DC); } void CXXNameMangler::mangleName(const TemplateDecl *TD, const TemplateArgument *TemplateArgs, unsigned NumTemplateArgs) { - const DeclContext *DC = TD->getDeclContext(); - while (isa(DC)) { - assert(cast(DC)->getLanguage() == - LinkageSpecDecl::lang_cxx && "Unexpected linkage decl!"); - DC = DC->getParent(); - } + const DeclContext *DC = IgnoreLinkageSpecDecls(TD->getDeclContext()); if (DC->isTranslationUnit() || isStdNamespace(DC)) { mangleUnscopedTemplateName(TD); @@ -456,8 +486,8 @@ void CXXNameMangler::mangleUnqualifiedName(const NamedDecl *ND) { break; case DeclarationName::CXXLiteralOperatorName: - // Guessing based on existing ABI. - Out << "ul"; + // FIXME: This mangling is not yet official. + Out << "li"; mangleSourceName(Name.getCXXLiteralIdentifier()); break; @@ -474,7 +504,8 @@ void CXXNameMangler::mangleSourceName(const IdentifierInfo *II) { Out << II->getLength() << II->getName(); } -void CXXNameMangler::mangleNestedName(const NamedDecl *ND) { +void CXXNameMangler::mangleNestedName(const NamedDecl *ND, + const DeclContext *DC) { // ::= N [] E // ::= N [] E @@ -488,7 +519,7 @@ void CXXNameMangler::mangleNestedName(const NamedDecl *ND) { mangleTemplatePrefix(TD); mangleTemplateArgumentList(*TemplateArgs); } else { - manglePrefix(ND->getDeclContext()); + manglePrefix(DC); mangleUnqualifiedName(ND); } @@ -512,9 +543,14 @@ void CXXNameMangler::mangleLocalName(const NamedDecl *ND) { // := Z E s [] // := _ Out << 'Z'; - mangleFunctionEncoding(cast(ND->getDeclContext())); + + if (const ObjCMethodDecl *MD = dyn_cast(ND->getDeclContext())) + mangleObjCMethodName(MD); + else + mangleFunctionEncoding(cast(ND->getDeclContext())); + Out << 'E'; - mangleSourceName(ND->getIdentifier()); + mangleUnqualifiedName(ND); } void CXXNameMangler::manglePrefix(const DeclContext *DC) { @@ -523,7 +559,6 @@ void CXXNameMangler::manglePrefix(const DeclContext *DC) { // ::= // ::= # empty // ::= - // FIXME: We only handle mangling of namespaces and classes at the moment. while (isa(DC)) DC = DC->getParent(); @@ -654,10 +689,13 @@ CXXNameMangler::mangleOperatorName(OverloadedOperatorKind OO, unsigned Arity) { case OO_Call: Out << "cl"; break; // ::= ix # [] case OO_Subscript: Out << "ix"; break; - // UNSUPPORTED: ::= qu # ? + + // ::= qu # ? + // The conditional operator can't be overloaded, but we still handle it when + // mangling expressions. + case OO_Conditional: Out << "qu"; break; case OO_None: - case OO_Conditional: case NUM_OVERLOADED_OPERATORS: assert(false && "Not an overloaded operator"); break; @@ -676,6 +714,21 @@ void CXXNameMangler::mangleQualifiers(Qualifiers Quals) { // FIXME: For now, just drop all extension qualifiers on the floor. } +void CXXNameMangler::mangleObjCMethodName(const ObjCMethodDecl *MD) { + llvm::SmallString<64> Name; + llvm::raw_svector_ostream OS(Name); + + const ObjCContainerDecl *CD = + dyn_cast(MD->getDeclContext()); + assert (CD && "Missing container decl in GetNameForMethod"); + OS << (MD->isInstanceMethod() ? '-' : '+') << '[' << CD->getName(); + if (const ObjCCategoryImplDecl *CID = dyn_cast(CD)) + OS << '(' << CID->getNameAsString() << ')'; + OS << ' ' << MD->getSelector().getAsString() << ']'; + + Out << OS.str().size() << OS.str(); +} + void CXXNameMangler::mangleType(QualType T) { // Only operate on the canonical type! T = Context.getASTContext().getCanonicalType(T); @@ -694,7 +747,7 @@ void CXXNameMangler::mangleType(QualType T) { #define ABSTRACT_TYPE(CLASS, PARENT) #define NON_CANONICAL_TYPE(CLASS, PARENT) \ case Type::CLASS: \ - llvm::llvm_unreachable("can't mangle non-canonical type " #CLASS "Type"); \ + llvm_unreachable("can't mangle non-canonical type " #CLASS "Type"); \ return; #define TYPE(CLASS, PARENT) \ case Type::CLASS: \ @@ -788,7 +841,7 @@ void CXXNameMangler::mangleType(const FunctionProtoType *T) { Out << 'E'; } void CXXNameMangler::mangleType(const FunctionNoProtoType *T) { - llvm::llvm_unreachable("Can't mangle K&R function prototypes"); + llvm_unreachable("Can't mangle K&R function prototypes"); } void CXXNameMangler::mangleBareFunctionType(const FunctionType *T, bool MangleReturnType) { @@ -814,6 +867,12 @@ void CXXNameMangler::mangleBareFunctionType(const FunctionType *T, Out << 'z'; } +// ::= +// ::= +void CXXNameMangler::mangleType(const UnresolvedUsingType *T) { + mangleName(T->getDecl()); +} + // ::= // ::= void CXXNameMangler::mangleType(const EnumType *T) { @@ -823,10 +882,7 @@ void CXXNameMangler::mangleType(const RecordType *T) { mangleType(static_cast(T)); } void CXXNameMangler::mangleType(const TagType *T) { - if (!T->getDecl()->getIdentifier()) - mangleName(T->getDecl()->getTypedefForAnonDecl()); - else - mangleName(T->getDecl()); + mangleName(T->getDecl()); } // ::= @@ -960,6 +1016,24 @@ void CXXNameMangler::mangleType(const TypenameType *T) { Out << 'E'; } +void CXXNameMangler::mangleIntegerLiteral(QualType T, + const llvm::APSInt &Value) { + // ::= L E # integer literal + Out << 'L'; + + mangleType(T); + if (T->isBooleanType()) { + // Boolean values are encoded as 0/1. + Out << (Value.getBoolValue() ? '1' : '0'); + } else { + if (Value.isNegative()) + Out << 'n'; + Value.abs().print(Out, false); + } + Out << 'E'; + +} + void CXXNameMangler::mangleExpression(const Expr *E) { // ::= // ::= @@ -978,6 +1052,32 @@ void CXXNameMangler::mangleExpression(const Expr *E) { switch (E->getStmtClass()) { default: assert(false && "Unhandled expression kind!"); + case Expr::UnaryOperatorClass: { + const UnaryOperator *UO = cast(E); + mangleOperatorName(UnaryOperator::getOverloadedOperator(UO->getOpcode()), + /*Arity=*/1); + mangleExpression(UO->getSubExpr()); + break; + } + + case Expr::BinaryOperatorClass: { + const BinaryOperator *BO = cast(E); + mangleOperatorName(BinaryOperator::getOverloadedOperator(BO->getOpcode()), + /*Arity=*/2); + mangleExpression(BO->getLHS()); + mangleExpression(BO->getRHS()); + break; + } + + case Expr::ConditionalOperatorClass: { + const ConditionalOperator *CO = cast(E); + mangleOperatorName(OO_Conditional, /*Arity=*/3); + mangleExpression(CO->getCond()); + mangleExpression(CO->getLHS()); + mangleExpression(CO->getRHS()); + break; + } + case Expr::ParenExprClass: mangleExpression(cast(E)->getSubExpr()); break; @@ -1014,6 +1114,11 @@ void CXXNameMangler::mangleExpression(const Expr *E) { break; } + case Expr::IntegerLiteralClass: + mangleIntegerLiteral(E->getType(), + llvm::APSInt(cast(E)->getValue())); + break; + } } @@ -1090,23 +1195,9 @@ void CXXNameMangler::mangleTemplateArgument(const TemplateArgument &A) { mangleExpression(A.getAsExpr()); Out << 'E'; break; - case TemplateArgument::Integral: { - // ::= L E # integer literal - - const llvm::APSInt *Integral = A.getAsIntegral(); - Out << 'L'; - mangleType(A.getIntegralType()); - if (A.getIntegralType()->isBooleanType()) { - // Boolean values are encoded as 0/1. - Out << (Integral->getBoolValue() ? '1' : '0'); - } else { - if (Integral->isNegative()) - Out << 'n'; - Integral->abs().print(Out, false); - } - Out << 'E'; + case TemplateArgument::Integral: + mangleIntegerLiteral(A.getIntegralType(), *A.getAsIntegral()); break; - } case TemplateArgument::Declaration: { // ::= L E # external name @@ -1228,12 +1319,29 @@ static bool isCharSpecialization(QualType T, const char *Name) { return SD->getIdentifier()->getName() == Name; } +template +bool isStreamCharSpecialization(const ClassTemplateSpecializationDecl *SD, + const char (&Str)[StrLen]) { + if (!SD->getIdentifier()->isStr(Str)) + return false; + + const TemplateArgumentList &TemplateArgs = SD->getTemplateArgs(); + if (TemplateArgs.size() != 2) + return false; + + if (!isCharType(TemplateArgs[0].getAsType())) + return false; + + if (!isCharSpecialization(TemplateArgs[1].getAsType(), "char_traits")) + return false; + + return true; +} + bool CXXNameMangler::mangleStandardSubstitution(const NamedDecl *ND) { // ::= St # ::std:: - // FIXME: type_info == comes out as __ZNK3std9type_infoeqERKS0_ instead of - // __ZNKSt9type_infoeqERKS_ if (const NamespaceDecl *NS = dyn_cast(ND)) { - if (isStdNamespace(NS)) { + if (isStd(NS)) { Out << "St"; return true; } @@ -1280,23 +1388,26 @@ bool CXXNameMangler::mangleStandardSubstitution(const NamedDecl *ND) { return true; } + // ::= Si # ::std::basic_istream > + if (isStreamCharSpecialization(SD, "basic_istream")) { + Out << "Si"; + return true; + } + // ::= So # ::std::basic_ostream > - if (SD->getIdentifier()->isStr("basic_ostream")) { - const TemplateArgumentList &TemplateArgs = SD->getTemplateArgs(); - - if (TemplateArgs.size() != 2) - return false; - - if (!isCharType(TemplateArgs[0].getAsType())) - return false; - - if (!isCharSpecialization(TemplateArgs[1].getAsType(), "char_traits")) - return false; - + if (isStreamCharSpecialization(SD, "basic_ostream")) { Out << "So"; return true; } + + // ::= Sd # ::std::basic_iostream > + if (isStreamCharSpecialization(SD, "basic_iostream")) { + Out << "Sd"; + return true; + } } return false; } @@ -1362,7 +1473,6 @@ void MangleContext::mangleCXXDtor(const CXXDestructorDecl *D, CXXDtorType Type, void MangleContext::mangleThunk(const FunctionDecl *FD, const ThunkAdjustment &ThisAdjustment, llvm::SmallVectorImpl &Res) { - // FIXME: Hum, we might have to thunk these, fix. assert(!isa(FD) && "Use mangleCXXDtor for destructor decls!"); @@ -1374,15 +1484,26 @@ void MangleContext::mangleThunk(const FunctionDecl *FD, Mangler.mangleFunctionEncoding(FD); } +void MangleContext::mangleCXXDtorThunk(const CXXDestructorDecl *D, + CXXDtorType Type, + const ThunkAdjustment &ThisAdjustment, + llvm::SmallVectorImpl &Res) { + // ::= T + // # base is the nominal target function of thunk + CXXNameMangler Mangler(*this, Res, D, Type); + Mangler.getStream() << "_ZT"; + Mangler.mangleCallOffset(ThisAdjustment); + Mangler.mangleFunctionEncoding(D); +} + /// \brief Mangles the a covariant thunk for the declaration D and emits that /// name to the given output stream. void MangleContext::mangleCovariantThunk(const FunctionDecl *FD, const CovariantThunkAdjustment& Adjustment, llvm::SmallVectorImpl &Res) { - // FIXME: Hum, we might have to thunk these, fix. assert(!isa(FD) && - "Use mangleCXXDtor for destructor decls!"); + "No such thing as a covariant thunk for a destructor!"); // ::= Tc // # base is the nominal target function of thunk @@ -1434,7 +1555,7 @@ void MangleContext::mangleCXXCtorVtable(const CXXRecordDecl *RD, int64_t Offset, Mangler.mangleName(Type); } -void MangleContext::mangleCXXRtti(QualType Ty, +void MangleContext::mangleCXXRTTI(QualType Ty, llvm::SmallVectorImpl &Res) { // ::= TI # typeinfo structure CXXNameMangler Mangler(*this, Res); @@ -1442,7 +1563,7 @@ void MangleContext::mangleCXXRtti(QualType Ty, Mangler.mangleType(Ty); } -void MangleContext::mangleCXXRttiName(QualType Ty, +void MangleContext::mangleCXXRTTIName(QualType Ty, llvm::SmallVectorImpl &Res) { // ::= TS # typeinfo name (null terminated byte string) CXXNameMangler Mangler(*this, Res); diff --git a/lib/CodeGen/Mangle.h b/lib/CodeGen/Mangle.h index 65b1d9f9618d..8d9629528d63 100644 --- a/lib/CodeGen/Mangle.h +++ b/lib/CodeGen/Mangle.h @@ -67,6 +67,9 @@ class MangleContext { void mangleThunk(const FunctionDecl *FD, const ThunkAdjustment &ThisAdjustment, llvm::SmallVectorImpl &); + void mangleCXXDtorThunk(const CXXDestructorDecl *D, CXXDtorType Type, + const ThunkAdjustment &ThisAdjustment, + llvm::SmallVectorImpl &); void mangleCovariantThunk(const FunctionDecl *FD, const CovariantThunkAdjustment& Adjustment, llvm::SmallVectorImpl &); @@ -76,8 +79,8 @@ class MangleContext { void mangleCXXCtorVtable(const CXXRecordDecl *RD, int64_t Offset, const CXXRecordDecl *Type, llvm::SmallVectorImpl &); - void mangleCXXRtti(QualType T, llvm::SmallVectorImpl &); - void mangleCXXRttiName(QualType T, llvm::SmallVectorImpl &); + void mangleCXXRTTI(QualType T, llvm::SmallVectorImpl &); + void mangleCXXRTTIName(QualType T, llvm::SmallVectorImpl &); void mangleCXXCtor(const CXXConstructorDecl *D, CXXCtorType Type, llvm::SmallVectorImpl &); void mangleCXXDtor(const CXXDestructorDecl *D, CXXDtorType Type, diff --git a/lib/CodeGen/TargetABIInfo.cpp b/lib/CodeGen/TargetABIInfo.cpp index 2bc61753a031..7be1eadfd9a2 100644 --- a/lib/CodeGen/TargetABIInfo.cpp +++ b/lib/CodeGen/TargetABIInfo.cpp @@ -17,37 +17,37 @@ #include "clang/AST/RecordLayout.h" #include "llvm/Type.h" #include "llvm/ADT/Triple.h" -#include - +#include "llvm/Support/raw_ostream.h" using namespace clang; using namespace CodeGen; ABIInfo::~ABIInfo() {} void ABIArgInfo::dump() const { - fprintf(stderr, "(ABIArgInfo Kind="); + llvm::raw_ostream &OS = llvm::errs(); + OS << "(ABIArgInfo Kind="; switch (TheKind) { case Direct: - fprintf(stderr, "Direct"); + OS << "Direct"; break; case Extend: - fprintf(stderr, "Extend"); + OS << "Extend"; break; case Ignore: - fprintf(stderr, "Ignore"); + OS << "Ignore"; break; case Coerce: - fprintf(stderr, "Coerce Type="); - getCoerceToType()->print(llvm::errs()); + OS << "Coerce Type="; + getCoerceToType()->print(OS); break; case Indirect: - fprintf(stderr, "Indirect Align=%d", getIndirectAlign()); + OS << "Indirect Align=" << getIndirectAlign(); break; case Expand: - fprintf(stderr, "Expand"); + OS << "Expand"; break; } - fprintf(stderr, ")\n"); + OS << ")\n"; } static bool isEmptyRecord(ASTContext &Context, QualType T, bool AllowArrays); diff --git a/lib/Driver/Driver.cpp b/lib/Driver/Driver.cpp index 87357cf08a3b..dbe7bd9b682d 100644 --- a/lib/Driver/Driver.cpp +++ b/lib/Driver/Driver.cpp @@ -41,9 +41,9 @@ using namespace clang; // Used to set values for "production" clang, for releases. // #define USE_PRODUCTION_CLANG -Driver::Driver(const char *_Name, const char *_Dir, - const char *_DefaultHostTriple, - const char *_DefaultImageName, +Driver::Driver(llvm::StringRef _Name, llvm::StringRef _Dir, + llvm::StringRef _DefaultHostTriple, + llvm::StringRef _DefaultImageName, bool IsProduction, Diagnostic &_Diags) : Opts(createDriverOptTable()), Diags(_Diags), Name(_Name), Dir(_Dir), DefaultHostTriple(_DefaultHostTriple), @@ -113,81 +113,57 @@ Compilation *Driver::BuildCompilation(int argc, const char **argv) { const char **Start = argv + 1, **End = argv + argc; const char *HostTriple = DefaultHostTriple.c_str(); - // Read -ccc args. + InputArgList *Args = ParseArgStrings(Start, End); + + // -no-canonical-prefixes is used very early in main. + Args->ClaimAllArgs(options::OPT_no_canonical_prefixes); + + // Extract -ccc args. // // FIXME: We need to figure out where this behavior should live. Most of it // should be outside in the client; the parts that aren't should have proper // options, either by introducing new ones or by overloading gcc ones like -V // or -b. - for (; Start != End && memcmp(*Start, "-ccc-", 5) == 0; ++Start) { - const char *Opt = *Start + 5; + CCCPrintOptions = Args->hasArg(options::OPT_ccc_print_options); + CCCPrintActions = Args->hasArg(options::OPT_ccc_print_phases); + CCCPrintBindings = Args->hasArg(options::OPT_ccc_print_bindings); + CCCIsCXX = Args->hasArg(options::OPT_ccc_cxx) || CCCIsCXX; + CCCEcho = Args->hasArg(options::OPT_ccc_echo); + if (const Arg *A = Args->getLastArg(options::OPT_ccc_gcc_name)) + CCCGenericGCCName = A->getValue(*Args); + CCCUseClangCXX = Args->hasFlag(options::OPT_ccc_clang_cxx, + options::OPT_ccc_no_clang_cxx, + CCCUseClangCXX); + CCCUsePCH = Args->hasFlag(options::OPT_ccc_pch_is_pch, + options::OPT_ccc_pch_is_pth); + CCCUseClang = !Args->hasArg(options::OPT_ccc_no_clang); + CCCUseClangCPP = !Args->hasArg(options::OPT_ccc_no_clang_cpp); + if (const Arg *A = Args->getLastArg(options::OPT_ccc_clang_archs)) { + llvm::StringRef Cur = A->getValue(*Args); - if (!strcmp(Opt, "print-options")) { - CCCPrintOptions = true; - } else if (!strcmp(Opt, "print-phases")) { - CCCPrintActions = true; - } else if (!strcmp(Opt, "print-bindings")) { - CCCPrintBindings = true; - } else if (!strcmp(Opt, "cxx")) { - CCCIsCXX = true; - } else if (!strcmp(Opt, "echo")) { - CCCEcho = true; + CCCClangArchs.clear(); + while (!Cur.empty()) { + std::pair Split = Cur.split(','); - } else if (!strcmp(Opt, "gcc-name")) { - assert(Start+1 < End && "FIXME: -ccc- argument handling."); - CCCGenericGCCName = *++Start; + if (!Split.first.empty()) { + llvm::Triple::ArchType Arch = + llvm::Triple(Split.first, "", "").getArch(); - } else if (!strcmp(Opt, "clang-cxx")) { - CCCUseClangCXX = true; - } else if (!strcmp(Opt, "no-clang-cxx")) { - CCCUseClangCXX = false; - } else if (!strcmp(Opt, "pch-is-pch")) { - CCCUsePCH = true; - } else if (!strcmp(Opt, "pch-is-pth")) { - CCCUsePCH = false; - } else if (!strcmp(Opt, "no-clang")) { - CCCUseClang = false; - } else if (!strcmp(Opt, "no-clang-cpp")) { - CCCUseClangCPP = false; - } else if (!strcmp(Opt, "clang-archs")) { - assert(Start+1 < End && "FIXME: -ccc- argument handling."); - llvm::StringRef Cur = *++Start; - - CCCClangArchs.clear(); - while (!Cur.empty()) { - std::pair Split = Cur.split(','); - - if (!Split.first.empty()) { - llvm::Triple::ArchType Arch = - llvm::Triple(Split.first, "", "").getArch(); - - if (Arch == llvm::Triple::UnknownArch) { - // FIXME: Error handling. - llvm::errs() << "invalid arch name: " << Split.first << "\n"; - exit(1); - } - - CCCClangArchs.insert(Arch); + if (Arch == llvm::Triple::UnknownArch) { + Diag(clang::diag::err_drv_invalid_arch_name) << Arch; + continue; } - Cur = Split.second; + CCCClangArchs.insert(Arch); } - } else if (!strcmp(Opt, "host-triple")) { - assert(Start+1 < End && "FIXME: -ccc- argument handling."); - HostTriple = *++Start; - } else if (!strcmp(Opt, "install-dir")) { - assert(Start+1 < End && "FIXME: -ccc- argument handling."); - Dir = *++Start; - - } else { - // FIXME: Error handling. - llvm::errs() << "invalid option: " << *Start << "\n"; - exit(1); + Cur = Split.second; } } - - InputArgList *Args = ParseArgStrings(Start, End); + if (const Arg *A = Args->getLastArg(options::OPT_ccc_host_triple)) + HostTriple = A->getValue(*Args); + if (const Arg *A = Args->getLastArg(options::OPT_ccc_install_dir)) + Dir = A->getValue(*Args); Host = GetHostInfo(HostTriple); @@ -287,110 +263,11 @@ void Driver::PrintOptions(const ArgList &Args) const { } } -static std::string getOptionHelpName(const OptTable &Opts, options::ID Id) { - std::string Name = Opts.getOptionName(Id); - - // Add metavar, if used. - switch (Opts.getOptionKind(Id)) { - case Option::GroupClass: case Option::InputClass: case Option::UnknownClass: - assert(0 && "Invalid option with help text."); - - case Option::MultiArgClass: case Option::JoinedAndSeparateClass: - assert(0 && "Cannot print metavar for this kind of option."); - - case Option::FlagClass: - break; - - case Option::SeparateClass: case Option::JoinedOrSeparateClass: - Name += ' '; - // FALLTHROUGH - case Option::JoinedClass: case Option::CommaJoinedClass: - Name += Opts.getOptionMetaVar(Id); - break; - } - - return Name; -} - +// FIXME: Move -ccc options to real options in the .td file (or eliminate), and +// then move to using OptTable::PrintHelp. void Driver::PrintHelp(bool ShowHidden) const { - llvm::raw_ostream &OS = llvm::outs(); - - OS << "OVERVIEW: clang \"gcc-compatible\" driver\n"; - OS << '\n'; - OS << "USAGE: " << Name << " [options] \n"; - OS << '\n'; - OS << "OPTIONS:\n"; - - // Render help text into (option, help) pairs. - std::vector< std::pair > OptionHelp; - - for (unsigned i = 0, e = getOpts().getNumOptions(); i != e; ++i) { - options::ID Id = (options::ID) (i + 1); - if (const char *Text = getOpts().getOptionHelpText(Id)) - OptionHelp.push_back(std::make_pair(getOptionHelpName(getOpts(), Id), - Text)); - } - - if (ShowHidden) { - OptionHelp.push_back(std::make_pair("\nDRIVER OPTIONS:","")); - OptionHelp.push_back(std::make_pair("-ccc-cxx", - "Act as a C++ driver")); - OptionHelp.push_back(std::make_pair("-ccc-gcc-name", - "Name for native GCC compiler")); - OptionHelp.push_back(std::make_pair("-ccc-clang-cxx", - "Enable the clang compiler for C++")); - OptionHelp.push_back(std::make_pair("-ccc-no-clang-cxx", - "Disable the clang compiler for C++")); - OptionHelp.push_back(std::make_pair("-ccc-no-clang", - "Disable the clang compiler")); - OptionHelp.push_back(std::make_pair("-ccc-no-clang-cpp", - "Disable the clang preprocessor")); - OptionHelp.push_back(std::make_pair("-ccc-clang-archs", - "Comma separate list of architectures " - "to use the clang compiler for")); - OptionHelp.push_back(std::make_pair("-ccc-pch-is-pch", - "Use lazy PCH for precompiled headers")); - OptionHelp.push_back(std::make_pair("-ccc-pch-is-pth", - "Use pretokenized headers for precompiled headers")); - - OptionHelp.push_back(std::make_pair("\nDEBUG/DEVELOPMENT OPTIONS:","")); - OptionHelp.push_back(std::make_pair("-ccc-host-triple", - "Simulate running on the given target")); - OptionHelp.push_back(std::make_pair("-ccc-install-dir", - "Simulate installation in the given directory")); - OptionHelp.push_back(std::make_pair("-ccc-print-options", - "Dump parsed command line arguments")); - OptionHelp.push_back(std::make_pair("-ccc-print-phases", - "Dump list of actions to perform")); - OptionHelp.push_back(std::make_pair("-ccc-print-bindings", - "Show bindings of tools to actions")); - OptionHelp.push_back(std::make_pair("CCC_ADD_ARGS", - "(ENVIRONMENT VARIABLE) Comma separated list of " - "arguments to prepend to the command line")); - } - - // Find the maximum option length. - unsigned OptionFieldWidth = 0; - for (unsigned i = 0, e = OptionHelp.size(); i != e; ++i) { - // Skip titles. - if (!OptionHelp[i].second) - continue; - - // Limit the amount of padding we are willing to give up for alignment. - unsigned Length = OptionHelp[i].first.size(); - if (Length <= 23) - OptionFieldWidth = std::max(OptionFieldWidth, Length); - } - - for (unsigned i = 0, e = OptionHelp.size(); i != e; ++i) { - const std::string &Option = OptionHelp[i].first; - OS << " " << Option; - for (int j = Option.length(), e = OptionFieldWidth; j < e; ++j) - OS << ' '; - OS << ' ' << OptionHelp[i].second << '\n'; - } - - OS.flush(); + getOpts().PrintHelp(llvm::outs(), Name.c_str(), + "clang \"gcc-compatible\" driver", ShowHidden); } void Driver::PrintVersion(const Compilation &C, llvm::raw_ostream &OS) const { diff --git a/lib/Driver/DriverOptions.cpp b/lib/Driver/DriverOptions.cpp index d1af95cd4504..72aaf56ad3e1 100644 --- a/lib/Driver/DriverOptions.cpp +++ b/lib/Driver/DriverOptions.cpp @@ -14,7 +14,7 @@ using namespace clang::driver; using namespace clang::driver::options; -static OptTable::Info InfoTable[] = { +static const OptTable::Info InfoTable[] = { #define OPTION(NAME, ID, KIND, GROUP, ALIAS, FLAGS, PARAM, \ HELPTEXT, METAVAR) \ { NAME, HELPTEXT, METAVAR, Option::KIND##Class, FLAGS, PARAM, \ diff --git a/lib/Driver/Job.cpp b/lib/Driver/Job.cpp index 280e7c4a5a09..1bd123e220ec 100644 --- a/lib/Driver/Job.cpp +++ b/lib/Driver/Job.cpp @@ -14,10 +14,11 @@ using namespace clang::driver; Job::~Job() {} -Command::Command(const Action &_Source, const char *_Executable, - const ArgStringList &_Arguments) - : Job(CommandClass), Source(_Source), Executable(_Executable), - Arguments(_Arguments) { +Command::Command(const Action &_Source, const Tool &_Creator, + const char *_Executable, const ArgStringList &_Arguments) + : Job(CommandClass), Source(_Source), Creator(_Creator), + Executable(_Executable), Arguments(_Arguments) +{ } PipedJob::PipedJob() : Job(PipedJobClass) {} diff --git a/lib/Driver/OptTable.cpp b/lib/Driver/OptTable.cpp index f68a1d8db77c..f69d5d806d28 100644 --- a/lib/Driver/OptTable.cpp +++ b/lib/Driver/OptTable.cpp @@ -11,9 +11,10 @@ #include "clang/Driver/Arg.h" #include "clang/Driver/ArgList.h" #include "clang/Driver/Option.h" +#include "llvm/Support/raw_ostream.h" #include #include - +#include using namespace clang::driver; using namespace clang::driver::options; @@ -255,3 +256,122 @@ InputArgList *OptTable::ParseArgs(const char **ArgBegin, const char **ArgEnd, return Args; } + +static std::string getOptionHelpName(const OptTable &Opts, OptSpecifier Id) { + std::string Name = Opts.getOptionName(Id); + + // Add metavar, if used. + switch (Opts.getOptionKind(Id)) { + case Option::GroupClass: case Option::InputClass: case Option::UnknownClass: + assert(0 && "Invalid option with help text."); + + case Option::MultiArgClass: case Option::JoinedAndSeparateClass: + assert(0 && "Cannot print metavar for this kind of option."); + + case Option::FlagClass: + break; + + case Option::SeparateClass: case Option::JoinedOrSeparateClass: + Name += ' '; + // FALLTHROUGH + case Option::JoinedClass: case Option::CommaJoinedClass: + if (const char *MetaVarName = Opts.getOptionMetaVar(Id)) + Name += MetaVarName; + else + Name += ""; + break; + } + + return Name; +} + +static void PrintHelpOptionList(llvm::raw_ostream &OS, llvm::StringRef Title, + std::vector > &OptionHelp) { + OS << Title << ":\n"; + + // Find the maximum option length. + unsigned OptionFieldWidth = 0; + for (unsigned i = 0, e = OptionHelp.size(); i != e; ++i) { + // Skip titles. + if (!OptionHelp[i].second) + continue; + + // Limit the amount of padding we are willing to give up for alignment. + unsigned Length = OptionHelp[i].first.size(); + if (Length <= 23) + OptionFieldWidth = std::max(OptionFieldWidth, Length); + } + + const unsigned InitialPad = 2; + for (unsigned i = 0, e = OptionHelp.size(); i != e; ++i) { + const std::string &Option = OptionHelp[i].first; + int Pad = OptionFieldWidth - int(Option.size()); + OS.indent(InitialPad) << Option; + + // Break on long option names. + if (Pad < 0) { + OS << "\n"; + Pad = OptionFieldWidth + InitialPad; + } + OS.indent(Pad + 1) << OptionHelp[i].second << '\n'; + } +} + +static const char *getOptionHelpGroup(const OptTable &Opts, OptSpecifier Id) { + unsigned GroupID = Opts.getOptionGroupID(Id); + + // If not in a group, return the default help group. + if (!GroupID) + return "OPTIONS"; + + // Abuse the help text of the option groups to store the "help group" + // name. + // + // FIXME: Split out option groups. + if (const char *GroupHelp = Opts.getOptionHelpText(GroupID)) + return GroupHelp; + + // Otherwise keep looking. + return getOptionHelpGroup(Opts, GroupID); +} + +void OptTable::PrintHelp(llvm::raw_ostream &OS, const char *Name, + const char *Title, bool ShowHidden) const { + OS << "OVERVIEW: " << Title << "\n"; + OS << '\n'; + OS << "USAGE: " << Name << " [options] \n"; + OS << '\n'; + + // Render help text into a map of group-name to a list of (option, help) + // pairs. + typedef std::map > > helpmap_ty; + helpmap_ty GroupedOptionHelp; + + for (unsigned i = 0, e = getNumOptions(); i != e; ++i) { + unsigned Id = i + 1; + + // FIXME: Split out option groups. + if (getOptionKind(Id) == Option::GroupClass) + continue; + + if (!ShowHidden && isOptionHelpHidden(Id)) + continue; + + if (const char *Text = getOptionHelpText(Id)) { + const char *HelpGroup = getOptionHelpGroup(*this, Id); + const std::string &OptName = getOptionHelpName(*this, Id); + GroupedOptionHelp[HelpGroup].push_back(std::make_pair(OptName, Text)); + } + } + + for (helpmap_ty::iterator it = GroupedOptionHelp .begin(), + ie = GroupedOptionHelp.end(); it != ie; ++it) { + if (it != GroupedOptionHelp .begin()) + OS << "\n"; + PrintHelpOptionList(OS, it->first, it->second); + } + + OS.flush(); +} diff --git a/lib/Driver/ToolChains.cpp b/lib/Driver/ToolChains.cpp index af639523f1d7..420573dea2a8 100644 --- a/lib/Driver/ToolChains.cpp +++ b/lib/Driver/ToolChains.cpp @@ -510,7 +510,7 @@ DerivedArgList *Darwin::TranslateArgs(InputArgList &Args, DAL->append(DAL->MakeJoinedArg(0, MArch, "armv7a")); else - llvm::llvm_unreachable("invalid Darwin arch"); + llvm_unreachable("invalid Darwin arch"); } return DAL; diff --git a/lib/Driver/Tools.cpp b/lib/Driver/Tools.cpp index eb165cf6a531..70597ab91396 100644 --- a/lib/Driver/Tools.cpp +++ b/lib/Driver/Tools.cpp @@ -9,6 +9,7 @@ #include "Tools.h" +#include "clang/Basic/Version.h" #include "clang/Driver/Action.h" #include "clang/Driver/Arg.h" #include "clang/Driver/ArgList.h" @@ -419,14 +420,17 @@ void Clang::AddARMTargetArgs(const ArgList &Args, // // FIXME: This changes CPP defines, we need -target-soft-float. CmdArgs.push_back("-msoft-float"); - CmdArgs.push_back("-mfloat-abi=soft"); + CmdArgs.push_back("-mfloat-abi"); + CmdArgs.push_back("soft"); } else if (FloatABI == "softfp") { // Floating point operations are hard, but argument passing is soft. - CmdArgs.push_back("-mfloat-abi=soft"); + CmdArgs.push_back("-mfloat-abi"); + CmdArgs.push_back("soft"); } else { // Floating point operations and argument passing are hard. assert(FloatABI == "hard" && "Invalid float abi!"); - CmdArgs.push_back("-mfloat-abi=hard"); + CmdArgs.push_back("-mfloat-abi"); + CmdArgs.push_back("hard"); } } @@ -590,6 +594,11 @@ void Clang::ConstructJob(Compilation &C, const JobAction &JA, assert(Inputs.size() == 1 && "Unable to handle multiple inputs."); + // Invoke ourselves in -cc1 mode. + // + // FIXME: Implement custom jobs for internal actions. + CmdArgs.push_back("-cc1"); + // Add the "effective" target triple. CmdArgs.push_back("-triple"); std::string TripleStr = getEffectiveClangTriple(D, getToolChain(), Args); @@ -647,6 +656,9 @@ void Clang::ConstructJob(Compilation &C, const JobAction &JA, // Enable region store model by default. CmdArgs.push_back("-analyzer-store=region"); + // Treat blocks as analysis entry points. + CmdArgs.push_back("-analyzer-opt-analyze-nested-blocks"); + // Add default argument set. if (!Args.hasArg(options::OPT__analyzer_no_default_checks)) { CmdArgs.push_back("-warn-dead-stores"); @@ -787,7 +799,8 @@ void Clang::ConstructJob(Compilation &C, const JobAction &JA, Arg *Unsupported; if ((Unsupported = Args.getLastArg(options::OPT_MG)) || (Unsupported = Args.getLastArg(options::OPT_MQ)) || - (Unsupported = Args.getLastArg(options::OPT_iframework))) + (Unsupported = Args.getLastArg(options::OPT_iframework)) || + (Unsupported = Args.getLastArg(options::OPT_fshort_enums))) D.Diag(clang::diag::err_drv_clang_unsupported) << Unsupported->getOption().getName(); @@ -803,7 +816,16 @@ void Clang::ConstructJob(Compilation &C, const JobAction &JA, Args.AddLastArg(CmdArgs, options::OPT_nostdinc); Args.AddLastArg(CmdArgs, options::OPT_nobuiltininc); - Args.AddLastArg(CmdArgs, options::OPT_isysroot); + // 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())); // Add preprocessing options like -I, -D, etc. if we are using the // preprocessor. @@ -877,7 +899,13 @@ void Clang::ConstructJob(Compilation &C, const JobAction &JA, CmdArgs.push_back(Args.MakeArgString(llvm::Twine(N))); } - // Forward -f options which we can pass directly. + if (const Arg *A = Args.getLastArg(options::OPT_fvisibility_EQ)) { + CmdArgs.push_back("-fvisibility"); + CmdArgs.push_back(A->getValue(Args)); + } + + // Forward -f (flag) options which we can pass directly. + Args.AddLastArg(CmdArgs, options::OPT_fcatch_undefined_behavior); Args.AddLastArg(CmdArgs, options::OPT_femit_all_decls); Args.AddLastArg(CmdArgs, options::OPT_ffreestanding); Args.AddLastArg(CmdArgs, options::OPT_fheinous_gnu_extensions); @@ -890,7 +918,6 @@ void Clang::ConstructJob(Compilation &C, const JobAction &JA, Args.AddLastArg(CmdArgs, options::OPT_fdiagnostics_print_source_range_info); Args.AddLastArg(CmdArgs, options::OPT_ftime_report); Args.AddLastArg(CmdArgs, options::OPT_ftrapv); - Args.AddLastArg(CmdArgs, options::OPT_fvisibility_EQ); Args.AddLastArg(CmdArgs, options::OPT_fwritable_strings); Args.AddLastArg(CmdArgs, options::OPT_pthread); @@ -1027,7 +1054,7 @@ void Clang::ConstructJob(Compilation &C, const JobAction &JA, // Default to -fno-builtin-str{cat,cpy} on Darwin for ARM. // - // FIXME: This is disabled until clang-cc supports -fno-builtin-foo. PR4941. + // FIXME: This is disabled until clang -cc1 supports -fno-builtin-foo. PR4941. #if 0 if (getToolChain().getTriple().getOS() == llvm::Triple::Darwin && (getToolChain().getTriple().getArch() == llvm::Triple::arm || @@ -1077,8 +1104,8 @@ void Clang::ConstructJob(Compilation &C, const JobAction &JA, Args.AddAllArgs(CmdArgs, options::OPT_undef); const char *Exec = - Args.MakeArgString(getToolChain().GetProgramPath(C, "clang-cc")); - Dest.addCommand(new Command(JA, Exec, CmdArgs)); + Args.MakeArgString(getToolChain().GetProgramPath(C, "clang")); + Dest.addCommand(new Command(JA, *this, Exec, CmdArgs)); // Explicitly warn that these options are unsupported, even though // we are allowing compilation to continue. @@ -1200,7 +1227,7 @@ void gcc::Common::ConstructJob(Compilation &C, const JobAction &JA, getToolChain().getHost().getDriver().CCCGenericGCCName.c_str(); const char *Exec = Args.MakeArgString(getToolChain().GetProgramPath(C, GCCName)); - Dest.addCommand(new Command(JA, Exec, CmdArgs)); + Dest.addCommand(new Command(JA, *this, Exec, CmdArgs)); } void gcc::Preprocess::RenderExtraToolArgs(ArgStringList &CmdArgs) const { @@ -1589,7 +1616,7 @@ void darwin::Preprocess::ConstructJob(Compilation &C, const JobAction &JA, const char *CC1Name = getCC1Name(Inputs[0].getType()); const char *Exec = Args.MakeArgString(getToolChain().GetProgramPath(C, CC1Name)); - Dest.addCommand(new Command(JA, Exec, CmdArgs)); + Dest.addCommand(new Command(JA, *this, Exec, CmdArgs)); } void darwin::Compile::ConstructJob(Compilation &C, const JobAction &JA, @@ -1683,7 +1710,7 @@ void darwin::Compile::ConstructJob(Compilation &C, const JobAction &JA, const char *CC1Name = getCC1Name(Inputs[0].getType()); const char *Exec = Args.MakeArgString(getToolChain().GetProgramPath(C, CC1Name)); - Dest.addCommand(new Command(JA, Exec, CmdArgs)); + Dest.addCommand(new Command(JA, *this, Exec, CmdArgs)); } void darwin::Assemble::ConstructJob(Compilation &C, const JobAction &JA, @@ -1738,7 +1765,7 @@ void darwin::Assemble::ConstructJob(Compilation &C, const JobAction &JA, const char *Exec = Args.MakeArgString(getToolChain().GetProgramPath(C, "as")); - Dest.addCommand(new Command(JA, Exec, CmdArgs)); + Dest.addCommand(new Command(JA, *this, Exec, CmdArgs)); } /// Helper routine for seeing if we should use dsymutil; this is a @@ -2152,7 +2179,7 @@ void darwin::Link::ConstructJob(Compilation &C, const JobAction &JA, const char *Exec = Args.MakeArgString(getToolChain().GetProgramPath(C, "ld")); - Dest.addCommand(new Command(JA, Exec, CmdArgs)); + Dest.addCommand(new Command(JA, *this, Exec, CmdArgs)); // Find the first non-empty base input (we want to ignore linker // inputs). @@ -2182,7 +2209,7 @@ void darwin::Link::ConstructJob(Compilation &C, const JobAction &JA, Args.MakeArgString(getToolChain().GetProgramPath(C, "dsymutil")); ArgStringList CmdArgs; CmdArgs.push_back(Output.getFilename()); - C.getJobs().addCommand(new Command(JA, Exec, CmdArgs)); + C.getJobs().addCommand(new Command(JA, *this, Exec, CmdArgs)); } } } @@ -2208,7 +2235,7 @@ void darwin::Lipo::ConstructJob(Compilation &C, const JobAction &JA, } const char *Exec = Args.MakeArgString(getToolChain().GetProgramPath(C, "lipo")); - Dest.addCommand(new Command(JA, Exec, CmdArgs)); + Dest.addCommand(new Command(JA, *this, Exec, CmdArgs)); } void auroraux::Assemble::ConstructJob(Compilation &C, const JobAction &JA, @@ -2238,7 +2265,7 @@ void auroraux::Assemble::ConstructJob(Compilation &C, const JobAction &JA, const char *Exec = Args.MakeArgString(getToolChain().GetProgramPath(C, "gas")); - Dest.addCommand(new Command(JA, Exec, CmdArgs)); + Dest.addCommand(new Command(JA, *this, Exec, CmdArgs)); } void auroraux::Link::ConstructJob(Compilation &C, const JobAction &JA, @@ -2339,7 +2366,7 @@ void auroraux::Link::ConstructJob(Compilation &C, const JobAction &JA, const char *Exec = Args.MakeArgString(getToolChain().GetProgramPath(C, "ld")); - Dest.addCommand(new Command(JA, Exec, CmdArgs)); + Dest.addCommand(new Command(JA, *this, Exec, CmdArgs)); } void openbsd::Assemble::ConstructJob(Compilation &C, const JobAction &JA, @@ -2369,7 +2396,7 @@ void openbsd::Assemble::ConstructJob(Compilation &C, const JobAction &JA, const char *Exec = Args.MakeArgString(getToolChain().GetProgramPath(C, "as")); - Dest.addCommand(new Command(JA, Exec, CmdArgs)); + Dest.addCommand(new Command(JA, *this, Exec, CmdArgs)); } void openbsd::Link::ConstructJob(Compilation &C, const JobAction &JA, @@ -2469,7 +2496,7 @@ void openbsd::Link::ConstructJob(Compilation &C, const JobAction &JA, const char *Exec = Args.MakeArgString(getToolChain().GetProgramPath(C, "ld")); - Dest.addCommand(new Command(JA, Exec, CmdArgs)); + Dest.addCommand(new Command(JA, *this, Exec, CmdArgs)); } void freebsd::Assemble::ConstructJob(Compilation &C, const JobAction &JA, @@ -2504,7 +2531,7 @@ void freebsd::Assemble::ConstructJob(Compilation &C, const JobAction &JA, const char *Exec = Args.MakeArgString(getToolChain().GetProgramPath(C, "as")); - Dest.addCommand(new Command(JA, Exec, CmdArgs)); + Dest.addCommand(new Command(JA, *this, Exec, CmdArgs)); } void freebsd::Link::ConstructJob(Compilation &C, const JobAction &JA, @@ -2617,7 +2644,7 @@ void freebsd::Link::ConstructJob(Compilation &C, const JobAction &JA, const char *Exec = Args.MakeArgString(getToolChain().GetProgramPath(C, "ld")); - Dest.addCommand(new Command(JA, Exec, CmdArgs)); + Dest.addCommand(new Command(JA, *this, Exec, CmdArgs)); } /// DragonFly Tools @@ -2656,7 +2683,7 @@ void dragonfly::Assemble::ConstructJob(Compilation &C, const JobAction &JA, const char *Exec = Args.MakeArgString(getToolChain().GetProgramPath(C, "as")); - Dest.addCommand(new Command(JA, Exec, CmdArgs)); + Dest.addCommand(new Command(JA, *this, Exec, CmdArgs)); } void dragonfly::Link::ConstructJob(Compilation &C, const JobAction &JA, @@ -2780,5 +2807,5 @@ void dragonfly::Link::ConstructJob(Compilation &C, const JobAction &JA, const char *Exec = Args.MakeArgString(getToolChain().GetProgramPath(C, "ld")); - Dest.addCommand(new Command(JA, Exec, CmdArgs)); + Dest.addCommand(new Command(JA, *this, Exec, CmdArgs)); } diff --git a/lib/Driver/Types.cpp b/lib/Driver/Types.cpp index 339767722716..433af03237cd 100644 --- a/lib/Driver/Types.cpp +++ b/lib/Driver/Types.cpp @@ -23,7 +23,7 @@ struct TypeInfo { ID PreprocessedType; }; -static TypeInfo TypeInfos[] = { +static const TypeInfo TypeInfos[] = { #define TYPE(NAME, ID, PP_TYPE, TEMP_SUFFIX, FLAGS) \ { NAME, FLAGS, TEMP_SUFFIX, TY_##PP_TYPE, }, #include "clang/Driver/Types.def" @@ -31,7 +31,7 @@ static TypeInfo TypeInfos[] = { }; static const unsigned numTypes = sizeof(TypeInfos) / sizeof(TypeInfos[0]); -static TypeInfo &getInfo(unsigned id) { +static const TypeInfo &getInfo(unsigned id) { assert(id > 0 && id - 1 < numTypes && "Invalid Type ID."); return TypeInfos[id - 1]; } diff --git a/lib/Frontend/ASTConsumers.cpp b/lib/Frontend/ASTConsumers.cpp index 9a30f59465f8..f1a666646ff9 100644 --- a/lib/Frontend/ASTConsumers.cpp +++ b/lib/Frontend/ASTConsumers.cpp @@ -28,8 +28,6 @@ #include "llvm/Support/Timer.h" #include "llvm/Support/raw_ostream.h" #include "llvm/System/Path.h" -#include - using namespace clang; //===----------------------------------------------------------------------===// @@ -405,8 +403,13 @@ void DeclContextPrinter::PrintDeclContext(const DeclContext* DC, Out << " " << OPD->getNameAsString() << "\n"; break; } + case Decl::FunctionTemplate: { + FunctionTemplateDecl* FTD = cast(*I); + Out << " " << FTD->getNameAsString() << "\n"; + break; + } default: - fprintf(stderr, "DeclKind: %d \"%s\"\n", DK, I->getDeclKindName()); + Out << "DeclKind: " << DK << '"' << I->getDeclKindName() << "\"\n"; assert(0 && "decl unhandled"); } } diff --git a/lib/Frontend/ASTUnit.cpp b/lib/Frontend/ASTUnit.cpp index f647c8a23705..48296c7289e3 100644 --- a/lib/Frontend/ASTUnit.cpp +++ b/lib/Frontend/ASTUnit.cpp @@ -17,27 +17,29 @@ #include "clang/AST/ASTConsumer.h" #include "clang/AST/DeclVisitor.h" #include "clang/AST/StmtVisitor.h" +#include "clang/Driver/Compilation.h" +#include "clang/Driver/Driver.h" +#include "clang/Driver/Job.h" +#include "clang/Driver/Tool.h" #include "clang/Frontend/CompilerInstance.h" #include "clang/Frontend/FrontendActions.h" +#include "clang/Frontend/FrontendDiagnostic.h" #include "clang/Frontend/FrontendOptions.h" #include "clang/Lex/HeaderSearch.h" #include "clang/Lex/Preprocessor.h" #include "clang/Basic/TargetOptions.h" #include "clang/Basic/TargetInfo.h" #include "clang/Basic/Diagnostic.h" -#include "llvm/LLVMContext.h" +#include "llvm/System/Host.h" #include "llvm/System/Path.h" using namespace clang; -ASTUnit::ASTUnit(DiagnosticClient *diagClient) : tempFile(false) { - Diags.setClient(diagClient ? diagClient : new TextDiagnosticBuffer()); +ASTUnit::ASTUnit(bool _MainFileIsAST) + : tempFile(false), MainFileIsAST(_MainFileIsAST) { } ASTUnit::~ASTUnit() { if (tempFile) llvm::sys::Path(getPCHFileName()).eraseFromDisk(); - - // The ASTUnit object owns the DiagnosticClient. - delete Diags.getClient(); } namespace { @@ -90,19 +92,19 @@ class PCHInfoCollector : public PCHReaderListener { } // anonymous namespace const std::string &ASTUnit::getOriginalSourceFileName() { - return dyn_cast(Ctx->getExternalSource())->getOriginalSourceFile(); + return OriginalSourceFile; } const std::string &ASTUnit::getPCHFileName() { + assert(isMainFileAST() && "Not an ASTUnit from a PCH file!"); return dyn_cast(Ctx->getExternalSource())->getFileName(); } ASTUnit *ASTUnit::LoadFromPCHFile(const std::string &Filename, - std::string *ErrMsg, - DiagnosticClient *diagClient, + Diagnostic &Diags, bool OnlyLocalDecls, bool UseBumpAllocator) { - llvm::OwningPtr AST(new ASTUnit(diagClient)); + llvm::OwningPtr AST(new ASTUnit(true)); AST->OnlyLocalDecls = OnlyLocalDecls; AST->HeaderInfo.reset(new HeaderSearch(AST->getFileManager())); @@ -118,7 +120,7 @@ ASTUnit *ASTUnit::LoadFromPCHFile(const std::string &Filename, llvm::OwningPtr Source; Reader.reset(new PCHReader(AST->getSourceManager(), AST->getFileManager(), - AST->Diags)); + Diags)); Reader->setListener(new PCHInfoCollector(LangInfo, HeaderInfo, TargetTriple, Predefines, Counter)); @@ -128,11 +130,12 @@ ASTUnit *ASTUnit::LoadFromPCHFile(const std::string &Filename, case PCHReader::Failure: case PCHReader::IgnorePCH: - if (ErrMsg) - *ErrMsg = "Could not load PCH file"; + Diags.Report(diag::err_fe_unable_to_load_pch); return NULL; } + AST->OriginalSourceFile = Reader->getOriginalSourceFile(); + // PCH loaded successfully. Now create the preprocessor. // Get information about the target being compiled for. @@ -143,8 +146,8 @@ ASTUnit *ASTUnit::LoadFromPCHFile(const std::string &Filename, TargetOpts.CPU = ""; TargetOpts.Features.clear(); TargetOpts.Triple = TargetTriple; - AST->Target.reset(TargetInfo::CreateTargetInfo(AST->Diags, TargetOpts)); - AST->PP.reset(new Preprocessor(AST->Diags, LangInfo, *AST->Target.get(), + AST->Target.reset(TargetInfo::CreateTargetInfo(Diags, TargetOpts)); + AST->PP.reset(new Preprocessor(Diags, LangInfo, *AST->Target.get(), AST->getSourceManager(), HeaderInfo)); Preprocessor &PP = *AST->PP.get(); @@ -177,13 +180,30 @@ ASTUnit *ASTUnit::LoadFromPCHFile(const std::string &Filename, namespace { -class NullAction : public ASTFrontendAction { +class TopLevelDeclTrackerConsumer : public ASTConsumer { + ASTUnit &Unit; + +public: + TopLevelDeclTrackerConsumer(ASTUnit &_Unit) : Unit(_Unit) {} + + void HandleTopLevelDecl(DeclGroupRef D) { + for (DeclGroupRef::iterator it = D.begin(), ie = D.end(); it != ie; ++it) + Unit.getTopLevelDecls().push_back(*it); + } +}; + +class TopLevelDeclTrackerAction : public ASTFrontendAction { +public: + ASTUnit &Unit; + virtual ASTConsumer *CreateASTConsumer(CompilerInstance &CI, llvm::StringRef InFile) { - return new ASTConsumer(); + return new TopLevelDeclTrackerConsumer(Unit); } public: + TopLevelDeclTrackerAction(ASTUnit &_Unit) : Unit(_Unit) {} + virtual bool hasCodeCompletionSupport() const { return false; } }; @@ -191,12 +211,11 @@ class NullAction : public ASTFrontendAction { ASTUnit *ASTUnit::LoadFromCompilerInvocation(const CompilerInvocation &CI, Diagnostic &Diags, - bool OnlyLocalDecls, - bool UseBumpAllocator) { + bool OnlyLocalDecls) { // Create the compiler instance to use for building the AST. - CompilerInstance Clang(&llvm::getGlobalContext(), false); + CompilerInstance Clang; llvm::OwningPtr AST; - NullAction Act; + llvm::OwningPtr Act; Clang.getInvocation() = CI; @@ -221,9 +240,10 @@ ASTUnit *ASTUnit::LoadFromCompilerInvocation(const CompilerInvocation &CI, "FIXME: AST inputs not yet supported here!"); // Create the AST unit. - // - // FIXME: Use the provided diagnostic client. - AST.reset(new ASTUnit()); + AST.reset(new ASTUnit(false)); + + AST->OnlyLocalDecls = OnlyLocalDecls; + AST->OriginalSourceFile = Clang.getFrontendOpts().Inputs[0].second; // Create a file manager object to provide access to and cache the filesystem. Clang.setFileManager(&AST->getFileManager()); @@ -234,20 +254,22 @@ ASTUnit *ASTUnit::LoadFromCompilerInvocation(const CompilerInvocation &CI, // Create the preprocessor. Clang.createPreprocessor(); - if (!Act.BeginSourceFile(Clang, Clang.getFrontendOpts().Inputs[0].second, + Act.reset(new TopLevelDeclTrackerAction(*AST)); + if (!Act->BeginSourceFile(Clang, Clang.getFrontendOpts().Inputs[0].second, /*IsAST=*/false)) goto error; - Act.Execute(); + Act->Execute(); - // Steal the created context and preprocessor, and take back the source and - // file managers. + // Steal the created target, context, and preprocessor, and take back the + // source and file managers. AST->Ctx.reset(Clang.takeASTContext()); AST->PP.reset(Clang.takePreprocessor()); Clang.takeSourceManager(); Clang.takeFileManager(); + AST->Target.reset(Clang.takeTarget()); - Act.EndSourceFile(); + Act->EndSourceFile(); Clang.takeDiagnosticClient(); Clang.takeDiagnostics(); @@ -261,3 +283,53 @@ ASTUnit *ASTUnit::LoadFromCompilerInvocation(const CompilerInvocation &CI, Clang.takeDiagnostics(); return 0; } + +ASTUnit *ASTUnit::LoadFromCommandLine(const char **ArgBegin, + const char **ArgEnd, + Diagnostic &Diags, + llvm::StringRef ResourceFilesPath, + bool OnlyLocalDecls, + bool UseBumpAllocator) { + llvm::SmallVector Args; + Args.push_back(""); // FIXME: Remove dummy argument. + Args.insert(Args.end(), ArgBegin, ArgEnd); + + // FIXME: Find a cleaner way to force the driver into restricted modes. We + // also want to force it to use clang. + Args.push_back("-fsyntax-only"); + + // FIXME: We shouldn't have to pass in the path info. + driver::Driver TheDriver("clang", "/", llvm::sys::getHostTriple(), + "a.out", false, Diags); + llvm::OwningPtr C( + TheDriver.BuildCompilation(Args.size(), Args.data())); + + // We expect to get back exactly one command job, if we didn't something + // failed. + const driver::JobList &Jobs = C->getJobs(); + if (Jobs.size() != 1 || !isa(Jobs.begin())) { + llvm::SmallString<256> Msg; + llvm::raw_svector_ostream OS(Msg); + C->PrintJob(OS, C->getJobs(), "; ", true); + Diags.Report(diag::err_fe_expected_compiler_job) << OS.str(); + return 0; + } + + const driver::Command *Cmd = cast(*Jobs.begin()); + if (llvm::StringRef(Cmd->getCreator().getName()) != "clang") { + Diags.Report(diag::err_fe_expected_clang_command); + return 0; + } + + const driver::ArgStringList &CCArgs = Cmd->getArguments(); + CompilerInvocation CI; + CompilerInvocation::CreateFromArgs(CI, (const char**) CCArgs.data(), + (const char**) CCArgs.data()+CCArgs.size(), + Diags); + + // Override the resources path. + CI.getHeaderSearchOpts().ResourceDir = ResourceFilesPath; + + CI.getFrontendOpts().DisableFree = UseBumpAllocator; + return LoadFromCompilerInvocation(CI, Diags, OnlyLocalDecls); +} diff --git a/lib/Frontend/AnalysisConsumer.cpp b/lib/Frontend/AnalysisConsumer.cpp index 5df1eceb8850..a74bbc24ee10 100644 --- a/lib/Frontend/AnalysisConsumer.cpp +++ b/lib/Frontend/AnalysisConsumer.cpp @@ -139,13 +139,17 @@ namespace { return; declDisplayed = true; - // FIXME: Is getCodeDecl() always a named decl? + SourceManager &SM = Mgr->getASTContext().getSourceManager(); + PresumedLoc Loc = SM.getPresumedLoc(D->getLocation()); + llvm::errs() << "ANALYZE: " << Loc.getFilename(); + if (isa(D) || isa(D)) { const NamedDecl *ND = cast(D); - SourceManager &SM = Mgr->getASTContext().getSourceManager(); - llvm::errs() << "ANALYZE: " - << SM.getPresumedLoc(ND->getLocation()).getFilename() - << ' ' << ND->getNameAsString() << '\n'; + llvm::errs() << ' ' << ND->getNameAsString() << '\n'; + } + else if (isa(D)) { + llvm::errs() << ' ' << "block(line:" << Loc.getLine() << ",col:" + << Loc.getColumn() << '\n'; } } @@ -167,7 +171,6 @@ namespace { Mgr.reset(new AnalysisManager(*Ctx, PP.getDiagnostics(), PP.getLangOptions(), PD, CreateStoreMgr, CreateConstraintMgr, - Opts.AnalyzerDisplayProgress, Opts.VisualizeEGDot, Opts.VisualizeEGUbi, Opts.PurgeDead, Opts.EagerlyAssume, Opts.TrimGraph)); @@ -265,10 +268,21 @@ void AnalysisConsumer::HandleTranslationUnit(ASTContext &C) { // Explicitly destroy the PathDiagnosticClient. This will flush its output. // FIXME: This should be replaced with something that doesn't rely on - // side-effects in PathDiagnosticClient's destructor. + // side-effects in PathDiagnosticClient's destructor. This is required when + // used with option -disable-free. Mgr.reset(NULL); } +static void FindBlocks(DeclContext *D, llvm::SmallVectorImpl &WL) { + if (BlockDecl *BD = dyn_cast(D)) + WL.push_back(BD); + + for (DeclContext::decl_iterator I = D->decls_begin(), E = D->decls_end(); + I!=E; ++I) + if (DeclContext *DC = dyn_cast(*I)) + FindBlocks(DC, WL); +} + void AnalysisConsumer::HandleCode(Decl *D, Stmt* Body, Actions& actions) { // Don't run the actions if an error has occured with parsing the file. @@ -285,8 +299,16 @@ void AnalysisConsumer::HandleCode(Decl *D, Stmt* Body, Actions& actions) { Mgr->ClearContexts(); // Dispatch on the actions. + llvm::SmallVector WL; + WL.push_back(D); + + if (Body && Opts.AnalyzeNestedBlocks) + FindBlocks(cast(D), WL); + for (Actions::iterator I = actions.begin(), E = actions.end(); I != E; ++I) - (*I)(*this, *Mgr, D); + for (llvm::SmallVectorImpl::iterator WI=WL.begin(), WE=WL.end(); + WI != WE; ++WI) + (*I)(*this, *Mgr, *WI); } //===----------------------------------------------------------------------===// diff --git a/lib/Frontend/Backend.cpp b/lib/Frontend/Backend.cpp index 9dc109da65ef..9be6786b5f75 100644 --- a/lib/Frontend/Backend.cpp +++ b/lib/Frontend/Backend.cpp @@ -15,6 +15,7 @@ #include "clang/Basic/TargetOptions.h" #include "clang/CodeGen/CodeGenOptions.h" #include "clang/CodeGen/ModuleBuilder.h" +#include "clang/Frontend/FrontendDiagnostic.h" #include "llvm/Module.h" #include "llvm/ModuleProvider.h" #include "llvm/PassManager.h" @@ -31,12 +32,14 @@ #include "llvm/Target/SubtargetFeature.h" #include "llvm/Target/TargetData.h" #include "llvm/Target/TargetMachine.h" +#include "llvm/Target/TargetOptions.h" #include "llvm/Target/TargetRegistry.h" using namespace clang; using namespace llvm; namespace { class BackendConsumer : public ASTConsumer { + Diagnostic &Diags; BackendAction Action; const CodeGenOptions &CodeGenOpts; const LangOptions &LangOpts; @@ -64,21 +67,20 @@ namespace { void CreatePasses(); - /// AddEmitPasses - Add passes necessary to emit assembly or LLVM - /// IR. + /// AddEmitPasses - Add passes necessary to emit assembly or LLVM IR. /// - /// \return True on success. On failure \arg Error will be set to - /// a user readable error message. - bool AddEmitPasses(std::string &Error); + /// \return True on success. + bool AddEmitPasses(); void EmitAssembly(); public: - BackendConsumer(BackendAction action, Diagnostic &Diags, + BackendConsumer(BackendAction action, Diagnostic &_Diags, const LangOptions &langopts, const CodeGenOptions &compopts, const TargetOptions &targetopts, bool TimePasses, const std::string &infile, llvm::raw_ostream *OS, LLVMContext& C) : + Diags(_Diags), Action(action), CodeGenOpts(compopts), LangOpts(langopts), @@ -195,7 +197,7 @@ FunctionPassManager *BackendConsumer::getPerFunctionPasses() const { return PerFunctionPasses; } -bool BackendConsumer::AddEmitPasses(std::string &Error) { +bool BackendConsumer::AddEmitPasses() { if (Action == Backend_EmitNothing) return true; @@ -207,48 +209,68 @@ bool BackendConsumer::AddEmitPasses(std::string &Error) { bool Fast = CodeGenOpts.OptimizationLevel == 0; // Create the TargetMachine for generating code. + std::string Error; std::string Triple = TheModule->getTargetTriple(); const llvm::Target *TheTarget = TargetRegistry::lookupTarget(Triple, Error); if (!TheTarget) { - Error = std::string("Unable to get target machine: ") + Error; + Diags.Report(diag::err_fe_unable_to_create_target) << Error; return false; } // FIXME: Expose these capabilities via actual APIs!!!! Aside from just // being gross, this is also totally broken if we ever care about // concurrency. + llvm::NoFramePointerElim = CodeGenOpts.DisableFPElim; + if (CodeGenOpts.FloatABI == "soft") + llvm::FloatABIType = llvm::FloatABI::Soft; + else if (CodeGenOpts.FloatABI == "hard") + llvm::FloatABIType = llvm::FloatABI::Hard; + else { + assert(CodeGenOpts.FloatABI.empty() && "Invalid float abi!"); + llvm::FloatABIType = llvm::FloatABI::Default; + } + NoZerosInBSS = CodeGenOpts.NoZeroInitializedInBSS; + llvm::UseSoftFloat = CodeGenOpts.SoftFloat; + UnwindTablesMandatory = CodeGenOpts.UnwindTables; + + TargetMachine::setAsmVerbosityDefault(CodeGenOpts.AsmVerbose); + + // FIXME: Parse this earlier. + if (CodeGenOpts.RelocationModel == "static") { + TargetMachine::setRelocationModel(llvm::Reloc::Static); + } else if (CodeGenOpts.RelocationModel == "pic") { + TargetMachine::setRelocationModel(llvm::Reloc::PIC_); + } else { + assert(CodeGenOpts.RelocationModel == "dynamic-no-pic" && + "Invalid PIC model!"); + TargetMachine::setRelocationModel(llvm::Reloc::DynamicNoPIC); + } + // FIXME: Parse this earlier. + if (CodeGenOpts.CodeModel == "small") { + TargetMachine::setCodeModel(llvm::CodeModel::Small); + } else if (CodeGenOpts.CodeModel == "kernel") { + TargetMachine::setCodeModel(llvm::CodeModel::Kernel); + } else if (CodeGenOpts.CodeModel == "medium") { + TargetMachine::setCodeModel(llvm::CodeModel::Medium); + } else if (CodeGenOpts.CodeModel == "large") { + TargetMachine::setCodeModel(llvm::CodeModel::Large); + } else { + assert(CodeGenOpts.CodeModel.empty() && "Invalid code model!"); + TargetMachine::setCodeModel(llvm::CodeModel::Default); + } + std::vector BackendArgs; BackendArgs.push_back("clang"); // Fake program name. - if (CodeGenOpts.AsmVerbose) - BackendArgs.push_back("-asm-verbose"); - if (!CodeGenOpts.CodeModel.empty()) { - BackendArgs.push_back("-code-model"); - BackendArgs.push_back(CodeGenOpts.CodeModel.c_str()); - } if (!CodeGenOpts.DebugPass.empty()) { BackendArgs.push_back("-debug-pass"); BackendArgs.push_back(CodeGenOpts.DebugPass.c_str()); } - if (CodeGenOpts.DisableFPElim) - BackendArgs.push_back("-disable-fp-elim"); - if (!CodeGenOpts.FloatABI.empty()) { - BackendArgs.push_back("-float-abi"); - BackendArgs.push_back(CodeGenOpts.FloatABI.c_str()); - } if (!CodeGenOpts.LimitFloatPrecision.empty()) { BackendArgs.push_back("-limit-float-precision"); BackendArgs.push_back(CodeGenOpts.LimitFloatPrecision.c_str()); } - if (CodeGenOpts.NoZeroInitializedInBSS) - BackendArgs.push_back("-nozero-initialized-in-bss"); - if (CodeGenOpts.SoftFloat) - BackendArgs.push_back("-soft-float"); - BackendArgs.push_back("-relocation-model"); - BackendArgs.push_back(CodeGenOpts.RelocationModel.c_str()); if (llvm::TimePassesIsEnabled) BackendArgs.push_back("-time-passes"); - if (CodeGenOpts.UnwindTables) - BackendArgs.push_back("-unwind-tables"); BackendArgs.push_back(0); llvm::cl::ParseCommandLineOptions(BackendArgs.size() - 1, (char**) &BackendArgs[0]); @@ -290,7 +312,7 @@ bool BackendConsumer::AddEmitPasses(std::string &Error) { TargetMachine::AssemblyFile, OptLevel)) { default: case FileModel::Error: - Error = "Unable to interface with target machine!\n"; + Diags.Report(diag::err_fe_unable_to_interface_with_target); return false; case FileModel::AsmFile: break; @@ -298,7 +320,7 @@ bool BackendConsumer::AddEmitPasses(std::string &Error) { if (TM->addPassesToEmitFileFinish(*CodeGenPasses, (MachineCodeEmitter *)0, OptLevel)) { - Error = "Unable to interface with target machine!\n"; + Diags.Report(diag::err_fe_unable_to_interface_with_target); return false; } } @@ -329,8 +351,14 @@ void BackendConsumer::CreatePasses() { switch (Inlining) { case CodeGenOptions::NoInlining: break; case CodeGenOptions::NormalInlining: { - // Inline small functions - unsigned Threshold = (CodeGenOpts.OptimizeSize || OptLevel < 3) ? 50 : 200; + // Set the inline threshold following llvm-gcc. + // + // FIXME: Derive these constants in a principled fashion. + unsigned Threshold = 200; + if (CodeGenOpts.OptimizeSize) + Threshold = 50; + else if (OptLevel > 2) + Threshold = 250; InliningPass = createFunctionInliningPass(Threshold); break; } @@ -372,13 +400,8 @@ void BackendConsumer::EmitAssembly() { assert(TheModule == M && "Unexpected module change during IR generation"); CreatePasses(); - - std::string Error; - if (!AddEmitPasses(Error)) { - // FIXME: Don't fail this way. - llvm::errs() << "ERROR: " << Error << "\n"; - ::exit(1); - } + if (!AddEmitPasses()) + return; // Run passes. For now we do all passes at once, but eventually we // would like to have the option of streaming code generation. diff --git a/lib/Frontend/CompilerInstance.cpp b/lib/Frontend/CompilerInstance.cpp index 1083d5ef1c02..2a6a8a8750d2 100644 --- a/lib/Frontend/CompilerInstance.cpp +++ b/lib/Frontend/CompilerInstance.cpp @@ -95,7 +95,7 @@ static void SetUpBuildDumpLog(const DiagnosticOptions &DiagOpts, return; } - (*OS) << "clang-cc command line arguments: "; + (*OS) << "clang -cc1 command line arguments: "; for (unsigned i = 0; i != argc; ++i) (*OS) << argv[i] << ' '; (*OS) << '\n'; @@ -172,10 +172,6 @@ CompilerInstance::createPreprocessor(Diagnostic &Diags, if (!PPOpts.TokenCache.empty()) PTHMgr = PTHManager::Create(PPOpts.TokenCache, Diags); - // FIXME: Don't fail like this. - if (Diags.hasErrorOccurred()) - exit(1); - // Create the Preprocessor. HeaderSearch *HeaderInfo = new HeaderSearch(FileMgr); Preprocessor *PP = new Preprocessor(Diags, LangInfo, Target, @@ -287,7 +283,7 @@ CompilerInstance::createCodeCompletionConsumer(Preprocessor &PP, } // Truncate the named file at the given line/column. - PP.getSourceManager().truncateFileAt(Entry, Line, Column); + PP.SetCodeCompletionPoint(Entry, Line, Column); // Set up the creation routine for code-completion. if (UseDebugPrinter) @@ -332,9 +328,9 @@ CompilerInstance::createOutputFile(llvm::StringRef OutputPath, InFile, Extension, &OutputPathName); if (!OS) { - // FIXME: Don't fail this way. - llvm::errs() << "error: " << Error << "\n"; - ::exit(1); + getDiagnostics().Report(diag::err_fe_unable_to_open_output) + << OutputPath << Error; + return 0; } // Add the output file -- but don't try to remove "-", since this means we are diff --git a/lib/Frontend/CompilerInvocation.cpp b/lib/Frontend/CompilerInvocation.cpp index c5375079506b..7a3388ffbb97 100644 --- a/lib/Frontend/CompilerInvocation.cpp +++ b/lib/Frontend/CompilerInvocation.cpp @@ -31,7 +31,7 @@ using namespace clang; static const char *getAnalysisName(Analyses Kind) { switch (Kind) { default: - llvm::llvm_unreachable("Unknown analysis store!"); + llvm_unreachable("Unknown analysis kind!"); #define ANALYSIS(NAME, CMDFLAG, DESC, SCOPE)\ case NAME: return "-" CMDFLAG; #include "clang/Frontend/Analyses.def" @@ -41,7 +41,7 @@ static const char *getAnalysisName(Analyses Kind) { static const char *getAnalysisStoreName(AnalysisStores Kind) { switch (Kind) { default: - llvm::llvm_unreachable("Unknown analysis store!"); + llvm_unreachable("Unknown analysis store!"); #define ANALYSIS_STORE(NAME, CMDFLAG, DESC, CREATFN) \ case NAME##Model: return CMDFLAG; #include "clang/Frontend/Analyses.def" @@ -51,7 +51,7 @@ static const char *getAnalysisStoreName(AnalysisStores Kind) { static const char *getAnalysisConstraintName(AnalysisConstraints Kind) { switch (Kind) { default: - llvm::llvm_unreachable("Unknown analysis constraints!"); + llvm_unreachable("Unknown analysis constraints!"); #define ANALYSIS_CONSTRAINTS(NAME, CMDFLAG, DESC, CREATFN) \ case NAME##Model: return CMDFLAG; #include "clang/Frontend/Analyses.def" @@ -61,7 +61,7 @@ static const char *getAnalysisConstraintName(AnalysisConstraints Kind) { static const char *getAnalysisDiagClientName(AnalysisDiagClients Kind) { switch (Kind) { default: - llvm::llvm_unreachable("Unknown analysis client!"); + llvm_unreachable("Unknown analysis client!"); #define ANALYSIS_DIAGNOSTICS(NAME, CMDFLAG, DESC, CREATFN, AUTOCREATE) \ case PD_##NAME: return CMDFLAG; #include "clang/Frontend/Analyses.def" @@ -96,6 +96,8 @@ static void AnalyzerOptsToArgs(const AnalyzerOptions &Opts, Res.push_back("-analyzer-opt-analyze-headers"); if (Opts.AnalyzerDisplayProgress) Res.push_back("-analyzer-display-progress"); + if (Opts.AnalyzeNestedBlocks) + Res.push_back("-analyzer-opt-analyze-nested-blocks"); if (Opts.EagerlyAssume) Res.push_back("-analyzer-eagerly-assume"); if (!Opts.PurgeDead) @@ -244,7 +246,7 @@ static const char *getInputKindName(FrontendOptions::InputKind Kind) { case FrontendOptions::IK_PreprocessedObjCXX:return "objective-c++-cpp-output"; } - llvm::llvm_unreachable("Unexpected language kind!"); + llvm_unreachable("Unexpected language kind!"); return 0; } @@ -252,7 +254,7 @@ static const char *getActionName(frontend::ActionKind Kind) { switch (Kind) { case frontend::PluginAction: case frontend::InheritanceView: - llvm::llvm_unreachable("Invalid kind!"); + llvm_unreachable("Invalid kind!"); case frontend::ASTDump: return "-ast-dump"; case frontend::ASTPrint: return "-ast-print"; @@ -282,7 +284,7 @@ static const char *getActionName(frontend::ActionKind Kind) { case frontend::RunPreprocessorOnly: return "-Eonly"; } - llvm::llvm_unreachable("Unexpected language kind!"); + llvm_unreachable("Unexpected language kind!"); return 0; } @@ -296,12 +298,16 @@ static void FrontendOptsToArgs(const FrontendOptions &Opts, Res.push_back("-empty-input-only"); if (Opts.RelocatablePCH) Res.push_back("-relocatable-pch"); + if (Opts.ShowHelp) + Res.push_back("-help"); if (Opts.ShowMacrosInCodeCompletion) Res.push_back("-code-completion-macros"); if (Opts.ShowStats) Res.push_back("-print-stats"); if (Opts.ShowTimers) Res.push_back("-ftime-report"); + if (Opts.ShowVersion) + Res.push_back("-version"); bool NeedLang = false; for (unsigned i = 0, e = Opts.Inputs.size(); i != e; ++i) @@ -345,6 +351,10 @@ static void FrontendOptsToArgs(const FrontendOptions &Opts, Res.push_back("-plugin"); Res.push_back(Opts.ActionName); } + for (unsigned i = 0, e = Opts.Plugins.size(); i != e; ++i) { + Res.push_back("-load"); + Res.push_back(Opts.Plugins[i]); + } } static void HeaderSearchOptsToArgs(const HeaderSearchOptions &Opts, @@ -399,8 +409,9 @@ static void HeaderSearchOptsToArgs(const HeaderSearchOptions &Opts, // FIXME: Provide an option for this, and move env detection to driver. llvm::llvm_report_error("Not yet implemented!"); } - if (!Opts.BuiltinIncludePath.empty()) { - // FIXME: Provide an option for this, and move to driver. + if (!Opts.ResourceDir.empty()) { + Res.push_back("-resource-dir"); + Res.push_back(Opts.ResourceDir); } if (!Opts.UseStandardIncludes) Res.push_back("-nostdinc"); @@ -437,6 +448,8 @@ static void LangOptsToArgs(const LangOptions &Opts, Res.push_back("-fno-operator-names"); if (Opts.PascalStrings) Res.push_back("-fpascal-strings"); + if (Opts.CatchUndefined) + Res.push_back("-fcatch-undefined-behavior"); if (Opts.WritableStrings) Res.push_back("-fwritable-strings"); if (!Opts.LaxVectorConversions) @@ -445,7 +458,7 @@ static void LangOptsToArgs(const LangOptions &Opts, Res.push_back("-faltivec"); if (Opts.Exceptions) Res.push_back("-fexceptions"); - if (!Opts.Rtti) + if (!Opts.RTTI) Res.push_back("-fno-rtti"); if (!Opts.NeXTRuntime) Res.push_back("-fgnu-runtime"); @@ -550,6 +563,11 @@ static void PreprocessorOptsToArgs(const PreprocessorOptions &Opts, assert(Opts.ImplicitPTHInclude == Opts.TokenCache && "Unsupported option combination!"); } + for (unsigned i = 0, e = Opts.RemappedFiles.size(); i != e; ++i) { + Res.push_back("-remap-file"); + Res.push_back(Opts.RemappedFiles[i].first + ";" + + Opts.RemappedFiles[i].second); + } } static void PreprocessorOutputOptsToArgs(const PreprocessorOutputOptions &Opts, @@ -696,6 +714,8 @@ static void ParseAnalyzerArgs(AnalyzerOptions &Opts, ArgList &Args, Opts.VisualizeEGUbi = Args.hasArg(OPT_analyzer_viz_egraph_ubigraph); Opts.AnalyzeAll = Args.hasArg(OPT_analyzer_opt_analyze_headers); Opts.AnalyzerDisplayProgress = Args.hasArg(OPT_analyzer_display_progress); + Opts.AnalyzeNestedBlocks = + Args.hasArg(OPT_analyzer_opt_analyze_nested_blocks); Opts.PurgeDead = !Args.hasArg(OPT_analyzer_no_purge_dead); Opts.EagerlyAssume = Args.hasArg(OPT_analyzer_eagerly_assume); Opts.AnalyzeSpecificFunction = getLastArgValue(Args, OPT_analyze_function); @@ -877,10 +897,13 @@ ParseFrontendArgs(FrontendOptions &Opts, ArgList &Args, Diagnostic &Diags) { } Opts.OutputFile = getLastArgValue(Args, OPT_o); + Opts.Plugins = getAllArgValues(Args, OPT_load); Opts.RelocatablePCH = Args.hasArg(OPT_relocatable_pch); + Opts.ShowHelp = Args.hasArg(OPT_help); Opts.ShowMacrosInCodeCompletion = Args.hasArg(OPT_code_completion_macros); Opts.ShowStats = Args.hasArg(OPT_print_stats); Opts.ShowTimers = Args.hasArg(OPT_ftime_report); + Opts.ShowVersion = Args.hasArg(OPT_version); Opts.ViewClassInheritance = getLastArgValue(Args, OPT_cxx_inheritance_view); FrontendOptions::InputKind DashX = FrontendOptions::IK_None; @@ -929,8 +952,8 @@ ParseFrontendArgs(FrontendOptions &Opts, ArgList &Args, Diagnostic &Diags) { return DashX; } -static std::string GetBuiltinIncludePath(const char *Argv0, - void *MainAddr) { +std::string CompilerInvocation::GetResourcesPath(const char *Argv0, + void *MainAddr) { llvm::sys::Path P = llvm::sys::Path::GetMainExecutable(Argv0, MainAddr); if (!P.isEmpty()) { @@ -941,22 +964,18 @@ static std::string GetBuiltinIncludePath(const char *Argv0, P.appendComponent("lib"); P.appendComponent("clang"); P.appendComponent(CLANG_VERSION_STRING); - P.appendComponent("include"); } return P.str(); } -static void ParseHeaderSearchArgs(HeaderSearchOptions &Opts, ArgList &Args, - const char *Argv0, void *MainAddr) { +static void ParseHeaderSearchArgs(HeaderSearchOptions &Opts, ArgList &Args) { using namespace cc1options; Opts.Sysroot = getLastArgValue(Args, OPT_isysroot, "/"); Opts.Verbose = Args.hasArg(OPT_v); + Opts.UseBuiltinIncludes = !Args.hasArg(OPT_nobuiltininc); Opts.UseStandardIncludes = !Args.hasArg(OPT_nostdinc); - Opts.BuiltinIncludePath = ""; - // FIXME: Add an option for this, its a slow call. - if (!Args.hasArg(OPT_nobuiltininc)) - Opts.BuiltinIncludePath = GetBuiltinIncludePath(Argv0, MainAddr); + Opts.ResourceDir = getLastArgValue(Args, OPT_resource_dir); // Add -I... and -F... options in order. for (arg_iterator it = Args.filtered_begin(OPT_I, OPT_F), @@ -1115,7 +1134,7 @@ static void ParseLangArgs(LangOptions &Opts, ArgList &Args, if (Args.hasArg(OPT_fno_lax_vector_conversions)) Opts.LaxVectorConversions = 0; Opts.Exceptions = Args.hasArg(OPT_fexceptions); - Opts.Rtti = !Args.hasArg(OPT_fno_rtti); + Opts.RTTI = !Args.hasArg(OPT_fno_rtti); Opts.Blocks = Args.hasArg(OPT_fblocks); Opts.CharIsSigned = !Args.hasArg(OPT_fno_signed_char); Opts.ShortWChar = Args.hasArg(OPT_fshort_wchar); @@ -1131,6 +1150,7 @@ static void ParseLangArgs(LangOptions &Opts, ArgList &Args, Opts.ObjCConstantStringClass = getLastArgValue(Args, OPT_fconstant_string_class); Opts.ObjCNonFragileABI = Args.hasArg(OPT_fobjc_nonfragile_abi); + Opts.CatchUndefined = Args.hasArg(OPT_fcatch_undefined_behavior); Opts.EmitAllDecls = Args.hasArg(OPT_femit_all_decls); Opts.PICLevel = getLastArgIntValue(Args, OPT_pic_level, 0, Diags); Opts.Static = Args.hasArg(OPT_static_define); @@ -1160,7 +1180,8 @@ static void ParseLangArgs(LangOptions &Opts, ArgList &Args, } } -static void ParsePreprocessorArgs(PreprocessorOptions &Opts, ArgList &Args) { +static void ParsePreprocessorArgs(PreprocessorOptions &Opts, ArgList &Args, + Diagnostic &Diags) { using namespace cc1options; Opts.ImplicitPCHInclude = getLastArgValue(Args, OPT_include_pch); Opts.ImplicitPTHInclude = getLastArgValue(Args, OPT_include_pth); @@ -1188,16 +1209,27 @@ static void ParsePreprocessorArgs(PreprocessorOptions &Opts, ArgList &Args) { // PCH is handled specially, we need to extra the original include path. if (it->getOption().matches(OPT_include_pch)) { std::string OriginalFile = - PCHReader::getOriginalSourceFile(it->getValue(Args)); - - // FIXME: Don't fail like this. + PCHReader::getOriginalSourceFile(it->getValue(Args), Diags); if (OriginalFile.empty()) - exit(1); + continue; Opts.Includes.push_back(OriginalFile); } else Opts.Includes.push_back(it->getValue(Args)); } + + for (arg_iterator it = Args.filtered_begin(OPT_remap_file), + ie = Args.filtered_end(); it != ie; ++it) { + std::pair Split = + llvm::StringRef(it->getValue(Args)).split(';'); + + if (Split.second.empty()) { + Diags.Report(diag::err_drv_invalid_remap_file) << it->getAsString(Args); + continue; + } + + Opts.addRemappedFile(Split.first, Split.second); + } } static void ParsePreprocessorOutputArgs(PreprocessorOutputOptions &Opts, @@ -1227,8 +1259,6 @@ static void ParseTargetArgs(TargetOptions &Opts, ArgList &Args) { void CompilerInvocation::CreateFromArgs(CompilerInvocation &Res, const char **ArgBegin, const char **ArgEnd, - const char *Argv0, - void *MainAddr, Diagnostic &Diags) { // Parse the arguments. llvm::OwningPtr Opts(createCC1OptTable()); @@ -1252,11 +1282,10 @@ void CompilerInvocation::CreateFromArgs(CompilerInvocation &Res, ParseDiagnosticArgs(Res.getDiagnosticOpts(), *Args, Diags); FrontendOptions::InputKind DashX = ParseFrontendArgs(Res.getFrontendOpts(), *Args, Diags); - ParseHeaderSearchArgs(Res.getHeaderSearchOpts(), *Args, - Argv0, MainAddr); + ParseHeaderSearchArgs(Res.getHeaderSearchOpts(), *Args); if (DashX != FrontendOptions::IK_AST) ParseLangArgs(Res.getLangOpts(), *Args, DashX, Diags); - ParsePreprocessorArgs(Res.getPreprocessorOpts(), *Args); + ParsePreprocessorArgs(Res.getPreprocessorOpts(), *Args, Diags); ParsePreprocessorOutputArgs(Res.getPreprocessorOutputOpts(), *Args); ParseTargetArgs(Res.getTargetOpts(), *Args); } diff --git a/lib/Frontend/DiagChecker.cpp b/lib/Frontend/DiagChecker.cpp index e7a66b1729c4..a50cc99ab79e 100644 --- a/lib/Frontend/DiagChecker.cpp +++ b/lib/Frontend/DiagChecker.cpp @@ -17,7 +17,7 @@ #include "clang/AST/ASTConsumer.h" #include "clang/Basic/SourceManager.h" #include "clang/Lex/Preprocessor.h" -#include +#include "llvm/Support/raw_ostream.h" using namespace clang; typedef TextDiagnosticBuffer::DiagList DiagList; @@ -190,12 +190,10 @@ static bool PrintProblem(SourceManager &SourceMgr, const char *Msg) { if (diag_begin == diag_end) return false; - fprintf(stderr, "%s\n", Msg); - + llvm::errs() << Msg << "\n"; for (const_diag_iterator I = diag_begin, E = diag_end; I != E; ++I) - fprintf(stderr, " Line %d: %s\n", - SourceMgr.getInstantiationLineNumber(I->first), - I->second.c_str()); + llvm::errs() << " Line " << SourceMgr.getInstantiationLineNumber(I->first) + << " " << I->second << "\n"; return true; } diff --git a/lib/Frontend/FixItRewriter.cpp b/lib/Frontend/FixItRewriter.cpp index dddcaa97e2ff..4fa2b3c51eb5 100644 --- a/lib/Frontend/FixItRewriter.cpp +++ b/lib/Frontend/FixItRewriter.cpp @@ -66,7 +66,7 @@ bool FixItRewriter::WriteFixedFile(const std::string &InFileName, Rewrite.getRewriteBufferFor(MainFileID)) { *OutFile << std::string(RewriteBuf->begin(), RewriteBuf->end()); } else { - std::fprintf(stderr, "Main file is unchanged\n"); + Diag(FullSourceLoc(), diag::note_fixit_main_file_unchanged); } OutFile->flush(); diff --git a/lib/Frontend/FrontendAction.cpp b/lib/Frontend/FrontendAction.cpp index 91c946c9cf25..96a68c931e1f 100644 --- a/lib/Frontend/FrontendAction.cpp +++ b/lib/Frontend/FrontendAction.cpp @@ -46,11 +46,9 @@ bool FrontendAction::BeginSourceFile(CompilerInstance &CI, assert(hasASTSupport() && "This action does not have AST support!"); std::string Error; - ASTUnit *AST = ASTUnit::LoadFromPCHFile(Filename, &Error); - if (!AST) { - CI.getDiagnostics().Report(diag::err_fe_invalid_ast_file) << Error; + ASTUnit *AST = ASTUnit::LoadFromPCHFile(Filename, CI.getDiagnostics()); + if (!AST) goto failure; - } setCurrentFile(Filename, AST); @@ -224,5 +222,5 @@ void ASTFrontendAction::ExecuteAction() { ASTConsumer * PreprocessorFrontendAction::CreateASTConsumer(CompilerInstance &CI, llvm::StringRef InFile) { - llvm::llvm_unreachable("Invalid CreateASTConsumer on preprocessor action!"); + llvm_unreachable("Invalid CreateASTConsumer on preprocessor action!"); } diff --git a/lib/Frontend/FrontendActions.cpp b/lib/Frontend/FrontendActions.cpp index 27e194e6f108..e3c313a42299 100644 --- a/lib/Frontend/FrontendActions.cpp +++ b/lib/Frontend/FrontendActions.cpp @@ -35,13 +35,16 @@ ASTConsumer *AnalysisAction::CreateASTConsumer(CompilerInstance &CI, ASTConsumer *ASTPrintAction::CreateASTConsumer(CompilerInstance &CI, llvm::StringRef InFile) { - return CreateASTPrinter(CI.createDefaultOutputFile(false, InFile)); + if (llvm::raw_ostream *OS = CI.createDefaultOutputFile(false, InFile)) + return CreateASTPrinter(OS); + return 0; } ASTConsumer *ASTPrintXMLAction::CreateASTConsumer(CompilerInstance &CI, llvm::StringRef InFile) { - return CreateASTPrinterXML(CI.createDefaultOutputFile(false, InFile, - "xml")); + if (llvm::raw_ostream *OS = CI.createDefaultOutputFile(false, InFile, "xml")) + return CreateASTPrinterXML(OS); + return 0; } ASTConsumer *ASTDumpAction::CreateASTConsumer(CompilerInstance &CI, @@ -74,6 +77,9 @@ ASTConsumer *GeneratePCHAction::CreateASTConsumer(CompilerInstance &CI, } llvm::raw_ostream *OS = CI.createDefaultOutputFile(true, InFile); + if (!OS) + return 0; + if (CI.getFrontendOpts().RelocatablePCH) return CreatePCHGenerator(CI.getPreprocessor(), OS, Sysroot.c_str()); @@ -82,8 +88,9 @@ ASTConsumer *GeneratePCHAction::CreateASTConsumer(CompilerInstance &CI, ASTConsumer *HTMLPrintAction::CreateASTConsumer(CompilerInstance &CI, llvm::StringRef InFile) { - return CreateHTMLPrinter(CI.createDefaultOutputFile(false, InFile), - CI.getPreprocessor()); + if (llvm::raw_ostream *OS = CI.createDefaultOutputFile(false, InFile)) + return CreateHTMLPrinter(OS, CI.getPreprocessor()); + return 0; } ASTConsumer *InheritanceViewAction::CreateASTConsumer(CompilerInstance &CI, @@ -140,10 +147,11 @@ void FixItAction::EndSourceFileAction() { ASTConsumer *RewriteObjCAction::CreateASTConsumer(CompilerInstance &CI, llvm::StringRef InFile) { - return CreateObjCRewriter(InFile, - CI.createDefaultOutputFile(true, InFile, "cpp"), - CI.getDiagnostics(), CI.getLangOpts(), - CI.getDiagnosticOpts().NoRewriteMacros); + if (llvm::raw_ostream *OS = CI.createDefaultOutputFile(false, InFile, "cpp")) + return CreateObjCRewriter(InFile, OS, + CI.getDiagnostics(), CI.getLangOpts(), + CI.getDiagnosticOpts().NoRewriteMacros); + return 0; } ASTConsumer *RewriteBlocksAction::CreateASTConsumer(CompilerInstance &CI, @@ -162,12 +170,21 @@ ASTConsumer *CodeGenAction::CreateASTConsumer(CompilerInstance &CI, llvm::StringRef InFile) { BackendAction BA = static_cast(Act); llvm::OwningPtr OS; - if (BA == Backend_EmitAssembly) + switch (BA) { + case Backend_EmitAssembly: OS.reset(CI.createDefaultOutputFile(false, InFile, "s")); - else if (BA == Backend_EmitLL) + break; + case Backend_EmitLL: OS.reset(CI.createDefaultOutputFile(false, InFile, "ll")); - else if (BA == Backend_EmitBC) + break; + case Backend_EmitBC: OS.reset(CI.createDefaultOutputFile(true, InFile, "bc")); + break; + case Backend_EmitNothing: + break; + } + if (BA != Backend_EmitNothing && !OS) + return 0; return CreateBackendConsumer(BA, CI.getDiagnostics(), CI.getLangOpts(), CI.getCodeGenOpts(), CI.getTargetOpts(), @@ -228,6 +245,8 @@ void GeneratePTHAction::ExecuteAction() { } llvm::raw_fd_ostream *OS = CI.createDefaultOutputFile(true, getCurrentFile()); + if (!OS) return; + CacheTokens(CI.getPreprocessor(), OS); } @@ -255,6 +274,8 @@ void PrintParseAction::ExecuteAction() { CompilerInstance &CI = getCompilerInstance(); Preprocessor &PP = getCompilerInstance().getPreprocessor(); llvm::raw_ostream *OS = CI.createDefaultOutputFile(false, getCurrentFile()); + if (!OS) return; + llvm::OwningPtr PA(CreatePrintParserActionsAction(PP, OS)); Parser P(PP, *PA); @@ -265,6 +286,8 @@ void PrintParseAction::ExecuteAction() { void PrintPreprocessedAction::ExecuteAction() { CompilerInstance &CI = getCompilerInstance(); llvm::raw_ostream *OS = CI.createDefaultOutputFile(false, getCurrentFile()); + if (!OS) return; + DoPrintPreprocessedInput(CI.getPreprocessor(), OS, CI.getPreprocessorOutputOpts()); } @@ -272,11 +295,15 @@ void PrintPreprocessedAction::ExecuteAction() { void RewriteMacrosAction::ExecuteAction() { CompilerInstance &CI = getCompilerInstance(); llvm::raw_ostream *OS = CI.createDefaultOutputFile(true, getCurrentFile()); + if (!OS) return; + RewriteMacrosInInput(CI.getPreprocessor(), OS); } void RewriteTestAction::ExecuteAction() { CompilerInstance &CI = getCompilerInstance(); llvm::raw_ostream *OS = CI.createDefaultOutputFile(false, getCurrentFile()); + if (!OS) return; + DoRewriteTest(CI.getPreprocessor(), OS); } diff --git a/lib/Frontend/HTMLPrint.cpp b/lib/Frontend/HTMLPrint.cpp index 75e6184572e5..9ea8cb3feee6 100644 --- a/lib/Frontend/HTMLPrint.cpp +++ b/lib/Frontend/HTMLPrint.cpp @@ -41,9 +41,9 @@ namespace { bool _SyntaxHighlight, bool _HighlightMacros) : Out(OS), PP(pp), SyntaxHighlight(_SyntaxHighlight), HighlightMacros(_HighlightMacros) {} - virtual ~HTMLPrinter(); void Initialize(ASTContext &context); + void HandleTranslationUnit(ASTContext &Ctx); }; } @@ -58,7 +58,7 @@ void HTMLPrinter::Initialize(ASTContext &context) { R.setSourceMgr(context.getSourceManager(), context.getLangOptions()); } -HTMLPrinter::~HTMLPrinter() { +void HTMLPrinter::HandleTranslationUnit(ASTContext &Ctx) { if (PP.getDiagnostics().hasErrorOccurred()) return; diff --git a/lib/Frontend/InitHeaderSearch.cpp b/lib/Frontend/InitHeaderSearch.cpp index a40a569d92f7..b4ea2576c3e6 100644 --- a/lib/Frontend/InitHeaderSearch.cpp +++ b/lib/Frontend/InitHeaderSearch.cpp @@ -21,10 +21,10 @@ #include "llvm/ADT/SmallVector.h" #include "llvm/ADT/StringExtras.h" #include "llvm/ADT/Triple.h" +#include "llvm/ADT/Twine.h" #include "llvm/Support/raw_ostream.h" #include "llvm/System/Path.h" #include "llvm/Config/config.h" -#include #ifdef _MSC_VER #define WIN32_LEAN_AND_MEAN 1 #include @@ -50,27 +50,27 @@ class InitHeaderSearch { : Headers(HS), Verbose(verbose), isysroot(iSysroot) {} /// AddPath - Add the specified path to the specified group list. - void AddPath(const llvm::StringRef &Path, IncludeDirGroup Group, + void AddPath(const llvm::Twine &Path, IncludeDirGroup Group, bool isCXXAware, bool isUserSupplied, bool isFramework, bool IgnoreSysRoot = false); /// AddGnuCPlusPlusIncludePaths - Add the necessary paths to suport a gnu /// libstdc++. - void AddGnuCPlusPlusIncludePaths(const std::string &Base, - const char *ArchDir, - const char *Dir32, - const char *Dir64, + void AddGnuCPlusPlusIncludePaths(llvm::StringRef Base, + llvm::StringRef ArchDir, + llvm::StringRef Dir32, + llvm::StringRef Dir64, const llvm::Triple &triple); /// AddMinGWCPlusPlusIncludePaths - Add the necessary paths to suport a MinGW /// libstdc++. - void AddMinGWCPlusPlusIncludePaths(const std::string &Base, - const char *Arch, - const char *Version); + void AddMinGWCPlusPlusIncludePaths(llvm::StringRef Base, + llvm::StringRef Arch, + llvm::StringRef Version); /// AddDelimitedPaths - Add a list of paths delimited by the system PATH /// separator. The processing follows that of the CPATH variable for gcc. - void AddDelimitedPaths(const char *String); + void AddDelimitedPaths(llvm::StringRef String); // AddDefaultCIncludePaths - Add paths that should always be searched. void AddDefaultCIncludePaths(const llvm::Triple &triple); @@ -91,25 +91,26 @@ class InitHeaderSearch { } -void InitHeaderSearch::AddPath(const llvm::StringRef &Path, +void InitHeaderSearch::AddPath(const llvm::Twine &Path, IncludeDirGroup Group, bool isCXXAware, bool isUserSupplied, bool isFramework, bool IgnoreSysRoot) { - assert(!Path.empty() && "can't handle empty path here"); + assert(!Path.isTriviallyEmpty() && "can't handle empty path here"); FileManager &FM = Headers.getFileMgr(); // Compute the actual path, taking into consideration -isysroot. - llvm::SmallString<256> MappedPath; + llvm::SmallString<256> MappedPathStr; + llvm::raw_svector_ostream MappedPath(MappedPathStr); // Handle isysroot. if (Group == System && !IgnoreSysRoot) { // FIXME: Portability. This should be a sys::Path interface, this doesn't // handle things like C:\ right, nor win32 \\network\device\blah. if (isysroot.size() != 1 || isysroot[0] != '/') // Add isysroot if present. - MappedPath.append(isysroot.begin(), isysroot.end()); + MappedPath << isysroot; } - MappedPath.append(Path.begin(), Path.end()); + Path.print(MappedPath); // Compute the DirectoryLookup type. SrcMgr::CharacteristicKind Type; @@ -146,29 +147,29 @@ void InitHeaderSearch::AddPath(const llvm::StringRef &Path, } -void InitHeaderSearch::AddDelimitedPaths(const char *at) { - if (*at == 0) // Empty string should not add '.' path. +void InitHeaderSearch::AddDelimitedPaths(llvm::StringRef at) { + if (at.empty()) // Empty string should not add '.' path. return; - const char* delim = strchr(at, llvm::sys::PathSeparator); - while (delim != 0) { - if (delim-at == 0) + llvm::StringRef::size_type delim; + while ((delim = at.find(llvm::sys::PathSeparator)) != llvm::StringRef::npos) { + if (delim == 0) AddPath(".", Angled, false, true, false); else - AddPath(llvm::StringRef(at, delim-at), Angled, false, true, false); - at = delim + 1; - delim = strchr(at, llvm::sys::PathSeparator); + AddPath(at.substr(0, delim), Angled, false, true, false); + at = at.substr(delim + 1); } - if (*at == 0) + + if (at.empty()) AddPath(".", Angled, false, true, false); else AddPath(at, Angled, false, true, false); } -void InitHeaderSearch::AddGnuCPlusPlusIncludePaths(const std::string &Base, - const char *ArchDir, - const char *Dir32, - const char *Dir64, +void InitHeaderSearch::AddGnuCPlusPlusIncludePaths(llvm::StringRef Base, + llvm::StringRef ArchDir, + llvm::StringRef Dir32, + llvm::StringRef Dir64, const llvm::Triple &triple) { // Add the base dir AddPath(Base, System, true, false, false); @@ -185,10 +186,10 @@ void InitHeaderSearch::AddGnuCPlusPlusIncludePaths(const std::string &Base, AddPath(Base + "/backward", System, true, false, false); } -void InitHeaderSearch::AddMinGWCPlusPlusIncludePaths(const std::string &Base, - const char *Arch, - const char *Version) { - std::string localBase = Base + "/" + Arch + "/" + Version + "/include"; +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); @@ -258,25 +259,25 @@ bool getSystemRegistryString(const char *keyPath, const char *valueName, int bestIndex = -1; double bestValue = 0.0; DWORD index, size = sizeof(keyName) - 1; - for (index = 0; RegEnumKeyEx(hTopKey, index, keyName, &size, NULL, - NULL, NULL, NULL) == ERROR_SUCCESS; index++) { - const char *sp = keyName; - while (*sp && !isdigit(*sp)) - sp++; - if (!*sp) - continue; - const char *ep = sp + 1; - while (*ep && (isdigit(*ep) || (*ep == '.'))) - ep++; - char numBuf[32]; - strncpy(numBuf, sp, sizeof(numBuf) - 1); - numBuf[sizeof(numBuf) - 1] = '\0'; - double value = strtod(numBuf, NULL); - if (value > bestValue) { - bestIndex = (int)index; - bestValue = value; - strcpy(bestName, keyName); - } + for (index = 0; RegEnumKeyEx(hTopKey, index, keyName, &size, NULL, + NULL, NULL, NULL) == ERROR_SUCCESS; index++) { + const char *sp = keyName; + while (*sp && !isdigit(*sp)) + sp++; + if (!*sp) + continue; + const char *ep = sp + 1; + while (*ep && (isdigit(*ep) || (*ep == '.'))) + ep++; + char numBuf[32]; + strncpy(numBuf, sp, sizeof(numBuf) - 1); + numBuf[sizeof(numBuf) - 1] = '\0'; + double value = strtod(numBuf, NULL); + if (value > bestValue) { + bestIndex = (int)index; + bestValue = value; + strcpy(bestName, keyName); + } size = sizeof(keyName) - 1; } // If we found the highest versioned key, open the key and get the value. @@ -500,6 +501,10 @@ void InitHeaderSearch::AddDefaultCPlusPlusIncludePaths(const llvm::Triple &tripl AddGnuCPlusPlusIncludePaths("/usr/include/c++/4.4.1", "i586-redhat-linux","", "", triple); + // Fedora 12 + AddGnuCPlusPlusIncludePaths("/usr/include/c++/4.4.2", + "i686-redhat-linux","", "", triple); + // openSUSE 11.1 32 bit AddGnuCPlusPlusIncludePaths("/usr/include/c++/4.3", "i586-suse-linux", "", "", triple); @@ -643,11 +648,11 @@ static void RemoveDuplicates(std::vector &SearchList, } if (Verbose) { - fprintf(stderr, "ignoring duplicate directory \"%s\"\n", - CurEntry.getName()); + llvm::errs() << "ignoring duplicate directory \"" + << CurEntry.getName() << "\"\n"; if (DirToRemove != i) - fprintf(stderr, " as it is a non-system directory that duplicates" - " a system directory\n"); + llvm::errs() << " as it is a non-system directory that duplicates " + << "a system directory\n"; } // This is reached if the current entry is a duplicate. Remove the @@ -680,11 +685,11 @@ void InitHeaderSearch::Realize() { // If verbose, print the list of directories that will be searched. if (Verbose) { - fprintf(stderr, "#include \"...\" search starts here:\n"); + llvm::errs() << "#include \"...\" search starts here:\n"; unsigned QuotedIdx = IncludeGroup[Quoted].size(); for (unsigned i = 0, e = SearchList.size(); i != e; ++i) { if (i == QuotedIdx) - fprintf(stderr, "#include <...> search starts here:\n"); + llvm::errs() << "#include <...> search starts here:\n"; const char *Name = SearchList[i].getName(); const char *Suffix; if (SearchList[i].isNormalDir()) @@ -695,9 +700,9 @@ void InitHeaderSearch::Realize() { assert(SearchList[i].isHeaderMap() && "Unknown DirectoryLookup"); Suffix = " (headermap)"; } - fprintf(stderr, " %s%s\n", Name, Suffix); + llvm::errs() << " " << Name << Suffix << "\n"; } - fprintf(stderr, "End of search list.\n"); + llvm::errs() << "End of search list.\n"; } } @@ -715,21 +720,22 @@ void clang::ApplyHeaderSearchOptions(HeaderSearch &HS, } // Add entries from CPATH and friends. - Init.AddDelimitedPaths(HSOpts.EnvIncPath.c_str()); + Init.AddDelimitedPaths(HSOpts.EnvIncPath); if (Lang.CPlusPlus && Lang.ObjC1) - Init.AddDelimitedPaths(HSOpts.ObjCXXEnvIncPath.c_str()); + Init.AddDelimitedPaths(HSOpts.ObjCXXEnvIncPath); else if (Lang.CPlusPlus) - Init.AddDelimitedPaths(HSOpts.CXXEnvIncPath.c_str()); + Init.AddDelimitedPaths(HSOpts.CXXEnvIncPath); else if (Lang.ObjC1) - Init.AddDelimitedPaths(HSOpts.ObjCEnvIncPath.c_str()); + Init.AddDelimitedPaths(HSOpts.ObjCEnvIncPath); else - Init.AddDelimitedPaths(HSOpts.CEnvIncPath.c_str()); + Init.AddDelimitedPaths(HSOpts.CEnvIncPath); - if (!HSOpts.BuiltinIncludePath.empty()) { + if (HSOpts.UseBuiltinIncludes) { // Ignore the sys root, we *always* look for clang headers relative to // supplied path. - Init.AddPath(HSOpts.BuiltinIncludePath, System, - false, false, false, /*IgnoreSysRoot=*/ true); + llvm::sys::Path P(HSOpts.ResourceDir); + P.appendComponent("include"); + Init.AddPath(P.str(), System, false, false, false, /*IgnoreSysRoot=*/ true); } if (HSOpts.UseStandardIncludes) diff --git a/lib/Frontend/InitPreprocessor.cpp b/lib/Frontend/InitPreprocessor.cpp index 972c21f88d4d..c1fc92d3b0c9 100644 --- a/lib/Frontend/InitPreprocessor.cpp +++ b/lib/Frontend/InitPreprocessor.cpp @@ -13,17 +13,23 @@ #include "clang/Frontend/Utils.h" #include "clang/Basic/TargetInfo.h" +#include "clang/Frontend/FrontendDiagnostic.h" #include "clang/Frontend/PreprocessorOptions.h" #include "clang/Lex/Preprocessor.h" +#include "clang/Basic/FileManager.h" +#include "clang/Basic/SourceManager.h" #include "llvm/ADT/StringExtras.h" +#include "llvm/ADT/StringMap.h" #include "llvm/ADT/STLExtras.h" +#include "llvm/Support/MemoryBuffer.h" #include "llvm/System/Path.h" using namespace clang; // Append a #define line to Buf for Macro. Macro should be of the form XXX, // in which case we emit "#define XXX 1" or "XXX=Y z W" in which case we emit // "#define XXX Y z W". To get a #define with no value, use "XXX=". -static void DefineBuiltinMacro(std::vector &Buf, const char *Macro) { +static void DefineBuiltinMacro(std::vector &Buf, const char *Macro, + Diagnostic *Diags = 0) { const char *Command = "#define "; Buf.insert(Buf.end(), Command, Command+strlen(Command)); if (const char *Equal = strchr(Macro, '=')) { @@ -34,9 +40,9 @@ static void DefineBuiltinMacro(std::vector &Buf, const char *Macro) { // Per GCC -D semantics, the macro ends at \n if it exists. const char *End = strpbrk(Equal, "\n\r"); if (End) { - fprintf(stderr, "warning: macro '%s' contains embedded newline, text " - "after the newline is ignored.\n", - std::string(Macro, Equal).c_str()); + assert(Diags && "Unexpected macro with embedded newline!"); + Diags->Report(diag::warn_fe_macro_contains_embedded_newline) + << std::string(Macro, Equal); } else { End = Equal+strlen(Equal); } @@ -118,11 +124,9 @@ static void AddImplicitIncludePTH(std::vector &Buf, Preprocessor &PP, const char *OriginalFile = P->getOriginalSourceFile(); if (!OriginalFile) { - assert(!ImplicitIncludePTH.empty()); - fprintf(stderr, "error: PTH file '%s' does not designate an original " - "source header file for -include-pth\n", - ImplicitIncludePTH.c_str()); - exit (1); + PP.getDiagnostics().Report(diag::err_fe_pth_file_has_no_source_header) + << ImplicitIncludePTH; + return; } AddImplicitInclude(Buf, OriginalFile); @@ -358,6 +362,9 @@ static void InitializePredefinedMacros(const TargetInfo &TI, DefineBuiltinMacro(Buf, "__int16=__INT16_TYPE__"); DefineBuiltinMacro(Buf, "__int32=__INT32_TYPE__"); DefineBuiltinMacro(Buf, "__int64=__INT64_TYPE__"); + // Both __PRETTY_FUNCTION__ and __FUNCTION__ are GCC extensions, however + // VC++ appears to only like __FUNCTION__. + DefineBuiltinMacro(Buf, "__PRETTY_FUNCTION__=__FUNCTION__"); // Work around some issues with Visual C++ headerws. if (LangOpts.CPlusPlus) { // Since we define wchar_t in C++ mode. @@ -478,6 +485,52 @@ static void InitializePredefinedMacros(const TargetInfo &TI, TI.getTargetDefines(LangOpts, Buf); } +// Initialize the remapping of files to alternative contents, e.g., +// those specified through other files. +static void InitializeFileRemapping(Diagnostic &Diags, + SourceManager &SourceMgr, + FileManager &FileMgr, + const PreprocessorOptions &InitOpts) { + // Remap files in the source manager. + for (PreprocessorOptions::remapped_file_iterator + 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; + 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; + continue; + } + + // Load the contents of the file we're mapping to. + std::string ErrorStr; + const llvm::MemoryBuffer *Buffer + = llvm::MemoryBuffer::getFile(ToFile->getName(), &ErrorStr); + if (!Buffer) { + Diags.Report(diag::err_fe_error_opening) + << Remap->second << ErrorStr; + continue; + } + + // Override the contents of the "from" file with the contents of + // the "to" file. + SourceMgr.overrideFileContents(FromFile, Buffer); + } +} + /// InitializePreprocessor - Initialize the preprocessor getting it and the /// environment ready to process a single file. This returns true on error. /// @@ -486,6 +539,9 @@ void clang::InitializePreprocessor(Preprocessor &PP, const HeaderSearchOptions &HSOpts) { std::vector PredefineBuffer; + InitializeFileRemapping(PP.getDiagnostics(), PP.getSourceManager(), + PP.getFileManager(), InitOpts); + const char *LineDirective = "# 1 \"\" 3\n"; PredefineBuffer.insert(PredefineBuffer.end(), LineDirective, LineDirective+strlen(LineDirective)); @@ -506,7 +562,8 @@ void clang::InitializePreprocessor(Preprocessor &PP, if (InitOpts.Macros[i].second) // isUndef UndefineBuiltinMacro(PredefineBuffer, InitOpts.Macros[i].first.c_str()); else - DefineBuiltinMacro(PredefineBuffer, InitOpts.Macros[i].first.c_str()); + DefineBuiltinMacro(PredefineBuffer, InitOpts.Macros[i].first.c_str(), + &PP.getDiagnostics()); } // If -imacros are specified, include them now. These are processed before @@ -523,6 +580,11 @@ void clang::InitializePreprocessor(Preprocessor &PP, AddImplicitInclude(PredefineBuffer, Path); } + // Exit the command line and go back to (2 is LC_LEAVE). + LineDirective = "# 1 \"\" 2\n"; + PredefineBuffer.insert(PredefineBuffer.end(), + LineDirective, LineDirective+strlen(LineDirective)); + // Null terminate PredefinedBuffer and add it. PredefineBuffer.push_back(0); PP.setPredefines(&PredefineBuffer[0]); diff --git a/lib/Frontend/LangStandards.cpp b/lib/Frontend/LangStandards.cpp index 771a58c60501..ed0ea1f45ef6 100644 --- a/lib/Frontend/LangStandards.cpp +++ b/lib/Frontend/LangStandards.cpp @@ -14,13 +14,13 @@ using namespace clang; using namespace clang::frontend; #define LANGSTANDARD(id, name, desc, features) \ - static LangStandard Lang_##id = { name, desc, features }; + static const LangStandard Lang_##id = { name, desc, features }; #include "clang/Frontend/LangStandards.def" const LangStandard &LangStandard::getLangStandardForKind(Kind K) { switch (K) { default: - llvm::llvm_unreachable("Invalid language kind!"); + llvm_unreachable("Invalid language kind!"); case lang_unspecified: llvm::llvm_report_error("getLangStandardForKind() on unspecified kind"); #define LANGSTANDARD(id, name, desc, features) \ diff --git a/lib/Frontend/PCHReader.cpp b/lib/Frontend/PCHReader.cpp index cb96bcb48aec..48ef2ac31aba 100644 --- a/lib/Frontend/PCHReader.cpp +++ b/lib/Frontend/PCHReader.cpp @@ -116,6 +116,7 @@ PCHValidator::ReadLanguageOptions(const LangOptions &LangOpts) { diag::warn_pch_stack_protector); PARSE_LANGOPT_BENIGN(InstantiationDepth); PARSE_LANGOPT_IMPORTANT(OpenCL, diag::warn_pch_opencl); + PARSE_LANGOPT_BENIGN(CatchUndefined); PARSE_LANGOPT_IMPORTANT(ElideConstructors, diag::warn_pch_elide_constructors); #undef PARSE_LANGOPT_IRRELEVANT #undef PARSE_LANGOPT_BENIGN @@ -1569,13 +1570,14 @@ void PCHReader::InitializeContext(ASTContext &Ctx) { /// \brief Retrieve the name of the original source file name /// directly from the PCH file, without actually loading the PCH /// file. -std::string PCHReader::getOriginalSourceFile(const std::string &PCHFileName) { +std::string PCHReader::getOriginalSourceFile(const std::string &PCHFileName, + Diagnostic &Diags) { // Open the PCH file. std::string ErrStr; llvm::OwningPtr Buffer; Buffer.reset(llvm::MemoryBuffer::getFile(PCHFileName.c_str(), &ErrStr)); if (!Buffer) { - fprintf(stderr, "error: %s\n", ErrStr.c_str()); + Diags.Report(diag::err_fe_unable_to_read_pch_file) << ErrStr; return std::string(); } @@ -1591,9 +1593,7 @@ std::string PCHReader::getOriginalSourceFile(const std::string &PCHFileName) { Stream.Read(8) != 'P' || Stream.Read(8) != 'C' || Stream.Read(8) != 'H') { - fprintf(stderr, - "error: '%s' does not appear to be a precompiled header file\n", - PCHFileName.c_str()); + Diags.Report(diag::err_fe_not_a_pch_file) << PCHFileName; return std::string(); } @@ -1608,14 +1608,14 @@ std::string PCHReader::getOriginalSourceFile(const std::string &PCHFileName) { switch (BlockID) { case pch::PCH_BLOCK_ID: if (Stream.EnterSubBlock(pch::PCH_BLOCK_ID)) { - fprintf(stderr, "error: malformed block record in PCH file\n"); + Diags.Report(diag::err_fe_pch_malformed_block) << PCHFileName; return std::string(); } break; default: if (Stream.SkipBlock()) { - fprintf(stderr, "error: malformed block record in PCH file\n"); + Diags.Report(diag::err_fe_pch_malformed_block) << PCHFileName; return std::string(); } break; @@ -1625,7 +1625,7 @@ std::string PCHReader::getOriginalSourceFile(const std::string &PCHFileName) { if (Code == llvm::bitc::END_BLOCK) { if (Stream.ReadBlockEnd()) { - fprintf(stderr, "error: error at end of module block in PCH file\n"); + Diags.Report(diag::err_fe_pch_error_at_end_block) << PCHFileName; return std::string(); } continue; @@ -1720,6 +1720,8 @@ bool PCHReader::ParseLanguageOptions( ++Idx; PARSE_LANGOPT(InstantiationDepth); PARSE_LANGOPT(OpenCL); + PARSE_LANGOPT(CatchUndefined); + // FIXME: Missing ElideConstructors?! #undef PARSE_LANGOPT return Listener->ReadLanguageOptions(LangOpts); @@ -1881,6 +1883,10 @@ QualType PCHReader::ReadTypeRecord(uint64_t Offset) { Exceptions.data()); } + case pch::TYPE_UNRESOLVED_USING: + return Context->getTypeDeclType( + cast(GetDecl(Record[0]))); + case pch::TYPE_TYPEDEF: assert(Record.size() == 1 && "incorrect encoding of typedef type"); return Context->getTypeDeclType(cast(GetDecl(Record[0]))); @@ -2045,6 +2051,9 @@ void TypeLocReader::VisitFunctionProtoTypeLoc(FunctionProtoTypeLoc TL) { void TypeLocReader::VisitFunctionNoProtoTypeLoc(FunctionNoProtoTypeLoc TL) { VisitFunctionTypeLoc(TL); } +void TypeLocReader::VisitUnresolvedUsingTypeLoc(UnresolvedUsingTypeLoc TL) { + TL.setNameLoc(SourceLocation::getFromRawEncoding(Record[Idx++])); +} void TypeLocReader::VisitTypedefTypeLoc(TypedefTypeLoc TL) { TL.setNameLoc(SourceLocation::getFromRawEncoding(Record[Idx++])); } @@ -2107,17 +2116,17 @@ void TypeLocReader::VisitObjCObjectPointerTypeLoc(ObjCObjectPointerTypeLoc TL) { TL.setProtocolLoc(i, SourceLocation::getFromRawEncoding(Record[Idx++])); } -DeclaratorInfo *PCHReader::GetDeclaratorInfo(const RecordData &Record, +TypeSourceInfo *PCHReader::GetTypeSourceInfo(const RecordData &Record, unsigned &Idx) { QualType InfoTy = GetType(Record[Idx++]); if (InfoTy.isNull()) return 0; - DeclaratorInfo *DInfo = getContext()->CreateDeclaratorInfo(InfoTy); + TypeSourceInfo *TInfo = getContext()->CreateTypeSourceInfo(InfoTy); TypeLocReader TLR(*this, Record, Idx); - for (TypeLoc TL = DInfo->getTypeLoc(); !TL.isNull(); TL = TL.getNextTypeLoc()) + for (TypeLoc TL = TInfo->getTypeLoc(); !TL.isNull(); TL = TL.getNextTypeLoc()) TLR.Visit(TL); - return DInfo; + return TInfo; } QualType PCHReader::GetType(pch::TypeID ID) { @@ -2183,7 +2192,7 @@ PCHReader::GetTemplateArgumentLocInfo(TemplateArgument::ArgKind Kind, case TemplateArgument::Expression: return ReadDeclExpr(); case TemplateArgument::Type: - return GetDeclaratorInfo(Record, Index); + return GetTypeSourceInfo(Record, Index); case TemplateArgument::Template: { SourceLocation QualStart = SourceLocation::getFromRawEncoding(Record[Index++]), @@ -2198,7 +2207,7 @@ PCHReader::GetTemplateArgumentLocInfo(TemplateArgument::ArgKind Kind, case TemplateArgument::Pack: return TemplateArgumentLocInfo(); } - llvm::llvm_unreachable("unexpected template argument loc"); + llvm_unreachable("unexpected template argument loc"); return TemplateArgumentLocInfo(); } diff --git a/lib/Frontend/PCHReaderDecl.cpp b/lib/Frontend/PCHReaderDecl.cpp index 03f3b4767994..01e1a4191a99 100644 --- a/lib/Frontend/PCHReaderDecl.cpp +++ b/lib/Frontend/PCHReaderDecl.cpp @@ -107,7 +107,7 @@ void PCHDeclReader::VisitTypedefDecl(TypedefDecl *TD) { // the type associated with the TypedefDecl. VisitNamedDecl(TD); uint64_t TypeData = Record[Idx++]; - TD->setTypeDeclaratorInfo(Reader.GetDeclaratorInfo(Record, Idx)); + TD->setTypeSourceInfo(Reader.GetTypeSourceInfo(Record, Idx)); TD->setTypeForDecl(Reader.GetType(TypeData).getTypePtr()); } @@ -126,6 +126,7 @@ void PCHDeclReader::VisitTagDecl(TagDecl *TD) { void PCHDeclReader::VisitEnumDecl(EnumDecl *ED) { VisitTagDecl(ED); ED->setIntegerType(Reader.GetType(Record[Idx++])); + ED->setPromotionType(Reader.GetType(Record[Idx++])); // FIXME: C++ InstantiatedFrom } @@ -150,9 +151,9 @@ void PCHDeclReader::VisitEnumConstantDecl(EnumConstantDecl *ECD) { void PCHDeclReader::VisitDeclaratorDecl(DeclaratorDecl *DD) { VisitValueDecl(DD); - DeclaratorInfo *DInfo = Reader.GetDeclaratorInfo(Record, Idx); - if (DInfo) - DD->setDeclaratorInfo(DInfo); + TypeSourceInfo *TInfo = Reader.GetTypeSourceInfo(Record, Idx); + if (TInfo) + DD->setTypeSourceInfo(TInfo); } void PCHDeclReader::VisitFunctionDecl(FunctionDecl *FD) { diff --git a/lib/Frontend/PCHReaderStmt.cpp b/lib/Frontend/PCHReaderStmt.cpp index 00734a0854a4..f28e61e1ecdc 100644 --- a/lib/Frontend/PCHReaderStmt.cpp +++ b/lib/Frontend/PCHReaderStmt.cpp @@ -349,7 +349,7 @@ unsigned PCHStmtReader::VisitPredefinedExpr(PredefinedExpr *E) { unsigned PCHStmtReader::VisitDeclRefExpr(DeclRefExpr *E) { VisitExpr(E); - E->setDecl(cast(Reader.GetDecl(Record[Idx++]))); + E->setDecl(cast(Reader.GetDecl(Record[Idx++]))); E->setLocation(SourceLocation::getFromRawEncoding(Record[Idx++])); // FIXME: read qualifier // FIXME: read explicit template arguments @@ -428,7 +428,7 @@ unsigned PCHStmtReader::VisitSizeOfAlignOfExpr(SizeOfAlignOfExpr *E) { E->setArgument(cast(StmtStack.back())); ++Idx; } else { - E->setArgument(Reader.GetDeclaratorInfo(Record, Idx)); + E->setArgument(Reader.GetTypeSourceInfo(Record, Idx)); } E->setOperatorLoc(SourceLocation::getFromRawEncoding(Record[Idx++])); E->setRParenLoc(SourceLocation::getFromRawEncoding(Record[Idx++])); @@ -456,7 +456,7 @@ unsigned PCHStmtReader::VisitCallExpr(CallExpr *E) { unsigned PCHStmtReader::VisitMemberExpr(MemberExpr *E) { VisitExpr(E); E->setBase(cast(StmtStack.back())); - E->setMemberDecl(cast(Reader.GetDecl(Record[Idx++]))); + E->setMemberDecl(cast(Reader.GetDecl(Record[Idx++]))); E->setMemberLoc(SourceLocation::getFromRawEncoding(Record[Idx++])); E->setArrow(Record[Idx++]); return 1; diff --git a/lib/Frontend/PCHWriter.cpp b/lib/Frontend/PCHWriter.cpp index e79f9c9dac19..681c1ff32cb0 100644 --- a/lib/Frontend/PCHWriter.cpp +++ b/lib/Frontend/PCHWriter.cpp @@ -166,6 +166,14 @@ void PCHTypeWriter::VisitFunctionProtoType(const FunctionProtoType *T) { Code = pch::TYPE_FUNCTION_PROTO; } +#if 0 +// For when we want it.... +void PCHTypeWriter::VisitUnresolvedUsingType(const UnresolvedUsingType *T) { + Writer.AddDeclRef(T->getDecl(), Record); + Code = pch::TYPE_UNRESOLVED_USING; +} +#endif + void PCHTypeWriter::VisitTypedefType(const TypedefType *T) { Writer.AddDeclRef(T->getDecl(), Record); Code = pch::TYPE_TYPEDEF; @@ -337,6 +345,9 @@ void TypeLocWriter::VisitFunctionProtoTypeLoc(FunctionProtoTypeLoc TL) { void TypeLocWriter::VisitFunctionNoProtoTypeLoc(FunctionNoProtoTypeLoc TL) { VisitFunctionTypeLoc(TL); } +void TypeLocWriter::VisitUnresolvedUsingTypeLoc(UnresolvedUsingTypeLoc TL) { + Writer.AddSourceLocation(TL.getNameLoc(), Record); +} void TypeLocWriter::VisitTypedefTypeLoc(TypedefTypeLoc TL) { Writer.AddSourceLocation(TL.getNameLoc(), Record); } @@ -770,6 +781,7 @@ void PCHWriter::WriteLanguageOptions(const LangOptions &LangOpts) { Record.push_back(LangOpts.getStackProtectorMode()); Record.push_back(LangOpts.InstantiationDepth); Record.push_back(LangOpts.OpenCL); + Record.push_back(LangOpts.CatchUndefined); Record.push_back(LangOpts.ElideConstructors); Stream.EmitRecord(pch::LANGUAGE_OPTIONS, Record); } @@ -2129,7 +2141,7 @@ void PCHWriter::AddTemplateArgumentLoc(const TemplateArgumentLoc &Arg, AddStmt(Arg.getLocInfo().getAsExpr()); break; case TemplateArgument::Type: - AddDeclaratorInfo(Arg.getLocInfo().getAsDeclaratorInfo(), Record); + AddTypeSourceInfo(Arg.getLocInfo().getAsTypeSourceInfo(), Record); break; case TemplateArgument::Template: Record.push_back( @@ -2145,15 +2157,15 @@ void PCHWriter::AddTemplateArgumentLoc(const TemplateArgumentLoc &Arg, } } -void PCHWriter::AddDeclaratorInfo(DeclaratorInfo *DInfo, RecordData &Record) { - if (DInfo == 0) { +void PCHWriter::AddTypeSourceInfo(TypeSourceInfo *TInfo, RecordData &Record) { + if (TInfo == 0) { AddTypeRef(QualType(), Record); return; } - AddTypeRef(DInfo->getType(), Record); + AddTypeRef(TInfo->getType(), Record); TypeLocWriter TLW(*this, Record); - for (TypeLoc TL = DInfo->getTypeLoc(); !TL.isNull(); TL = TL.getNextTypeLoc()) + for (TypeLoc TL = TInfo->getTypeLoc(); !TL.isNull(); TL = TL.getNextTypeLoc()) TLW.Visit(TL); } diff --git a/lib/Frontend/PCHWriterDecl.cpp b/lib/Frontend/PCHWriterDecl.cpp index c7bfee2c8bcd..049cdb03ea3b 100644 --- a/lib/Frontend/PCHWriterDecl.cpp +++ b/lib/Frontend/PCHWriterDecl.cpp @@ -14,9 +14,9 @@ #include "clang/Frontend/PCHWriter.h" #include "clang/AST/DeclVisitor.h" #include "clang/AST/Expr.h" +#include "llvm/ADT/Twine.h" #include "llvm/Bitcode/BitstreamWriter.h" -#include - +#include "llvm/Support/ErrorHandling.h" using namespace clang; //===----------------------------------------------------------------------===// @@ -106,7 +106,7 @@ void PCHDeclWriter::VisitTypeDecl(TypeDecl *D) { void PCHDeclWriter::VisitTypedefDecl(TypedefDecl *D) { VisitTypeDecl(D); - Writer.AddDeclaratorInfo(D->getTypeDeclaratorInfo(), Record); + Writer.AddTypeSourceInfo(D->getTypeSourceInfo(), Record); Code = pch::DECL_TYPEDEF; } @@ -123,6 +123,7 @@ void PCHDeclWriter::VisitTagDecl(TagDecl *D) { void PCHDeclWriter::VisitEnumDecl(EnumDecl *D) { VisitTagDecl(D); Writer.AddTypeRef(D->getIntegerType(), Record); + Writer.AddTypeRef(D->getPromotionType(), Record); // FIXME: C++ InstantiatedFrom Code = pch::DECL_ENUM; } @@ -151,7 +152,7 @@ void PCHDeclWriter::VisitEnumConstantDecl(EnumConstantDecl *D) { void PCHDeclWriter::VisitDeclaratorDecl(DeclaratorDecl *D) { VisitValueDecl(D); - Writer.AddDeclaratorInfo(D->getDeclaratorInfo(), Record); + Writer.AddTypeSourceInfo(D->getTypeSourceInfo(), Record); } void PCHDeclWriter::VisitFunctionDecl(FunctionDecl *D) { @@ -370,7 +371,7 @@ void PCHDeclWriter::VisitParmVarDecl(ParmVarDecl *D) { // If the assumptions about the DECL_PARM_VAR abbrev are true, use it. Here // we dynamically check for the properties that we optimize for, but don't // know are true of all PARM_VAR_DECLs. - if (!D->getDeclaratorInfo() && + if (!D->getTypeSourceInfo() && !D->hasAttrs() && !D->isImplicit() && !D->isUsed() && @@ -568,12 +569,9 @@ void PCHWriter::WriteDecl(ASTContext &Context, Decl *D) { W.Visit(D); if (DC) W.VisitDeclContext(DC, LexicalOffset, VisibleOffset); - if (!W.Code) { - fprintf(stderr, "Cannot serialize declaration of kind %s\n", - D->getDeclKindName()); - assert(false && "Unhandled declaration kind while generating PCH"); - exit(-1); - } + if (!W.Code) + llvm::llvm_report_error(llvm::StringRef("unexpected declaration kind '") + + D->getDeclKindName() + "'"); Stream.EmitRecord(W.Code, Record, W.AbbrevToUse); // If the declaration had any attributes, write them now. diff --git a/lib/Frontend/PCHWriterStmt.cpp b/lib/Frontend/PCHWriterStmt.cpp index 27b83ed6cbb2..22f7ad66d9d1 100644 --- a/lib/Frontend/PCHWriterStmt.cpp +++ b/lib/Frontend/PCHWriterStmt.cpp @@ -388,7 +388,7 @@ void PCHStmtWriter::VisitSizeOfAlignOfExpr(SizeOfAlignOfExpr *E) { VisitExpr(E); Record.push_back(E->isSizeOf()); if (E->isArgumentType()) - Writer.AddDeclaratorInfo(E->getArgumentTypeInfo(), Record); + Writer.AddTypeSourceInfo(E->getArgumentTypeInfo(), Record); else { Record.push_back(0); Writer.WriteSubStmt(E->getArgumentExpr()); diff --git a/lib/Frontend/PlistDiagnostics.cpp b/lib/Frontend/PlistDiagnostics.cpp index 80ee2c2e8eba..92cafe6d1cbe 100644 --- a/lib/Frontend/PlistDiagnostics.cpp +++ b/lib/Frontend/PlistDiagnostics.cpp @@ -29,6 +29,40 @@ namespace clang { class Preprocessor; } +namespace { +struct CompareDiagnostics { + // Compare if 'X' is "<" than 'Y'. + bool operator()(const PathDiagnostic *X, const PathDiagnostic *Y) const { + // First compare by location + const FullSourceLoc &XLoc = X->getLocation().asLocation(); + const FullSourceLoc &YLoc = Y->getLocation().asLocation(); + if (XLoc < YLoc) + return true; + if (XLoc != YLoc) + return false; + + // Next, compare by bug type. + llvm::StringRef XBugType = X->getBugType(); + llvm::StringRef YBugType = Y->getBugType(); + if (XBugType < YBugType) + return true; + if (XBugType != YBugType) + return false; + + // Next, compare by bug description. + llvm::StringRef XDesc = X->getDescription(); + llvm::StringRef YDesc = Y->getDescription(); + if (XDesc < YDesc) + return true; + if (XDesc != YDesc) + return false; + + // FIXME: Further refine by comparing PathDiagnosticPieces? + return false; + } +}; +} + namespace { class PlistDiagnostics : public PathDiagnosticClient { std::vector BatchedDiags; @@ -314,6 +348,11 @@ void PlistDiagnostics::FlushDiagnostics(llvm::SmallVectorImpl return; flushed = true; + + // Sort the diagnostics so that they are always emitted in a deterministic + // order. + if (!BatchedDiags.empty()) + std::sort(BatchedDiags.begin(), BatchedDiags.end(), CompareDiagnostics()); // Build up a set of FIDs that we use by scanning the locations and // ranges of the diagnostics. diff --git a/lib/Frontend/PrintPreprocessedOutput.cpp b/lib/Frontend/PrintPreprocessedOutput.cpp index 37424057809c..d9708d8bced4 100644 --- a/lib/Frontend/PrintPreprocessedOutput.cpp +++ b/lib/Frontend/PrintPreprocessedOutput.cpp @@ -36,22 +36,23 @@ static void PrintMacroDefinition(const IdentifierInfo &II, const MacroInfo &MI, if (MI.isFunctionLike()) { OS << '('; - if (MI.arg_empty()) - ; - else if (MI.getNumArgs() == 1) - OS << (*MI.arg_begin())->getName(); - else { + if (!MI.arg_empty()) { MacroInfo::arg_iterator AI = MI.arg_begin(), E = MI.arg_end(); - OS << (*AI++)->getName(); - while (AI != E) - OS << ',' << (*AI++)->getName(); + for (; AI+1 != E; ++AI) { + OS << (*AI)->getName(); + OS << ','; + } + + // Last argument. + if ((*AI)->getName() == "__VA_ARGS__") + OS << "..."; + else + OS << (*AI)->getName(); } - if (MI.isVariadic()) { - if (!MI.arg_empty()) - OS << ','; - OS << "..."; - } + if (MI.isGNUVarargs()) + OS << "..."; // #define foo(x...) + OS << ')'; } @@ -94,6 +95,7 @@ class PrintPPOutputPPCallbacks : public PPCallbacks { bool Initialized; bool DisableLineMarkers; bool DumpDefines; + bool UseLineDirective; public: PrintPPOutputPPCallbacks(Preprocessor &pp, llvm::raw_ostream &os, bool lineMarkers, bool defines) @@ -105,6 +107,9 @@ class PrintPPOutputPPCallbacks : public PPCallbacks { EmittedMacroOnThisLine = false; FileType = SrcMgr::C_User; Initialized = false; + + // If we're in microsoft mode, use normal #line instead of line markers. + UseLineDirective = PP.getLangOptions().Microsoft; } void SetEmittedTokensOnThisLine() { EmittedTokensOnThisLine = true; } @@ -141,17 +146,24 @@ void PrintPPOutputPPCallbacks::WriteLineInfo(unsigned LineNo, EmittedMacroOnThisLine = false; } - OS << '#' << ' ' << LineNo << ' ' << '"'; - OS.write(&CurFilename[0], CurFilename.size()); - OS << '"'; + // Emit #line directives or GNU line markers depending on what mode we're in. + if (UseLineDirective) { + OS << "#line" << ' ' << LineNo << ' ' << '"'; + OS.write(&CurFilename[0], CurFilename.size()); + OS << '"'; + } else { + OS << '#' << ' ' << LineNo << ' ' << '"'; + OS.write(&CurFilename[0], CurFilename.size()); + OS << '"'; + + if (ExtraLen) + OS.write(Extra, ExtraLen); - if (ExtraLen) - OS.write(Extra, ExtraLen); - - if (FileType == SrcMgr::C_System) - OS.write(" 3", 2); - else if (FileType == SrcMgr::C_ExternCSystem) - OS.write(" 3 4", 4); + if (FileType == SrcMgr::C_System) + OS.write(" 3", 2); + else if (FileType == SrcMgr::C_ExternCSystem) + OS.write(" 3 4", 4); + } OS << '\n'; } diff --git a/lib/Frontend/RewriteObjC.cpp b/lib/Frontend/RewriteObjC.cpp index 710fa55b69bf..df85c13cea78 100644 --- a/lib/Frontend/RewriteObjC.cpp +++ b/lib/Frontend/RewriteObjC.cpp @@ -255,7 +255,10 @@ namespace { Stmt *RewriteMessageExpr(ObjCMessageExpr *Exp); Stmt *RewriteObjCStringLiteral(ObjCStringLiteral *Exp); Stmt *RewriteObjCProtocolExpr(ObjCProtocolExpr *Exp); - void WarnAboutReturnGotoContinueOrBreakStmts(Stmt *S); + void WarnAboutReturnGotoStmts(Stmt *S); + void HasReturnStmts(Stmt *S, bool &hasReturns); + void RewriteTryReturnStmts(Stmt *S); + void RewriteSyncReturnStmts(Stmt *S, std::string buf); Stmt *RewriteObjCTryStmt(ObjCAtTryStmt *S); Stmt *RewriteObjCSynchronizedStmt(ObjCAtSynchronizedStmt *S); Stmt *RewriteObjCCatchStmt(ObjCAtCatchStmt *S); @@ -328,11 +331,16 @@ namespace { const char *funcName, std::string Tag); std::string SynthesizeBlockFunc(BlockExpr *CE, int i, const char *funcName, std::string Tag); - std::string SynthesizeBlockImpl(BlockExpr *CE, std::string Tag, - bool hasCopyDisposeHelpers); + std::string SynthesizeBlockImpl(BlockExpr *CE, + std::string Tag, std::string Desc); + std::string SynthesizeBlockDescriptor(std::string DescTag, + std::string ImplTag, + int i, const char *funcName, + unsigned hasCopy); Stmt *SynthesizeBlockCall(CallExpr *Exp); void SynthesizeBlockLiterals(SourceLocation FunLocStart, const char *FunName); + void RewriteRecordBody(RecordDecl *RD); void CollectBlockDeclRefInfo(BlockExpr *Exp); void GetBlockCallExprs(Stmt *S); @@ -547,14 +555,21 @@ void RewriteObjC::Initialize(ASTContext &context) { Preamble += "struct __block_impl {\n"; Preamble += " void *isa;\n"; Preamble += " int Flags;\n"; - Preamble += " int Size;\n"; + Preamble += " int Reserved;\n"; Preamble += " void *FuncPtr;\n"; Preamble += "};\n"; Preamble += "// Runtime copy/destroy helper functions (from Block_private.h)\n"; - Preamble += "__OBJC_RW_STATICIMPORT void _Block_object_assign(void *, const void *, const int);\n"; - Preamble += "__OBJC_RW_STATICIMPORT void _Block_object_dispose(const void *, const int);\n"; - Preamble += "__OBJC_RW_STATICIMPORT void *_NSConcreteGlobalBlock[32];\n"; - Preamble += "__OBJC_RW_STATICIMPORT void *_NSConcreteStackBlock[32];\n"; + Preamble += "#ifdef __OBJC_EXPORT_BLOCKS\n"; + Preamble += "extern \"C\" __declspec(dllexport) void _Block_object_assign(void *, const void *, const int);\n"; + Preamble += "extern \"C\" __declspec(dllexport) void _Block_object_dispose(const void *, const int);\n"; + Preamble += "extern \"C\" __declspec(dllexport) void *_NSConcreteGlobalBlock[32];\n"; + Preamble += "extern \"C\" __declspec(dllexport) void *_NSConcreteStackBlock[32];\n"; + Preamble += "#else\n"; + Preamble += "__OBJC_RW_DLLIMPORT void _Block_object_assign(void *, const void *, const int);\n"; + Preamble += "__OBJC_RW_DLLIMPORT void _Block_object_dispose(const void *, const int);\n"; + Preamble += "__OBJC_RW_DLLIMPORT void *_NSConcreteGlobalBlock[32];\n"; + Preamble += "__OBJC_RW_DLLIMPORT void *_NSConcreteStackBlock[32];\n"; + Preamble += "#endif\n"; Preamble += "#endif\n"; if (LangOpts.Microsoft) { Preamble += "#undef __OBJC_RW_DLLIMPORT\n"; @@ -1325,7 +1340,12 @@ Stmt *RewriteObjC::RewriteObjCForCollectionStmt(ObjCForCollectionStmt *S, // type elem; NamedDecl* D = cast(DS->getSingleDecl()); QualType ElementType = cast(D)->getType(); - elementTypeAsString = ElementType.getAsString(); + if (ElementType->isObjCQualifiedIdType() || + ElementType->isObjCQualifiedInterfaceType()) + // Simply use 'id' for all qualified types. + elementTypeAsString = "id"; + else + elementTypeAsString = ElementType.getAsString(); buf += elementTypeAsString; buf += " "; elementName = D->getNameAsCString(); @@ -1335,8 +1355,13 @@ Stmt *RewriteObjC::RewriteObjCForCollectionStmt(ObjCForCollectionStmt *S, else { DeclRefExpr *DR = cast(S->getElement()); elementName = DR->getDecl()->getNameAsCString(); - elementTypeAsString - = cast(DR->getDecl())->getType().getAsString(); + ValueDecl *VD = cast(DR->getDecl()); + if (VD->getType()->isObjCQualifiedIdType() || + VD->getType()->isObjCQualifiedInterfaceType()) + // Simply use 'id' for all qualified types. + elementTypeAsString = "id"; + else + elementTypeAsString = VD->getType().getAsString(); } // struct __objcFastEnumerationState enumState = { 0 }; @@ -1502,7 +1527,9 @@ Stmt *RewriteObjC::RewriteObjCSynchronizedStmt(ObjCAtSynchronizedStmt *S) { buf += "}\n"; buf += "{ /* implicit finally clause */\n"; buf += " if (!_rethrow) objc_exception_try_exit(&_stack);\n"; - buf += " objc_sync_exit("; + + std::string syncBuf; + syncBuf += " objc_sync_exit("; Expr *syncExpr = new (Context) CStyleCastExpr(Context->getObjCIdType(), CastExpr::CK_Unknown, S->getSynchExpr(), @@ -1513,31 +1540,102 @@ Stmt *RewriteObjC::RewriteObjCSynchronizedStmt(ObjCAtSynchronizedStmt *S) { llvm::raw_string_ostream syncExprBuf(syncExprBufS); syncExpr->printPretty(syncExprBuf, *Context, 0, PrintingPolicy(LangOpts)); - buf += syncExprBuf.str(); - buf += ");\n"; - buf += " if (_rethrow) objc_exception_throw(_rethrow);\n"; + syncBuf += syncExprBuf.str(); + syncBuf += ");"; + + buf += syncBuf; + buf += "\n if (_rethrow) objc_exception_throw(_rethrow);\n"; buf += "}\n"; buf += "}"; ReplaceText(lastCurlyLoc, 1, buf.c_str(), buf.size()); + + bool hasReturns = false; + HasReturnStmts(S->getSynchBody(), hasReturns); + if (hasReturns) + RewriteSyncReturnStmts(S->getSynchBody(), syncBuf); + return 0; } -void RewriteObjC::WarnAboutReturnGotoContinueOrBreakStmts(Stmt *S) { +void RewriteObjC::WarnAboutReturnGotoStmts(Stmt *S) +{ // Perform a bottom up traversal of all children. for (Stmt::child_iterator CI = S->child_begin(), E = S->child_end(); CI != E; ++CI) if (*CI) - WarnAboutReturnGotoContinueOrBreakStmts(*CI); + WarnAboutReturnGotoStmts(*CI); - if (isa(S) || isa(S) || - isa(S) || isa(S)) { + if (isa(S) || isa(S)) { Diags.Report(Context->getFullLoc(S->getLocStart()), TryFinallyContainsReturnDiag); } return; } +void RewriteObjC::HasReturnStmts(Stmt *S, bool &hasReturns) +{ + // Perform a bottom up traversal of all children. + for (Stmt::child_iterator CI = S->child_begin(), E = S->child_end(); + CI != E; ++CI) + if (*CI) + HasReturnStmts(*CI, hasReturns); + + if (isa(S)) + hasReturns = true; + return; +} + +void RewriteObjC::RewriteTryReturnStmts(Stmt *S) { + // Perform a bottom up traversal of all children. + for (Stmt::child_iterator CI = S->child_begin(), E = S->child_end(); + CI != E; ++CI) + if (*CI) { + RewriteTryReturnStmts(*CI); + } + if (isa(S)) { + SourceLocation startLoc = S->getLocStart(); + const char *startBuf = SM->getCharacterData(startLoc); + + const char *semiBuf = strchr(startBuf, ';'); + assert((*semiBuf == ';') && "RewriteTryReturnStmts: can't find ';'"); + SourceLocation onePastSemiLoc = startLoc.getFileLocWithOffset(semiBuf-startBuf+1); + + std::string buf; + buf = "{ objc_exception_try_exit(&_stack); return"; + + ReplaceText(startLoc, 6, buf.c_str(), buf.size()); + InsertText(onePastSemiLoc, "}", 1); + } + return; +} + +void RewriteObjC::RewriteSyncReturnStmts(Stmt *S, std::string syncExitBuf) { + // Perform a bottom up traversal of all children. + for (Stmt::child_iterator CI = S->child_begin(), E = S->child_end(); + CI != E; ++CI) + if (*CI) { + RewriteSyncReturnStmts(*CI, syncExitBuf); + } + if (isa(S)) { + SourceLocation startLoc = S->getLocStart(); + const char *startBuf = SM->getCharacterData(startLoc); + + const char *semiBuf = strchr(startBuf, ';'); + assert((*semiBuf == ';') && "RewriteSyncReturnStmts: can't find ';'"); + SourceLocation onePastSemiLoc = startLoc.getFileLocWithOffset(semiBuf-startBuf+1); + + std::string buf; + buf = "{ objc_exception_try_exit(&_stack);"; + buf += syncExitBuf; + buf += " return"; + + ReplaceText(startLoc, 6, buf.c_str(), buf.size()); + InsertText(onePastSemiLoc, "}", 1); + } + return; +} + Stmt *RewriteObjC::RewriteObjCTryStmt(ObjCAtTryStmt *S) { // Get the start location and compute the semi location. SourceLocation startLoc = S->getLocStart(); @@ -1689,13 +1787,21 @@ Stmt *RewriteObjC::RewriteObjCTryStmt(ObjCAtTryStmt *S) { lastCurlyLoc = body->getLocEnd(); // Now check for any return/continue/go statements within the @try. - WarnAboutReturnGotoContinueOrBreakStmts(S->getTryBody()); + WarnAboutReturnGotoStmts(S->getTryBody()); } else { /* no finally clause - make sure we synthesize an implicit one */ buf = "{ /* implicit finally clause */\n"; buf += " if (!_rethrow) objc_exception_try_exit(&_stack);\n"; buf += " if (_rethrow) objc_exception_throw(_rethrow);\n"; buf += "}"; ReplaceText(lastCurlyLoc, 1, buf.c_str(), buf.size()); + + // Now check for any return/continue/go statements within the @try. + // The implicit finally clause won't called if the @try contains any + // jump statements. + bool hasReturns = false; + HasReturnStmts(S->getTryBody(), hasReturns); + if (hasReturns) + RewriteTryReturnStmts(S->getTryBody()); } // Now emit the final closing curly brace... lastCurlyLoc = lastCurlyLoc.getFileLocWithOffset(1); @@ -1878,6 +1984,10 @@ void RewriteObjC::RewriteObjCQualifiedInterfaceTypes(Decl *Dcl) { return; Type = proto->getResultType(); } + else if (FieldDecl *FD = dyn_cast(Dcl)) { + Loc = FD->getLocation(); + Type = FD->getType(); + } else return; @@ -2134,8 +2244,7 @@ Stmt *RewriteObjC::RewriteObjCStringLiteral(ObjCStringLiteral *Exp) { PrintingPolicy(LangOpts)); Preamble += prettyBuf.str(); Preamble += ","; - // The minus 2 removes the begin/end double quotes. - Preamble += utostr(prettyBuf.str().size()-2) + "};\n"; + Preamble += utostr(Exp->getString()->getByteLength()) + "};\n"; VarDecl *NewVD = VarDecl::Create(*Context, TUDecl, SourceLocation(), &Context->Idents.get(S.c_str()), strType, 0, @@ -2569,7 +2678,7 @@ Stmt *RewriteObjC::SynthMessageExpr(ObjCMessageExpr *Exp) { // Build sizeof(returnType) SizeOfAlignOfExpr *sizeofExpr = new (Context) SizeOfAlignOfExpr(true, - Context->getTrivialDeclaratorInfo(returnType), + Context->getTrivialTypeSourceInfo(returnType), Context->getSizeType(), SourceLocation(), SourceLocation()); // (sizeof(returnType) <= 8 ? objc_msgSend(...) : objc_msgSend_stret(...)) @@ -2609,12 +2718,12 @@ Stmt *RewriteObjC::RewriteMessageExpr(ObjCMessageExpr *Exp) { // typedef struct objc_object Protocol; QualType RewriteObjC::getProtocolType() { if (!ProtocolTypeDecl) { - DeclaratorInfo *DInfo - = Context->getTrivialDeclaratorInfo(Context->getObjCIdType()); + TypeSourceInfo *TInfo + = Context->getTrivialTypeSourceInfo(Context->getObjCIdType()); ProtocolTypeDecl = TypedefDecl::Create(*Context, TUDecl, SourceLocation(), &Context->Idents.get("Protocol"), - DInfo); + TInfo); } return Context->getTypeDeclType(ProtocolTypeDecl); } @@ -2737,7 +2846,7 @@ void RewriteObjC::SynthesizeObjCInternalStruct(ObjCInterfaceDecl *CDecl, ReplaceText(LocStart, endHeader-startBuf, Result.c_str(), Result.size()); } else { // rewrite the original header *without* disturbing the '{' - ReplaceText(LocStart, cursor-startBuf-1, Result.c_str(), Result.size()); + ReplaceText(LocStart, cursor-startBuf, Result.c_str(), Result.size()); } if (RCDecl && ObjCSynthesizedStructs.count(RCDecl)) { Result = "\n struct "; @@ -3689,20 +3798,18 @@ std::string RewriteObjC::SynthesizeBlockHelperFuncs(BlockExpr *CE, int i, return S; } -std::string RewriteObjC::SynthesizeBlockImpl(BlockExpr *CE, std::string Tag, - bool hasCopyDisposeHelpers) { +std::string RewriteObjC::SynthesizeBlockImpl(BlockExpr *CE, std::string Tag, + std::string Desc) { std::string S = "\nstruct " + Tag; std::string Constructor = " " + Tag; S += " {\n struct __block_impl impl;\n"; + S += " struct " + Desc; + S += "* Desc;\n"; - if (hasCopyDisposeHelpers) - S += " void *copy;\n void *dispose;\n"; - - Constructor += "(void *fp"; - - if (hasCopyDisposeHelpers) - Constructor += ", void *copyHelp, void *disposeHelp"; + Constructor += "(void *fp, "; // Invoke function pointer. + Constructor += "struct " + Desc; // Descriptor pointer. + Constructor += " *desc"; if (BlockDeclRefs.size()) { // Output all "by copy" declarations. @@ -3765,11 +3872,9 @@ std::string RewriteObjC::SynthesizeBlockImpl(BlockExpr *CE, std::string Tag, Constructor += " impl.isa = &_NSConcreteGlobalBlock;\n"; else Constructor += " impl.isa = &_NSConcreteStackBlock;\n"; - Constructor += " impl.Size = sizeof("; - Constructor += Tag + ");\n impl.Flags = flags;\n impl.FuncPtr = fp;\n"; + Constructor += " impl.Flags = flags;\n impl.FuncPtr = fp;\n"; - if (hasCopyDisposeHelpers) - Constructor += " copy = copyHelp;\n dispose = disposeHelp;\n"; + Constructor += " Desc = desc;\n"; // Initialize all "by copy" arguments. for (llvm::SmallPtrSet::iterator I = BlockByCopyDecls.begin(), @@ -3800,10 +3905,8 @@ std::string RewriteObjC::SynthesizeBlockImpl(BlockExpr *CE, std::string Tag, Constructor += " impl.isa = &_NSConcreteGlobalBlock;\n"; else Constructor += " impl.isa = &_NSConcreteStackBlock;\n"; - Constructor += " impl.Size = sizeof("; - Constructor += Tag + ");\n impl.Flags = flags;\n impl.FuncPtr = fp;\n"; - if (hasCopyDisposeHelpers) - Constructor += " copy = copyHelp;\n dispose = disposeHelp;\n"; + Constructor += " impl.Flags = flags;\n impl.FuncPtr = fp;\n"; + Constructor += " Desc = desc;\n"; } Constructor += " "; Constructor += "}\n"; @@ -3812,6 +3915,29 @@ std::string RewriteObjC::SynthesizeBlockImpl(BlockExpr *CE, std::string Tag, return S; } +std::string RewriteObjC::SynthesizeBlockDescriptor(std::string DescTag, + std::string ImplTag, int i, + const char *FunName, + unsigned hasCopy) { + std::string S = "\nstatic struct " + DescTag; + + S += " {\n unsigned long reserved;\n"; + S += " unsigned long Block_size;\n"; + if (hasCopy) { + S += " void *copy;\n void *dispose;\n"; + } + S += "} "; + + S += DescTag + "_DATA = { 0, sizeof(struct "; + S += ImplTag + ")"; + if (hasCopy) { + S += ", __" + std::string(FunName) + "_block_copy_" + utostr(i); + S += ", __" + std::string(FunName) + "_block_dispose_" + utostr(i); + } + S += "};\n"; + return S; +} + void RewriteObjC::SynthesizeBlockLiterals(SourceLocation FunLocStart, const char *FunName) { // Insert closures that were part of the function. @@ -3819,21 +3945,24 @@ void RewriteObjC::SynthesizeBlockLiterals(SourceLocation FunLocStart, CollectBlockDeclRefInfo(Blocks[i]); - std::string Tag = "__" + std::string(FunName) + "_block_impl_" + utostr(i); + std::string ImplTag = "__" + std::string(FunName) + "_block_impl_" + utostr(i); + std::string DescTag = "__" + std::string(FunName) + "_block_desc_" + utostr(i); - std::string CI = SynthesizeBlockImpl(Blocks[i], Tag, - ImportedBlockDecls.size() > 0); + std::string CI = SynthesizeBlockImpl(Blocks[i], ImplTag, DescTag); InsertText(FunLocStart, CI.c_str(), CI.size()); - std::string CF = SynthesizeBlockFunc(Blocks[i], i, FunName, Tag); + std::string CF = SynthesizeBlockFunc(Blocks[i], i, FunName, ImplTag); InsertText(FunLocStart, CF.c_str(), CF.size()); if (ImportedBlockDecls.size()) { - std::string HF = SynthesizeBlockHelperFuncs(Blocks[i], i, FunName, Tag); + std::string HF = SynthesizeBlockHelperFuncs(Blocks[i], i, FunName, ImplTag); InsertText(FunLocStart, HF.c_str(), HF.size()); } + std::string BD = SynthesizeBlockDescriptor(DescTag, ImplTag, i, FunName, + ImportedBlockDecls.size() > 0); + InsertText(FunLocStart, BD.c_str(), BD.size()); BlockDeclRefs.clear(); BlockByRefDecls.clear(); @@ -4243,25 +4372,21 @@ Stmt *RewriteObjC::SynthBlockInitExpr(BlockExpr *Exp) { SourceLocation()); InitExprs.push_back(castExpr); - if (ImportedBlockDecls.size()) { - std::string Buf = "__" + FuncName + "_block_copy_" + BlockNumber; - FD = SynthBlockInitFunctionDecl(Buf.c_str()); - Arg = new (Context) DeclRefExpr(FD, FD->getType(), SourceLocation()); - castExpr = new (Context) CStyleCastExpr(Context->VoidPtrTy, - CastExpr::CK_Unknown, Arg, - Context->VoidPtrTy, SourceLocation(), - SourceLocation()); - InitExprs.push_back(castExpr); + // Initialize the block descriptor. + std::string DescData = "__" + FuncName + "_block_desc_" + BlockNumber + "_DATA"; - Buf = "__" + FuncName + "_block_dispose_" + BlockNumber; - FD = SynthBlockInitFunctionDecl(Buf.c_str()); - Arg = new (Context) DeclRefExpr(FD, FD->getType(), SourceLocation()); - castExpr = new (Context) CStyleCastExpr(Context->VoidPtrTy, - CastExpr::CK_Unknown, Arg, - Context->VoidPtrTy, SourceLocation(), - SourceLocation()); - InitExprs.push_back(castExpr); - } + VarDecl *NewVD = VarDecl::Create(*Context, TUDecl, SourceLocation(), + &Context->Idents.get(DescData.c_str()), + Context->VoidPtrTy, 0, + VarDecl::Static); + UnaryOperator *DescRefExpr = new (Context) UnaryOperator( + new (Context) DeclRefExpr(NewVD, + Context->VoidPtrTy, SourceLocation()), + UnaryOperator::AddrOf, + Context->getPointerType(Context->VoidPtrTy), + SourceLocation()); + InitExprs.push_back(DescRefExpr); + // Add initializers for any closure decl refs. if (BlockDeclRefs.size()) { Expr *Exp; @@ -4297,6 +4422,17 @@ Stmt *RewriteObjC::SynthBlockInitExpr(BlockExpr *Exp) { InitExprs.push_back(Exp); } } + if (ImportedBlockDecls.size()) { // generate "1<<25" to indicate we have helper functions. + unsigned IntSize = + static_cast(Context->getTypeSize(Context->IntTy)); + BinaryOperator *Exp = new (Context) BinaryOperator( + new (Context) IntegerLiteral(llvm::APInt(IntSize, 1), + Context->IntTy,SourceLocation()), + new (Context) IntegerLiteral(llvm::APInt(IntSize, 25), + Context->IntTy, SourceLocation()), + BinaryOperator::Shl, Context->IntTy, SourceLocation()); + InitExprs.push_back(Exp); + } NewRep = new (Context) CallExpr(*Context, DRE, &InitExprs[0], InitExprs.size(), FType, SourceLocation()); NewRep = new (Context) UnaryOperator(NewRep, UnaryOperator::AddrOf, @@ -4486,7 +4622,14 @@ Stmt *RewriteObjC::RewriteFunctionBodyOrGlobalInitializer(Stmt *S) { // FIXME: What we're doing here is modifying the type-specifier that // precedes the first Decl. In the future the DeclGroup should have // a separate type-specifier that we can rewrite. - RewriteObjCQualifiedInterfaceTypes(*DS->decl_begin()); + // NOTE: We need to avoid rewriting the DeclStmt if it is within + // the context of an ObjCForCollectionStmt. For example: + // NSArray *someArray; + // for (id index in someArray) ; + // This is because RewriteObjCForCollectionStmt() does textual rewriting + // and it depends on the original text locations/positions. + if (Stmts.empty() || !isa(Stmts.back())) + RewriteObjCQualifiedInterfaceTypes(*DS->decl_begin()); // Blocks rewrite rules. for (DeclStmt::decl_iterator DI = DS->decl_begin(), DE = DS->decl_end(); @@ -4552,6 +4695,18 @@ Stmt *RewriteObjC::RewriteFunctionBodyOrGlobalInitializer(Stmt *S) { return S; } +void RewriteObjC::RewriteRecordBody(RecordDecl *RD) { + for (RecordDecl::field_iterator i = RD->field_begin(), + e = RD->field_end(); i != e; ++i) { + FieldDecl *FD = *i; + if (isTopLevelBlockPointerType(FD->getType())) + RewriteBlockPointerDecl(FD); + if (FD->getType()->isObjCQualifiedIdType() || + FD->getType()->isObjCQualifiedInterfaceType()) + RewriteObjCQualifiedInterfaceTypes(FD); + } +} + /// HandleDeclInMainFile - This is called for each top-level decl defined in the /// main file of the input. void RewriteObjC::HandleDeclInMainFile(Decl *D) { @@ -4618,6 +4773,10 @@ void RewriteObjC::HandleDeclInMainFile(Decl *D) { RewriteCastExpr(CE); } } + } else if (VD->getType()->isRecordType()) { + RecordDecl *RD = VD->getType()->getAs()->getDecl(); + if (RD->isDefinition()) + RewriteRecordBody(RD); } if (VD->getInit()) { GlobalVarDecl = VD; @@ -4645,17 +4804,16 @@ void RewriteObjC::HandleDeclInMainFile(Decl *D) { RewriteBlockPointerDecl(TD); else if (TD->getUnderlyingType()->isFunctionPointerType()) CheckFunctionPointerDecl(TD->getUnderlyingType(), TD); + else if (TD->getUnderlyingType()->isRecordType()) { + RecordDecl *RD = TD->getUnderlyingType()->getAs()->getDecl(); + if (RD->isDefinition()) + RewriteRecordBody(RD); + } return; } if (RecordDecl *RD = dyn_cast(D)) { - if (RD->isDefinition()) { - for (RecordDecl::field_iterator i = RD->field_begin(), - e = RD->field_end(); i != e; ++i) { - FieldDecl *FD = *i; - if (isTopLevelBlockPointerType(FD->getType())) - RewriteBlockPointerDecl(FD); - } - } + if (RD->isDefinition()) + RewriteRecordBody(RD); return; } // Nothing yet. diff --git a/lib/Frontend/TextDiagnosticPrinter.cpp b/lib/Frontend/TextDiagnosticPrinter.cpp index 6ab0e1605276..61f8a70fffff 100644 --- a/lib/Frontend/TextDiagnosticPrinter.cpp +++ b/lib/Frontend/TextDiagnosticPrinter.cpp @@ -279,13 +279,14 @@ void TextDiagnosticPrinter::EmitCaretDiagnostic(SourceLocation Loc, assert(!Loc.isInvalid() && "must have a valid source location here"); // If this is a macro ID, first emit information about where this was - // instantiated (recursively) then emit information about where. the token was + // instantiated (recursively) then emit information about where the token was // spelled from. if (!Loc.isFileID()) { SourceLocation OneLevelUp = SM.getImmediateInstantiationRange(Loc).first; // FIXME: Map ranges? EmitCaretDiagnostic(OneLevelUp, Ranges, NumRanges, SM, 0, 0, Columns); + // Map the location. Loc = SM.getImmediateSpellingLoc(Loc); // Map the ranges. @@ -295,15 +296,22 @@ void TextDiagnosticPrinter::EmitCaretDiagnostic(SourceLocation Loc, if (E.isMacroID()) E = SM.getImmediateSpellingLoc(E); Ranges[i] = SourceRange(S, E); } + + // Get the pretty name, according to #line directives etc. + PresumedLoc PLoc = SM.getPresumedLoc(Loc); + + // If this diagnostic is not in the main file, print out the "included from" + // lines. + if (LastWarningLoc != PLoc.getIncludeLoc()) { + LastWarningLoc = PLoc.getIncludeLoc(); + PrintIncludeStack(LastWarningLoc, SM); + } if (DiagOpts->ShowLocation) { - std::pair IInfo = SM.getDecomposedInstantiationLoc(Loc); - // Emit the file/line/column that this expansion came from. - OS << SM.getBuffer(IInfo.first)->getBufferIdentifier() << ':' - << SM.getLineNumber(IInfo.first, IInfo.second) << ':'; + OS << PLoc.getFilename() << ':' << PLoc.getLine() << ':'; if (DiagOpts->ShowColumn) - OS << SM.getColumnNumber(IInfo.first, IInfo.second) << ':'; + OS << PLoc.getColumn() << ':'; OS << ' '; } OS << "note: instantiated from:\n"; @@ -489,12 +497,17 @@ static inline char findMatchingPunctuation(char c) { /// /// \returns the index pointing one character past the end of the /// word. -unsigned findEndOfWord(unsigned Start, - const llvm::SmallVectorImpl &Str, - unsigned Length, unsigned Column, - unsigned Columns) { +static unsigned findEndOfWord(unsigned Start, + const llvm::SmallVectorImpl &Str, + unsigned Length, unsigned Column, + unsigned Columns) { + assert(Start < Str.size() && "Invalid start position!"); unsigned End = Start + 1; + // If we are already at the end of the string, take that as the word. + if (End == Str.size()) + return End; + // Determine if the start of the string is actually opening // punctuation, e.g., a quote or parentheses. char EndPunct = findMatchingPunctuation(Str[Start]); @@ -645,11 +658,17 @@ void TextDiagnosticPrinter::HandleDiagnostic(Diagnostic::Level Level, if (DiagOpts->ShowLocation) { if (DiagOpts->ShowColors) OS.changeColor(savedColor, true); - OS << PLoc.getFilename() << ':' << LineNo << ':'; - if (DiagOpts->ShowColumn) - if (unsigned ColNo = PLoc.getColumn()) - OS << ColNo << ':'; - + + // Emit a Visual Studio compatible line number syntax. + if (LangOpts && LangOpts->Microsoft) { + OS << PLoc.getFilename() << '(' << LineNo << ')'; + OS << " : "; + } else { + OS << PLoc.getFilename() << ':' << LineNo << ':'; + if (DiagOpts->ShowColumn) + if (unsigned ColNo = PLoc.getColumn()) + OS << ColNo << ':'; + } if (DiagOpts->ShowSourceRanges && Info.getNumRanges()) { FileID CaretFileID = SM.getFileID(SM.getInstantiationLoc(Info.getLocation())); diff --git a/lib/Headers/limits.h b/lib/Headers/limits.h index e4909ab034e6..26275337d583 100644 --- a/lib/Headers/limits.h +++ b/lib/Headers/limits.h @@ -49,7 +49,6 @@ #undef LONG_MAX #undef ULONG_MAX -#undef MB_LEN_MAX #undef CHAR_BIT #undef CHAR_MIN #undef CHAR_MAX diff --git a/lib/Headers/tmmintrin.h b/lib/Headers/tmmintrin.h index 374a27ecd77b..7adb776fef76 100644 --- a/lib/Headers/tmmintrin.h +++ b/lib/Headers/tmmintrin.h @@ -67,7 +67,7 @@ _mm_abs_epi32(__m128i a) } #define _mm_alignr_epi8(a, b, n) (__builtin_ia32_palignr128((a), (b), (n))) -#define _mm_alignr_pi8(a, b, n) (__builtin_ia32_palignr((a), (b), (n))) +#define _mm_alignr_pi8(a, b, n) (__builtin_ia32_palignr((a), (b), (n*8))) static inline __m128i __attribute__((__always_inline__, __nodebug__)) _mm_hadd_epi16(__m128i a, __m128i b) diff --git a/lib/Index/ASTVisitor.h b/lib/Index/ASTVisitor.h index 0ae78fb74ff4..943c72025312 100644 --- a/lib/Index/ASTVisitor.h +++ b/lib/Index/ASTVisitor.h @@ -52,8 +52,8 @@ class ASTVisitor : public DeclVisitor, void VisitDeclaratorDecl(DeclaratorDecl *D) { BaseDeclVisitor::VisitDeclaratorDecl(D); - if (DeclaratorInfo *DInfo = D->getDeclaratorInfo()) - Visit(DInfo->getTypeLoc()); + if (TypeSourceInfo *TInfo = D->getTypeSourceInfo()) + Visit(TInfo->getTypeLoc()); } void VisitFunctionDecl(FunctionDecl *D) { @@ -104,7 +104,7 @@ class ASTVisitor : public DeclVisitor, } void VisitBlockExpr(BlockExpr *Node) { - Visit(Node->getBlockDecl()); + // The BlockDecl is also visited by 'VisitDeclContext()'. No need to visit it twice. } void VisitStmt(Stmt *Node) { diff --git a/lib/Index/CMakeLists.txt b/lib/Index/CMakeLists.txt index 5f818175ca5d..4d6703563613 100644 --- a/lib/Index/CMakeLists.txt +++ b/lib/Index/CMakeLists.txt @@ -3,6 +3,7 @@ set(LLVM_NO_RTTI 1) add_clang_library(clangIndex ASTLocation.cpp Analyzer.cpp + CallGraph.cpp DeclReferenceMap.cpp Entity.cpp GlobalSelector.cpp diff --git a/lib/Analysis/CallGraph.cpp b/lib/Index/CallGraph.cpp similarity index 99% rename from lib/Analysis/CallGraph.cpp rename to lib/Index/CallGraph.cpp index c1040f0c9949..6403319de1f0 100644 --- a/lib/Analysis/CallGraph.cpp +++ b/lib/Index/CallGraph.cpp @@ -11,7 +11,7 @@ // //===----------------------------------------------------------------------===// -#include "clang/Analysis/CallGraph.h" +#include "clang/Index/CallGraph.h" #include "clang/AST/ASTContext.h" #include "clang/AST/StmtVisitor.h" diff --git a/lib/Index/ResolveLocation.cpp b/lib/Index/ResolveLocation.cpp index c7379f7a8352..81a5de44bf56 100644 --- a/lib/Index/ResolveLocation.cpp +++ b/lib/Index/ResolveLocation.cpp @@ -30,7 +30,7 @@ class LocResolverBase { ASTContext &Ctx; SourceLocation Loc; - ASTLocation ResolveInDeclarator(Decl *D, Stmt *Stm, DeclaratorInfo *DInfo); + ASTLocation ResolveInDeclarator(Decl *D, Stmt *Stm, TypeSourceInfo *TInfo); enum RangePos { BeforeLoc, @@ -39,13 +39,13 @@ class LocResolverBase { }; RangePos CheckRange(SourceRange Range); - RangePos CheckRange(DeclaratorInfo *DInfo); + RangePos CheckRange(TypeSourceInfo *TInfo); RangePos CheckRange(Decl *D) { if (DeclaratorDecl *DD = dyn_cast(D)) - if (ContainsLocation(DD->getDeclaratorInfo())) + if (ContainsLocation(DD->getTypeSourceInfo())) return ContainsLoc; if (TypedefDecl *TD = dyn_cast(D)) - if (ContainsLocation(TD->getTypeDeclaratorInfo())) + if (ContainsLocation(TD->getTypeSourceInfo())) return ContainsLoc; return CheckRange(D->getSourceRange()); @@ -142,9 +142,9 @@ StmtLocResolver::VisitSizeOfAlignOfExpr(SizeOfAlignOfExpr *Node) { "Should visit only after verifying that loc is in range"); if (Node->isArgumentType()) { - DeclaratorInfo *DInfo = Node->getArgumentTypeInfo(); - if (ContainsLocation(DInfo)) - return ResolveInDeclarator(Parent, Node, DInfo); + TypeSourceInfo *TInfo = Node->getArgumentTypeInfo(); + if (ContainsLocation(TInfo)) + return ResolveInDeclarator(Parent, Node, TInfo); } else { Expr *SubNode = Node->getArgumentExpr(); if (ContainsLocation(SubNode)) @@ -245,8 +245,8 @@ ASTLocation DeclLocResolver::VisitFunctionDecl(FunctionDecl *D) { assert(ContainsLocation(D) && "Should visit only after verifying that loc is in range"); - if (ContainsLocation(D->getDeclaratorInfo())) - return ResolveInDeclarator(D, 0, D->getDeclaratorInfo()); + if (ContainsLocation(D->getTypeSourceInfo())) + return ResolveInDeclarator(D, 0, D->getTypeSourceInfo()); // First, search through the parameters of the function. for (FunctionDecl::param_iterator @@ -296,8 +296,8 @@ ASTLocation DeclLocResolver::VisitFunctionDecl(FunctionDecl *D) { ASTLocation DeclLocResolver::VisitDeclaratorDecl(DeclaratorDecl *D) { assert(ContainsLocation(D) && "Should visit only after verifying that loc is in range"); - if (ContainsLocation(D->getDeclaratorInfo())) - return ResolveInDeclarator(D, /*Stmt=*/0, D->getDeclaratorInfo()); + if (ContainsLocation(D->getTypeSourceInfo())) + return ResolveInDeclarator(D, /*Stmt=*/0, D->getTypeSourceInfo()); return ASTLocation(D); } @@ -306,8 +306,8 @@ ASTLocation DeclLocResolver::VisitTypedefDecl(TypedefDecl *D) { assert(ContainsLocation(D) && "Should visit only after verifying that loc is in range"); - if (ContainsLocation(D->getTypeDeclaratorInfo())) - return ResolveInDeclarator(D, /*Stmt=*/0, D->getTypeDeclaratorInfo()); + if (ContainsLocation(D->getTypeSourceInfo())) + return ResolveInDeclarator(D, /*Stmt=*/0, D->getTypeSourceInfo()); return ASTLocation(D); } @@ -321,8 +321,8 @@ ASTLocation DeclLocResolver::VisitVarDecl(VarDecl *D) { if (Init && ContainsLocation(Init)) return StmtLocResolver(Ctx, Loc, D).Visit(Init); - if (ContainsLocation(D->getDeclaratorInfo())) - return ResolveInDeclarator(D, 0, D->getDeclaratorInfo()); + if (ContainsLocation(D->getTypeSourceInfo())) + return ResolveInDeclarator(D, 0, D->getTypeSourceInfo()); return ASTLocation(D); } @@ -491,12 +491,12 @@ ASTLocation TypeLocResolver::VisitTypeLoc(TypeLoc TL) { } ASTLocation LocResolverBase::ResolveInDeclarator(Decl *D, Stmt *Stm, - DeclaratorInfo *DInfo) { - assert(ContainsLocation(DInfo) && + TypeSourceInfo *TInfo) { + assert(ContainsLocation(TInfo) && "Should visit only after verifying that loc is in range"); (void)TypeLocResolver(Ctx, Loc, D); - for (TypeLoc TL = DInfo->getTypeLoc(); TL; TL = TL.getNextTypeLoc()) + for (TypeLoc TL = TInfo->getTypeLoc(); TL; TL = TL.getNextTypeLoc()) if (ContainsLocation(TL)) return TypeLocResolver(Ctx, Loc, D).Visit(TL); @@ -504,11 +504,11 @@ ASTLocation LocResolverBase::ResolveInDeclarator(Decl *D, Stmt *Stm, return ASTLocation(D, Stm); } -LocResolverBase::RangePos LocResolverBase::CheckRange(DeclaratorInfo *DInfo) { - if (!DInfo) +LocResolverBase::RangePos LocResolverBase::CheckRange(TypeSourceInfo *TInfo) { + if (!TInfo) return BeforeLoc; // Keep looking. - for (TypeLoc TL = DInfo->getTypeLoc(); TL; TL = TL.getNextTypeLoc()) + for (TypeLoc TL = TInfo->getTypeLoc(); TL; TL = TL.getNextTypeLoc()) if (ContainsLocation(TL)) return ContainsLoc; diff --git a/lib/Lex/Lexer.cpp b/lib/Lex/Lexer.cpp index 52a7a04567a6..a91e40435cb0 100644 --- a/lib/Lex/Lexer.cpp +++ b/lib/Lex/Lexer.cpp @@ -33,7 +33,7 @@ #include using namespace clang; -static void InitCharacterInfo(); +static void InitCharacterInfo(LangOptions); //===----------------------------------------------------------------------===// // Token Class Implementation @@ -59,7 +59,7 @@ tok::ObjCKeywordKind Token::getObjCKeywordID() const { void Lexer::InitLexer(const char *BufStart, const char *BufPtr, const char *BufEnd) { - InitCharacterInfo(); + InitCharacterInfo(Features); BufferStart = BufStart; BufferPtr = BufPtr; @@ -70,7 +70,7 @@ void Lexer::InitLexer(const char *BufStart, const char *BufPtr, " to simplify lexing!"); Is_PragmaLexer = false; - IsEofCodeCompletion = false; + IsInConflictMarker = false; // Start of the file is a start of line. IsAtStartOfLine = true; @@ -105,10 +105,6 @@ Lexer::Lexer(FileID FID, const llvm::MemoryBuffer *InputFile, Preprocessor &PP) // Default to keeping comments if the preprocessor wants them. SetCommentRetentionState(PP.getCommentRetentionState()); - - // If the input file is truncated, the EOF is a code-completion token. - if (PP.getSourceManager().isTruncatedFile(FID)) - IsEofCodeCompletion = true; } /// Lexer constructor - Create a new raw lexer object. This object is only @@ -258,7 +254,7 @@ enum { // Statically initialize CharInfo table based on ASCII character set // Reference: FreeBSD 7.2 /usr/share/misc/ascii -static const unsigned char CharInfo[256] = +static unsigned char CharInfo[256] = { // 0 NUL 1 SOH 2 STX 3 ETX // 4 EOT 5 ENQ 6 ACK 7 BEL @@ -326,7 +322,7 @@ static const unsigned char CharInfo[256] = 0 , 0 , 0 , 0 }; -static void InitCharacterInfo() { +static void InitCharacterInfo(LangOptions Features) { static bool isInited = false; if (isInited) return; // check the statically-initialized CharInfo table @@ -344,6 +340,11 @@ static void InitCharacterInfo() { } for (unsigned i = '0'; i <= '9'; ++i) assert(CHAR_NUMBER == CharInfo[i]); + + if (Features.Microsoft) + // Hack to treat DOS & CP/M EOF (^Z) as horizontal whitespace. + CharInfo[26/*sub*/] = CHAR_HORZ_WS; + isInited = true; } @@ -1326,24 +1327,16 @@ bool Lexer::LexEndOfFile(Token &Result, const char *CurPtr) { // Otherwise, check if we are code-completing, then issue diagnostics for // unterminated #if and missing newline. - if (IsEofCodeCompletion) { - bool isIntendedFile = true; - if (PP && FileLoc.isFileID()) { - SourceManager &SM = PP->getSourceManager(); - isIntendedFile = SM.isTruncatedFile(SM.getFileID(FileLoc)); - } + if (PP && PP->isCodeCompletionFile(FileLoc)) { + // We're at the end of the file, but we've been asked to consider the + // end of the file to be a code-completion token. Return the + // code-completion token. + Result.startToken(); + FormTokenWithChars(Result, CurPtr, tok::code_completion); - if (isIntendedFile) { - // We're at the end of the file, but we've been asked to consider the - // end of the file to be a code-completion token. Return the - // code-completion token. - Result.startToken(); - FormTokenWithChars(Result, CurPtr, tok::code_completion); - - // Only do the eof -> code_completion translation once. - IsEofCodeCompletion = false; - return true; - } + // Only do the eof -> code_completion translation once. + PP->SetCodeCompletionPoint(0, 0, 0); + return true; } // If we are in a #if directive, emit an error. @@ -1398,6 +1391,105 @@ unsigned Lexer::isNextPPTokenLParen() { return Tok.is(tok::l_paren); } +/// FindConflictEnd - Find the end of a version control conflict marker. +static const char *FindConflictEnd(const char *CurPtr, const char *BufferEnd) { + llvm::StringRef RestOfBuffer(CurPtr+7, BufferEnd-CurPtr-7); + size_t Pos = RestOfBuffer.find(">>>>>>>"); + while (Pos != llvm::StringRef::npos) { + // Must occur at start of line. + if (RestOfBuffer[Pos-1] != '\r' && + RestOfBuffer[Pos-1] != '\n') { + RestOfBuffer = RestOfBuffer.substr(Pos+7); + continue; + } + return RestOfBuffer.data()+Pos; + } + return 0; +} + +/// IsStartOfConflictMarker - If the specified pointer is the start of a version +/// control conflict marker like '<<<<<<<', recognize it as such, emit an error +/// and recover nicely. This returns true if it is a conflict marker and false +/// if not. +bool Lexer::IsStartOfConflictMarker(const char *CurPtr) { + // Only a conflict marker if it starts at the beginning of a line. + if (CurPtr != BufferStart && + CurPtr[-1] != '\n' && CurPtr[-1] != '\r') + return false; + + // Check to see if we have <<<<<<<. + if (BufferEnd-CurPtr < 8 || + llvm::StringRef(CurPtr, 7) != "<<<<<<<") + return false; + + // If we have a situation where we don't care about conflict markers, ignore + // it. + if (IsInConflictMarker || isLexingRawMode()) + return false; + + // Check to see if there is a >>>>>>> somewhere in the buffer at the start of + // a line to terminate this conflict marker. + if (FindConflictEnd(CurPtr+7, BufferEnd)) { + // We found a match. We are really in a conflict marker. + // Diagnose this, and ignore to the end of line. + Diag(CurPtr, diag::err_conflict_marker); + IsInConflictMarker = true; + + // Skip ahead to the end of line. We know this exists because the + // end-of-conflict marker starts with \r or \n. + while (*CurPtr != '\r' && *CurPtr != '\n') { + assert(CurPtr != BufferEnd && "Didn't find end of line"); + ++CurPtr; + } + BufferPtr = CurPtr; + return true; + } + + // No end of conflict marker found. + return false; +} + + +/// HandleEndOfConflictMarker - If this is a '=======' or '|||||||' or '>>>>>>>' +/// marker, then it is the end of a conflict marker. Handle it by ignoring up +/// until the end of the line. This returns true if it is a conflict marker and +/// false if not. +bool Lexer::HandleEndOfConflictMarker(const char *CurPtr) { + // Only a conflict marker if it starts at the beginning of a line. + if (CurPtr != BufferStart && + CurPtr[-1] != '\n' && CurPtr[-1] != '\r') + return false; + + // If we have a situation where we don't care about conflict markers, ignore + // it. + if (!IsInConflictMarker || isLexingRawMode()) + return false; + + // Check to see if we have the marker (7 characters in a row). + for (unsigned i = 1; i != 7; ++i) + if (CurPtr[i] != CurPtr[0]) + return false; + + // If we do have it, search for the end of the conflict marker. This could + // fail if it got skipped with a '#if 0' or something. Note that CurPtr might + // be the end of conflict marker. + if (const char *End = FindConflictEnd(CurPtr, BufferEnd)) { + CurPtr = End; + + // Skip ahead to the end of line. + while (CurPtr != BufferEnd && *CurPtr != '\r' && *CurPtr != '\n') + ++CurPtr; + + BufferPtr = CurPtr; + + // No longer in the conflict marker. + IsInConflictMarker = false; + return true; + } + + return false; +} + /// LexTokenInternal - This implements a simple C family lexer. It is an /// extremely performance critical piece of code. This assumes that the buffer @@ -1764,14 +1856,20 @@ void Lexer::LexTokenInternal(Token &Result) { Char = getCharAndSize(CurPtr, SizeTmp); if (ParsingFilename) { return LexAngledStringLiteral(Result, CurPtr); - } else if (Char == '<' && - getCharAndSize(CurPtr+SizeTmp, SizeTmp2) == '=') { - Kind = tok::lesslessequal; - CurPtr = ConsumeChar(ConsumeChar(CurPtr, SizeTmp, Result), - SizeTmp2, Result); } else if (Char == '<') { - CurPtr = ConsumeChar(CurPtr, SizeTmp, Result); - Kind = tok::lessless; + char After = getCharAndSize(CurPtr+SizeTmp, SizeTmp2); + if (After == '=') { + Kind = tok::lesslessequal; + CurPtr = ConsumeChar(ConsumeChar(CurPtr, SizeTmp, Result), + SizeTmp2, Result); + } else if (After == '<' && IsStartOfConflictMarker(CurPtr-1)) { + // If this is actually a '<<<<<<<' version control conflict marker, + // recognize it as such and recover nicely. + goto LexNextToken; + } else { + CurPtr = ConsumeChar(CurPtr, SizeTmp, Result); + Kind = tok::lessless; + } } else if (Char == '=') { CurPtr = ConsumeChar(CurPtr, SizeTmp, Result); Kind = tok::lessequal; @@ -1790,14 +1888,20 @@ void Lexer::LexTokenInternal(Token &Result) { if (Char == '=') { CurPtr = ConsumeChar(CurPtr, SizeTmp, Result); Kind = tok::greaterequal; - } else if (Char == '>' && - getCharAndSize(CurPtr+SizeTmp, SizeTmp2) == '=') { - CurPtr = ConsumeChar(ConsumeChar(CurPtr, SizeTmp, Result), - SizeTmp2, Result); - Kind = tok::greatergreaterequal; } else if (Char == '>') { - CurPtr = ConsumeChar(CurPtr, SizeTmp, Result); - Kind = tok::greatergreater; + char After = getCharAndSize(CurPtr+SizeTmp, SizeTmp2); + if (After == '=') { + CurPtr = ConsumeChar(ConsumeChar(CurPtr, SizeTmp, Result), + SizeTmp2, Result); + Kind = tok::greatergreaterequal; + } else if (After == '>' && HandleEndOfConflictMarker(CurPtr-1)) { + // If this is '>>>>>>>' and we're in a conflict marker, ignore it. + goto LexNextToken; + } else { + CurPtr = ConsumeChar(CurPtr, SizeTmp, Result); + Kind = tok::greatergreater; + } + } else { Kind = tok::greater; } @@ -1817,6 +1921,9 @@ void Lexer::LexTokenInternal(Token &Result) { Kind = tok::pipeequal; CurPtr = ConsumeChar(CurPtr, SizeTmp, Result); } else if (Char == '|') { + // If this is '|||||||' and we're in a conflict marker, ignore it. + if (CurPtr[1] == '|' && HandleEndOfConflictMarker(CurPtr-1)) + goto LexNextToken; Kind = tok::pipepipe; CurPtr = ConsumeChar(CurPtr, SizeTmp, Result); } else { @@ -1841,6 +1948,10 @@ void Lexer::LexTokenInternal(Token &Result) { case '=': Char = getCharAndSize(CurPtr, SizeTmp); if (Char == '=') { + // If this is '=======' and we're in a conflict marker, ignore it. + if (CurPtr[1] == '=' && HandleEndOfConflictMarker(CurPtr-1)) + goto LexNextToken; + Kind = tok::equalequal; CurPtr = ConsumeChar(CurPtr, SizeTmp, Result); } else { diff --git a/lib/Lex/MacroArgs.cpp b/lib/Lex/MacroArgs.cpp index c14d7c438d60..376cce8eb321 100644 --- a/lib/Lex/MacroArgs.cpp +++ b/lib/Lex/MacroArgs.cpp @@ -20,7 +20,8 @@ using namespace clang; /// MacroArgs ctor function - This destroys the vector passed in. MacroArgs *MacroArgs::create(const MacroInfo *MI, const Token *UnexpArgTokens, - unsigned NumToks, bool VarargsElided) { + unsigned NumToks, bool VarargsElided, + Preprocessor &PP) { assert(MI->isFunctionLike() && "Can't have args for an object-like macro!"); @@ -40,13 +41,26 @@ MacroArgs *MacroArgs::create(const MacroInfo *MI, /// destroy - Destroy and deallocate the memory for this object. /// -void MacroArgs::destroy() { +void MacroArgs::destroy(Preprocessor &PP) { // Run the dtor to deallocate the vectors. this->~MacroArgs(); // Release the memory for the object. free(this); } +/// deallocate - This should only be called by the Preprocessor when managing +/// its freelist. +MacroArgs *MacroArgs::deallocate() { + MacroArgs *Next = ArgCache; + + // Run the dtor to deallocate the vectors. + this->~MacroArgs(); + // Release the memory for the object. + free(this); + + return Next; +} + /// getArgLength - Given a pointer to an expanded or unexpanded argument, /// return the number of tokens, not counting the EOF, that make up the diff --git a/lib/Lex/MacroArgs.h b/lib/Lex/MacroArgs.h index 8dee5b3bc997..fa040c7a4d6f 100644 --- a/lib/Lex/MacroArgs.h +++ b/lib/Lex/MacroArgs.h @@ -30,6 +30,13 @@ class MacroArgs { /// concatenated together, with 'EOF' markers at the end of each argument. unsigned NumUnexpArgTokens; + /// VarargsElided - True if this is a C99 style varargs macro invocation and + /// there was no argument specified for the "..." argument. If the argument + /// was specified (even empty) or this isn't a C99 style varargs function, or + /// if in strict mode and the C99 varargs macro had only a ... argument, this + /// is false. + bool VarargsElided; + /// PreExpArgTokens - Pre-expanded tokens for arguments that need them. Empty /// if not yet computed. This includes the EOF marker at the end of the /// stream. @@ -39,26 +46,24 @@ class MacroArgs { /// stringified form of an argument has not yet been computed, this is empty. std::vector StringifiedArgs; - /// VarargsElided - True if this is a C99 style varargs macro invocation and - /// there was no argument specified for the "..." argument. If the argument - /// was specified (even empty) or this isn't a C99 style varargs function, or - /// if in strict mode and the C99 varargs macro had only a ... argument, this - /// is false. - bool VarargsElided; - + /// ArgCache - This is a linked list of MacroArgs objects that the + /// Preprocessor owns which we use to avoid thrashing malloc/free. + MacroArgs *ArgCache; + MacroArgs(unsigned NumToks, bool varargsElided) - : NumUnexpArgTokens(NumToks), VarargsElided(varargsElided) {} + : NumUnexpArgTokens(NumToks), VarargsElided(varargsElided), ArgCache(0) {} ~MacroArgs() {} public: /// MacroArgs ctor function - Create a new MacroArgs object with the specified /// macro and argument info. static MacroArgs *create(const MacroInfo *MI, const Token *UnexpArgTokens, - unsigned NumArgTokens, bool VarargsElided); + unsigned NumArgTokens, bool VarargsElided, + Preprocessor &PP); /// destroy - Destroy and deallocate the memory for this object. /// - void destroy(); + void destroy(Preprocessor &PP); /// ArgNeedsPreexpansion - If we can prove that the argument won't be affected /// by pre-expansion, return false. Otherwise, conservatively return true. @@ -102,6 +107,11 @@ class MacroArgs { /// static Token StringifyArgument(const Token *ArgToks, Preprocessor &PP, bool Charify = false); + + + /// deallocate - This should only be called by the Preprocessor when managing + /// its freelist. + MacroArgs *deallocate(); }; } // end namespace clang diff --git a/lib/Lex/PPDirectives.cpp b/lib/Lex/PPDirectives.cpp index 9caca339be32..f5c60eb49438 100644 --- a/lib/Lex/PPDirectives.cpp +++ b/lib/Lex/PPDirectives.cpp @@ -481,11 +481,11 @@ void Preprocessor::HandleDirective(Token &Result) { CurPPLexer->ParsingPreprocessorDirective = true; ++NumDirectives; - + // We are about to read a token. For the multiple-include optimization FA to // work, we have to remember if we had read any tokens *before* this // pp-directive. - bool ReadAnyTokensBeforeDirective = CurPPLexer->MIOpt.getHasReadAnyTokensVal(); + bool ReadAnyTokensBeforeDirective =CurPPLexer->MIOpt.getHasReadAnyTokensVal(); // Save the '#' token in case we need to return it later. Token SavedHash = Result; @@ -1112,9 +1112,10 @@ void Preprocessor::HandleIncludeDirective(Token &IncludeTok, } // Finally, if all is good, enter the new file! - if (EnterSourceFile(FID, CurDir)) + std::string ErrorStr; + if (EnterSourceFile(FID, CurDir, ErrorStr)) Diag(FilenameTok, diag::err_pp_error_opening_file) - << std::string(SourceMgr.getFileEntryForID(FID)->getName()); + << std::string(SourceMgr.getFileEntryForID(FID)->getName()) << ErrorStr; } /// HandleIncludeNextDirective - Implements #include_next. @@ -1548,8 +1549,9 @@ void Preprocessor::HandleIfdefDirective(Token &Result, bool isIfndef, // Should we include the stuff contained by this directive? if (!MI == isIfndef) { // Yes, remember that we are inside a conditional, then lex the next token. - CurPPLexer->pushConditionalLevel(DirectiveTok.getLocation(), /*wasskip*/false, - /*foundnonskip*/true, /*foundelse*/false); + CurPPLexer->pushConditionalLevel(DirectiveTok.getLocation(), + /*wasskip*/false, /*foundnonskip*/true, + /*foundelse*/false); } else { // No, skip the contents of this block and return the first token after it. SkipExcludedConditionalBlock(DirectiveTok.getLocation(), diff --git a/lib/Lex/PPExpressions.cpp b/lib/Lex/PPExpressions.cpp index b54dfe093b2c..2a6b2a729417 100644 --- a/lib/Lex/PPExpressions.cpp +++ b/lib/Lex/PPExpressions.cpp @@ -72,8 +72,8 @@ struct DefinedTracker { }; /// EvaluateDefined - Process a 'defined(sym)' expression. -static bool EvaluateDefined(PPValue &Result, Token &PeekTok, - DefinedTracker &DT, bool ValueLive, Preprocessor &PP) { +static bool EvaluateDefined(PPValue &Result, Token &PeekTok, DefinedTracker &DT, + bool ValueLive, Preprocessor &PP) { IdentifierInfo *II; Result.setBegin(PeekTok.getLocation()); @@ -142,22 +142,21 @@ static bool EvaluateValue(PPValue &Result, Token &PeekTok, DefinedTracker &DT, // 'defined' or if it is a macro. Note that we check here because many // keywords are pp-identifiers, so we can't check the kind. if (IdentifierInfo *II = PeekTok.getIdentifierInfo()) { - if (II->isStr("defined")) { - // Handle "defined X" and "defined(X)". + // Handle "defined X" and "defined(X)". + if (II->isStr("defined")) return(EvaluateDefined(Result, PeekTok, DT, ValueLive, PP)); - } else { - // If this identifier isn't 'defined' or one of the special - // preprocessor keywords and it wasn't macro expanded, it turns - // into a simple 0, unless it is the C++ keyword "true", in which case it - // turns into "1". - if (ValueLive) - PP.Diag(PeekTok, diag::warn_pp_undef_identifier) << II; - Result.Val = II->getTokenID() == tok::kw_true; - Result.Val.setIsUnsigned(false); // "0" is signed intmax_t 0. - Result.setRange(PeekTok.getLocation()); - PP.LexNonComment(PeekTok); - return false; - } + + // If this identifier isn't 'defined' or one of the special + // preprocessor keywords and it wasn't macro expanded, it turns + // into a simple 0, unless it is the C++ keyword "true", in which case it + // turns into "1". + if (ValueLive) + PP.Diag(PeekTok, diag::warn_pp_undef_identifier) << II; + Result.Val = II->getTokenID() == tok::kw_true; + Result.Val.setIsUnsigned(false); // "0" is signed intmax_t 0. + Result.setRange(PeekTok.getLocation()); + PP.LexNonComment(PeekTok); + return false; } switch (PeekTok.getKind()) { @@ -677,6 +676,15 @@ static bool EvaluateDirectiveSubExpr(PPValue &LHS, unsigned MinPrec, /// to "!defined(X)" return X in IfNDefMacro. bool Preprocessor:: EvaluateDirectiveExpression(IdentifierInfo *&IfNDefMacro) { + // Save the current state of 'DisableMacroExpansion' and reset it to false. If + // 'DisableMacroExpansion' is true, then we must be in a macro argument list + // in which case a directive is undefined behavior. We want macros to be able + // to recursively expand in order to get more gcc-list behavior, so we force + // DisableMacroExpansion to false and restore it when we're done parsing the + // expression. + bool DisableMacroExpansionAtStartOfDirective = DisableMacroExpansion; + DisableMacroExpansion = false; + // Peek ahead one token. Token Tok; Lex(Tok); @@ -690,6 +698,9 @@ EvaluateDirectiveExpression(IdentifierInfo *&IfNDefMacro) { // Parse error, skip the rest of the macro line. if (Tok.isNot(tok::eom)) DiscardUntilEndOfDirective(); + + // Restore 'DisableMacroExpansion'. + DisableMacroExpansion = DisableMacroExpansionAtStartOfDirective; return false; } @@ -702,6 +713,8 @@ EvaluateDirectiveExpression(IdentifierInfo *&IfNDefMacro) { if (DT.State == DefinedTracker::NotDefinedMacro) IfNDefMacro = DT.TheMacro; + // Restore 'DisableMacroExpansion'. + DisableMacroExpansion = DisableMacroExpansionAtStartOfDirective; return ResVal.Val != 0; } @@ -712,6 +725,9 @@ EvaluateDirectiveExpression(IdentifierInfo *&IfNDefMacro) { // Parse error, skip the rest of the macro line. if (Tok.isNot(tok::eom)) DiscardUntilEndOfDirective(); + + // Restore 'DisableMacroExpansion'. + DisableMacroExpansion = DisableMacroExpansionAtStartOfDirective; return false; } @@ -722,6 +738,8 @@ EvaluateDirectiveExpression(IdentifierInfo *&IfNDefMacro) { DiscardUntilEndOfDirective(); } + // Restore 'DisableMacroExpansion'. + DisableMacroExpansion = DisableMacroExpansionAtStartOfDirective; return ResVal.Val != 0; } diff --git a/lib/Lex/PPLexerChange.cpp b/lib/Lex/PPLexerChange.cpp index 8a61d7b9c247..ce1b19ca7c10 100644 --- a/lib/Lex/PPLexerChange.cpp +++ b/lib/Lex/PPLexerChange.cpp @@ -64,7 +64,8 @@ PreprocessorLexer *Preprocessor::getCurrentFileLexer() const { /// EnterSourceFile - Add a source file to the top of the include stack and /// start lexing tokens from it instead of the current buffer. -bool Preprocessor::EnterSourceFile(FileID FID, const DirectoryLookup *CurDir) { +bool Preprocessor::EnterSourceFile(FileID FID, const DirectoryLookup *CurDir, + std::string &ErrorStr) { assert(CurTokenLexer == 0 && "Cannot #include a file inside a macro!"); ++NumEnteredSourceFiles; @@ -79,8 +80,9 @@ bool Preprocessor::EnterSourceFile(FileID FID, const DirectoryLookup *CurDir) { } // Get the MemoryBuffer for this FID, if it fails, we fail. - const llvm::MemoryBuffer *InputFile = getSourceManager().getBuffer(FID); - if (InputFile == 0) + const llvm::MemoryBuffer *InputFile = + getSourceManager().getBuffer(FID, &ErrorStr); + if (!ErrorStr.empty()) return true; EnterSourceFileWithLexer(new Lexer(FID, InputFile, *this), CurDir); diff --git a/lib/Lex/PPMacroExpansion.cpp b/lib/Lex/PPMacroExpansion.cpp index 699b701ea870..dfb14ff06f1f 100644 --- a/lib/Lex/PPMacroExpansion.cpp +++ b/lib/Lex/PPMacroExpansion.cpp @@ -204,7 +204,7 @@ bool Preprocessor::HandleMacroExpandedIdentifier(Token &Identifier, // expansion stack, only to take it right back off. if (MI->getNumTokens() == 0) { // No need for arg info. - if (Args) Args->destroy(); + if (Args) Args->destroy(*this); // Ignore this macro use, just return the next token in the current // buffer. @@ -232,7 +232,7 @@ bool Preprocessor::HandleMacroExpandedIdentifier(Token &Identifier, // "#define VAL 42". // No need for arg info. - if (Args) Args->destroy(); + if (Args) Args->destroy(*this); // Propagate the isAtStartOfLine/hasLeadingSpace markers of the macro // identifier to the expanded token. @@ -446,7 +446,7 @@ MacroArgs *Preprocessor::ReadFunctionLikeMacroArgs(Token &MacroName, } return MacroArgs::create(MI, ArgTokens.data(), ArgTokens.size(), - isVarargsElided); + isVarargsElided, *this); } /// ComputeDATE_TIME - Compute the current time, enter it into the specified @@ -486,6 +486,12 @@ static bool HasFeature(const Preprocessor &PP, const IdentifierInfo *II) { case 6: if (II->isStr("blocks")) return LangOpts.Blocks; return false; + case 8: + if (II->isStr("cxx_rtti")) return LangOpts.RTTI; + return false; + case 14: + if (II->isStr("cxx_exceptions")) return LangOpts.Exceptions; + return false; case 19: if (II->isStr("objc_nonfragile_abi")) return LangOpts.ObjCNonFragileABI; return false; @@ -667,7 +673,6 @@ void Preprocessor::ExpandBuiltinMacro(Token &Tok) { // __BASE_FILE__ is a GNU extension that returns the top of the presumed // #include stack instead of the current file. if (II == Ident__BASE_FILE__) { - Diag(Tok, diag::ext_pp_base_file); SourceLocation NextLoc = PLoc.getIncludeLoc(); while (NextLoc.isValid()) { PLoc = SourceMgr.getPresumedLoc(NextLoc); @@ -697,8 +702,6 @@ void Preprocessor::ExpandBuiltinMacro(Token &Tok) { Tok.getLocation(), Tok.getLength())); } else if (II == Ident__INCLUDE_LEVEL__) { - Diag(Tok, diag::ext_pp_include_level); - // Compute the presumed include depth of this token. This can be affected // by GNU line markers. unsigned Depth = 0; @@ -715,7 +718,6 @@ void Preprocessor::ExpandBuiltinMacro(Token &Tok) { } else if (II == Ident__TIMESTAMP__) { // MSVC, ICC, GCC, VisualAge C++ extension. The generated string should be // of the form "Ddd Mmm dd hh::mm::ss yyyy", which is returned by asctime. - Diag(Tok, diag::ext_pp_timestamp); // Get the file that we are lexing out of. If we're currently lexing from // a macro, dig into the include stack. @@ -725,7 +727,6 @@ void Preprocessor::ExpandBuiltinMacro(Token &Tok) { if (TheLexer) CurFile = SourceMgr.getFileEntryForID(TheLexer->getFileID()); - // If this file is older than the file it depends on, emit a diagnostic. const char *Result; if (CurFile) { time_t TT = CurFile->getModificationTime(); @@ -741,8 +742,6 @@ void Preprocessor::ExpandBuiltinMacro(Token &Tok) { Tok.setKind(tok::string_literal); CreateString(TmpBuffer, Len+1, Tok, Tok.getLocation()); } else if (II == Ident__COUNTER__) { - Diag(Tok, diag::ext_pp_counter); - // __COUNTER__ expands to a simple numeric value. sprintf(TmpBuffer, "%u", CounterValue++); Tok.setKind(tok::numeric_constant); diff --git a/lib/Lex/Preprocessor.cpp b/lib/Lex/Preprocessor.cpp index 066909475fe3..d4e441b2f183 100644 --- a/lib/Lex/Preprocessor.cpp +++ b/lib/Lex/Preprocessor.cpp @@ -26,6 +26,7 @@ //===----------------------------------------------------------------------===// #include "clang/Lex/Preprocessor.h" +#include "MacroArgs.h" #include "clang/Lex/HeaderSearch.h" #include "clang/Lex/MacroInfo.h" #include "clang/Lex/Pragma.h" @@ -50,7 +51,8 @@ Preprocessor::Preprocessor(Diagnostic &diags, const LangOptions &opts, bool OwnsHeaders) : Diags(&diags), Features(opts), Target(target),FileMgr(Headers.getFileMgr()), SourceMgr(SM), HeaderInfo(Headers), Identifiers(opts, IILookup), - BuiltinInfo(Target), CurPPLexer(0), CurDirLookup(0), Callbacks(0) { + BuiltinInfo(Target), CodeCompletionFile(0), CurPPLexer(0), CurDirLookup(0), + Callbacks(0), MacroArgCache(0) { ScratchBuf = new ScratchBuffer(SourceMgr); CounterValue = 0; // __COUNTER__ starts at 0. OwnsHeaderSearch = OwnsHeaders; @@ -101,7 +103,7 @@ Preprocessor::~Preprocessor() { Macros.begin(), E = Macros.end(); I != E; ++I) { // We don't need to free the MacroInfo objects directly. These // will be released when the BumpPtrAllocator 'BP' object gets - // destroyed. We still need to run the dstor, however, to free + // destroyed. We still need to run the dtor, however, to free // memory alocated by MacroInfo. I->second->Destroy(BP); I->first->setHasMacroDefinition(false); @@ -110,6 +112,10 @@ Preprocessor::~Preprocessor() { // Free any cached macro expanders. for (unsigned i = 0, e = NumCachedTokenLexers; i != e; ++i) delete TokenLexerCache[i]; + + // Free any cached MacroArgs. + for (MacroArgs *ArgList = MacroArgCache; ArgList; ) + ArgList = ArgList->deallocate(); // Release pragma information. delete PragmaHandlers; @@ -188,6 +194,57 @@ void Preprocessor::PrintStats() { << NumFastTokenPaste << " on the fast path.\n"; } +bool Preprocessor::SetCodeCompletionPoint(const FileEntry *File, + unsigned TruncateAtLine, + unsigned TruncateAtColumn) { + using llvm::MemoryBuffer; + + CodeCompletionFile = File; + + // Okay to clear out the code-completion point by passing NULL. + if (!CodeCompletionFile) + return false; + + // Load the actual file's contents. + const MemoryBuffer *Buffer = SourceMgr.getMemoryBufferForFile(File); + if (!Buffer) + return true; + + // Find the byte position of the truncation point. + const char *Position = Buffer->getBufferStart(); + for (unsigned Line = 1; Line < TruncateAtLine; ++Line) { + for (; *Position; ++Position) { + if (*Position != '\r' && *Position != '\n') + continue; + + // Eat \r\n or \n\r as a single line. + if ((Position[1] == '\r' || Position[1] == '\n') && + Position[0] != Position[1]) + ++Position; + ++Position; + break; + } + } + + Position += TruncateAtColumn - 1; + + // Truncate the buffer. + if (Position < Buffer->getBufferEnd()) { + MemoryBuffer *TruncatedBuffer + = MemoryBuffer::getMemBufferCopy(Buffer->getBufferStart(), Position, + Buffer->getBufferIdentifier()); + SourceMgr.overrideFileContents(File, TruncatedBuffer); + } + + return false; +} + +bool Preprocessor::isCodeCompletionFile(SourceLocation FileLoc) const { + return CodeCompletionFile && FileLoc.isFileID() && + SourceMgr.getFileEntryForID(SourceMgr.getFileID(FileLoc)) + == CodeCompletionFile; +} + //===----------------------------------------------------------------------===// // Token Spelling //===----------------------------------------------------------------------===// @@ -380,7 +437,9 @@ void Preprocessor::EnterMainSourceFile() { FileID MainFileID = SourceMgr.getMainFileID(); // Enter the main file source buffer. - EnterSourceFile(MainFileID, 0); + std::string ErrorStr; + bool Res = EnterSourceFile(MainFileID, 0, ErrorStr); + assert(!Res && "Entering main file should not fail!"); // Tell the header info that the main file was entered. If the file is later // #imported, it won't be re-entered. @@ -406,7 +465,8 @@ void Preprocessor::EnterMainSourceFile() { assert(!FID.isInvalid() && "Could not create FileID for predefines?"); // Start parsing the predefines. - EnterSourceFile(FID, 0); + Res = EnterSourceFile(FID, 0, ErrorStr); + assert(!Res && "Entering predefines should not fail!"); } diff --git a/lib/Lex/TokenLexer.cpp b/lib/Lex/TokenLexer.cpp index f006f5ae55bb..a40bb62db46d 100644 --- a/lib/Lex/TokenLexer.cpp +++ b/lib/Lex/TokenLexer.cpp @@ -92,7 +92,7 @@ void TokenLexer::destroy() { } // TokenLexer owns its formal arguments. - if (ActualArgs) ActualArgs->destroy(); + if (ActualArgs) ActualArgs->destroy(PP); } /// Expand the arguments of a function-like macro so that we can quickly @@ -321,13 +321,12 @@ void TokenLexer::Lex(Token &Tok) { // If this token is followed by a token paste (##) operator, paste the tokens! if (!isAtEnd() && Tokens[CurToken].is(tok::hashhash)) { - if (PasteTokens(Tok)) { - // When handling the microsoft /##/ extension, the final token is - // returned by PasteTokens, not the pasted token. + // When handling the microsoft /##/ extension, the final token is + // returned by PasteTokens, not the pasted token. + if (PasteTokens(Tok)) return; - } else { - TokenIsFromPaste = true; - } + + TokenIsFromPaste = true; } // The token's current location indicate where the token was lexed from. We diff --git a/lib/Parse/DeclSpec.cpp b/lib/Parse/DeclSpec.cpp index f00f33fcb948..4cd8fe887bb1 100644 --- a/lib/Parse/DeclSpec.cpp +++ b/lib/Parse/DeclSpec.cpp @@ -137,7 +137,7 @@ const char *DeclSpec::getSpecifierName(DeclSpec::SCS S) { case DeclSpec::SCS_private_extern: return "__private_extern__"; case DeclSpec::SCS_mutable: return "mutable"; } - llvm::llvm_unreachable("Unknown typespec!"); + llvm_unreachable("Unknown typespec!"); } const char *DeclSpec::getSpecifierName(TSW W) { @@ -147,7 +147,7 @@ const char *DeclSpec::getSpecifierName(TSW W) { case TSW_long: return "long"; case TSW_longlong: return "long long"; } - llvm::llvm_unreachable("Unknown typespec!"); + llvm_unreachable("Unknown typespec!"); } const char *DeclSpec::getSpecifierName(TSC C) { @@ -156,7 +156,7 @@ const char *DeclSpec::getSpecifierName(TSC C) { case TSC_imaginary: return "imaginary"; case TSC_complex: return "complex"; } - llvm::llvm_unreachable("Unknown typespec!"); + llvm_unreachable("Unknown typespec!"); } @@ -166,7 +166,7 @@ const char *DeclSpec::getSpecifierName(TSS S) { case TSS_signed: return "signed"; case TSS_unsigned: return "unsigned"; } - llvm::llvm_unreachable("Unknown typespec!"); + llvm_unreachable("Unknown typespec!"); } const char *DeclSpec::getSpecifierName(DeclSpec::TST T) { @@ -195,7 +195,7 @@ const char *DeclSpec::getSpecifierName(DeclSpec::TST T) { case DeclSpec::TST_decltype: return "(decltype)"; case DeclSpec::TST_error: return "(error)"; } - llvm::llvm_unreachable("Unknown typespec!"); + llvm_unreachable("Unknown typespec!"); } const char *DeclSpec::getSpecifierName(TQ T) { @@ -205,7 +205,7 @@ const char *DeclSpec::getSpecifierName(TQ T) { case DeclSpec::TQ_restrict: return "restrict"; case DeclSpec::TQ_volatile: return "volatile"; } - llvm::llvm_unreachable("Unknown typespec!"); + llvm_unreachable("Unknown typespec!"); } bool DeclSpec::SetStorageClassSpec(SCS S, SourceLocation Loc, diff --git a/lib/Parse/ExtensionRAIIObject.h b/lib/Parse/ExtensionRAIIObject.h deleted file mode 100644 index cc7c8e21705c..000000000000 --- a/lib/Parse/ExtensionRAIIObject.h +++ /dev/null @@ -1,40 +0,0 @@ -//===--- ExtensionRAIIObject.h - Use RAII for __extension__ -----*- 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 and implements the ExtensionRAIIObject class. -// -//===----------------------------------------------------------------------===// - -#ifndef LLVM_CLANG_PARSE_EXTENSION_RAII_OBJECT_H -#define LLVM_CLANG_PARSE_EXTENSION_RAII_OBJECT_H - -#include "clang/Parse/ParseDiagnostic.h" - -namespace clang { - - /// ExtensionRAIIObject - This saves the state of extension warnings when - /// constructed and disables them. When destructed, it restores them back to - /// the way they used to be. This is used to handle __extension__ in the - /// parser. - class ExtensionRAIIObject { - void operator=(const ExtensionRAIIObject &); // DO NOT IMPLEMENT - ExtensionRAIIObject(const ExtensionRAIIObject&); // DO NOT IMPLEMENT - Diagnostic &Diags; - public: - ExtensionRAIIObject(Diagnostic &diags) : Diags(diags) { - Diags.IncrementAllExtensionsSilenced(); - } - - ~ExtensionRAIIObject() { - Diags.DecrementAllExtensionsSilenced(); - } - }; -} - -#endif diff --git a/lib/Parse/MinimalAction.cpp b/lib/Parse/MinimalAction.cpp index aa0b89b1a3a2..8b207fab436c 100644 --- a/lib/Parse/MinimalAction.cpp +++ b/lib/Parse/MinimalAction.cpp @@ -45,6 +45,7 @@ Action::DeclPtrTy Action::ActOnUsingDirective(Scope *CurScope, // Defined out-of-line here because of dependency on AttributeList Action::DeclPtrTy Action::ActOnUsingDeclaration(Scope *CurScope, AccessSpecifier AS, + bool HasUsingKeyword, SourceLocation UsingLoc, const CXXScopeSpec &SS, UnqualifiedId &Name, diff --git a/lib/Parse/ParseDecl.cpp b/lib/Parse/ParseDecl.cpp index b13dc7335670..5dd78f7b547c 100644 --- a/lib/Parse/ParseDecl.cpp +++ b/lib/Parse/ParseDecl.cpp @@ -1,4 +1,3 @@ - //===--- ParseDecl.cpp - Declaration Parsing ------------------------------===// // // The LLVM Compiler Infrastructure @@ -16,7 +15,7 @@ #include "clang/Parse/ParseDiagnostic.h" #include "clang/Parse/Scope.h" #include "clang/Parse/Template.h" -#include "ExtensionRAIIObject.h" +#include "RAIIObjectsForParser.h" #include "llvm/ADT/SmallSet.h" using namespace clang; @@ -825,14 +824,18 @@ void Parser::ParseDeclarationSpecifiers(DeclSpec &DS, if (DS.hasTypeSpecifier()) goto DoneWithDeclSpec; + CXXScopeSpec SS; + SS.setScopeRep(Tok.getAnnotationValue()); + SS.setRange(Tok.getAnnotationRange()); + // We are looking for a qualified typename. Token Next = NextToken(); if (Next.is(tok::annot_template_id) && static_cast(Next.getAnnotationValue()) ->Kind == TNK_Type_template) { // We have a qualified template-id, e.g., N::A - CXXScopeSpec SS; - ParseOptionalCXXScopeSpecifier(SS, /*ObjectType=*/0, true); + DS.getTypeSpecScope() = SS; + ConsumeToken(); // The C++ scope. assert(Tok.is(tok::annot_template_id) && "ParseOptionalCXXScopeSpecifier not working"); AnnotateTemplateIdTokenAsType(&SS); @@ -840,8 +843,8 @@ void Parser::ParseDeclarationSpecifiers(DeclSpec &DS, } if (Next.is(tok::annot_typename)) { - // FIXME: is this scope-specifier getting dropped? - ConsumeToken(); // the scope-specifier + DS.getTypeSpecScope() = SS; + ConsumeToken(); // The C++ scope. if (Tok.getAnnotationValue()) isInvalid = DS.SetTypeSpecType(DeclSpec::TST_typename, Loc, PrevSpec, DiagID, @@ -855,10 +858,6 @@ void Parser::ParseDeclarationSpecifiers(DeclSpec &DS, if (Next.isNot(tok::identifier)) goto DoneWithDeclSpec; - CXXScopeSpec SS; - SS.setScopeRep(Tok.getAnnotationValue()); - SS.setRange(Tok.getAnnotationRange()); - // If the next token is the name of the class type that the C++ scope // denotes, followed by a '(', then this is a constructor declaration. // We're done with the decl-specifiers. @@ -880,6 +879,7 @@ void Parser::ParseDeclarationSpecifiers(DeclSpec &DS, goto DoneWithDeclSpec; } + DS.getTypeSpecScope() = SS; ConsumeToken(); // The C++ scope. isInvalid = DS.SetTypeSpecType(DeclSpec::TST_typename, Loc, PrevSpec, @@ -1545,8 +1545,11 @@ ParseStructDeclaration(DeclSpec &DS, FieldCallback &Fields) { /// struct-declarator: declarator /// struct-declarator: declarator[opt] ':' constant-expression - if (Tok.isNot(tok::colon)) + if (Tok.isNot(tok::colon)) { + // Don't parse FOO:BAR as if it were a typo for FOO::BAR. + ColonProtectionRAIIObject X(*this); ParseDeclarator(DeclaratorInfo.D); + } if (Tok.is(tok::colon)) { ConsumeToken(); @@ -1616,7 +1619,7 @@ void Parser::ParseStructUnionBody(SourceLocation RecordLoc, // Check for extraneous top-level semicolon. if (Tok.is(tok::semi)) { Diag(Tok, diag::ext_extra_struct_semi) - << CodeModificationHint::CreateRemoval(SourceRange(Tok.getLocation())); + << CodeModificationHint::CreateRemoval(Tok.getLocation()); ConsumeToken(); continue; } @@ -1841,7 +1844,7 @@ void Parser::ParseEnumBody(SourceLocation StartLoc, DeclPtrTy EnumDecl) { !(getLang().C99 || getLang().CPlusPlus0x)) Diag(CommaLoc, diag::ext_enumerator_list_comma) << getLang().CPlusPlus - << CodeModificationHint::CreateRemoval((SourceRange(CommaLoc))); + << CodeModificationHint::CreateRemoval(CommaLoc); } // Eat the }. @@ -2333,9 +2336,10 @@ void Parser::ParseDirectDeclarator(Declarator &D) { ParseOptionalCXXScopeSpecifier(D.getCXXScopeSpec(), /*ObjectType=*/0, true); if (afterCXXScope) { - // Change the declaration context for name lookup, until this function - // is exited (and the declarator has been parsed). - DeclScopeObj.EnterDeclaratorScope(); + if (Actions.ShouldEnterDeclaratorScope(CurScope, D.getCXXScopeSpec())) + // Change the declaration context for name lookup, until this function + // is exited (and the declarator has been parsed). + DeclScopeObj.EnterDeclaratorScope(); } if (Tok.is(tok::identifier) || Tok.is(tok::kw_operator) || diff --git a/lib/Parse/ParseDeclCXX.cpp b/lib/Parse/ParseDeclCXX.cpp index 505a4d800ded..d4d19a0b0765 100644 --- a/lib/Parse/ParseDeclCXX.cpp +++ b/lib/Parse/ParseDeclCXX.cpp @@ -17,7 +17,7 @@ #include "clang/Parse/DeclSpec.h" #include "clang/Parse/Scope.h" #include "clang/Parse/Template.h" -#include "ExtensionRAIIObject.h" +#include "RAIIObjectsForParser.h" using namespace clang; /// ParseNamespace - We know that the current token is a namespace keyword. This @@ -161,7 +161,8 @@ Parser::DeclPtrTy Parser::ParseNamespaceAlias(SourceLocation NamespaceLoc, /// 'extern' string-literal '{' declaration-seq[opt] '}' /// 'extern' string-literal declaration /// -Parser::DeclPtrTy Parser::ParseLinkage(unsigned Context) { +Parser::DeclPtrTy Parser::ParseLinkage(ParsingDeclSpec &DS, + unsigned Context) { assert(Tok.is(tok::string_literal) && "Not a string literal!"); llvm::SmallVector LangBuffer; // LangBuffer is guaranteed to be big enough. @@ -185,7 +186,7 @@ Parser::DeclPtrTy Parser::ParseLinkage(unsigned Context) { } if (Tok.isNot(tok::l_brace)) { - ParseDeclarationOrFunctionDefinition(Attr.AttrList); + ParseDeclarationOrFunctionDefinition(DS, Attr.AttrList); return Actions.ActOnFinishLinkageSpecification(CurScope, LinkageSpec, SourceLocation()); } @@ -356,7 +357,7 @@ Parser::DeclPtrTy Parser::ParseUsingDeclaration(unsigned Context, AttrList ? "attributes list" : "using declaration", tok::semi); - return Actions.ActOnUsingDeclaration(CurScope, AS, UsingLoc, SS, Name, + return Actions.ActOnUsingDeclaration(CurScope, AS, true, UsingLoc, SS, Name, AttrList, IsTypeName, TypenameLoc); } @@ -599,11 +600,15 @@ void Parser::ParseClassSpecifier(tok::TokenKind TagTokKind, } // Parse the (optional) nested-name-specifier. - CXXScopeSpec SS; - if (getLang().CPlusPlus && - ParseOptionalCXXScopeSpecifier(SS, /*ObjectType=*/0, true)) - if (Tok.isNot(tok::identifier) && Tok.isNot(tok::annot_template_id)) - Diag(Tok, diag::err_expected_ident); + CXXScopeSpec &SS = DS.getTypeSpecScope(); + if (getLang().CPlusPlus) { + // "FOO : BAR" is not a potential typo for "FOO::BAR". + ColonProtectionRAIIObject X(*this); + + if (ParseOptionalCXXScopeSpecifier(SS, /*ObjectType=*/0, true)) + if (Tok.isNot(tok::identifier) && Tok.isNot(tok::annot_template_id)) + Diag(Tok, diag::err_expected_ident); + } TemplateParameterLists *TemplateParams = TemplateInfo.TemplateParams; @@ -954,7 +959,7 @@ Parser::BaseResult Parser::ParseBaseSpecifier(DeclPtrTy ClassDecl) { if (IsVirtual) { // Complain about duplicate 'virtual' Diag(VirtualLoc, diag::err_dup_virtual) - << CodeModificationHint::CreateRemoval(SourceRange(VirtualLoc)); + << CodeModificationHint::CreateRemoval(VirtualLoc); } IsVirtual = true; @@ -1060,6 +1065,46 @@ void Parser::HandleMemberFunctionDefaultArgs(Declarator& DeclaratorInfo, /// void Parser::ParseCXXClassMemberDeclaration(AccessSpecifier AS, const ParsedTemplateInfo &TemplateInfo) { + // Access declarations. + if (!TemplateInfo.Kind && + (Tok.is(tok::identifier) || Tok.is(tok::coloncolon)) && + TryAnnotateCXXScopeToken() && + Tok.is(tok::annot_cxxscope)) { + bool isAccessDecl = false; + if (NextToken().is(tok::identifier)) + isAccessDecl = GetLookAheadToken(2).is(tok::semi); + else + isAccessDecl = NextToken().is(tok::kw_operator); + + if (isAccessDecl) { + // Collect the scope specifier token we annotated earlier. + CXXScopeSpec SS; + ParseOptionalCXXScopeSpecifier(SS, /*ObjectType*/ 0, false); + + // Try to parse an unqualified-id. + UnqualifiedId Name; + if (ParseUnqualifiedId(SS, false, true, true, /*ObjectType*/ 0, Name)) { + SkipUntil(tok::semi); + return; + } + + // TODO: recover from mistakenly-qualified operator declarations. + if (ExpectAndConsume(tok::semi, + diag::err_expected_semi_after, + "access declaration", + tok::semi)) + return; + + Actions.ActOnUsingDeclaration(CurScope, AS, + false, SourceLocation(), + SS, Name, + /* AttrList */ 0, + /* IsTypeName */ false, + SourceLocation()); + return; + } + } + // static_assert-declaration if (Tok.is(tok::kw_static_assert)) { // FIXME: Check for templates @@ -1085,11 +1130,13 @@ void Parser::ParseCXXClassMemberDeclaration(AccessSpecifier AS, return ParseCXXClassMemberDeclaration(AS, TemplateInfo); } + // Don't parse FOO:BAR as if it were a typo for FOO::BAR. + ColonProtectionRAIIObject X(*this); + CXX0XAttributeList AttrList; // Optional C++0x attribute-specifier - if (getLang().CPlusPlus0x && isCXX0XAttributeSpecifier()) { + if (getLang().CPlusPlus0x && isCXX0XAttributeSpecifier()) AttrList = ParseCXX0XAttributes(); - } if (Tok.is(tok::kw_using)) { // FIXME: Check for template aliases @@ -1133,6 +1180,9 @@ void Parser::ParseCXXClassMemberDeclaration(AccessSpecifier AS, ParsingDeclarator DeclaratorInfo(*this, DS, Declarator::MemberContext); if (Tok.isNot(tok::colon)) { + // Don't parse FOO:BAR as if it were a typo for FOO::BAR. + ColonProtectionRAIIObject X(*this); + // Parse the first declarator. ParseDeclarator(DeclaratorInfo); // Error parsing the declarator? @@ -1349,7 +1399,7 @@ void Parser::ParseCXXMemberSpecification(SourceLocation RecordLoc, // Check for extraneous top-level semicolon. if (Tok.is(tok::semi)) { Diag(Tok, diag::ext_extra_struct_semi) - << CodeModificationHint::CreateRemoval(SourceRange(Tok.getLocation())); + << CodeModificationHint::CreateRemoval(Tok.getLocation()); ConsumeToken(); continue; } diff --git a/lib/Parse/ParseExpr.cpp b/lib/Parse/ParseExpr.cpp index f780cf1a6054..bdbc67f782dc 100644 --- a/lib/Parse/ParseExpr.cpp +++ b/lib/Parse/ParseExpr.cpp @@ -23,7 +23,7 @@ #include "clang/Parse/DeclSpec.h" #include "clang/Parse/Scope.h" #include "clang/Basic/PrettyStackTrace.h" -#include "ExtensionRAIIObject.h" +#include "RAIIObjectsForParser.h" #include "llvm/ADT/SmallVector.h" #include "llvm/ADT/SmallString.h" using namespace clang; @@ -317,6 +317,9 @@ Parser::ParseRHSOfBinaryExpression(OwningExprResult LHS, unsigned MinPrec) { OwningExprResult TernaryMiddle(Actions, true); if (NextTokPrec == prec::Conditional) { if (Tok.isNot(tok::colon)) { + // Don't parse FOO:BAR as if it were a typo for FOO::BAR. + ColonProtectionRAIIObject X(*this); + // Handle this production specially: // logical-OR-expression '?' expression ':' conditional-expression // In particular, the RHS of the '?' is 'expression', not @@ -562,9 +565,15 @@ Parser::OwningExprResult Parser::ParseCastExpression(bool isUnaryExpression, TypeTy *CastTy; SourceLocation LParenLoc = Tok.getLocation(); SourceLocation RParenLoc; - Res = ParseParenExpression(ParenExprType, false/*stopIfCastExr*/, - TypeOfCast, CastTy, RParenLoc); - if (Res.isInvalid()) return move(Res); + + { + // The inside of the parens don't need to be a colon protected scope. + ColonProtectionRAIIObject X(*this, false); + + Res = ParseParenExpression(ParenExprType, false/*stopIfCastExr*/, + TypeOfCast, CastTy, RParenLoc); + if (Res.isInvalid()) return move(Res); + } switch (ParenExprType) { case SimpleExpr: break; // Nothing else to do. @@ -826,6 +835,7 @@ Parser::OwningExprResult Parser::ParseCastExpression(bool isUnaryExpression, case tok::kw___is_empty: case tok::kw___is_polymorphic: case tok::kw___is_abstract: + case tok::kw___is_literal: case tok::kw___has_trivial_constructor: case tok::kw___has_trivial_copy: case tok::kw___has_trivial_assign: diff --git a/lib/Parse/ParseExprCXX.cpp b/lib/Parse/ParseExprCXX.cpp index 52003e6fa1b2..abd26d7d4905 100644 --- a/lib/Parse/ParseExprCXX.cpp +++ b/lib/Parse/ParseExprCXX.cpp @@ -214,11 +214,29 @@ bool Parser::ParseOptionalCXXScopeSpecifier(CXXScopeSpec &SS, // namespace-name '::' // nested-name-specifier identifier '::' Token Next = NextToken(); + + // If we get foo:bar, this is almost certainly a typo for foo::bar. Recover + // and emit a fixit hint for it. + if (Next.is(tok::colon) && !ColonIsSacred && + Actions.IsInvalidUnlessNestedName(CurScope, SS, II, ObjectType, + EnteringContext) && + // If the token after the colon isn't an identifier, it's still an + // error, but they probably meant something else strange so don't + // recover like this. + PP.LookAhead(1).is(tok::identifier)) { + Diag(Next, diag::err_unexected_colon_in_nested_name_spec) + << CodeModificationHint::CreateReplacement(Next.getLocation(), "::"); + + // Recover as if the user wrote '::'. + Next.setKind(tok::coloncolon); + } + if (Next.is(tok::coloncolon)) { // We have an identifier followed by a '::'. Lookup this name // as the name in a nested-name-specifier. SourceLocation IdLoc = ConsumeToken(); - assert(Tok.is(tok::coloncolon) && "NextToken() not working properly!"); + assert((Tok.is(tok::coloncolon) || Tok.is(tok::colon)) && + "NextToken() not working properly!"); SourceLocation CCLoc = ConsumeToken(); if (!HasScopeSpecifier) { @@ -1459,6 +1477,7 @@ static UnaryTypeTrait UnaryTypeTraitFromTokKind(tok::TokenKind kind) { case tok::kw___is_pod: return UTT_IsPOD; case tok::kw___is_polymorphic: return UTT_IsPolymorphic; case tok::kw___is_union: return UTT_IsUnion; + case tok::kw___is_literal: return UTT_IsLiteral; } } diff --git a/lib/Parse/ParseObjc.cpp b/lib/Parse/ParseObjc.cpp index 295625ae272d..2c53847f8ed0 100644 --- a/lib/Parse/ParseObjc.cpp +++ b/lib/Parse/ParseObjc.cpp @@ -30,6 +30,11 @@ using namespace clang; Parser::DeclPtrTy Parser::ParseObjCAtDirectives() { SourceLocation AtLoc = ConsumeToken(); // the "@" + if (Tok.is(tok::code_completion)) { + Actions.CodeCompleteObjCAtDirective(CurScope, ObjCImpDecl, false); + ConsumeToken(); + } + switch (Tok.getObjCKeywordID()) { case tok::objc_class: return ParseObjCAtClassDeclaration(AtLoc); @@ -228,6 +233,63 @@ Parser::DeclPtrTy Parser::ParseObjCAtInterfaceDeclaration( return ClsType; } +/// The Objective-C property callback. This should be defined where +/// it's used, but instead it's been lifted to here to support VS2005. +struct Parser::ObjCPropertyCallback : FieldCallback { + Parser &P; + DeclPtrTy IDecl; + llvm::SmallVectorImpl &Props; + ObjCDeclSpec &OCDS; + SourceLocation AtLoc; + tok::ObjCKeywordKind MethodImplKind; + + ObjCPropertyCallback(Parser &P, DeclPtrTy IDecl, + llvm::SmallVectorImpl &Props, + ObjCDeclSpec &OCDS, SourceLocation AtLoc, + tok::ObjCKeywordKind MethodImplKind) : + P(P), IDecl(IDecl), Props(Props), OCDS(OCDS), AtLoc(AtLoc), + MethodImplKind(MethodImplKind) { + } + + DeclPtrTy invoke(FieldDeclarator &FD) { + if (FD.D.getIdentifier() == 0) { + P.Diag(AtLoc, diag::err_objc_property_requires_field_name) + << FD.D.getSourceRange(); + return DeclPtrTy(); + } + if (FD.BitfieldSize) { + P.Diag(AtLoc, diag::err_objc_property_bitfield) + << FD.D.getSourceRange(); + return DeclPtrTy(); + } + + // Install the property declarator into interfaceDecl. + IdentifierInfo *SelName = + OCDS.getGetterName() ? OCDS.getGetterName() : FD.D.getIdentifier(); + + Selector GetterSel = + P.PP.getSelectorTable().getNullarySelector(SelName); + IdentifierInfo *SetterName = OCDS.getSetterName(); + Selector SetterSel; + if (SetterName) + SetterSel = P.PP.getSelectorTable().getSelector(1, &SetterName); + else + SetterSel = SelectorTable::constructSetterName(P.PP.getIdentifierTable(), + P.PP.getSelectorTable(), + FD.D.getIdentifier()); + bool isOverridingProperty = false; + DeclPtrTy Property = + P.Actions.ActOnProperty(P.CurScope, AtLoc, FD, OCDS, + GetterSel, SetterSel, IDecl, + &isOverridingProperty, + MethodImplKind); + if (!isOverridingProperty) + Props.push_back(Property); + + return Property; + } +}; + /// objc-interface-decl-list: /// empty /// objc-interface-decl-list objc-property-decl [OBJC2] @@ -288,6 +350,12 @@ void Parser::ParseObjCInterfaceDeclList(DeclPtrTy interfaceDecl, // Otherwise, we have an @ directive, eat the @. SourceLocation AtLoc = ConsumeToken(); // the "@" + if (Tok.is(tok::code_completion)) { + Actions.CodeCompleteObjCAtDirective(CurScope, ObjCImpDecl, true); + ConsumeToken(); + break; + } + tok::ObjCKeywordKind DirectiveKind = Tok.getObjCKeywordID(); if (DirectiveKind == tok::objc_end) { // @end -> terminate list @@ -329,61 +397,8 @@ void Parser::ParseObjCInterfaceDeclList(DeclPtrTy interfaceDecl, ParseObjCPropertyAttribute(OCDS, interfaceDecl, allMethods.data(), allMethods.size()); - struct ObjCPropertyCallback : FieldCallback { - Parser &P; - DeclPtrTy IDecl; - llvm::SmallVectorImpl &Props; - ObjCDeclSpec &OCDS; - SourceLocation AtLoc; - tok::ObjCKeywordKind MethodImplKind; - - ObjCPropertyCallback(Parser &P, DeclPtrTy IDecl, - llvm::SmallVectorImpl &Props, - ObjCDeclSpec &OCDS, SourceLocation AtLoc, - tok::ObjCKeywordKind MethodImplKind) : - P(P), IDecl(IDecl), Props(Props), OCDS(OCDS), AtLoc(AtLoc), - MethodImplKind(MethodImplKind) { - } - - DeclPtrTy invoke(FieldDeclarator &FD) { - if (FD.D.getIdentifier() == 0) { - P.Diag(AtLoc, diag::err_objc_property_requires_field_name) - << FD.D.getSourceRange(); - return DeclPtrTy(); - } - if (FD.BitfieldSize) { - P.Diag(AtLoc, diag::err_objc_property_bitfield) - << FD.D.getSourceRange(); - return DeclPtrTy(); - } - - // Install the property declarator into interfaceDecl. - IdentifierInfo *SelName = - OCDS.getGetterName() ? OCDS.getGetterName() : FD.D.getIdentifier(); - - Selector GetterSel = - P.PP.getSelectorTable().getNullarySelector(SelName); - IdentifierInfo *SetterName = OCDS.getSetterName(); - Selector SetterSel; - if (SetterName) - SetterSel = P.PP.getSelectorTable().getSelector(1, &SetterName); - else - SetterSel = SelectorTable::constructSetterName(P.PP.getIdentifierTable(), - P.PP.getSelectorTable(), - FD.D.getIdentifier()); - bool isOverridingProperty = false; - DeclPtrTy Property = - P.Actions.ActOnProperty(P.CurScope, AtLoc, FD, OCDS, - GetterSel, SetterSel, IDecl, - &isOverridingProperty, - MethodImplKind); - if (!isOverridingProperty) - Props.push_back(Property); - - return Property; - } - } Callback(*this, interfaceDecl, allProperties, - OCDS, AtLoc, MethodImplKind); + ObjCPropertyCallback Callback(*this, interfaceDecl, allProperties, + OCDS, AtLoc, MethodImplKind); // Parse all the comma separated declarators. DeclSpec DS; @@ -397,7 +412,10 @@ void Parser::ParseObjCInterfaceDeclList(DeclPtrTy interfaceDecl, // We break out of the big loop in two cases: when we see @end or when we see // EOF. In the former case, eat the @end. In the later case, emit an error. - if (Tok.isObjCAtKeyword(tok::objc_end)) + if (Tok.is(tok::code_completion)) { + Actions.CodeCompleteObjCAtDirective(CurScope, ObjCImpDecl, true); + ConsumeToken(); + } else if (Tok.isObjCAtKeyword(tok::objc_end)) ConsumeToken(); // the "end" identifier else Diag(Tok, diag::err_objc_missing_end); @@ -938,7 +956,7 @@ void Parser::ParseObjCClassInstanceVariables(DeclPtrTy interfaceDecl, // Check for extraneous top-level semicolon. if (Tok.is(tok::semi)) { Diag(Tok, diag::ext_extra_struct_semi) - << CodeModificationHint::CreateRemoval(SourceRange(Tok.getLocation())); + << CodeModificationHint::CreateRemoval(Tok.getLocation()); ConsumeToken(); continue; } @@ -1503,7 +1521,7 @@ Parser::DeclPtrTy Parser::ParseObjCMethodDefinition() { if (Tok.is(tok::semi)) { if (ObjCImpDecl) { Diag(Tok, diag::warn_semicolon_before_method_body) - << CodeModificationHint::CreateRemoval(SourceRange(Tok.getLocation())); + << CodeModificationHint::CreateRemoval(Tok.getLocation()); } ConsumeToken(); } @@ -1545,12 +1563,21 @@ Parser::DeclPtrTy Parser::ParseObjCMethodDefinition() { } Parser::OwningStmtResult Parser::ParseObjCAtStatement(SourceLocation AtLoc) { - if (Tok.isObjCAtKeyword(tok::objc_try)) { + if (Tok.is(tok::code_completion)) { + Actions.CodeCompleteObjCAtStatement(CurScope); + ConsumeToken(); + return StmtError(); + } + + if (Tok.isObjCAtKeyword(tok::objc_try)) return ParseObjCTryStmt(AtLoc); - } else if (Tok.isObjCAtKeyword(tok::objc_throw)) + + if (Tok.isObjCAtKeyword(tok::objc_throw)) return ParseObjCThrowStmt(AtLoc); - else if (Tok.isObjCAtKeyword(tok::objc_synchronized)) + + if (Tok.isObjCAtKeyword(tok::objc_synchronized)) return ParseObjCSynchronizedStmt(AtLoc); + OwningExprResult Res(ParseExpressionWithLeadingAt(AtLoc)); if (Res.isInvalid()) { // If the expression is invalid, skip ahead to the next semicolon. Not @@ -1559,6 +1586,7 @@ Parser::OwningStmtResult Parser::ParseObjCAtStatement(SourceLocation AtLoc) { SkipUntil(tok::semi); return StmtError(); } + // Otherwise, eat the semicolon. ExpectAndConsume(tok::semi, diag::err_expected_semi_after_expr); return Actions.ActOnExprStmt(Actions.FullExpr(Res)); @@ -1566,6 +1594,11 @@ Parser::OwningStmtResult Parser::ParseObjCAtStatement(SourceLocation AtLoc) { Parser::OwningExprResult Parser::ParseObjCAtExpression(SourceLocation AtLoc) { switch (Tok.getKind()) { + case tok::code_completion: + Actions.CodeCompleteObjCAtExpression(CurScope); + ConsumeToken(); + return ExprError(); + case tok::string_literal: // primary-expression: string-literal case tok::wide_string_literal: return ParsePostfixExpressionSuffix(ParseObjCStringLiteral(AtLoc)); diff --git a/lib/Parse/ParseStmt.cpp b/lib/Parse/ParseStmt.cpp index c87010e356a0..a2ac64655502 100644 --- a/lib/Parse/ParseStmt.cpp +++ b/lib/Parse/ParseStmt.cpp @@ -13,7 +13,7 @@ //===----------------------------------------------------------------------===// #include "clang/Parse/Parser.h" -#include "ExtensionRAIIObject.h" +#include "RAIIObjectsForParser.h" #include "clang/Parse/DeclSpec.h" #include "clang/Parse/Scope.h" #include "clang/Basic/Diagnostic.h" @@ -279,6 +279,11 @@ Parser::OwningStmtResult Parser::ParseCaseStatement(AttributeList *Attr) { ConsumeToken(); } + /// We don't want to treat 'case x : y' as a potential typo for 'case x::y'. + /// Disable this form of error recovery while we're parsing the case + /// expression. + ColonProtectionRAIIObject ColonProtection(*this); + OwningExprResult LHS(ParseConstantExpression()); if (LHS.isInvalid()) { SkipUntil(tok::colon); @@ -298,6 +303,8 @@ Parser::OwningStmtResult Parser::ParseCaseStatement(AttributeList *Attr) { return StmtError(); } } + + ColonProtection.restore(); if (Tok.isNot(tok::colon)) { Diag(Tok, diag::err_expected_colon_after) << "'case'"; @@ -1162,7 +1169,20 @@ Parser::OwningStmtResult Parser::FuzzyParseMicrosoftAsmStatement() { Tok.isNot(tok::r_brace) && Tok.isNot(tok::semi) && Tok.isNot(tok::eof)); } - return Actions.ActOnNullStmt(Tok.getLocation()); + llvm::SmallVector Names; + Token t; + t.setKind(tok::string_literal); + t.setLiteralData("\"FIXME: not done\""); + t.clearFlag(Token::NeedsCleaning); + t.setLength(17); + OwningExprResult AsmString(Actions.ActOnStringLiteral(&t, 1)); + ExprVector Constraints(Actions); + ExprVector Exprs(Actions); + ExprVector Clobbers(Actions); + return Actions.ActOnAsmStmt(Tok.getLocation(), true, true, 0, 0, Names.data(), + move_arg(Constraints), move_arg(Exprs), + move(AsmString), move_arg(Clobbers), + Tok.getLocation()); } /// ParseAsmStatement - Parse a GNU extended asm statement. diff --git a/lib/Parse/ParseTemplate.cpp b/lib/Parse/ParseTemplate.cpp index 0dbf37c830fc..cc28541b01fe 100644 --- a/lib/Parse/ParseTemplate.cpp +++ b/lib/Parse/ParseTemplate.cpp @@ -16,6 +16,7 @@ #include "clang/Parse/DeclSpec.h" #include "clang/Parse/Scope.h" #include "clang/Parse/Template.h" +#include "RAIIObjectsForParser.h" using namespace clang; /// \brief Parse a template declaration, explicit instantiation, or @@ -522,7 +523,7 @@ Parser::ParseTemplateTemplateParameter(unsigned Depth, unsigned Position) { if (Default.isInvalid()) { Diag(Tok.getLocation(), diag::err_default_template_template_parameter_not_template); - static tok::TokenKind EndToks[] = { + static const tok::TokenKind EndToks[] = { tok::comma, tok::greater, tok::greatergreater }; SkipUntil(EndToks, 3, true, true); diff --git a/lib/Parse/Parser.cpp b/lib/Parse/Parser.cpp index e321564336f1..a864e7c24cba 100644 --- a/lib/Parse/Parser.cpp +++ b/lib/Parse/Parser.cpp @@ -17,7 +17,7 @@ #include "clang/Parse/Scope.h" #include "clang/Parse/Template.h" #include "llvm/Support/raw_ostream.h" -#include "ExtensionRAIIObject.h" +#include "RAIIObjectsForParser.h" #include "ParsePragma.h" using namespace clang; @@ -36,7 +36,8 @@ class ActionCommentHandler : public CommentHandler { Parser::Parser(Preprocessor &pp, Action &actions) : CrashInfo(*this), PP(pp), Actions(actions), Diags(PP.getDiagnostics()), - GreaterThanIsOperator(true), TemplateParameterDepth(0) { + GreaterThanIsOperator(true), ColonIsSacred(false), + TemplateParameterDepth(0) { Tok.setKind(tok::eof); CurScope = 0; NumCachedScopes = 0; @@ -405,7 +406,7 @@ Parser::DeclGroupPtrTy Parser::ParseExternalDeclaration(CXX0XAttributeList Attr) case tok::semi: if (!getLang().CPlusPlus0x) Diag(Tok, diag::ext_top_level_semi) - << CodeModificationHint::CreateRemoval(SourceRange(Tok.getLocation())); + << CodeModificationHint::CreateRemoval(Tok.getLocation()); ConsumeToken(); // TODO: Invoke action for top-level semicolon. @@ -507,12 +508,13 @@ bool Parser::isDeclarationAfterDeclarator() { /// \brief Determine whether the current token, if it occurs after a /// declarator, indicates the start of a function definition. bool Parser::isStartOfFunctionDefinition() { - return Tok.is(tok::l_brace) || // int X() {} - (!getLang().CPlusPlus && - isDeclarationSpecifier()) || // int X(f) int f; {} - (getLang().CPlusPlus && - (Tok.is(tok::colon) || // X() : Base() {} (used for ctors) - Tok.is(tok::kw_try))); // X() try { ... } + if (Tok.is(tok::l_brace)) // int X() {} + return true; + + if (!getLang().CPlusPlus) + return isDeclarationSpecifier(); // int X(f) int f; {} + return Tok.is(tok::colon) || // X() : Base() {} (used for ctors) + Tok.is(tok::kw_try); // X() try { ... } } /// ParseDeclarationOrFunctionDefinition - Parse either a function-definition or @@ -532,10 +534,10 @@ bool Parser::isStartOfFunctionDefinition() { /// [OMP] threadprivate-directive [TODO] /// Parser::DeclGroupPtrTy -Parser::ParseDeclarationOrFunctionDefinition(AttributeList *Attr, +Parser::ParseDeclarationOrFunctionDefinition(ParsingDeclSpec &DS, + AttributeList *Attr, AccessSpecifier AS) { // Parse the common declaration-specifiers piece. - ParsingDeclSpec DS(*this); if (Attr) DS.AddAttributes(Attr); @@ -584,13 +586,20 @@ Parser::ParseDeclarationOrFunctionDefinition(AttributeList *Attr, DS.getStorageClassSpec() == DeclSpec::SCS_extern && DS.getParsedSpecifiers() == DeclSpec::PQ_StorageClassSpecifier) { DS.abort(); - DeclPtrTy TheDecl = ParseLinkage(Declarator::FileContext); + DeclPtrTy TheDecl = ParseLinkage(DS, Declarator::FileContext); return Actions.ConvertDeclToDeclGroup(TheDecl); } return ParseDeclGroup(DS, Declarator::FileContext, true); } +Parser::DeclGroupPtrTy +Parser::ParseDeclarationOrFunctionDefinition(AttributeList *Attr, + AccessSpecifier AS) { + ParsingDeclSpec DS(*this); + return ParseDeclarationOrFunctionDefinition(DS, Attr, AS); +} + /// ParseFunctionDefinition - We parsed and verified that the specified /// Declarator is well formed. If this is a K&R-style function, read the /// parameters declaration-list, then start the compound-statement. @@ -1029,7 +1038,9 @@ bool Parser::TryAnnotateCXXScopeToken(bool EnteringContext) { CXXScopeSpec SS; if (!ParseOptionalCXXScopeSpecifier(SS, /*ObjectType=*/0, EnteringContext)) - return Tok.is(tok::annot_template_id); + // If the token left behind is not an identifier, we either had an error or + // successfully turned it into an annotation token. + return Tok.isNot(tok::identifier); // Push the current token back into the token stream (or revert it if it is // cached) and use an annotation scope token for current token. diff --git a/lib/Parse/RAIIObjectsForParser.h b/lib/Parse/RAIIObjectsForParser.h new file mode 100644 index 000000000000..06bbbc23a010 --- /dev/null +++ b/lib/Parse/RAIIObjectsForParser.h @@ -0,0 +1,85 @@ +//===--- RAIIObjectsForParser.h - RAII helpers for the parser ---*- 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 and implements the some simple RAII objects that are used +// by the parser to manage bits in recursion. +// +//===----------------------------------------------------------------------===// + +#ifndef LLVM_CLANG_PARSE_RAII_OBJECTS_FOR_PARSER_H +#define LLVM_CLANG_PARSE_RAII_OBJECTS_FOR_PARSER_H + +#include "clang/Parse/ParseDiagnostic.h" + +namespace clang { + // TODO: move ParsingDeclRAIIObject here. + // TODO: move ParsingClassDefinition here. + // TODO: move TentativeParsingAction here. + + + /// ExtensionRAIIObject - This saves the state of extension warnings when + /// constructed and disables them. When destructed, it restores them back to + /// the way they used to be. This is used to handle __extension__ in the + /// parser. + class ExtensionRAIIObject { + void operator=(const ExtensionRAIIObject &); // DO NOT IMPLEMENT + ExtensionRAIIObject(const ExtensionRAIIObject&); // DO NOT IMPLEMENT + Diagnostic &Diags; + public: + ExtensionRAIIObject(Diagnostic &diags) : Diags(diags) { + Diags.IncrementAllExtensionsSilenced(); + } + + ~ExtensionRAIIObject() { + Diags.DecrementAllExtensionsSilenced(); + } + }; + + /// ColonProtectionRAIIObject - This sets the Parser::ColonIsSacred bool and + /// restores it when destroyed. This says that "foo:" should not be + /// considered a possible typo for "foo::" for error recovery purposes. + class ColonProtectionRAIIObject { + Parser &P; + bool OldVal; + public: + ColonProtectionRAIIObject(Parser &p, bool Value = true) + : P(p), OldVal(P.ColonIsSacred) { + P.ColonIsSacred = Value; + } + + /// restore - This can be used to restore the state early, before the dtor + /// is run. + void restore() { + P.ColonIsSacred = OldVal; + } + + ~ColonProtectionRAIIObject() { + restore(); + } + }; + + /// \brief RAII object that makes '>' behave either as an operator + /// or as the closing angle bracket for a template argument list. + class GreaterThanIsOperatorScope { + bool &GreaterThanIsOperator; + bool OldGreaterThanIsOperator; + public: + GreaterThanIsOperatorScope(bool >IO, bool Val) + : GreaterThanIsOperator(GTIO), OldGreaterThanIsOperator(GTIO) { + GreaterThanIsOperator = Val; + } + + ~GreaterThanIsOperatorScope() { + GreaterThanIsOperator = OldGreaterThanIsOperator; + } + }; + +} // end namespace clang + +#endif diff --git a/lib/Sema/CodeCompleteConsumer.cpp b/lib/Sema/CodeCompleteConsumer.cpp index 91b16d3774d4..d8ed8949cb5d 100644 --- a/lib/Sema/CodeCompleteConsumer.cpp +++ b/lib/Sema/CodeCompleteConsumer.cpp @@ -46,7 +46,7 @@ CodeCompletionString::Chunk::Chunk(ChunkKind Kind, llvm::StringRef Text) } case CK_Optional: - llvm::llvm_unreachable("Optional strings cannot be created from text"); + llvm_unreachable("Optional strings cannot be created from text"); break; case CK_LeftParen: diff --git a/lib/Sema/Lookup.h b/lib/Sema/Lookup.h index e2134a2683d6..78f79eac2ba1 100644 --- a/lib/Sema/Lookup.h +++ b/lib/Sema/Lookup.h @@ -26,13 +26,6 @@ namespace clang { /// a single declaration, a set of overloaded functions, or an /// ambiguity. Use the getKind() method to determine which of these /// results occurred for a given lookup. -/// -/// Any non-ambiguous lookup can be converted into a single -/// (possibly NULL) @c NamedDecl* via the getAsSingleDecl() method. -/// This permits the common-case usage in C and Objective-C where -/// name lookup will always return a single declaration. Use of -/// this is largely deprecated; callers should handle the possibility -/// of multiple declarations. class LookupResult { public: enum LookupResultKind { @@ -40,12 +33,11 @@ class LookupResult { NotFound = 0, /// @brief Name lookup found a single declaration that met the - /// criteria. getAsDecl will return this declaration. + /// criteria. getFoundDecl() will return this declaration. Found, /// @brief Name lookup found a set of overloaded functions that - /// met the criteria. getAsDecl will turn this set of overloaded - /// functions into an OverloadedFunctionDecl. + /// met the criteria. FoundOverloaded, /// @brief Name lookup found an unresolvable value declaration @@ -282,13 +274,6 @@ class LookupResult { } } - /// \brief Fetch this as an unambiguous single declaration - /// (possibly an overloaded one). - /// - /// This is deprecated; users should be written to handle - /// ambiguous and overloaded lookups. - NamedDecl *getAsSingleDecl(ASTContext &Context) const; - template DeclClass *getAsSingle() const { if (getResultKind() != Found) return 0; diff --git a/lib/Sema/ParseAST.cpp b/lib/Sema/ParseAST.cpp index 7c7df4bb61b4..898b3c230e87 100644 --- a/lib/Sema/ParseAST.cpp +++ b/lib/Sema/ParseAST.cpp @@ -75,7 +75,7 @@ void clang::ParseAST(Preprocessor &PP, ASTConsumer *Consumer, while ((ADecl = P.RetrievePendingObjCImpDecl())) Consumer->HandleTopLevelDecl(ADecl.getAsVal()); - // process any TopLevelDecls generated by #pragma weak + // Process any TopLevelDecls generated by #pragma weak. for (llvm::SmallVector::iterator I = S.WeakTopLevelDecls().begin(), E = S.WeakTopLevelDecls().end(); I != E; ++I) @@ -83,6 +83,13 @@ void clang::ParseAST(Preprocessor &PP, ASTConsumer *Consumer, Consumer->HandleTranslationUnit(Ctx); + if (ExternalSemaSource *ESS = + dyn_cast_or_null(Ctx.getExternalSource())) + ESS->ForgetSema(); + + if (SemaConsumer *SC = dyn_cast(Consumer)) + SC->ForgetSema(); + if (PrintStats) { fprintf(stderr, "\nSTATISTICS:\n"); P.getActions().PrintStats(); diff --git a/lib/Sema/Sema.cpp b/lib/Sema/Sema.cpp index f0812bfe7fdb..ef6147420bed 100644 --- a/lib/Sema/Sema.cpp +++ b/lib/Sema/Sema.cpp @@ -278,20 +278,20 @@ void Sema::ActOnTranslationUnitScope(SourceLocation Loc, Scope *S) { PushDeclContext(S, Context.getTranslationUnitDecl()); if (PP.getTargetInfo().getPointerWidth(0) >= 64) { - DeclaratorInfo *DInfo; + TypeSourceInfo *TInfo; // Install [u]int128_t for 64-bit targets. - DInfo = Context.getTrivialDeclaratorInfo(Context.Int128Ty); + TInfo = Context.getTrivialTypeSourceInfo(Context.Int128Ty); PushOnScopeChains(TypedefDecl::Create(Context, CurContext, SourceLocation(), &Context.Idents.get("__int128_t"), - DInfo), TUScope); + TInfo), TUScope); - DInfo = Context.getTrivialDeclaratorInfo(Context.UnsignedInt128Ty); + TInfo = Context.getTrivialTypeSourceInfo(Context.UnsignedInt128Ty); PushOnScopeChains(TypedefDecl::Create(Context, CurContext, SourceLocation(), &Context.Idents.get("__uint128_t"), - DInfo), TUScope); + TInfo), TUScope); } @@ -301,7 +301,7 @@ void Sema::ActOnTranslationUnitScope(SourceLocation Loc, Scope *S) { if (Context.getObjCSelType().isNull()) { // Create the built-in typedef for 'SEL'. QualType SelT = Context.getPointerType(Context.ObjCBuiltinSelTy); - DeclaratorInfo *SelInfo = Context.getTrivialDeclaratorInfo(SelT); + TypeSourceInfo *SelInfo = Context.getTrivialTypeSourceInfo(SelT); TypedefDecl *SelTypedef = TypedefDecl::Create(Context, CurContext, SourceLocation(), &Context.Idents.get("SEL"), SelInfo); @@ -322,7 +322,7 @@ void Sema::ActOnTranslationUnitScope(SourceLocation Loc, Scope *S) { // Create the built-in typedef for 'id'. if (Context.getObjCIdType().isNull()) { QualType IdT = Context.getObjCObjectPointerType(Context.ObjCBuiltinIdTy); - DeclaratorInfo *IdInfo = Context.getTrivialDeclaratorInfo(IdT); + TypeSourceInfo *IdInfo = Context.getTrivialTypeSourceInfo(IdT); TypedefDecl *IdTypedef = TypedefDecl::Create(Context, CurContext, SourceLocation(), &Context.Idents.get("id"), IdInfo); @@ -334,7 +334,7 @@ void Sema::ActOnTranslationUnitScope(SourceLocation Loc, Scope *S) { if (Context.getObjCClassType().isNull()) { QualType ClassType = Context.getObjCObjectPointerType(Context.ObjCBuiltinClassTy); - DeclaratorInfo *ClassInfo = Context.getTrivialDeclaratorInfo(ClassType); + TypeSourceInfo *ClassInfo = Context.getTrivialTypeSourceInfo(ClassType); TypedefDecl *ClassTypedef = TypedefDecl::Create(Context, CurContext, SourceLocation(), &Context.Idents.get("Class"), ClassInfo); @@ -728,18 +728,27 @@ void Sema::DeleteStmt(StmtTy *S) { /// translation unit when EOF is reached and all but the top-level scope is /// popped. void Sema::ActOnEndOfTranslationUnit() { - // C++: Perform implicit template instantiations. - // - // FIXME: When we perform these implicit instantiations, we do not carefully - // keep track of the point of instantiation (C++ [temp.point]). This means - // that name lookup that occurs within the template instantiation will - // always happen at the end of the translation unit, so it will find - // some names that should not be found. Although this is common behavior - // for C++ compilers, it is technically wrong. In the future, we either need - // to be able to filter the results of name lookup or we need to perform - // template instantiations earlier. - PerformPendingImplicitInstantiations(); - + + while (1) { + // C++: Perform implicit template instantiations. + // + // FIXME: When we perform these implicit instantiations, we do not carefully + // keep track of the point of instantiation (C++ [temp.point]). This means + // that name lookup that occurs within the template instantiation will + // always happen at the end of the translation unit, so it will find + // some names that should not be found. Although this is common behavior + // for C++ compilers, it is technically wrong. In the future, we either need + // to be able to filter the results of name lookup or we need to perform + // template instantiations earlier. + PerformPendingImplicitInstantiations(); + + /// If ProcessPendingClassesWithUnmarkedVirtualMembers ends up marking + /// any virtual member functions it might lead to more pending template + /// instantiations, which is why we need to loop here. + if (!ProcessPendingClassesWithUnmarkedVirtualMembers()) + break; + } + // Check for #pragma weak identifiers that were never declared // FIXME: This will cause diagnostics to be emitted in a non-determinstic // order! Iterating over a densemap like this is bad. diff --git a/lib/Sema/Sema.h b/lib/Sema/Sema.h index b594eceaf3c6..ada8aa157a40 100644 --- a/lib/Sema/Sema.h +++ b/lib/Sema/Sema.h @@ -32,6 +32,7 @@ #include "llvm/ADT/OwningPtr.h" #include #include +#include #include #include @@ -94,7 +95,10 @@ namespace clang { class CXXBasePaths; class CXXTemporary; class LookupResult; - + class InitializedEntity; + class InitializationKind; + class InitializationSequence; + /// BlockSemaInfo - When a block is being parsed, this contains information /// about the block. It is pointed to from Sema::CurBlock. struct BlockSemaInfo { @@ -131,7 +135,7 @@ struct BlockSemaInfo { BlockSemaInfo *PrevBlockInfo; }; -/// \brief Holds a QualType and a DeclaratorInfo* that came out of a declarator +/// \brief Holds a QualType and a TypeSourceInfo* that came out of a declarator /// parsing. /// /// LocInfoType is a "transient" type, only needed for passing to/from Parser @@ -144,17 +148,17 @@ class LocInfoType : public Type { LocInfo = (1 << TypeClassBitSize) - 1 }; - DeclaratorInfo *DeclInfo; + TypeSourceInfo *DeclInfo; - LocInfoType(QualType ty, DeclaratorInfo *DInfo) - : Type((TypeClass)LocInfo, ty, ty->isDependentType()), DeclInfo(DInfo) { + LocInfoType(QualType ty, TypeSourceInfo *TInfo) + : Type((TypeClass)LocInfo, ty, ty->isDependentType()), DeclInfo(TInfo) { assert(getTypeClass() == (TypeClass)LocInfo && "LocInfo didn't fit in TC?"); } friend class Sema; public: QualType getType() const { return getCanonicalTypeInternal(); } - DeclaratorInfo *getDeclaratorInfo() const { return DeclInfo; } + TypeSourceInfo *getTypeSourceInfo() const { return DeclInfo; } virtual void getAsStringInternal(std::string &Str, const PrintingPolicy &Policy) const; @@ -335,6 +339,10 @@ class Sema : public Action { typedef std::vector > PotentiallyReferencedDecls; + /// \brief A set of diagnostics that may be emitted. + typedef std::vector > + PotentiallyEmittedDiagnostics; + /// \brief Data structure used to record current or nested /// expression evaluation contexts. struct ExpressionEvaluationContextRecord { @@ -354,10 +362,14 @@ class Sema : public Action { /// evaluated. PotentiallyReferencedDecls *PotentiallyReferenced; + /// \brief The set of diagnostics to emit should this potentially + /// potentially-evaluated context become evaluated. + PotentiallyEmittedDiagnostics *PotentiallyDiagnosed; + ExpressionEvaluationContextRecord(ExpressionEvaluationContext Context, unsigned NumTemporaries) : Context(Context), NumTemporaries(NumTemporaries), - PotentiallyReferenced(0) { } + PotentiallyReferenced(0), PotentiallyDiagnosed(0) { } void addReferencedDecl(SourceLocation Loc, Decl *Decl) { if (!PotentiallyReferenced) @@ -365,9 +377,17 @@ class Sema : public Action { PotentiallyReferenced->push_back(std::make_pair(Loc, Decl)); } + void addDiagnostic(SourceLocation Loc, const PartialDiagnostic &PD) { + if (!PotentiallyDiagnosed) + PotentiallyDiagnosed = new PotentiallyEmittedDiagnostics; + PotentiallyDiagnosed->push_back(std::make_pair(Loc, PD)); + } + void Destroy() { delete PotentiallyReferenced; + delete PotentiallyDiagnosed; PotentiallyReferenced = 0; + PotentiallyDiagnosed = 0; } }; @@ -517,14 +537,14 @@ class Sema : public Action { QualType BuildBlockPointerType(QualType T, unsigned Quals, SourceLocation Loc, DeclarationName Entity); QualType GetTypeForDeclarator(Declarator &D, Scope *S, - DeclaratorInfo **DInfo = 0, + TypeSourceInfo **TInfo = 0, TagDecl **OwnedDecl = 0); - DeclaratorInfo *GetDeclaratorInfoForDeclarator(Declarator &D, QualType T); - /// \brief Create a LocInfoType to hold the given QualType and DeclaratorInfo. - QualType CreateLocInfoType(QualType T, DeclaratorInfo *DInfo); + TypeSourceInfo *GetTypeSourceInfoForDeclarator(Declarator &D, QualType T); + /// \brief Create a LocInfoType to hold the given QualType and TypeSourceInfo. + QualType CreateLocInfoType(QualType T, TypeSourceInfo *TInfo); DeclarationName GetNameForDeclarator(Declarator &D); DeclarationName GetNameFromUnqualifiedId(const UnqualifiedId &Name); - static QualType GetTypeFromParser(TypeTy *Ty, DeclaratorInfo **DInfo = 0); + static QualType GetTypeFromParser(TypeTy *Ty, TypeSourceInfo **TInfo = 0); bool CheckSpecifiedExceptionType(QualType T, const SourceRange &Range); bool CheckDistantExceptionSpec(QualType T); bool CheckEquivalentExceptionSpec( @@ -596,23 +616,24 @@ class Sema : public Action { SourceLocation NameLoc, unsigned Diagnostic); NamedDecl* ActOnTypedefDeclarator(Scope* S, Declarator& D, DeclContext* DC, - QualType R, DeclaratorInfo *DInfo, + QualType R, TypeSourceInfo *TInfo, LookupResult &Previous, bool &Redeclaration); NamedDecl* ActOnVariableDeclarator(Scope* S, Declarator& D, DeclContext* DC, - QualType R, DeclaratorInfo *DInfo, + QualType R, TypeSourceInfo *TInfo, LookupResult &Previous, MultiTemplateParamsArg TemplateParamLists, bool &Redeclaration); void CheckVariableDeclaration(VarDecl *NewVD, LookupResult &Previous, bool &Redeclaration); NamedDecl* ActOnFunctionDeclarator(Scope* S, Declarator& D, DeclContext* DC, - QualType R, DeclaratorInfo *DInfo, + QualType R, TypeSourceInfo *TInfo, LookupResult &Previous, MultiTemplateParamsArg TemplateParamLists, bool IsFunctionDefinition, bool &Redeclaration); void AddOverriddenMethods(CXXRecordDecl *DC, CXXMethodDecl *MD); - void CheckFunctionDeclaration(FunctionDecl *NewFD, LookupResult &Previous, + void CheckFunctionDeclaration(Scope *S, + FunctionDecl *NewFD, LookupResult &Previous, bool IsExplicitSpecialization, bool &Redeclaration, bool &OverloadableAttrRequired); @@ -710,7 +731,7 @@ class Sema : public Action { AccessSpecifier AS); FieldDecl *CheckFieldDecl(DeclarationName Name, QualType T, - DeclaratorInfo *DInfo, + TypeSourceInfo *TInfo, RecordDecl *Record, SourceLocation Loc, bool Mutable, Expr *BitfieldWidth, SourceLocation TSSL, @@ -811,19 +832,9 @@ class Sema : public Action { return NULL; } - /// OverloadingResult - Capture the result of performing overload - /// resolution. - enum OverloadingResult { - OR_Success, ///< Overload resolution succeeded. - OR_No_Viable_Function, ///< No viable function found. - OR_Ambiguous, ///< Ambiguous candidates found. - OR_Deleted ///< Overload resoltuion refers to a deleted function. - }; - - /// Subroutines of ActOnDeclarator(). TypedefDecl *ParseTypedefDecl(Scope *S, Declarator &D, QualType T, - DeclaratorInfo *DInfo); + TypeSourceInfo *TInfo); void MergeTypeDefDecl(TypedefDecl *New, LookupResult &OldDecls); bool MergeFunctionDecl(FunctionDecl *New, Decl *Old); bool MergeCompatibleFunctionDecls(FunctionDecl *New, FunctionDecl *Old); @@ -831,8 +842,22 @@ class Sema : public Action { bool MergeCXXFunctionDecl(FunctionDecl *New, FunctionDecl *Old); /// C++ Overloading. - bool IsOverload(FunctionDecl *New, LookupResult &OldDecls, - NamedDecl *&OldDecl); + enum OverloadKind { + /// This is a legitimate overload: the existing declarations are + /// functions or function templates with different signatures. + Ovl_Overload, + + /// This is not an overload because the signature exactly matches + /// an existing declaration. + Ovl_Match, + + /// This is not an overload because the lookup results contain a + /// non-function. + Ovl_NonFunction + }; + OverloadKind CheckOverload(FunctionDecl *New, + const LookupResult &OldDecls, + NamedDecl *&OldDecl); bool IsOverload(FunctionDecl *New, FunctionDecl *Old); ImplicitConversionSequence @@ -896,7 +921,8 @@ class Sema : public Action { const char *Flavor, bool Elidable = false); ImplicitConversionSequence - TryObjectArgumentInitialization(Expr *From, CXXMethodDecl *Method); + TryObjectArgumentInitialization(QualType FromType, CXXMethodDecl *Method, + CXXRecordDecl *ActingContext); bool PerformObjectArgumentInitialization(Expr *&From, CXXMethodDecl *Method); ImplicitConversionSequence TryContextuallyConvertToBool(Expr *From); @@ -922,18 +948,20 @@ class Sema : public Action { OverloadCandidateSet& CandidateSet, bool SuppressUserConversions = false); void AddMethodCandidate(NamedDecl *Decl, - Expr *Object, Expr **Args, unsigned NumArgs, + QualType ObjectType, Expr **Args, unsigned NumArgs, OverloadCandidateSet& CandidateSet, bool SuppressUserConversion = false, bool ForceRValue = false); - void AddMethodCandidate(CXXMethodDecl *Method, - Expr *Object, Expr **Args, unsigned NumArgs, + void AddMethodCandidate(CXXMethodDecl *Method, CXXRecordDecl *ActingContext, + QualType ObjectType, Expr **Args, unsigned NumArgs, OverloadCandidateSet& CandidateSet, bool SuppressUserConversions = false, bool ForceRValue = false); void AddMethodTemplateCandidate(FunctionTemplateDecl *MethodTmpl, + CXXRecordDecl *ActingContext, const TemplateArgumentListInfo *ExplicitTemplateArgs, - Expr *Object, Expr **Args, unsigned NumArgs, + QualType ObjectType, + Expr **Args, unsigned NumArgs, OverloadCandidateSet& CandidateSet, bool SuppressUserConversions = false, bool ForceRValue = false); @@ -944,14 +972,17 @@ class Sema : public Action { bool SuppressUserConversions = false, bool ForceRValue = false); void AddConversionCandidate(CXXConversionDecl *Conversion, + CXXRecordDecl *ActingContext, Expr *From, QualType ToType, OverloadCandidateSet& CandidateSet); void AddTemplateConversionCandidate(FunctionTemplateDecl *FunctionTemplate, + CXXRecordDecl *ActingContext, Expr *From, QualType ToType, OverloadCandidateSet &CandidateSet); void AddSurrogateCandidate(CXXConversionDecl *Conversion, + CXXRecordDecl *ActingContext, const FunctionProtoType *Proto, - Expr *Object, Expr **Args, unsigned NumArgs, + QualType ObjectTy, Expr **Args, unsigned NumArgs, OverloadCandidateSet& CandidateSet); void AddOperatorCandidates(OverloadedOperatorKind Op, Scope *S, SourceLocation OpLoc, @@ -990,6 +1021,8 @@ class Sema : public Action { FunctionDecl *ResolveAddressOfOverloadedFunction(Expr *From, QualType ToType, bool Complain); Expr *FixOverloadedFunctionReference(Expr *E, FunctionDecl *Fn); + OwningExprResult FixOverloadedFunctionReference(OwningExprResult, + FunctionDecl *Fn); void AddOverloadedCallCandidates(llvm::SmallVectorImpl& Callees, DeclarationName &UnqualifiedName, @@ -1023,7 +1056,7 @@ class Sema : public Action { SourceLocation RLoc, ExprArg Base,ExprArg Idx); - ExprResult + OwningExprResult BuildCallToMemberFunction(Scope *S, Expr *MemExpr, SourceLocation LParenLoc, Expr **Args, unsigned NumArgs, SourceLocation *CommaLocs, @@ -1107,6 +1140,10 @@ class Sema : public Action { /// namespace alias definition, ignoring non-namespace names (C++ /// [basic.lookup.udir]p1). LookupNamespaceName, + /// Look up all declarations in a scope with the given name, + /// including resolved using declarations. This is appropriate + /// for checking redeclarations for a using declaration. + LookupUsingDeclName, /// Look up an ordinary name that is going to be redeclared as a /// name with linkage. This lookup ignores any declarations that /// are outside of the current scope unless they have linkage. See @@ -1115,9 +1152,7 @@ class Sema : public Action { /// Look up the name of an Objective-C protocol. LookupObjCProtocolName, /// Look up the name of an Objective-C implementation - LookupObjCImplementationName, - /// Look up the name of an Objective-C category implementation - LookupObjCCategoryImplName + LookupObjCImplementationName }; enum RedeclarationKind { @@ -1138,9 +1173,9 @@ class Sema : public Action { case Sema::LookupTagName: case Sema::LookupMemberName: case Sema::LookupRedeclarationWithLinkage: // FIXME: check linkage, scoping + case Sema::LookupUsingDeclName: case Sema::LookupObjCProtocolName: case Sema::LookupObjCImplementationName: - case Sema::LookupObjCCategoryImplName: return D->isInIdentifierNamespace(IDNS); case Sema::LookupOperatorName: @@ -1160,7 +1195,7 @@ class Sema : public Action { } /// \brief Look up a name, looking for a single declaration. Return - /// null if no unambiguous results were found. + /// null if the results were absent, ambiguous, or overloaded. /// /// It is preferable to use the elaborated form and explicitly handle /// ambiguity and overloaded. @@ -1176,7 +1211,6 @@ class Sema : public Action { bool EnteringContext = false); ObjCProtocolDecl *LookupProtocol(IdentifierInfo *II); - ObjCCategoryImplDecl *LookupObjCCategoryImpl(IdentifierInfo *II); void LookupOverloadedOperatorName(OverloadedOperatorKind Op, Scope *S, QualType T1, QualType T2, @@ -1379,7 +1413,7 @@ class Sema : public Action { StmtArg SynchBody); VarDecl *BuildExceptionDeclaration(Scope *S, QualType ExDeclType, - DeclaratorInfo *DInfo, + TypeSourceInfo *TInfo, IdentifierInfo *Name, SourceLocation Loc, SourceRange Range); @@ -1438,10 +1472,10 @@ class Sema : public Action { OwningExprResult ActOnDependentIdExpression(const CXXScopeSpec &SS, DeclarationName Name, SourceLocation NameLoc, - bool CheckForImplicitMember, + bool isAddressOfOperand, const TemplateArgumentListInfo *TemplateArgs); - OwningExprResult BuildDeclRefExpr(NamedDecl *D, QualType Ty, + OwningExprResult BuildDeclRefExpr(ValueDecl *D, QualType Ty, SourceLocation Loc, const CXXScopeSpec *SS = 0); VarDecl *BuildAnonymousStructUnionMemberPath(FieldDecl *Field, @@ -1451,9 +1485,10 @@ class Sema : public Action { FieldDecl *Field, Expr *BaseObjectExpr = 0, SourceLocation OpLoc = SourceLocation()); - OwningExprResult BuildImplicitMemberReferenceExpr(const CXXScopeSpec &SS, - LookupResult &R, - const TemplateArgumentListInfo *TemplateArgs); + OwningExprResult BuildImplicitMemberExpr(const CXXScopeSpec &SS, + LookupResult &R, + const TemplateArgumentListInfo *TemplateArgs, + bool IsDefiniteInstance); bool UseArgumentDependentLookup(const CXXScopeSpec &SS, const LookupResult &R, bool HasTrailingLParen); @@ -1498,7 +1533,7 @@ class Sema : public Action { virtual OwningExprResult ActOnUnaryOp(Scope *S, SourceLocation OpLoc, tok::TokenKind Op, ExprArg Input); - OwningExprResult CreateSizeOfAlignOfExpr(DeclaratorInfo *T, + OwningExprResult CreateSizeOfAlignOfExpr(TypeSourceInfo *T, SourceLocation OpLoc, bool isSizeOf, SourceRange R); OwningExprResult CreateSizeOfAlignOfExpr(Expr *E, SourceLocation OpLoc, @@ -1525,6 +1560,7 @@ class Sema : public Action { SourceLocation RLoc); OwningExprResult BuildMemberReferenceExpr(ExprArg Base, + QualType BaseType, SourceLocation OpLoc, bool IsArrow, const CXXScopeSpec &SS, @@ -1534,23 +1570,24 @@ class Sema : public Action { const TemplateArgumentListInfo *TemplateArgs); OwningExprResult BuildMemberReferenceExpr(ExprArg Base, + QualType BaseType, SourceLocation OpLoc, bool IsArrow, const CXXScopeSpec &SS, LookupResult &R, const TemplateArgumentListInfo *TemplateArgs); OwningExprResult LookupMemberExpr(LookupResult &R, Expr *&Base, - bool IsArrow, SourceLocation OpLoc, + bool &IsArrow, SourceLocation OpLoc, const CXXScopeSpec &SS, NamedDecl *FirstQualifierInScope, DeclPtrTy ObjCImpDecl); bool CheckQualifiedMemberReference(Expr *BaseExpr, QualType BaseType, - NestedNameSpecifier *Qualifier, - SourceRange QualifierRange, + const CXXScopeSpec &SS, const LookupResult &R); OwningExprResult ActOnDependentMemberExpr(ExprArg Base, + QualType BaseType, bool IsArrow, SourceLocation OpLoc, const CXXScopeSpec &SS, @@ -1592,6 +1629,11 @@ class Sema : public Action { MultiExprArg Args, SourceLocation *CommaLocs, SourceLocation RParenLoc); + OwningExprResult BuildResolvedCallExpr(Expr *Fn, + NamedDecl *NDecl, + SourceLocation LParenLoc, + Expr **Args, unsigned NumArgs, + SourceLocation RParenLoc); virtual OwningExprResult ActOnCastExpr(Scope *S, SourceLocation LParenLoc, TypeTy *Ty, SourceLocation RParenLoc, @@ -1715,6 +1757,21 @@ class Sema : public Action { SourceLocation IdentLoc, IdentifierInfo *Ident); + void HideUsingShadowDecl(Scope *S, UsingShadowDecl *Shadow); + bool CheckUsingShadowDecl(UsingDecl *UD, NamedDecl *Target, + const LookupResult &PreviousDecls); + UsingShadowDecl *BuildUsingShadowDecl(Scope *S, UsingDecl *UD, + NamedDecl *Target); + + bool CheckUsingDeclRedeclaration(SourceLocation UsingLoc, + bool isTypeName, + const CXXScopeSpec &SS, + SourceLocation NameLoc, + const LookupResult &Previous); + bool CheckUsingDeclQualifier(SourceLocation UsingLoc, + const CXXScopeSpec &SS, + SourceLocation NameLoc); + NamedDecl *BuildUsingDeclaration(Scope *S, AccessSpecifier AS, SourceLocation UsingLoc, const CXXScopeSpec &SS, @@ -1727,6 +1784,7 @@ class Sema : public Action { virtual DeclPtrTy ActOnUsingDeclaration(Scope *CurScope, AccessSpecifier AS, + bool HasUsingKeyword, SourceLocation UsingLoc, const CXXScopeSpec &SS, UnqualifiedId &Name, @@ -1809,7 +1867,8 @@ class Sema : public Action { /// getAssignOperatorMethod - Returns the default copy assignmment operator /// for the class. - CXXMethodDecl *getAssignOperatorMethod(ParmVarDecl *Decl, + CXXMethodDecl *getAssignOperatorMethod(SourceLocation CurrentLocation, + ParmVarDecl *Decl, CXXRecordDecl *ClassDecl); /// MaybeBindToTemporary - If the passed in expression has a record type with @@ -1817,14 +1876,6 @@ class Sema : public Action { /// it simply returns the passed in expression. OwningExprResult MaybeBindToTemporary(Expr *E); - /// InitializationKind - Represents which kind of C++ initialization - /// [dcl.init] a routine is to perform. - enum InitializationKind { - IK_Direct, ///< Direct initialization - IK_Copy, ///< Copy initialization - IK_Default ///< Default initialization - }; - CXXConstructorDecl * TryInitializationByConstructor(QualType ClassType, Expr **Args, unsigned NumArgs, @@ -1982,7 +2033,8 @@ class Sema : public Action { IdentifierInfo &II, QualType ObjectType, NamedDecl *ScopeLookupResult, - bool EnteringContext); + bool EnteringContext, + bool ErrorRecoveryLookup); virtual CXXScopeTy *ActOnCXXNestedNameSpecifier(Scope *S, const CXXScopeSpec &SS, @@ -1992,6 +2044,12 @@ class Sema : public Action { TypeTy *ObjectType, bool EnteringContext); + virtual bool IsInvalidUnlessNestedName(Scope *S, + const CXXScopeSpec &SS, + IdentifierInfo &II, + TypeTy *ObjectType, + bool EnteringContext); + /// ActOnCXXNestedNameSpecifier - Called during parsing of a /// nested-name-specifier that involves a template-id, e.g., /// "foo::bar::", and now we need to build a scope @@ -2006,6 +2064,8 @@ class Sema : public Action { SourceRange TypeRange, SourceLocation CCLoc); + virtual bool ShouldEnterDeclaratorScope(Scope *S, const CXXScopeSpec &SS); + /// ActOnCXXEnterDeclaratorScope - Called when a C++ scope specifier (global /// scope or nested-name-specifier) is parsed, part of a declarator-id. /// After this method is called, according to [C++ 3.4.3p3], names should be @@ -2102,10 +2162,13 @@ class Sema : public Action { MemInitResult BuildMemberInitializer(FieldDecl *Member, Expr **Args, unsigned NumArgs, SourceLocation IdLoc, + SourceLocation LParenLoc, SourceLocation RParenLoc); - MemInitResult BuildBaseInitializer(QualType BaseType, Expr **Args, - unsigned NumArgs, SourceLocation IdLoc, + MemInitResult BuildBaseInitializer(QualType BaseType, + TypeSourceInfo *BaseTInfo, + Expr **Args, unsigned NumArgs, + SourceLocation LParenLoc, SourceLocation RParenLoc, CXXRecordDecl *ClassDecl); @@ -2119,12 +2182,34 @@ class Sema : public Action { /// as referenced. void MarkBaseAndMemberDestructorsReferenced(CXXDestructorDecl *Destructor); + /// ClassesWithUnmarkedVirtualMembers - Contains record decls whose virtual + /// members might need to be marked as referenced. This is either done when + /// the key function definition is emitted (this is handled by by + /// MaybeMarkVirtualMembersReferenced), or at the end of the translation unit + /// (done by ProcessPendingClassesWithUnmarkedVirtualMembers). + std::map ClassesWithUnmarkedVirtualMembers; + + /// MaybeMarkVirtualMembersReferenced - If the passed in method is the + /// key function of the record decl, will mark virtual member functions as + /// referenced. + void MaybeMarkVirtualMembersReferenced(SourceLocation Loc, CXXMethodDecl *MD); + + /// MarkVirtualMembersReferenced - Will mark all virtual members of the given + /// CXXRecordDecl referenced. + void MarkVirtualMembersReferenced(SourceLocation Loc, CXXRecordDecl *RD); + + /// ProcessPendingClassesWithUnmarkedVirtualMembers - Will process classes + /// that might need to have their virtual members marked as referenced. + /// Returns false if no work was done. + bool ProcessPendingClassesWithUnmarkedVirtualMembers(); + void AddImplicitlyDeclaredMembersToClass(CXXRecordDecl *ClassDecl); virtual void ActOnMemInitializers(DeclPtrTy ConstructorDecl, SourceLocation ColonLoc, MemInitTy **MemInits, unsigned NumMemInits); + void CheckCompletedCXXClass(CXXRecordDecl *Record); virtual void ActOnFinishCXXMemberSpecification(Scope* S, SourceLocation RLoc, DeclPtrTy TagDecl, SourceLocation LBrac, @@ -2168,6 +2253,14 @@ class Sema : public Action { bool Virtual, AccessSpecifier Access, QualType BaseType, SourceLocation BaseLoc); + + /// SetClassDeclAttributesFromBase - Copies class decl traits + /// (such as whether the class has a trivial constructor, + /// trivial destructor etc) from the given base class. + void SetClassDeclAttributesFromBase(CXXRecordDecl *Class, + const CXXRecordDecl *BaseClass, + bool BaseIsVirtual); + virtual BaseResult ActOnBaseSpecifier(DeclPtrTy classdecl, SourceRange SpecifierRange, bool Virtual, AccessSpecifier Access, @@ -2208,6 +2301,7 @@ class Sema : public Action { bool CheckOverridingFunctionAttributes(const CXXMethodDecl *New, const CXXMethodDecl *Old); + bool CheckPureMethod(CXXMethodDecl *Method, SourceRange InitRange); //===--------------------------------------------------------------------===// // C++ Access Control // @@ -2452,7 +2546,7 @@ class Sema : public Action { TemplateArgumentListBuilder &Converted); bool CheckTemplateArgument(TemplateTypeParmDecl *Param, - DeclaratorInfo *Arg); + TypeSourceInfo *Arg); bool CheckTemplateArgumentAddressOfObjectOrFunction(Expr *Arg, NamedDecl *&Entity); bool CheckTemplateArgumentPointerToMember(Expr *Arg, @@ -3084,7 +3178,7 @@ class Sema : public Action { void PerformPendingImplicitInstantiations(); - DeclaratorInfo *SubstType(DeclaratorInfo *T, + TypeSourceInfo *SubstType(TypeSourceInfo *T, const MultiLevelTemplateArgumentList &TemplateArgs, SourceLocation Loc, DeclarationName Entity); @@ -3490,6 +3584,9 @@ class Sema : public Action { AssignConvertType CheckPointerTypesForAssignment(QualType lhsType, QualType rhsType); + AssignConvertType CheckObjCPointerTypesForAssignment(QualType lhsType, + QualType rhsType); + // Helper function for CheckAssignmentConstraints involving two // block pointer types. AssignConvertType CheckBlockPointerTypesForAssignment(QualType lhsType, @@ -3556,6 +3653,9 @@ class Sema : public Action { Expr *&cond, Expr *&lhs, Expr *&rhs, SourceLocation questionLoc); QualType FindCompositePointerType(Expr *&E1, Expr *&E2); // C++ 5.9 + QualType FindCompositeObjCPointerType(Expr *&LHS, Expr *&RHS, + SourceLocation questionLoc); + /// type checking for vector binary operators. inline QualType CheckVectorOperands(SourceLocation l, Expr *&lex, Expr *&rex); inline QualType CheckVectorCompareOperands(Expr *&lex, Expr *&rx, @@ -3718,6 +3818,10 @@ class Sema : public Action { virtual void CodeCompleteNamespaceAliasDecl(Scope *S); virtual void CodeCompleteOperatorName(Scope *S); + virtual void CodeCompleteObjCAtDirective(Scope *S, DeclPtrTy ObjCImpDecl, + bool InInterface); + virtual void CodeCompleteObjCAtStatement(Scope *S); + virtual void CodeCompleteObjCAtExpression(Scope *S); virtual void CodeCompleteObjCPropertyFlags(Scope *S, ObjCDeclSpec &ODS); virtual void CodeCompleteObjCPropertyGetter(Scope *S, DeclPtrTy ClassDecl, DeclPtrTy *Methods, diff --git a/lib/Sema/SemaAttr.cpp b/lib/Sema/SemaAttr.cpp index 5769716b33ea..095f537f7102 100644 --- a/lib/Sema/SemaAttr.cpp +++ b/lib/Sema/SemaAttr.cpp @@ -183,20 +183,19 @@ void Sema::ActOnPragmaUnused(const Token *Identifiers, unsigned NumIdentifiers, LookupResult Lookup(*this, Name, Tok.getLocation(), LookupOrdinaryName); LookupParsedName(Lookup, curScope, NULL, true); - NamedDecl *ND = Lookup.getAsSingleDecl(Context); - - if (!ND) { + if (Lookup.empty()) { Diag(PragmaLoc, diag::warn_pragma_unused_undeclared_var) << Name << SourceRange(Tok.getLocation()); continue; } - if (!isa(ND) || !cast(ND)->hasLocalStorage()) { + VarDecl *VD = Lookup.getAsSingle(); + if (!VD || !VD->hasLocalStorage()) { Diag(PragmaLoc, diag::warn_pragma_unused_expected_localvar) << Name << SourceRange(Tok.getLocation()); continue; } - ND->addAttr(::new (Context) UnusedAttr()); + VD->addAttr(::new (Context) UnusedAttr()); } } diff --git a/lib/Sema/SemaCXXCast.cpp b/lib/Sema/SemaCXXCast.cpp index 6b4f87ef1dfb..814af9080d84 100644 --- a/lib/Sema/SemaCXXCast.cpp +++ b/lib/Sema/SemaCXXCast.cpp @@ -12,6 +12,7 @@ //===----------------------------------------------------------------------===// #include "Sema.h" +#include "SemaInit.h" #include "clang/AST/ExprCXX.h" #include "clang/AST/ASTContext.h" #include "clang/AST/CXXInheritance.h" @@ -539,6 +540,16 @@ static TryCastResult TryStaticCast(Sema &Self, Expr *&SrcExpr, return TC_Success; } } + else if (CStyle && DestType->isObjCObjectPointerType()) { + // allow c-style cast of objective-c pointers as they are pervasive. + Kind = CastExpr::CK_AnyPointerToObjCPointerCast; + return TC_Success; + } + else if (CStyle && DestType->isBlockPointerType()) { + // allow c-style cast of void * to block pointers. + Kind = CastExpr::CK_AnyPointerToBlockPointerCast; + return TC_Success; + } } } @@ -859,7 +870,9 @@ TryStaticImplicitCast(Sema &Self, Expr *&SrcExpr, QualType DestType, if (CXXConstructorDecl *Constructor = Self.TryInitializationByConstructor(DestType, &SrcExpr, 1, OpRange.getBegin(), - Sema::IK_Direct)) { + InitializationKind::CreateDirect(OpRange.getBegin(), + OpRange.getBegin(), + OpRange.getEnd()))) { ConversionDecl = Constructor; Kind = CastExpr::CK_ConstructorConversion; return TC_Success; @@ -1053,8 +1066,10 @@ static TryCastResult TryReinterpretCast(Sema &Self, Expr *SrcExpr, return TC_Failed; } - bool destIsPtr = DestType->isPointerType(); - bool srcIsPtr = SrcType->isPointerType(); + bool destIsPtr = + CStyle? DestType->isAnyPointerType() : DestType->isPointerType(); + bool srcIsPtr = + CStyle ? SrcType->isAnyPointerType() : SrcType->isPointerType(); if (!destIsPtr && !srcIsPtr) { // Except for std::nullptr_t->integer and lvalue->reference, which are // handled above, at least one of the two arguments must be a pointer. @@ -1106,7 +1121,11 @@ static TryCastResult TryReinterpretCast(Sema &Self, Expr *SrcExpr, msg = diag::err_bad_cxx_cast_const_away; return TC_Failed; } - + if (CStyle && DestType->isObjCObjectPointerType()) { + Kind = CastExpr::CK_AnyPointerToObjCPointerCast; + return TC_Success; + } + // Not casting away constness, so the only remaining check is for compatible // pointer categories. Kind = CastExpr::CK_BitCast; @@ -1141,7 +1160,6 @@ static TryCastResult TryReinterpretCast(Sema &Self, Expr *SrcExpr, // Void pointers are not specified, but supported by every compiler out there. // So we finish by allowing everything that remains - it's got to be two // object pointers. - Kind = CastExpr::CK_BitCast; return TC_Success; } diff --git a/lib/Sema/SemaCXXScopeSpec.cpp b/lib/Sema/SemaCXXScopeSpec.cpp index 34a5b784d49b..039691f122f9 100644 --- a/lib/Sema/SemaCXXScopeSpec.cpp +++ b/lib/Sema/SemaCXXScopeSpec.cpp @@ -313,7 +313,10 @@ NamedDecl *Sema::FindFirstQualifierInScope(Scope *S, NestedNameSpecifier *NNS) { LookupName(Found, S); assert(!Found.isAmbiguous() && "Cannot handle ambiguities here yet"); - NamedDecl *Result = Found.getAsSingleDecl(Context); + if (!Found.isSingleResult()) + return 0; + + NamedDecl *Result = Found.getFoundDecl(); if (isAcceptableNestedNameSpecifier(Result)) return Result; @@ -327,6 +330,12 @@ NamedDecl *Sema::FindFirstQualifierInScope(Scope *S, NestedNameSpecifier *NNS) { /// that it contains an extra parameter \p ScopeLookupResult, which provides /// the result of name lookup within the scope of the nested-name-specifier /// that was computed at template definitino time. +/// +/// If ErrorRecoveryLookup is true, then this call is used to improve error +/// recovery. This means that it should not emit diagnostics, it should +/// just return null on failure. It also means it should only return a valid +/// scope if it *knows* that the result is correct. It should not return in a +/// dependent context, for example. Sema::CXXScopeTy *Sema::BuildCXXNestedNameSpecifier(Scope *S, const CXXScopeSpec &SS, SourceLocation IdLoc, @@ -334,7 +343,8 @@ Sema::CXXScopeTy *Sema::BuildCXXNestedNameSpecifier(Scope *S, IdentifierInfo &II, QualType ObjectType, NamedDecl *ScopeLookupResult, - bool EnteringContext) { + bool EnteringContext, + bool ErrorRecoveryLookup) { NestedNameSpecifier *Prefix = static_cast(SS.getScopeRep()); @@ -400,6 +410,10 @@ Sema::CXXScopeTy *Sema::BuildCXXNestedNameSpecifier(Scope *S, ObjectTypeSearchedInScope = true; } } else if (isDependent) { + // Don't speculate if we're just trying to improve error recovery. + if (ErrorRecoveryLookup) + return 0; + // We were not able to compute the declaration context for a dependent // base object type or prior nested-name-specifier, so this // nested-name-specifier refers to an unknown specialization. Just build @@ -414,7 +428,7 @@ Sema::CXXScopeTy *Sema::BuildCXXNestedNameSpecifier(Scope *S, } // FIXME: Deal with ambiguities cleanly. - NamedDecl *SD = Found.getAsSingleDecl(Context); + NamedDecl *SD = Found.getAsSingle(); if (isAcceptableNestedNameSpecifier(SD)) { if (!ObjectType.isNull() && !ObjectTypeSearchedInScope) { // C++ [basic.lookup.classref]p4: @@ -429,7 +443,7 @@ Sema::CXXScopeTy *Sema::BuildCXXNestedNameSpecifier(Scope *S, if (S) { LookupResult FoundOuter(*this, &II, IdLoc, LookupNestedNameSpecifierName); LookupName(FoundOuter, S); - OuterDecl = FoundOuter.getAsSingleDecl(Context); + OuterDecl = FoundOuter.getAsSingle(); } else OuterDecl = ScopeLookupResult; @@ -439,14 +453,17 @@ Sema::CXXScopeTy *Sema::BuildCXXNestedNameSpecifier(Scope *S, !Context.hasSameType( Context.getTypeDeclType(cast(OuterDecl)), Context.getTypeDeclType(cast(SD))))) { + if (ErrorRecoveryLookup) + return 0; + Diag(IdLoc, diag::err_nested_name_member_ref_lookup_ambiguous) << &II; Diag(SD->getLocation(), diag::note_ambig_member_ref_object_type) << ObjectType; Diag(OuterDecl->getLocation(), diag::note_ambig_member_ref_scope); - // Fall through so that we'll pick the name we found in the object type, - // since that's probably what the user wanted anyway. + // Fall through so that we'll pick the name we found in the object + // type, since that's probably what the user wanted anyway. } } @@ -466,17 +483,21 @@ Sema::CXXScopeTy *Sema::BuildCXXNestedNameSpecifier(Scope *S, T.getTypePtr()); } + // Otherwise, we have an error case. If we don't want diagnostics, just + // return an error now. + if (ErrorRecoveryLookup) + return 0; + // If we didn't find anything during our lookup, try again with // ordinary name lookup, which can help us produce better error // messages. - if (!SD) { + if (Found.empty()) { Found.clear(LookupOrdinaryName); LookupName(Found, S); - SD = Found.getAsSingleDecl(Context); } unsigned DiagID; - if (SD) + if (!Found.empty()) DiagID = diag::err_expected_class_or_namespace; else if (SS.isSet()) { Diag(IdLoc, diag::err_no_member) << &II << LookupCtx << SS.getRange(); @@ -507,7 +528,23 @@ Sema::CXXScopeTy *Sema::ActOnCXXNestedNameSpecifier(Scope *S, bool EnteringContext) { return BuildCXXNestedNameSpecifier(S, SS, IdLoc, CCLoc, II, QualType::getFromOpaquePtr(ObjectTypePtr), - /*ScopeLookupResult=*/0, EnteringContext); + /*ScopeLookupResult=*/0, EnteringContext, + false); +} + +/// IsInvalidUnlessNestedName - This method is used for error recovery +/// purposes to determine whether the specified identifier is only valid as +/// a nested name specifier, for example a namespace name. It is +/// conservatively correct to always return false from this method. +/// +/// The arguments are the same as those passed to ActOnCXXNestedNameSpecifier. +bool Sema::IsInvalidUnlessNestedName(Scope *S, const CXXScopeSpec &SS, + IdentifierInfo &II, TypeTy *ObjectType, + bool EnteringContext) { + return BuildCXXNestedNameSpecifier(S, SS, SourceLocation(), SourceLocation(), + II, QualType::getFromOpaquePtr(ObjectType), + /*ScopeLookupResult=*/0, EnteringContext, + true); } Sema::CXXScopeTy *Sema::ActOnCXXNestedNameSpecifier(Scope *S, @@ -522,6 +559,44 @@ Sema::CXXScopeTy *Sema::ActOnCXXNestedNameSpecifier(Scope *S, T.getTypePtr()); } +bool Sema::ShouldEnterDeclaratorScope(Scope *S, const CXXScopeSpec &SS) { + assert(SS.isSet() && "Parser passed invalid CXXScopeSpec."); + + NestedNameSpecifier *Qualifier = + static_cast(SS.getScopeRep()); + + // There are only two places a well-formed program may qualify a + // declarator: first, when defining a namespace or class member + // out-of-line, and second, when naming an explicitly-qualified + // friend function. The latter case is governed by + // C++03 [basic.lookup.unqual]p10: + // In a friend declaration naming a member function, a name used + // in the function declarator and not part of a template-argument + // in a template-id is first looked up in the scope of the member + // function's class. If it is not found, or if the name is part of + // a template-argument in a template-id, the look up is as + // described for unqualified names in the definition of the class + // granting friendship. + // i.e. we don't push a scope unless it's a class member. + + switch (Qualifier->getKind()) { + case NestedNameSpecifier::Global: + case NestedNameSpecifier::Namespace: + // These are always namespace scopes. We never want to enter a + // namespace scope from anything but a file context. + return CurContext->getLookupContext()->isFileContext(); + + case NestedNameSpecifier::Identifier: + case NestedNameSpecifier::TypeSpec: + case NestedNameSpecifier::TypeSpecWithTemplate: + // These are never namespace scopes. + return true; + } + + // Silence bogus warning. + return false; +} + /// ActOnCXXEnterDeclaratorScope - Called when a C++ scope specifier (global /// scope or nested-name-specifier) is parsed, part of a declarator-id. /// After this method is called, according to [C++ 3.4.3p3], names should be diff --git a/lib/Sema/SemaChecking.cpp b/lib/Sema/SemaChecking.cpp index 9060fe6ab742..28de5005f8a8 100644 --- a/lib/Sema/SemaChecking.cpp +++ b/lib/Sema/SemaChecking.cpp @@ -700,30 +700,30 @@ bool Sema::SemaBuiltinPrefetch(CallExpr *TheCall) { if (Arg->isTypeDependent()) continue; - QualType RWType = Arg->getType(); - - const BuiltinType *BT = RWType->getAs(); - llvm::APSInt Result; - if (!BT || BT->getKind() != BuiltinType::Int) - return Diag(TheCall->getLocStart(), diag::err_prefetch_invalid_argument) + if (!Arg->getType()->isIntegralType()) + return Diag(TheCall->getLocStart(), diag::err_prefetch_invalid_arg_type) << Arg->getSourceRange(); + ImpCastExprToType(Arg, Context.IntTy, CastExpr::CK_IntegralCast); + TheCall->setArg(i, Arg); + if (Arg->isValueDependent()) continue; + llvm::APSInt Result; if (!Arg->isIntegerConstantExpr(Result, Context)) - return Diag(TheCall->getLocStart(), diag::err_prefetch_invalid_argument) + return Diag(TheCall->getLocStart(), diag::err_prefetch_invalid_arg_ice) << SourceRange(Arg->getLocStart(), Arg->getLocEnd()); // FIXME: gcc issues a warning and rewrites these to 0. These // seems especially odd for the third argument since the default // is 3. if (i == 1) { - if (Result.getSExtValue() < 0 || Result.getSExtValue() > 1) + if (Result.getLimitedValue() > 1) return Diag(TheCall->getLocStart(), diag::err_argument_invalid_range) << "0" << "1" << Arg->getSourceRange(); } else { - if (Result.getSExtValue() < 0 || Result.getSExtValue() > 3) + if (Result.getLimitedValue() > 3) return Diag(TheCall->getLocStart(), diag::err_argument_invalid_range) << "0" << "3" << Arg->getSourceRange(); } diff --git a/lib/Sema/SemaCodeComplete.cpp b/lib/Sema/SemaCodeComplete.cpp index b386adb9df57..4ce9330fc142 100644 --- a/lib/Sema/SemaCodeComplete.cpp +++ b/lib/Sema/SemaCodeComplete.cpp @@ -45,11 +45,64 @@ namespace { /// the result set twice. llvm::SmallPtrSet AllDeclsFound; + typedef std::pair DeclIndexPair; + + /// \brief An entry in the shadow map, which is optimized to store + /// a single (declaration, index) mapping (the common case) but + /// can also store a list of (declaration, index) mappings. + class ShadowMapEntry { + typedef llvm::SmallVector DeclIndexPairVector; + + /// \brief Contains either the solitary NamedDecl * or a vector + /// of (declaration, index) pairs. + llvm::PointerUnion DeclOrVector; + + /// \brief When the entry contains a single declaration, this is + /// the index associated with that entry. + unsigned SingleDeclIndex; + + public: + ShadowMapEntry() : DeclOrVector(), SingleDeclIndex(0) { } + + void Add(NamedDecl *ND, unsigned Index) { + if (DeclOrVector.isNull()) { + // 0 - > 1 elements: just set the single element information. + DeclOrVector = ND; + SingleDeclIndex = Index; + return; + } + + if (NamedDecl *PrevND = DeclOrVector.dyn_cast()) { + // 1 -> 2 elements: create the vector of results and push in the + // existing declaration. + DeclIndexPairVector *Vec = new DeclIndexPairVector; + Vec->push_back(DeclIndexPair(PrevND, SingleDeclIndex)); + DeclOrVector = Vec; + } + + // Add the new element to the end of the vector. + DeclOrVector.get()->push_back( + DeclIndexPair(ND, Index)); + } + + void Destroy() { + if (DeclIndexPairVector *Vec + = DeclOrVector.dyn_cast()) { + delete Vec; + DeclOrVector = ((NamedDecl *)0); + } + } + + // Iteration. + class iterator; + iterator begin() const; + iterator end() const; + }; + /// \brief A mapping from declaration names to the declarations that have /// this name within a particular scope and their index within the list of /// results. - typedef std::multimap > ShadowMap; + typedef llvm::DenseMap ShadowMap; /// \brief The semantic analysis object for which results are being /// produced. @@ -117,6 +170,95 @@ namespace { }; } +class ResultBuilder::ShadowMapEntry::iterator { + llvm::PointerUnion DeclOrIterator; + unsigned SingleDeclIndex; + +public: + typedef DeclIndexPair value_type; + typedef value_type reference; + typedef std::ptrdiff_t difference_type; + typedef std::input_iterator_tag iterator_category; + + class pointer { + DeclIndexPair Value; + + public: + pointer(const DeclIndexPair &Value) : Value(Value) { } + + const DeclIndexPair *operator->() const { + return &Value; + } + }; + + iterator() : DeclOrIterator((NamedDecl *)0), SingleDeclIndex(0) { } + + iterator(NamedDecl *SingleDecl, unsigned Index) + : DeclOrIterator(SingleDecl), SingleDeclIndex(Index) { } + + iterator(const DeclIndexPair *Iterator) + : DeclOrIterator(Iterator), SingleDeclIndex(0) { } + + iterator &operator++() { + if (DeclOrIterator.is()) { + DeclOrIterator = (NamedDecl *)0; + SingleDeclIndex = 0; + return *this; + } + + const DeclIndexPair *I = DeclOrIterator.get(); + ++I; + DeclOrIterator = I; + return *this; + } + + iterator operator++(int) { + iterator tmp(*this); + ++(*this); + return tmp; + } + + reference operator*() const { + if (NamedDecl *ND = DeclOrIterator.dyn_cast()) + return reference(ND, SingleDeclIndex); + + return *DeclOrIterator.get(); + } + + pointer operator->() const { + return pointer(**this); + } + + friend bool operator==(const iterator &X, const iterator &Y) { + return X.DeclOrIterator.getOpaqueValue() + == Y.DeclOrIterator.getOpaqueValue() && + X.SingleDeclIndex == Y.SingleDeclIndex; + } + + friend bool operator!=(const iterator &X, const iterator &Y) { + return !(X == Y); + } +}; + +ResultBuilder::ShadowMapEntry::iterator +ResultBuilder::ShadowMapEntry::begin() const { + if (DeclOrVector.isNull()) + return iterator(); + + if (NamedDecl *ND = DeclOrVector.dyn_cast()) + return iterator(ND, SingleDeclIndex); + + return iterator(DeclOrVector.get()->begin()); +} + +ResultBuilder::ShadowMapEntry::iterator +ResultBuilder::ShadowMapEntry::end() const { + if (DeclOrVector.is() || DeclOrVector.isNull()) + return iterator(); + + return iterator(DeclOrVector.get()->end()); +} + /// \brief Determines whether the given hidden result could be found with /// some extra work, e.g., by qualifying the name. /// @@ -214,7 +356,16 @@ void ResultBuilder::MaybeAddResult(Result R, DeclContext *CurContext) { if (isa(CanonDecl) || (IDNS & (Decl::IDNS_OrdinaryFriend | Decl::IDNS_TagFriend))) return; + + // Class template (partial) specializations are never added as results. + if (isa(CanonDecl) || + isa(CanonDecl)) + return; + // Using declarations themselves are never added as results. + if (isa(CanonDecl)) + return; + if (const IdentifierInfo *Id = R.Declaration->getIdentifier()) { // __va_list_tag is a freak of nature. Find it and skip it. if (Id->isStr("__va_list_tag") || Id->isStr("__builtin_va_list")) @@ -241,14 +392,18 @@ void ResultBuilder::MaybeAddResult(Result R, DeclContext *CurContext) { return; ShadowMap &SMap = ShadowMaps.back(); - ShadowMap::iterator I, IEnd; - for (llvm::tie(I, IEnd) = SMap.equal_range(R.Declaration->getDeclName()); - I != IEnd; ++I) { - NamedDecl *ND = I->second.first; - unsigned Index = I->second.second; + ShadowMapEntry::iterator I, IEnd; + ShadowMap::iterator NamePos = SMap.find(R.Declaration->getDeclName()); + if (NamePos != SMap.end()) { + I = NamePos->second.begin(); + IEnd = NamePos->second.end(); + } + + for (; I != IEnd; ++I) { + NamedDecl *ND = I->first; + unsigned Index = I->second; if (ND->getCanonicalDecl() == CanonDecl) { // This is a redeclaration. Always pick the newer declaration. - I->second.first = R.Declaration; Results[Index].Declaration = R.Declaration; // Pick the best rank of the two. @@ -265,23 +420,28 @@ void ResultBuilder::MaybeAddResult(Result R, DeclContext *CurContext) { std::list::iterator SM, SMEnd = ShadowMaps.end(); --SMEnd; for (SM = ShadowMaps.begin(); SM != SMEnd; ++SM) { - for (llvm::tie(I, IEnd) = SM->equal_range(R.Declaration->getDeclName()); - I != IEnd; ++I) { + ShadowMapEntry::iterator I, IEnd; + ShadowMap::iterator NamePos = SM->find(R.Declaration->getDeclName()); + if (NamePos != SM->end()) { + I = NamePos->second.begin(); + IEnd = NamePos->second.end(); + } + for (; I != IEnd; ++I) { // A tag declaration does not hide a non-tag declaration. - if (I->second.first->getIdentifierNamespace() == Decl::IDNS_Tag && + if (I->first->getIdentifierNamespace() == Decl::IDNS_Tag && (IDNS & (Decl::IDNS_Member | Decl::IDNS_Ordinary | Decl::IDNS_ObjCProtocol))) continue; // Protocols are in distinct namespaces from everything else. - if (((I->second.first->getIdentifierNamespace() & Decl::IDNS_ObjCProtocol) + if (((I->first->getIdentifierNamespace() & Decl::IDNS_ObjCProtocol) || (IDNS & Decl::IDNS_ObjCProtocol)) && - I->second.first->getIdentifierNamespace() != IDNS) + I->first->getIdentifierNamespace() != IDNS) continue; // The newly-added result is hidden by an entry in the shadow map. if (canHiddenResultBeFound(SemaRef.getLangOptions(), R.Declaration, - I->second.first)) { + I->first)) { // Note that this result was hidden. R.Hidden = true; R.QualifierIsInformative = false; @@ -327,8 +487,7 @@ void ResultBuilder::MaybeAddResult(Result R, DeclContext *CurContext) { // Insert this result into the set of results and into the current shadow // map. - SMap.insert(std::make_pair(R.Declaration->getDeclName(), - std::make_pair(R.Declaration, Results.size()))); + SMap[R.Declaration->getDeclName()].Add(R.Declaration, Results.size()); Results.push_back(R); } @@ -339,6 +498,12 @@ void ResultBuilder::EnterNewScope() { /// \brief Exit from the current scope. void ResultBuilder::ExitScope() { + for (ShadowMap::iterator E = ShadowMaps.back().begin(), + EEnd = ShadowMaps.back().end(); + E != EEnd; + ++E) + E->second.Destroy(); + ShadowMaps.pop_back(); } @@ -403,18 +568,20 @@ bool ResultBuilder::IsNamespaceOrAlias(NamedDecl *ND) const { return isa(ND) || isa(ND); } -/// \brief Brief determines whether the given declaration is a namespace or -/// namespace alias. +/// \brief Determines whether the given declaration is a type. bool ResultBuilder::IsType(NamedDecl *ND) const { return isa(ND); } -/// \brief Since every declaration found within a class is a member that we -/// care about, always returns true. This predicate exists mostly to -/// communicate to the result builder that we are performing a lookup for -/// member access. +/// \brief Determines which members of a class should be visible via +/// "." or "->". Only value declarations, nested name specifiers, and +/// using declarations thereof should show up. bool ResultBuilder::IsMember(NamedDecl *ND) const { - return true; + if (UsingShadowDecl *Using = dyn_cast(ND)) + ND = Using->getTargetDecl(); + + return isa(ND) || isa(ND) || + isa(ND); } // Find the next outer declaration context corresponding to this scope. @@ -615,7 +782,7 @@ static unsigned CollectLookupResults(Scope *S, } /// \brief Add type specifiers for the current language as keyword results. -static void AddTypeSpecifierResults(const LangOptions &LangOpts, unsigned Rank, +static void AddTypeSpecifierResults(const LangOptions &LangOpts, unsigned Rank, ResultBuilder &Results) { typedef CodeCompleteConsumer::Result Result; Results.MaybeAddResult(Result("short", Rank)); @@ -773,10 +940,11 @@ static void AddTemplateParameterChunks(ASTContext &Context, /// \brief Add a qualifier to the given code-completion string, if the /// provided nested-name-specifier is non-NULL. -void AddQualifierToCompletionString(CodeCompletionString *Result, - NestedNameSpecifier *Qualifier, - bool QualifierIsInformative, - ASTContext &Context) { +static void +AddQualifierToCompletionString(CodeCompletionString *Result, + NestedNameSpecifier *Qualifier, + bool QualifierIsInformative, + ASTContext &Context) { if (!Qualifier) return; @@ -791,6 +959,23 @@ void AddQualifierToCompletionString(CodeCompletionString *Result, Result->AddTextChunk(PrintedNNS); } +static void AddFunctionTypeQualsToCompletionString(CodeCompletionString *Result, + FunctionDecl *Function) { + const FunctionProtoType *Proto + = Function->getType()->getAs(); + if (!Proto || !Proto->getTypeQuals()) + return; + + std::string QualsStr; + if (Proto->getTypeQuals() & Qualifiers::Const) + QualsStr += " const"; + if (Proto->getTypeQuals() & Qualifiers::Volatile) + QualsStr += " volatile"; + if (Proto->getTypeQuals() & Qualifiers::Restrict) + QualsStr += " restrict"; + Result->AddInformativeChunk(QualsStr); +} + /// \brief If possible, create a new code completion string for the given /// result. /// @@ -864,6 +1049,7 @@ CodeCompleteConsumer::Result::CreateCodeCompletionString(Sema &S) { Result->AddChunk(Chunk(CodeCompletionString::CK_LeftParen)); AddFunctionParameterChunks(S.Context, Function, Result); Result->AddChunk(Chunk(CodeCompletionString::CK_RightParen)); + AddFunctionTypeQualsToCompletionString(Result, Function); return Result; } @@ -917,6 +1103,7 @@ CodeCompleteConsumer::Result::CreateCodeCompletionString(Sema &S) { Result->AddChunk(Chunk(CodeCompletionString::CK_LeftParen)); AddFunctionParameterChunks(S.Context, Function, Result); Result->AddChunk(Chunk(CodeCompletionString::CK_RightParen)); + AddFunctionTypeQualsToCompletionString(Result, Function); return Result; } @@ -1064,13 +1251,54 @@ namespace { typedef CodeCompleteConsumer::Result Result; bool isEarlierDeclarationName(DeclarationName X, DeclarationName Y) const { - if (!X.getObjCSelector().isNull() && !Y.getObjCSelector().isNull()) { - // Consider all selector kinds to be equivalent. - } else if (X.getNameKind() != Y.getNameKind()) + Selector XSel = X.getObjCSelector(); + Selector YSel = Y.getObjCSelector(); + if (!XSel.isNull() && !YSel.isNull()) { + // We are comparing two selectors. + unsigned N = std::min(XSel.getNumArgs(), YSel.getNumArgs()); + if (N == 0) + ++N; + for (unsigned I = 0; I != N; ++I) { + IdentifierInfo *XId = XSel.getIdentifierInfoForSlot(I); + IdentifierInfo *YId = YSel.getIdentifierInfoForSlot(I); + if (!XId || !YId) + return XId && !YId; + + switch (XId->getName().compare_lower(YId->getName())) { + case -1: return true; + case 1: return false; + default: break; + } + } + + return XSel.getNumArgs() < YSel.getNumArgs(); + } + + // For non-selectors, order by kind. + if (X.getNameKind() != Y.getNameKind()) return X.getNameKind() < Y.getNameKind(); - return llvm::LowercaseString(X.getAsString()) - < llvm::LowercaseString(Y.getAsString()); + // Order identifiers by comparison of their lowercased names. + if (IdentifierInfo *XId = X.getAsIdentifierInfo()) + return XId->getName().compare_lower( + Y.getAsIdentifierInfo()->getName()) < 0; + + // Order overloaded operators by the order in which they appear + // in our list of operators. + if (OverloadedOperatorKind XOp = X.getCXXOverloadedOperator()) + return XOp < Y.getCXXOverloadedOperator(); + + // Order C++0x user-defined literal operators lexically by their + // lowercased suffixes. + if (IdentifierInfo *XLit = X.getCXXLiteralIdentifier()) + return XLit->getName().compare_lower( + Y.getCXXLiteralIdentifier()->getName()) < 0; + + // The only stable ordering we have is to turn the name into a + // string and then compare the lower-case strings. This is + // inefficient, but thankfully does not happen too often. + return llvm::StringRef(X.getAsString()).compare_lower( + Y.getAsString()) < 0; } bool operator()(const Result &X, const Result &Y) const { @@ -1088,7 +1316,7 @@ namespace { : X.Pattern->getTypedText(); const char *YStr = (Y.Kind == Result::RK_Keyword)? Y.Keyword : Y.Pattern->getTypedText(); - return strcmp(XStr, YStr) < 0; + return llvm::StringRef(XStr).compare_lower(YStr) < 0; } // Result kinds are ordered by decreasing importance. @@ -1113,12 +1341,11 @@ namespace { Y.Declaration->getDeclName()); case Result::RK_Macro: - return llvm::LowercaseString(X.Macro->getName()) < - llvm::LowercaseString(Y.Macro->getName()); + return X.Macro->getName().compare_lower(Y.Macro->getName()) < 0; case Result::RK_Keyword: case Result::RK_Pattern: - llvm::llvm_unreachable("Result kinds handled above"); + llvm_unreachable("Result kinds handled above"); break; } @@ -1153,9 +1380,23 @@ static void HandleCodeCompleteResults(Sema *S, } void Sema::CodeCompleteOrdinaryName(Scope *S) { + typedef CodeCompleteConsumer::Result Result; ResultBuilder Results(*this, &ResultBuilder::IsOrdinaryName); unsigned NextRank = CollectLookupResults(S, Context.getTranslationUnitDecl(), 0, CurContext, Results); + + Results.EnterNewScope(); + AddTypeSpecifierResults(getLangOptions(), NextRank, Results); + + if (getLangOptions().ObjC1) { + // Add the "super" keyword, if appropriate. + if (ObjCMethodDecl *Method = dyn_cast(CurContext)) + if (Method->getClassInterface()->getSuperClass()) + Results.MaybeAddResult(Result("super", NextRank)); + } + + Results.ExitScope(); + if (CodeCompleter->includeMacros()) AddMacroResults(PP, NextRank, Results); HandleCodeCompleteResults(this, CodeCompleter, Results.data(),Results.size()); @@ -1257,6 +1498,8 @@ void Sema::CodeCompleteMemberReferenceExpr(Scope *S, ExprTy *BaseE, // We could have the start of a nested-name-specifier. Add those // results as well. + // FIXME: We should really walk base classes to produce + // nested-name-specifiers so that we produce more-precise results. Results.setFilter(&ResultBuilder::IsNestedNameSpecifier); CollectLookupResults(S, Context.getTranslationUnitDecl(), NextRank, CurContext, Results); @@ -1448,14 +1691,21 @@ void Sema::CodeCompleteCall(Scope *S, ExprTy *FnIn, ExprTy **ArgsIn, unsigned NumArgs) { if (!CodeCompleter) return; - + + // When we're code-completing for a call, we fall back to ordinary + // name code-completion whenever we can't produce specific + // results. We may want to revisit this strategy in the future, + // e.g., by merging the two kinds of results. + Expr *Fn = (Expr *)FnIn; Expr **Args = (Expr **)ArgsIn; - + // Ignore type-dependent call expressions entirely. if (Fn->isTypeDependent() || - Expr::hasAnyTypeDependentArguments(Args, NumArgs)) + Expr::hasAnyTypeDependentArguments(Args, NumArgs)) { + CodeCompleteOrdinaryName(S); return; + } llvm::SmallVector Fns; DeclarationName UnqualifiedName; @@ -1498,8 +1748,12 @@ void Sema::CodeCompleteCall(Scope *S, ExprTy *FnIn, if (Cand->Viable) Results.push_back(ResultCandidate(Cand->Function)); } - CodeCompleter->ProcessOverloadCandidates(*this, NumArgs, Results.data(), - Results.size()); + + if (Results.empty()) + CodeCompleteOrdinaryName(S); + else + CodeCompleter->ProcessOverloadCandidates(*this, NumArgs, Results.data(), + Results.size()); } void Sema::CodeCompleteQualifiedId(Scope *S, const CXXScopeSpec &SS, @@ -1510,7 +1764,12 @@ void Sema::CodeCompleteQualifiedId(Scope *S, const CXXScopeSpec &SS, DeclContext *Ctx = computeDeclContext(SS, EnteringContext); if (!Ctx) return; - + + // Try to instantiate any non-dependent declaration contexts before + // we look in them. + if (!isDependentScopeSpecifier(SS) && RequireCompleteDeclContext(SS)) + return; + ResultBuilder Results(*this); unsigned NextRank = CollectMemberLookupResults(Ctx, 0, Ctx, Results); @@ -1644,6 +1903,183 @@ void Sema::CodeCompleteOperatorName(Scope *S) { HandleCodeCompleteResults(this, CodeCompleter, Results.data(),Results.size()); } +void Sema::CodeCompleteObjCAtDirective(Scope *S, DeclPtrTy ObjCImpDecl, + bool InInterface) { + typedef CodeCompleteConsumer::Result Result; + ResultBuilder Results(*this); + Results.EnterNewScope(); + if (ObjCImpDecl) { + // Since we have an implementation, we can end it. + Results.MaybeAddResult(Result("end", 0)); + + CodeCompletionString *Pattern = 0; + Decl *ImpDecl = ObjCImpDecl.getAs(); + if (isa(ImpDecl) || + isa(ImpDecl)) { + // @dynamic + Pattern = new CodeCompletionString; + Pattern->AddTypedTextChunk("dynamic"); + Pattern->AddTextChunk(" "); + Pattern->AddPlaceholderChunk("property"); + Results.MaybeAddResult(Result(Pattern, 0)); + + // @synthesize + Pattern = new CodeCompletionString; + Pattern->AddTypedTextChunk("synthesize"); + Pattern->AddTextChunk(" "); + Pattern->AddPlaceholderChunk("property"); + Results.MaybeAddResult(Result(Pattern, 0)); + } + } else if (InInterface) { + // Since we have an interface or protocol, we can end it. + Results.MaybeAddResult(Result("end", 0)); + + if (LangOpts.ObjC2) { + // @property + Results.MaybeAddResult(Result("property", 0)); + } + + // @required + Results.MaybeAddResult(Result("required", 0)); + + // @optional + Results.MaybeAddResult(Result("optional", 0)); + } else { + CodeCompletionString *Pattern = 0; + + // @class name ; + Pattern = new CodeCompletionString; + Pattern->AddTypedTextChunk("class"); + Pattern->AddTextChunk(" "); + Pattern->AddPlaceholderChunk("identifier"); + Pattern->AddTextChunk(";"); // add ';' chunk + Results.MaybeAddResult(Result(Pattern, 0)); + + // @interface name + // FIXME: Could introduce the whole pattern, including superclasses and + // such. + Pattern = new CodeCompletionString; + Pattern->AddTypedTextChunk("interface"); + Pattern->AddTextChunk(" "); + Pattern->AddPlaceholderChunk("class"); + Results.MaybeAddResult(Result(Pattern, 0)); + + // @protocol name + Pattern = new CodeCompletionString; + Pattern->AddTypedTextChunk("protocol"); + Pattern->AddTextChunk(" "); + Pattern->AddPlaceholderChunk("protocol"); + Results.MaybeAddResult(Result(Pattern, 0)); + + // @implementation name + Pattern = new CodeCompletionString; + Pattern->AddTypedTextChunk("implementation"); + Pattern->AddTextChunk(" "); + Pattern->AddPlaceholderChunk("class"); + Results.MaybeAddResult(Result(Pattern, 0)); + + // @compatibility_alias name + Pattern = new CodeCompletionString; + Pattern->AddTypedTextChunk("compatibility_alias"); + Pattern->AddTextChunk(" "); + Pattern->AddPlaceholderChunk("alias"); + Pattern->AddTextChunk(" "); + Pattern->AddPlaceholderChunk("class"); + Results.MaybeAddResult(Result(Pattern, 0)); + } + Results.ExitScope(); + HandleCodeCompleteResults(this, CodeCompleter, Results.data(),Results.size()); +} + +static void AddObjCExpressionResults(unsigned Rank, ResultBuilder &Results) { + typedef CodeCompleteConsumer::Result Result; + CodeCompletionString *Pattern = 0; + + // @encode ( type-name ) + Pattern = new CodeCompletionString; + Pattern->AddTypedTextChunk("encode"); + Pattern->AddChunk(CodeCompletionString::CK_LeftParen); + Pattern->AddPlaceholderChunk("type-name"); + Pattern->AddChunk(CodeCompletionString::CK_RightParen); + Results.MaybeAddResult(Result(Pattern, Rank)); + + // @protocol ( protocol-name ) + Pattern = new CodeCompletionString; + Pattern->AddTypedTextChunk("protocol"); + Pattern->AddChunk(CodeCompletionString::CK_LeftParen); + Pattern->AddPlaceholderChunk("protocol-name"); + Pattern->AddChunk(CodeCompletionString::CK_RightParen); + Results.MaybeAddResult(Result(Pattern, Rank)); + + // @selector ( selector ) + Pattern = new CodeCompletionString; + Pattern->AddTypedTextChunk("selector"); + Pattern->AddChunk(CodeCompletionString::CK_LeftParen); + Pattern->AddPlaceholderChunk("selector"); + Pattern->AddChunk(CodeCompletionString::CK_RightParen); + Results.MaybeAddResult(Result(Pattern, Rank)); +} + +void Sema::CodeCompleteObjCAtStatement(Scope *S) { + typedef CodeCompleteConsumer::Result Result; + ResultBuilder Results(*this); + Results.EnterNewScope(); + + CodeCompletionString *Pattern = 0; + + // @try { statements } @catch ( declaration ) { statements } @finally + // { statements } + Pattern = new CodeCompletionString; + Pattern->AddTypedTextChunk("try"); + Pattern->AddChunk(CodeCompletionString::CK_LeftBrace); + Pattern->AddPlaceholderChunk("statements"); + Pattern->AddChunk(CodeCompletionString::CK_RightBrace); + Pattern->AddTextChunk("@catch"); + Pattern->AddChunk(CodeCompletionString::CK_LeftParen); + Pattern->AddPlaceholderChunk("parameter"); + Pattern->AddChunk(CodeCompletionString::CK_RightParen); + Pattern->AddChunk(CodeCompletionString::CK_LeftBrace); + Pattern->AddPlaceholderChunk("statements"); + Pattern->AddChunk(CodeCompletionString::CK_RightBrace); + Pattern->AddTextChunk("@finally"); + Pattern->AddChunk(CodeCompletionString::CK_LeftBrace); + Pattern->AddPlaceholderChunk("statements"); + Pattern->AddChunk(CodeCompletionString::CK_RightBrace); + Results.MaybeAddResult(Result(Pattern, 0)); + + // @throw + Pattern = new CodeCompletionString; + Pattern->AddTypedTextChunk("throw"); + Pattern->AddTextChunk(" "); + Pattern->AddPlaceholderChunk("expression"); + Pattern->AddTextChunk(";"); + Results.MaybeAddResult(Result(Pattern, 0)); // FIXME: add ';' chunk + + // @synchronized ( expression ) { statements } + Pattern = new CodeCompletionString; + Pattern->AddTypedTextChunk("synchronized"); + Pattern->AddTextChunk(" "); + Pattern->AddChunk(CodeCompletionString::CK_LeftParen); + Pattern->AddPlaceholderChunk("expression"); + Pattern->AddChunk(CodeCompletionString::CK_RightParen); + Pattern->AddChunk(CodeCompletionString::CK_LeftBrace); + Pattern->AddPlaceholderChunk("statements"); + Pattern->AddChunk(CodeCompletionString::CK_RightBrace); + Results.MaybeAddResult(Result(Pattern, 0)); // FIXME: add ';' chunk + + AddObjCExpressionResults(0, Results); + Results.ExitScope(); + HandleCodeCompleteResults(this, CodeCompleter, Results.data(),Results.size()); +} + +void Sema::CodeCompleteObjCAtExpression(Scope *S) { + ResultBuilder Results(*this); + Results.EnterNewScope(); + AddObjCExpressionResults(0, Results); + Results.ExitScope(); + HandleCodeCompleteResults(this, CodeCompleter, Results.data(),Results.size()); +} + /// \brief Determine whether the addition of the given flag to an Objective-C /// property's attributes will cause a conflict. static bool ObjCPropertyFlagConflicts(unsigned Attributes, unsigned NewFlag) { diff --git a/lib/Sema/SemaDecl.cpp b/lib/Sema/SemaDecl.cpp index 520d7de710bd..14d2377784d5 100644 --- a/lib/Sema/SemaDecl.cpp +++ b/lib/Sema/SemaDecl.cpp @@ -12,6 +12,7 @@ //===----------------------------------------------------------------------===// #include "Sema.h" +#include "SemaInit.h" #include "Lookup.h" #include "clang/AST/APValue.h" #include "clang/AST/ASTConsumer.h" @@ -229,7 +230,7 @@ DeclSpec::TST Sema::isTagName(IdentifierInfo &II, Scope *S) { LookupName(R, S, false); R.suppressDiagnostics(); if (R.getResultKind() == LookupResult::Found) - if (const TagDecl *TD = dyn_cast(R.getAsSingleDecl(Context))) { + if (const TagDecl *TD = R.getAsSingle()) { switch (TD->getTagKind()) { case TagDecl::TK_struct: return DeclSpec::TST_struct; case TagDecl::TK_union: return DeclSpec::TST_union; @@ -379,7 +380,9 @@ void Sema::PushOnScopeChains(NamedDecl *D, Scope *S, bool AddToContext) { // scope. if ((isa(D) && cast(D)->getTemplatedDecl()->isOutOfLine()) || - (isa(D) && cast(D)->isOutOfLine()) || + (isa(D) && + (cast(D)->isFunctionTemplateSpecialization() || + cast(D)->isOutOfLine())) || (isa(D) && cast(D)->isOutOfLine())) return; @@ -588,7 +591,7 @@ NamedDecl *Sema::LazilyCreateBuiltin(IdentifierInfo *II, unsigned bid, FunctionDecl *New = FunctionDecl::Create(Context, Context.getTranslationUnitDecl(), - Loc, II, R, /*DInfo=*/0, + Loc, II, R, /*TInfo=*/0, FunctionDecl::Extern, false, /*hasPrototype=*/true); New->setImplicit(); @@ -599,7 +602,7 @@ NamedDecl *Sema::LazilyCreateBuiltin(IdentifierInfo *II, unsigned bid, llvm::SmallVector Params; for (unsigned i = 0, e = FT->getNumArgs(); i != e; ++i) Params.push_back(ParmVarDecl::Create(Context, New, SourceLocation(), 0, - FT->getArgType(i), /*DInfo=*/0, + FT->getArgType(i), /*TInfo=*/0, VarDecl::None, 0)); New->setParams(Context, Params.data(), Params.size()); } @@ -762,6 +765,24 @@ struct GNUCompatibleParamWarning { QualType PromotedType; }; + +/// getSpecialMember - get the special member enum for a method. +static Sema::CXXSpecialMember getSpecialMember(ASTContext &Ctx, + const CXXMethodDecl *MD) { + if (const CXXConstructorDecl *Ctor = dyn_cast(MD)) { + if (Ctor->isDefaultConstructor()) + return Sema::CXXDefaultConstructor; + if (Ctor->isCopyConstructor(Ctx)) + return Sema::CXXCopyConstructor; + } + + if (isa(MD)) + return Sema::CXXDestructor; + + assert(MD->isCopyAssignment() && "Must have copy assignment operator"); + return Sema::CXXCopyAssignment; +} + /// MergeFunctionDecl - We just parsed a function 'New' from /// declarator D which has the same name and scope as a previous /// declaration 'Old'. Figure out how to resolve this situation, @@ -782,6 +803,15 @@ bool Sema::MergeFunctionDecl(FunctionDecl *New, Decl *OldD) { else Old = dyn_cast(OldD); if (!Old) { + if (UsingShadowDecl *Shadow = dyn_cast(OldD)) { + Diag(New->getLocation(), diag::err_using_decl_conflict_reverse); + Diag(Shadow->getTargetDecl()->getLocation(), + diag::note_using_decl_target); + Diag(Shadow->getUsingDecl()->getLocation(), + diag::note_using_decl) << 0; + return true; + } + Diag(New->getLocation(), diag::err_redefinition_different_kind) << New->getDeclName(); Diag(OldD->getLocation(), diag::note_previous_definition); @@ -827,33 +857,45 @@ bool Sema::MergeFunctionDecl(FunctionDecl *New, Decl *OldD) { const CXXMethodDecl* OldMethod = dyn_cast(Old); const CXXMethodDecl* NewMethod = dyn_cast(New); - if (OldMethod && NewMethod && !NewMethod->getFriendObjectKind() && - NewMethod->getLexicalDeclContext()->isRecord()) { - // -- Member function declarations with the same name and the - // same parameter types cannot be overloaded if any of them - // is a static member function declaration. - if (OldMethod->isStatic() || NewMethod->isStatic()) { - Diag(New->getLocation(), diag::err_ovl_static_nonstatic_member); + if (OldMethod && NewMethod) { + if (!NewMethod->getFriendObjectKind() && + NewMethod->getLexicalDeclContext()->isRecord()) { + // -- Member function declarations with the same name and the + // same parameter types cannot be overloaded if any of them + // is a static member function declaration. + if (OldMethod->isStatic() || NewMethod->isStatic()) { + Diag(New->getLocation(), diag::err_ovl_static_nonstatic_member); + Diag(Old->getLocation(), PrevDiag) << Old << Old->getType(); + return true; + } + + // C++ [class.mem]p1: + // [...] A member shall not be declared twice in the + // member-specification, except that a nested class or member + // class template can be declared and then later defined. + unsigned NewDiag; + if (isa(OldMethod)) + NewDiag = diag::err_constructor_redeclared; + else if (isa(NewMethod)) + NewDiag = diag::err_destructor_redeclared; + else if (isa(NewMethod)) + NewDiag = diag::err_conv_function_redeclared; + else + NewDiag = diag::err_member_redeclared; + + Diag(New->getLocation(), NewDiag); Diag(Old->getLocation(), PrevDiag) << Old << Old->getType(); - return true; + } else { + if (OldMethod->isImplicit()) { + Diag(NewMethod->getLocation(), + diag::err_definition_of_implicitly_declared_member) + << New << getSpecialMember(Context, OldMethod); + + Diag(OldMethod->getLocation(), + diag::note_previous_implicit_declaration); + return true; + } } - - // C++ [class.mem]p1: - // [...] A member shall not be declared twice in the - // member-specification, except that a nested class or member - // class template can be declared and then later defined. - unsigned NewDiag; - if (isa(OldMethod)) - NewDiag = diag::err_constructor_redeclared; - else if (isa(NewMethod)) - NewDiag = diag::err_destructor_redeclared; - else if (isa(NewMethod)) - NewDiag = diag::err_conv_function_redeclared; - else - NewDiag = diag::err_member_redeclared; - - Diag(New->getLocation(), NewDiag); - Diag(Old->getLocation(), PrevDiag) << Old << Old->getType(); } // (C++98 8.3.5p3): @@ -894,7 +936,7 @@ bool Sema::MergeFunctionDecl(FunctionDecl *New, Decl *OldD) { ParamType != ParamEnd; ++ParamType) { ParmVarDecl *Param = ParmVarDecl::Create(Context, New, SourceLocation(), 0, - *ParamType, /*DInfo=*/0, + *ParamType, /*TInfo=*/0, VarDecl::None, 0); Param->setImplicit(); Params.push_back(Param); @@ -1057,10 +1099,11 @@ void Sema::MergeVarDecl(VarDecl *New, LookupResult &Previous) { if (getLangOptions().CPlusPlus) { if (Context.hasSameType(New->getType(), Old->getType())) MergedT = New->getType(); - // C++ [basic.types]p7: - // [...] The declared type of an array object might be an array of - // unknown size and therefore be incomplete at one point in a - // translation unit and complete later on; [...] + // C++ [basic.link]p10: + // [...] the types specified by all declarations referring to a given + // object or function shall be identical, except that declarations for an + // array object can specify array types that differ by the presence or + // absence of a major array bound (8.3.4). else if (Old->getType()->isIncompleteArrayType() && New->getType()->isArrayType()) { CanQual OldArray @@ -1069,6 +1112,14 @@ void Sema::MergeVarDecl(VarDecl *New, LookupResult &Previous) { = Context.getCanonicalType(New->getType())->getAs(); if (OldArray->getElementType() == NewArray->getElementType()) MergedT = New->getType(); + } else if (Old->getType()->isArrayType() && + New->getType()->isIncompleteArrayType()) { + CanQual OldArray + = Context.getCanonicalType(Old->getType())->getAs(); + CanQual NewArray + = Context.getCanonicalType(New->getType())->getAs(); + if (OldArray->getElementType() == NewArray->getElementType()) + MergedT = Old->getType(); } } else { MergedT = Context.mergeTypes(New->getType(), Old->getType()); @@ -1202,6 +1253,11 @@ Sema::ControlFlowKind Sema::CheckFallThrough(Stmt *Root) { HasFakeEdge = true; continue; } + if (isa(S)) { + HasFakeEdge = true; + HasLiveReturn = true; + continue; + } bool NoReturnEdge = false; if (CallExpr *C = dyn_cast(S)) { Expr *CEE = C->getCallee()->IgnoreParenCasts(); @@ -1209,11 +1265,10 @@ Sema::ControlFlowKind Sema::CheckFallThrough(Stmt *Root) { NoReturnEdge = true; HasFakeEdge = true; } else if (DeclRefExpr *DRE = dyn_cast(CEE)) { - if (FunctionDecl *FD = dyn_cast(DRE->getDecl())) { - if (FD->hasAttr()) { - NoReturnEdge = true; - HasFakeEdge = true; - } + ValueDecl *VD = DRE->getDecl(); + if (VD->hasAttr()) { + NoReturnEdge = true; + HasFakeEdge = true; } } } @@ -1648,9 +1703,9 @@ Sema::DeclPtrTy Sema::BuildAnonymousStructOrUnion(Scope *S, DeclSpec &DS, // Mock up a declarator. Declarator Dc(DS, Declarator::TypeNameContext); - DeclaratorInfo *DInfo = 0; - GetTypeForDeclarator(Dc, S, &DInfo); - assert(DInfo && "couldn't build declarator info for anonymous struct/union"); + TypeSourceInfo *TInfo = 0; + GetTypeForDeclarator(Dc, S, &TInfo); + assert(TInfo && "couldn't build declarator info for anonymous struct/union"); // Create a declaration for this anonymous struct/union. NamedDecl *Anon = 0; @@ -1658,7 +1713,7 @@ Sema::DeclPtrTy Sema::BuildAnonymousStructOrUnion(Scope *S, DeclSpec &DS, Anon = FieldDecl::Create(Context, OwningClass, Record->getLocation(), /*IdentifierInfo=*/0, Context.getTypeDeclType(Record), - DInfo, + TInfo, /*BitWidth=*/0, /*Mutable=*/false); Anon->setAccess(AS_public); if (getLangOptions().CPlusPlus) @@ -1685,7 +1740,7 @@ Sema::DeclPtrTy Sema::BuildAnonymousStructOrUnion(Scope *S, DeclSpec &DS, Anon = VarDecl::Create(Context, Owner, Record->getLocation(), /*IdentifierInfo=*/0, Context.getTypeDeclType(Record), - DInfo, + TInfo, SC); } Anon->setImplicit(); @@ -1765,13 +1820,8 @@ DeclarationName Sema::GetNameFromUnqualifiedId(const UnqualifiedId &Name) { case UnqualifiedId::IK_TemplateId: { TemplateName TName - = TemplateName::getFromVoidPointer(Name.TemplateId->Template); - if (TemplateDecl *Template = TName.getAsTemplateDecl()) - return Template->getDeclName(); - if (OverloadedFunctionDecl *Ovl = TName.getAsOverloadedFunctionDecl()) - return Ovl->getDeclName(); - - return DeclarationName(); + = TemplateName::getFromVoidPointer(Name.TemplateId->Template); + return Context.getNameForTemplate(TName); } } @@ -1851,8 +1901,8 @@ Sema::HandleDeclarator(Scope *S, Declarator &D, DeclContext *DC; NamedDecl *New; - DeclaratorInfo *DInfo = 0; - QualType R = GetTypeForDeclarator(D, S, &DInfo); + TypeSourceInfo *TInfo = 0; + QualType R = GetTypeForDeclarator(D, S, &TInfo); LookupResult Previous(*this, Name, D.getIdentifierLoc(), LookupOrdinaryName, ForRedeclaration); @@ -1982,13 +2032,13 @@ Sema::HandleDeclarator(Scope *S, Declarator &D, return DeclPtrTy(); } - New = ActOnTypedefDeclarator(S, D, DC, R, DInfo, Previous, Redeclaration); + New = ActOnTypedefDeclarator(S, D, DC, R, TInfo, Previous, Redeclaration); } else if (R->isFunctionType()) { - New = ActOnFunctionDeclarator(S, D, DC, R, DInfo, Previous, + New = ActOnFunctionDeclarator(S, D, DC, R, TInfo, Previous, move(TemplateParamLists), IsFunctionDefinition, Redeclaration); } else { - New = ActOnVariableDeclarator(S, D, DC, R, DInfo, Previous, + New = ActOnVariableDeclarator(S, D, DC, R, TInfo, Previous, move(TemplateParamLists), Redeclaration); } @@ -1998,9 +2048,7 @@ Sema::HandleDeclarator(Scope *S, Declarator &D, // If this has an identifier and is not an invalid redeclaration or // function template specialization, add it to the scope stack. - if (Name && !(Redeclaration && New->isInvalidDecl()) && - !(isa(New) && - cast(New)->isFunctionTemplateSpecialization())) + if (Name && !(Redeclaration && New->isInvalidDecl())) PushOnScopeChains(New, S); return DeclPtrTy::make(New); @@ -2104,7 +2152,7 @@ void Sema::DiagnoseFunctionSpecifiers(Declarator& D) { NamedDecl* Sema::ActOnTypedefDeclarator(Scope* S, Declarator& D, DeclContext* DC, - QualType R, DeclaratorInfo *DInfo, + QualType R, TypeSourceInfo *TInfo, LookupResult &Previous, bool &Redeclaration) { // Typedef declarators cannot be qualified (C++ [dcl.meaning]p1). if (D.getCXXScopeSpec().isSet()) { @@ -2125,7 +2173,7 @@ Sema::ActOnTypedefDeclarator(Scope* S, Declarator& D, DeclContext* DC, if (D.getDeclSpec().isThreadSpecified()) Diag(D.getDeclSpec().getThreadSpecLoc(), diag::err_invalid_thread); - TypedefDecl *NewTD = ParseTypedefDecl(S, D, R, DInfo); + TypedefDecl *NewTD = ParseTypedefDecl(S, D, R, TInfo); if (!NewTD) return 0; // Handle attributes prior to checking for duplicates in MergeVarDecl @@ -2151,7 +2199,7 @@ Sema::ActOnTypedefDeclarator(Scope* S, Declarator& D, DeclContext* DC, TryToFixInvalidVariablyModifiedType(T, Context, SizeIsNegative); if (!FixedTy.isNull()) { Diag(D.getIdentifierLoc(), diag::warn_illegal_constant_array_size); - NewTD->setTypeDeclaratorInfo(Context.getTrivialDeclaratorInfo(FixedTy)); + NewTD->setTypeSourceInfo(Context.getTrivialTypeSourceInfo(FixedTy)); } else { if (SizeIsNegative) Diag(D.getIdentifierLoc(), diag::err_typecheck_negative_array_size); @@ -2244,7 +2292,7 @@ isOutOfScopePreviousDeclaration(NamedDecl *PrevDecl, DeclContext *DC, NamedDecl* Sema::ActOnVariableDeclarator(Scope* S, Declarator& D, DeclContext* DC, - QualType R, DeclaratorInfo *DInfo, + QualType R, TypeSourceInfo *TInfo, LookupResult &Previous, MultiTemplateParamsArg TemplateParamLists, bool &Redeclaration) { @@ -2302,7 +2350,7 @@ Sema::ActOnVariableDeclarator(Scope* S, Declarator& D, DeclContext* DC, Diag(D.getDeclSpec().getStorageClassSpecLoc(), diag::err_static_out_of_line) << CodeModificationHint::CreateRemoval( - SourceRange(D.getDeclSpec().getStorageClassSpecLoc())); + D.getDeclSpec().getStorageClassSpecLoc()); } else if (SC == VarDecl::None) SC = VarDecl::Static; } @@ -2346,7 +2394,7 @@ Sema::ActOnVariableDeclarator(Scope* S, Declarator& D, DeclContext* DC, } NewVD = VarDecl::Create(Context, DC, D.getIdentifierLoc(), - II, R, DInfo, SC); + II, R, TInfo, SC); if (D.isInvalidType()) NewVD->setInvalidDecl(); @@ -2449,12 +2497,6 @@ void Sema::CheckVariableDeclaration(VarDecl *NewVD, return NewVD->setInvalidDecl(); } - // The variable can not have an abstract class type. - if (RequireNonAbstractType(NewVD->getLocation(), T, - diag::err_abstract_type_in_decl, - AbstractVariableType)) - return NewVD->setInvalidDecl(); - // Emit an error if an address space was applied to decl with local storage. // This includes arrays of objects with address space qualifiers, but not // automatic variables that point to other address spaces. @@ -2596,7 +2638,7 @@ void Sema::AddOverriddenMethods(CXXRecordDecl *DC, CXXMethodDecl *MD) { if (!CheckOverridingFunctionReturnType(MD, OldMD) && !CheckOverridingFunctionExceptionSpec(MD, OldMD) && !CheckOverridingFunctionAttributes(MD, OldMD)) - MD->addOverriddenMethod(OldMD); + MD->addOverriddenMethod(OldMD->getCanonicalDecl()); } } } @@ -2604,7 +2646,7 @@ void Sema::AddOverriddenMethods(CXXRecordDecl *DC, CXXMethodDecl *MD) { NamedDecl* Sema::ActOnFunctionDeclarator(Scope* S, Declarator& D, DeclContext* DC, - QualType R, DeclaratorInfo *DInfo, + QualType R, TypeSourceInfo *TInfo, LookupResult &Previous, MultiTemplateParamsArg TemplateParamLists, bool IsFunctionDefinition, bool &Redeclaration) { @@ -2686,7 +2728,7 @@ Sema::ActOnFunctionDeclarator(Scope* S, Declarator& D, DeclContext* DC, // Create the new declaration NewFD = CXXConstructorDecl::Create(Context, cast(DC), - D.getIdentifierLoc(), Name, R, DInfo, + D.getIdentifierLoc(), Name, R, TInfo, isExplicit, isInline, /*isImplicitlyDeclared=*/false); } else if (Name.getNameKind() == DeclarationName::CXXDestructorName) { @@ -2707,7 +2749,7 @@ Sema::ActOnFunctionDeclarator(Scope* S, Declarator& D, DeclContext* DC, // Create a FunctionDecl to satisfy the function definition parsing // code path. NewFD = FunctionDecl::Create(Context, DC, D.getIdentifierLoc(), - Name, R, DInfo, SC, isInline, + Name, R, TInfo, SC, isInline, /*hasPrototype=*/true); D.setInvalidType(); } @@ -2720,7 +2762,7 @@ Sema::ActOnFunctionDeclarator(Scope* S, Declarator& D, DeclContext* DC, CheckConversionDeclarator(D, R, SC); NewFD = CXXConversionDecl::Create(Context, cast(DC), - D.getIdentifierLoc(), Name, R, DInfo, + D.getIdentifierLoc(), Name, R, TInfo, isInline, isExplicit); isVirtualOkay = true; @@ -2754,7 +2796,7 @@ Sema::ActOnFunctionDeclarator(Scope* S, Declarator& D, DeclContext* DC, // This is a C++ method declaration. NewFD = CXXMethodDecl::Create(Context, cast(DC), - D.getIdentifierLoc(), Name, R, DInfo, + D.getIdentifierLoc(), Name, R, TInfo, isStatic, isInline); isVirtualOkay = !isStatic; @@ -2772,7 +2814,7 @@ Sema::ActOnFunctionDeclarator(Scope* S, Declarator& D, DeclContext* DC, NewFD = FunctionDecl::Create(Context, DC, D.getIdentifierLoc(), - Name, R, DInfo, SC, isInline, HasPrototype); + Name, R, TInfo, SC, isInline, HasPrototype); } if (D.isInvalidType()) @@ -2830,18 +2872,11 @@ Sema::ActOnFunctionDeclarator(Scope* S, Declarator& D, DeclContext* DC, // 'virtual' was specified outside of the class. Diag(D.getDeclSpec().getVirtualSpecLoc(), diag::err_virtual_out_of_class) << CodeModificationHint::CreateRemoval( - SourceRange(D.getDeclSpec().getVirtualSpecLoc())); + D.getDeclSpec().getVirtualSpecLoc()); } else { // Okay: Add virtual to the method. - cast(NewFD)->setVirtualAsWritten(true); CXXRecordDecl *CurClass = cast(DC); - CurClass->setAggregate(false); - CurClass->setPOD(false); - CurClass->setEmpty(false); - CurClass->setPolymorphic(true); - CurClass->setHasTrivialConstructor(false); - CurClass->setHasTrivialCopyConstructor(false); - CurClass->setHasTrivialCopyAssignment(false); + CurClass->setMethodAsVirtual(NewFD); } } @@ -2865,9 +2900,6 @@ Sema::ActOnFunctionDeclarator(Scope* S, Declarator& D, DeclContext* DC, NewFD->setAccess(AS_public); } - if (CXXMethodDecl *NewMD = dyn_cast(NewFD)) - AddOverriddenMethods(cast(DC), NewMD); - if (SC == FunctionDecl::Static && isa(NewFD) && !CurContext->isRecord()) { // C++ [class.static]p1: @@ -2880,7 +2912,7 @@ Sema::ActOnFunctionDeclarator(Scope* S, Declarator& D, DeclContext* DC, Diag(D.getDeclSpec().getStorageClassSpecLoc(), diag::err_static_out_of_line) << CodeModificationHint::CreateRemoval( - SourceRange(D.getDeclSpec().getStorageClassSpecLoc())); + D.getDeclSpec().getStorageClassSpecLoc()); } // Handle GNU asm-label extension (encoded as an attribute). @@ -2937,7 +2969,7 @@ Sema::ActOnFunctionDeclarator(Scope* S, Declarator& D, DeclContext* DC, AE = FT->arg_type_end(); AI != AE; ++AI) { ParmVarDecl *Param = ParmVarDecl::Create(Context, DC, SourceLocation(), 0, - *AI, /*DInfo=*/0, + *AI, /*TInfo=*/0, VarDecl::None, 0); Param->setImplicit(); Params.push_back(Param); @@ -2996,7 +3028,7 @@ Sema::ActOnFunctionDeclarator(Scope* S, Declarator& D, DeclContext* DC, // Perform semantic checking on the function declaration. bool OverloadableAttrRequired = false; // FIXME: HACK! - CheckFunctionDeclaration(NewFD, Previous, isExplicitSpecialization, + CheckFunctionDeclaration(S, NewFD, Previous, isExplicitSpecialization, Redeclaration, /*FIXME:*/OverloadableAttrRequired); assert((NewFD->isInvalidDecl() || !Redeclaration || @@ -3118,7 +3150,7 @@ Sema::ActOnFunctionDeclarator(Scope* S, Declarator& D, DeclContext* DC, /// an explicit specialization of the previous declaration. /// /// This sets NewFD->isInvalidDecl() to true if there was an error. -void Sema::CheckFunctionDeclaration(FunctionDecl *NewFD, +void Sema::CheckFunctionDeclaration(Scope *S, FunctionDecl *NewFD, LookupResult &Previous, bool IsExplicitSpecialization, bool &Redeclaration, @@ -3156,34 +3188,47 @@ void Sema::CheckFunctionDeclaration(FunctionDecl *NewFD, // there's no more work to do here; we'll just add the new // function to the scope. - if (!getLangOptions().CPlusPlus && - AllowOverloadingOfFunction(Previous, Context)) { - OverloadableAttrRequired = true; - - // Functions marked "overloadable" must have a prototype (that - // we can't get through declaration merging). - if (!NewFD->getType()->getAs()) { - Diag(NewFD->getLocation(), diag::err_attribute_overloadable_no_prototype) - << NewFD; - Redeclaration = true; - - // Turn this into a variadic function with no parameters. - QualType R = Context.getFunctionType( - NewFD->getType()->getAs()->getResultType(), - 0, 0, true, 0); - NewFD->setType(R); - return NewFD->setInvalidDecl(); - } - } - NamedDecl *OldDecl = 0; - if (!Previous.empty()) { - if (!AllowOverloadingOfFunction(Previous, Context)) { - Redeclaration = true; - OldDecl = Previous.getFoundDecl(); - } else if (!IsOverload(NewFD, Previous, OldDecl)) { - if (!isUsingDecl(OldDecl)) + if (!AllowOverloadingOfFunction(Previous, Context)) { + Redeclaration = true; + OldDecl = Previous.getFoundDecl(); + } else { + if (!getLangOptions().CPlusPlus) { + OverloadableAttrRequired = true; + + // Functions marked "overloadable" must have a prototype (that + // we can't get through declaration merging). + if (!NewFD->getType()->getAs()) { + Diag(NewFD->getLocation(), + diag::err_attribute_overloadable_no_prototype) + << NewFD; Redeclaration = true; + + // Turn this into a variadic function with no parameters. + QualType R = Context.getFunctionType( + NewFD->getType()->getAs()->getResultType(), + 0, 0, true, 0); + NewFD->setType(R); + return NewFD->setInvalidDecl(); + } + } + + switch (CheckOverload(NewFD, Previous, OldDecl)) { + case Ovl_Match: + Redeclaration = true; + if (isa(OldDecl) && CurContext->isRecord()) { + HideUsingShadowDecl(S, cast(OldDecl)); + Redeclaration = false; + } + break; + + case Ovl_NonFunction: + Redeclaration = true; + break; + + case Ovl_Overload: + Redeclaration = false; + break; } } @@ -3243,8 +3288,6 @@ void Sema::CheckFunctionDeclaration(FunctionDecl *NewFD, Diag(NewFD->getLocation(), diag::err_destructor_name); return NewFD->setInvalidDecl(); } - - CheckDestructor(Destructor); } Record->setUserDeclaredDestructor(true); @@ -3257,8 +3300,22 @@ void Sema::CheckFunctionDeclaration(FunctionDecl *NewFD, // FIXME: C++0x: don't do this for "= default" destructors Record->setHasTrivialDestructor(false); } else if (CXXConversionDecl *Conversion - = dyn_cast(NewFD)) + = dyn_cast(NewFD)) { ActOnConversionDeclarator(Conversion); + } + + // Find any virtual functions that this function overrides. + if (CXXMethodDecl *Method = dyn_cast(NewFD)) { + if (!Method->isFunctionTemplateSpecialization() && + !Method->getDescribedFunctionTemplate()) + AddOverriddenMethods(Method->getParent(), Method); + } + + // Additional checks for the destructor; make sure we do this after we + // figure out whether the destructor is virtual. + if (CXXDestructorDecl *Destructor = dyn_cast(NewFD)) + if (!Destructor->getParent()->isDependentType()) + CheckDestructor(Destructor); // Extra checking for C++ overloaded operators (C++ [over.oper]). if (NewFD->isOverloadedOperator() && @@ -3392,18 +3449,9 @@ void Sema::AddInitializerToDecl(DeclPtrTy dcl, ExprArg init, bool DirectInit) { IntegerLiteral *IL; Expr *Init = static_cast(init.get()); if ((IL = dyn_cast(Init)) && IL->getValue() == 0 && - Context.getCanonicalType(IL->getType()) == Context.IntTy) { - if (Method->isVirtualAsWritten()) { - Method->setPure(); - - // A class is abstract if at least one function is pure virtual. - cast(CurContext)->setAbstract(true); - } else if (!Method->isInvalidDecl()) { - Diag(Method->getLocation(), diag::err_non_virtual_pure) - << Method->getDeclName() << Init->getSourceRange(); - Method->setInvalidDecl(); - } - } else { + Context.getCanonicalType(IL->getType()) == Context.IntTy) + CheckPureMethod(Method, Init->getSourceRange()); + else { Diag(Method->getLocation(), diag::err_member_function_initialization) << Method->getDeclName() << Init->getSourceRange(); Method->setInvalidDecl(); @@ -3436,6 +3484,12 @@ void Sema::AddInitializerToDecl(DeclPtrTy dcl, ExprArg init, bool DirectInit) { return; } + // The variable can not have an abstract class type. + if (RequireNonAbstractType(VDecl->getLocation(), VDecl->getType(), + diag::err_abstract_type_in_decl, + AbstractVariableType)) + VDecl->setInvalidDecl(); + const VarDecl *Def = 0; if (VDecl->getDefinition(Def)) { Diag(VDecl->getLocation(), diag::err_redefinition) @@ -3458,8 +3512,36 @@ void Sema::AddInitializerToDecl(DeclPtrTy dcl, ExprArg init, bool DirectInit) { Diag(VDecl->getLocation(), diag::err_block_extern_cant_init); VDecl->setInvalidDecl(); } else if (!VDecl->isInvalidDecl()) { - if (CheckInitializerTypes(Init, DclT, VDecl->getLocation(), - VDecl->getDeclName(), DirectInit)) + if (VDecl->getType()->isReferenceType() + || isa(Init)) { + InitializedEntity Entity + = InitializedEntity::InitializeVariable(VDecl); + + // FIXME: Poor source location information. + InitializationKind Kind + = DirectInit? InitializationKind::CreateDirect(VDecl->getLocation(), + SourceLocation(), + SourceLocation()) + : InitializationKind::CreateCopy(VDecl->getLocation(), + SourceLocation()); + InitializationSequence InitSeq(*this, Entity, Kind, &Init, 1); + if (InitSeq) { + OwningExprResult Result = InitSeq.Perform(*this, Entity, Kind, + MultiExprArg(*this, (void**)&Init, 1), + &DclT); + if (Result.isInvalid()) { + VDecl->setInvalidDecl(); + return; + } + + Init = Result.takeAs(); + } else { + InitSeq.Diagnose(*this, Entity, Kind, &Init, 1); + VDecl->setInvalidDecl(); + return; + } + } else if (CheckInitializerTypes(Init, DclT, VDecl->getLocation(), + VDecl->getDeclName(), DirectInit)) VDecl->setInvalidDecl(); // C++ 3.6.2p2, allow dynamic initialization of static initializers. @@ -3649,7 +3731,7 @@ void Sema::ActOnUninitializedDecl(DeclPtrTy dcl, SourceRange(Var->getLocation(), Var->getLocation()), Var->getDeclName(), - IK_Default, + InitializationKind::CreateDefault(Var->getLocation()), ConstructorArgs); // FIXME: Location info for the variable initialization? @@ -3668,6 +3750,12 @@ void Sema::ActOnUninitializedDecl(DeclPtrTy dcl, Var->setInvalidDecl(); } } + + // The variable can not have an abstract class type. + if (RequireNonAbstractType(Var->getLocation(), Type, + diag::err_abstract_type_in_decl, + AbstractVariableType)) + Var->setInvalidDecl(); } #if 0 @@ -3817,9 +3905,9 @@ Sema::ActOnParamDeclarator(Scope *S, Declarator &D) { if (getLangOptions().CPlusPlus) CheckExtraCXXDefaultArguments(D); - DeclaratorInfo *DInfo = 0; + TypeSourceInfo *TInfo = 0; TagDecl *OwnedDecl = 0; - QualType parmDeclType = GetTypeForDeclarator(D, S, &DInfo, &OwnedDecl); + QualType parmDeclType = GetTypeForDeclarator(D, S, &TInfo, &OwnedDecl); if (getLangOptions().CPlusPlus && OwnedDecl && OwnedDecl->isDefinition()) { // C++ [dcl.fct]p6: @@ -3862,7 +3950,7 @@ Sema::ActOnParamDeclarator(Scope *S, Declarator &D) { ParmVarDecl *New = ParmVarDecl::Create(Context, CurContext, D.getIdentifierLoc(), II, - T, DInfo, StorageClass, 0); + T, TInfo, StorageClass, 0); if (D.isInvalidType()) New->setInvalidDecl(); @@ -3960,6 +4048,50 @@ Sema::DeclPtrTy Sema::ActOnStartOfFunctionDef(Scope *FnBodyScope, return ActOnStartOfFunctionDef(FnBodyScope, DP); } +static bool ShouldWarnAboutMissingPrototype(const FunctionDecl *FD) { + // Don't warn about invalid declarations. + if (FD->isInvalidDecl()) + return false; + + // Or declarations that aren't global. + if (!FD->isGlobal()) + return false; + + // Don't warn about C++ member functions. + if (isa(FD)) + return false; + + // Don't warn about 'main'. + if (FD->isMain()) + return false; + + // Don't warn about inline functions. + if (FD->isInlineSpecified()) + return false; + + // Don't warn about function templates. + if (FD->getDescribedFunctionTemplate()) + return false; + + // Don't warn about function template specializations. + if (FD->isFunctionTemplateSpecialization()) + return false; + + bool MissingPrototype = true; + for (const FunctionDecl *Prev = FD->getPreviousDeclaration(); + Prev; Prev = Prev->getPreviousDeclaration()) { + // Ignore any declarations that occur in function or method + // scope, because they aren't visible from the header. + if (Prev->getDeclContext()->isFunctionOrMethod()) + continue; + + MissingPrototype = !Prev->getType()->isFunctionProtoType(); + break; + } + + return MissingPrototype; +} + Sema::DeclPtrTy Sema::ActOnStartOfFunctionDef(Scope *FnBodyScope, DeclPtrTy D) { // Clear the last template instantiation error context. LastTemplateInstantiationErrorContext = ActiveTemplateInstantiation(); @@ -4005,23 +4137,8 @@ Sema::DeclPtrTy Sema::ActOnStartOfFunctionDef(Scope *FnBodyScope, DeclPtrTy D) { // prototype declaration. This warning is issued even if the // definition itself provides a prototype. The aim is to detect // global functions that fail to be declared in header files. - if (!FD->isInvalidDecl() && FD->isGlobal() && !isa(FD) && - !FD->isMain()) { - bool MissingPrototype = true; - for (const FunctionDecl *Prev = FD->getPreviousDeclaration(); - Prev; Prev = Prev->getPreviousDeclaration()) { - // Ignore any declarations that occur in function or method - // scope, because they aren't visible from the header. - if (Prev->getDeclContext()->isFunctionOrMethod()) - continue; - - MissingPrototype = !Prev->getType()->isFunctionProtoType(); - break; - } - - if (MissingPrototype) - Diag(FD->getLocation(), diag::warn_missing_prototype) << FD; - } + if (ShouldWarnAboutMissingPrototype(FD)) + Diag(FD->getLocation(), diag::warn_missing_prototype) << FD; if (FnBodyScope) PushDeclContext(FnBodyScope, FD); @@ -4090,11 +4207,8 @@ Sema::DeclPtrTy Sema::ActOnFinishFunctionBody(DeclPtrTy D, StmtArg BodyArg, if (!FD->isInvalidDecl()) DiagnoseUnusedParameters(FD->param_begin(), FD->param_end()); - // C++ [basic.def.odr]p2: - // [...] A virtual member function is used if it is not pure. [...] if (CXXMethodDecl *Method = dyn_cast(FD)) - if (Method->isVirtual() && !Method->isPure()) - MarkDeclarationReferenced(Method->getLocation(), Method); + MaybeMarkVirtualMembersReferenced(Method->getLocation(), Method); assert(FD == getCurFunctionDecl() && "Function parsing confused"); } else if (ObjCMethodDecl *MD = dyn_cast_or_null(dcl)) { @@ -4301,20 +4415,20 @@ void Sema::AddKnownFunctionAttributes(FunctionDecl *FD) { } TypedefDecl *Sema::ParseTypedefDecl(Scope *S, Declarator &D, QualType T, - DeclaratorInfo *DInfo) { + TypeSourceInfo *TInfo) { assert(D.getIdentifier() && "Wrong callback for declspec without declarator"); assert(!T.isNull() && "GetTypeForDeclarator() returned null type"); - if (!DInfo) { + if (!TInfo) { assert(D.isInvalidType() && "no declarator info for valid type"); - DInfo = Context.getTrivialDeclaratorInfo(T); + TInfo = Context.getTrivialTypeSourceInfo(T); } // Scope manipulation handled by caller. TypedefDecl *NewTD = TypedefDecl::Create(Context, CurContext, D.getIdentifierLoc(), D.getIdentifier(), - DInfo); + TInfo); if (const TagType *TT = T->getAs()) { TagDecl *TD = TT->getDecl(); @@ -4621,8 +4735,7 @@ Sema::DeclPtrTy Sema::ActOnTag(Scope *S, unsigned TagSpec, TagUseKind TUK, Previous.clear(); } } - } else if (TUK == TUK_Reference && SS.isEmpty() && Name && - (Kind != TagDecl::TK_enum || !getLangOptions().CPlusPlus)) { + } else if (TUK == TUK_Reference && SS.isEmpty() && Name) { // C++ [basic.scope.pdecl]p5: // -- for an elaborated-type-specifier of the form // @@ -4640,6 +4753,11 @@ Sema::DeclPtrTy Sema::ActOnTag(Scope *S, unsigned TagSpec, TagUseKind TUK, // C99 6.7.2.3p8 has a similar (but not identical!) provision for // C structs and unions. // + // It is an error in C++ to declare (rather than define) an enum + // type, including via an elaborated type specifier. We'll + // diagnose that later; for now, declare the enum in the same + // scope as we would have picked for any other tag type. + // // GNU C also supports this behavior as part of its incomplete // enum types extension, while GNU C++ does not. // @@ -4739,10 +4857,7 @@ Sema::DeclPtrTy Sema::ActOnTag(Scope *S, unsigned TagSpec, TagUseKind TUK, LookupResult Lookup(*this, Name, NameLoc, LookupOrdinaryName, ForRedeclaration); LookupName(Lookup, S); - TypedefDecl *PrevTypedef = 0; - if (NamedDecl *Prev = Lookup.getAsSingleDecl(Context)) - PrevTypedef = dyn_cast(Prev); - + TypedefDecl *PrevTypedef = Lookup.getAsSingle(); NamedDecl *PrevTypedefNamed = PrevTypedef; if (PrevTypedef && isDeclInScope(PrevTypedefNamed, SearchDC, S) && Context.getCanonicalType(Context.getTypeDeclType(PrevTypedef)) != @@ -4947,8 +5062,8 @@ FieldDecl *Sema::HandleField(Scope *S, RecordDecl *Record, SourceLocation Loc = DeclStart; if (II) Loc = D.getIdentifierLoc(); - DeclaratorInfo *DInfo = 0; - QualType T = GetTypeForDeclarator(D, S, &DInfo); + TypeSourceInfo *TInfo = 0; + QualType T = GetTypeForDeclarator(D, S, &TInfo); if (getLangOptions().CPlusPlus) CheckExtraCXXDefaultArguments(D); @@ -4974,7 +5089,7 @@ FieldDecl *Sema::HandleField(Scope *S, RecordDecl *Record, = (D.getDeclSpec().getStorageClassSpec() == DeclSpec::SCS_mutable); SourceLocation TSSL = D.getSourceRange().getBegin(); FieldDecl *NewFD - = CheckFieldDecl(II, T, DInfo, Record, Loc, Mutable, BitWidth, TSSL, + = CheckFieldDecl(II, T, TInfo, Record, Loc, Mutable, BitWidth, TSSL, AS, PrevDecl, &D); if (NewFD->isInvalidDecl() && PrevDecl) { // Don't introduce NewFD into scope; there's already something @@ -4998,7 +5113,7 @@ FieldDecl *Sema::HandleField(Scope *S, RecordDecl *Record, /// /// \todo The Declarator argument is a hack. It will be removed once FieldDecl *Sema::CheckFieldDecl(DeclarationName Name, QualType T, - DeclaratorInfo *DInfo, + TypeSourceInfo *TInfo, RecordDecl *Record, SourceLocation Loc, bool Mutable, Expr *BitWidth, SourceLocation TSSL, @@ -5015,9 +5130,14 @@ FieldDecl *Sema::CheckFieldDecl(DeclarationName Name, QualType T, T = Context.IntTy; } + QualType EltTy = Context.getBaseElementType(T); + if (!EltTy->isDependentType() && + RequireCompleteType(Loc, EltTy, diag::err_field_incomplete)) + InvalidDecl = true; + // C99 6.7.2.1p8: A member of a structure or union may have any type other // than a variably modified type. - if (T->isVariablyModifiedType()) { + if (!InvalidDecl && T->isVariablyModifiedType()) { bool SizeIsNegative; QualType FixedTy = TryToFixInvalidVariablyModifiedType(T, Context, SizeIsNegative); @@ -5034,20 +5154,22 @@ FieldDecl *Sema::CheckFieldDecl(DeclarationName Name, QualType T, } // Fields can not have abstract class types - if (RequireNonAbstractType(Loc, T, diag::err_abstract_type_in_decl, - AbstractFieldType)) + if (!InvalidDecl && RequireNonAbstractType(Loc, T, + diag::err_abstract_type_in_decl, + AbstractFieldType)) InvalidDecl = true; bool ZeroWidth = false; // If this is declared as a bit-field, check the bit-field. - if (BitWidth && VerifyBitField(Loc, II, T, BitWidth, &ZeroWidth)) { + if (!InvalidDecl && BitWidth && + VerifyBitField(Loc, II, T, BitWidth, &ZeroWidth)) { InvalidDecl = true; DeleteExpr(BitWidth); BitWidth = 0; ZeroWidth = false; } - FieldDecl *NewFD = FieldDecl::Create(Context, Record, Loc, II, T, DInfo, + FieldDecl *NewFD = FieldDecl::Create(Context, Record, Loc, II, T, TInfo, BitWidth, Mutable); if (InvalidDecl) NewFD->setInvalidDecl(); @@ -5059,8 +5181,6 @@ FieldDecl *Sema::CheckFieldDecl(DeclarationName Name, QualType T, } if (getLangOptions().CPlusPlus) { - QualType EltTy = Context.getBaseElementType(T); - CXXRecordDecl* CXXRecord = cast(Record); if (!T->isPODType()) @@ -5296,8 +5416,8 @@ Sema::DeclPtrTy Sema::ActOnIvar(Scope *S, // FIXME: Unnamed fields can be handled in various different ways, for // example, unnamed unions inject all members into the struct namespace! - DeclaratorInfo *DInfo = 0; - QualType T = GetTypeForDeclarator(D, S, &DInfo); + TypeSourceInfo *TInfo = 0; + QualType T = GetTypeForDeclarator(D, S, &TInfo); if (BitWidth) { // 6.7.2.1p3, 6.7.2.1p4 @@ -5340,7 +5460,7 @@ Sema::DeclPtrTy Sema::ActOnIvar(Scope *S, // Construct the decl. ObjCIvarDecl *NewID = ObjCIvarDecl::Create(Context, EnclosingContext, Loc, II, T, - DInfo, ac, (Expr *)BitfieldWidth); + TInfo, ac, (Expr *)BitfieldWidth); if (II) { NamedDecl *PrevDecl = LookupSingleName(S, II, LookupMemberName, @@ -5403,8 +5523,10 @@ void Sema::ActOnFields(Scope* S, // If the field is already invalid for some reason, don't emit more // diagnostics about it. - if (FD->isInvalidDecl()) + if (FD->isInvalidDecl()) { + EnclosingDecl->setInvalidDecl(); continue; + } // C99 6.7.2.1p2: // A structure or union shall not contain a member with @@ -5540,7 +5662,7 @@ EnumConstantDecl *Sema::CheckEnumConstant(EnumDecl *Enum, llvm::APSInt EnumVal(32); QualType EltTy; if (Val) { - if (Val->isTypeDependent()) + if (Enum->isDependentType()) EltTy = Context.DependentTy; else { // Make sure to promote the operand type to int. @@ -5552,8 +5674,7 @@ EnumConstantDecl *Sema::CheckEnumConstant(EnumDecl *Enum, // C99 6.7.2.2p2: Make sure we have an integer constant expression. SourceLocation ExpLoc; - if (!Val->isValueDependent() && - VerifyIntegerConstantExpression(Val, &EnumVal)) { + if (VerifyIntegerConstantExpression(Val, &EnumVal)) { Val = 0; } else { EltTy = Val->getType(); @@ -5562,7 +5683,9 @@ EnumConstantDecl *Sema::CheckEnumConstant(EnumDecl *Enum, } if (!Val) { - if (LastEnumConst) { + if (Enum->isDependentType()) + EltTy = Context.DependentTy; + else if (LastEnumConst) { // Assign the last value + 1. EnumVal = LastEnumConst->getInitVal(); ++EnumVal; @@ -5576,6 +5699,7 @@ EnumConstantDecl *Sema::CheckEnumConstant(EnumDecl *Enum, // First value, set to zero. EltTy = Context.IntTy; EnumVal.zextOrTrunc(static_cast(Context.getTypeSize(EltTy))); + EnumVal.setIsSigned(true); } } @@ -5647,6 +5771,19 @@ void Sema::ActOnEnumBody(SourceLocation EnumLoc, SourceLocation LBraceLoc, if (Attr) ProcessDeclAttributeList(S, Enum, Attr); + if (Enum->isDependentType()) { + for (unsigned i = 0; i != NumElements; ++i) { + EnumConstantDecl *ECD = + cast_or_null(Elements[i].getAs()); + if (!ECD) continue; + + ECD->setType(EnumType); + } + + Enum->completeDefinition(Context, Context.DependentTy, Context.DependentTy); + return; + } + // TODO: If the result value doesn't fit in an int, it must be a long or long // long value. ISO C does not support this, but GCC does as an extension, // emit a warning. @@ -5698,6 +5835,17 @@ void Sema::ActOnEnumBody(SourceLocation EnumLoc, SourceLocation LBraceLoc, QualType BestType; unsigned BestWidth; + // C++0x N3000 [conv.prom]p3: + // An rvalue of an unscoped enumeration type whose underlying + // type is not fixed can be converted to an rvalue of the first + // of the following types that can represent all the values of + // the enumeration: int, unsigned int, long int, unsigned long + // int, long long int, or unsigned long long int. + // C99 6.4.4.3p2: + // An identifier declared as an enumeration constant has type int. + // The C99 rule is modified by a gcc extension + QualType BestPromotionType; + bool Packed = Enum->getAttr() ? true : false; if (NumNegativeBits) { @@ -5705,22 +5853,21 @@ void Sema::ActOnEnumBody(SourceLocation EnumLoc, SourceLocation LBraceLoc, // int/long/longlong) that fits. // If it's packed, check also if it fits a char or a short. if (Packed && NumNegativeBits <= CharWidth && NumPositiveBits < CharWidth) { - BestType = Context.SignedCharTy; - BestWidth = CharWidth; + BestType = Context.SignedCharTy; + BestWidth = CharWidth; } else if (Packed && NumNegativeBits <= ShortWidth && NumPositiveBits < ShortWidth) { - BestType = Context.ShortTy; - BestWidth = ShortWidth; - } - else if (NumNegativeBits <= IntWidth && NumPositiveBits < IntWidth) { + BestType = Context.ShortTy; + BestWidth = ShortWidth; + } else if (NumNegativeBits <= IntWidth && NumPositiveBits < IntWidth) { BestType = Context.IntTy; BestWidth = IntWidth; } else { BestWidth = Context.Target.getLongWidth(); - if (NumNegativeBits <= BestWidth && NumPositiveBits < BestWidth) + if (NumNegativeBits <= BestWidth && NumPositiveBits < BestWidth) { BestType = Context.LongTy; - else { + } else { BestWidth = Context.Target.getLongLongWidth(); if (NumNegativeBits > BestWidth || NumPositiveBits >= BestWidth) @@ -5728,31 +5875,46 @@ void Sema::ActOnEnumBody(SourceLocation EnumLoc, SourceLocation LBraceLoc, BestType = Context.LongLongTy; } } + BestPromotionType = (BestWidth <= IntWidth ? Context.IntTy : BestType); } else { // If there is no negative value, figure out which of uint, ulong, ulonglong // fits. // If it's packed, check also if it fits a char or a short. if (Packed && NumPositiveBits <= CharWidth) { - BestType = Context.UnsignedCharTy; - BestWidth = CharWidth; + BestType = Context.UnsignedCharTy; + BestPromotionType = Context.IntTy; + BestWidth = CharWidth; } else if (Packed && NumPositiveBits <= ShortWidth) { - BestType = Context.UnsignedShortTy; - BestWidth = ShortWidth; - } - else if (NumPositiveBits <= IntWidth) { + BestType = Context.UnsignedShortTy; + BestPromotionType = Context.IntTy; + BestWidth = ShortWidth; + } else if (NumPositiveBits <= IntWidth) { BestType = Context.UnsignedIntTy; BestWidth = IntWidth; + BestPromotionType = (NumPositiveBits == BestWidth + ? Context.UnsignedIntTy : Context.IntTy); } else if (NumPositiveBits <= (BestWidth = Context.Target.getLongWidth())) { BestType = Context.UnsignedLongTy; + BestPromotionType = (NumPositiveBits == BestWidth + ? Context.UnsignedLongTy : Context.LongTy); } else { BestWidth = Context.Target.getLongLongWidth(); assert(NumPositiveBits <= BestWidth && "How could an initializer get larger than ULL?"); BestType = Context.UnsignedLongLongTy; + BestPromotionType = (NumPositiveBits == BestWidth + ? Context.UnsignedLongLongTy : Context.LongLongTy); } } + // If we're in C and the promotion type is larger than an int, just + // use the underlying type, which is generally the unsigned integer + // type of the same rank as the promotion type. This is how the gcc + // extension works. + if (!getLangOptions().CPlusPlus && BestPromotionType != Context.IntTy) + BestPromotionType = BestType; + // Loop over all of the enumerator constants, changing their types to match // the type of the enum if needed. for (unsigned i = 0; i != NumElements; ++i) { @@ -5765,19 +5927,8 @@ void Sema::ActOnEnumBody(SourceLocation EnumLoc, SourceLocation LBraceLoc, // enumerator value fits in an int, type it as an int, otherwise type it the // same as the enumerator decl itself. This means that in "enum { X = 1U }" // that X has type 'int', not 'unsigned'. - if (ECD->getType() == Context.IntTy) { - // Make sure the init value is signed. - llvm::APSInt IV = ECD->getInitVal(); - IV.setIsSigned(true); - ECD->setInitVal(IV); - - if (getLangOptions().CPlusPlus) - // C++ [dcl.enum]p4: Following the closing brace of an - // enum-specifier, each enumerator has the type of its - // enumeration. - ECD->setType(EnumType); - continue; // Already int type. - } + if (!getLangOptions().CPlusPlus && ECD->getType() == Context.IntTy) + continue; // Determine whether the value fits into an int. llvm::APSInt InitVal = ECD->getInitVal(); @@ -5792,7 +5943,7 @@ void Sema::ActOnEnumBody(SourceLocation EnumLoc, SourceLocation LBraceLoc, QualType NewTy; unsigned NewWidth; bool NewSign; - if (FitsInInt) { + if (FitsInInt && !getLangOptions().CPlusPlus) { NewTy = Context.IntTy; NewWidth = IntWidth; NewSign = true; @@ -5830,7 +5981,7 @@ void Sema::ActOnEnumBody(SourceLocation EnumLoc, SourceLocation LBraceLoc, ECD->setType(NewTy); } - Enum->completeDefinition(Context, BestType); + Enum->completeDefinition(Context, BestType, BestPromotionType); } Sema::DeclPtrTy Sema::ActOnFileScopeAsmDecl(SourceLocation Loc, diff --git a/lib/Sema/SemaDeclAttr.cpp b/lib/Sema/SemaDeclAttr.cpp index b2124fe01459..84ee2073382f 100644 --- a/lib/Sema/SemaDeclAttr.cpp +++ b/lib/Sema/SemaDeclAttr.cpp @@ -195,98 +195,13 @@ static void HandleExtVectorTypeAttr(Scope *scope, Decl *d, QualType T = S.BuildExtVectorType(curType, S.Owned(sizeExpr), Attr.getLoc()); if (!T.isNull()) { // FIXME: preserve the old source info. - tDecl->setTypeDeclaratorInfo(S.Context.getTrivialDeclaratorInfo(T)); + tDecl->setTypeSourceInfo(S.Context.getTrivialTypeSourceInfo(T)); // Remember this typedef decl, we will need it later for diagnostics. S.ExtVectorDecls.push_back(tDecl); } } - -/// HandleVectorSizeAttribute - this attribute is only applicable to integral -/// and float scalars, although arrays, pointers, and function return values are -/// allowed in conjunction with this construct. Aggregates with this attribute -/// are invalid, even if they are of the same size as a corresponding scalar. -/// The raw attribute should contain precisely 1 argument, the vector size for -/// the variable, measured in bytes. If curType and rawAttr are well formed, -/// this routine will return a new vector type. -static void HandleVectorSizeAttr(Decl *D, const AttributeList &Attr, Sema &S) { - QualType CurType; - if (ValueDecl *VD = dyn_cast(D)) - CurType = VD->getType(); - else if (TypedefDecl *TD = dyn_cast(D)) - CurType = TD->getUnderlyingType(); - else { - S.Diag(D->getLocation(), diag::err_attr_wrong_decl) - << "vector_size" << SourceRange(Attr.getLoc(), Attr.getLoc()); - return; - } - - // Check the attribute arugments. - if (Attr.getNumArgs() != 1) { - S.Diag(Attr.getLoc(), diag::err_attribute_wrong_number_arguments) << 1; - return; - } - Expr *sizeExpr = static_cast(Attr.getArg(0)); - llvm::APSInt vecSize(32); - if (!sizeExpr->isIntegerConstantExpr(vecSize, S.Context)) { - S.Diag(Attr.getLoc(), diag::err_attribute_argument_not_int) - << "vector_size" << sizeExpr->getSourceRange(); - return; - } - // navigate to the base type - we need to provide for vector pointers, vector - // arrays, and functions returning vectors. - if (CurType->isPointerType() || CurType->isArrayType() || - CurType->isFunctionType()) { - S.Diag(Attr.getLoc(), diag::err_unsupported_vector_size) << CurType; - return; - /* FIXME: rebuild the type from the inside out, vectorizing the inner type. - do { - if (PointerType *PT = dyn_cast(canonType)) - canonType = PT->getPointeeType().getTypePtr(); - else if (ArrayType *AT = dyn_cast(canonType)) - canonType = AT->getElementType().getTypePtr(); - else if (FunctionType *FT = dyn_cast(canonType)) - canonType = FT->getResultType().getTypePtr(); - } while (canonType->isPointerType() || canonType->isArrayType() || - canonType->isFunctionType()); - */ - } - // the base type must be integer or float, and can't already be a vector. - if (CurType->isVectorType() || - (!CurType->isIntegerType() && !CurType->isRealFloatingType())) { - S.Diag(Attr.getLoc(), diag::err_attribute_invalid_vector_type) << CurType; - return; - } - unsigned typeSize = static_cast(S.Context.getTypeSize(CurType)); - // vecSize is specified in bytes - convert to bits. - unsigned vectorSize = static_cast(vecSize.getZExtValue() * 8); - - // the vector size needs to be an integral multiple of the type size. - if (vectorSize % typeSize) { - S.Diag(Attr.getLoc(), diag::err_attribute_invalid_size) - << sizeExpr->getSourceRange(); - return; - } - if (vectorSize == 0) { - S.Diag(Attr.getLoc(), diag::err_attribute_zero_size) - << sizeExpr->getSourceRange(); - return; - } - - // Success! Instantiate the vector type, the number of elements is > 0, and - // not required to be a power of 2, unlike GCC. - CurType = S.Context.getVectorType(CurType, vectorSize/typeSize); - - if (ValueDecl *VD = dyn_cast(D)) - VD->setType(CurType); - else { - // FIXME: preserve existing source info. - DeclaratorInfo *DInfo = S.Context.getTrivialDeclaratorInfo(CurType); - cast(D)->setTypeDeclaratorInfo(DInfo); - } -} - static void HandlePackedAttr(Decl *d, const AttributeList &Attr, Sema &S) { // check the attribute arguments. if (Attr.getNumArgs() > 0) { @@ -461,7 +376,8 @@ static bool HandleCommonNoReturnAttr(Decl *d, const AttributeList &Attr, if (!isFunctionOrMethod(d) && !isa(d)) { ValueDecl *VD = dyn_cast(d); - if (VD == 0 || !VD->getType()->isBlockPointerType()) { + if (VD == 0 || (!VD->getType()->isBlockPointerType() + && !VD->getType()->isFunctionPointerType())) { S.Diag(Attr.getLoc(), Attr.isCXX0XAttribute() ? diag::err_attribute_wrong_decl_type : diag::warn_attribute_wrong_decl_type) @@ -1143,10 +1059,6 @@ static void HandlePureAttr(Decl *d, const AttributeList &Attr, Sema &S) { } static void HandleCleanupAttr(Decl *d, const AttributeList &Attr, Sema &S) { - // Match gcc which ignores cleanup attrs when compiling C++. - if (S.getLangOptions().CPlusPlus) - return; - if (!Attr.getParameterName()) { S.Diag(Attr.getLoc(), diag::err_attribute_wrong_number_arguments) << 1; return; @@ -1709,7 +1621,7 @@ static void HandleModeAttr(Decl *D, const AttributeList &Attr, Sema &S) { // Install the new type. if (TypedefDecl *TD = dyn_cast(D)) { // FIXME: preserve existing source info. - TD->setTypeDeclaratorInfo(S.Context.getTrivialDeclaratorInfo(NewTy)); + TD->setTypeSourceInfo(S.Context.getTrivialTypeSourceInfo(NewTy)); } else cast(D)->setType(NewTy); } @@ -1964,6 +1876,7 @@ static void ProcessDeclAttribute(Scope *scope, Decl *D, case AttributeList::AT_IBOutlet: HandleIBOutletAttr (D, Attr, S); break; case AttributeList::AT_address_space: case AttributeList::AT_objc_gc: + case AttributeList::AT_vector_size: // Ignore these, these are type attributes, handled by // ProcessTypeAttributes. break; @@ -2013,7 +1926,6 @@ static void ProcessDeclAttribute(Scope *scope, Decl *D, case AttributeList::AT_unavailable: HandleUnavailableAttr (D, Attr, S); break; case AttributeList::AT_unused: HandleUnusedAttr (D, Attr, S); break; case AttributeList::AT_used: HandleUsedAttr (D, Attr, S); break; - case AttributeList::AT_vector_size: HandleVectorSizeAttr (D, Attr, S); break; case AttributeList::AT_visibility: HandleVisibilityAttr (D, Attr, S); break; case AttributeList::AT_warn_unused_result: HandleWarnUnusedResult(D,Attr,S); break; @@ -2062,11 +1974,11 @@ NamedDecl * Sema::DeclClonePragmaWeak(NamedDecl *ND, IdentifierInfo *II) { if (FunctionDecl *FD = dyn_cast(ND)) { NewD = FunctionDecl::Create(FD->getASTContext(), FD->getDeclContext(), FD->getLocation(), DeclarationName(II), - FD->getType(), FD->getDeclaratorInfo()); + FD->getType(), FD->getTypeSourceInfo()); } else if (VarDecl *VD = dyn_cast(ND)) { NewD = VarDecl::Create(VD->getASTContext(), VD->getDeclContext(), VD->getLocation(), II, - VD->getType(), VD->getDeclaratorInfo(), + VD->getType(), VD->getTypeSourceInfo(), VD->getStorageClass()); } return NewD; diff --git a/lib/Sema/SemaDeclCXX.cpp b/lib/Sema/SemaDeclCXX.cpp index f161cb5546a2..228a716ca483 100644 --- a/lib/Sema/SemaDeclCXX.cpp +++ b/lib/Sema/SemaDeclCXX.cpp @@ -12,11 +12,14 @@ //===----------------------------------------------------------------------===// #include "Sema.h" +#include "SemaInit.h" #include "Lookup.h" #include "clang/AST/ASTConsumer.h" #include "clang/AST/ASTContext.h" +#include "clang/AST/RecordLayout.h" #include "clang/AST/CXXInheritance.h" #include "clang/AST/DeclVisitor.h" +#include "clang/AST/TypeLoc.h" #include "clang/AST/TypeOrdering.h" #include "clang/AST/StmtVisitor.h" #include "clang/Parse/DeclSpec.h" @@ -482,24 +485,47 @@ Sema::CheckBaseSpecifier(CXXRecordDecl *Class, assert(BaseDecl && "Base type is not incomplete, but has no definition"); CXXRecordDecl * CXXBaseDecl = cast(BaseDecl); assert(CXXBaseDecl && "Base type is not a C++ type"); - if (!CXXBaseDecl->isEmpty()) - Class->setEmpty(false); - if (CXXBaseDecl->isPolymorphic()) - Class->setPolymorphic(true); + // C++0x CWG Issue #817 indicates that [[final]] classes shouldn't be bases. if (CXXBaseDecl->hasAttr()) { Diag(BaseLoc, diag::err_final_base) << BaseType.getAsString(); - Diag(CXXBaseDecl->getLocation(), diag::note_previous_class_decl) - << BaseType.getAsString(); + Diag(CXXBaseDecl->getLocation(), diag::note_previous_decl) + << BaseType; return 0; } + SetClassDeclAttributesFromBase(Class, CXXBaseDecl, Virtual); + + // Create the base specifier. + // FIXME: Allocate via ASTContext? + return new (Context) CXXBaseSpecifier(SpecifierRange, Virtual, + Class->getTagKind() == RecordDecl::TK_class, + Access, BaseType); +} + +void Sema::SetClassDeclAttributesFromBase(CXXRecordDecl *Class, + const CXXRecordDecl *BaseClass, + bool BaseIsVirtual) { + // A class with a non-empty base class is not empty. + // FIXME: Standard ref? + if (!BaseClass->isEmpty()) + Class->setEmpty(false); + + // C++ [class.virtual]p1: + // A class that [...] inherits a virtual function is called a polymorphic + // class. + if (BaseClass->isPolymorphic()) + Class->setPolymorphic(true); + // C++ [dcl.init.aggr]p1: // An aggregate is [...] a class with [...] no base classes [...]. Class->setAggregate(false); + + // C++ [class]p4: + // A POD-struct is an aggregate class... Class->setPOD(false); - if (Virtual) { + if (BaseIsVirtual) { // C++ [class.ctor]p5: // A constructor is trivial if its class has no virtual base classes. Class->setHasTrivialConstructor(false); @@ -521,33 +547,27 @@ Sema::CheckBaseSpecifier(CXXRecordDecl *Class, // C++ [class.ctor]p5: // A constructor is trivial if all the direct base classes of its // class have trivial constructors. - if (!cast(BaseDecl)->hasTrivialConstructor()) + if (!BaseClass->hasTrivialConstructor()) Class->setHasTrivialConstructor(false); // C++ [class.copy]p6: // A copy constructor is trivial if all the direct base classes of its // class have trivial copy constructors. - if (!cast(BaseDecl)->hasTrivialCopyConstructor()) + if (!BaseClass->hasTrivialCopyConstructor()) Class->setHasTrivialCopyConstructor(false); // C++ [class.copy]p11: // A copy assignment operator is trivial if all the direct base classes // of its class have trivial copy assignment operators. - if (!cast(BaseDecl)->hasTrivialCopyAssignment()) + if (!BaseClass->hasTrivialCopyAssignment()) Class->setHasTrivialCopyAssignment(false); } // C++ [class.ctor]p3: // A destructor is trivial if all the direct base classes of its class // have trivial destructors. - if (!cast(BaseDecl)->hasTrivialDestructor()) + if (!BaseClass->hasTrivialDestructor()) Class->setHasTrivialDestructor(false); - - // Create the base specifier. - // FIXME: Allocate via ASTContext? - return new (Context) CXXBaseSpecifier(SpecifierRange, Virtual, - Class->getTagKind() == RecordDecl::TK_class, - Access, BaseType); } /// ActOnBaseSpecifier - Parsed a base specifier. A base specifier is @@ -976,19 +996,26 @@ Sema::ActOnMemInitializer(DeclPtrTy ConstructorD, if (Member) return BuildMemberInitializer(Member, (Expr**)Args, NumArgs, IdLoc, - RParenLoc); + LParenLoc, RParenLoc); } // It didn't name a member, so see if it names a class. - TypeTy *BaseTy = TemplateTypeTy ? TemplateTypeTy - : getTypeName(*MemberOrBase, IdLoc, S, &SS); - if (!BaseTy) + QualType BaseType; + + TypeSourceInfo *TInfo = 0; + if (TemplateTypeTy) + BaseType = GetTypeFromParser(TemplateTypeTy, &TInfo); + else + BaseType = QualType::getFromOpaquePtr(getTypeName(*MemberOrBase, IdLoc, + S, &SS)); + if (BaseType.isNull()) return Diag(IdLoc, diag::err_mem_init_not_member_or_class) << MemberOrBase << SourceRange(IdLoc, RParenLoc); - QualType BaseType = GetTypeFromParser(BaseTy); + if (!TInfo) + TInfo = Context.getTrivialTypeSourceInfo(BaseType, IdLoc); - return BuildBaseInitializer(BaseType, (Expr **)Args, NumArgs, IdLoc, - RParenLoc, ClassDecl); + return BuildBaseInitializer(BaseType, TInfo, (Expr **)Args, NumArgs, + LParenLoc, RParenLoc, ClassDecl); } /// Checks an initializer expression for use of uninitialized fields, such as @@ -1037,6 +1064,7 @@ static bool InitExprContainsUninitializedFields(const Stmt* S, Sema::MemInitResult Sema::BuildMemberInitializer(FieldDecl *Member, Expr **Args, unsigned NumArgs, SourceLocation IdLoc, + SourceLocation LParenLoc, SourceLocation RParenLoc) { // FIXME: CXXBaseOrMemberInitializer should only contain a single // subexpression so we can wrap it in a CXXExprWithTemporaries if necessary. @@ -1081,7 +1109,8 @@ Sema::BuildMemberInitializer(FieldDecl *Member, Expr **Args, NumArgs), IdLoc, SourceRange(IdLoc, RParenLoc), - Member->getDeclName(), IK_Direct, + Member->getDeclName(), + InitializationKind::CreateDirect(IdLoc, LParenLoc, RParenLoc), ConstructorArgs); if (C) { @@ -1118,22 +1147,25 @@ Sema::BuildMemberInitializer(FieldDecl *Member, Expr **Args, ExprTemporaries.clear(); // FIXME: Perform direct initialization of the member. - return new (Context) CXXBaseOrMemberInitializer(Member, (Expr **)Args, - NumArgs, C, IdLoc, RParenLoc); + return new (Context) CXXBaseOrMemberInitializer(Context, Member, IdLoc, + C, LParenLoc, (Expr **)Args, + NumArgs, RParenLoc); } Sema::MemInitResult -Sema::BuildBaseInitializer(QualType BaseType, Expr **Args, - unsigned NumArgs, SourceLocation IdLoc, - SourceLocation RParenLoc, CXXRecordDecl *ClassDecl) { +Sema::BuildBaseInitializer(QualType BaseType, TypeSourceInfo *BaseTInfo, + Expr **Args, unsigned NumArgs, + SourceLocation LParenLoc, SourceLocation RParenLoc, + CXXRecordDecl *ClassDecl) { bool HasDependentArg = false; for (unsigned i = 0; i < NumArgs; i++) HasDependentArg |= Args[i]->isTypeDependent(); + SourceLocation BaseLoc = BaseTInfo->getTypeLoc().getSourceRange().getBegin(); if (!BaseType->isDependentType()) { if (!BaseType->isRecordType()) - return Diag(IdLoc, diag::err_base_init_does_not_name_class) - << BaseType << SourceRange(IdLoc, RParenLoc); + return Diag(BaseLoc, diag::err_base_init_does_not_name_class) + << BaseType << BaseTInfo->getTypeLoc().getSourceRange(); // C++ [class.base.init]p2: // [...] Unless the mem-initializer-id names a nonstatic data @@ -1179,16 +1211,16 @@ Sema::BuildBaseInitializer(QualType BaseType, Expr **Args, // a direct non-virtual base class and an inherited virtual base // class, the mem-initializer is ill-formed. if (DirectBaseSpec && VirtualBaseSpec) - return Diag(IdLoc, diag::err_base_init_direct_and_virtual) - << BaseType << SourceRange(IdLoc, RParenLoc); + return Diag(BaseLoc, diag::err_base_init_direct_and_virtual) + << BaseType << BaseTInfo->getTypeLoc().getSourceRange(); // C++ [base.class.init]p2: // Unless the mem-initializer-id names a nonstatic data membeer of the // constructor's class ot a direst or virtual base of that class, the // mem-initializer is ill-formed. if (!DirectBaseSpec && !VirtualBaseSpec) - return Diag(IdLoc, diag::err_not_direct_base_or_virtual) - << BaseType << ClassDecl->getNameAsCString() - << SourceRange(IdLoc, RParenLoc); + return Diag(BaseLoc, diag::err_not_direct_base_or_virtual) + << BaseType << ClassDecl->getNameAsCString() + << BaseTInfo->getTypeLoc().getSourceRange(); } CXXConstructorDecl *C = 0; @@ -1200,8 +1232,10 @@ Sema::BuildBaseInitializer(QualType BaseType, Expr **Args, C = PerformInitializationByConstructor(BaseType, MultiExprArg(*this, (void**)Args, NumArgs), - IdLoc, SourceRange(IdLoc, RParenLoc), - Name, IK_Direct, + BaseLoc, + SourceRange(BaseLoc, RParenLoc), + Name, + InitializationKind::CreateDirect(BaseLoc, LParenLoc, RParenLoc), ConstructorArgs); if (C) { // Take over the constructor arguments as our own. @@ -1214,8 +1248,9 @@ Sema::BuildBaseInitializer(QualType BaseType, Expr **Args, // subexpression so we can wrap it in a CXXExprWithTemporaries if necessary. ExprTemporaries.clear(); - return new (Context) CXXBaseOrMemberInitializer(BaseType, (Expr **)Args, - NumArgs, C, IdLoc, RParenLoc); + return new (Context) CXXBaseOrMemberInitializer(Context, BaseTInfo, C, + LParenLoc, (Expr **)Args, + NumArgs, RParenLoc); } bool @@ -1277,14 +1312,14 @@ Sema::SetBaseOrMemberInitializers(CXXConstructorDecl *Constructor, } else { CXXRecordDecl *VBaseDecl = - cast(VBase->getType()->getAs()->getDecl()); + cast(VBase->getType()->getAs()->getDecl()); assert(VBaseDecl && "SetBaseOrMemberInitializers - VBaseDecl null"); CXXConstructorDecl *Ctor = VBaseDecl->getDefaultConstructor(Context); if (!Ctor) { Diag(Constructor->getLocation(), diag::err_missing_default_ctor) << (int)IsImplicitConstructor << Context.getTagDeclType(ClassDecl) << 0 << VBase->getType(); - Diag(VBaseDecl->getLocation(), diag::note_previous_class_decl) + Diag(VBaseDecl->getLocation(), diag::note_previous_decl) << Context.getTagDeclType(VBaseDecl); HadError = true; continue; @@ -1298,13 +1333,18 @@ Sema::SetBaseOrMemberInitializers(CXXConstructorDecl *Constructor, MarkDeclarationReferenced(Constructor->getLocation(), Ctor); // FIXME: CXXBaseOrMemberInitializer should only contain a single - // subexpression so we can wrap it in a CXXExprWithTemporaries if necessary. + // subexpression so we can wrap it in a CXXExprWithTemporaries if + // necessary. + // FIXME: Is there any better source-location information we can give? ExprTemporaries.clear(); CXXBaseOrMemberInitializer *Member = - new (Context) CXXBaseOrMemberInitializer(VBase->getType(), - CtorArgs.takeAs(), - CtorArgs.size(), Ctor, + new (Context) CXXBaseOrMemberInitializer(Context, + Context.getTrivialTypeSourceInfo(VBase->getType(), + SourceLocation()), + Ctor, SourceLocation(), + CtorArgs.takeAs(), + CtorArgs.size(), SourceLocation()); AllToInit.push_back(Member); } @@ -1332,7 +1372,7 @@ Sema::SetBaseOrMemberInitializers(CXXConstructorDecl *Constructor, Diag(Constructor->getLocation(), diag::err_missing_default_ctor) << (int)IsImplicitConstructor << Context.getTagDeclType(ClassDecl) << 0 << Base->getType(); - Diag(BaseDecl->getLocation(), diag::note_previous_class_decl) + Diag(BaseDecl->getLocation(), diag::note_previous_decl) << Context.getTagDeclType(BaseDecl); HadError = true; continue; @@ -1346,13 +1386,18 @@ Sema::SetBaseOrMemberInitializers(CXXConstructorDecl *Constructor, MarkDeclarationReferenced(Constructor->getLocation(), Ctor); // FIXME: CXXBaseOrMemberInitializer should only contain a single - // subexpression so we can wrap it in a CXXExprWithTemporaries if necessary. + // subexpression so we can wrap it in a CXXExprWithTemporaries if + // necessary. + // FIXME: Is there any better source-location information we can give? ExprTemporaries.clear(); CXXBaseOrMemberInitializer *Member = - new (Context) CXXBaseOrMemberInitializer(Base->getType(), - CtorArgs.takeAs(), - CtorArgs.size(), Ctor, + new (Context) CXXBaseOrMemberInitializer(Context, + Context.getTrivialTypeSourceInfo(Base->getType(), + SourceLocation()), + Ctor, SourceLocation(), + CtorArgs.takeAs(), + CtorArgs.size(), SourceLocation()); AllToInit.push_back(Member); } @@ -1399,7 +1444,7 @@ Sema::SetBaseOrMemberInitializers(CXXConstructorDecl *Constructor, << (int)IsImplicitConstructor << Context.getTagDeclType(ClassDecl) << 1 << (*Field)->getDeclName(); Diag(Field->getLocation(), diag::note_field_decl); - Diag(RT->getDecl()->getLocation(), diag::note_previous_class_decl) + Diag(RT->getDecl()->getLocation(), diag::note_previous_decl) << Context.getTagDeclType(RT->getDecl()); HadError = true; continue; @@ -1427,9 +1472,12 @@ Sema::SetBaseOrMemberInitializers(CXXConstructorDecl *Constructor, // subexpression so we can wrap it in a CXXExprWithTemporaries if necessary. ExprTemporaries.clear(); CXXBaseOrMemberInitializer *Member = - new (Context) CXXBaseOrMemberInitializer(*Field,CtorArgs.takeAs(), - CtorArgs.size(), Ctor, + new (Context) CXXBaseOrMemberInitializer(Context, + *Field, SourceLocation(), + Ctor, SourceLocation(), + CtorArgs.takeAs(), + CtorArgs.size(), SourceLocation()); AllToInit.push_back(Member); @@ -1537,13 +1585,15 @@ void Sema::ActOnMemInitializers(DeclPtrTy ConstructorDecl, if (FieldDecl *Field = Member->getMember()) Diag(Member->getSourceLocation(), diag::error_multiple_mem_initialization) - << Field->getNameAsString(); + << Field->getNameAsString() + << Member->getSourceRange(); else { Type *BaseClass = Member->getBaseClass(); assert(BaseClass && "ActOnMemInitializers - neither field or base"); Diag(Member->getSourceLocation(), diag::error_multiple_base_initialization) - << QualType(BaseClass, 0); + << QualType(BaseClass, 0) + << Member->getSourceRange(); } Diag(PrevMember->getSourceLocation(), diag::note_previous_initializer) << 0; @@ -1920,6 +1970,28 @@ namespace { }; } +/// \brief Perform semantic checks on a class definition that has been +/// completing, introducing implicitly-declared members, checking for +/// abstract types, etc. +void Sema::CheckCompletedCXXClass(CXXRecordDecl *Record) { + if (!Record || Record->isInvalidDecl()) + return; + + if (!Record->isAbstract()) { + // Collect all the pure virtual methods and see if this is an abstract + // class after all. + PureVirtualMethodCollector Collector(Context, Record); + if (!Collector.empty()) + Record->setAbstract(true); + } + + if (Record->isAbstract()) + (void)AbstractClassUsageDiagnoser(*this, Record); + + if (!Record->isDependentType() && !Record->isInvalidDecl()) + AddImplicitlyDeclaredMembersToClass(Record); +} + void Sema::ActOnFinishCXXMemberSpecification(Scope* S, SourceLocation RLoc, DeclPtrTy TagDecl, SourceLocation LBrac, @@ -1928,24 +2000,13 @@ void Sema::ActOnFinishCXXMemberSpecification(Scope* S, SourceLocation RLoc, return; AdjustDeclIfTemplate(TagDecl); + ActOnFields(S, RLoc, TagDecl, (DeclPtrTy*)FieldCollector->getCurFields(), FieldCollector->getCurNumFields(), LBrac, RBrac, 0); - CXXRecordDecl *RD = cast(TagDecl.getAs()); - if (!RD->isAbstract()) { - // Collect all the pure virtual methods and see if this is an abstract - // class after all. - PureVirtualMethodCollector Collector(Context, RD); - if (!Collector.empty()) - RD->setAbstract(true); - } - - if (RD->isAbstract()) - (void)AbstractClassUsageDiagnoser(*this, RD); - - if (!RD->isDependentType() && !RD->isInvalidDecl()) - AddImplicitlyDeclaredMembersToClass(RD); + CheckCompletedCXXClass( + dyn_cast_or_null(TagDecl.getAs())); } /// AddImplicitlyDeclaredMembersToClass - Adds any implicitly-declared @@ -1974,7 +2035,7 @@ void Sema::AddImplicitlyDeclaredMembersToClass(CXXRecordDecl *ClassDecl) { ClassDecl->getLocation(), Name, Context.getFunctionType(Context.VoidTy, 0, 0, false, 0), - /*DInfo=*/0, + /*TInfo=*/0, /*isExplicit=*/false, /*isInline=*/true, /*isImplicitlyDeclared=*/true); @@ -2046,7 +2107,7 @@ void Sema::AddImplicitlyDeclaredMembersToClass(CXXRecordDecl *ClassDecl) { Context.getFunctionType(Context.VoidTy, &ArgType, 1, false, 0), - /*DInfo=*/0, + /*TInfo=*/0, /*isExplicit=*/false, /*isInline=*/true, /*isImplicitlyDeclared=*/true); @@ -2058,7 +2119,7 @@ void Sema::AddImplicitlyDeclaredMembersToClass(CXXRecordDecl *ClassDecl) { ParmVarDecl *FromParam = ParmVarDecl::Create(Context, CopyConstructor, ClassDecl->getLocation(), /*IdentifierInfo=*/0, - ArgType, /*DInfo=*/0, + ArgType, /*TInfo=*/0, VarDecl::None, 0); CopyConstructor->setParams(Context, &FromParam, 1); ClassDecl->addDecl(CopyConstructor); @@ -2132,7 +2193,7 @@ void Sema::AddImplicitlyDeclaredMembersToClass(CXXRecordDecl *ClassDecl) { CXXMethodDecl::Create(Context, ClassDecl, ClassDecl->getLocation(), Name, Context.getFunctionType(RetType, &ArgType, 1, false, 0), - /*DInfo=*/0, /*isStatic=*/false, /*isInline=*/true); + /*TInfo=*/0, /*isStatic=*/false, /*isInline=*/true); CopyAssignment->setAccess(AS_public); CopyAssignment->setImplicit(); CopyAssignment->setTrivial(ClassDecl->hasTrivialCopyAssignment()); @@ -2142,13 +2203,14 @@ void Sema::AddImplicitlyDeclaredMembersToClass(CXXRecordDecl *ClassDecl) { ParmVarDecl *FromParam = ParmVarDecl::Create(Context, CopyAssignment, ClassDecl->getLocation(), /*IdentifierInfo=*/0, - ArgType, /*DInfo=*/0, + ArgType, /*TInfo=*/0, VarDecl::None, 0); CopyAssignment->setParams(Context, &FromParam, 1); // Don't call addedAssignmentOperator. There is no way to distinguish an // implicit from an explicit assignment operator. ClassDecl->addDecl(CopyAssignment); + AddOverriddenMethods(ClassDecl, CopyAssignment); } if (!ClassDecl->hasUserDeclaredDestructor()) { @@ -2814,6 +2876,7 @@ void Sema::PushUsingDirective(Scope *S, UsingDirectiveDecl *UDir) { Sema::DeclPtrTy Sema::ActOnUsingDeclaration(Scope *S, AccessSpecifier AS, + bool HasUsingKeyword, SourceLocation UsingLoc, const CXXScopeSpec &SS, UnqualifiedId &Name, @@ -2830,6 +2893,9 @@ Sema::DeclPtrTy Sema::ActOnUsingDeclaration(Scope *S, break; case UnqualifiedId::IK_ConstructorName: + // C++0x inherited constructors. + if (getLangOptions().CPlusPlus0x) break; + Diag(Name.getSourceRange().getBegin(), diag::err_using_decl_constructor) << SS.getRange(); return DeclPtrTy(); @@ -2846,45 +2912,237 @@ Sema::DeclPtrTy Sema::ActOnUsingDeclaration(Scope *S, } DeclarationName TargetName = GetNameFromUnqualifiedId(Name); + if (!TargetName) + return DeclPtrTy(); + + // Warn about using declarations. + // TODO: store that the declaration was written without 'using' and + // talk about access decls instead of using decls in the + // diagnostics. + if (!HasUsingKeyword) { + UsingLoc = Name.getSourceRange().getBegin(); + + Diag(UsingLoc, diag::warn_access_decl_deprecated) + << CodeModificationHint::CreateInsertion(SS.getRange().getBegin(), + "using "); + } + NamedDecl *UD = BuildUsingDeclaration(S, AS, UsingLoc, SS, Name.getSourceRange().getBegin(), TargetName, AttrList, /* IsInstantiation */ false, IsTypeName, TypenameLoc); - if (UD) { - PushOnScopeChains(UD, S); - UD->setAccess(AS); - } + if (UD) + PushOnScopeChains(UD, S, /*AddToContext*/ false); return DeclPtrTy::make(UD); } +/// Determines whether to create a using shadow decl for a particular +/// decl, given the set of decls existing prior to this using lookup. +bool Sema::CheckUsingShadowDecl(UsingDecl *Using, NamedDecl *Orig, + const LookupResult &Previous) { + // Diagnose finding a decl which is not from a base class of the + // current class. We do this now because there are cases where this + // function will silently decide not to build a shadow decl, which + // will pre-empt further diagnostics. + // + // We don't need to do this in C++0x because we do the check once on + // the qualifier. + // + // FIXME: diagnose the following if we care enough: + // struct A { int foo; }; + // struct B : A { using A::foo; }; + // template struct C : A {}; + // template struct D : C { using B::foo; } // <--- + // This is invalid (during instantiation) in C++03 because B::foo + // resolves to the using decl in B, which is not a base class of D. + // We can't diagnose it immediately because C is an unknown + // specialization. The UsingShadowDecl in D then points directly + // to A::foo, which will look well-formed when we instantiate. + // The right solution is to not collapse the shadow-decl chain. + if (!getLangOptions().CPlusPlus0x && CurContext->isRecord()) { + DeclContext *OrigDC = Orig->getDeclContext(); + + // Handle enums and anonymous structs. + if (isa(OrigDC)) OrigDC = OrigDC->getParent(); + CXXRecordDecl *OrigRec = cast(OrigDC); + while (OrigRec->isAnonymousStructOrUnion()) + OrigRec = cast(OrigRec->getDeclContext()); + + if (cast(CurContext)->isProvablyNotDerivedFrom(OrigRec)) { + if (OrigDC == CurContext) { + Diag(Using->getLocation(), + diag::err_using_decl_nested_name_specifier_is_current_class) + << Using->getNestedNameRange(); + Diag(Orig->getLocation(), diag::note_using_decl_target); + return true; + } + + Diag(Using->getNestedNameRange().getBegin(), + diag::err_using_decl_nested_name_specifier_is_not_base_class) + << Using->getTargetNestedNameDecl() + << cast(CurContext) + << Using->getNestedNameRange(); + Diag(Orig->getLocation(), diag::note_using_decl_target); + return true; + } + } + + if (Previous.empty()) return false; + + NamedDecl *Target = Orig; + if (isa(Target)) + Target = cast(Target)->getTargetDecl(); + + // If the target happens to be one of the previous declarations, we + // don't have a conflict. + // + // FIXME: but we might be increasing its access, in which case we + // should redeclare it. + NamedDecl *NonTag = 0, *Tag = 0; + for (LookupResult::iterator I = Previous.begin(), E = Previous.end(); + I != E; ++I) { + NamedDecl *D = (*I)->getUnderlyingDecl(); + if (D->getCanonicalDecl() == Target->getCanonicalDecl()) + return false; + + (isa(D) ? Tag : NonTag) = D; + } + + if (Target->isFunctionOrFunctionTemplate()) { + FunctionDecl *FD; + if (isa(Target)) + FD = cast(Target)->getTemplatedDecl(); + else + FD = cast(Target); + + NamedDecl *OldDecl = 0; + switch (CheckOverload(FD, Previous, OldDecl)) { + case Ovl_Overload: + return false; + + case Ovl_NonFunction: + Diag(Using->getLocation(), diag::err_using_decl_conflict); + break; + + // We found a decl with the exact signature. + case Ovl_Match: + if (isa(OldDecl)) { + // Silently ignore the possible conflict. + return false; + } + + // If we're in a record, we want to hide the target, so we + // return true (without a diagnostic) to tell the caller not to + // build a shadow decl. + if (CurContext->isRecord()) + return true; + + // If we're not in a record, this is an error. + Diag(Using->getLocation(), diag::err_using_decl_conflict); + break; + } + + Diag(Target->getLocation(), diag::note_using_decl_target); + Diag(OldDecl->getLocation(), diag::note_using_decl_conflict); + return true; + } + + // Target is not a function. + + if (isa(Target)) { + // No conflict between a tag and a non-tag. + if (!Tag) return false; + + Diag(Using->getLocation(), diag::err_using_decl_conflict); + Diag(Target->getLocation(), diag::note_using_decl_target); + Diag(Tag->getLocation(), diag::note_using_decl_conflict); + return true; + } + + // No conflict between a tag and a non-tag. + if (!NonTag) return false; + + Diag(Using->getLocation(), diag::err_using_decl_conflict); + Diag(Target->getLocation(), diag::note_using_decl_target); + Diag(NonTag->getLocation(), diag::note_using_decl_conflict); + return true; +} + /// Builds a shadow declaration corresponding to a 'using' declaration. -static UsingShadowDecl *BuildUsingShadowDecl(Sema &SemaRef, Scope *S, - AccessSpecifier AS, - UsingDecl *UD, NamedDecl *Orig) { - // FIXME: diagnose hiding, collisions +UsingShadowDecl *Sema::BuildUsingShadowDecl(Scope *S, + UsingDecl *UD, + NamedDecl *Orig) { // If we resolved to another shadow declaration, just coalesce them. - if (isa(Orig)) { - Orig = cast(Orig)->getTargetDecl(); - assert(!isa(Orig) && "nested shadow declaration"); + NamedDecl *Target = Orig; + if (isa(Target)) { + Target = cast(Target)->getTargetDecl(); + assert(!isa(Target) && "nested shadow declaration"); } UsingShadowDecl *Shadow - = UsingShadowDecl::Create(SemaRef.Context, SemaRef.CurContext, - UD->getLocation(), UD, Orig); + = UsingShadowDecl::Create(Context, CurContext, + UD->getLocation(), UD, Target); UD->addShadowDecl(Shadow); if (S) - SemaRef.PushOnScopeChains(Shadow, S); + PushOnScopeChains(Shadow, S); else - SemaRef.CurContext->addDecl(Shadow); - Shadow->setAccess(AS); + CurContext->addDecl(Shadow); + Shadow->setAccess(UD->getAccess()); + + if (Orig->isInvalidDecl() || UD->isInvalidDecl()) + Shadow->setInvalidDecl(); return Shadow; } +/// Hides a using shadow declaration. This is required by the current +/// using-decl implementation when a resolvable using declaration in a +/// class is followed by a declaration which would hide or override +/// one or more of the using decl's targets; for example: +/// +/// struct Base { void foo(int); }; +/// struct Derived : Base { +/// using Base::foo; +/// void foo(int); +/// }; +/// +/// The governing language is C++03 [namespace.udecl]p12: +/// +/// When a using-declaration brings names from a base class into a +/// derived class scope, member functions in the derived class +/// override and/or hide member functions with the same name and +/// parameter types in a base class (rather than conflicting). +/// +/// There are two ways to implement this: +/// (1) optimistically create shadow decls when they're not hidden +/// by existing declarations, or +/// (2) don't create any shadow decls (or at least don't make them +/// visible) until we've fully parsed/instantiated the class. +/// The problem with (1) is that we might have to retroactively remove +/// a shadow decl, which requires several O(n) operations because the +/// decl structures are (very reasonably) not designed for removal. +/// (2) avoids this but is very fiddly and phase-dependent. +void Sema::HideUsingShadowDecl(Scope *S, UsingShadowDecl *Shadow) { + // Remove it from the DeclContext... + Shadow->getDeclContext()->removeDecl(Shadow); + + // ...and the scope, if applicable... + if (S) { + S->RemoveDecl(DeclPtrTy::make(static_cast(Shadow))); + IdResolver.RemoveDecl(Shadow); + } + + // ...and the using decl. + Shadow->getUsingDecl()->removeShadowDecl(Shadow); + + // TODO: complain somehow if Shadow was used. It shouldn't + // be possible for this to happen, because +} + /// Builds a using declaration. /// /// \param IsInstantiation - Whether this call arises from an @@ -2910,56 +3168,76 @@ NamedDecl *Sema::BuildUsingDeclaration(Scope *S, AccessSpecifier AS, return 0; } + // Do the redeclaration lookup in the current scope. + LookupResult Previous(*this, Name, IdentLoc, LookupUsingDeclName, + ForRedeclaration); + Previous.setHideTags(false); + if (S) { + LookupName(Previous, S); + + // It is really dumb that we have to do this. + LookupResult::Filter F = Previous.makeFilter(); + while (F.hasNext()) { + NamedDecl *D = F.next(); + if (!isDeclInScope(D, CurContext, S)) + F.erase(); + } + F.done(); + } else { + assert(IsInstantiation && "no scope in non-instantiation"); + assert(CurContext->isRecord() && "scope not record in instantiation"); + LookupQualifiedName(Previous, CurContext); + } + NestedNameSpecifier *NNS = static_cast(SS.getScopeRep()); + // Check for invalid redeclarations. + if (CheckUsingDeclRedeclaration(UsingLoc, IsTypeName, SS, IdentLoc, Previous)) + return 0; + + // Check for bad qualifiers. + if (CheckUsingDeclQualifier(UsingLoc, SS, IdentLoc)) + return 0; + DeclContext *LookupContext = computeDeclContext(SS); + NamedDecl *D; if (!LookupContext) { if (IsTypeName) { - return UnresolvedUsingTypenameDecl::Create(Context, CurContext, - UsingLoc, TypenameLoc, - SS.getRange(), NNS, - IdentLoc, Name); - } else { - return UnresolvedUsingValueDecl::Create(Context, CurContext, - UsingLoc, SS.getRange(), NNS, + // FIXME: not all declaration name kinds are legal here + D = UnresolvedUsingTypenameDecl::Create(Context, CurContext, + UsingLoc, TypenameLoc, + SS.getRange(), NNS, IdentLoc, Name); - } - } - - if (const CXXRecordDecl *RD = dyn_cast(CurContext)) { - // C++0x N2914 [namespace.udecl]p3: - // A using-declaration used as a member-declaration shall refer to a member - // of a base class of the class being defined, shall refer to a member of an - // anonymous union that is a member of a base class of the class being - // defined, or shall refer to an enumerator for an enumeration type that is - // a member of a base class of the class being defined. - - CXXRecordDecl *LookupRD = dyn_cast(LookupContext); - if (!LookupRD || !RD->isDerivedFrom(LookupRD)) { - Diag(SS.getRange().getBegin(), - diag::err_using_decl_nested_name_specifier_is_not_a_base_class) - << NNS << RD->getDeclName(); - return 0; + } else { + D = UnresolvedUsingValueDecl::Create(Context, CurContext, + UsingLoc, SS.getRange(), NNS, + IdentLoc, Name); } } else { - // C++0x N2914 [namespace.udecl]p8: - // A using-declaration for a class member shall be a member-declaration. - if (isa(LookupContext)) { - Diag(IdentLoc, diag::err_using_decl_can_not_refer_to_class_member) - << SS.getRange(); - return 0; - } + D = UsingDecl::Create(Context, CurContext, IdentLoc, + SS.getRange(), UsingLoc, NNS, Name, + IsTypeName); + } + D->setAccess(AS); + CurContext->addDecl(D); + + if (!LookupContext) return D; + UsingDecl *UD = cast(D); + + if (RequireCompleteDeclContext(SS)) { + UD->setInvalidDecl(); + return UD; } - // Look up the target name. Unlike most lookups, we do not want to - // hide tag declarations: tag names are visible through the using - // declaration even if hidden by ordinary names. + // Look up the target name. + LookupResult R(*this, Name, IdentLoc, LookupOrdinaryName); - // We don't hide tags behind ordinary decls if we're in a - // non-dependent context, but in a dependent context, this is - // important for the stability of two-phase lookup. + // Unlike most lookups, we don't always want to hide tag + // declarations: tag names are visible through the using declaration + // even if hidden by ordinary names, *except* in a dependent context + // where it's important for the sanity of two-phase lookup. if (!IsInstantiation) R.setHideTags(false); @@ -2968,54 +3246,243 @@ NamedDecl *Sema::BuildUsingDeclaration(Scope *S, AccessSpecifier AS, if (R.empty()) { Diag(IdentLoc, diag::err_no_member) << Name << LookupContext << SS.getRange(); - return 0; + UD->setInvalidDecl(); + return UD; } - if (R.isAmbiguous()) - return 0; + if (R.isAmbiguous()) { + UD->setInvalidDecl(); + return UD; + } if (IsTypeName) { // If we asked for a typename and got a non-type decl, error out. - if (R.getResultKind() != LookupResult::Found - || !isa(R.getFoundDecl())) { + if (!R.getAsSingle()) { Diag(IdentLoc, diag::err_using_typename_non_type); for (LookupResult::iterator I = R.begin(), E = R.end(); I != E; ++I) Diag((*I)->getUnderlyingDecl()->getLocation(), diag::note_using_decl_target); - return 0; + UD->setInvalidDecl(); + return UD; } } else { // If we asked for a non-typename and we got a type, error out, // but only if this is an instantiation of an unresolved using // decl. Otherwise just silently find the type name. - if (IsInstantiation && - R.getResultKind() == LookupResult::Found && - isa(R.getFoundDecl())) { + if (IsInstantiation && R.getAsSingle()) { Diag(IdentLoc, diag::err_using_dependent_value_is_type); Diag(R.getFoundDecl()->getLocation(), diag::note_using_decl_target); - return 0; + UD->setInvalidDecl(); + return UD; } } // C++0x N2914 [namespace.udecl]p6: // A using-declaration shall not name a namespace. - if (R.getResultKind() == LookupResult::Found - && isa(R.getFoundDecl())) { + if (R.getAsSingle()) { Diag(IdentLoc, diag::err_using_decl_can_not_refer_to_namespace) << SS.getRange(); - return 0; + UD->setInvalidDecl(); + return UD; } - UsingDecl *UD = UsingDecl::Create(Context, CurContext, IdentLoc, - SS.getRange(), UsingLoc, NNS, Name, - IsTypeName); - - for (LookupResult::iterator I = R.begin(), E = R.end(); I != E; ++I) - BuildUsingShadowDecl(*this, S, AS, UD, *I); + for (LookupResult::iterator I = R.begin(), E = R.end(); I != E; ++I) { + if (!CheckUsingShadowDecl(UD, *I, Previous)) + BuildUsingShadowDecl(S, UD, *I); + } return UD; } +/// Checks that the given using declaration is not an invalid +/// redeclaration. Note that this is checking only for the using decl +/// itself, not for any ill-formedness among the UsingShadowDecls. +bool Sema::CheckUsingDeclRedeclaration(SourceLocation UsingLoc, + bool isTypeName, + const CXXScopeSpec &SS, + SourceLocation NameLoc, + const LookupResult &Prev) { + // C++03 [namespace.udecl]p8: + // C++0x [namespace.udecl]p10: + // A using-declaration is a declaration and can therefore be used + // repeatedly where (and only where) multiple declarations are + // allowed. + // That's only in file contexts. + if (CurContext->getLookupContext()->isFileContext()) + return false; + + NestedNameSpecifier *Qual + = static_cast(SS.getScopeRep()); + + for (LookupResult::iterator I = Prev.begin(), E = Prev.end(); I != E; ++I) { + NamedDecl *D = *I; + + bool DTypename; + NestedNameSpecifier *DQual; + if (UsingDecl *UD = dyn_cast(D)) { + DTypename = UD->isTypeName(); + DQual = UD->getTargetNestedNameDecl(); + } else if (UnresolvedUsingValueDecl *UD + = dyn_cast(D)) { + DTypename = false; + DQual = UD->getTargetNestedNameSpecifier(); + } else if (UnresolvedUsingTypenameDecl *UD + = dyn_cast(D)) { + DTypename = true; + DQual = UD->getTargetNestedNameSpecifier(); + } else continue; + + // using decls differ if one says 'typename' and the other doesn't. + // FIXME: non-dependent using decls? + if (isTypeName != DTypename) continue; + + // using decls differ if they name different scopes (but note that + // template instantiation can cause this check to trigger when it + // didn't before instantiation). + if (Context.getCanonicalNestedNameSpecifier(Qual) != + Context.getCanonicalNestedNameSpecifier(DQual)) + continue; + + Diag(NameLoc, diag::err_using_decl_redeclaration) << SS.getRange(); + Diag(D->getLocation(), diag::note_using_decl) << 1; + return true; + } + + return false; +} + + +/// Checks that the given nested-name qualifier used in a using decl +/// in the current context is appropriately related to the current +/// scope. If an error is found, diagnoses it and returns true. +bool Sema::CheckUsingDeclQualifier(SourceLocation UsingLoc, + const CXXScopeSpec &SS, + SourceLocation NameLoc) { + DeclContext *NamedContext = computeDeclContext(SS); + + if (!CurContext->isRecord()) { + // C++03 [namespace.udecl]p3: + // C++0x [namespace.udecl]p8: + // A using-declaration for a class member shall be a member-declaration. + + // If we weren't able to compute a valid scope, it must be a + // dependent class scope. + if (!NamedContext || NamedContext->isRecord()) { + Diag(NameLoc, diag::err_using_decl_can_not_refer_to_class_member) + << SS.getRange(); + return true; + } + + // Otherwise, everything is known to be fine. + return false; + } + + // The current scope is a record. + + // If the named context is dependent, we can't decide much. + if (!NamedContext) { + // FIXME: in C++0x, we can diagnose if we can prove that the + // nested-name-specifier does not refer to a base class, which is + // still possible in some cases. + + // Otherwise we have to conservatively report that things might be + // okay. + return false; + } + + if (!NamedContext->isRecord()) { + // Ideally this would point at the last name in the specifier, + // but we don't have that level of source info. + Diag(SS.getRange().getBegin(), + diag::err_using_decl_nested_name_specifier_is_not_class) + << (NestedNameSpecifier*) SS.getScopeRep() << SS.getRange(); + return true; + } + + if (getLangOptions().CPlusPlus0x) { + // C++0x [namespace.udecl]p3: + // In a using-declaration used as a member-declaration, the + // nested-name-specifier shall name a base class of the class + // being defined. + + if (cast(CurContext)->isProvablyNotDerivedFrom( + cast(NamedContext))) { + if (CurContext == NamedContext) { + Diag(NameLoc, + diag::err_using_decl_nested_name_specifier_is_current_class) + << SS.getRange(); + return true; + } + + Diag(SS.getRange().getBegin(), + diag::err_using_decl_nested_name_specifier_is_not_base_class) + << (NestedNameSpecifier*) SS.getScopeRep() + << cast(CurContext) + << SS.getRange(); + return true; + } + + return false; + } + + // C++03 [namespace.udecl]p4: + // A using-declaration used as a member-declaration shall refer + // to a member of a base class of the class being defined [etc.]. + + // Salient point: SS doesn't have to name a base class as long as + // lookup only finds members from base classes. Therefore we can + // diagnose here only if we can prove that that can't happen, + // i.e. if the class hierarchies provably don't intersect. + + // TODO: it would be nice if "definitely valid" results were cached + // in the UsingDecl and UsingShadowDecl so that these checks didn't + // need to be repeated. + + struct UserData { + llvm::DenseSet Bases; + + static bool collect(const CXXRecordDecl *Base, void *OpaqueData) { + UserData *Data = reinterpret_cast(OpaqueData); + Data->Bases.insert(Base); + return true; + } + + bool hasDependentBases(const CXXRecordDecl *Class) { + return !Class->forallBases(collect, this); + } + + /// Returns true if the base is dependent or is one of the + /// accumulated base classes. + static bool doesNotContain(const CXXRecordDecl *Base, void *OpaqueData) { + UserData *Data = reinterpret_cast(OpaqueData); + return !Data->Bases.count(Base); + } + + bool mightShareBases(const CXXRecordDecl *Class) { + return Bases.count(Class) || !Class->forallBases(doesNotContain, this); + } + }; + + UserData Data; + + // Returns false if we find a dependent base. + if (Data.hasDependentBases(cast(CurContext))) + return false; + + // Returns false if the class has a dependent base or if it or one + // of its bases is present in the base set of the current context. + if (Data.mightShareBases(cast(NamedContext))) + return false; + + Diag(SS.getRange().getBegin(), + diag::err_using_decl_nested_name_specifier_is_not_base_class) + << (NestedNameSpecifier*) SS.getScopeRep() + << cast(CurContext) + << SS.getRange(); + + return true; +} + Sema::DeclPtrTy Sema::ActOnNamespaceAliasDef(Scope *S, SourceLocation NamespaceLoc, SourceLocation AliasLoc, @@ -3081,7 +3548,6 @@ void Sema::DefineImplicitDefaultConstructor(SourceLocation CurrentLocation, } else { Constructor->setUsed(); } - return; } void Sema::DefineImplicitDestructor(SourceLocation CurrentLocation, @@ -3163,7 +3629,8 @@ void Sema::DefineImplicitOverloadedAssign(SourceLocation CurrentLocation, CXXRecordDecl *BaseClassDecl = cast(Base->getType()->getAs()->getDecl()); if (CXXMethodDecl *BaseAssignOpMethod = - getAssignOperatorMethod(MethodDecl->getParamDecl(0), BaseClassDecl)) + getAssignOperatorMethod(CurrentLocation, MethodDecl->getParamDecl(0), + BaseClassDecl)) MarkDeclarationReferenced(CurrentLocation, BaseAssignOpMethod); } for (CXXRecordDecl::field_iterator Field = ClassDecl->field_begin(), @@ -3175,7 +3642,8 @@ void Sema::DefineImplicitOverloadedAssign(SourceLocation CurrentLocation, CXXRecordDecl *FieldClassDecl = cast(FieldClassType->getDecl()); if (CXXMethodDecl *FieldAssignOpMethod = - getAssignOperatorMethod(MethodDecl->getParamDecl(0), FieldClassDecl)) + getAssignOperatorMethod(CurrentLocation, MethodDecl->getParamDecl(0), + FieldClassDecl)) MarkDeclarationReferenced(CurrentLocation, FieldAssignOpMethod); } else if (FieldType->isReferenceType()) { Diag(ClassDecl->getLocation(), diag::err_uninitialized_member_for_assign) @@ -3196,7 +3664,8 @@ void Sema::DefineImplicitOverloadedAssign(SourceLocation CurrentLocation, } CXXMethodDecl * -Sema::getAssignOperatorMethod(ParmVarDecl *ParmDecl, +Sema::getAssignOperatorMethod(SourceLocation CurrentLocation, + ParmVarDecl *ParmDecl, CXXRecordDecl *ClassDecl) { QualType LHSType = Context.getTypeDeclType(ClassDecl); QualType RHSType(LHSType); @@ -3206,18 +3675,17 @@ Sema::getAssignOperatorMethod(ParmVarDecl *ParmDecl, RHSType = Context.getCVRQualifiedType(RHSType, ParmDecl->getType().getCVRQualifiers()); ExprOwningPtr LHS(this, new (Context) DeclRefExpr(ParmDecl, - LHSType, - SourceLocation())); + LHSType, + SourceLocation())); ExprOwningPtr RHS(this, new (Context) DeclRefExpr(ParmDecl, - RHSType, - SourceLocation())); + RHSType, + CurrentLocation)); Expr *Args[2] = { &*LHS, &*RHS }; OverloadCandidateSet CandidateSet; AddMemberOperatorCandidates(clang::OO_Equal, SourceLocation(), Args, 2, CandidateSet); OverloadCandidateSet::iterator Best; - if (BestViableFunction(CandidateSet, - ClassDecl->getLocation(), Best) == OR_Success) + if (BestViableFunction(CandidateSet, CurrentLocation, Best) == OR_Success) return cast(Best->Function); assert(false && "getAssignOperatorMethod - copy assignment operator method not found"); @@ -3286,8 +3754,10 @@ Sema::BuildCXXConstructExpr(SourceLocation ConstructLoc, QualType DeclInitType, if (ImplicitCastExpr *ICE = dyn_cast(E)) if (ICE->getCastKind() == CastExpr::CK_NoOp) E = ICE->getSubExpr(); - - if (isa(E) || isa(E)) + + if (CallExpr *CE = dyn_cast(E)) + Elidable = !CE->getCallReturnType()->isReferenceType(); + else if (isa(E)) Elidable = true; } @@ -3428,7 +3898,9 @@ void Sema::AddCXXDirectInitializerToDecl(DeclPtrTy Dcl, SourceRange(VDecl->getLocation(), RParenLoc), VDecl->getDeclName(), - IK_Direct, + InitializationKind::CreateDirect(VDecl->getLocation(), + LParenLoc, + RParenLoc), ConstructorArgs); if (!Constructor) RealDecl->setInvalidDecl(); @@ -3464,7 +3936,7 @@ static void AddConstructorInitializationCandidates(Sema &SemaRef, QualType ClassType, Expr **Args, unsigned NumArgs, - Sema::InitializationKind Kind, + InitializationKind Kind, OverloadCandidateSet &CandidateSet) { // C++ [dcl.init]p14: // If the initialization is direct-initialization, or if it is @@ -3499,10 +3971,12 @@ static void AddConstructorInitializationCandidates(Sema &SemaRef, else Constructor = cast(*Con); - if ((Kind == Sema::IK_Direct) || - (Kind == Sema::IK_Copy && + if ((Kind.getKind() == InitializationKind::IK_Direct) || + (Kind.getKind() == InitializationKind::IK_Value) || + (Kind.getKind() == InitializationKind::IK_Copy && Constructor->isConvertingConstructor(/*AllowExplicit=*/false)) || - (Kind == Sema::IK_Default && Constructor->isDefaultConstructor())) { + ((Kind.getKind() == InitializationKind::IK_Default) && + Constructor->isDefaultConstructor())) { if (ConstructorTmpl) SemaRef.AddTemplateOverloadCandidate(ConstructorTmpl, /*ExplicitArgs*/ 0, @@ -3774,7 +4248,7 @@ Sema::CheckReferenceInit(Expr *&Init, QualType DeclType, // real, update the initializer with the resulting function. if (!ICS) { if (DiagnoseUseOfDecl(Fn, DeclLoc)) - return true; + return true; Init = FixOverloadedFunctionReference(Init, Fn); } @@ -3874,23 +4348,28 @@ Sema::CheckReferenceInit(Expr *&Init, QualType DeclType, = T2RecordDecl->getVisibleConversionFunctions(); for (UnresolvedSet::iterator I = Conversions->begin(), E = Conversions->end(); I != E; ++I) { + NamedDecl *D = *I; + CXXRecordDecl *ActingDC = cast(D->getDeclContext()); + if (isa(D)) + D = cast(D)->getTargetDecl(); + FunctionTemplateDecl *ConvTemplate - = dyn_cast(*I); + = dyn_cast(D); CXXConversionDecl *Conv; if (ConvTemplate) Conv = cast(ConvTemplate->getTemplatedDecl()); else - Conv = cast(*I); + Conv = cast(D); // If the conversion function doesn't return a reference type, // it can't be considered for this conversion. if (Conv->getConversionType()->isLValueReferenceType() && (AllowExplicit || !Conv->isExplicit())) { if (ConvTemplate) - AddTemplateConversionCandidate(ConvTemplate, Init, DeclType, - CandidateSet); + AddTemplateConversionCandidate(ConvTemplate, ActingDC, + Init, DeclType, CandidateSet); else - AddConversionCandidate(Conv, Init, DeclType, CandidateSet); + AddConversionCandidate(Conv, ActingDC, Init, DeclType, CandidateSet); } } @@ -4125,6 +4604,138 @@ Sema::CheckReferenceInit(Expr *&Init, QualType DeclType, } } +static inline bool +CheckOperatorNewDeleteDeclarationScope(Sema &SemaRef, + const FunctionDecl *FnDecl) { + const DeclContext *DC = FnDecl->getDeclContext()->getLookupContext(); + if (isa(DC)) { + return SemaRef.Diag(FnDecl->getLocation(), + diag::err_operator_new_delete_declared_in_namespace) + << FnDecl->getDeclName(); + } + + if (isa(DC) && + FnDecl->getStorageClass() == FunctionDecl::Static) { + return SemaRef.Diag(FnDecl->getLocation(), + diag::err_operator_new_delete_declared_static) + << FnDecl->getDeclName(); + } + + return false; +} + +static inline bool +CheckOperatorNewDeleteTypes(Sema &SemaRef, const FunctionDecl *FnDecl, + CanQualType ExpectedResultType, + CanQualType ExpectedFirstParamType, + unsigned DependentParamTypeDiag, + unsigned InvalidParamTypeDiag) { + QualType ResultType = + FnDecl->getType()->getAs()->getResultType(); + + // Check that the result type is not dependent. + if (ResultType->isDependentType()) + return SemaRef.Diag(FnDecl->getLocation(), + diag::err_operator_new_delete_dependent_result_type) + << FnDecl->getDeclName() << ExpectedResultType; + + // Check that the result type is what we expect. + if (SemaRef.Context.getCanonicalType(ResultType) != ExpectedResultType) + return SemaRef.Diag(FnDecl->getLocation(), + diag::err_operator_new_delete_invalid_result_type) + << FnDecl->getDeclName() << ExpectedResultType; + + // A function template must have at least 2 parameters. + if (FnDecl->getDescribedFunctionTemplate() && FnDecl->getNumParams() < 2) + return SemaRef.Diag(FnDecl->getLocation(), + diag::err_operator_new_delete_template_too_few_parameters) + << FnDecl->getDeclName(); + + // The function decl must have at least 1 parameter. + if (FnDecl->getNumParams() == 0) + return SemaRef.Diag(FnDecl->getLocation(), + diag::err_operator_new_delete_too_few_parameters) + << FnDecl->getDeclName(); + + // Check the the first parameter type is not dependent. + QualType FirstParamType = FnDecl->getParamDecl(0)->getType(); + if (FirstParamType->isDependentType()) + return SemaRef.Diag(FnDecl->getLocation(), DependentParamTypeDiag) + << FnDecl->getDeclName() << ExpectedFirstParamType; + + // Check that the first parameter type is what we expect. + if (SemaRef.Context.getCanonicalType(FirstParamType) != + ExpectedFirstParamType) + return SemaRef.Diag(FnDecl->getLocation(), InvalidParamTypeDiag) + << FnDecl->getDeclName() << ExpectedFirstParamType; + + return false; +} + +static bool +CheckOperatorNewDeclaration(Sema &SemaRef, const FunctionDecl *FnDecl) { + // C++ [basic.stc.dynamic.allocation]p1: + // A program is ill-formed if an allocation function is declared in a + // namespace scope other than global scope or declared static in global + // scope. + if (CheckOperatorNewDeleteDeclarationScope(SemaRef, FnDecl)) + return true; + + CanQualType SizeTy = + SemaRef.Context.getCanonicalType(SemaRef.Context.getSizeType()); + + // C++ [basic.stc.dynamic.allocation]p1: + // The return type shall be void*. The first parameter shall have type + // std::size_t. + if (CheckOperatorNewDeleteTypes(SemaRef, FnDecl, SemaRef.Context.VoidPtrTy, + SizeTy, + diag::err_operator_new_dependent_param_type, + diag::err_operator_new_param_type)) + return true; + + // C++ [basic.stc.dynamic.allocation]p1: + // The first parameter shall not have an associated default argument. + if (FnDecl->getParamDecl(0)->hasDefaultArg()) + return SemaRef.Diag(FnDecl->getLocation(), + diag::err_operator_new_default_arg) + << FnDecl->getDeclName() << FnDecl->getParamDecl(0)->getDefaultArgRange(); + + return false; +} + +static bool +CheckOperatorDeleteDeclaration(Sema &SemaRef, const FunctionDecl *FnDecl) { + // C++ [basic.stc.dynamic.deallocation]p1: + // A program is ill-formed if deallocation functions are declared in a + // namespace scope other than global scope or declared static in global + // scope. + if (CheckOperatorNewDeleteDeclarationScope(SemaRef, FnDecl)) + return true; + + // C++ [basic.stc.dynamic.deallocation]p2: + // Each deallocation function shall return void and its first parameter + // shall be void*. + if (CheckOperatorNewDeleteTypes(SemaRef, FnDecl, SemaRef.Context.VoidTy, + SemaRef.Context.VoidPtrTy, + diag::err_operator_delete_dependent_param_type, + diag::err_operator_delete_param_type)) + return true; + + QualType FirstParamType = FnDecl->getParamDecl(0)->getType(); + if (FirstParamType->isDependentType()) + return SemaRef.Diag(FnDecl->getLocation(), + diag::err_operator_delete_dependent_param_type) + << FnDecl->getDeclName() << SemaRef.Context.VoidPtrTy; + + if (SemaRef.Context.getCanonicalType(FirstParamType) != + SemaRef.Context.VoidPtrTy) + return SemaRef.Diag(FnDecl->getLocation(), + diag::err_operator_delete_param_type) + << FnDecl->getDeclName() << SemaRef.Context.VoidPtrTy; + + return false; +} + /// CheckOverloadedOperatorDeclaration - Check whether the declaration /// of this overloaded operator is well-formed. If so, returns false; /// otherwise, emits appropriate diagnostics and returns true. @@ -4140,29 +4751,11 @@ bool Sema::CheckOverloadedOperatorDeclaration(FunctionDecl *FnDecl) { // described completely in 3.7.3. The attributes and restrictions // found in the rest of this subclause do not apply to them unless // explicitly stated in 3.7.3. - // FIXME: Write a separate routine for checking this. For now, just allow it. if (Op == OO_Delete || Op == OO_Array_Delete) - return false; + return CheckOperatorDeleteDeclaration(*this, FnDecl); - if (Op == OO_New || Op == OO_Array_New) { - bool ret = false; - if (FunctionDecl::param_iterator Param = FnDecl->param_begin()) { - QualType SizeTy = Context.getCanonicalType(Context.getSizeType()); - QualType T = Context.getCanonicalType((*Param)->getType()); - if (!T->isDependentType() && SizeTy != T) { - Diag(FnDecl->getLocation(), - diag::err_operator_new_param_type) << FnDecl->getDeclName() - << SizeTy; - ret = true; - } - } - QualType ResultTy = Context.getCanonicalType(FnDecl->getResultType()); - if (!ResultTy->isDependentType() && ResultTy != Context.VoidPtrTy) - return Diag(FnDecl->getLocation(), - diag::err_operator_new_result_type) << FnDecl->getDeclName() - << static_cast(Context.VoidPtrTy); - return ret; - } + if (Op == OO_New || Op == OO_Array_New) + return CheckOperatorNewDeclaration(*this, FnDecl); // C++ [over.oper]p6: // An operator function shall either be a non-static member @@ -4201,14 +4794,10 @@ bool Sema::CheckOverloadedOperatorDeclaration(FunctionDecl *FnDecl) { if (Op != OO_Call) { for (FunctionDecl::param_iterator Param = FnDecl->param_begin(); Param != FnDecl->param_end(); ++Param) { - if ((*Param)->hasUnparsedDefaultArg()) + if ((*Param)->hasDefaultArg()) return Diag((*Param)->getLocation(), diag::err_operator_overload_default_arg) - << FnDecl->getDeclName(); - else if (Expr *DefArg = (*Param)->getDefaultArg()) - return Diag((*Param)->getLocation(), - diag::err_operator_overload_default_arg) - << FnDecl->getDeclName() << DefArg->getSourceRange(); + << FnDecl->getDeclName() << (*Param)->getDefaultArgRange(); } } @@ -4346,7 +4935,7 @@ Sema::DeclPtrTy Sema::ActOnFinishLinkageSpecification(Scope *S, /// occurs within a C++ catch clause, returning the newly-created /// variable. VarDecl *Sema::BuildExceptionDeclaration(Scope *S, QualType ExDeclType, - DeclaratorInfo *DInfo, + TypeSourceInfo *TInfo, IdentifierInfo *Name, SourceLocation Loc, SourceRange Range) { @@ -4396,7 +4985,7 @@ VarDecl *Sema::BuildExceptionDeclaration(Scope *S, QualType ExDeclType, // FIXME: Need to check for abstract classes. VarDecl *ExDecl = VarDecl::Create(Context, CurContext, Loc, - Name, ExDeclType, DInfo, VarDecl::None); + Name, ExDeclType, TInfo, VarDecl::None); if (Invalid) ExDecl->setInvalidDecl(); @@ -4407,8 +4996,8 @@ VarDecl *Sema::BuildExceptionDeclaration(Scope *S, QualType ExDeclType, /// ActOnExceptionDeclarator - Parsed the exception-declarator in a C++ catch /// handler. Sema::DeclPtrTy Sema::ActOnExceptionDeclarator(Scope *S, Declarator &D) { - DeclaratorInfo *DInfo = 0; - QualType ExDeclType = GetTypeForDeclarator(D, S, &DInfo); + TypeSourceInfo *TInfo = 0; + QualType ExDeclType = GetTypeForDeclarator(D, S, &TInfo); bool Invalid = D.isInvalidType(); IdentifierInfo *II = D.getIdentifier(); @@ -4428,7 +5017,7 @@ Sema::DeclPtrTy Sema::ActOnExceptionDeclarator(Scope *S, Declarator &D) { Invalid = true; } - VarDecl *ExDecl = BuildExceptionDeclaration(S, ExDeclType, DInfo, + VarDecl *ExDecl = BuildExceptionDeclaration(S, ExDeclType, TInfo, D.getIdentifier(), D.getIdentifierLoc(), D.getDeclSpec().getSourceRange()); @@ -4462,10 +5051,8 @@ Sema::DeclPtrTy Sema::ActOnStaticAssertDeclaration(SourceLocation AssertLoc, } if (Value == 0) { - std::string str(AssertMessage->getStrData(), - AssertMessage->getByteLength()); Diag(AssertLoc, diag::err_static_assert_failed) - << str << AssertExpr->getSourceRange(); + << AssertMessage->getString() << AssertExpr->getSourceRange(); } } @@ -4602,8 +5189,8 @@ Sema::ActOnFriendFunctionDecl(Scope *S, assert(DS.getStorageClassSpec() == DeclSpec::SCS_unspecified); SourceLocation Loc = D.getIdentifierLoc(); - DeclaratorInfo *DInfo = 0; - QualType T = GetTypeForDeclarator(D, S, &DInfo); + TypeSourceInfo *TInfo = 0; + QualType T = GetTypeForDeclarator(D, S, &TInfo); // C++ [class.friend]p1 // A friend of a class is a function or class.... @@ -4726,7 +5313,7 @@ Sema::ActOnFriendFunctionDecl(Scope *S, } bool Redeclaration = false; - NamedDecl *ND = ActOnFunctionDeclarator(S, D, DC, T, DInfo, Previous, + NamedDecl *ND = ActOnFunctionDeclarator(S, D, DC, T, TInfo, Previous, move(TemplateParams), IsDefinition, Redeclaration); @@ -4890,6 +5477,26 @@ bool Sema::CheckOverridingFunctionAttributes(const CXXMethodDecl *New, return false; } +/// \brief Mark the given method pure. +/// +/// \param Method the method to be marked pure. +/// +/// \param InitRange the source range that covers the "0" initializer. +bool Sema::CheckPureMethod(CXXMethodDecl *Method, SourceRange InitRange) { + if (Method->isVirtual() || Method->getParent()->isDependentContext()) { + Method->setPure(); + + // A class is abstract if at least one function is pure virtual. + Method->getParent()->setAbstract(true); + return false; + } + + if (!Method->isInvalidDecl()) + Diag(Method->getLocation(), diag::err_non_virtual_pure) + << Method->getDeclName() << InitRange; + return true; +} + /// ActOnCXXEnterDeclInitializer - Invoked when we are about to parse an /// initializer for the declaration 'Dcl'. /// After this method is called, according to [C++ 3.4.1p13], if 'Dcl' is a @@ -4949,9 +5556,9 @@ Sema::ActOnCXXConditionDeclaration(Scope *S, Declarator &D) { assert(D.getDeclSpec().getStorageClassSpec() != DeclSpec::SCS_typedef && "Parser allowed 'typedef' as storage class of condition decl."); - DeclaratorInfo *DInfo = 0; + TypeSourceInfo *TInfo = 0; TagDecl *OwnedTag = 0; - QualType Ty = GetTypeForDeclarator(D, S, &DInfo, &OwnedTag); + QualType Ty = GetTypeForDeclarator(D, S, &TInfo, &OwnedTag); if (Ty->isFunctionType()) { // The declarator shall not specify a function... // We exit without creating a CXXConditionDeclExpr because a FunctionDecl @@ -4972,3 +5579,80 @@ Sema::ActOnCXXConditionDeclaration(Scope *S, Declarator &D) { VD->setDeclaredInCondition(true); return Dcl; } + +void Sema::MaybeMarkVirtualMembersReferenced(SourceLocation Loc, + CXXMethodDecl *MD) { + // Ignore dependent types. + if (MD->isDependentContext()) + return; + + CXXRecordDecl *RD = MD->getParent(); + + // Ignore classes without a vtable. + if (!RD->isDynamicClass()) + return; + + if (!MD->isOutOfLine()) { + // The only inline functions we care about are constructors. We also defer + // marking the virtual members as referenced until we've reached the end + // of the translation unit. We do this because we need to know the key + // function of the class in order to determine the key function. + if (isa(MD)) + ClassesWithUnmarkedVirtualMembers.insert(std::make_pair(RD, Loc)); + return; + } + + const CXXMethodDecl *KeyFunction = Context.getKeyFunction(RD); + + if (!KeyFunction) { + // This record does not have a key function, so we assume that the vtable + // will be emitted when it's used by the constructor. + if (!isa(MD)) + return; + } else if (KeyFunction->getCanonicalDecl() != MD->getCanonicalDecl()) { + // We don't have the right key function. + return; + } + + // Mark the members as referenced. + MarkVirtualMembersReferenced(Loc, RD); + ClassesWithUnmarkedVirtualMembers.erase(RD); +} + +bool Sema::ProcessPendingClassesWithUnmarkedVirtualMembers() { + if (ClassesWithUnmarkedVirtualMembers.empty()) + return false; + + for (std::map::iterator i = + ClassesWithUnmarkedVirtualMembers.begin(), + e = ClassesWithUnmarkedVirtualMembers.end(); i != e; ++i) { + CXXRecordDecl *RD = i->first; + + const CXXMethodDecl *KeyFunction = Context.getKeyFunction(RD); + if (KeyFunction) { + // We know that the class has a key function. If the key function was + // declared in this translation unit, then it the class decl would not + // have been in the ClassesWithUnmarkedVirtualMembers map. + continue; + } + + SourceLocation Loc = i->second; + MarkVirtualMembersReferenced(Loc, RD); + } + + ClassesWithUnmarkedVirtualMembers.clear(); + return true; +} + +void Sema::MarkVirtualMembersReferenced(SourceLocation Loc, CXXRecordDecl *RD) { + for (CXXRecordDecl::method_iterator i = RD->method_begin(), + e = RD->method_end(); i != e; ++i) { + CXXMethodDecl *MD = *i; + + // C++ [basic.def.odr]p2: + // [...] A virtual member function is used if it is not pure. [...] + if (MD->isVirtual() && !MD->isPure()) + MarkDeclarationReferenced(Loc, MD); + } +} + diff --git a/lib/Sema/SemaDeclObjC.cpp b/lib/Sema/SemaDeclObjC.cpp index 7da37affdc1e..a768e1bdf781 100644 --- a/lib/Sema/SemaDeclObjC.cpp +++ b/lib/Sema/SemaDeclObjC.cpp @@ -1349,10 +1349,10 @@ ObjCMethodDecl *Sema::LookupInstanceMethodInGlobalPool(Selector Sel, } if (issueWarning && (MethList.Method && MethList.Next)) { Diag(R.getBegin(), diag::warn_multiple_method_decl) << Sel << R; - Diag(MethList.Method->getLocStart(), diag::note_using_decl) + Diag(MethList.Method->getLocStart(), diag::note_using) << MethList.Method->getSourceRange(); for (ObjCMethodList *Next = MethList.Next; Next; Next = Next->Next) - Diag(Next->Method->getLocStart(), diag::note_also_found_decl) + Diag(Next->Method->getLocStart(), diag::note_also_found) << Next->Method->getSourceRange(); } return MethList.Method; @@ -1413,10 +1413,10 @@ ObjCMethodDecl *Sema::LookupFactoryMethodInGlobalPool(Selector Sel, } if (issueWarning && (MethList.Method && MethList.Next)) { Diag(R.getBegin(), diag::warn_multiple_method_decl) << Sel << R; - Diag(MethList.Method->getLocStart(), diag::note_using_decl) + Diag(MethList.Method->getLocStart(), diag::note_using) << MethList.Method->getSourceRange(); for (ObjCMethodList *Next = MethList.Next; Next; Next = Next->Next) - Diag(Next->Method->getLocStart(), diag::note_also_found_decl) + Diag(Next->Method->getLocStart(), diag::note_also_found) << Next->Method->getSourceRange(); } return MethList.Method; @@ -1495,7 +1495,7 @@ void Sema::ProcessPropertyDecl(ObjCPropertyDecl *property, property->getLocation(), property->getIdentifier(), property->getType(), - /*DInfo=*/0, + /*TInfo=*/0, VarDecl::None, 0); SetterMethod->setMethodParams(Context, &Argument, 1); @@ -1765,7 +1765,7 @@ Sema::DeclPtrTy Sema::ActOnMethodDeclaration( for (unsigned i = 0, e = Sel.getNumArgs(); i != e; ++i) { QualType ArgType; - DeclaratorInfo *DI; + TypeSourceInfo *DI; if (ArgInfo[i].Type == 0) { ArgType = Context.getObjCIdType(); diff --git a/lib/Sema/SemaExceptionSpec.cpp b/lib/Sema/SemaExceptionSpec.cpp index 25af0528d8b5..7e2a98d0bf1f 100644 --- a/lib/Sema/SemaExceptionSpec.cpp +++ b/lib/Sema/SemaExceptionSpec.cpp @@ -35,10 +35,15 @@ static const FunctionProtoType *GetUnderlyingFunction(QualType T) /// exception specification. Incomplete types, or pointers to incomplete types /// other than void are not allowed. bool Sema::CheckSpecifiedExceptionType(QualType T, const SourceRange &Range) { - // FIXME: This may not correctly work with the fix for core issue 437, - // where a class's own type is considered complete within its body. But - // perhaps RequireCompleteType itself should contain this logic? + // This check (and the similar one below) deals with issue 437, that changes + // C++ 9.2p2 this way: + // Within the class member-specification, the class is regarded as complete + // within function bodies, default arguments, exception-specifications, and + // constructor ctor-initializers (including such things in nested classes). + if (T->isRecordType() && T->getAs()->isBeingDefined()) + return false; + // C++ 15.4p2: A type denoted in an exception-specification shall not denote // an incomplete type. if (RequireCompleteType(Range.getBegin(), T, @@ -58,8 +63,12 @@ bool Sema::CheckSpecifiedExceptionType(QualType T, const SourceRange &Range) { } else return false; + // Again as before + if (T->isRecordType() && T->getAs()->isBeingDefined()) + return false; + if (!T->isVoidType() && RequireCompleteType(Range.getBegin(), T, - PDiag(diag::err_incomplete_in_exception_spec) << /*direct*/kind << Range)) + PDiag(diag::err_incomplete_in_exception_spec) << kind << Range)) return true; return false; diff --git a/lib/Sema/SemaExpr.cpp b/lib/Sema/SemaExpr.cpp index f653cf63d803..358f4456bb0c 100644 --- a/lib/Sema/SemaExpr.cpp +++ b/lib/Sema/SemaExpr.cpp @@ -259,15 +259,43 @@ bool Sema::DefaultVariadicArgumentPromotion(Expr *&Expr, VariadicCallType CT) { DefaultArgumentPromotion(Expr); if (Expr->getType()->isObjCInterfaceType()) { - Diag(Expr->getLocStart(), - diag::err_cannot_pass_objc_interface_to_vararg) - << Expr->getType() << CT; - return true; + switch (ExprEvalContexts.back().Context ) { + case Unevaluated: + // The argument will never be evaluated, so don't complain. + break; + + case PotentiallyEvaluated: + Diag(Expr->getLocStart(), + diag::err_cannot_pass_objc_interface_to_vararg) + << Expr->getType() << CT; + return true; + + case PotentiallyPotentiallyEvaluated: + ExprEvalContexts.back().addDiagnostic(Expr->getLocStart(), + PDiag(diag::err_cannot_pass_objc_interface_to_vararg) + << Expr->getType() << CT); + break; + } } - if (!Expr->getType()->isPODType()) - Diag(Expr->getLocStart(), diag::warn_cannot_pass_non_pod_arg_to_vararg) - << Expr->getType() << CT; + if (!Expr->getType()->isPODType()) { + switch (ExprEvalContexts.back().Context ) { + case Unevaluated: + // The argument will never be evaluated, so don't complain. + break; + + case PotentiallyEvaluated: + Diag(Expr->getLocStart(), diag::warn_cannot_pass_non_pod_arg_to_vararg) + << Expr->getType() << CT; + break; + + case PotentiallyPotentiallyEvaluated: + ExprEvalContexts.back().addDiagnostic(Expr->getLocStart(), + PDiag(diag::warn_cannot_pass_non_pod_arg_to_vararg) + << Expr->getType() << CT); + break; + } + } return false; } @@ -415,7 +443,7 @@ static bool ShouldSnapshotBlockValueReference(BlockSemaInfo *CurBlock, /// BuildDeclRefExpr - Build a DeclRefExpr. Sema::OwningExprResult -Sema::BuildDeclRefExpr(NamedDecl *D, QualType Ty, SourceLocation Loc, +Sema::BuildDeclRefExpr(ValueDecl *D, QualType Ty, SourceLocation Loc, const CXXScopeSpec *SS) { if (Context.getCanonicalType(Ty) == Context.UndeducedAutoTy) { Diag(Loc, @@ -605,6 +633,7 @@ Sema::BuildAnonymousStructUnionMemberReference(SourceLocation Loc, MemberType = Context.getQualifiedType(MemberType, NewQuals); MarkDeclarationReferenced(Loc, *FI); + PerformObjectMemberConversion(Result, *FI); // FIXME: Might this end up being a qualified name? Result = new (Context) MemberExpr(Result, BaseObjectIsPointer, *FI, OpLoc, MemberType); @@ -665,9 +694,9 @@ static void DecomposeTemplateName(LookupResult &R, const UnqualifiedId &Id) { if (TemplateDecl *TD = TName.getAsTemplateDecl()) R.addDecl(TD); - else if (OverloadedFunctionDecl *OD - = TName.getAsOverloadedFunctionDecl()) - for (OverloadIterator I(OD), E; I != E; ++I) + else if (OverloadedTemplateStorage *OT = TName.getAsOverloadedTemplate()) + for (OverloadedTemplateStorage::iterator I = OT->begin(), E = OT->end(); + I != E; ++I) R.addDecl(*I); R.resolveKind(); @@ -703,18 +732,188 @@ static bool IsDependentIdExpression(Sema &SemaRef, const CXXScopeSpec &SS) { // We can't look into record types unless they're fully-formed. if (!IsFullyFormedScope(SemaRef, cast(DC))) return true; - // We can always look into fully-formed record types, but if we're - // in a dependent but not fully-formed context, we can't decide - // whether the qualifier names a base class. We shouldn't be trying - // to decide that yet anyway, but we are, so we need to delay that - // decision. - CXXRecordDecl *CurRecord; - if (CXXMethodDecl *CurMethod = dyn_cast(SemaRef.CurContext)) - CurRecord = cast(CurMethod->getParent()); - else - CurRecord = dyn_cast(SemaRef.CurContext); + return false; +} - return CurRecord && !IsFullyFormedScope(SemaRef, CurRecord); +/// Determines if the given class is provably not derived from all of +/// the prospective base classes. +static bool IsProvablyNotDerivedFrom(Sema &SemaRef, + CXXRecordDecl *Record, + const llvm::SmallPtrSet &Bases) { + if (Bases.count(Record->getCanonicalDecl())) + return false; + + RecordDecl *RD = Record->getDefinition(SemaRef.Context); + if (!RD) return false; + Record = cast(RD); + + for (CXXRecordDecl::base_class_iterator I = Record->bases_begin(), + E = Record->bases_end(); I != E; ++I) { + CanQualType BaseT = SemaRef.Context.getCanonicalType((*I).getType()); + CanQual BaseRT = BaseT->getAs(); + if (!BaseRT) return false; + + CXXRecordDecl *BaseRecord = cast(BaseRT->getDecl()); + if (!IsProvablyNotDerivedFrom(SemaRef, BaseRecord, Bases)) + return false; + } + + return true; +} + +/// Determines if this a C++ class member. +static bool IsClassMember(NamedDecl *D) { + DeclContext *DC = D->getDeclContext(); + + // C++0x [class.mem]p1: + // The enumerators of an unscoped enumeration defined in + // the class are members of the class. + // FIXME: support C++0x scoped enumerations. + if (isa(DC)) + DC = DC->getParent(); + + return DC->isRecord(); +} + +/// Determines if this is an instance member of a class. +static bool IsInstanceMember(NamedDecl *D) { + assert(IsClassMember(D) && + "checking whether non-member is instance member"); + + if (isa(D)) return true; + + if (isa(D)) + return !cast(D)->isStatic(); + + if (isa(D)) { + D = cast(D)->getTemplatedDecl(); + return !cast(D)->isStatic(); + } + + return false; +} + +enum IMAKind { + /// The reference is definitely not an instance member access. + IMA_Static, + + /// The reference may be an implicit instance member access. + IMA_Mixed, + + /// The reference may be to an instance member, but it is invalid if + /// so, because the context is not an instance method. + IMA_Mixed_StaticContext, + + /// The reference may be to an instance member, but it is invalid if + /// so, because the context is from an unrelated class. + IMA_Mixed_Unrelated, + + /// The reference is definitely an implicit instance member access. + IMA_Instance, + + /// The reference may be to an unresolved using declaration. + IMA_Unresolved, + + /// The reference may be to an unresolved using declaration and the + /// context is not an instance method. + IMA_Unresolved_StaticContext, + + /// The reference is to a member of an anonymous structure in a + /// non-class context. + IMA_AnonymousMember, + + /// All possible referrents are instance members and the current + /// context is not an instance method. + IMA_Error_StaticContext, + + /// All possible referrents are instance members of an unrelated + /// class. + IMA_Error_Unrelated +}; + +/// The given lookup names class member(s) and is not being used for +/// an address-of-member expression. Classify the type of access +/// according to whether it's possible that this reference names an +/// instance member. This is best-effort; it is okay to +/// conservatively answer "yes", in which case some errors will simply +/// not be caught until template-instantiation. +static IMAKind ClassifyImplicitMemberAccess(Sema &SemaRef, + const LookupResult &R) { + assert(!R.empty() && IsClassMember(*R.begin())); + + bool isStaticContext = + (!isa(SemaRef.CurContext) || + cast(SemaRef.CurContext)->isStatic()); + + if (R.isUnresolvableResult()) + return isStaticContext ? IMA_Unresolved_StaticContext : IMA_Unresolved; + + // Collect all the declaring classes of instance members we find. + bool hasNonInstance = false; + llvm::SmallPtrSet Classes; + for (LookupResult::iterator I = R.begin(), E = R.end(); I != E; ++I) { + NamedDecl *D = (*I)->getUnderlyingDecl(); + if (IsInstanceMember(D)) { + CXXRecordDecl *R = cast(D->getDeclContext()); + + // If this is a member of an anonymous record, move out to the + // innermost non-anonymous struct or union. If there isn't one, + // that's a special case. + while (R->isAnonymousStructOrUnion()) { + R = dyn_cast(R->getParent()); + if (!R) return IMA_AnonymousMember; + } + Classes.insert(R->getCanonicalDecl()); + } + else + hasNonInstance = true; + } + + // If we didn't find any instance members, it can't be an implicit + // member reference. + if (Classes.empty()) + return IMA_Static; + + // If the current context is not an instance method, it can't be + // an implicit member reference. + if (isStaticContext) + return (hasNonInstance ? IMA_Mixed_StaticContext : IMA_Error_StaticContext); + + // If we can prove that the current context is unrelated to all the + // declaring classes, it can't be an implicit member reference (in + // which case it's an error if any of those members are selected). + if (IsProvablyNotDerivedFrom(SemaRef, + cast(SemaRef.CurContext)->getParent(), + Classes)) + return (hasNonInstance ? IMA_Mixed_Unrelated : IMA_Error_Unrelated); + + return (hasNonInstance ? IMA_Mixed : IMA_Instance); +} + +/// Diagnose a reference to a field with no object available. +static void DiagnoseInstanceReference(Sema &SemaRef, + const CXXScopeSpec &SS, + const LookupResult &R) { + SourceLocation Loc = R.getNameLoc(); + SourceRange Range(Loc); + if (SS.isSet()) Range.setBegin(SS.getRange().getBegin()); + + if (R.getAsSingle()) { + if (CXXMethodDecl *MD = dyn_cast(SemaRef.CurContext)) { + if (MD->isStatic()) { + // "invalid use of member 'x' in static member function" + SemaRef.Diag(Loc, diag::err_invalid_member_use_in_static_method) + << Range << R.getLookupName(); + return; + } + } + + SemaRef.Diag(Loc, diag::err_invalid_non_static_member_use) + << R.getLookupName() << Range; + return; + } + + SemaRef.Diag(Loc, diag::err_member_call_without_object) << Range; } Sema::OwningExprResult Sema::ActOnIdExpression(Scope *S, @@ -746,10 +945,8 @@ Sema::OwningExprResult Sema::ActOnIdExpression(Scope *S, // Determine whether this is a member of an unknown specialization; // we need to handle these differently. if (SS.isSet() && IsDependentIdExpression(*this, SS)) { - bool CheckForImplicitMember = !isAddressOfOperand; - return ActOnDependentIdExpression(SS, Name, NameLoc, - CheckForImplicitMember, + isAddressOfOperand, TemplateArgs); } @@ -847,23 +1044,41 @@ Sema::OwningExprResult Sema::ActOnIdExpression(Scope *S, } } - // &SomeClass::foo is an abstract member reference, regardless of - // the nature of foo, but &SomeClass::foo(...) is not. If this is - // *not* an abstract member reference, and any of the results is a - // class member (which necessarily means they're all class members), - // then we make an implicit member reference instead. - // - // This check considers all the same information as the "needs ADL" - // check, but there's no simple logical relationship other than the - // fact that they can never be simultaneously true. We could - // calculate them both in one pass if that proves important for - // performance. - if (!ADL) { + // Check whether this might be a C++ implicit instance member access. + // C++ [expr.prim.general]p6: + // Within the definition of a non-static member function, an + // identifier that names a non-static member is transformed to a + // class member access expression. + // But note that &SomeClass::foo is grammatically distinct, even + // though we don't parse it that way. + if (!R.empty() && IsClassMember(*R.begin())) { bool isAbstractMemberPointer = (isAddressOfOperand && !SS.isEmpty()); - if (!isAbstractMemberPointer && !R.empty() && - isa((*R.begin())->getDeclContext())) { - return BuildImplicitMemberReferenceExpr(SS, R, TemplateArgs); + if (!isAbstractMemberPointer) { + switch (ClassifyImplicitMemberAccess(*this, R)) { + case IMA_Instance: + return BuildImplicitMemberExpr(SS, R, TemplateArgs, true); + + case IMA_AnonymousMember: + assert(R.isSingleResult()); + return BuildAnonymousStructUnionMemberReference(R.getNameLoc(), + R.getAsSingle()); + + case IMA_Mixed: + case IMA_Mixed_Unrelated: + case IMA_Unresolved: + return BuildImplicitMemberExpr(SS, R, TemplateArgs, false); + + case IMA_Static: + case IMA_Mixed_StaticContext: + case IMA_Unresolved_StaticContext: + break; + + case IMA_Error_StaticContext: + case IMA_Error_Unrelated: + DiagnoseInstanceReference(*this, SS, R); + return ExprError(); + } } } @@ -1027,7 +1242,7 @@ Sema::PerformObjectMemberConversion(Expr *&From, NamedDecl *Member) { /// \brief Build a MemberExpr AST node. static MemberExpr *BuildMemberExpr(ASTContext &C, Expr *Base, bool isArrow, - const CXXScopeSpec &SS, NamedDecl *Member, + const CXXScopeSpec &SS, ValueDecl *Member, SourceLocation Loc, QualType Ty, const TemplateArgumentListInfo *TemplateArgs = 0) { NestedNameSpecifier *Qualifier = 0; @@ -1041,35 +1256,15 @@ static MemberExpr *BuildMemberExpr(ASTContext &C, Expr *Base, bool isArrow, Member, Loc, TemplateArgs, Ty); } -/// Return true if all the decls in the given result are instance -/// methods. -static bool IsOnlyInstanceMethods(const LookupResult &R) { - for (LookupResult::iterator I = R.begin(), E = R.end(); I != E; ++I) { - NamedDecl *D = (*I)->getUnderlyingDecl(); - - CXXMethodDecl *Method; - if (isa(D)) - Method = cast(cast(D) - ->getTemplatedDecl()); - else if (isa(D)) - Method = cast(D); - else - return false; - - if (Method->isStatic()) - return false; - } - - return true; -} - -/// Builds an implicit member access expression from the given -/// unqualified lookup set, which is known to contain only class -/// members. +/// Builds an implicit member access expression. The current context +/// is known to be an instance method, and the given unqualified lookup +/// set is known to contain only instance members, at least one of which +/// is from an appropriate type. Sema::OwningExprResult -Sema::BuildImplicitMemberReferenceExpr(const CXXScopeSpec &SS, - LookupResult &R, - const TemplateArgumentListInfo *TemplateArgs) { +Sema::BuildImplicitMemberExpr(const CXXScopeSpec &SS, + LookupResult &R, + const TemplateArgumentListInfo *TemplateArgs, + bool IsKnownInstance) { assert(!R.empty() && !R.isAmbiguous()); SourceLocation Loc = R.getNameLoc(); @@ -1082,44 +1277,18 @@ Sema::BuildImplicitMemberReferenceExpr(const CXXScopeSpec &SS, if (cast(FD->getDeclContext())->isAnonymousStructOrUnion()) return BuildAnonymousStructUnionMemberReference(Loc, FD); - QualType ThisType; - if (isImplicitMemberReference(R, ThisType)) { - Expr *This = new (Context) CXXThisExpr(SourceLocation(), ThisType); - return BuildMemberReferenceExpr(ExprArg(*this, This), - /*OpLoc*/ SourceLocation(), - /*IsArrow*/ true, - SS, R, TemplateArgs); + // If this is known to be an instance access, go ahead and build a + // 'this' expression now. + QualType ThisType = cast(CurContext)->getThisType(Context); + Expr *This = 0; // null signifies implicit access + if (IsKnownInstance) { + This = new (Context) CXXThisExpr(SourceLocation(), ThisType); } - // Diagnose now if none of the available methods are static. - if (IsOnlyInstanceMethods(R)) - return ExprError(Diag(Loc, diag::err_member_call_without_object)); - - if (R.getAsSingle()) { - if (CXXMethodDecl *MD = dyn_cast(CurContext)) { - if (MD->isStatic()) { - // "invalid use of member 'x' in static member function" - Diag(Loc, diag::err_invalid_member_use_in_static_method) - << R.getLookupName(); - return ExprError(); - } - } - - // Any other ways we could have found the field in a well-formed - // program would have been turned into implicit member expressions - // above. - Diag(Loc, diag::err_invalid_non_static_member_use) - << R.getLookupName(); - return ExprError(); - } - - // We're not in an implicit member-reference context, but the lookup - // results might not require an instance. Try to build a non-member - // decl reference. - if (TemplateArgs) - return BuildTemplateIdExpr(SS, R, /* ADL */ false, *TemplateArgs); - - return BuildDeclarationNameExpr(SS, R, /*ADL*/ false); + return BuildMemberReferenceExpr(ExprArg(*this, This), ThisType, + /*OpLoc*/ SourceLocation(), + /*IsArrow*/ true, + SS, R, TemplateArgs); } bool Sema::UseArgumentDependentLookup(const CXXScopeSpec &SS, @@ -1146,7 +1315,7 @@ bool Sema::UseArgumentDependentLookup(const CXXScopeSpec &SS, // -- a declaration of a class member // Since using decls preserve this property, we check this on the // original decl. - if (D->getDeclContext()->isRecord()) + if (IsClassMember(D)) return false; // C++0x [basic.lookup.argdep]p3: @@ -1205,11 +1374,9 @@ Sema::OwningExprResult Sema::BuildDeclarationNameExpr(const CXXScopeSpec &SS, LookupResult &R, bool NeedsADL) { - assert(R.getResultKind() != LookupResult::FoundUnresolvedValue); - - // If this isn't an overloaded result and we don't need ADL, just - // build an ordinary singleton decl ref. - if (!NeedsADL && !R.isOverloadedResult()) + // If this is a single, fully-resolved result and we don't need ADL, + // just build an ordinary singleton decl ref. + if (!NeedsADL && R.isSingleResult()) return BuildDeclarationNameExpr(SS, R.getNameLoc(), R.getFoundDecl()); // We only need to check the declaration if there's exactly one @@ -1246,7 +1413,23 @@ Sema::BuildDeclarationNameExpr(const CXXScopeSpec &SS, if (CheckDeclInExpr(*this, Loc, D)) return ExprError(); - ValueDecl *VD = cast(D); + if (TemplateDecl *Template = dyn_cast(D)) { + // Specifically diagnose references to class templates that are missing + // a template argument list. + Diag(Loc, diag::err_template_decl_ref) + << Template << SS.getRange(); + Diag(Template->getLocation(), diag::note_template_decl_here); + return ExprError(); + } + + // Make sure that we're referring to a value. + ValueDecl *VD = dyn_cast(D); + if (!VD) { + Diag(Loc, diag::err_ref_non_value) + << D << SS.getRange(); + Diag(D->getLocation(), diag::note_previous_declaration); + return ExprError(); + } // Check whether this declaration can be used. Note that we suppress // this check when we're going to perform argument-dependent lookup @@ -1558,20 +1741,20 @@ bool Sema::CheckAlignOfExpr(Expr *E, SourceLocation OpLoc, /// \brief Build a sizeof or alignof expression given a type operand. Action::OwningExprResult -Sema::CreateSizeOfAlignOfExpr(DeclaratorInfo *DInfo, +Sema::CreateSizeOfAlignOfExpr(TypeSourceInfo *TInfo, SourceLocation OpLoc, bool isSizeOf, SourceRange R) { - if (!DInfo) + if (!TInfo) return ExprError(); - QualType T = DInfo->getType(); + QualType T = TInfo->getType(); if (!T->isDependentType() && CheckSizeOfAlignOfOperand(T, OpLoc, R, isSizeOf)) return ExprError(); // C99 6.5.3.4p4: the type (an unsigned integer type) is size_t. - return Owned(new (Context) SizeOfAlignOfExpr(isSizeOf, DInfo, + return Owned(new (Context) SizeOfAlignOfExpr(isSizeOf, TInfo, Context.getSizeType(), OpLoc, R.getEnd())); } @@ -1613,9 +1796,9 @@ Sema::ActOnSizeOfAlignOfExpr(SourceLocation OpLoc, bool isSizeof, bool isType, if (TyOrEx == 0) return ExprError(); if (isType) { - DeclaratorInfo *DInfo; - (void) GetTypeFromParser(TyOrEx, &DInfo); - return CreateSizeOfAlignOfExpr(DInfo, OpLoc, isSizeof, ArgRange); + TypeSourceInfo *TInfo; + (void) GetTypeFromParser(TyOrEx, &TInfo); + return CreateSizeOfAlignOfExpr(TInfo, OpLoc, isSizeof, ArgRange); } Expr *ArgEx = (Expr *)TyOrEx; @@ -1952,7 +2135,8 @@ static Decl *FindGetterNameDecl(const ObjCObjectPointerType *QIdTy, } Sema::OwningExprResult -Sema::ActOnDependentMemberExpr(ExprArg Base, bool IsArrow, SourceLocation OpLoc, +Sema::ActOnDependentMemberExpr(ExprArg Base, QualType BaseType, + bool IsArrow, SourceLocation OpLoc, const CXXScopeSpec &SS, NamedDecl *FirstQualifierInScope, DeclarationName Name, SourceLocation NameLoc, @@ -1969,20 +2153,21 @@ Sema::ActOnDependentMemberExpr(ExprArg Base, bool IsArrow, SourceLocation OpLoc, // accessing the 'f' property if T is an Obj-C interface. The extra check // allows this, while still reporting an error if T is a struct pointer. if (!IsArrow) { - const PointerType *PT = BaseExpr->getType()->getAs(); + const PointerType *PT = BaseType->getAs(); if (PT && (!getLangOptions().ObjC1 || PT->getPointeeType()->isRecordType())) { + assert(BaseExpr && "cannot happen with implicit member accesses"); Diag(NameLoc, diag::err_typecheck_member_reference_struct_union) - << BaseExpr->getType() << BaseExpr->getSourceRange(); + << BaseType << BaseExpr->getSourceRange(); return ExprError(); } } - assert(BaseExpr->getType()->isDependentType()); + assert(BaseType->isDependentType()); // Get the type being accessed in BaseType. If this is an arrow, the BaseExpr // must have pointer type, and the accessed type is the pointee. - return Owned(CXXDependentScopeMemberExpr::Create(Context, BaseExpr, + return Owned(CXXDependentScopeMemberExpr::Create(Context, BaseExpr, BaseType, IsArrow, OpLoc, static_cast(SS.getScopeRep()), SS.getRange(), @@ -1997,15 +2182,18 @@ Sema::ActOnDependentMemberExpr(ExprArg Base, bool IsArrow, SourceLocation OpLoc, static void DiagnoseQualifiedMemberReference(Sema &SemaRef, Expr *BaseExpr, QualType BaseType, - NestedNameSpecifier *Qualifier, - SourceRange QualifierRange, + const CXXScopeSpec &SS, const LookupResult &R) { - DeclContext *DC = R.getRepresentativeDecl()->getDeclContext(); + // If this is an implicit member access, use a different set of + // diagnostics. + if (!BaseExpr) + return DiagnoseInstanceReference(SemaRef, SS, R); // FIXME: this is an exceedingly lame diagnostic for some of the more // complicated cases here. + DeclContext *DC = R.getRepresentativeDecl()->getDeclContext(); SemaRef.Diag(R.getNameLoc(), diag::err_not_direct_base_or_virtual) - << QualifierRange << DC << BaseType; + << SS.getRange() << DC << BaseType; } // Check whether the declarations we found through a nested-name @@ -2022,37 +2210,78 @@ static void DiagnoseQualifiedMemberReference(Sema &SemaRef, // we actually pick through overload resolution is from a superclass. bool Sema::CheckQualifiedMemberReference(Expr *BaseExpr, QualType BaseType, - NestedNameSpecifier *Qualifier, - SourceRange QualifierRange, + const CXXScopeSpec &SS, const LookupResult &R) { - QualType BaseTypeCanon - = Context.getCanonicalType(BaseType).getUnqualifiedType(); - - bool FoundValid = false; + const RecordType *BaseRT = BaseType->getAs(); + if (!BaseRT) { + // We can't check this yet because the base type is still + // dependent. + assert(BaseType->isDependentType()); + return false; + } + CXXRecordDecl *BaseRecord = cast(BaseRT->getDecl()); for (LookupResult::iterator I = R.begin(), E = R.end(); I != E; ++I) { - TypeDecl* TyD = cast((*I)->getUnderlyingDecl()->getDeclContext()); - CanQualType MemberTypeCanon - = Context.getCanonicalType(Context.getTypeDeclType(TyD)); + // If this is an implicit member reference and we find a + // non-instance member, it's not an error. + if (!BaseExpr && !IsInstanceMember((*I)->getUnderlyingDecl())) + return false; - if (BaseTypeCanon == MemberTypeCanon || - IsDerivedFrom(BaseTypeCanon, MemberTypeCanon)) { - FoundValid = true; - break; + // Note that we use the DC of the decl, not the underlying decl. + CXXRecordDecl *RecordD = cast((*I)->getDeclContext()); + while (RecordD->isAnonymousStructOrUnion()) + RecordD = cast(RecordD->getParent()); + + llvm::SmallPtrSet MemberRecord; + MemberRecord.insert(RecordD->getCanonicalDecl()); + + if (!IsProvablyNotDerivedFrom(*this, BaseRecord, MemberRecord)) + return false; + } + + DiagnoseQualifiedMemberReference(*this, BaseExpr, BaseType, SS, R); + return true; +} + +static bool +LookupMemberExprInRecord(Sema &SemaRef, LookupResult &R, + SourceRange BaseRange, const RecordType *RTy, + SourceLocation OpLoc, const CXXScopeSpec &SS) { + RecordDecl *RDecl = RTy->getDecl(); + if (SemaRef.RequireCompleteType(OpLoc, QualType(RTy, 0), + PDiag(diag::err_typecheck_incomplete_tag) + << BaseRange)) + return true; + + DeclContext *DC = RDecl; + if (SS.isSet()) { + // If the member name was a qualified-id, look into the + // nested-name-specifier. + DC = SemaRef.computeDeclContext(SS, false); + + if (SemaRef.RequireCompleteDeclContext(SS)) { + SemaRef.Diag(SS.getRange().getEnd(), diag::err_typecheck_incomplete_tag) + << SS.getRange() << DC; + return true; + } + + assert(DC && "Cannot handle non-computable dependent contexts in lookup"); + + if (!isa(DC)) { + SemaRef.Diag(R.getNameLoc(), diag::err_qualified_member_nonclass) + << DC << SS.getRange(); + return true; } } - if (!FoundValid) { - DiagnoseQualifiedMemberReference(*this, BaseExpr, BaseType, - Qualifier, QualifierRange, R); - return true; - } + // The record definition is complete, now look up the member. + SemaRef.LookupQualifiedName(R, DC); return false; } Sema::OwningExprResult -Sema::BuildMemberReferenceExpr(ExprArg BaseArg, +Sema::BuildMemberReferenceExpr(ExprArg BaseArg, QualType BaseType, SourceLocation OpLoc, bool IsArrow, const CXXScopeSpec &SS, NamedDecl *FirstQualifierInScope, @@ -2060,38 +2289,53 @@ Sema::BuildMemberReferenceExpr(ExprArg BaseArg, const TemplateArgumentListInfo *TemplateArgs) { Expr *Base = BaseArg.takeAs(); - if (Base->getType()->isDependentType()) - return ActOnDependentMemberExpr(ExprArg(*this, Base), + if (BaseType->isDependentType() || + (SS.isSet() && isDependentScopeSpecifier(SS))) + return ActOnDependentMemberExpr(ExprArg(*this, Base), BaseType, IsArrow, OpLoc, SS, FirstQualifierInScope, Name, NameLoc, TemplateArgs); LookupResult R(*this, Name, NameLoc, LookupMemberName); - OwningExprResult Result = - LookupMemberExpr(R, Base, IsArrow, OpLoc, - SS, FirstQualifierInScope, - /*ObjCImpDecl*/ DeclPtrTy()); - if (Result.isInvalid()) { - Owned(Base); - return ExprError(); + // Implicit member accesses. + if (!Base) { + QualType RecordTy = BaseType; + if (IsArrow) RecordTy = RecordTy->getAs()->getPointeeType(); + if (LookupMemberExprInRecord(*this, R, SourceRange(), + RecordTy->getAs(), + OpLoc, SS)) + return ExprError(); + + // Explicit member accesses. + } else { + OwningExprResult Result = + LookupMemberExpr(R, Base, IsArrow, OpLoc, + SS, FirstQualifierInScope, + /*ObjCImpDecl*/ DeclPtrTy()); + + if (Result.isInvalid()) { + Owned(Base); + return ExprError(); + } + + if (Result.get()) + return move(Result); } - if (Result.get()) - return move(Result); - - return BuildMemberReferenceExpr(ExprArg(*this, Base), OpLoc, - IsArrow, SS, R, TemplateArgs); + return BuildMemberReferenceExpr(ExprArg(*this, Base), BaseType, + OpLoc, IsArrow, SS, R, TemplateArgs); } Sema::OwningExprResult -Sema::BuildMemberReferenceExpr(ExprArg Base, SourceLocation OpLoc, - bool IsArrow, const CXXScopeSpec &SS, +Sema::BuildMemberReferenceExpr(ExprArg Base, QualType BaseExprType, + SourceLocation OpLoc, bool IsArrow, + const CXXScopeSpec &SS, LookupResult &R, const TemplateArgumentListInfo *TemplateArgs) { Expr *BaseExpr = Base.takeAs(); - QualType BaseType = BaseExpr->getType(); + QualType BaseType = BaseExprType; if (IsArrow) { assert(BaseType->isPointerType()); BaseType = BaseType->getAs()->getPointeeType(); @@ -2112,29 +2356,30 @@ Sema::BuildMemberReferenceExpr(ExprArg Base, SourceLocation OpLoc, : BaseType->getAs()->getDecl()); Diag(R.getNameLoc(), diag::err_no_member) - << MemberName << DC << BaseExpr->getSourceRange(); + << MemberName << DC + << (BaseExpr ? BaseExpr->getSourceRange() : SourceRange()); return ExprError(); } - // We can't always diagnose the problem yet: it's permitted for - // lookup to find things from an invalid context as long as they - // don't get picked by overload resolution. - if (SS.isSet() && CheckQualifiedMemberReference(BaseExpr, BaseType, - Qualifier, SS.getRange(), R)) + // Diagnose qualified lookups that find only declarations from a + // non-base type. Note that it's okay for lookup to find + // declarations from a non-base type as long as those aren't the + // ones picked by overload resolution. + if (SS.isSet() && CheckQualifiedMemberReference(BaseExpr, BaseType, SS, R)) return ExprError(); // Construct an unresolved result if we in fact got an unresolved // result. if (R.isOverloadedResult() || R.isUnresolvableResult()) { - bool Dependent = R.isUnresolvableResult(); - Dependent = Dependent || - UnresolvedLookupExpr::ComputeDependence(R.begin(), R.end(), - TemplateArgs); + bool Dependent = + R.isUnresolvableResult() || + UnresolvedLookupExpr::ComputeDependence(R.begin(), R.end(), TemplateArgs); UnresolvedMemberExpr *MemExpr = UnresolvedMemberExpr::Create(Context, Dependent, R.isUnresolvableResult(), - BaseExpr, IsArrow, OpLoc, + BaseExpr, BaseExprType, + IsArrow, OpLoc, Qualifier, SS.getRange(), MemberName, MemberLoc, TemplateArgs); @@ -2155,6 +2400,15 @@ Sema::BuildMemberReferenceExpr(ExprArg Base, SourceLocation OpLoc, if (MemberDecl->isInvalidDecl()) return ExprError(); + // Handle the implicit-member-access case. + if (!BaseExpr) { + // If this is not an instance member, convert to a non-member access. + if (!IsInstanceMember(MemberDecl)) + return BuildDeclarationNameExpr(SS, R.getNameLoc(), MemberDecl); + + BaseExpr = new (Context) CXXThisExpr(SourceLocation(), BaseExprType); + } + bool ShouldCheckUse = true; if (CXXMethodDecl *MD = dyn_cast(MemberDecl)) { // Don't diagnose the use of a virtual member function unless it's @@ -2172,7 +2426,8 @@ Sema::BuildMemberReferenceExpr(ExprArg Base, SourceLocation OpLoc, if (FieldDecl *FD = dyn_cast(MemberDecl)) { // We may have found a field within an anonymous union or struct // (C++ [class.union]). - if (cast(FD->getDeclContext())->isAnonymousStructOrUnion()) + if (cast(FD->getDeclContext())->isAnonymousStructOrUnion() && + !BaseType->getAs()->getDecl()->isAnonymousStructOrUnion()) return BuildAnonymousStructUnionMemberReference(MemberLoc, FD, BaseExpr, OpLoc); @@ -2246,7 +2501,7 @@ Sema::BuildMemberReferenceExpr(ExprArg Base, SourceLocation OpLoc, /// fixed for ObjC++. Sema::OwningExprResult Sema::LookupMemberExpr(LookupResult &R, Expr *&BaseExpr, - bool IsArrow, SourceLocation OpLoc, + bool &IsArrow, SourceLocation OpLoc, const CXXScopeSpec &SS, NamedDecl *FirstQualifierInScope, DeclPtrTy ObjCImpDecl) { @@ -2295,6 +2550,16 @@ Sema::LookupMemberExpr(LookupResult &R, Expr *&BaseExpr, // If this is an Objective-C pseudo-builtin and a definition is provided then // use that. if (BaseType->isObjCIdType()) { + if (IsArrow) { + // Handle the following exceptional case PObj->isa. + if (const ObjCObjectPointerType *OPT = + BaseType->getAs()) { + if (OPT->getPointeeType()->isSpecificBuiltinType(BuiltinType::ObjCId) && + MemberName.getAsIdentifierInfo()->isStr("isa")) + return Owned(new (Context) ObjCIsaExpr(BaseExpr, true, MemberLoc, + Context.getObjCClassType())); + } + } // We have an 'id' type. Rather than fall through, we check if this // is a reference to 'isa'. if (BaseType != Context.ObjCIdRedefinitionType) { @@ -2377,41 +2642,48 @@ Sema::LookupMemberExpr(LookupResult &R, Expr *&BaseExpr, BaseType = PT->getPointeeType(); else if (BaseType->isObjCObjectPointerType()) ; - else { + else if (BaseType->isRecordType()) { + // Recover from arrow accesses to records, e.g.: + // struct MyRecord foo; + // foo->bar + // This is actually well-formed in C++ if MyRecord has an + // overloaded operator->, but that should have been dealt with + // by now. + Diag(OpLoc, diag::err_typecheck_member_reference_suggestion) + << BaseType << int(IsArrow) << BaseExpr->getSourceRange() + << CodeModificationHint::CreateReplacement(OpLoc, "."); + IsArrow = false; + } else { Diag(MemberLoc, diag::err_typecheck_member_reference_arrow) << BaseType << BaseExpr->getSourceRange(); return ExprError(); } + } else { + // Recover from dot accesses to pointers, e.g.: + // type *foo; + // foo.bar + // This is actually well-formed in two cases: + // - 'type' is an Objective C type + // - 'bar' is a pseudo-destructor name which happens to refer to + // the appropriate pointer type + if (MemberName.getNameKind() != DeclarationName::CXXDestructorName) { + const PointerType *PT = BaseType->getAs(); + if (PT && PT->getPointeeType()->isRecordType()) { + Diag(OpLoc, diag::err_typecheck_member_reference_suggestion) + << BaseType << int(IsArrow) << BaseExpr->getSourceRange() + << CodeModificationHint::CreateReplacement(OpLoc, "->"); + BaseType = PT->getPointeeType(); + IsArrow = true; + } + } } - + // Handle field access to simple records. This also handles access // to fields of the ObjC 'id' struct. if (const RecordType *RTy = BaseType->getAs()) { - RecordDecl *RDecl = RTy->getDecl(); - if (RequireCompleteType(OpLoc, BaseType, - PDiag(diag::err_typecheck_incomplete_tag) - << BaseExpr->getSourceRange())) + if (LookupMemberExprInRecord(*this, R, BaseExpr->getSourceRange(), + RTy, OpLoc, SS)) return ExprError(); - - DeclContext *DC = RDecl; - if (SS.isSet()) { - // If the member name was a qualified-id, look into the - // nested-name-specifier. - DC = computeDeclContext(SS, false); - - if (!isa(DC)) { - Diag(MemberLoc, diag::err_qualified_member_nonclass) - << DC << SS.getRange(); - return ExprError(); - } - - // FIXME: If DC is not computable, we should build a - // CXXDependentScopeMemberExpr. - assert(DC && "Cannot handle non-computable dependent contexts in lookup"); - } - - // The record definition is complete, now make sure the member is valid. - LookupQualifiedName(R, DC); return Owned((Expr*) 0); } @@ -2644,7 +2916,7 @@ Sema::LookupMemberExpr(LookupResult &R, Expr *&BaseExpr, BaseType->isSpecificBuiltinType(BuiltinType::ObjCId) && MemberName.getAsIdentifierInfo()->isStr("isa")) return Owned(new (Context) ObjCIsaExpr(BaseExpr, false, MemberLoc, - Context.getObjCIdType())); + Context.getObjCClassType())); // Handle 'field access' to vectors, such as 'V.xx'. if (BaseType->isExtVectorType()) { @@ -2723,7 +2995,7 @@ Sema::OwningExprResult Sema::ActOnMemberAccessExpr(Scope *S, ExprArg BaseArg, Expr *Base = BaseArg.takeAs(); OwningExprResult Result(*this); if (Base->getType()->isDependentType()) { - Result = ActOnDependentMemberExpr(ExprArg(*this, Base), + Result = ActOnDependentMemberExpr(ExprArg(*this, Base), Base->getType(), IsArrow, OpLoc, SS, FirstQualifierInScope, Name, NameLoc, @@ -2756,8 +3028,8 @@ Sema::OwningExprResult Sema::ActOnMemberAccessExpr(Scope *S, ExprArg BaseArg, } } - Result = BuildMemberReferenceExpr(ExprArg(*this, Base), OpLoc, - IsArrow, SS, R, TemplateArgs); + Result = BuildMemberReferenceExpr(ExprArg(*this, Base), Base->getType(), + OpLoc, IsArrow, SS, R, TemplateArgs); } return move(Result); @@ -3054,16 +3326,16 @@ Sema::ActOnCallExpr(Scope *S, ExprArg fn, SourceLocation LParenLoc, isa(*MemE->decls_begin())); (void)MemE; - return Owned(BuildCallToMemberFunction(S, Fn, LParenLoc, Args, NumArgs, - CommaLocs, RParenLoc)); + return BuildCallToMemberFunction(S, Fn, LParenLoc, Args, NumArgs, + CommaLocs, RParenLoc); } // Determine whether this is a call to a member function. if (MemberExpr *MemExpr = dyn_cast(NakedFn)) { NamedDecl *MemDecl = MemExpr->getMemberDecl(); if (isa(MemDecl)) - return Owned(BuildCallToMemberFunction(S, Fn, LParenLoc, Args, NumArgs, - CommaLocs, RParenLoc)); + return BuildCallToMemberFunction(S, Fn, LParenLoc, Args, NumArgs, + CommaLocs, RParenLoc); } // Determine whether this is a call to a pointer-to-member function. @@ -3155,13 +3427,28 @@ Sema::ActOnCallExpr(Scope *S, ExprArg fn, SourceLocation LParenLoc, } else { assert(Fns.size() <= 1 && "overloaded without Overloaded flag"); if (Fns.empty()) - NDecl = FDecl = 0; + NDecl = 0; else { NDecl = Fns[0]; - FDecl = dyn_cast(NDecl); } } + return BuildResolvedCallExpr(Fn, NDecl, LParenLoc, Args, NumArgs, RParenLoc); +} + +/// BuildCallExpr - Build a call to a resolved expression, i.e. an +/// expression not of \p OverloadTy. The expression should +/// unary-convert to an expression of function-pointer or +/// block-pointer type. +/// +/// \param NDecl the declaration being called, if available +Sema::OwningExprResult +Sema::BuildResolvedCallExpr(Expr *Fn, NamedDecl *NDecl, + SourceLocation LParenLoc, + Expr **Args, unsigned NumArgs, + SourceLocation RParenLoc) { + FunctionDecl *FDecl = dyn_cast_or_null(NDecl); + // Promote the function operand. UsualUnaryConversions(Fn); @@ -3661,41 +3948,14 @@ QualType Sema::CheckConditionalOperands(Expr *&Cond, Expr *&LHS, Expr *&RHS, ImpCastExprToType(LHS, RHSTy, CastExpr::CK_Unknown); return RHSTy; } - // Handle things like Class and struct objc_class*. Here we case the result - // to the pseudo-builtin, because that will be implicitly cast back to the - // redefinition type if an attempt is made to access its fields. - if (LHSTy->isObjCClassType() && - (RHSTy.getDesugaredType() == Context.ObjCClassRedefinitionType)) { - ImpCastExprToType(RHS, LHSTy, CastExpr::CK_BitCast); - return LHSTy; - } - if (RHSTy->isObjCClassType() && - (LHSTy.getDesugaredType() == Context.ObjCClassRedefinitionType)) { - ImpCastExprToType(LHS, RHSTy, CastExpr::CK_BitCast); - return RHSTy; - } - // And the same for struct objc_object* / id - if (LHSTy->isObjCIdType() && - (RHSTy.getDesugaredType() == Context.ObjCIdRedefinitionType)) { - ImpCastExprToType(RHS, LHSTy, CastExpr::CK_BitCast); - return LHSTy; - } - if (RHSTy->isObjCIdType() && - (LHSTy.getDesugaredType() == Context.ObjCIdRedefinitionType)) { - ImpCastExprToType(LHS, RHSTy, CastExpr::CK_BitCast); - return RHSTy; - } - // And the same for struct objc_selector* / SEL - if (Context.isObjCSelType(LHSTy) && - (RHSTy.getDesugaredType() == Context.ObjCSelRedefinitionType)) { - ImpCastExprToType(RHS, LHSTy, CastExpr::CK_BitCast); - return LHSTy; - } - if (Context.isObjCSelType(RHSTy) && - (LHSTy.getDesugaredType() == Context.ObjCSelRedefinitionType)) { - ImpCastExprToType(LHS, RHSTy, CastExpr::CK_BitCast); - return RHSTy; - } + + // All objective-c pointer type analysis is done here. + QualType compositeType = FindCompositeObjCPointerType(LHS, RHS, + QuestionLoc); + if (!compositeType.isNull()) + return compositeType; + + // Handle block pointer types. if (LHSTy->isBlockPointerType() || RHSTy->isBlockPointerType()) { if (!LHSTy->isBlockPointerType() || !RHSTy->isBlockPointerType()) { @@ -3706,7 +3966,7 @@ QualType Sema::CheckConditionalOperands(Expr *&Cond, Expr *&LHS, Expr *&RHS, return destType; } Diag(QuestionLoc, diag::err_typecheck_cond_incompatible_operands) - << LHSTy << RHSTy << LHS->getSourceRange() << RHS->getSourceRange(); + << LHSTy << RHSTy << LHS->getSourceRange() << RHS->getSourceRange(); return QualType(); } // We have 2 block pointer types. @@ -3717,11 +3977,11 @@ QualType Sema::CheckConditionalOperands(Expr *&Cond, Expr *&LHS, Expr *&RHS, // The block pointer types aren't identical, continue checking. QualType lhptee = LHSTy->getAs()->getPointeeType(); QualType rhptee = RHSTy->getAs()->getPointeeType(); - + if (!Context.typesAreCompatible(lhptee.getUnqualifiedType(), rhptee.getUnqualifiedType())) { Diag(QuestionLoc, diag::warn_typecheck_cond_incompatible_pointers) - << LHSTy << RHSTy << LHS->getSourceRange() << RHS->getSourceRange(); + << LHSTy << RHSTy << LHS->getSourceRange() << RHS->getSourceRange(); // In this situation, we assume void* type. No especially good // reason, but this is what gcc does, and we do have to pick // to get a consistent AST. @@ -3735,86 +3995,7 @@ QualType Sema::CheckConditionalOperands(Expr *&Cond, Expr *&LHS, Expr *&RHS, ImpCastExprToType(RHS, LHSTy, CastExpr::CK_BitCast); return LHSTy; } - // Check constraints for Objective-C object pointers types. - if (LHSTy->isObjCObjectPointerType() && RHSTy->isObjCObjectPointerType()) { - - if (Context.getCanonicalType(LHSTy) == Context.getCanonicalType(RHSTy)) { - // Two identical object pointer types are always compatible. - return LHSTy; - } - const ObjCObjectPointerType *LHSOPT = LHSTy->getAs(); - const ObjCObjectPointerType *RHSOPT = RHSTy->getAs(); - QualType compositeType = LHSTy; - - // If both operands are interfaces and either operand can be - // assigned to the other, use that type as the composite - // type. This allows - // xxx ? (A*) a : (B*) b - // where B is a subclass of A. - // - // Additionally, as for assignment, if either type is 'id' - // allow silent coercion. Finally, if the types are - // incompatible then make sure to use 'id' as the composite - // type so the result is acceptable for sending messages to. - - // FIXME: Consider unifying with 'areComparableObjCPointerTypes'. - // It could return the composite type. - if (Context.canAssignObjCInterfaces(LHSOPT, RHSOPT)) { - compositeType = RHSOPT->isObjCBuiltinType() ? RHSTy : LHSTy; - } else if (Context.canAssignObjCInterfaces(RHSOPT, LHSOPT)) { - compositeType = LHSOPT->isObjCBuiltinType() ? LHSTy : RHSTy; - } else if ((LHSTy->isObjCQualifiedIdType() || - RHSTy->isObjCQualifiedIdType()) && - Context.ObjCQualifiedIdTypesAreCompatible(LHSTy, RHSTy, true)) { - // Need to handle "id" explicitly. - // GCC allows qualified id and any Objective-C type to devolve to - // id. Currently localizing to here until clear this should be - // part of ObjCQualifiedIdTypesAreCompatible. - compositeType = Context.getObjCIdType(); - } else if (LHSTy->isObjCIdType() || RHSTy->isObjCIdType()) { - compositeType = Context.getObjCIdType(); - } else if (!(compositeType = - Context.areCommonBaseCompatible(LHSOPT, RHSOPT)).isNull()) - ; - else { - Diag(QuestionLoc, diag::ext_typecheck_cond_incompatible_operands) - << LHSTy << RHSTy - << LHS->getSourceRange() << RHS->getSourceRange(); - QualType incompatTy = Context.getObjCIdType(); - ImpCastExprToType(LHS, incompatTy, CastExpr::CK_BitCast); - ImpCastExprToType(RHS, incompatTy, CastExpr::CK_BitCast); - return incompatTy; - } - // The object pointer types are compatible. - ImpCastExprToType(LHS, compositeType, CastExpr::CK_BitCast); - ImpCastExprToType(RHS, compositeType, CastExpr::CK_BitCast); - return compositeType; - } - // Check Objective-C object pointer types and 'void *' - if (LHSTy->isVoidPointerType() && RHSTy->isObjCObjectPointerType()) { - QualType lhptee = LHSTy->getAs()->getPointeeType(); - QualType rhptee = RHSTy->getAs()->getPointeeType(); - QualType destPointee - = Context.getQualifiedType(lhptee, rhptee.getQualifiers()); - QualType destType = Context.getPointerType(destPointee); - // Add qualifiers if necessary. - ImpCastExprToType(LHS, destType, CastExpr::CK_NoOp); - // Promote to void*. - ImpCastExprToType(RHS, destType, CastExpr::CK_BitCast); - return destType; - } - if (LHSTy->isObjCObjectPointerType() && RHSTy->isVoidPointerType()) { - QualType lhptee = LHSTy->getAs()->getPointeeType(); - QualType rhptee = RHSTy->getAs()->getPointeeType(); - QualType destPointee - = Context.getQualifiedType(rhptee, lhptee.getQualifiers()); - QualType destType = Context.getPointerType(destPointee); - // Add qualifiers if necessary. - ImpCastExprToType(RHS, destType, CastExpr::CK_NoOp); - // Promote to void*. - ImpCastExprToType(LHS, destType, CastExpr::CK_BitCast); - return destType; - } + // Check constraints for C object pointers types (C99 6.5.15p3,6). if (LHSTy->isPointerType() && RHSTy->isPointerType()) { // get the "pointed to" types @@ -3892,6 +4073,131 @@ QualType Sema::CheckConditionalOperands(Expr *&Cond, Expr *&LHS, Expr *&RHS, return QualType(); } +/// FindCompositeObjCPointerType - Helper method to find composite type of +/// two objective-c pointer types of the two input expressions. +QualType Sema::FindCompositeObjCPointerType(Expr *&LHS, Expr *&RHS, + SourceLocation QuestionLoc) { + QualType LHSTy = LHS->getType(); + QualType RHSTy = RHS->getType(); + + // Handle things like Class and struct objc_class*. Here we case the result + // to the pseudo-builtin, because that will be implicitly cast back to the + // redefinition type if an attempt is made to access its fields. + if (LHSTy->isObjCClassType() && + (RHSTy.getDesugaredType() == Context.ObjCClassRedefinitionType)) { + ImpCastExprToType(RHS, LHSTy, CastExpr::CK_BitCast); + return LHSTy; + } + if (RHSTy->isObjCClassType() && + (LHSTy.getDesugaredType() == Context.ObjCClassRedefinitionType)) { + ImpCastExprToType(LHS, RHSTy, CastExpr::CK_BitCast); + return RHSTy; + } + // And the same for struct objc_object* / id + if (LHSTy->isObjCIdType() && + (RHSTy.getDesugaredType() == Context.ObjCIdRedefinitionType)) { + ImpCastExprToType(RHS, LHSTy, CastExpr::CK_BitCast); + return LHSTy; + } + if (RHSTy->isObjCIdType() && + (LHSTy.getDesugaredType() == Context.ObjCIdRedefinitionType)) { + ImpCastExprToType(LHS, RHSTy, CastExpr::CK_BitCast); + return RHSTy; + } + // And the same for struct objc_selector* / SEL + if (Context.isObjCSelType(LHSTy) && + (RHSTy.getDesugaredType() == Context.ObjCSelRedefinitionType)) { + ImpCastExprToType(RHS, LHSTy, CastExpr::CK_BitCast); + return LHSTy; + } + if (Context.isObjCSelType(RHSTy) && + (LHSTy.getDesugaredType() == Context.ObjCSelRedefinitionType)) { + ImpCastExprToType(LHS, RHSTy, CastExpr::CK_BitCast); + return RHSTy; + } + // Check constraints for Objective-C object pointers types. + if (LHSTy->isObjCObjectPointerType() && RHSTy->isObjCObjectPointerType()) { + + if (Context.getCanonicalType(LHSTy) == Context.getCanonicalType(RHSTy)) { + // Two identical object pointer types are always compatible. + return LHSTy; + } + const ObjCObjectPointerType *LHSOPT = LHSTy->getAs(); + const ObjCObjectPointerType *RHSOPT = RHSTy->getAs(); + QualType compositeType = LHSTy; + + // If both operands are interfaces and either operand can be + // assigned to the other, use that type as the composite + // type. This allows + // xxx ? (A*) a : (B*) b + // where B is a subclass of A. + // + // Additionally, as for assignment, if either type is 'id' + // allow silent coercion. Finally, if the types are + // incompatible then make sure to use 'id' as the composite + // type so the result is acceptable for sending messages to. + + // FIXME: Consider unifying with 'areComparableObjCPointerTypes'. + // It could return the composite type. + if (Context.canAssignObjCInterfaces(LHSOPT, RHSOPT)) { + compositeType = RHSOPT->isObjCBuiltinType() ? RHSTy : LHSTy; + } else if (Context.canAssignObjCInterfaces(RHSOPT, LHSOPT)) { + compositeType = LHSOPT->isObjCBuiltinType() ? LHSTy : RHSTy; + } else if ((LHSTy->isObjCQualifiedIdType() || + RHSTy->isObjCQualifiedIdType()) && + Context.ObjCQualifiedIdTypesAreCompatible(LHSTy, RHSTy, true)) { + // Need to handle "id" explicitly. + // GCC allows qualified id and any Objective-C type to devolve to + // id. Currently localizing to here until clear this should be + // part of ObjCQualifiedIdTypesAreCompatible. + compositeType = Context.getObjCIdType(); + } else if (LHSTy->isObjCIdType() || RHSTy->isObjCIdType()) { + compositeType = Context.getObjCIdType(); + } else if (!(compositeType = + Context.areCommonBaseCompatible(LHSOPT, RHSOPT)).isNull()) + ; + else { + Diag(QuestionLoc, diag::ext_typecheck_cond_incompatible_operands) + << LHSTy << RHSTy + << LHS->getSourceRange() << RHS->getSourceRange(); + QualType incompatTy = Context.getObjCIdType(); + ImpCastExprToType(LHS, incompatTy, CastExpr::CK_BitCast); + ImpCastExprToType(RHS, incompatTy, CastExpr::CK_BitCast); + return incompatTy; + } + // The object pointer types are compatible. + ImpCastExprToType(LHS, compositeType, CastExpr::CK_BitCast); + ImpCastExprToType(RHS, compositeType, CastExpr::CK_BitCast); + return compositeType; + } + // Check Objective-C object pointer types and 'void *' + if (LHSTy->isVoidPointerType() && RHSTy->isObjCObjectPointerType()) { + QualType lhptee = LHSTy->getAs()->getPointeeType(); + QualType rhptee = RHSTy->getAs()->getPointeeType(); + QualType destPointee + = Context.getQualifiedType(lhptee, rhptee.getQualifiers()); + QualType destType = Context.getPointerType(destPointee); + // Add qualifiers if necessary. + ImpCastExprToType(LHS, destType, CastExpr::CK_NoOp); + // Promote to void*. + ImpCastExprToType(RHS, destType, CastExpr::CK_BitCast); + return destType; + } + if (LHSTy->isObjCObjectPointerType() && RHSTy->isVoidPointerType()) { + QualType lhptee = LHSTy->getAs()->getPointeeType(); + QualType rhptee = RHSTy->getAs()->getPointeeType(); + QualType destPointee + = Context.getQualifiedType(rhptee, lhptee.getQualifiers()); + QualType destType = Context.getPointerType(destPointee); + // Add qualifiers if necessary. + ImpCastExprToType(RHS, destType, CastExpr::CK_NoOp); + // Promote to void*. + ImpCastExprToType(LHS, destType, CastExpr::CK_BitCast); + return destType; + } + return QualType(); +} + /// ActOnConditionalOp - Parse a ?: operation. Note that 'LHS' may be null /// in the case of a the GNU conditional expr extension. Action::OwningExprResult Sema::ActOnConditionalOp(SourceLocation QuestionLoc, @@ -4051,6 +4357,29 @@ Sema::CheckBlockPointerTypesForAssignment(QualType lhsType, return ConvTy; } +/// CheckObjCPointerTypesForAssignment - Compares two objective-c pointer types +/// for assignment compatibility. +Sema::AssignConvertType +Sema::CheckObjCPointerTypesForAssignment(QualType lhsType, QualType rhsType) { + if (lhsType->isObjCBuiltinType() || rhsType->isObjCBuiltinType()) + return Compatible; + QualType lhptee = + lhsType->getAs()->getPointeeType(); + QualType rhptee = + rhsType->getAs()->getPointeeType(); + // make sure we operate on the canonical type + lhptee = Context.getCanonicalType(lhptee); + rhptee = Context.getCanonicalType(rhptee); + if (!lhptee.isAtLeastAsQualifiedAs(rhptee)) + return CompatiblePointerDiscardsQualifiers; + + if (Context.typesAreCompatible(lhsType, rhsType)) + return Compatible; + if (lhsType->isObjCQualifiedIdType() || rhsType->isObjCQualifiedIdType()) + return IncompatibleObjCQualifiedId; + return IncompatiblePointer; +} + /// CheckAssignmentConstraints (C99 6.5.16) - This routine currently /// has code to accommodate several GCC extensions when type checking /// pointers. Here are some objectionable examples that GCC considers warnings: @@ -4173,13 +4502,7 @@ Sema::CheckAssignmentConstraints(QualType lhsType, QualType rhsType) { return IncompatiblePointer; } if (rhsType->isObjCObjectPointerType()) { - if (lhsType->isObjCBuiltinType() || rhsType->isObjCBuiltinType()) - return Compatible; - if (Context.typesAreCompatible(lhsType, rhsType)) - return Compatible; - if (lhsType->isObjCQualifiedIdType() || rhsType->isObjCQualifiedIdType()) - return IncompatibleObjCQualifiedId; - return IncompatiblePointer; + return CheckObjCPointerTypesForAssignment(lhsType, rhsType); } if (const PointerType *RHSPT = rhsType->getAs()) { if (RHSPT->getPointeeType()->isVoidType()) @@ -4794,6 +5117,7 @@ QualType Sema::CheckCompareOperands(Expr *&lex, Expr *&rex, SourceLocation Loc, unsigned OpaqueOpc, bool isRelational) { BinaryOperator::Opcode Opc = (BinaryOperator::Opcode)OpaqueOpc; + // Handle vector comparisons separately. if (lex->getType()->isVectorType() || rex->getType()->isVectorType()) return CheckVectorCompareOperands(lex, rex, Loc, isRelational); @@ -4871,17 +5195,15 @@ QualType Sema::CheckCompareOperands(Expr *&lex, Expr *&rex, SourceLocation Loc, } // The result of comparisons is 'bool' in C++, 'int' in C. - QualType ResultTy = getLangOptions().CPlusPlus? Context.BoolTy :Context.IntTy; + QualType ResultTy = getLangOptions().CPlusPlus ? Context.BoolTy:Context.IntTy; if (isRelational) { if (lType->isRealType() && rType->isRealType()) return ResultTy; } else { // Check for comparisons of floating point operands using != and ==. - if (lType->isFloatingType()) { - assert(rType->isFloatingType()); + if (lType->isFloatingType() && rType->isFloatingType()) CheckFloatComparison(Loc,lex,rex); - } if (lType->isArithmeticType() && rType->isArithmeticType()) return ResultTy; @@ -6157,18 +6479,33 @@ Sema::OwningExprResult Sema::ActOnBuiltinOffsetOf(Scope *S, RecordDecl *RD = RC->getDecl(); if (CXXRecordDecl *CRD = dyn_cast(RD)) { if (!CRD->isPOD() && !DidWarnAboutNonPOD) { - ExprError(Diag(BuiltinLoc, diag::warn_offsetof_non_pod_type) - << SourceRange(CompPtr[0].LocStart, OC.LocEnd) - << Res->getType()); - DidWarnAboutNonPOD = true; + switch (ExprEvalContexts.back().Context ) { + case Unevaluated: + // The argument will never be evaluated, so don't complain. + break; + + case PotentiallyEvaluated: + ExprError(Diag(BuiltinLoc, diag::warn_offsetof_non_pod_type) + << SourceRange(CompPtr[0].LocStart, OC.LocEnd) + << Res->getType()); + DidWarnAboutNonPOD = true; + break; + + case PotentiallyPotentiallyEvaluated: + ExprEvalContexts.back().addDiagnostic(BuiltinLoc, + PDiag(diag::warn_offsetof_non_pod_type) + << SourceRange(CompPtr[0].LocStart, OC.LocEnd) + << Res->getType()); + DidWarnAboutNonPOD = true; + break; + } } } LookupResult R(*this, OC.U.IdentInfo, OC.LocStart, LookupMemberName); LookupQualifiedName(R, RD); - FieldDecl *MemberDecl - = dyn_cast_or_null(R.getAsSingleDecl(Context)); + FieldDecl *MemberDecl = R.getAsSingle(); // FIXME: Leaks Res if (!MemberDecl) return ExprError(Diag(BuiltinLoc, diag::err_no_member) @@ -6180,6 +6517,7 @@ Sema::OwningExprResult Sema::ActOnBuiltinOffsetOf(Scope *S, Res = BuildAnonymousStructUnionMemberReference( OC.LocEnd, MemberDecl, Res, OC.LocEnd).takeAs(); } else { + PerformObjectMemberConversion(Res, MemberDecl); // MemberDecl->getType() doesn't get the right qualifiers, but it // doesn't matter here. Res = new (Context) MemberExpr(Res, false, MemberDecl, OC.LocEnd, @@ -6270,6 +6608,7 @@ void Sema::ActOnBlockStart(SourceLocation CaretLoc, Scope *BlockScope) { CurFunctionNeedsScopeChecking = false; BSI->TheDecl = BlockDecl::Create(Context, CurContext, CaretLoc); + CurContext->addDecl(BSI->TheDecl); PushDeclContext(BlockScope, BSI->TheDecl); } @@ -6625,16 +6964,26 @@ Sema::PopExpressionEvaluationContext() { ExpressionEvaluationContextRecord Rec = ExprEvalContexts.back(); ExprEvalContexts.pop_back(); - if (Rec.Context == PotentiallyPotentiallyEvaluated && - Rec.PotentiallyReferenced) { - // Mark any remaining declarations in the current position of the stack - // as "referenced". If they were not meant to be referenced, semantic - // analysis would have eliminated them (e.g., in ActOnCXXTypeId). - for (PotentiallyReferencedDecls::iterator - I = Rec.PotentiallyReferenced->begin(), - IEnd = Rec.PotentiallyReferenced->end(); - I != IEnd; ++I) - MarkDeclarationReferenced(I->first, I->second); + if (Rec.Context == PotentiallyPotentiallyEvaluated) { + if (Rec.PotentiallyReferenced) { + // Mark any remaining declarations in the current position of the stack + // as "referenced". If they were not meant to be referenced, semantic + // analysis would have eliminated them (e.g., in ActOnCXXTypeId). + for (PotentiallyReferencedDecls::iterator + I = Rec.PotentiallyReferenced->begin(), + IEnd = Rec.PotentiallyReferenced->end(); + I != IEnd; ++I) + MarkDeclarationReferenced(I->first, I->second); + } + + if (Rec.PotentiallyDiagnosed) { + // Emit any pending diagnostics. + for (PotentiallyEmittedDiagnostics::iterator + I = Rec.PotentiallyDiagnosed->begin(), + IEnd = Rec.PotentiallyDiagnosed->end(); + I != IEnd; ++I) + Diag(I->first, I->second); + } } // When are coming out of an unevaluated context, clear out any @@ -6708,6 +7057,8 @@ void Sema::MarkDeclarationReferenced(SourceLocation Loc, Decl *D) { if (!Constructor->isUsed()) DefineImplicitCopyConstructor(Loc, Constructor, TypeQuals); } + + MaybeMarkVirtualMembersReferenced(Loc, Constructor); } else if (CXXDestructorDecl *Destructor = dyn_cast(D)) { if (Destructor->isImplicit() && !Destructor->isUsed()) DefineImplicitDestructor(Loc, Destructor); diff --git a/lib/Sema/SemaExprCXX.cpp b/lib/Sema/SemaExprCXX.cpp index 00fb65df92c7..6d991b6a7c6b 100644 --- a/lib/Sema/SemaExprCXX.cpp +++ b/lib/Sema/SemaExprCXX.cpp @@ -12,6 +12,7 @@ //===----------------------------------------------------------------------===// #include "Sema.h" +#include "SemaInit.h" #include "Lookup.h" #include "clang/AST/ASTContext.h" #include "clang/AST/CXXInheritance.h" @@ -37,8 +38,7 @@ Sema::ActOnCXXTypeid(SourceLocation OpLoc, SourceLocation LParenLoc, IdentifierInfo *TypeInfoII = &PP.getIdentifierTable().get("type_info"); LookupResult R(*this, TypeInfoII, SourceLocation(), LookupTagName); LookupQualifiedName(R, StdNamespace); - Decl *TypeInfoDecl = R.getAsSingleDecl(Context); - RecordDecl *TypeInfoRecordDecl = dyn_cast_or_null(TypeInfoDecl); + RecordDecl *TypeInfoRecordDecl = R.getAsSingle(); if (!TypeInfoRecordDecl) return ExprError(Diag(OpLoc, diag::err_need_header_before_typeid)); @@ -226,7 +226,9 @@ Sema::ActOnCXXTypeConstructExpr(SourceRange TypeRange, TypeTy *TypeRep, SourceRange(TypeRange.getBegin(), RParenLoc), DeclarationName(), - IK_Direct, + InitializationKind::CreateDirect(TypeRange.getBegin(), + LParenLoc, + RParenLoc), ConstructorArgs); if (!Constructor) @@ -322,9 +324,9 @@ Sema::ActOnCXXNew(SourceLocation StartLoc, bool UseGlobal, } } - //FIXME: Store DeclaratorInfo in CXXNew expression. - DeclaratorInfo *DInfo = 0; - QualType AllocType = GetTypeForDeclarator(D, /*Scope=*/0, &DInfo); + //FIXME: Store TypeSourceInfo in CXXNew expression. + TypeSourceInfo *TInfo = 0; + QualType AllocType = GetTypeForDeclarator(D, /*Scope=*/0, &TInfo); if (D.isInvalidType()) return ExprError(); @@ -450,12 +452,17 @@ Sema::BuildCXXNew(SourceLocation StartLoc, bool UseGlobal, // Skip all the checks. } else if ((RT = AllocType->getAs()) && !AllocType->isAggregateType()) { + InitializationKind InitKind = InitializationKind::CreateDefault(TypeLoc); + if (NumConsArgs > 0) + InitKind = InitializationKind::CreateDirect(TypeLoc, + PlacementLParen, + PlacementRParen); Constructor = PerformInitializationByConstructor( AllocType, move(ConstructorArgs), TypeLoc, SourceRange(TypeLoc, ConstructorRParen), RT->getDecl()->getDeclName(), - NumConsArgs != 0 ? IK_Direct : IK_Default, + InitKind, ConvertedConstructorArgs); if (!Constructor) return ExprError(); @@ -602,7 +609,8 @@ bool Sema::FindAllocationOverload(SourceLocation StartLoc, SourceRange Range, Alloc != AllocEnd; ++Alloc) { // Even member operator new/delete are implicitly treated as // static, so don't use AddMemberCandidate. - if (FunctionDecl *Fn = dyn_cast(*Alloc)) { + if (FunctionDecl *Fn = + dyn_cast((*Alloc)->getUnderlyingDecl())) { AddOverloadCandidate(Fn, Args, NumArgs, Candidates, /*SuppressUserConversions=*/false); continue; @@ -761,10 +769,10 @@ void Sema::DeclareGlobalAllocationFunction(DeclarationName Name, &BadAllocType); FunctionDecl *Alloc = FunctionDecl::Create(Context, GlobalCtx, SourceLocation(), Name, - FnType, /*DInfo=*/0, FunctionDecl::None, false, true); + FnType, /*TInfo=*/0, FunctionDecl::None, false, true); Alloc->setImplicit(); ParmVarDecl *Param = ParmVarDecl::Create(Context, Alloc, SourceLocation(), - 0, Argument, /*DInfo=*/0, + 0, Argument, /*TInfo=*/0, VarDecl::None, 0); Alloc->setParams(Context, &Param, 1); @@ -1270,6 +1278,16 @@ Sema::PerformImplicitConversion(Expr *&From, QualType ToType, // Nothing else to do. break; + case ICK_NoReturn_Adjustment: + // If both sides are functions (or pointers/references to them), there could + // be incompatible exception declarations. + if (CheckExceptionSpecCompatibility(From, ToType)) + return true; + + ImpCastExprToType(From, Context.getNoReturnType(From->getType(), false), + CastExpr::CK_NoOp); + break; + case ICK_Integral_Promotion: case ICK_Integral_Conversion: ImpCastExprToType(From, ToType, CastExpr::CK_IntegralCast); @@ -1574,7 +1592,7 @@ static bool FindConditionalOverload(Sema &Self, Expr *&LHS, Expr *&RHS, OverloadCandidateSet::iterator Best; switch (Self.BestViableFunction(CandidateSet, Loc, Best)) { - case Sema::OR_Success: + case OR_Success: // We found a match. Perform the conversions on the arguments and move on. if (Self.PerformImplicitConversion(LHS, Best->BuiltinTypes.ParamTypes[0], Best->Conversions[0], "converting") || @@ -1583,13 +1601,13 @@ static bool FindConditionalOverload(Sema &Self, Expr *&LHS, Expr *&RHS, break; return false; - case Sema::OR_No_Viable_Function: + case OR_No_Viable_Function: Self.Diag(Loc, diag::err_typecheck_cond_incompatible_operands) << LHS->getType() << RHS->getType() << LHS->getSourceRange() << RHS->getSourceRange(); return true; - case Sema::OR_Ambiguous: + case OR_Ambiguous: Self.Diag(Loc, diag::err_conditional_ambiguous_ovl) << LHS->getType() << RHS->getType() << LHS->getSourceRange() << RHS->getSourceRange(); @@ -1597,7 +1615,7 @@ static bool FindConditionalOverload(Sema &Self, Expr *&LHS, Expr *&RHS, // the viable candidates. break; - case Sema::OR_Deleted: + case OR_Deleted: assert(false && "Conditional operator has only built-in overloads"); break; } @@ -1788,6 +1806,11 @@ QualType Sema::CXXCheckConditionalOperands(Expr *&Cond, Expr *&LHS, Expr *&RHS, QualType Composite = FindCompositePointerType(LHS, RHS); if (!Composite.isNull()) return Composite; + + // Similarly, attempt to find composite type of twp objective-c pointers. + Composite = FindCompositeObjCPointerType(LHS, RHS, QuestionLoc); + if (!Composite.isNull()) + return Composite; // Fourth bullet is same for pointers-to-member. However, the possible // conversions are far more limited: we have null-to-pointer, upcast of @@ -1882,8 +1905,8 @@ QualType Sema::FindCompositePointerType(Expr *&E1, Expr *&E2) { assert(getLangOptions().CPlusPlus && "This function assumes C++"); QualType T1 = E1->getType(), T2 = E2->getType(); - if (!T1->isPointerType() && !T1->isMemberPointerType() && - !T2->isPointerType() && !T2->isMemberPointerType()) + if (!T1->isAnyPointerType() && !T1->isMemberPointerType() && + !T2->isAnyPointerType() && !T2->isMemberPointerType()) return QualType(); // C++0x 5.9p2 @@ -2070,14 +2093,17 @@ Expr *Sema::MaybeCreateCXXExprWithTemporaries(Expr *SubExpr, bool ShouldDestroyTemps) { assert(SubExpr && "sub expression can't be null!"); - if (ExprTemporaries.empty()) + unsigned FirstTemporary = ExprEvalContexts.back().NumTemporaries; + assert(ExprTemporaries.size() >= FirstTemporary); + if (ExprTemporaries.size() == FirstTemporary) return SubExpr; Expr *E = CXXExprWithTemporaries::Create(Context, SubExpr, - &ExprTemporaries[0], - ExprTemporaries.size(), + &ExprTemporaries[FirstTemporary], + ExprTemporaries.size() - FirstTemporary, ShouldDestroyTemps); - ExprTemporaries.clear(); + ExprTemporaries.erase(ExprTemporaries.begin() + FirstTemporary, + ExprTemporaries.end()); return E; } @@ -2164,15 +2190,13 @@ Sema::ActOnStartCXXMemberReference(Scope *S, ExprArg Base, SourceLocation OpLoc, CXXMemberCallExpr *Sema::BuildCXXMemberCallExpr(Expr *Exp, CXXMethodDecl *Method) { + if (PerformObjectArgumentInitialization(Exp, Method)) + assert(0 && "Calling BuildCXXMemberCallExpr with invalid call?"); + MemberExpr *ME = new (Context) MemberExpr(Exp, /*IsArrow=*/false, Method, SourceLocation(), Method->getType()); - QualType ResultType; - if (const CXXConversionDecl *Conv = dyn_cast(Method)) - ResultType = Conv->getConversionType().getNonReferenceType(); - else - ResultType = Method->getResultType().getNonReferenceType(); - + QualType ResultType = Method->getResultType().getNonReferenceType(); MarkDeclarationReferenced(Exp->getLocStart(), Method); CXXMemberCallExpr *CE = new (Context) CXXMemberCallExpr(Context, ME, 0, 0, ResultType, @@ -2208,11 +2232,7 @@ Sema::OwningExprResult Sema::BuildCXXCastArgument(SourceLocation CastLoc, case CastExpr::CK_UserDefinedConversion: { assert(!From->getType()->isPointerType() && "Arg can't have pointer type!"); - - // Cast to base if needed. - if (PerformObjectArgumentInitialization(From, Method)) - return ExprError(); - + // Create an implicit call expr that calls it. CXXMemberCallExpr *CE = BuildCXXMemberCallExpr(From, Method); return MaybeBindToTemporary(CE); diff --git a/lib/Sema/SemaInit.cpp b/lib/Sema/SemaInit.cpp index 2eba704ff3a3..45184650eb7e 100644 --- a/lib/Sema/SemaInit.cpp +++ b/lib/Sema/SemaInit.cpp @@ -15,11 +15,13 @@ // //===----------------------------------------------------------------------===// +#include "SemaInit.h" #include "Sema.h" #include "clang/Parse/Designator.h" #include "clang/AST/ASTContext.h" #include "clang/AST/ExprCXX.h" #include "clang/AST/ExprObjC.h" +#include "llvm/Support/ErrorHandling.h" #include using namespace clang; @@ -76,7 +78,7 @@ static bool CheckSingleInitializer(Expr *&Init, QualType DeclType, OverloadCandidateSet CandidateSet; if (S.IsUserDefinedConversion(Init, DeclType, ICS.UserDefined, CandidateSet, - true, false, false) != S.OR_Ambiguous) + true, false, false) != OR_Ambiguous) return S.Diag(Init->getSourceRange().getBegin(), diag::err_typecheck_convert_incompatible) << DeclType << Init->getType() << "initializing" @@ -230,13 +232,20 @@ bool Sema::CheckInitializerTypes(Expr *&Init, QualType &DeclType, ASTOwningVector<&ActionBase::DeleteExpr> ConstructorArgs(*this); + // FIXME: Poor location information + InitializationKind InitKind + = InitializationKind::CreateCopy(Init->getLocStart(), + SourceLocation()); + if (DirectInit) + InitKind = InitializationKind::CreateDirect(Init->getLocStart(), + SourceLocation(), + SourceLocation()); CXXConstructorDecl *Constructor = PerformInitializationByConstructor(DeclType, MultiExprArg(*this, (void **)&Init, 1), InitLoc, Init->getSourceRange(), - InitEntity, - DirectInit? IK_Direct : IK_Copy, + InitEntity, InitKind, ConstructorArgs); if (!Constructor) return true; @@ -637,8 +646,8 @@ void InitListChecker::CheckExplicitInitList(InitListExpr *IList, QualType &T, if (T->isScalarType() && !TopLevelObject) SemaRef.Diag(IList->getLocStart(), diag::warn_braces_around_scalar_init) << IList->getSourceRange() - << CodeModificationHint::CreateRemoval(SourceRange(IList->getLocStart())) - << CodeModificationHint::CreateRemoval(SourceRange(IList->getLocEnd())); + << CodeModificationHint::CreateRemoval(IList->getLocStart()) + << CodeModificationHint::CreateRemoval(IList->getLocEnd()); } void InitListChecker::CheckListElementTypes(InitListExpr *IList, @@ -1875,12 +1884,13 @@ bool Sema::CheckValueInitialization(QualType Type, SourceLocation Loc) { if (ClassDecl->hasUserDeclaredConstructor()) { ASTOwningVector<&ActionBase::DeleteExpr> ConstructorArgs(*this); + // FIXME: Poor location information CXXConstructorDecl *Constructor = PerformInitializationByConstructor(Type, MultiExprArg(*this, 0, 0), Loc, SourceRange(Loc), DeclarationName(), - IK_Direct, + InitializationKind::CreateValue(Loc, Loc, Loc), ConstructorArgs); if (!Constructor) return true; @@ -1908,3 +1918,1379 @@ bool Sema::CheckValueInitialization(QualType Type, SourceLocation Loc) { return false; } + +//===----------------------------------------------------------------------===// +// Initialization entity +//===----------------------------------------------------------------------===// + +void InitializedEntity::InitDeclLoc() { + assert((Kind == EK_Variable || Kind == EK_Parameter || Kind == EK_Member) && + "InitDeclLoc cannot be used with non-declaration entities."); + + if (TypeSourceInfo *DI = VariableOrMember->getTypeSourceInfo()) { + TL = DI->getTypeLoc(); + return; + } + + // FIXME: Once we've gone through the effort to create the fake + // TypeSourceInfo, should we cache it in the declaration? + // (If not, we "leak" it). + TypeSourceInfo *DI = VariableOrMember->getASTContext() + .CreateTypeSourceInfo(VariableOrMember->getType()); + DI->getTypeLoc().initialize(VariableOrMember->getLocation()); + TL = DI->getTypeLoc(); +} + +InitializedEntity InitializedEntity::InitializeBase(ASTContext &Context, + CXXBaseSpecifier *Base) +{ + InitializedEntity Result; + Result.Kind = EK_Base; + Result.Base = Base; + // FIXME: CXXBaseSpecifier should store a TypeLoc. + TypeSourceInfo *DI = Context.CreateTypeSourceInfo(Base->getType()); + DI->getTypeLoc().initialize(Base->getSourceRange().getBegin()); + Result.TL = DI->getTypeLoc(); + return Result; +} + +//===----------------------------------------------------------------------===// +// Initialization sequence +//===----------------------------------------------------------------------===// + +void InitializationSequence::Step::Destroy() { + switch (Kind) { + case SK_ResolveAddressOfOverloadedFunction: + case SK_CastDerivedToBaseRValue: + case SK_CastDerivedToBaseLValue: + case SK_BindReference: + case SK_BindReferenceToTemporary: + case SK_UserConversion: + case SK_QualificationConversionRValue: + case SK_QualificationConversionLValue: + case SK_ListInitialization: + case SK_ConstructorInitialization: + case SK_ZeroInitialization: + break; + + case SK_ConversionSequence: + delete ICS; + } +} + +void InitializationSequence::AddAddressOverloadResolutionStep( + FunctionDecl *Function) { + Step S; + S.Kind = SK_ResolveAddressOfOverloadedFunction; + S.Type = Function->getType(); + S.Function = Function; + Steps.push_back(S); +} + +void InitializationSequence::AddDerivedToBaseCastStep(QualType BaseType, + bool IsLValue) { + Step S; + S.Kind = IsLValue? SK_CastDerivedToBaseLValue : SK_CastDerivedToBaseRValue; + S.Type = BaseType; + Steps.push_back(S); +} + +void InitializationSequence::AddReferenceBindingStep(QualType T, + bool BindingTemporary) { + Step S; + S.Kind = BindingTemporary? SK_BindReferenceToTemporary : SK_BindReference; + S.Type = T; + Steps.push_back(S); +} + +void InitializationSequence::AddUserConversionStep(FunctionDecl *Function, + QualType T) { + Step S; + S.Kind = SK_UserConversion; + S.Type = T; + S.Function = Function; + Steps.push_back(S); +} + +void InitializationSequence::AddQualificationConversionStep(QualType Ty, + bool IsLValue) { + Step S; + S.Kind = IsLValue? SK_QualificationConversionLValue + : SK_QualificationConversionRValue; + S.Type = Ty; + Steps.push_back(S); +} + +void InitializationSequence::AddConversionSequenceStep( + const ImplicitConversionSequence &ICS, + QualType T) { + Step S; + S.Kind = SK_ConversionSequence; + S.Type = T; + S.ICS = new ImplicitConversionSequence(ICS); + Steps.push_back(S); +} + +void InitializationSequence::AddListInitializationStep(QualType T) { + Step S; + S.Kind = SK_ListInitialization; + S.Type = T; + Steps.push_back(S); +} + +void +InitializationSequence::AddConstructorInitializationStep( + CXXConstructorDecl *Constructor, + QualType T) { + Step S; + S.Kind = SK_ConstructorInitialization; + S.Type = T; + S.Function = Constructor; + Steps.push_back(S); +} + +void InitializationSequence::AddZeroInitializationStep(QualType T) { + Step S; + S.Kind = SK_ZeroInitialization; + S.Type = T; + Steps.push_back(S); +} + +void InitializationSequence::SetOverloadFailure(FailureKind Failure, + OverloadingResult Result) { + SequenceKind = FailedSequence; + this->Failure = Failure; + this->FailedOverloadResult = Result; +} + +//===----------------------------------------------------------------------===// +// Attempt initialization +//===----------------------------------------------------------------------===// + +/// \brief Attempt list initialization (C++0x [dcl.init.list]) +static void TryListInitialization(Sema &S, + const InitializedEntity &Entity, + const InitializationKind &Kind, + InitListExpr *InitList, + InitializationSequence &Sequence) { + // FIXME: We only perform rudimentary checking of list + // initializations at this point, then assume that any list + // initialization of an array, aggregate, or scalar will be + // well-formed. We we actually "perform" list initialization, we'll + // do all of the necessary checking. C++0x initializer lists will + // force us to perform more checking here. + Sequence.setSequenceKind(InitializationSequence::ListInitialization); + + QualType DestType = Entity.getType().getType(); + + // C++ [dcl.init]p13: + // If T is a scalar type, then a declaration of the form + // + // T x = { a }; + // + // is equivalent to + // + // T x = a; + if (DestType->isScalarType()) { + if (InitList->getNumInits() > 1 && S.getLangOptions().CPlusPlus) { + Sequence.SetFailed(InitializationSequence::FK_TooManyInitsForScalar); + return; + } + + // Assume scalar initialization from a single value works. + } else if (DestType->isAggregateType()) { + // Assume aggregate initialization works. + } else if (DestType->isVectorType()) { + // Assume vector initialization works. + } else if (DestType->isReferenceType()) { + // FIXME: C++0x defines behavior for this. + Sequence.SetFailed(InitializationSequence::FK_ReferenceBindingToInitList); + return; + } else if (DestType->isRecordType()) { + // FIXME: C++0x defines behavior for this + Sequence.SetFailed(InitializationSequence::FK_InitListBadDestinationType); + } + + // Add a general "list initialization" step. + Sequence.AddListInitializationStep(DestType); +} + +/// \brief Try a reference initialization that involves calling a conversion +/// function. +/// +/// FIXME: look intos DRs 656, 896 +static OverloadingResult TryRefInitWithConversionFunction(Sema &S, + const InitializedEntity &Entity, + const InitializationKind &Kind, + Expr *Initializer, + bool AllowRValues, + InitializationSequence &Sequence) { + QualType DestType = Entity.getType().getType(); + QualType cv1T1 = DestType->getAs()->getPointeeType(); + QualType T1 = cv1T1.getUnqualifiedType(); + QualType cv2T2 = Initializer->getType(); + QualType T2 = cv2T2.getUnqualifiedType(); + + bool DerivedToBase; + assert(!S.CompareReferenceRelationship(Initializer->getLocStart(), + T1, T2, DerivedToBase) && + "Must have incompatible references when binding via conversion"); + (void)DerivedToBase; + + // Build the candidate set directly in the initialization sequence + // structure, so that it will persist if we fail. + OverloadCandidateSet &CandidateSet = Sequence.getFailedCandidateSet(); + CandidateSet.clear(); + + // Determine whether we are allowed to call explicit constructors or + // explicit conversion operators. + bool AllowExplicit = Kind.getKind() == InitializationKind::IK_Direct; + + const RecordType *T1RecordType = 0; + if (AllowRValues && (T1RecordType = T1->getAs())) { + // The type we're converting to is a class type. Enumerate its constructors + // to see if there is a suitable conversion. + CXXRecordDecl *T1RecordDecl = cast(T1RecordType->getDecl()); + + DeclarationName ConstructorName + = S.Context.DeclarationNames.getCXXConstructorName( + S.Context.getCanonicalType(T1).getUnqualifiedType()); + DeclContext::lookup_iterator Con, ConEnd; + for (llvm::tie(Con, ConEnd) = T1RecordDecl->lookup(ConstructorName); + Con != ConEnd; ++Con) { + // Find the constructor (which may be a template). + CXXConstructorDecl *Constructor = 0; + FunctionTemplateDecl *ConstructorTmpl + = dyn_cast(*Con); + if (ConstructorTmpl) + Constructor = cast( + ConstructorTmpl->getTemplatedDecl()); + else + Constructor = cast(*Con); + + if (!Constructor->isInvalidDecl() && + Constructor->isConvertingConstructor(AllowExplicit)) { + if (ConstructorTmpl) + S.AddTemplateOverloadCandidate(ConstructorTmpl, /*ExplicitArgs*/ 0, + &Initializer, 1, CandidateSet); + else + S.AddOverloadCandidate(Constructor, &Initializer, 1, CandidateSet); + } + } + } + + if (const RecordType *T2RecordType = T2->getAs()) { + // The type we're converting from is a class type, enumerate its conversion + // functions. + CXXRecordDecl *T2RecordDecl = cast(T2RecordType->getDecl()); + + // Determine the type we are converting to. If we are allowed to + // convert to an rvalue, take the type that the destination type + // refers to. + QualType ToType = AllowRValues? cv1T1 : DestType; + + const UnresolvedSet *Conversions + = T2RecordDecl->getVisibleConversionFunctions(); + for (UnresolvedSet::iterator I = Conversions->begin(), + E = Conversions->end(); + I != E; ++I) { + NamedDecl *D = *I; + CXXRecordDecl *ActingDC = cast(D->getDeclContext()); + if (isa(D)) + D = cast(D)->getTargetDecl(); + + FunctionTemplateDecl *ConvTemplate = dyn_cast(D); + CXXConversionDecl *Conv; + if (ConvTemplate) + Conv = cast(ConvTemplate->getTemplatedDecl()); + else + Conv = cast(*I); + + // If the conversion function doesn't return a reference type, + // it can't be considered for this conversion unless we're allowed to + // consider rvalues. + // FIXME: Do we need to make sure that we only consider conversion + // candidates with reference-compatible results? That might be needed to + // break recursion. + if ((AllowExplicit || !Conv->isExplicit()) && + (AllowRValues || Conv->getConversionType()->isLValueReferenceType())){ + if (ConvTemplate) + S.AddTemplateConversionCandidate(ConvTemplate, ActingDC, Initializer, + ToType, CandidateSet); + else + S.AddConversionCandidate(Conv, ActingDC, Initializer, cv1T1, + CandidateSet); + } + } + } + + SourceLocation DeclLoc = Initializer->getLocStart(); + + // Perform overload resolution. If it fails, return the failed result. + OverloadCandidateSet::iterator Best; + if (OverloadingResult Result + = S.BestViableFunction(CandidateSet, DeclLoc, Best)) + return Result; + + FunctionDecl *Function = Best->Function; + + // Compute the returned type of the conversion. + if (isa(Function)) + T2 = Function->getResultType(); + else + T2 = cv1T1; + + // Add the user-defined conversion step. + Sequence.AddUserConversionStep(Function, T2.getNonReferenceType()); + + // Determine whether we need to perform derived-to-base or + // cv-qualification adjustments. + bool NewDerivedToBase = false; + Sema::ReferenceCompareResult NewRefRelationship + = S.CompareReferenceRelationship(DeclLoc, T1, T2.getNonReferenceType(), + NewDerivedToBase); + assert(NewRefRelationship != Sema::Ref_Incompatible && + "Overload resolution picked a bad conversion function"); + (void)NewRefRelationship; + if (NewDerivedToBase) + Sequence.AddDerivedToBaseCastStep( + S.Context.getQualifiedType(T1, + T2.getNonReferenceType().getQualifiers()), + /*isLValue=*/true); + + if (cv1T1.getQualifiers() != T2.getNonReferenceType().getQualifiers()) + Sequence.AddQualificationConversionStep(cv1T1, T2->isReferenceType()); + + Sequence.AddReferenceBindingStep(cv1T1, !T2->isReferenceType()); + return OR_Success; +} + +/// \brief Attempt reference initialization (C++0x [dcl.init.list]) +static void TryReferenceInitialization(Sema &S, + const InitializedEntity &Entity, + const InitializationKind &Kind, + Expr *Initializer, + InitializationSequence &Sequence) { + Sequence.setSequenceKind(InitializationSequence::ReferenceBinding); + + QualType DestType = Entity.getType().getType(); + QualType cv1T1 = DestType->getAs()->getPointeeType(); + QualType T1 = cv1T1.getUnqualifiedType(); + QualType cv2T2 = Initializer->getType(); + QualType T2 = cv2T2.getUnqualifiedType(); + SourceLocation DeclLoc = Initializer->getLocStart(); + + // If the initializer is the address of an overloaded function, try + // to resolve the overloaded function. If all goes well, T2 is the + // type of the resulting function. + if (S.Context.getCanonicalType(T2) == S.Context.OverloadTy) { + FunctionDecl *Fn = S.ResolveAddressOfOverloadedFunction(Initializer, + T1, + false); + if (!Fn) { + Sequence.SetFailed(InitializationSequence::FK_AddressOfOverloadFailed); + return; + } + + Sequence.AddAddressOverloadResolutionStep(Fn); + cv2T2 = Fn->getType(); + T2 = cv2T2.getUnqualifiedType(); + } + + // FIXME: Rvalue references + bool ForceRValue = false; + + // Compute some basic properties of the types and the initializer. + bool isLValueRef = DestType->isLValueReferenceType(); + bool isRValueRef = !isLValueRef; + bool DerivedToBase = false; + Expr::isLvalueResult InitLvalue = ForceRValue ? Expr::LV_InvalidExpression : + Initializer->isLvalue(S.Context); + Sema::ReferenceCompareResult RefRelationship + = S.CompareReferenceRelationship(DeclLoc, cv1T1, cv2T2, DerivedToBase); + + // C++0x [dcl.init.ref]p5: + // A reference to type "cv1 T1" is initialized by an expression of type + // "cv2 T2" as follows: + // + // - If the reference is an lvalue reference and the initializer + // expression + OverloadingResult ConvOvlResult = OR_Success; + if (isLValueRef) { + if (InitLvalue == Expr::LV_Valid && + RefRelationship >= Sema::Ref_Compatible_With_Added_Qualification) { + // - is an lvalue (but is not a bit-field), and "cv1 T1" is + // reference-compatible with "cv2 T2," or + // + // Per C++ [over.best.ics]p2, we ignore whether the lvalue is a + // bit-field when we're determining whether the reference initialization + // can occur. This property will be checked by PerformInitialization. + if (DerivedToBase) + Sequence.AddDerivedToBaseCastStep( + S.Context.getQualifiedType(T1, cv2T2.getQualifiers()), + /*isLValue=*/true); + if (cv1T1.getQualifiers() != cv2T2.getQualifiers()) + Sequence.AddQualificationConversionStep(cv1T1, /*IsLValue=*/true); + Sequence.AddReferenceBindingStep(cv1T1, /*bindingTemporary=*/false); + return; + } + + // - has a class type (i.e., T2 is a class type), where T1 is not + // reference-related to T2, and can be implicitly converted to an + // lvalue of type "cv3 T3," where "cv1 T1" is reference-compatible + // with "cv3 T3" (this conversion is selected by enumerating the + // applicable conversion functions (13.3.1.6) and choosing the best + // one through overload resolution (13.3)), + if (RefRelationship == Sema::Ref_Incompatible && T2->isRecordType()) { + ConvOvlResult = TryRefInitWithConversionFunction(S, Entity, Kind, + Initializer, + /*AllowRValues=*/false, + Sequence); + if (ConvOvlResult == OR_Success) + return; + } + } + + // - Otherwise, the reference shall be an lvalue reference to a + // non-volatile const type (i.e., cv1 shall be const), or the reference + // shall be an rvalue reference and the initializer expression shall + // be an rvalue. + if (!((isLValueRef && cv1T1.getCVRQualifiers() == Qualifiers::Const) || + (isRValueRef && InitLvalue != Expr::LV_Valid))) { + if (ConvOvlResult && !Sequence.getFailedCandidateSet().empty()) + Sequence.SetOverloadFailure( + InitializationSequence::FK_ReferenceInitOverloadFailed, + ConvOvlResult); + else if (isLValueRef) + Sequence.SetFailed(InitLvalue == Expr::LV_Valid + ? (RefRelationship == Sema::Ref_Related + ? InitializationSequence::FK_ReferenceInitDropsQualifiers + : InitializationSequence::FK_NonConstLValueReferenceBindingToUnrelated) + : InitializationSequence::FK_NonConstLValueReferenceBindingToTemporary); + else + Sequence.SetFailed( + InitializationSequence::FK_RValueReferenceBindingToLValue); + + return; + } + + // - If T1 and T2 are class types and + if (T1->isRecordType() && T2->isRecordType()) { + // - the initializer expression is an rvalue and "cv1 T1" is + // reference-compatible with "cv2 T2", or + if (InitLvalue != Expr::LV_Valid && + RefRelationship >= Sema::Ref_Compatible_With_Added_Qualification) { + if (DerivedToBase) + Sequence.AddDerivedToBaseCastStep( + S.Context.getQualifiedType(T1, cv2T2.getQualifiers()), + /*isLValue=*/false); + if (cv1T1.getQualifiers() != cv2T2.getQualifiers()) + Sequence.AddQualificationConversionStep(cv1T1, /*IsLValue=*/false); + Sequence.AddReferenceBindingStep(cv1T1, /*bindingTemporary=*/true); + return; + } + + // - T1 is not reference-related to T2 and the initializer expression + // can be implicitly converted to an rvalue of type "cv3 T3" (this + // conversion is selected by enumerating the applicable conversion + // functions (13.3.1.6) and choosing the best one through overload + // resolution (13.3)), + if (RefRelationship == Sema::Ref_Incompatible) { + ConvOvlResult = TryRefInitWithConversionFunction(S, Entity, + Kind, Initializer, + /*AllowRValues=*/true, + Sequence); + if (ConvOvlResult) + Sequence.SetOverloadFailure( + InitializationSequence::FK_ReferenceInitOverloadFailed, + ConvOvlResult); + + return; + } + + Sequence.SetFailed(InitializationSequence::FK_ReferenceInitDropsQualifiers); + return; + } + + // - If the initializer expression is an rvalue, with T2 an array type, + // and "cv1 T1" is reference-compatible with "cv2 T2," the reference + // is bound to the object represented by the rvalue (see 3.10). + // FIXME: How can an array type be reference-compatible with anything? + // Don't we mean the element types of T1 and T2? + + // - Otherwise, a temporary of type “cv1 T1” is created and initialized + // from the initializer expression using the rules for a non-reference + // copy initialization (8.5). The reference is then bound to the + // temporary. [...] + // Determine whether we are allowed to call explicit constructors or + // explicit conversion operators. + bool AllowExplicit = (Kind.getKind() == InitializationKind::IK_Direct); + ImplicitConversionSequence ICS + = S.TryImplicitConversion(Initializer, cv1T1, + /*SuppressUserConversions=*/false, AllowExplicit, + /*ForceRValue=*/false, + /*FIXME:InOverloadResolution=*/false, + /*UserCast=*/Kind.isExplicitCast()); + + if (ICS.ConversionKind == ImplicitConversionSequence::BadConversion) { + // FIXME: Use the conversion function set stored in ICS to turn + // this into an overloading ambiguity diagnostic. However, we need + // to keep that set as an OverloadCandidateSet rather than as some + // other kind of set. + Sequence.SetFailed(InitializationSequence::FK_ReferenceInitFailed); + return; + } + + // [...] If T1 is reference-related to T2, cv1 must be the + // same cv-qualification as, or greater cv-qualification + // than, cv2; otherwise, the program is ill-formed. + if (RefRelationship == Sema::Ref_Related && + !cv1T1.isAtLeastAsQualifiedAs(cv2T2)) { + Sequence.SetFailed(InitializationSequence::FK_ReferenceInitDropsQualifiers); + return; + } + + // Perform the actual conversion. + Sequence.AddConversionSequenceStep(ICS, cv1T1); + Sequence.AddReferenceBindingStep(cv1T1, /*bindingTemporary=*/true); + return; +} + +/// \brief Attempt character array initialization from a string literal +/// (C++ [dcl.init.string], C99 6.7.8). +static void TryStringLiteralInitialization(Sema &S, + const InitializedEntity &Entity, + const InitializationKind &Kind, + Expr *Initializer, + InitializationSequence &Sequence) { + // FIXME: Implement! +} + +/// \brief Attempt initialization by constructor (C++ [dcl.init]), which +/// enumerates the constructors of the initialized entity and performs overload +/// resolution to select the best. +static void TryConstructorInitialization(Sema &S, + const InitializedEntity &Entity, + const InitializationKind &Kind, + Expr **Args, unsigned NumArgs, + QualType DestType, + InitializationSequence &Sequence) { + Sequence.setSequenceKind(InitializationSequence::ConstructorInitialization); + + // Build the candidate set directly in the initialization sequence + // structure, so that it will persist if we fail. + OverloadCandidateSet &CandidateSet = Sequence.getFailedCandidateSet(); + CandidateSet.clear(); + + // Determine whether we are allowed to call explicit constructors or + // explicit conversion operators. + bool AllowExplicit = (Kind.getKind() == InitializationKind::IK_Direct || + Kind.getKind() == InitializationKind::IK_Value || + Kind.getKind() == InitializationKind::IK_Default); + + // The type we're converting to is a class type. Enumerate its constructors + // to see if one is suitable. + const RecordType *DestRecordType = DestType->getAs(); + assert(DestRecordType && "Constructor initialization requires record type"); + CXXRecordDecl *DestRecordDecl + = cast(DestRecordType->getDecl()); + + DeclarationName ConstructorName + = S.Context.DeclarationNames.getCXXConstructorName( + S.Context.getCanonicalType(DestType).getUnqualifiedType()); + DeclContext::lookup_iterator Con, ConEnd; + for (llvm::tie(Con, ConEnd) = DestRecordDecl->lookup(ConstructorName); + Con != ConEnd; ++Con) { + // Find the constructor (which may be a template). + CXXConstructorDecl *Constructor = 0; + FunctionTemplateDecl *ConstructorTmpl + = dyn_cast(*Con); + if (ConstructorTmpl) + Constructor = cast( + ConstructorTmpl->getTemplatedDecl()); + else + Constructor = cast(*Con); + + if (!Constructor->isInvalidDecl() && + Constructor->isConvertingConstructor(AllowExplicit)) { + if (ConstructorTmpl) + S.AddTemplateOverloadCandidate(ConstructorTmpl, /*ExplicitArgs*/ 0, + Args, NumArgs, CandidateSet); + else + S.AddOverloadCandidate(Constructor, Args, NumArgs, CandidateSet); + } + } + + SourceLocation DeclLoc = Kind.getLocation(); + + // Perform overload resolution. If it fails, return the failed result. + OverloadCandidateSet::iterator Best; + if (OverloadingResult Result + = S.BestViableFunction(CandidateSet, DeclLoc, Best)) { + Sequence.SetOverloadFailure( + InitializationSequence::FK_ConstructorOverloadFailed, + Result); + return; + } + + // Add the constructor initialization step. Any cv-qualification conversion is + // subsumed by the initialization. + Sequence.AddConstructorInitializationStep( + cast(Best->Function), + DestType); +} + +/// \brief Attempt value initialization (C++ [dcl.init]p7). +static void TryValueInitialization(Sema &S, + const InitializedEntity &Entity, + const InitializationKind &Kind, + InitializationSequence &Sequence) { + // C++ [dcl.init]p5: + // + // To value-initialize an object of type T means: + QualType T = Entity.getType().getType(); + + // -- if T is an array type, then each element is value-initialized; + while (const ArrayType *AT = S.Context.getAsArrayType(T)) + T = AT->getElementType(); + + if (const RecordType *RT = T->getAs()) { + if (CXXRecordDecl *ClassDecl = dyn_cast(RT->getDecl())) { + // -- if T is a class type (clause 9) with a user-declared + // constructor (12.1), then the default constructor for T is + // called (and the initialization is ill-formed if T has no + // accessible default constructor); + // + // FIXME: we really want to refer to a single subobject of the array, + // but Entity doesn't have a way to capture that (yet). + if (ClassDecl->hasUserDeclaredConstructor()) + return TryConstructorInitialization(S, Entity, Kind, 0, 0, T, Sequence); + + // FIXME: non-union class type w/ non-trivial default constructor gets + // zero-initialized, then constructor gets called. + } + } + + Sequence.AddZeroInitializationStep(Entity.getType().getType()); + Sequence.setSequenceKind(InitializationSequence::ZeroInitialization); +} + +/// \brief Attempt a user-defined conversion between two types (C++ [dcl.init]), +/// which enumerates all conversion functions and performs overload resolution +/// to select the best. +static void TryUserDefinedConversion(Sema &S, + const InitializedEntity &Entity, + const InitializationKind &Kind, + Expr *Initializer, + InitializationSequence &Sequence) { + Sequence.setSequenceKind(InitializationSequence::UserDefinedConversion); + + QualType DestType = Entity.getType().getType(); + assert(!DestType->isReferenceType() && "References are handled elsewhere"); + QualType SourceType = Initializer->getType(); + assert((DestType->isRecordType() || SourceType->isRecordType()) && + "Must have a class type to perform a user-defined conversion"); + + // Build the candidate set directly in the initialization sequence + // structure, so that it will persist if we fail. + OverloadCandidateSet &CandidateSet = Sequence.getFailedCandidateSet(); + CandidateSet.clear(); + + // Determine whether we are allowed to call explicit constructors or + // explicit conversion operators. + bool AllowExplicit = Kind.getKind() == InitializationKind::IK_Direct; + + if (const RecordType *DestRecordType = DestType->getAs()) { + // The type we're converting to is a class type. Enumerate its constructors + // to see if there is a suitable conversion. + CXXRecordDecl *DestRecordDecl + = cast(DestRecordType->getDecl()); + + DeclarationName ConstructorName + = S.Context.DeclarationNames.getCXXConstructorName( + S.Context.getCanonicalType(DestType).getUnqualifiedType()); + DeclContext::lookup_iterator Con, ConEnd; + for (llvm::tie(Con, ConEnd) = DestRecordDecl->lookup(ConstructorName); + Con != ConEnd; ++Con) { + // Find the constructor (which may be a template). + CXXConstructorDecl *Constructor = 0; + FunctionTemplateDecl *ConstructorTmpl + = dyn_cast(*Con); + if (ConstructorTmpl) + Constructor = cast( + ConstructorTmpl->getTemplatedDecl()); + else + Constructor = cast(*Con); + + if (!Constructor->isInvalidDecl() && + Constructor->isConvertingConstructor(AllowExplicit)) { + if (ConstructorTmpl) + S.AddTemplateOverloadCandidate(ConstructorTmpl, /*ExplicitArgs*/ 0, + &Initializer, 1, CandidateSet); + else + S.AddOverloadCandidate(Constructor, &Initializer, 1, CandidateSet); + } + } + } + + if (const RecordType *SourceRecordType = SourceType->getAs()) { + // The type we're converting from is a class type, enumerate its conversion + // functions. + CXXRecordDecl *SourceRecordDecl + = cast(SourceRecordType->getDecl()); + + const UnresolvedSet *Conversions + = SourceRecordDecl->getVisibleConversionFunctions(); + for (UnresolvedSet::iterator I = Conversions->begin(), + E = Conversions->end(); + I != E; ++I) { + NamedDecl *D = *I; + CXXRecordDecl *ActingDC = cast(D->getDeclContext()); + if (isa(D)) + D = cast(D)->getTargetDecl(); + + FunctionTemplateDecl *ConvTemplate = dyn_cast(D); + CXXConversionDecl *Conv; + if (ConvTemplate) + Conv = cast(ConvTemplate->getTemplatedDecl()); + else + Conv = cast(*I); + + if (AllowExplicit || !Conv->isExplicit()) { + if (ConvTemplate) + S.AddTemplateConversionCandidate(ConvTemplate, ActingDC, Initializer, + DestType, CandidateSet); + else + S.AddConversionCandidate(Conv, ActingDC, Initializer, DestType, + CandidateSet); + } + } + } + + SourceLocation DeclLoc = Initializer->getLocStart(); + + // Perform overload resolution. If it fails, return the failed result. + OverloadCandidateSet::iterator Best; + if (OverloadingResult Result + = S.BestViableFunction(CandidateSet, DeclLoc, Best)) { + Sequence.SetOverloadFailure( + InitializationSequence::FK_UserConversionOverloadFailed, + Result); + return; + } + + FunctionDecl *Function = Best->Function; + + if (isa(Function)) { + // Add the user-defined conversion step. Any cv-qualification conversion is + // subsumed by the initialization. + Sequence.AddUserConversionStep(Function, DestType); + return; + } + + // Add the user-defined conversion step that calls the conversion function. + QualType ConvType = Function->getResultType().getNonReferenceType(); + Sequence.AddUserConversionStep(Function, ConvType); + + // If the conversion following the call to the conversion function is + // interesting, add it as a separate step. + if (Best->FinalConversion.First || Best->FinalConversion.Second || + Best->FinalConversion.Third) { + ImplicitConversionSequence ICS; + ICS.ConversionKind = ImplicitConversionSequence::StandardConversion; + ICS.Standard = Best->FinalConversion; + Sequence.AddConversionSequenceStep(ICS, DestType); + } +} + +/// \brief Attempt an implicit conversion (C++ [conv]) converting from one +/// non-class type to another. +static void TryImplicitConversion(Sema &S, + const InitializedEntity &Entity, + const InitializationKind &Kind, + Expr *Initializer, + InitializationSequence &Sequence) { + ImplicitConversionSequence ICS + = S.TryImplicitConversion(Initializer, Entity.getType().getType(), + /*SuppressUserConversions=*/true, + /*AllowExplicit=*/false, + /*ForceRValue=*/false, + /*FIXME:InOverloadResolution=*/false, + /*UserCast=*/Kind.isExplicitCast()); + + if (ICS.ConversionKind == ImplicitConversionSequence::BadConversion) { + Sequence.SetFailed(InitializationSequence::FK_ConversionFailed); + return; + } + + Sequence.AddConversionSequenceStep(ICS, Entity.getType().getType()); +} + +InitializationSequence::InitializationSequence(Sema &S, + const InitializedEntity &Entity, + const InitializationKind &Kind, + Expr **Args, + unsigned NumArgs) { + ASTContext &Context = S.Context; + + // C++0x [dcl.init]p16: + // The semantics of initializers are as follows. The destination type is + // the type of the object or reference being initialized and the source + // type is the type of the initializer expression. The source type is not + // defined when the initializer is a braced-init-list or when it is a + // parenthesized list of expressions. + QualType DestType = Entity.getType().getType(); + + if (DestType->isDependentType() || + Expr::hasAnyTypeDependentArguments(Args, NumArgs)) { + SequenceKind = DependentSequence; + return; + } + + QualType SourceType; + Expr *Initializer = 0; + if (Kind.getKind() == InitializationKind::IK_Copy) { + Initializer = Args[0]; + if (!isa(Initializer)) + SourceType = Initializer->getType(); + } + + // - If the initializer is a braced-init-list, the object is + // list-initialized (8.5.4). + if (InitListExpr *InitList = dyn_cast_or_null(Initializer)) { + TryListInitialization(S, Entity, Kind, InitList, *this); + return; + } + + // - If the destination type is a reference type, see 8.5.3. + if (DestType->isReferenceType()) { + // C++0x [dcl.init.ref]p1: + // A variable declared to be a T& or T&&, that is, "reference to type T" + // (8.3.2), shall be initialized by an object, or function, of type T or + // by an object that can be converted into a T. + // (Therefore, multiple arguments are not permitted.) + if (NumArgs != 1) + SetFailed(FK_TooManyInitsForReference); + else + TryReferenceInitialization(S, Entity, Kind, Args[0], *this); + return; + } + + // - If the destination type is an array of characters, an array of + // char16_t, an array of char32_t, or an array of wchar_t, and the + // initializer is a string literal, see 8.5.2. + if (Initializer && IsStringInit(Initializer, DestType, Context)) { + TryStringLiteralInitialization(S, Entity, Kind, Initializer, *this); + return; + } + + // - If the initializer is (), the object is value-initialized. + if (Kind.getKind() == InitializationKind::IK_Value) { + TryValueInitialization(S, Entity, Kind, *this); + return; + } + + // - Otherwise, if the destination type is an array, the program is + // ill-formed. + if (const ArrayType *AT = Context.getAsArrayType(DestType)) { + if (AT->getElementType()->isAnyCharacterType()) + SetFailed(FK_ArrayNeedsInitListOrStringLiteral); + else + SetFailed(FK_ArrayNeedsInitList); + + return; + } + + // - If the destination type is a (possibly cv-qualified) class type: + if (DestType->isRecordType()) { + // - If the initialization is direct-initialization, or if it is + // copy-initialization where the cv-unqualified version of the + // source type is the same class as, or a derived class of, the + // class of the destination, constructors are considered. [...] + if (Kind.getKind() == InitializationKind::IK_Direct || + (Kind.getKind() == InitializationKind::IK_Copy && + (Context.hasSameUnqualifiedType(SourceType, DestType) || + S.IsDerivedFrom(SourceType, DestType)))) + TryConstructorInitialization(S, Entity, Kind, Args, NumArgs, + Entity.getType().getType(), *this); + // - Otherwise (i.e., for the remaining copy-initialization cases), + // user-defined conversion sequences that can convert from the source + // type to the destination type or (when a conversion function is + // used) to a derived class thereof are enumerated as described in + // 13.3.1.4, and the best one is chosen through overload resolution + // (13.3). + else + TryUserDefinedConversion(S, Entity, Kind, Initializer, *this); + return; + } + + // - Otherwise, if the source type is a (possibly cv-qualified) class + // type, conversion functions are considered. + if (SourceType->isRecordType()) { + TryUserDefinedConversion(S, Entity, Kind, Initializer, *this); + return; + } + + // - Otherwise, the initial value of the object being initialized is the + // (possibly converted) value of the initializer expression. Standard + // conversions (Clause 4) will be used, if necessary, to convert the + // initializer expression to the cv-unqualified version of the + // destination type; no user-defined conversions are considered. + TryImplicitConversion(S, Entity, Kind, Initializer, *this); +} + +InitializationSequence::~InitializationSequence() { + for (llvm::SmallVectorImpl::iterator Step = Steps.begin(), + StepEnd = Steps.end(); + Step != StepEnd; ++Step) + Step->Destroy(); +} + +//===----------------------------------------------------------------------===// +// Perform initialization +//===----------------------------------------------------------------------===// + +Action::OwningExprResult +InitializationSequence::Perform(Sema &S, + const InitializedEntity &Entity, + const InitializationKind &Kind, + Action::MultiExprArg Args, + QualType *ResultType) { + if (SequenceKind == FailedSequence) { + unsigned NumArgs = Args.size(); + Diagnose(S, Entity, Kind, (Expr **)Args.release(), NumArgs); + return S.ExprError(); + } + + if (SequenceKind == DependentSequence) { + // If the declaration is a non-dependent, incomplete array type + // that has an initializer, then its type will be completed once + // the initializer is instantiated. + if (ResultType && !Entity.getType().getType()->isDependentType() && + Args.size() == 1) { + QualType DeclType = Entity.getType().getType(); + if (const IncompleteArrayType *ArrayT + = S.Context.getAsIncompleteArrayType(DeclType)) { + // FIXME: We don't currently have the ability to accurately + // compute the length of an initializer list without + // performing full type-checking of the initializer list + // (since we have to determine where braces are implicitly + // introduced and such). So, we fall back to making the array + // type a dependently-sized array type with no specified + // bound. + if (isa((Expr *)Args.get()[0])) { + SourceRange Brackets; + // Scavange the location of the brackets from the entity, if we can. + if (isa(Entity.getType())) { + IncompleteArrayTypeLoc ArrayLoc + = cast(Entity.getType()); + Brackets = ArrayLoc.getBracketsRange(); + } + + *ResultType + = S.Context.getDependentSizedArrayType(ArrayT->getElementType(), + /*NumElts=*/0, + ArrayT->getSizeModifier(), + ArrayT->getIndexTypeCVRQualifiers(), + Brackets); + } + + } + } + + if (Kind.getKind() == InitializationKind::IK_Copy) + return Sema::OwningExprResult(S, Args.release()[0]); + + unsigned NumArgs = Args.size(); + return S.Owned(new (S.Context) ParenListExpr(S.Context, + SourceLocation(), + (Expr **)Args.release(), + NumArgs, + SourceLocation())); + } + + QualType DestType = Entity.getType().getType().getNonReferenceType(); + if (ResultType) + *ResultType = Entity.getType().getType(); + + Sema::OwningExprResult CurInit(S); + // For copy initialization and any other initialization forms that + // only have a single initializer, we start with the (only) + // initializer we have. + // FIXME: DPG is not happy about this. There's confusion regarding whether + // we're supposed to start the conversion from the solitary initializer or + // from the set of arguments. + if (Kind.getKind() == InitializationKind::IK_Copy || + SequenceKind != ConstructorInitialization) { + assert(Args.size() == 1); + CurInit = Sema::OwningExprResult(S, Args.release()[0]); + if (CurInit.isInvalid()) + return S.ExprError(); + } + + // Walk through the computed steps for the initialization sequence, + // performing the specified conversions along the way. + for (step_iterator Step = step_begin(), StepEnd = step_end(); + Step != StepEnd; ++Step) { + if (CurInit.isInvalid()) + return S.ExprError(); + + Expr *CurInitExpr = (Expr *)CurInit.get(); + QualType SourceType = CurInitExpr->getType(); + + switch (Step->Kind) { + case SK_ResolveAddressOfOverloadedFunction: + // Overload resolution determined which function invoke; update the + // initializer to reflect that choice. + CurInit = S.FixOverloadedFunctionReference(move(CurInit), Step->Function); + break; + + case SK_CastDerivedToBaseRValue: + case SK_CastDerivedToBaseLValue: { + // We have a derived-to-base cast that produces either an rvalue or an + // lvalue. Perform that cast. + + // Casts to inaccessible base classes are allowed with C-style casts. + bool IgnoreBaseAccess = Kind.isCStyleOrFunctionalCast(); + if (S.CheckDerivedToBaseConversion(SourceType, Step->Type, + CurInitExpr->getLocStart(), + CurInitExpr->getSourceRange(), + IgnoreBaseAccess)) + return S.ExprError(); + + CurInit = S.Owned(new (S.Context) ImplicitCastExpr(Step->Type, + CastExpr::CK_DerivedToBase, + (Expr*)CurInit.release(), + Step->Kind == SK_CastDerivedToBaseLValue)); + break; + } + + case SK_BindReference: + if (FieldDecl *BitField = CurInitExpr->getBitField()) { + // References cannot bind to bit fields (C++ [dcl.init.ref]p5). + S.Diag(Kind.getLocation(), diag::err_reference_bind_to_bitfield) + << Entity.getType().getType().isVolatileQualified() + << BitField->getDeclName() + << CurInitExpr->getSourceRange(); + S.Diag(BitField->getLocation(), diag::note_bitfield_decl); + return S.ExprError(); + } + + // Reference binding does not have any corresponding ASTs. + + // Check exception specifications + if (S.CheckExceptionSpecCompatibility(CurInitExpr, DestType)) + return S.ExprError(); + break; + + case SK_BindReferenceToTemporary: + // Check exception specifications + if (S.CheckExceptionSpecCompatibility(CurInitExpr, DestType)) + return S.ExprError(); + + // FIXME: At present, we have no AST to describe when we need to make a + // temporary to bind a reference to. We should. + break; + + case SK_UserConversion: { + // We have a user-defined conversion that invokes either a constructor + // or a conversion function. + CastExpr::CastKind CastKind = CastExpr::CK_Unknown; + if (CXXConstructorDecl *Constructor + = dyn_cast(Step->Function)) { + // Build a call to the selected constructor. + ASTOwningVector<&ActionBase::DeleteExpr> ConstructorArgs(S); + SourceLocation Loc = CurInitExpr->getLocStart(); + CurInit.release(); // Ownership transferred into MultiExprArg, below. + + // Determine the arguments required to actually perform the constructor + // call. + if (S.CompleteConstructorCall(Constructor, + Sema::MultiExprArg(S, + (void **)&CurInitExpr, + 1), + Loc, ConstructorArgs)) + return S.ExprError(); + + // Build the an expression that constructs a temporary. + CurInit = S.BuildCXXConstructExpr(Loc, Step->Type, Constructor, + move_arg(ConstructorArgs)); + if (CurInit.isInvalid()) + return S.ExprError(); + + CastKind = CastExpr::CK_ConstructorConversion; + } else { + // Build a call to the conversion function. + CXXConversionDecl *Conversion = cast(Step->Function); + + // FIXME: Should we move this initialization into a separate + // derived-to-base conversion? I believe the answer is "no", because + // we don't want to turn off access control here for c-style casts. + if (S.PerformObjectArgumentInitialization(CurInitExpr, Conversion)) + return S.ExprError(); + + // Do a little dance to make sure that CurInit has the proper + // pointer. + CurInit.release(); + + // Build the actual call to the conversion function. + CurInit = S.Owned(S.BuildCXXMemberCallExpr(CurInitExpr, Conversion)); + if (CurInit.isInvalid() || !CurInit.get()) + return S.ExprError(); + + CastKind = CastExpr::CK_UserDefinedConversion; + } + + CurInit = S.MaybeBindToTemporary(CurInit.takeAs()); + CurInitExpr = CurInit.takeAs(); + CurInit = S.Owned(new (S.Context) ImplicitCastExpr(CurInitExpr->getType(), + CastKind, + CurInitExpr, + false)); + break; + } + + case SK_QualificationConversionLValue: + case SK_QualificationConversionRValue: + // Perform a qualification conversion; these can never go wrong. + S.ImpCastExprToType(CurInitExpr, Step->Type, + CastExpr::CK_NoOp, + Step->Kind == SK_QualificationConversionLValue); + CurInit.release(); + CurInit = S.Owned(CurInitExpr); + break; + + case SK_ConversionSequence: + if (S.PerformImplicitConversion(CurInitExpr, Step->Type, "converting", + false, false, *Step->ICS)) + return S.ExprError(); + + CurInit.release(); + CurInit = S.Owned(CurInitExpr); + break; + + case SK_ListInitialization: { + InitListExpr *InitList = cast(CurInitExpr); + QualType Ty = Step->Type; + if (S.CheckInitList(InitList, ResultType? *ResultType : Ty)) + return S.ExprError(); + + CurInit.release(); + CurInit = S.Owned(InitList); + break; + } + + case SK_ConstructorInitialization: { + CXXConstructorDecl *Constructor + = cast(Step->Function); + + // Build a call to the selected constructor. + ASTOwningVector<&ActionBase::DeleteExpr> ConstructorArgs(S); + SourceLocation Loc = Kind.getLocation(); + + // Determine the arguments required to actually perform the constructor + // call. + if (S.CompleteConstructorCall(Constructor, move(Args), + Loc, ConstructorArgs)) + return S.ExprError(); + + // Build the an expression that constructs a temporary. + CurInit = S.BuildCXXConstructExpr(Loc, Step->Type, Constructor, + move_arg(ConstructorArgs)); + if (CurInit.isInvalid()) + return S.ExprError(); + + CurInit = S.MaybeBindToTemporary(CurInit.takeAs()); + break; + } + + case SK_ZeroInitialization: { + if (Kind.getKind() == InitializationKind::IK_Value) + CurInit = S.Owned(new (S.Context) CXXZeroInitValueExpr(Step->Type, + Kind.getRange().getBegin(), + Kind.getRange().getEnd())); + else + CurInit = S.Owned(new (S.Context) ImplicitValueInitExpr(Step->Type)); + break; + } + } + } + + return move(CurInit); +} + +//===----------------------------------------------------------------------===// +// Diagnose initialization failures +//===----------------------------------------------------------------------===// +bool InitializationSequence::Diagnose(Sema &S, + const InitializedEntity &Entity, + const InitializationKind &Kind, + Expr **Args, unsigned NumArgs) { + if (SequenceKind != FailedSequence) + return false; + + QualType DestType = Entity.getType().getType(); + switch (Failure) { + case FK_TooManyInitsForReference: + S.Diag(Kind.getLocation(), diag::err_reference_has_multiple_inits) + << SourceRange(Args[0]->getLocStart(), Args[NumArgs - 1]->getLocEnd()); + break; + + case FK_ArrayNeedsInitList: + case FK_ArrayNeedsInitListOrStringLiteral: + S.Diag(Kind.getLocation(), diag::err_array_init_not_init_list) + << (Failure == FK_ArrayNeedsInitListOrStringLiteral); + break; + + case FK_AddressOfOverloadFailed: + S.ResolveAddressOfOverloadedFunction(Args[0], + DestType.getNonReferenceType(), + true); + break; + + case FK_ReferenceInitOverloadFailed: + case FK_UserConversionOverloadFailed: + switch (FailedOverloadResult) { + case OR_Ambiguous: + S.Diag(Kind.getLocation(), diag::err_typecheck_ambiguous_condition) + << Args[0]->getType() << DestType.getNonReferenceType() + << Args[0]->getSourceRange(); + S.PrintOverloadCandidates(FailedCandidateSet, true); + break; + + case OR_No_Viable_Function: + S.Diag(Kind.getLocation(), diag::err_typecheck_nonviable_condition) + << Args[0]->getType() << DestType.getNonReferenceType() + << Args[0]->getSourceRange(); + S.PrintOverloadCandidates(FailedCandidateSet, false); + break; + + case OR_Deleted: { + S.Diag(Kind.getLocation(), diag::err_typecheck_deleted_function) + << Args[0]->getType() << DestType.getNonReferenceType() + << Args[0]->getSourceRange(); + OverloadCandidateSet::iterator Best; + OverloadingResult Ovl = S.BestViableFunction(FailedCandidateSet, + Kind.getLocation(), + Best); + if (Ovl == OR_Deleted) { + S.Diag(Best->Function->getLocation(), diag::note_unavailable_here) + << Best->Function->isDeleted(); + } else { + llvm_unreachable("Inconsistent overload resolution?"); + } + break; + } + + case OR_Success: + llvm_unreachable("Conversion did not fail!"); + break; + } + break; + + case FK_NonConstLValueReferenceBindingToTemporary: + case FK_NonConstLValueReferenceBindingToUnrelated: + S.Diag(Kind.getLocation(), + Failure == FK_NonConstLValueReferenceBindingToTemporary + ? diag::err_lvalue_reference_bind_to_temporary + : diag::err_lvalue_reference_bind_to_unrelated) + << DestType.getNonReferenceType() + << Args[0]->getType() + << Args[0]->getSourceRange(); + break; + + case FK_RValueReferenceBindingToLValue: + S.Diag(Kind.getLocation(), diag::err_lvalue_to_rvalue_ref) + << Args[0]->getSourceRange(); + break; + + case FK_ReferenceInitDropsQualifiers: + S.Diag(Kind.getLocation(), diag::err_reference_bind_drops_quals) + << DestType.getNonReferenceType() + << Args[0]->getType() + << Args[0]->getSourceRange(); + break; + + case FK_ReferenceInitFailed: + S.Diag(Kind.getLocation(), diag::err_reference_bind_failed) + << DestType.getNonReferenceType() + << (Args[0]->isLvalue(S.Context) == Expr::LV_Valid) + << Args[0]->getType() + << Args[0]->getSourceRange(); + break; + + case FK_ConversionFailed: + S.Diag(Kind.getLocation(), diag::err_cannot_initialize_decl_noname) + << DestType + << (Args[0]->isLvalue(S.Context) == Expr::LV_Valid) + << Args[0]->getType() + << Args[0]->getSourceRange(); + break; + + case FK_TooManyInitsForScalar: { + InitListExpr *InitList = cast(Args[0]); + + S.Diag(Kind.getLocation(), diag::err_excess_initializers) + << /*scalar=*/2 + << SourceRange(InitList->getInit(1)->getLocStart(), + InitList->getLocEnd()); + break; + } + + case FK_ReferenceBindingToInitList: + S.Diag(Kind.getLocation(), diag::err_reference_bind_init_list) + << DestType.getNonReferenceType() << Args[0]->getSourceRange(); + break; + + case FK_InitListBadDestinationType: + S.Diag(Kind.getLocation(), diag::err_init_list_bad_dest_type) + << (DestType->isRecordType()) << DestType << Args[0]->getSourceRange(); + break; + + case FK_ConstructorOverloadFailed: { + SourceRange ArgsRange; + if (NumArgs) + ArgsRange = SourceRange(Args[0]->getLocStart(), + Args[NumArgs - 1]->getLocEnd()); + + // FIXME: Using "DestType" for the entity we're printing is probably + // bad. + switch (FailedOverloadResult) { + case OR_Ambiguous: + S.Diag(Kind.getLocation(), diag::err_ovl_ambiguous_init) + << DestType << ArgsRange; + S.PrintOverloadCandidates(FailedCandidateSet, true); + break; + + case OR_No_Viable_Function: + S.Diag(Kind.getLocation(), diag::err_ovl_no_viable_function_in_init) + << DestType << ArgsRange; + S.PrintOverloadCandidates(FailedCandidateSet, false); + break; + + case OR_Deleted: { + S.Diag(Kind.getLocation(), diag::err_ovl_deleted_init) + << true << DestType << ArgsRange; + OverloadCandidateSet::iterator Best; + OverloadingResult Ovl = S.BestViableFunction(FailedCandidateSet, + Kind.getLocation(), + Best); + if (Ovl == OR_Deleted) { + S.Diag(Best->Function->getLocation(), diag::note_unavailable_here) + << Best->Function->isDeleted(); + } else { + llvm_unreachable("Inconsistent overload resolution?"); + } + break; + } + + case OR_Success: + llvm_unreachable("Conversion did not fail!"); + break; + } + break; + } + } + + return true; +} diff --git a/lib/Sema/SemaInit.h b/lib/Sema/SemaInit.h new file mode 100644 index 000000000000..2d4b01f26b0d --- /dev/null +++ b/lib/Sema/SemaInit.h @@ -0,0 +1,579 @@ +//===--- SemaInit.h - Semantic Analysis for Initializers --------*- C++ -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// +// This file provides supporting data types for initialization of objects. +// +//===----------------------------------------------------------------------===// +#ifndef LLVM_CLANG_SEMA_INIT_H +#define LLVM_CLANG_SEMA_INIT_H + +#include "SemaOverload.h" +#include "clang/AST/TypeLoc.h" +#include "clang/Parse/Action.h" +#include "clang/Basic/SourceLocation.h" +#include "llvm/ADT/PointerIntPair.h" +#include "llvm/ADT/SmallVector.h" +#include + +namespace clang { + +class CXXBaseSpecifier; +class DeclaratorDecl; +class DeclaratorInfo; +class FieldDecl; +class FunctionDecl; +class ParmVarDecl; +class Sema; +class TypeLoc; +class VarDecl; + +/// \brief Describes an entity that is being initialized. +class InitializedEntity { +public: + /// \brief Specifies the kind of entity being initialized. + enum EntityKind { + /// \brief The entity being initialized is a variable. + EK_Variable, + /// \brief The entity being initialized is a function parameter. + EK_Parameter, + /// \brief The entity being initialized is the result of a function call. + EK_Result, + /// \brief The entity being initialized is an exception object that + /// is being thrown. + EK_Exception, + /// \brief The entity being initialized is a temporary object. + 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 + }; + +private: + /// \brief The kind of entity being initialized. + EntityKind Kind; + + /// \brief The type of the object or reference being initialized along with + /// its location information. + TypeLoc TL; + + union { + /// \brief When Kind == EK_Variable, EK_Parameter, or EK_Member, + /// the VarDecl, ParmVarDecl, or FieldDecl, respectively. + DeclaratorDecl *VariableOrMember; + + /// \brief When Kind == EK_Result or EK_Exception, the location of the + /// 'return' or 'throw' keyword, respectively. When Kind == EK_Temporary, + /// the location where the temporary is being created. + unsigned Location; + + /// \brief When Kind == EK_Base, the base specifier that provides the + /// base class. + CXXBaseSpecifier *Base; + }; + + InitializedEntity() { } + + /// \brief Create the initialization entity for a variable. + InitializedEntity(VarDecl *Var) + : Kind(EK_Variable), + VariableOrMember(reinterpret_cast(Var)) + { + InitDeclLoc(); + } + + /// \brief Create the initialization entity for a parameter. + InitializedEntity(ParmVarDecl *Parm) + : Kind(EK_Parameter), + VariableOrMember(reinterpret_cast(Parm)) + { + InitDeclLoc(); + } + + /// \brief Create the initialization entity for the result of a function, + /// throwing an object, or performing an explicit cast. + InitializedEntity(EntityKind Kind, SourceLocation Loc, TypeLoc TL) + : Kind(Kind), TL(TL), Location(Loc.getRawEncoding()) { } + + /// \brief Create the initialization entity for a member subobject. + InitializedEntity(FieldDecl *Member) + : Kind(EK_Member), + VariableOrMember(reinterpret_cast(Member)) + { + InitDeclLoc(); + } + + /// \brief Initialize type-location information from a declaration. + void InitDeclLoc(); + +public: + /// \brief Create the initialization entity for a variable. + static InitializedEntity InitializeVariable(VarDecl *Var) { + return InitializedEntity(Var); + } + + /// \brief Create the initialization entity for a parameter. + static InitializedEntity InitializeParameter(ParmVarDecl *Parm) { + return InitializedEntity(Parm); + } + + /// \brief Create the initialization entity for the result of a function. + static InitializedEntity InitializeResult(SourceLocation ReturnLoc, + TypeLoc TL) { + return InitializedEntity(EK_Result, ReturnLoc, TL); + } + + /// \brief Create the initialization entity for an exception object. + static InitializedEntity InitializeException(SourceLocation ThrowLoc, + TypeLoc TL) { + return InitializedEntity(EK_Exception, ThrowLoc, TL); + } + + /// \brief Create the initialization entity for a temporary. + static InitializedEntity InitializeTemporary(EntityKind Kind, TypeLoc TL) { + return InitializedEntity(Kind, SourceLocation(), TL); + } + + /// \brief Create the initialization entity for a base class subobject. + static InitializedEntity InitializeBase(ASTContext &Context, + CXXBaseSpecifier *Base); + + /// \brief Create the initialize entity for a member subobject. + static InitializedEntity InitializeMember(FieldDecl *Member) { + return InitializedEntity(Member); + } + + /// \brief Determine the kind of initialization. + EntityKind getKind() const { return Kind; } + + /// \brief Retrieve type being initialized. + TypeLoc getType() const { return TL; } + + /// \brief Determine the location of the 'return' keyword when initializing + /// the result of a function call. + SourceLocation getReturnLoc() const { + assert(getKind() == EK_Result && "No 'return' location!"); + return SourceLocation::getFromRawEncoding(Location); + } + + /// \brief Determine the location of the 'throw' keyword when initializing + /// an exception object. + SourceLocation getThrowLoc() const { + assert(getKind() == EK_Exception && "No 'throw' location!"); + return SourceLocation::getFromRawEncoding(Location); + } +}; + +/// \brief Describes the kind of initialization being performed, along with +/// location information for tokens related to the initialization (equal sign, +/// parentheses). +class InitializationKind { +public: + /// \brief The kind of initialization being performed. + enum InitKind { + IK_Direct, ///< Direct initialization + IK_Copy, ///< Copy initialization + IK_Default, ///< Default initialization + IK_Value ///< Value initialization + }; + +private: + /// \brief The kind of initialization that we're storing. + enum StoredInitKind { + SIK_Direct = IK_Direct, ///< Direct initialization + SIK_Copy = IK_Copy, ///< Copy initialization + SIK_Default = IK_Default, ///< Default initialization + SIK_Value = IK_Value, ///< Value initialization + SIK_DirectCast, ///< Direct initialization due to a cast + /// \brief Direct initialization due to a C-style or functional cast. + SIK_DirectCStyleOrFunctionalCast + }; + + /// \brief The kind of initialization being performed. + StoredInitKind Kind; + + /// \brief The source locations involved in the initialization. + SourceLocation Locations[3]; + + InitializationKind(StoredInitKind Kind, SourceLocation Loc1, + SourceLocation Loc2, SourceLocation Loc3) + : Kind(Kind) + { + Locations[0] = Loc1; + Locations[1] = Loc2; + Locations[2] = Loc3; + } + +public: + /// \brief Create a direct initialization. + static InitializationKind CreateDirect(SourceLocation InitLoc, + SourceLocation LParenLoc, + SourceLocation RParenLoc) { + return InitializationKind(SIK_Direct, InitLoc, LParenLoc, RParenLoc); + } + + /// \brief Create a direct initialization due to a cast. + static InitializationKind CreateCast(SourceRange TypeRange, + bool IsCStyleCast) { + return InitializationKind(IsCStyleCast? SIK_DirectCStyleOrFunctionalCast + : SIK_DirectCast, + TypeRange.getBegin(), TypeRange.getBegin(), + TypeRange.getEnd()); + } + + /// \brief Create a copy initialization. + static InitializationKind CreateCopy(SourceLocation InitLoc, + SourceLocation EqualLoc) { + return InitializationKind(SIK_Copy, InitLoc, EqualLoc, EqualLoc); + } + + /// \brief Create a default initialization. + static InitializationKind CreateDefault(SourceLocation InitLoc) { + return InitializationKind(SIK_Default, InitLoc, InitLoc, InitLoc); + } + + /// \brief Create a value initialization. + static InitializationKind CreateValue(SourceLocation InitLoc, + SourceLocation LParenLoc, + SourceLocation RParenLoc) { + return InitializationKind(SIK_Value, InitLoc, LParenLoc, RParenLoc); + } + + /// \brief Determine the initialization kind. + InitKind getKind() const { + if (Kind > SIK_Value) + return IK_Direct; + + return (InitKind)Kind; + } + + /// \brief Determine whether this initialization is an explicit cast. + bool isExplicitCast() const { + return Kind == SIK_DirectCast || Kind == SIK_DirectCStyleOrFunctionalCast; + } + + /// \brief Determine whether this initialization is a C-style cast. + bool isCStyleOrFunctionalCast() const { + return Kind == SIK_DirectCStyleOrFunctionalCast; + } + + /// \brief Retrieve the location at which initialization is occurring. + SourceLocation getLocation() const { return Locations[0]; } + + /// \brief Retrieve the source range that covers the initialization. + SourceRange getRange() const { + return SourceRange(Locations[0], Locations[2]); + } + + /// \brief Retrieve the location of the equal sign for copy initialization + /// (if present). + SourceLocation getEqualLoc() const { + assert(Kind == SIK_Copy && "Only copy initialization has an '='"); + return Locations[1]; + } + + /// \brief Retrieve the source range containing the locations of the open + /// and closing parentheses for value and direct initializations. + SourceRange getParenRange() const { + assert((getKind() == IK_Direct || Kind == SIK_Value) && + "Only direct- and value-initialization have parentheses"); + return SourceRange(Locations[1], Locations[2]); + } +}; + +/// \brief Describes the sequence of initializations required to initialize +/// a given object or reference with a set of arguments. +class InitializationSequence { +public: + /// \brief Describes the kind of initialization sequence computed. + /// + /// FIXME: Much of this information is in the initialization steps... why is + /// it duplicated here? + enum SequenceKind { + /// \brief A failed initialization sequence. The failure kind tells what + /// happened. + FailedSequence = 0, + + /// \brief A dependent initialization, which could not be + /// type-checked due to the presence of dependent types or + /// dependently-type expressions. + DependentSequence, + + /// \brief A user-defined conversion sequence. + UserDefinedConversion, + + /// \brief A constructor call. + ConstructorInitialization, + + /// \brief A reference binding. + ReferenceBinding, + + /// \brief List initialization + ListInitialization, + + /// \brief Zero-initialization. + ZeroInitialization + }; + + /// \brief Describes the kind of a particular step in an initialization + /// sequence. + enum StepKind { + /// \brief Resolve the address of an overloaded function to a specific + /// function declaration. + SK_ResolveAddressOfOverloadedFunction, + /// \brief Perform a derived-to-base cast, producing an rvalue. + SK_CastDerivedToBaseRValue, + /// \brief Perform a derived-to-base cast, producing an lvalue. + SK_CastDerivedToBaseLValue, + /// \brief Reference binding to an lvalue. + SK_BindReference, + /// \brief Reference binding to a temporary. + SK_BindReferenceToTemporary, + /// \brief Perform a user-defined conversion, either via a conversion + /// function or via a constructor. + SK_UserConversion, + /// \brief Perform a qualification conversion, producing an rvalue. + SK_QualificationConversionRValue, + /// \brief Perform a qualification conversion, producing an lvalue. + SK_QualificationConversionLValue, + /// \brief Perform an implicit conversion sequence. + SK_ConversionSequence, + /// \brief Perform list-initialization + SK_ListInitialization, + /// \brief Perform initialization via a constructor. + SK_ConstructorInitialization, + /// \brief Zero-initialize the object + SK_ZeroInitialization + }; + + /// \brief A single step in the initialization sequence. + class Step { + public: + /// \brief The kind of conversion or initialization step we are taking. + StepKind Kind; + + // \brief The type that results from this initialization. + QualType Type; + + union { + /// \brief When Kind == SK_ResolvedOverloadedFunction or Kind == + /// SK_UserConversion, the function that the expression should be + /// resolved to or the conversion function to call, respectively. + FunctionDecl *Function; + + /// \brief When Kind = SK_ConversionSequence, the implicit conversion + /// sequence + ImplicitConversionSequence *ICS; + }; + + void Destroy(); + }; + +private: + /// \brief The kind of initialization sequence computed. + enum SequenceKind SequenceKind; + + /// \brief Steps taken by this initialization. + llvm::SmallVector Steps; + +public: + /// \brief Describes why initialization failed. + enum FailureKind { + /// \brief Too many initializers provided for a reference. + FK_TooManyInitsForReference, + /// \brief Array must be initialized with an initializer list. + FK_ArrayNeedsInitList, + /// \brief Array must be initialized with an initializer list or a + /// string literal. + FK_ArrayNeedsInitListOrStringLiteral, + /// \brief Cannot resolve the address of an overloaded function. + FK_AddressOfOverloadFailed, + /// \brief Overloading due to reference initialization failed. + FK_ReferenceInitOverloadFailed, + /// \brief Non-const lvalue reference binding to a temporary. + FK_NonConstLValueReferenceBindingToTemporary, + /// \brief Non-const lvalue reference binding to an lvalue of unrelated + /// type. + FK_NonConstLValueReferenceBindingToUnrelated, + /// \brief Rvalue reference binding to an lvalue. + FK_RValueReferenceBindingToLValue, + /// \brief Reference binding drops qualifiers. + FK_ReferenceInitDropsQualifiers, + /// \brief Reference binding failed. + FK_ReferenceInitFailed, + /// \brief Implicit conversion failed. + FK_ConversionFailed, + /// \brief Too many initializers for scalar + FK_TooManyInitsForScalar, + /// \brief Reference initialization from an initializer list + FK_ReferenceBindingToInitList, + /// \brief Initialization of some unused destination type with an + /// initializer list. + FK_InitListBadDestinationType, + /// \brief Overloading for a user-defined conversion failed. + FK_UserConversionOverloadFailed, + /// \brief Overloaded for initialization by constructor failed. + FK_ConstructorOverloadFailed + }; + +private: + /// \brief The reason why initialization failued. + FailureKind Failure; + + /// \brief The failed result of overload resolution. + OverloadingResult FailedOverloadResult; + + /// \brief The candidate set created when initialization failed. + OverloadCandidateSet FailedCandidateSet; + +public: + /// \brief Try to perform initialization of the given entity, creating a + /// record of the steps required to perform the initialization. + /// + /// The generated initialization sequence will either contain enough + /// information to diagnose + /// + /// \param S the semantic analysis object. + /// + /// \param Entity the entity being initialized. + /// + /// \param Kind the kind of initialization being performed. + /// + /// \param Args the argument(s) provided for initialization. + /// + /// \param NumArgs the number of arguments provided for initialization. + InitializationSequence(Sema &S, + const InitializedEntity &Entity, + const InitializationKind &Kind, + Expr **Args, + unsigned NumArgs); + + ~InitializationSequence(); + + /// \brief Perform the actual initialization of the given entity based on + /// the computed initialization sequence. + /// + /// \param S the semantic analysis object. + /// + /// \param Entity the entity being initialized. + /// + /// \param Kind the kind of initialization being performed. + /// + /// \param Args the argument(s) provided for initialization, ownership of + /// which is transfered into the routine. + /// + /// \param ResultType if non-NULL, will be set to the type of the + /// initialized object, which is the type of the declaration in most + /// cases. However, when the initialized object is a variable of + /// incomplete array type and the initializer is an initializer + /// list, this type will be set to the completed array type. + /// + /// \returns an expression that performs the actual object initialization, if + /// the initialization is well-formed. Otherwise, emits diagnostics + /// and returns an invalid expression. + Action::OwningExprResult Perform(Sema &S, + const InitializedEntity &Entity, + const InitializationKind &Kind, + Action::MultiExprArg Args, + QualType *ResultType = 0); + + /// \brief Diagnose an potentially-invalid initialization sequence. + /// + /// \returns true if the initialization sequence was ill-formed, + /// false otherwise. + bool Diagnose(Sema &S, + const InitializedEntity &Entity, + const InitializationKind &Kind, + Expr **Args, unsigned NumArgs); + + /// \brief Determine the kind of initialization sequence computed. + enum SequenceKind getKind() const { return SequenceKind; } + + /// \brief Set the kind of sequence computed. + void setSequenceKind(enum SequenceKind SK) { SequenceKind = SK; } + + /// \brief Determine whether the initialization sequence is valid. + operator bool() const { return SequenceKind != FailedSequence; } + + typedef llvm::SmallVector::const_iterator step_iterator; + step_iterator step_begin() const { return Steps.begin(); } + step_iterator step_end() const { return Steps.end(); } + + /// \brief Add a new step in the initialization that resolves the address + /// of an overloaded function to a specific function declaration. + /// + /// \param Function the function to which the overloaded function reference + /// resolves. + void AddAddressOverloadResolutionStep(FunctionDecl *Function); + + /// \brief Add a new step in the initialization that performs a derived-to- + /// base cast. + /// + /// \param BaseType the base type to which we will be casting. + /// + /// \param IsLValue true if the result of this cast will be treated as + /// an lvalue. + void AddDerivedToBaseCastStep(QualType BaseType, bool IsLValue); + + /// \brief Add a new step binding a reference to an object. + /// + /// \param BindingTemporary true if we are binding a reference to a temporary + /// object (thereby extending its lifetime); false if we are binding to an + /// lvalue or an lvalue treated as an rvalue. + void AddReferenceBindingStep(QualType T, bool BindingTemporary); + + /// \brief Add a new step invoking a conversion function, which is either + /// a constructor or a conversion function. + void AddUserConversionStep(FunctionDecl *Function, QualType T); + + /// \brief Add a new step that performs a qualification conversion to the + /// given type. + void AddQualificationConversionStep(QualType Ty, bool IsLValue); + + /// \brief Add a new step that applies an implicit conversion sequence. + void AddConversionSequenceStep(const ImplicitConversionSequence &ICS, + QualType T); + + /// \brief Add a list-initialiation step + void AddListInitializationStep(QualType T); + + /// \brief Add a constructor-initialization step. + void AddConstructorInitializationStep(CXXConstructorDecl *Constructor, + QualType T); + + /// \brief Add a zero-initialization step. + void AddZeroInitializationStep(QualType T); + + /// \brief Note that this initialization sequence failed. + void SetFailed(FailureKind Failure) { + SequenceKind = FailedSequence; + this->Failure = Failure; + } + + /// \brief Note that this initialization sequence failed due to failed + /// overload resolution. + void SetOverloadFailure(FailureKind Failure, OverloadingResult Result); + + /// \brief Retrieve a reference to the candidate set when overload + /// resolution fails. + OverloadCandidateSet &getFailedCandidateSet() { + return FailedCandidateSet; + } + + /// \brief Determine why initialization failed. + FailureKind getFailureKind() const { + assert(getKind() == FailedSequence && "Not an initialization failure!"); + return Failure; + } +}; + +} // end namespace clang + +#endif // LLVM_CLANG_SEMA_INIT_H diff --git a/lib/Sema/SemaLookup.cpp b/lib/Sema/SemaLookup.cpp index 8f0982740d4a..724e2fc1e4f5 100644 --- a/lib/Sema/SemaLookup.cpp +++ b/lib/Sema/SemaLookup.cpp @@ -222,6 +222,11 @@ getIdentifierNamespacesFromLookupNameKind(Sema::LookupNameKind NameKind, IDNS = Decl::IDNS_Ordinary | Decl::IDNS_Tag | Decl::IDNS_Member; break; + case Sema::LookupUsingDeclName: + IDNS = Decl::IDNS_Ordinary | Decl::IDNS_Tag + | Decl::IDNS_Member | Decl::IDNS_Using; + break; + case Sema::LookupObjCProtocolName: IDNS = Decl::IDNS_ObjCProtocol; break; @@ -229,10 +234,6 @@ getIdentifierNamespacesFromLookupNameKind(Sema::LookupNameKind NameKind, case Sema::LookupObjCImplementationName: IDNS = Decl::IDNS_ObjCImplementation; break; - - case Sema::LookupObjCCategoryImplName: - IDNS = Decl::IDNS_ObjCCategoryImpl; - break; } return IDNS; } @@ -245,7 +246,7 @@ void LookupResult::deletePaths(CXXBasePaths *Paths) { /// Resolves the result kind of this lookup. void LookupResult::resolveKind() { unsigned N = Decls.size(); - + // Fast case: no possible ambiguity. if (N == 0) { assert(ResultKind == NotFound); @@ -282,9 +283,6 @@ void LookupResult::resolveKind() { // If it's not unique, pull something off the back (and // continue at this index). Decls[I] = Decls[--N]; - } else if (isa(D)) { - // FIXME: support unresolved using value declarations - Decls[I] = Decls[--N]; } else { // Otherwise, do some decl type analysis and then continue. @@ -318,13 +316,13 @@ void LookupResult::resolveKind() { // wherever the object, function, or enumerator name is visible. // But it's still an error if there are distinct tag types found, // even if they're not visible. (ref?) - if (HideTags && HasTag && !Ambiguous && !HasUnresolved && - (HasFunction || HasNonFunction)) + if (HideTags && HasTag && !Ambiguous && + (HasFunction || HasNonFunction || HasUnresolved)) Decls[UniqueTagIndex] = Decls[--N]; Decls.set_size(N); - if (HasFunction && HasNonFunction) + if (HasNonFunction && (HasFunction || HasUnresolved)) Ambiguous = true; if (Ambiguous) @@ -337,44 +335,6 @@ void LookupResult::resolveKind() { ResultKind = LookupResult::Found; } -/// @brief Converts the result of name lookup into a single (possible -/// NULL) pointer to a declaration. -/// -/// The resulting declaration will either be the declaration we found -/// (if only a single declaration was found), an -/// OverloadedFunctionDecl (if an overloaded function was found), or -/// NULL (if no declaration was found). This conversion must not be -/// used anywhere where name lookup could result in an ambiguity. -/// -/// The OverloadedFunctionDecl conversion is meant as a stop-gap -/// solution, since it causes the OverloadedFunctionDecl to be -/// leaked. FIXME: Eventually, there will be a better way to iterate -/// over the set of overloaded functions returned by name lookup. -NamedDecl *LookupResult::getAsSingleDecl(ASTContext &C) const { - size_t size = Decls.size(); - if (size == 0) return 0; - if (size == 1) return (*begin())->getUnderlyingDecl(); - - if (isAmbiguous()) return 0; - - iterator I = begin(), E = end(); - - OverloadedFunctionDecl *Ovl - = OverloadedFunctionDecl::Create(C, (*I)->getDeclContext(), - (*I)->getDeclName()); - for (; I != E; ++I) { - NamedDecl *ND = (*I)->getUnderlyingDecl(); - assert(ND->isFunctionOrFunctionTemplate()); - if (isa(ND)) - Ovl->addOverload(cast(ND)); - else - Ovl->addOverload(cast(ND)); - // FIXME: UnresolvedUsingDecls. - } - - return Ovl; -} - void LookupResult::addDeclsFromBasePaths(const CXXBasePaths &P) { CXXBasePaths::paths_iterator I, E; DeclContext::lookup_iterator DI, DE; @@ -521,7 +481,12 @@ bool Sema::CppLookupName(LookupResult &R, Scope *S) { DeclContext *OuterCtx = findOuterContext(S); for (; Ctx && Ctx->getPrimaryContext() != OuterCtx; Ctx = Ctx->getLookupParent()) { - if (Ctx->isFunctionOrMethod()) + // We do not directly look into function or method contexts + // (since all local variables are found via the identifier + // changes) or in transparent contexts (since those entities + // will be found in the nearest enclosing non-transparent + // context). + if (Ctx->isFunctionOrMethod() || Ctx->isTransparentContext()) continue; // Perform qualified name lookup into this context. @@ -649,6 +614,7 @@ bool Sema::LookupName(LookupResult &R, Scope *S, bool AllowBuiltinCreation) { case Sema::LookupOperatorName: case Sema::LookupNestedNameSpecifierName: case Sema::LookupNamespaceName: + case Sema::LookupUsingDeclName: assert(false && "C does not perform these kinds of name lookup"); break; @@ -670,9 +636,6 @@ bool Sema::LookupName(LookupResult &R, Scope *S, bool AllowBuiltinCreation) { IDNS = Decl::IDNS_ObjCImplementation; break; - case Sema::LookupObjCCategoryImplName: - IDNS = Decl::IDNS_ObjCCategoryImpl; - break; } // Scan up the scope chain looking for a decl that matches this @@ -964,12 +927,14 @@ bool Sema::LookupQualifiedName(LookupResult &R, DeclContext *LookupCtx) { case LookupTagName: BaseCallback = &CXXRecordDecl::FindTagMember; break; + + case LookupUsingDeclName: + // This lookup is for redeclarations only. case LookupOperatorName: case LookupNamespaceName: case LookupObjCProtocolName: case LookupObjCImplementationName: - case LookupObjCCategoryImplName: // These lookups will never find a member in a C++ class (or base class). return false; @@ -1202,7 +1167,7 @@ bool Sema::DiagnoseAmbiguousLookup(LookupResult &Result) { } } - llvm::llvm_unreachable("unknown ambiguity kind"); + llvm_unreachable("unknown ambiguity kind"); return true; } @@ -1610,7 +1575,7 @@ NamedDecl *Sema::LookupSingleName(Scope *S, DeclarationName Name, RedeclarationKind Redecl) { LookupResult R(*this, Name, SourceLocation(), NameKind, Redecl); LookupName(R, S); - return R.getAsSingleDecl(Context); + return R.getAsSingle(); } /// \brief Find the protocol with the given name, if any. @@ -1619,13 +1584,6 @@ ObjCProtocolDecl *Sema::LookupProtocol(IdentifierInfo *II) { return cast_or_null(D); } -/// \brief Find the Objective-C category implementation with the given -/// name, if any. -ObjCCategoryImplDecl *Sema::LookupObjCCategoryImpl(IdentifierInfo *II) { - Decl *D = LookupSingleName(TUScope, II, LookupObjCCategoryImplName); - return cast_or_null(D); -} - void Sema::LookupOverloadedOperatorName(OverloadedOperatorKind Op, Scope *S, QualType T1, QualType T2, FunctionSet &Functions) { diff --git a/lib/Sema/SemaOverload.cpp b/lib/Sema/SemaOverload.cpp index 6ea6a145576d..561cfdb52e0b 100644 --- a/lib/Sema/SemaOverload.cpp +++ b/lib/Sema/SemaOverload.cpp @@ -38,6 +38,7 @@ GetConversionCategory(ImplicitConversionKind Kind) { ICC_Lvalue_Transformation, ICC_Lvalue_Transformation, ICC_Lvalue_Transformation, + ICC_Identity, ICC_Qualification_Adjustment, ICC_Promotion, ICC_Promotion, @@ -66,6 +67,7 @@ ImplicitConversionRank GetConversionRank(ImplicitConversionKind Kind) { ICR_Exact_Match, ICR_Exact_Match, ICR_Exact_Match, + ICR_Exact_Match, ICR_Promotion, ICR_Promotion, ICR_Promotion, @@ -91,6 +93,7 @@ const char* GetImplicitConversionName(ImplicitConversionKind Kind) { "Lvalue-to-rvalue", "Array-to-pointer", "Function-to-pointer", + "Noreturn adjustment", "Qualification", "Integral promotion", "Floating point promotion", @@ -172,7 +175,7 @@ isPointerConversionToVoidPointer(ASTContext& Context) const { if (First == ICK_Array_To_Pointer) FromType = Context.getArrayDecayedType(FromType); - if (Second == ICK_Pointer_Conversion) + if (Second == ICK_Pointer_Conversion && FromType->isPointerType()) if (const PointerType* ToPtrType = ToType->getAs()) return ToPtrType->getPointeeType()->isVoidType(); @@ -255,12 +258,13 @@ void ImplicitConversionSequence::DebugPrint() const { } // IsOverload - Determine whether the given New declaration is an -// overload of the Old declaration. This routine returns false if New -// and Old cannot be overloaded, e.g., if they are functions with the -// same signature (C++ 1.3.10) or if the Old declaration isn't a -// function (or overload set). When it does return false and Old is an -// OverloadedFunctionDecl, MatchedDecl will be set to point to the -// FunctionDecl that New cannot be overloaded with. +// overload of the declarations in Old. This routine returns false if +// New and Old cannot be overloaded, e.g., if New has the same +// signature as some function in Old (C++ 1.3.10) or if the Old +// declarations aren't functions (or function templates) at all. When +// it does return false, MatchedDecl will point to the decl that New +// cannot be overloaded with. This decl may be a UsingShadowDecl on +// top of the underlying declaration. // // Example: Given the following input: // @@ -271,42 +275,51 @@ void ImplicitConversionSequence::DebugPrint() const { // When we process #1, there is no previous declaration of "f", // so IsOverload will not be used. // -// When we process #2, Old is a FunctionDecl for #1. By comparing the -// parameter types, we see that #1 and #2 are overloaded (since they -// have different signatures), so this routine returns false; -// MatchedDecl is unchanged. +// When we process #2, Old contains only the FunctionDecl for #1. By +// comparing the parameter types, we see that #1 and #2 are overloaded +// (since they have different signatures), so this routine returns +// false; MatchedDecl is unchanged. // -// When we process #3, Old is an OverloadedFunctionDecl containing #1 -// and #2. We compare the signatures of #3 to #1 (they're overloaded, -// so we do nothing) and then #3 to #2. Since the signatures of #3 and -// #2 are identical (return types of functions are not part of the +// When we process #3, Old is an overload set containing #1 and #2. We +// compare the signatures of #3 to #1 (they're overloaded, so we do +// nothing) and then #3 to #2. Since the signatures of #3 and #2 are +// identical (return types of functions are not part of the // signature), IsOverload returns false and MatchedDecl will be set to // point to the FunctionDecl for #2. -bool -Sema::IsOverload(FunctionDecl *New, LookupResult &Previous, NamedDecl *&Match) { - for (LookupResult::iterator I = Previous.begin(), E = Previous.end(); +Sema::OverloadKind +Sema::CheckOverload(FunctionDecl *New, const LookupResult &Old, + NamedDecl *&Match) { + for (LookupResult::iterator I = Old.begin(), E = Old.end(); I != E; ++I) { - NamedDecl *Old = (*I)->getUnderlyingDecl(); - if (FunctionTemplateDecl *OldT = dyn_cast(Old)) { + NamedDecl *OldD = (*I)->getUnderlyingDecl(); + if (FunctionTemplateDecl *OldT = dyn_cast(OldD)) { if (!IsOverload(New, OldT->getTemplatedDecl())) { - Match = Old; - return false; + Match = *I; + return Ovl_Match; } - } else if (FunctionDecl *OldF = dyn_cast(Old)) { + } else if (FunctionDecl *OldF = dyn_cast(OldD)) { if (!IsOverload(New, OldF)) { - Match = Old; - return false; + Match = *I; + return Ovl_Match; } + } else if (isa(OldD) || isa(OldD)) { + // We can overload with these, which can show up when doing + // redeclaration checks for UsingDecls. + assert(Old.getLookupKind() == LookupUsingDeclName); + } else if (isa(OldD)) { + // Optimistically assume that an unresolved using decl will + // overload; if it doesn't, we'll have to diagnose during + // template instantiation. } else { // (C++ 13p1): // Only function declarations can be overloaded; object and type // declarations cannot be overloaded. - Match = Old; - return false; + Match = *I; + return Ovl_NonFunction; } } - return true; + return Ovl_Overload; } bool Sema::IsOverload(FunctionDecl *New, FunctionDecl *Old) { @@ -474,6 +487,23 @@ Sema::TryImplicitConversion(Expr* From, QualType ToType, return ICS; } +/// \brief Determine whether the conversion from FromType to ToType is a valid +/// conversion that strips "noreturn" off the nested function type. +static bool IsNoReturnConversion(ASTContext &Context, QualType FromType, + QualType ToType, QualType &ResultTy) { + if (Context.hasSameUnqualifiedType(FromType, ToType)) + return false; + + // Strip the noreturn off the type we're converting from; noreturn can + // safely be removed. + FromType = Context.getNoReturnType(FromType, false); + if (!Context.hasSameUnqualifiedType(FromType, ToType)) + return false; + + ResultTy = FromType; + return true; +} + /// IsStandardConversion - Determines whether there is a standard /// conversion sequence (C++ [conv], C++ [over.ics.scs]) from the /// expression From to the type ToType. Standard conversion sequences @@ -553,7 +583,7 @@ Sema::IsStandardConversion(Expr* From, QualType ToType, // function. (C++ 4.3p1). FromType = Context.getPointerType(FromType); } else if (FunctionDecl *Fn - = ResolveAddressOfOverloadedFunction(From, ToType, false)) { + = ResolveAddressOfOverloadedFunction(From, ToType, false)) { // Address of overloaded function (C++ [over.over]). SCS.First = ICK_Function_To_Pointer; @@ -644,7 +674,7 @@ Sema::IsStandardConversion(Expr* From, QualType ToType, } else if (ToType->isBooleanType() && (FromType->isArithmeticType() || FromType->isEnumeralType() || - FromType->isPointerType() || + FromType->isAnyPointerType() || FromType->isBlockPointerType() || FromType->isMemberPointerType() || FromType->isNullPtrType())) { @@ -655,6 +685,9 @@ Sema::IsStandardConversion(Expr* From, QualType ToType, Context.typesAreCompatible(ToType, FromType)) { // Compatible conversions (Clang extension for C function overloading) SCS.Second = ICK_Compatible_Conversion; + } else if (IsNoReturnConversion(Context, FromType, ToType, FromType)) { + // Treat a conversion that strips "noreturn" as an identity conversion. + SCS.Second = ICK_NoReturn_Adjustment; } else { // No second conversion required. SCS.Second = ICK_Identity; @@ -728,19 +761,21 @@ bool Sema::IsIntegralPromotion(Expr *From, QualType FromType, QualType ToType) { // can be converted to an rvalue of the first of the following types // that can represent all the values of its underlying type: int, // unsigned int, long, or unsigned long (C++ 4.5p2). - if ((FromType->isEnumeralType() || FromType->isWideCharType()) - && ToType->isIntegerType()) { + + // We pre-calculate the promotion type for enum types. + if (const EnumType *FromEnumType = FromType->getAs()) + if (ToType->isIntegerType()) + return Context.hasSameUnqualifiedType(ToType, + FromEnumType->getDecl()->getPromotionType()); + + if (FromType->isWideCharType() && ToType->isIntegerType()) { // Determine whether the type we're converting from is signed or // unsigned. bool FromIsSigned; uint64_t FromSize = Context.getTypeSize(FromType); - if (const EnumType *FromEnumType = FromType->getAs()) { - QualType UnderlyingType = FromEnumType->getDecl()->getIntegerType(); - FromIsSigned = UnderlyingType->isSignedIntegerType(); - } else { - // FIXME: Is wchar_t signed or unsigned? We assume it's signed for now. - FromIsSigned = true; - } + + // FIXME: Is wchar_t signed or unsigned? We assume it's signed for now. + FromIsSigned = true; // The types we'll try to promote to, in the appropriate // order. Try each of these types. @@ -1233,7 +1268,7 @@ bool Sema::IsMemberPointerConversion(Expr *From, QualType FromType, return false; } - + /// CheckMemberPointerConversion - Check the member pointer conversion from the /// expression From to the type ToType. This routine checks for ambiguous or /// virtual (FIXME: or inaccessible) base-to-derived member pointer conversions @@ -1371,13 +1406,13 @@ Sema::IsQualificationConversion(QualType FromType, QualType ToType) { /// for overload resolution. /// \param UserCast true if looking for user defined conversion for a static /// cast. -Sema::OverloadingResult Sema::IsUserDefinedConversion( - Expr *From, QualType ToType, - UserDefinedConversionSequence& User, - OverloadCandidateSet& CandidateSet, - bool AllowConversionFunctions, - bool AllowExplicit, bool ForceRValue, - bool UserCast) { +OverloadingResult Sema::IsUserDefinedConversion(Expr *From, QualType ToType, + UserDefinedConversionSequence& User, + OverloadCandidateSet& CandidateSet, + bool AllowConversionFunctions, + bool AllowExplicit, + bool ForceRValue, + bool UserCast) { if (const RecordType *ToRecordType = ToType->getAs()) { if (RequireCompleteType(From->getLocStart(), ToType, PDiag())) { // We're not going to find any constructors. @@ -1446,6 +1481,11 @@ Sema::OverloadingResult Sema::IsUserDefinedConversion( = FromRecordDecl->getVisibleConversionFunctions(); for (UnresolvedSet::iterator I = Conversions->begin(), E = Conversions->end(); I != E; ++I) { + NamedDecl *D = *I; + CXXRecordDecl *ActingContext = cast(D->getDeclContext()); + if (isa(D)) + D = cast(D)->getTargetDecl(); + CXXConversionDecl *Conv; FunctionTemplateDecl *ConvTemplate; if ((ConvTemplate = dyn_cast(*I))) @@ -1455,10 +1495,11 @@ Sema::OverloadingResult Sema::IsUserDefinedConversion( if (AllowExplicit || !Conv->isExplicit()) { if (ConvTemplate) - AddTemplateConversionCandidate(ConvTemplate, From, ToType, - CandidateSet); + AddTemplateConversionCandidate(ConvTemplate, ActingContext, + From, ToType, CandidateSet); else - AddConversionCandidate(Conv, From, ToType, CandidateSet); + AddConversionCandidate(Conv, ActingContext, From, ToType, + CandidateSet); } } } @@ -2075,8 +2116,10 @@ bool Sema::PerformCopyInitialization(Expr *&From, QualType ToType, /// parameter of the given member function (@c Method) from the /// expression @p From. ImplicitConversionSequence -Sema::TryObjectArgumentInitialization(Expr *From, CXXMethodDecl *Method) { - QualType ClassType = Context.getTypeDeclType(Method->getParent()); +Sema::TryObjectArgumentInitialization(QualType FromType, + CXXMethodDecl *Method, + CXXRecordDecl *ActingContext) { + QualType ClassType = Context.getTypeDeclType(ActingContext); // [class.dtor]p2: A destructor can be invoked for a const, volatile or // const volatile object. unsigned Quals = isa(Method) ? @@ -2090,7 +2133,6 @@ Sema::TryObjectArgumentInitialization(Expr *From, CXXMethodDecl *Method) { ICS.ConversionKind = ImplicitConversionSequence::BadConversion; // We need to have an object of class type. - QualType FromType = From->getType(); if (const PointerType *PT = FromType->getAs()) FromType = PT->getPointeeType(); @@ -2150,8 +2192,11 @@ Sema::PerformObjectArgumentInitialization(Expr *&From, CXXMethodDecl *Method) { DestType = ImplicitParamRecordType; } + // Note that we always use the true parent context when performing + // the actual argument initialization. ImplicitConversionSequence ICS - = TryObjectArgumentInitialization(From, Method); + = TryObjectArgumentInitialization(From->getType(), Method, + Method->getParent()); if (ICS.ConversionKind == ImplicitConversionSequence::BadConversion) return Diag(From->getSourceRange().getBegin(), diag::err_implicit_object_parameter_init) @@ -2226,9 +2271,11 @@ Sema::AddOverloadCandidate(FunctionDecl *Function, // that is named without a member access expression (e.g., // "this->f") that was either written explicitly or created // implicitly. This can happen with a qualified call to a member - // function, e.g., X::f(). We use a NULL object as the implied - // object argument (C++ [over.call.func]p3). - AddMethodCandidate(Method, 0, Args, NumArgs, CandidateSet, + // function, e.g., X::f(). We use an empty type for the implied + // object argument (C++ [over.call.func]p3), and the acting context + // is irrelevant. + AddMethodCandidate(Method, Method->getParent(), + QualType(), Args, NumArgs, CandidateSet, SuppressUserConversions, ForceRValue); return; } @@ -2340,10 +2387,12 @@ void Sema::AddFunctionCandidates(const FunctionSet &Functions, for (FunctionSet::const_iterator F = Functions.begin(), FEnd = Functions.end(); F != FEnd; ++F) { + // FIXME: using declarations if (FunctionDecl *FD = dyn_cast(*F)) { if (isa(FD) && !cast(FD)->isStatic()) AddMethodCandidate(cast(FD), - Args[0], Args + 1, NumArgs - 1, + cast(FD)->getParent(), + Args[0]->getType(), Args + 1, NumArgs - 1, CandidateSet, SuppressUserConversions); else AddOverloadCandidate(FD, Args, NumArgs, CandidateSet, @@ -2353,8 +2402,9 @@ void Sema::AddFunctionCandidates(const FunctionSet &Functions, if (isa(FunTmpl->getTemplatedDecl()) && !cast(FunTmpl->getTemplatedDecl())->isStatic()) AddMethodTemplateCandidate(FunTmpl, + cast(FunTmpl->getDeclContext()), /*FIXME: explicit args */ 0, - Args[0], Args + 1, NumArgs - 1, + Args[0]->getType(), Args + 1, NumArgs - 1, CandidateSet, SuppressUserConversions); else @@ -2368,13 +2418,14 @@ void Sema::AddFunctionCandidates(const FunctionSet &Functions, /// AddMethodCandidate - Adds a named decl (which is some kind of /// method) as a method candidate to the given overload set. -void Sema::AddMethodCandidate(NamedDecl *Decl, Expr *Object, +void Sema::AddMethodCandidate(NamedDecl *Decl, + QualType ObjectType, Expr **Args, unsigned NumArgs, OverloadCandidateSet& CandidateSet, bool SuppressUserConversions, bool ForceRValue) { // FIXME: use this - //DeclContext *ActingContext = Decl->getDeclContext(); + CXXRecordDecl *ActingContext = cast(Decl->getDeclContext()); if (isa(Decl)) Decl = cast(Decl)->getTargetDecl(); @@ -2382,13 +2433,14 @@ void Sema::AddMethodCandidate(NamedDecl *Decl, Expr *Object, if (FunctionTemplateDecl *TD = dyn_cast(Decl)) { assert(isa(TD->getTemplatedDecl()) && "Expected a member function template"); - AddMethodTemplateCandidate(TD, /*ExplicitArgs*/ 0, - Object, Args, NumArgs, + AddMethodTemplateCandidate(TD, ActingContext, /*ExplicitArgs*/ 0, + ObjectType, Args, NumArgs, CandidateSet, SuppressUserConversions, ForceRValue); } else { - AddMethodCandidate(cast(Decl), Object, Args, NumArgs, + AddMethodCandidate(cast(Decl), ActingContext, + ObjectType, Args, NumArgs, CandidateSet, SuppressUserConversions, ForceRValue); } } @@ -2403,8 +2455,8 @@ void Sema::AddMethodCandidate(NamedDecl *Decl, Expr *Object, /// a slightly hacky way to implement the overloading rules for elidable copy /// initialization in C++0x (C++0x 12.8p15). void -Sema::AddMethodCandidate(CXXMethodDecl *Method, Expr *Object, - Expr **Args, unsigned NumArgs, +Sema::AddMethodCandidate(CXXMethodDecl *Method, CXXRecordDecl *ActingContext, + QualType ObjectType, Expr **Args, unsigned NumArgs, OverloadCandidateSet& CandidateSet, bool SuppressUserConversions, bool ForceRValue) { const FunctionProtoType* Proto @@ -2453,13 +2505,14 @@ Sema::AddMethodCandidate(CXXMethodDecl *Method, Expr *Object, Candidate.Viable = true; Candidate.Conversions.resize(NumArgs + 1); - if (Method->isStatic() || !Object) + if (Method->isStatic() || ObjectType.isNull()) // The implicit object argument is ignored. Candidate.IgnoreObjectArgument = true; else { // Determine the implicit conversion sequence for the object // parameter. - Candidate.Conversions[0] = TryObjectArgumentInitialization(Object, Method); + Candidate.Conversions[0] + = TryObjectArgumentInitialization(ObjectType, Method, ActingContext); if (Candidate.Conversions[0].ConversionKind == ImplicitConversionSequence::BadConversion) { Candidate.Viable = false; @@ -2500,8 +2553,10 @@ Sema::AddMethodCandidate(CXXMethodDecl *Method, Expr *Object, /// function template specialization. void Sema::AddMethodTemplateCandidate(FunctionTemplateDecl *MethodTmpl, + CXXRecordDecl *ActingContext, const TemplateArgumentListInfo *ExplicitTemplateArgs, - Expr *Object, Expr **Args, unsigned NumArgs, + QualType ObjectType, + Expr **Args, unsigned NumArgs, OverloadCandidateSet& CandidateSet, bool SuppressUserConversions, bool ForceRValue) { @@ -2533,7 +2588,8 @@ Sema::AddMethodTemplateCandidate(FunctionTemplateDecl *MethodTmpl, assert(Specialization && "Missing member function template specialization?"); assert(isa(Specialization) && "Specialization is not a member function?"); - AddMethodCandidate(cast(Specialization), Object, Args, NumArgs, + AddMethodCandidate(cast(Specialization), ActingContext, + ObjectType, Args, NumArgs, CandidateSet, SuppressUserConversions, ForceRValue); } @@ -2585,6 +2641,7 @@ Sema::AddTemplateOverloadCandidate(FunctionTemplateDecl *FunctionTemplate, /// conversion function produces). void Sema::AddConversionCandidate(CXXConversionDecl *Conversion, + CXXRecordDecl *ActingContext, Expr *From, QualType ToType, OverloadCandidateSet& CandidateSet) { assert(!Conversion->getDescribedFunctionTemplate() && @@ -2611,7 +2668,9 @@ Sema::AddConversionCandidate(CXXConversionDecl *Conversion, // object parameter. Candidate.Viable = true; Candidate.Conversions.resize(1); - Candidate.Conversions[0] = TryObjectArgumentInitialization(From, Conversion); + Candidate.Conversions[0] + = TryObjectArgumentInitialization(From->getType(), Conversion, + ActingContext); // Conversion functions to a different type in the base class is visible in // the derived class. So, a derived to base conversion should not participate // in overload resolution. @@ -2683,6 +2742,7 @@ Sema::AddConversionCandidate(CXXConversionDecl *Conversion, /// [temp.deduct.conv]). void Sema::AddTemplateConversionCandidate(FunctionTemplateDecl *FunctionTemplate, + CXXRecordDecl *ActingDC, Expr *From, QualType ToType, OverloadCandidateSet &CandidateSet) { assert(isa(FunctionTemplate->getTemplatedDecl()) && @@ -2705,7 +2765,7 @@ Sema::AddTemplateConversionCandidate(FunctionTemplateDecl *FunctionTemplate, // Add the conversion function template specialization produced by // template argument deduction as a candidate. assert(Specialization && "Missing function template specialization?"); - AddConversionCandidate(Specialization, From, ToType, CandidateSet); + AddConversionCandidate(Specialization, ActingDC, From, ToType, CandidateSet); } /// AddSurrogateCandidate - Adds a "surrogate" candidate function that @@ -2714,8 +2774,10 @@ Sema::AddTemplateConversionCandidate(FunctionTemplateDecl *FunctionTemplate, /// with the given arguments (C++ [over.call.object]p2-4). Proto is /// the type of function that we'll eventually be calling. void Sema::AddSurrogateCandidate(CXXConversionDecl *Conversion, + CXXRecordDecl *ActingContext, const FunctionProtoType *Proto, - Expr *Object, Expr **Args, unsigned NumArgs, + QualType ObjectType, + Expr **Args, unsigned NumArgs, OverloadCandidateSet& CandidateSet) { if (!CandidateSet.isNewCandidate(Conversion)) return; @@ -2735,7 +2797,7 @@ void Sema::AddSurrogateCandidate(CXXConversionDecl *Conversion, // Determine the implicit conversion sequence for the implicit // object parameter. ImplicitConversionSequence ObjectInit - = TryObjectArgumentInitialization(Object, Conversion); + = TryObjectArgumentInitialization(ObjectType, Conversion, ActingContext); if (ObjectInit.ConversionKind == ImplicitConversionSequence::BadConversion) { Candidate.Viable = false; return; @@ -2870,7 +2932,8 @@ void Sema::AddMemberOperatorCandidates(OverloadedOperatorKind Op, OperEnd = Operators.end(); Oper != OperEnd; ++Oper) - AddMethodCandidate(*Oper, Args[0], Args + 1, NumArgs - 1, CandidateSet, + AddMethodCandidate(*Oper, Args[0]->getType(), + Args + 1, NumArgs - 1, CandidateSet, /* SuppressUserConversions = */ false); } } @@ -4111,10 +4174,9 @@ Sema::isBetterOverloadCandidate(const OverloadCandidate& Cand1, /// function, Best points to the candidate function found. /// /// \returns The result of overload resolution. -Sema::OverloadingResult -Sema::BestViableFunction(OverloadCandidateSet& CandidateSet, - SourceLocation Loc, - OverloadCandidateSet::iterator& Best) { +OverloadingResult Sema::BestViableFunction(OverloadCandidateSet& CandidateSet, + SourceLocation Loc, + OverloadCandidateSet::iterator& Best) { // Find the best viable function. Best = CandidateSet.end(); for (OverloadCandidateSet::iterator Cand = CandidateSet.begin(); @@ -4426,7 +4488,10 @@ Sema::ResolveAddressOfOverloadedFunction(Expr *From, QualType ToType, continue; if (FunctionDecl *FunDecl = dyn_cast(*I)) { - if (FunctionType == Context.getCanonicalType(FunDecl->getType())) { + QualType ResultTy; + if (Context.hasSameUnqualifiedType(FunctionType, FunDecl->getType()) || + IsNoReturnConversion(Context, FunDecl->getType(), FunctionType, + ResultTy)) { Matches.insert(cast(FunDecl->getCanonicalDecl())); FoundNonTemplateFunction = true; } @@ -5122,7 +5187,7 @@ Sema::CreateOverloadedArraySubscriptExpr(SourceLocation LLoc, /// parameter). The caller needs to validate that the member /// expression refers to a member function or an overloaded member /// function. -Sema::ExprResult +Sema::OwningExprResult Sema::BuildCallToMemberFunction(Scope *S, Expr *MemExprE, SourceLocation LParenLoc, Expr **Args, unsigned NumArgs, SourceLocation *CommaLocs, @@ -5131,46 +5196,46 @@ Sema::BuildCallToMemberFunction(Scope *S, Expr *MemExprE, // argument and the member function we're referring to. Expr *NakedMemExpr = MemExprE->IgnoreParens(); - // Extract the object argument. - Expr *ObjectArg; - MemberExpr *MemExpr; CXXMethodDecl *Method = 0; if (isa(NakedMemExpr)) { MemExpr = cast(NakedMemExpr); - ObjectArg = MemExpr->getBase(); Method = cast(MemExpr->getMemberDecl()); } else { UnresolvedMemberExpr *UnresExpr = cast(NakedMemExpr); - ObjectArg = UnresExpr->getBase(); + + QualType ObjectType = UnresExpr->getBaseType(); // Add overload candidates OverloadCandidateSet CandidateSet; + // FIXME: avoid copy. + TemplateArgumentListInfo TemplateArgsBuffer, *TemplateArgs = 0; + if (UnresExpr->hasExplicitTemplateArgs()) { + UnresExpr->copyTemplateArgumentsInto(TemplateArgsBuffer); + TemplateArgs = &TemplateArgsBuffer; + } + for (UnresolvedMemberExpr::decls_iterator I = UnresExpr->decls_begin(), E = UnresExpr->decls_end(); I != E; ++I) { - // TODO: note if we found something through a using declaration - NamedDecl *Func = (*I)->getUnderlyingDecl(); - + NamedDecl *Func = *I; + CXXRecordDecl *ActingDC = cast(Func->getDeclContext()); + if (isa(Func)) + Func = cast(Func)->getTargetDecl(); + if ((Method = dyn_cast(Func))) { // If explicit template arguments were provided, we can't call a // non-template member function. - if (UnresExpr->hasExplicitTemplateArgs()) + if (TemplateArgs) continue; - AddMethodCandidate(Method, ObjectArg, Args, NumArgs, CandidateSet, - /*SuppressUserConversions=*/false); + AddMethodCandidate(Method, ActingDC, ObjectType, Args, NumArgs, + CandidateSet, /*SuppressUserConversions=*/false); } else { - // FIXME: avoid copy. - TemplateArgumentListInfo TemplateArgs; - if (UnresExpr->hasExplicitTemplateArgs()) - UnresExpr->copyTemplateArgumentsInto(TemplateArgs); - AddMethodTemplateCandidate(cast(Func), - (UnresExpr->hasExplicitTemplateArgs() - ? &TemplateArgs : 0), - ObjectArg, Args, NumArgs, + ActingDC, TemplateArgs, + ObjectType, Args, NumArgs, CandidateSet, /*SuppressUsedConversions=*/false); } @@ -5190,14 +5255,14 @@ Sema::BuildCallToMemberFunction(Scope *S, Expr *MemExprE, << DeclName << MemExprE->getSourceRange(); PrintOverloadCandidates(CandidateSet, /*OnlyViable=*/false); // FIXME: Leaking incoming expressions! - return true; + return ExprError(); case OR_Ambiguous: Diag(UnresExpr->getMemberLoc(), diag::err_ovl_ambiguous_member_call) << DeclName << MemExprE->getSourceRange(); PrintOverloadCandidates(CandidateSet, /*OnlyViable=*/false); // FIXME: Leaking incoming expressions! - return true; + return ExprError(); case OR_Deleted: Diag(UnresExpr->getMemberLoc(), diag::err_ovl_deleted_member_call) @@ -5205,16 +5270,24 @@ Sema::BuildCallToMemberFunction(Scope *S, Expr *MemExprE, << DeclName << MemExprE->getSourceRange(); PrintOverloadCandidates(CandidateSet, /*OnlyViable=*/false); // FIXME: Leaking incoming expressions! - return true; + return ExprError(); } MemExprE = FixOverloadedFunctionReference(MemExprE, Method); + + // If overload resolution picked a static member, build a + // non-member call based on that function. + if (Method->isStatic()) { + return BuildResolvedCallExpr(MemExprE, Method, LParenLoc, + Args, NumArgs, RParenLoc); + } + MemExpr = cast(MemExprE->IgnoreParens()); } assert(Method && "Member call to something that isn't a method?"); ExprOwningPtr - TheCall(this, new (Context) CXXMemberCallExpr(Context, MemExpr, Args, + TheCall(this, new (Context) CXXMemberCallExpr(Context, MemExprE, Args, NumArgs, Method->getResultType().getNonReferenceType(), RParenLoc)); @@ -5222,24 +5295,25 @@ Sema::BuildCallToMemberFunction(Scope *S, Expr *MemExprE, // Check for a valid return type. if (CheckCallReturnType(Method->getResultType(), MemExpr->getMemberLoc(), TheCall.get(), Method)) - return true; + return ExprError(); // Convert the object argument (for a non-static member function call). + Expr *ObjectArg = MemExpr->getBase(); if (!Method->isStatic() && PerformObjectArgumentInitialization(ObjectArg, Method)) - return true; + return ExprError(); MemExpr->setBase(ObjectArg); // Convert the rest of the arguments const FunctionProtoType *Proto = cast(Method->getType()); if (ConvertArgumentsForCall(&*TheCall, MemExpr, Method, Proto, Args, NumArgs, RParenLoc)) - return true; + return ExprError(); if (CheckFunctionCall(Method, TheCall.get())) - return true; + return ExprError(); - return MaybeBindToTemporary(TheCall.release()).release(); + return MaybeBindToTemporary(TheCall.release()); } /// BuildCallToObjectOfClassType - Build a call to an object of class @@ -5276,7 +5350,7 @@ Sema::BuildCallToObjectOfClassType(Scope *S, Expr *Object, for (LookupResult::iterator Oper = R.begin(), OperEnd = R.end(); Oper != OperEnd; ++Oper) { - AddMethodCandidate(*Oper, Object, Args, NumArgs, CandidateSet, + AddMethodCandidate(*Oper, Object->getType(), Args, NumArgs, CandidateSet, /*SuppressUserConversions=*/ false); } @@ -5302,12 +5376,17 @@ Sema::BuildCallToObjectOfClassType(Scope *S, Expr *Object, = cast(Record->getDecl())->getConversionFunctions(); for (UnresolvedSet::iterator I = Conversions->begin(), E = Conversions->end(); I != E; ++I) { + NamedDecl *D = *I; + CXXRecordDecl *ActingContext = cast(D->getDeclContext()); + if (isa(D)) + D = cast(D)->getTargetDecl(); + // Skip over templated conversion functions; they aren't // surrogates. - if (isa(*I)) + if (isa(D)) continue; - CXXConversionDecl *Conv = cast(*I); + CXXConversionDecl *Conv = cast(D); // Strip the reference type (if any) and then the pointer type (if // any) to get down to what might be a function type. @@ -5316,7 +5395,9 @@ Sema::BuildCallToObjectOfClassType(Scope *S, Expr *Object, ConvType = ConvPtrType->getPointeeType(); if (const FunctionProtoType *Proto = ConvType->getAs()) - AddSurrogateCandidate(Conv, Proto, Object, Args, NumArgs, CandidateSet); + AddSurrogateCandidate(Conv, ActingContext, Proto, + Object->getType(), Args, NumArgs, + CandidateSet); } // Perform overload resolution. @@ -5372,8 +5453,7 @@ Sema::BuildCallToObjectOfClassType(Scope *S, Expr *Object, // Create an implicit member expr to refer to the conversion operator. // and then call it. - CXXMemberCallExpr *CE = - BuildCXXMemberCallExpr(Object, Conv); + CXXMemberCallExpr *CE = BuildCXXMemberCallExpr(Object, Conv); return ActOnCallExpr(S, ExprArg(*this, CE), LParenLoc, MultiExprArg(*this, (ExprTy**)Args, NumArgs), @@ -5503,9 +5583,16 @@ Sema::BuildOverloadedArrowExpr(Scope *S, ExprArg BaseIn, SourceLocation OpLoc) { R.suppressDiagnostics(); for (LookupResult::iterator Oper = R.begin(), OperEnd = R.end(); - Oper != OperEnd; ++Oper) - AddMethodCandidate(cast(*Oper), Base, 0, 0, CandidateSet, + Oper != OperEnd; ++Oper) { + NamedDecl *D = *Oper; + CXXRecordDecl *ActingContext = cast(D->getDeclContext()); + if (isa(D)) + D = cast(D)->getTargetDecl(); + + AddMethodCandidate(cast(D), ActingContext, + Base->getType(), 0, 0, CandidateSet, /*SuppressUserConversions=*/false); + } // Perform overload resolution. OverloadCandidateSet::iterator Best; @@ -5632,19 +5719,11 @@ Expr *Sema::FixOverloadedFunctionReference(Expr *E, FunctionDecl *Fn) { } if (UnresolvedLookupExpr *ULE = dyn_cast(E)) { + // FIXME: avoid copy. + TemplateArgumentListInfo TemplateArgsBuffer, *TemplateArgs = 0; if (ULE->hasExplicitTemplateArgs()) { - // FIXME: avoid copy. - TemplateArgumentListInfo TemplateArgs; - if (ULE->hasExplicitTemplateArgs()) - ULE->copyTemplateArgumentsInto(TemplateArgs); - - return DeclRefExpr::Create(Context, - ULE->getQualifier(), - ULE->getQualifierRange(), - Fn, - ULE->getNameLoc(), - Fn->getType(), - &TemplateArgs); + ULE->copyTemplateArgumentsInto(TemplateArgsBuffer); + TemplateArgs = &TemplateArgsBuffer; } return DeclRefExpr::Create(Context, @@ -5652,23 +5731,43 @@ Expr *Sema::FixOverloadedFunctionReference(Expr *E, FunctionDecl *Fn) { ULE->getQualifierRange(), Fn, ULE->getNameLoc(), - Fn->getType()); + Fn->getType(), + TemplateArgs); } if (UnresolvedMemberExpr *MemExpr = dyn_cast(E)) { // FIXME: avoid copy. - TemplateArgumentListInfo TemplateArgs; - if (MemExpr->hasExplicitTemplateArgs()) - MemExpr->copyTemplateArgumentsInto(TemplateArgs); + TemplateArgumentListInfo TemplateArgsBuffer, *TemplateArgs = 0; + if (MemExpr->hasExplicitTemplateArgs()) { + MemExpr->copyTemplateArgumentsInto(TemplateArgsBuffer); + TemplateArgs = &TemplateArgsBuffer; + } - return MemberExpr::Create(Context, MemExpr->getBase()->Retain(), + Expr *Base; + + // If we're filling in + if (MemExpr->isImplicitAccess()) { + if (cast(Fn)->isStatic()) { + return DeclRefExpr::Create(Context, + MemExpr->getQualifier(), + MemExpr->getQualifierRange(), + Fn, + MemExpr->getMemberLoc(), + Fn->getType(), + TemplateArgs); + } else + Base = new (Context) CXXThisExpr(SourceLocation(), + MemExpr->getBaseType()); + } else + Base = MemExpr->getBase()->Retain(); + + return MemberExpr::Create(Context, Base, MemExpr->isArrow(), MemExpr->getQualifier(), MemExpr->getQualifierRange(), Fn, MemExpr->getMemberLoc(), - (MemExpr->hasExplicitTemplateArgs() - ? &TemplateArgs : 0), + TemplateArgs, Fn->getType()); } @@ -5676,4 +5775,9 @@ Expr *Sema::FixOverloadedFunctionReference(Expr *E, FunctionDecl *Fn) { return E->Retain(); } +Sema::OwningExprResult Sema::FixOverloadedFunctionReference(OwningExprResult E, + FunctionDecl *Fn) { + return Owned(FixOverloadedFunctionReference((Expr *)E.get(), Fn)); +} + } // end namespace clang diff --git a/lib/Sema/SemaOverload.h b/lib/Sema/SemaOverload.h index 0d1f37aa4beb..3613d608834a 100644 --- a/lib/Sema/SemaOverload.h +++ b/lib/Sema/SemaOverload.h @@ -15,12 +15,26 @@ #ifndef LLVM_CLANG_SEMA_OVERLOAD_H #define LLVM_CLANG_SEMA_OVERLOAD_H +#include "clang/AST/Decl.h" +#include "clang/AST/Type.h" +#include "llvm/ADT/SmallPtrSet.h" #include "llvm/ADT/SmallVector.h" namespace clang { + class ASTContext; class CXXConstructorDecl; + class CXXConversionDecl; class FunctionDecl; + /// OverloadingResult - Capture the result of performing overload + /// resolution. + enum OverloadingResult { + OR_Success, ///< Overload resolution succeeded. + OR_No_Viable_Function, ///< No viable function found. + OR_Ambiguous, ///< Ambiguous candidates found. + OR_Deleted ///< Overload resoltuion refers to a deleted function. + }; + /// ImplicitConversionKind - The kind of implicit conversion used to /// convert an argument to a parameter's type. The enumerator values /// match with Table 9 of (C++ 13.3.3.1.1) and are listed such that @@ -30,6 +44,7 @@ namespace clang { ICK_Lvalue_To_Rvalue, ///< Lvalue-to-rvalue conversion (C++ 4.1) ICK_Array_To_Pointer, ///< Array-to-pointer conversion (C++ 4.2) ICK_Function_To_Pointer, ///< Function-to-pointer (C++ 4.3) + ICK_NoReturn_Adjustment, ///< Removal of noreturn from a type (Clang) ICK_Qualification, ///< Qualification conversions (C++ 4.4) ICK_Integral_Promotion, ///< Integral promotions (C++ 4.5) ICK_Floating_Promotion, ///< Floating point promotions (C++ 4.6) @@ -270,6 +285,7 @@ namespace clang { /// OverloadCandidateSet - A set of overload candidates, used in C++ /// overload resolution (C++ 13.3). class OverloadCandidateSet : public llvm::SmallVector { + typedef llvm::SmallVector inherited; llvm::SmallPtrSet Functions; public: @@ -278,6 +294,12 @@ namespace clang { bool isNewCandidate(Decl *F) { return Functions.insert(F->getCanonicalDecl()); } + + /// \brief Clear out all of the candidates. + void clear() { + inherited::clear(); + Functions.clear(); + } }; } // end namespace clang diff --git a/lib/Sema/SemaTemplate.cpp b/lib/Sema/SemaTemplate.cpp index f47577e9097e..ac1b1ec0eed0 100644 --- a/lib/Sema/SemaTemplate.cpp +++ b/lib/Sema/SemaTemplate.cpp @@ -108,36 +108,36 @@ TemplateNameKind Sema::isTemplateName(Scope *S, if (R.empty()) return TNK_Non_template; - NamedDecl *Template = R.getAsSingleDecl(Context); + TemplateName Template; + TemplateNameKind TemplateKind; - if (SS.isSet() && !SS.isInvalid()) { - NestedNameSpecifier *Qualifier - = static_cast(SS.getScopeRep()); - if (OverloadedFunctionDecl *Ovl - = dyn_cast(Template)) - TemplateResult - = TemplateTy::make(Context.getQualifiedTemplateName(Qualifier, false, - Ovl)); - else - TemplateResult - = TemplateTy::make(Context.getQualifiedTemplateName(Qualifier, false, - cast(Template))); - } else if (OverloadedFunctionDecl *Ovl - = dyn_cast(Template)) { - TemplateResult = TemplateTy::make(TemplateName(Ovl)); + unsigned ResultCount = R.end() - R.begin(); + if (ResultCount > 1) { + // We assume that we'll preserve the qualifier from a function + // template name in other ways. + Template = Context.getOverloadedTemplateName(R.begin(), R.end()); + TemplateKind = TNK_Function_template; } else { - TemplateResult = TemplateTy::make( - TemplateName(cast(Template))); + TemplateDecl *TD = cast((*R.begin())->getUnderlyingDecl()); + + if (SS.isSet() && !SS.isInvalid()) { + NestedNameSpecifier *Qualifier + = static_cast(SS.getScopeRep()); + Template = Context.getQualifiedTemplateName(Qualifier, false, TD); + } else { + Template = TemplateName(TD); + } + + if (isa(TD)) + TemplateKind = TNK_Function_template; + else { + assert(isa(TD) || isa(TD)); + TemplateKind = TNK_Type_template; + } } - if (isa(Template) || - isa(Template)) - return TNK_Type_template; - - assert((isa(Template) || - isa(Template)) && - "Unhandled template kind in Sema::isTemplateName"); - return TNK_Function_template; + TemplateResult = TemplateTy::make(Template); + return TemplateKind; } void Sema::LookupTemplateName(LookupResult &Found, @@ -248,126 +248,30 @@ void Sema::LookupTemplateName(LookupResult &Found, } } -/// Constructs a full type for the given nested-name-specifier. -static QualType GetTypeForQualifier(ASTContext &Context, - NestedNameSpecifier *Qualifier) { - // Three possibilities: - - // 1. A namespace (global or not). - assert(!Qualifier->getAsNamespace() && "can't construct type for namespace"); - - // 2. A type (templated or not). - Type *Ty = Qualifier->getAsType(); - if (Ty) return QualType(Ty, 0); - - // 3. A dependent identifier. - assert(Qualifier->getAsIdentifier()); - return Context.getTypenameType(Qualifier->getPrefix(), - Qualifier->getAsIdentifier()); -} - -static bool HasDependentTypeAsBase(ASTContext &Context, - CXXRecordDecl *Record, - CanQualType T) { - for (CXXRecordDecl::base_class_iterator I = Record->bases_begin(), - E = Record->bases_end(); I != E; ++I) { - CanQualType BaseT = Context.getCanonicalType((*I).getType()); - if (BaseT == T) - return true; - - // We have to recurse here to cover some really bizarre cases. - // Obviously, we can only have the dependent type as an indirect - // base class through a dependent base class, and usually it's - // impossible to know which instantiation a dependent base class - // will have. But! If we're actually *inside* the dependent base - // class, then we know its instantiation and can therefore be - // reasonably expected to look into it. - - // template class A : Base { - // class Inner : A { - // void foo() { - // Base::foo(); // statically known to be an implicit member - // reference - // } - // }; - // }; - - CanQual RT = BaseT->getAs(); - - // Base might be a dependent member type, in which case we - // obviously can't look into it. - if (!RT) continue; - - CXXRecordDecl *BaseRecord = cast(RT->getDecl()); - if (BaseRecord->isDefinition() && - HasDependentTypeAsBase(Context, BaseRecord, T)) - return true; - } - - return false; -} - -/// Checks whether the given dependent nested-name specifier -/// introduces an implicit member reference. This is only true if the -/// nested-name specifier names a type identical to one of the current -/// instance method's context's (possibly indirect) base classes. -static bool IsImplicitDependentMemberReference(Sema &SemaRef, - NestedNameSpecifier *Qualifier, - QualType &ThisType) { - // If the context isn't a C++ method, then it isn't an implicit - // member reference. - CXXMethodDecl *MD = dyn_cast(SemaRef.CurContext); - if (!MD || MD->isStatic()) - return false; - - ASTContext &Context = SemaRef.Context; - - // We want to check whether the method's context is known to inherit - // from the type named by the nested name specifier. The trivial - // case here is: - // template class Base { ... }; - // template class Derived : Base { - // void foo() { - // Base::foo(); - // } - // }; - - QualType QT = GetTypeForQualifier(Context, Qualifier); - CanQualType T = Context.getCanonicalType(QT); - - // And now, just walk the non-dependent type hierarchy, trying to - // find the given type as a literal base class. - CXXRecordDecl *Record = cast(MD->getParent()); - if (Context.getCanonicalType(Context.getTypeDeclType(Record)) == T || - HasDependentTypeAsBase(Context, Record, T)) { - ThisType = MD->getThisType(Context); - return true; - } - - return false; -} - -/// ActOnDependentIdExpression - Handle a dependent declaration name -/// that was just parsed. +/// ActOnDependentIdExpression - Handle a dependent id-expression that +/// was just parsed. This is only possible with an explicit scope +/// specifier naming a dependent type. Sema::OwningExprResult Sema::ActOnDependentIdExpression(const CXXScopeSpec &SS, DeclarationName Name, SourceLocation NameLoc, - bool CheckForImplicitMember, + bool isAddressOfOperand, const TemplateArgumentListInfo *TemplateArgs) { NestedNameSpecifier *Qualifier = static_cast(SS.getScopeRep()); - QualType ThisType; - if (CheckForImplicitMember && - IsImplicitDependentMemberReference(*this, Qualifier, ThisType)) { - Expr *This = new (Context) CXXThisExpr(SourceLocation(), ThisType); - + if (!isAddressOfOperand && + isa(CurContext) && + cast(CurContext)->isInstance()) { + QualType ThisType = cast(CurContext)->getThisType(Context); + // Since the 'this' expression is synthesized, we don't need to // perform the double-lookup check. NamedDecl *FirstQualifierInScope = 0; - return Owned(CXXDependentScopeMemberExpr::Create(Context, This, true, + return Owned(CXXDependentScopeMemberExpr::Create(Context, + /*This*/ 0, ThisType, + /*IsArrow*/ true, /*Op*/ SourceLocation(), Qualifier, SS.getRange(), FirstQualifierInScope, @@ -426,10 +330,10 @@ static TemplateArgumentLoc translateTemplateArgument(Sema &SemaRef, switch (Arg.getKind()) { case ParsedTemplateArgument::Type: { - DeclaratorInfo *DI; + TypeSourceInfo *DI; QualType T = SemaRef.GetTypeFromParser(Arg.getAsType(), &DI); if (!DI) - DI = SemaRef.Context.getTrivialDeclaratorInfo(T, Arg.getLocation()); + DI = SemaRef.Context.getTrivialTypeSourceInfo(T, Arg.getLocation()); return TemplateArgumentLoc(TemplateArgument(T), DI); } @@ -447,7 +351,7 @@ static TemplateArgumentLoc translateTemplateArgument(Sema &SemaRef, } } - llvm::llvm_unreachable("Unhandled parsed template argument"); + llvm_unreachable("Unhandled parsed template argument"); return TemplateArgumentLoc(); } @@ -515,10 +419,10 @@ void Sema::ActOnTypeParameterDefault(DeclPtrTy TypeParam, TemplateTypeParmDecl *Parm = cast(TypeParam.getAs()); - DeclaratorInfo *DefaultDInfo; - GetTypeFromParser(DefaultT, &DefaultDInfo); + TypeSourceInfo *DefaultTInfo; + GetTypeFromParser(DefaultT, &DefaultTInfo); - assert(DefaultDInfo && "expected source information for type"); + assert(DefaultTInfo && "expected source information for type"); // C++0x [temp.param]p9: // A default template-argument may be specified for any kind of @@ -533,12 +437,12 @@ void Sema::ActOnTypeParameterDefault(DeclPtrTy TypeParam, // FIXME: Implement this check! Needs a recursive walk over the types. // Check the template argument itself. - if (CheckTemplateArgument(Parm, DefaultDInfo)) { + if (CheckTemplateArgument(Parm, DefaultTInfo)) { Parm->setInvalidDecl(); return; } - Parm->setDefaultArgument(DefaultDInfo, false); + Parm->setDefaultArgument(DefaultTInfo, false); } /// \brief Check that the type of a non-type template parameter is @@ -592,8 +496,8 @@ Sema::CheckNonTypeTemplateParameterType(QualType T, SourceLocation Loc) { Sema::DeclPtrTy Sema::ActOnNonTypeTemplateParameter(Scope *S, Declarator &D, unsigned Depth, unsigned Position) { - DeclaratorInfo *DInfo = 0; - QualType T = GetTypeForDeclarator(D, S, &DInfo); + TypeSourceInfo *TInfo = 0; + QualType T = GetTypeForDeclarator(D, S, &TInfo); assert(S->isTemplateParamScope() && "Non-type template parameter not in template parameter scope!"); @@ -615,7 +519,7 @@ Sema::DeclPtrTy Sema::ActOnNonTypeTemplateParameter(Scope *S, Declarator &D, NonTypeTemplateParmDecl *Param = NonTypeTemplateParmDecl::Create(Context, CurContext, D.getIdentifierLoc(), - Depth, Position, ParamName, T, DInfo); + Depth, Position, ParamName, T, TInfo); if (Invalid) Param->setInvalidDecl(); @@ -1266,8 +1170,27 @@ Sema::MatchTemplateParametersToScopeSpecifier(SourceLocation DeclStartLoc, ExplicitSpecializationsInSpecifier; for (NestedNameSpecifier *NNS = (NestedNameSpecifier *)SS.getScopeRep(); NNS; NNS = NNS->getPrefix()) { + const Type *T = NNS->getAsType(); + if (!T) break; + + // C++0x [temp.expl.spec]p17: + // A member or a member template may be nested within many + // enclosing class templates. In an explicit specialization for + // such a member, the member declaration shall be preceded by a + // template<> for each enclosing class template that is + // explicitly specialized. + // We interpret this as forbidding typedefs of template + // specializations in the scope specifiers of out-of-line decls. + if (const TypedefType *TT = dyn_cast(T)) { + const Type *UnderlyingT = TT->LookThroughTypedefs().getTypePtr(); + if (isa(UnderlyingT)) + // FIXME: better source location information. + Diag(DeclStartLoc, diag::err_typedef_in_def_scope) << QualType(T,0); + T = UnderlyingT; + } + if (const TemplateSpecializationType *SpecType - = dyn_cast_or_null(NNS->getAsType())) { + = dyn_cast(T)) { TemplateDecl *Template = SpecType->getTemplateName().getAsTemplateDecl(); if (!Template) continue; // FIXME: should this be an error? probably... @@ -1481,7 +1404,7 @@ Sema::ActOnTemplateIdType(TemplateTy TemplateD, SourceLocation TemplateLoc, if (Result.isNull()) return true; - DeclaratorInfo *DI = Context.CreateDeclaratorInfo(Result); + TypeSourceInfo *DI = Context.CreateTypeSourceInfo(Result); TemplateSpecializationTypeLoc TL = cast(DI->getTypeLoc()); TL.setTemplateNameLoc(TemplateLoc); @@ -1501,7 +1424,7 @@ Sema::TypeResult Sema::ActOnTagTemplateIdType(TypeResult TypeResult, return Sema::TypeResult(); // FIXME: preserve source info, ideally without copying the DI. - DeclaratorInfo *DI; + TypeSourceInfo *DI; QualType Type = GetTypeFromParser(TypeResult.get(), &DI); // Verify the tag specifier. @@ -1687,7 +1610,7 @@ bool Sema::CheckTemplateTypeArgument(TemplateTypeParmDecl *Param, return true; } - if (CheckTemplateArgument(Param, AL.getSourceDeclaratorInfo())) + if (CheckTemplateArgument(Param, AL.getTypeSourceInfo())) return true; // Add the converted template type argument. @@ -1718,14 +1641,14 @@ bool Sema::CheckTemplateTypeArgument(TemplateTypeParmDecl *Param, /// parameters that precede \p Param in the template parameter list. /// /// \returns the substituted template argument, or NULL if an error occurred. -static DeclaratorInfo * +static TypeSourceInfo * SubstDefaultTemplateArgument(Sema &SemaRef, TemplateDecl *Template, SourceLocation TemplateLoc, SourceLocation RAngleLoc, TemplateTypeParmDecl *Param, TemplateArgumentListBuilder &Converted) { - DeclaratorInfo *ArgType = Param->getDefaultArgumentInfo(); + TypeSourceInfo *ArgType = Param->getDefaultArgumentInfo(); // If the argument type is dependent, instantiate it now based // on the previously-computed template arguments. @@ -1851,7 +1774,7 @@ Sema::SubstDefaultTemplateArgumentIfAvailable(TemplateDecl *Template, if (!TypeParm->hasDefaultArgument()) return TemplateArgumentLoc(); - DeclaratorInfo *DI = SubstDefaultTemplateArgument(*this, Template, + TypeSourceInfo *DI = SubstDefaultTemplateArgument(*this, Template, TemplateLoc, RAngleLoc, TypeParm, @@ -2012,7 +1935,7 @@ bool Sema::CheckTemplateArgument(NamedDecl *Param, } case TemplateArgument::Pack: - llvm::llvm_unreachable("Caller must expand template argument packs"); + llvm_unreachable("Caller must expand template argument packs"); break; } @@ -2065,16 +1988,16 @@ bool Sema::CheckTemplateArgument(NamedDecl *Param, return true; case TemplateArgument::Declaration: - llvm::llvm_unreachable( + llvm_unreachable( "Declaration argument with template template parameter"); break; case TemplateArgument::Integral: - llvm::llvm_unreachable( + llvm_unreachable( "Integral argument with template template parameter"); break; case TemplateArgument::Pack: - llvm::llvm_unreachable("Caller must expand template argument packs"); + llvm_unreachable("Caller must expand template argument packs"); break; } @@ -2168,7 +2091,7 @@ bool Sema::CheckTemplateArgumentList(TemplateDecl *Template, break; } - DeclaratorInfo *ArgType = SubstDefaultTemplateArgument(*this, + TypeSourceInfo *ArgType = SubstDefaultTemplateArgument(*this, Template, TemplateLoc, RAngleLoc, @@ -2240,8 +2163,8 @@ bool Sema::CheckTemplateArgumentList(TemplateDecl *Template, /// This routine implements the semantics of C++ [temp.arg.type]. It /// returns true if an error occurred, and false otherwise. bool Sema::CheckTemplateArgument(TemplateTypeParmDecl *Param, - DeclaratorInfo *ArgInfo) { - assert(ArgInfo && "invalid DeclaratorInfo"); + TypeSourceInfo *ArgInfo) { + assert(ArgInfo && "invalid TypeSourceInfo"); QualType Arg = ArgInfo->getType(); // C++ [temp.arg.type]p2: @@ -4469,8 +4392,7 @@ Sema::DeclResult Sema::ActOnExplicitInstantiation(Scope *S, if (D.getDeclSpec().isInlineSpecified() && getLangOptions().CPlusPlus0x) Diag(D.getDeclSpec().getInlineSpecLoc(), diag::err_explicit_instantiation_inline) - << CodeModificationHint::CreateRemoval( - SourceRange(D.getDeclSpec().getInlineSpecLoc())); + <( - Previous.getAsSingleDecl(Context)); + VarDecl *Prev = Previous.getAsSingle(); if (!Prev || !Prev->isStaticDataMember()) { // We expect to see a data data member here. Diag(D.getIdentifierLoc(), diag::err_explicit_instantiation_not_known) @@ -4793,7 +4714,7 @@ Sema::CheckTypenameType(NestedNameSpecifier *NNS, const IdentifierInfo &II, break; case LookupResult::FoundUnresolvedValue: - llvm::llvm_unreachable("unresolved using decl in non-dependent context"); + llvm_unreachable("unresolved using decl in non-dependent context"); return QualType(); case LookupResult::FoundOverloaded: diff --git a/lib/Sema/SemaTemplateDeduction.cpp b/lib/Sema/SemaTemplateDeduction.cpp index 613ffde5734a..b4754db7d6b5 100644 --- a/lib/Sema/SemaTemplateDeduction.cpp +++ b/lib/Sema/SemaTemplateDeduction.cpp @@ -2361,6 +2361,7 @@ MarkUsedTemplateParameters(Sema &SemaRef, QualType T, case Type::Enum: case Type::ObjCInterface: case Type::ObjCObjectPointer: + case Type::UnresolvedUsing: #define TYPE(Class, Base) #define ABSTRACT_TYPE(Class, Base) #define DEPENDENT_TYPE(Class, Base) diff --git a/lib/Sema/SemaTemplateInstantiate.cpp b/lib/Sema/SemaTemplateInstantiate.cpp index 623cde87a9c8..dddb93c87e3f 100644 --- a/lib/Sema/SemaTemplateInstantiate.cpp +++ b/lib/Sema/SemaTemplateInstantiate.cpp @@ -544,7 +544,7 @@ namespace { /// \brief Rebuild the exception declaration and register the declaration /// as an instantiated local. VarDecl *RebuildExceptionDecl(VarDecl *ExceptionDecl, QualType T, - DeclaratorInfo *Declarator, + TypeSourceInfo *Declarator, IdentifierInfo *Name, SourceLocation Loc, SourceRange TypeRange); @@ -552,13 +552,10 @@ namespace { /// elaborated type. QualType RebuildElaboratedType(QualType T, ElaboratedType::TagKind Tag); - Sema::OwningExprResult TransformPredefinedExpr(PredefinedExpr *E, - bool isAddressOfOperand); - Sema::OwningExprResult TransformDeclRefExpr(DeclRefExpr *E, - bool isAddressOfOperand); + Sema::OwningExprResult TransformPredefinedExpr(PredefinedExpr *E); + Sema::OwningExprResult TransformDeclRefExpr(DeclRefExpr *E); - Sema::OwningExprResult TransformCXXDefaultArgExpr(CXXDefaultArgExpr *E, - bool isAddressOfOperand); + Sema::OwningExprResult TransformCXXDefaultArgExpr(CXXDefaultArgExpr *E); /// \brief Transforms a template type parameter type by performing /// substitution of the corresponding template type argument. @@ -632,7 +629,7 @@ TemplateInstantiator::TransformFirstQualifierInScope(NamedDecl *D, VarDecl * TemplateInstantiator::RebuildExceptionDecl(VarDecl *ExceptionDecl, QualType T, - DeclaratorInfo *Declarator, + TypeSourceInfo *Declarator, IdentifierInfo *Name, SourceLocation Loc, SourceRange TypeRange) { @@ -670,8 +667,7 @@ TemplateInstantiator::RebuildElaboratedType(QualType T, } Sema::OwningExprResult -TemplateInstantiator::TransformPredefinedExpr(PredefinedExpr *E, - bool isAddressOfOperand) { +TemplateInstantiator::TransformPredefinedExpr(PredefinedExpr *E) { if (!E->isTypeDependent()) return SemaRef.Owned(E->Retain()); @@ -694,8 +690,7 @@ TemplateInstantiator::TransformPredefinedExpr(PredefinedExpr *E, } Sema::OwningExprResult -TemplateInstantiator::TransformDeclRefExpr(DeclRefExpr *E, - bool isAddressOfOperand) { +TemplateInstantiator::TransformDeclRefExpr(DeclRefExpr *E) { // FIXME: Clean this up a bit NamedDecl *D = E->getDecl(); if (NonTypeTemplateParmDecl *NTTP = dyn_cast(D)) { @@ -782,29 +777,11 @@ TemplateInstantiator::TransformDeclRefExpr(DeclRefExpr *E, // FindInstantiatedDecl will find it in the local instantiation scope. } - NamedDecl *InstD = SemaRef.FindInstantiatedDecl(D, TemplateArgs); - if (!InstD) - return SemaRef.ExprError(); - - assert(!isa(InstD) && "decl ref instantiated to UsingDecl"); - - CXXScopeSpec SS; - NestedNameSpecifier *Qualifier = 0; - if (E->getQualifier()) { - Qualifier = TransformNestedNameSpecifier(E->getQualifier(), - E->getQualifierRange()); - if (!Qualifier) - return SemaRef.ExprError(); - - SS.setScopeRep(Qualifier); - SS.setRange(E->getQualifierRange()); - } - - return SemaRef.BuildDeclarationNameExpr(SS, E->getLocation(), InstD); + return TreeTransform::TransformDeclRefExpr(E); } Sema::OwningExprResult TemplateInstantiator::TransformCXXDefaultArgExpr( - CXXDefaultArgExpr *E, bool isAddressOfOperand) { + CXXDefaultArgExpr *E) { assert(!cast(E->getParam()->getDeclContext())-> getDescribedFunctionTemplate() && "Default arg expressions are never formed in dependent cases."); @@ -889,7 +866,7 @@ TemplateInstantiator::TransformTemplateTypeParmType(TypeLocBuilder &TLB, /// /// \returns If the instantiation succeeds, the instantiated /// type. Otherwise, produces diagnostics and returns a NULL type. -DeclaratorInfo *Sema::SubstType(DeclaratorInfo *T, +TypeSourceInfo *Sema::SubstType(TypeSourceInfo *T, const MultiLevelTemplateArgumentList &Args, SourceLocation Loc, DeclarationName Entity) { @@ -936,6 +913,13 @@ Sema::SubstBaseSpecifiers(CXXRecordDecl *Instantiation, Base = Pattern->bases_begin(), BaseEnd = Pattern->bases_end(); Base != BaseEnd; ++Base) { if (!Base->getType()->isDependentType()) { + const CXXRecordDecl *BaseDecl = + cast(Base->getType()->getAs()->getDecl()); + + // Make sure to set the attributes from the base. + SetClassDeclAttributesFromBase(Instantiation, BaseDecl, + Base->isVirtual()); + InstantiatedBases.push_back(new (Context) CXXBaseSpecifier(*Base)); continue; } @@ -1053,12 +1037,10 @@ Sema::InstantiateClass(SourceLocation PointOfInstantiation, Member != MemberEnd; ++Member) { Decl *NewMember = SubstDecl(*Member, Instantiation, TemplateArgs); if (NewMember) { - if (NewMember->isInvalidDecl()) { - Invalid = true; - } else if (FieldDecl *Field = dyn_cast(NewMember)) + if (FieldDecl *Field = dyn_cast(NewMember)) Fields.push_back(DeclPtrTy::make(Field)); - else if (UsingDecl *UD = dyn_cast(NewMember)) - Instantiation->addDecl(UD); + else if (NewMember->isInvalidDecl()) + Invalid = true; } else { // FIXME: Eventually, a NULL return will mean that one of the // instantiations was a semantic disaster, and we'll want to set Invalid = @@ -1070,13 +1052,10 @@ Sema::InstantiateClass(SourceLocation PointOfInstantiation, ActOnFields(0, Instantiation->getLocation(), DeclPtrTy::make(Instantiation), Fields.data(), Fields.size(), SourceLocation(), SourceLocation(), 0); + CheckCompletedCXXClass(Instantiation); if (Instantiation->isInvalidDecl()) Invalid = true; - // Add any implicitly-declared members that we might need. - if (!Invalid) - AddImplicitlyDeclaredMembersToClass(Instantiation); - // Exit the scope of this instantiation. CurContext = PreviousContext; diff --git a/lib/Sema/SemaTemplateInstantiateDecl.cpp b/lib/Sema/SemaTemplateInstantiateDecl.cpp index a1258572ccb4..8d74bd76ca5c 100644 --- a/lib/Sema/SemaTemplateInstantiateDecl.cpp +++ b/lib/Sema/SemaTemplateInstantiateDecl.cpp @@ -16,6 +16,7 @@ #include "clang/AST/DeclTemplate.h" #include "clang/AST/DeclVisitor.h" #include "clang/AST/Expr.h" +#include "clang/AST/ExprCXX.h" #include "clang/Basic/PrettyStackTrace.h" #include "clang/Lex/Preprocessor.h" @@ -66,6 +67,8 @@ namespace { Decl *VisitNonTypeTemplateParmDecl(NonTypeTemplateParmDecl *D); Decl *VisitTemplateTemplateParmDecl(TemplateTemplateParmDecl *D); Decl *VisitUsingDirectiveDecl(UsingDirectiveDecl *D); + Decl *VisitUsingDecl(UsingDecl *D); + Decl *VisitUsingShadowDecl(UsingShadowDecl *D); Decl *VisitUnresolvedUsingValueDecl(UnresolvedUsingValueDecl *D); Decl *VisitUnresolvedUsingTypenameDecl(UnresolvedUsingTypenameDecl *D); @@ -125,13 +128,13 @@ TemplateDeclInstantiator::VisitNamespaceDecl(NamespaceDecl *D) { Decl *TemplateDeclInstantiator::VisitTypedefDecl(TypedefDecl *D) { bool Invalid = false; - DeclaratorInfo *DI = D->getTypeDeclaratorInfo(); + TypeSourceInfo *DI = D->getTypeSourceInfo(); if (DI->getType()->isDependentType()) { DI = SemaRef.SubstType(DI, TemplateArgs, D->getLocation(), D->getDeclName()); if (!DI) { Invalid = true; - DI = SemaRef.Context.getTrivialDeclaratorInfo(SemaRef.Context.IntTy); + DI = SemaRef.Context.getTrivialTypeSourceInfo(SemaRef.Context.IntTy); } } @@ -147,9 +150,38 @@ Decl *TemplateDeclInstantiator::VisitTypedefDecl(TypedefDecl *D) { return Typedef; } +/// \brief Instantiate the arguments provided as part of initialization. +/// +/// \returns true if an error occurred, false otherwise. +static bool InstantiateInitializationArguments(Sema &SemaRef, + Expr **Args, unsigned NumArgs, + const MultiLevelTemplateArgumentList &TemplateArgs, + llvm::SmallVectorImpl &FakeCommaLocs, + ASTOwningVector<&ActionBase::DeleteExpr> &InitArgs) { + for (unsigned I = 0; I != NumArgs; ++I) { + // When we hit the first defaulted argument, break out of the loop: + // we don't pass those default arguments on. + if (Args[I]->isDefaultArgument()) + break; + + Sema::OwningExprResult Arg = SemaRef.SubstExpr(Args[I], TemplateArgs); + if (Arg.isInvalid()) + return true; + + Expr *ArgExpr = (Expr *)Arg.get(); + InitArgs.push_back(Arg.release()); + + // FIXME: We're faking all of the comma locations. Do we need them? + FakeCommaLocs.push_back( + SemaRef.PP.getLocForEndOfToken(ArgExpr->getLocEnd())); + } + + return false; +} + Decl *TemplateDeclInstantiator::VisitVarDecl(VarDecl *D) { // Do substitution on the type of the declaration - DeclaratorInfo *DI = SemaRef.SubstType(D->getDeclaratorInfo(), + TypeSourceInfo *DI = SemaRef.SubstType(D->getTypeSourceInfo(), TemplateArgs, D->getTypeSpecStartLoc(), D->getDeclName()); @@ -193,48 +225,82 @@ Decl *TemplateDeclInstantiator::VisitVarDecl(VarDecl *D) { TSK_ImplicitInstantiation); if (D->getInit()) { - OwningExprResult Init - = SemaRef.SubstExpr(D->getInit(), TemplateArgs); - if (Init.isInvalid()) - Var->setInvalidDecl(); - else if (!D->getType()->isDependentType() && - !D->getInit()->isTypeDependent() && - !D->getInit()->isValueDependent()) { - // If neither the declaration's type nor its initializer are dependent, - // we don't want to redo all the checking, especially since the - // initializer might have been wrapped by a CXXConstructExpr since we did - // it the first time. - Var->setType(D->getType()); - Var->setInit(SemaRef.Context, Init.takeAs()); - } - else if (ParenListExpr *PLE = dyn_cast((Expr *)Init.get())) { - // FIXME: We're faking all of the comma locations, which is suboptimal. - // Do we even need these comma locations? - llvm::SmallVector FakeCommaLocs; - if (PLE->getNumExprs() > 0) { - FakeCommaLocs.reserve(PLE->getNumExprs() - 1); - for (unsigned I = 0, N = PLE->getNumExprs() - 1; I != N; ++I) { - Expr *E = PLE->getExpr(I)->Retain(); - FakeCommaLocs.push_back( - SemaRef.PP.getLocForEndOfToken(E->getLocEnd())); - } - PLE->getExpr(PLE->getNumExprs() - 1)->Retain(); + if (Var->isStaticDataMember() && !D->isOutOfLine()) + SemaRef.PushExpressionEvaluationContext(Sema::Unevaluated); + else + SemaRef.PushExpressionEvaluationContext(Sema::PotentiallyEvaluated); + + // Extract the initializer, skipping through any temporary-binding + // expressions and look at the subexpression as it was written. + Expr *DInit = D->getInit(); + while (CXXBindTemporaryExpr *Binder = dyn_cast(DInit)) + DInit = Binder->getSubExpr(); + if (ImplicitCastExpr *ICE = dyn_cast(DInit)) + DInit = ICE->getSubExprAsWritten(); + + if (ParenListExpr *PLE = dyn_cast(DInit)) { + // The initializer is a parenthesized list of expressions that is + // type-dependent. Instantiate each of the expressions; we'll be + // performing direct initialization with them. + llvm::SmallVector CommaLocs; + ASTOwningVector<&ActionBase::DeleteExpr> InitArgs(SemaRef); + if (!InstantiateInitializationArguments(SemaRef, + PLE->getExprs(), + PLE->getNumExprs(), + TemplateArgs, + CommaLocs, InitArgs)) { + // Add the direct initializer to the declaration. + SemaRef.AddCXXDirectInitializerToDecl(Sema::DeclPtrTy::make(Var), + PLE->getLParenLoc(), + move_arg(InitArgs), + CommaLocs.data(), + PLE->getRParenLoc()); } + } else if (CXXConstructExpr *Construct =dyn_cast(DInit)) { + // The initializer resolved to a constructor. Instantiate the constructor + // arguments. + llvm::SmallVector CommaLocs; + ASTOwningVector<&ActionBase::DeleteExpr> InitArgs(SemaRef); + + if (!InstantiateInitializationArguments(SemaRef, + Construct->getArgs(), + Construct->getNumArgs(), + TemplateArgs, + CommaLocs, InitArgs)) { + if (D->hasCXXDirectInitializer()) { + SourceLocation FakeLParenLoc = + SemaRef.PP.getLocForEndOfToken(D->getLocation()); + SourceLocation FakeRParenLoc = CommaLocs.empty()? FakeLParenLoc + : CommaLocs.back(); + SemaRef.AddCXXDirectInitializerToDecl(Sema::DeclPtrTy::make(Var), + FakeLParenLoc, + move_arg(InitArgs), + CommaLocs.data(), + FakeRParenLoc); + } else if (InitArgs.size() == 1) { + Expr *Init = (Expr*)(InitArgs.take()[0]); + SemaRef.AddInitializerToDecl(Sema::DeclPtrTy::make(Var), + SemaRef.Owned(Init), + false); + } else { + assert(InitArgs.size() == 0); + SemaRef.ActOnUninitializedDecl(Sema::DeclPtrTy::make(Var), false); + } + } + } else { + OwningExprResult Init + = SemaRef.SubstExpr(D->getInit(), TemplateArgs); - // Add the direct initializer to the declaration. - SemaRef.AddCXXDirectInitializerToDecl(Sema::DeclPtrTy::make(Var), - PLE->getLParenLoc(), - Sema::MultiExprArg(SemaRef, - (void**)PLE->getExprs(), - PLE->getNumExprs()), - FakeCommaLocs.data(), - PLE->getRParenLoc()); - - // When Init is destroyed, it will destroy the instantiated ParenListExpr; - // we've explicitly retained all of its subexpressions already. - } else - SemaRef.AddInitializerToDecl(Sema::DeclPtrTy::make(Var), move(Init), - D->hasCXXDirectInitializer()); + // FIXME: Not happy about invalidating decls just because of a bad + // initializer, unless it affects the type. + if (Init.isInvalid()) + Var->setInvalidDecl(); + else + SemaRef.AddInitializerToDecl(Sema::DeclPtrTy::make(Var), move(Init), + D->hasCXXDirectInitializer()); + } + + SemaRef.PopExpressionEvaluationContext(); } else if (!Var->isStaticDataMember() || Var->isOutOfLine()) SemaRef.ActOnUninitializedDecl(Sema::DeclPtrTy::make(Var), false); @@ -243,12 +309,12 @@ Decl *TemplateDeclInstantiator::VisitVarDecl(VarDecl *D) { Decl *TemplateDeclInstantiator::VisitFieldDecl(FieldDecl *D) { bool Invalid = false; - DeclaratorInfo *DI = D->getDeclaratorInfo(); + TypeSourceInfo *DI = D->getTypeSourceInfo(); if (DI->getType()->isDependentType()) { DI = SemaRef.SubstType(DI, TemplateArgs, D->getLocation(), D->getDeclName()); if (!DI) { - DI = D->getDeclaratorInfo(); + DI = D->getTypeSourceInfo(); Invalid = true; } else if (DI->getType()->isFunctionType()) { // C++ [temp.arg.type]p3: @@ -561,7 +627,12 @@ TemplateDeclInstantiator::VisitFunctionTemplateDecl(FunctionTemplateDecl *D) { InstTemplate->setAccess(D->getAccess()); assert(InstTemplate && "VisitFunctionDecl/CXXMethodDecl didn't create a template!"); - if (!InstTemplate->getInstantiatedFromMemberTemplate()) + + // Link the instantiation back to the pattern *unless* this is a + // non-definition friend declaration. + if (!InstTemplate->getInstantiatedFromMemberTemplate() && + !(InstTemplate->getFriendObjectKind() && + !D->getTemplatedDecl()->isThisDeclarationADefinition())) InstTemplate->setInstantiatedFromMemberTemplate(D); // Add non-friends into the owner. @@ -638,7 +709,7 @@ Decl *TemplateDeclInstantiator::VisitCXXRecordDecl(CXXRecordDecl *D) { TemplateArgs); FunctionDecl *Function = FunctionDecl::Create(SemaRef.Context, DC, D->getLocation(), - D->getDeclName(), T, D->getDeclaratorInfo(), + D->getDeclName(), T, D->getTypeSourceInfo(), D->getStorageClass(), D->isInlineSpecified(), D->hasWrittenPrototype()); Function->setLexicalDeclContext(Owner); @@ -700,7 +771,8 @@ Decl *TemplateDeclInstantiator::VisitCXXRecordDecl(CXXRecordDecl *D) { Previous.clear(); } - SemaRef.CheckFunctionDeclaration(Function, Previous, false, Redeclaration, + SemaRef.CheckFunctionDeclaration(/*Scope*/ 0, Function, Previous, + false, Redeclaration, /*FIXME:*/OverloadableAttrRequired); // If the original function was part of a friend declaration, @@ -771,7 +843,7 @@ TemplateDeclInstantiator::VisitCXXMethodDecl(CXXMethodDecl *D, Method = CXXConstructorDecl::Create(SemaRef.Context, Record, Constructor->getLocation(), Name, T, - Constructor->getDeclaratorInfo(), + Constructor->getTypeSourceInfo(), Constructor->isExplicit(), Constructor->isInlineSpecified(), false); } else if (CXXDestructorDecl *Destructor = dyn_cast(D)) { @@ -789,12 +861,12 @@ TemplateDeclInstantiator::VisitCXXMethodDecl(CXXMethodDecl *D, ConvTy); Method = CXXConversionDecl::Create(SemaRef.Context, Record, Conversion->getLocation(), Name, - T, Conversion->getDeclaratorInfo(), + T, Conversion->getTypeSourceInfo(), Conversion->isInlineSpecified(), Conversion->isExplicit()); } else { Method = CXXMethodDecl::Create(SemaRef.Context, Record, D->getLocation(), - D->getDeclName(), T, D->getDeclaratorInfo(), + D->getDeclName(), T, D->getTypeSourceInfo(), D->isStatic(), D->isInlineSpecified()); } @@ -860,15 +932,16 @@ TemplateDeclInstantiator::VisitCXXMethodDecl(CXXMethodDecl *D, bool Redeclaration = false; bool OverloadableAttrRequired = false; - SemaRef.CheckFunctionDeclaration(Method, Previous, false, Redeclaration, + SemaRef.CheckFunctionDeclaration(0, Method, Previous, false, Redeclaration, /*FIXME:*/OverloadableAttrRequired); + if (D->isPure()) + SemaRef.CheckPureMethod(Method, SourceRange()); + if (!FunctionTemplate && (!Method->isInvalidDecl() || Previous.empty()) && !Method->getFriendObjectKind()) Owner->addDecl(Method); - SemaRef.AddOverriddenMethods(Record, Method); - return Method; } @@ -886,7 +959,7 @@ Decl *TemplateDeclInstantiator::VisitCXXConversionDecl(CXXConversionDecl *D) { ParmVarDecl *TemplateDeclInstantiator::VisitParmVarDecl(ParmVarDecl *D) { QualType T; - DeclaratorInfo *DI = D->getDeclaratorInfo(); + TypeSourceInfo *DI = D->getTypeSourceInfo(); if (DI) { DI = SemaRef.SubstType(DI, TemplateArgs, D->getLocation(), D->getDeclName()); @@ -948,7 +1021,7 @@ Decl *TemplateDeclInstantiator::VisitNonTypeTemplateParmDecl( NonTypeTemplateParmDecl *D) { // Substitute into the type of the non-type template parameter. QualType T; - DeclaratorInfo *DI = D->getDeclaratorInfo(); + TypeSourceInfo *DI = D->getTypeSourceInfo(); if (DI) { DI = SemaRef.SubstType(DI, TemplateArgs, D->getLocation(), D->getDeclName()); @@ -1027,6 +1100,80 @@ Decl *TemplateDeclInstantiator::VisitUsingDirectiveDecl(UsingDirectiveDecl *D) { return Inst; } +Decl *TemplateDeclInstantiator::VisitUsingDecl(UsingDecl *D) { + // The nested name specifier is non-dependent, so no transformation + // is required. + + // We only need to do redeclaration lookups if we're in a class + // scope (in fact, it's not really even possible in non-class + // scopes). + bool CheckRedeclaration = Owner->isRecord(); + + LookupResult Prev(SemaRef, D->getDeclName(), D->getLocation(), + Sema::LookupUsingDeclName, Sema::ForRedeclaration); + + UsingDecl *NewUD = UsingDecl::Create(SemaRef.Context, Owner, + D->getLocation(), + D->getNestedNameRange(), + D->getUsingLocation(), + D->getTargetNestedNameDecl(), + D->getDeclName(), + D->isTypeName()); + + CXXScopeSpec SS; + SS.setScopeRep(D->getTargetNestedNameDecl()); + SS.setRange(D->getNestedNameRange()); + + if (CheckRedeclaration) { + Prev.setHideTags(false); + SemaRef.LookupQualifiedName(Prev, Owner); + + // Check for invalid redeclarations. + if (SemaRef.CheckUsingDeclRedeclaration(D->getUsingLocation(), + D->isTypeName(), SS, + D->getLocation(), Prev)) + NewUD->setInvalidDecl(); + + } + + if (!NewUD->isInvalidDecl() && + SemaRef.CheckUsingDeclQualifier(D->getUsingLocation(), SS, + D->getLocation())) + NewUD->setInvalidDecl(); + + SemaRef.Context.setInstantiatedFromUsingDecl(NewUD, D); + NewUD->setAccess(D->getAccess()); + Owner->addDecl(NewUD); + + // Don't process the shadow decls for an invalid decl. + if (NewUD->isInvalidDecl()) + return NewUD; + + // Process the shadow decls. + for (UsingDecl::shadow_iterator I = D->shadow_begin(), E = D->shadow_end(); + I != E; ++I) { + UsingShadowDecl *Shadow = *I; + NamedDecl *InstTarget = + cast(SemaRef.FindInstantiatedDecl(Shadow->getTargetDecl(), + TemplateArgs)); + + if (CheckRedeclaration && + SemaRef.CheckUsingShadowDecl(NewUD, InstTarget, Prev)) + continue; + + UsingShadowDecl *InstShadow + = SemaRef.BuildUsingShadowDecl(/*Scope*/ 0, NewUD, InstTarget); + SemaRef.Context.setInstantiatedFromUsingShadowDecl(InstShadow, Shadow); + } + + return NewUD; +} + +Decl *TemplateDeclInstantiator::VisitUsingShadowDecl(UsingShadowDecl *D) { + // Ignore these; we handle them in bulk when processing the UsingDecl. + return 0; +} + Decl * TemplateDeclInstantiator ::VisitUnresolvedUsingTypenameDecl(UnresolvedUsingTypenameDecl *D) { NestedNameSpecifier *NNS = @@ -1047,8 +1194,8 @@ Decl * TemplateDeclInstantiator /*instantiation*/ true, /*typename*/ true, D->getTypenameLoc()); if (UD) - SemaRef.Context.setInstantiatedFromUnresolvedUsingDecl(cast(UD), - D); + SemaRef.Context.setInstantiatedFromUsingDecl(cast(UD), D); + return UD; } @@ -1072,8 +1219,8 @@ Decl * TemplateDeclInstantiator /*instantiation*/ true, /*typename*/ false, SourceLocation()); if (UD) - SemaRef.Context.setInstantiatedFromUnresolvedUsingDecl(cast(UD), - D); + SemaRef.Context.setInstantiatedFromUsingDecl(cast(UD), D); + return UD; } @@ -1336,6 +1483,43 @@ TemplateDeclInstantiator::InitFunctionInstantiation(FunctionDecl *New, } } + const FunctionProtoType *Proto = Tmpl->getType()->getAs(); + assert(Proto && "Function template without prototype?"); + + if (Proto->hasExceptionSpec() || Proto->hasAnyExceptionSpec() || + Proto->getNoReturnAttr()) { + // The function has an exception specification or a "noreturn" + // attribute. Substitute into each of the exception types. + llvm::SmallVector Exceptions; + for (unsigned I = 0, N = Proto->getNumExceptions(); I != N; ++I) { + // FIXME: Poor location information! + QualType T + = SemaRef.SubstType(Proto->getExceptionType(I), TemplateArgs, + New->getLocation(), New->getDeclName()); + if (T.isNull() || + SemaRef.CheckSpecifiedExceptionType(T, New->getLocation())) + continue; + + Exceptions.push_back(T); + } + + // Rebuild the function type + + const FunctionProtoType *NewProto + = New->getType()->getAs(); + assert(NewProto && "Template instantiation without function prototype?"); + New->setType(SemaRef.Context.getFunctionType(NewProto->getResultType(), + NewProto->arg_type_begin(), + NewProto->getNumArgs(), + NewProto->isVariadic(), + NewProto->getTypeQuals(), + Proto->hasExceptionSpec(), + Proto->hasAnyExceptionSpec(), + Exceptions.size(), + Exceptions.data(), + Proto->getNoReturnAttr())); + } + return false; } @@ -1352,17 +1536,8 @@ TemplateDeclInstantiator::InitMethodInstantiation(CXXMethodDecl *New, CXXRecordDecl *Record = cast(Owner); New->setAccess(Tmpl->getAccess()); - if (Tmpl->isVirtualAsWritten()) { - New->setVirtualAsWritten(true); - Record->setAggregate(false); - Record->setPOD(false); - Record->setEmpty(false); - Record->setPolymorphic(true); - } - if (Tmpl->isPure()) { - New->setPure(); - Record->setAbstract(true); - } + if (Tmpl->isVirtualAsWritten()) + Record->setMethodAsVirtual(New); // FIXME: attributes // FIXME: New needs a pointer to Tmpl @@ -1623,14 +1798,19 @@ Sema::InstantiateMemInitializers(CXXConstructorDecl *New, MemInitResult NewInit; if (Init->isBaseInitializer()) { - QualType BaseType(Init->getBaseClass(), 0); - BaseType = SubstType(BaseType, TemplateArgs, Init->getSourceLocation(), - New->getDeclName()); - - NewInit = BuildBaseInitializer(BaseType, + TypeSourceInfo *BaseTInfo = SubstType(Init->getBaseClassInfo(), + TemplateArgs, + Init->getSourceLocation(), + New->getDeclName()); + if (!BaseTInfo) { + New->setInvalidDecl(); + continue; + } + + NewInit = BuildBaseInitializer(BaseTInfo->getType(), BaseTInfo, (Expr **)NewArgs.data(), NewArgs.size(), - Init->getSourceLocation(), + Init->getLParenLoc(), Init->getRParenLoc(), New->getParent()); } else if (Init->isMemberInitializer()) { @@ -1646,6 +1826,7 @@ Sema::InstantiateMemInitializers(CXXConstructorDecl *New, NewInit = BuildMemberInitializer(Member, (Expr **)NewArgs.data(), NewArgs.size(), Init->getSourceLocation(), + Init->getLParenLoc(), Init->getRParenLoc()); } @@ -1749,16 +1930,28 @@ static bool isInstantiationOf(EnumDecl *Pattern, return false; } +static bool isInstantiationOf(UsingShadowDecl *Pattern, + UsingShadowDecl *Instance, + ASTContext &C) { + return C.getInstantiatedFromUsingShadowDecl(Instance) == Pattern; +} + +static bool isInstantiationOf(UsingDecl *Pattern, + UsingDecl *Instance, + ASTContext &C) { + return C.getInstantiatedFromUsingDecl(Instance) == Pattern; +} + static bool isInstantiationOf(UnresolvedUsingValueDecl *Pattern, UsingDecl *Instance, ASTContext &C) { - return C.getInstantiatedFromUnresolvedUsingDecl(Instance) == Pattern; + return C.getInstantiatedFromUsingDecl(Instance) == Pattern; } static bool isInstantiationOf(UnresolvedUsingTypenameDecl *Pattern, UsingDecl *Instance, ASTContext &C) { - return C.getInstantiatedFromUnresolvedUsingDecl(Instance) == Pattern; + return C.getInstantiatedFromUsingDecl(Instance) == Pattern; } static bool isInstantiationOfStaticDataMember(VarDecl *Pattern, @@ -1776,6 +1969,8 @@ static bool isInstantiationOfStaticDataMember(VarDecl *Pattern, return false; } +// Other is the prospective instantiation +// D is the prospective pattern static bool isInstantiationOf(ASTContext &Ctx, NamedDecl *D, Decl *Other) { if (D->getKind() != Other->getKind()) { if (UnresolvedUsingTypenameDecl *UUD @@ -1827,6 +2022,12 @@ static bool isInstantiationOf(ASTContext &Ctx, NamedDecl *D, Decl *Other) { } } + if (UsingDecl *Using = dyn_cast(Other)) + return isInstantiationOf(cast(D), Using, Ctx); + + if (UsingShadowDecl *Shadow = dyn_cast(Other)) + return isInstantiationOf(cast(D), Shadow, Ctx); + return D->getDeclName() && isa(Other) && D->getDeclName() == cast(Other)->getDeclName(); } @@ -1979,7 +2180,10 @@ NamedDecl *Sema::FindInstantiatedDecl(NamedDecl *D, ParentDC->decls_end()); } - assert(Result && "Unable to find instantiation of declaration!"); + // UsingShadowDecls can instantiate to nothing because of using hiding. + assert((Result || isa(D)) + && "Unable to find instantiation of declaration!"); + D = Result; } diff --git a/lib/Sema/SemaType.cpp b/lib/Sema/SemaType.cpp index afce5e33ba6b..37f19f2be4c6 100644 --- a/lib/Sema/SemaType.cpp +++ b/lib/Sema/SemaType.cpp @@ -356,10 +356,14 @@ static QualType ConvertDeclSpecToType(Declarator &TheDeclarator, Sema &TheSema){ // or incomplete types shall not be restrict-qualified." C++ also allows // restrict-qualified references. if (TypeQuals & DeclSpec::TQ_restrict) { - if (Result->isPointerType() || Result->isReferenceType()) { - QualType EltTy = Result->isPointerType() ? - Result->getAs()->getPointeeType() : - Result->getAs()->getPointeeType(); + if (Result->isAnyPointerType() || Result->isReferenceType()) { + QualType EltTy; + if (Result->isObjCObjectPointerType()) + EltTy = Result; + else + EltTy = Result->isPointerType() ? + Result->getAs()->getPointeeType() : + Result->getAs()->getPointeeType(); // If we have a pointer or reference, the pointee must have an object // incomplete type. @@ -846,20 +850,20 @@ QualType Sema::BuildBlockPointerType(QualType T, unsigned CVR, return Context.getQualifiedType(Context.getBlockPointerType(T), Quals); } -QualType Sema::GetTypeFromParser(TypeTy *Ty, DeclaratorInfo **DInfo) { +QualType Sema::GetTypeFromParser(TypeTy *Ty, TypeSourceInfo **TInfo) { QualType QT = QualType::getFromOpaquePtr(Ty); if (QT.isNull()) { - if (DInfo) *DInfo = 0; + if (TInfo) *TInfo = 0; return QualType(); } - DeclaratorInfo *DI = 0; + TypeSourceInfo *DI = 0; if (LocInfoType *LIT = dyn_cast(QT)) { QT = LIT->getType(); - DI = LIT->getDeclaratorInfo(); + DI = LIT->getTypeSourceInfo(); } - if (DInfo) *DInfo = DI; + if (TInfo) *TInfo = DI; return QT; } @@ -870,7 +874,7 @@ QualType Sema::GetTypeFromParser(TypeTy *Ty, DeclaratorInfo **DInfo) { /// owns the declaration of a type (e.g., the definition of a struct /// type), then *OwnedDecl will receive the owned declaration. QualType Sema::GetTypeForDeclarator(Declarator &D, Scope *S, - DeclaratorInfo **DInfo, + TypeSourceInfo **TInfo, TagDecl **OwnedDecl) { // Determine the type of the declarator. Not all forms of declarator // have a type. @@ -897,6 +901,9 @@ QualType Sema::GetTypeForDeclarator(Declarator &D, Scope *S, break; } + if (T.isNull()) + return T; + if (T == Context.UndeducedAutoTy) { int Error = -1; @@ -1186,7 +1193,7 @@ QualType Sema::GetTypeForDeclarator(Declarator &D, Scope *S, case NestedNameSpecifier::Namespace: case NestedNameSpecifier::Global: - llvm::llvm_unreachable("Nested-name-specifier must name a type"); + llvm_unreachable("Nested-name-specifier must name a type"); break; case NestedNameSpecifier::TypeSpec: @@ -1256,11 +1263,11 @@ QualType Sema::GetTypeForDeclarator(Declarator &D, Scope *S, if (const AttributeList *Attrs = D.getAttributes()) ProcessTypeAttributeList(T, Attrs); - if (DInfo) { + if (TInfo) { if (D.isInvalidType()) - *DInfo = 0; + *TInfo = 0; else - *DInfo = GetDeclaratorInfoForDeclarator(D, T); + *TInfo = GetTypeSourceInfoForDeclarator(D, T); } return T; @@ -1326,18 +1333,18 @@ namespace { } } void VisitTemplateSpecializationTypeLoc(TemplateSpecializationTypeLoc TL) { - DeclaratorInfo *DInfo = 0; - Sema::GetTypeFromParser(DS.getTypeRep(), &DInfo); + TypeSourceInfo *TInfo = 0; + Sema::GetTypeFromParser(DS.getTypeRep(), &TInfo); // If we got no declarator info from previous Sema routines, // just fill with the typespec loc. - if (!DInfo) { + if (!TInfo) { TL.initialize(DS.getTypeSpecTypeLoc()); return; } TemplateSpecializationTypeLoc OldTL = - cast(DInfo->getTypeLoc()); + cast(TInfo->getTypeLoc()); TL.copy(OldTL); } void VisitTypeLoc(TypeLoc TL) { @@ -1353,7 +1360,7 @@ namespace { DeclaratorLocFiller(const DeclaratorChunk &Chunk) : Chunk(Chunk) {} void VisitQualifiedTypeLoc(QualifiedTypeLoc TL) { - llvm::llvm_unreachable("qualified type locs not expected here!"); + llvm_unreachable("qualified type locs not expected here!"); } void VisitBlockPointerTypeLoc(BlockPointerTypeLoc TL) { @@ -1408,18 +1415,18 @@ namespace { } void VisitTypeLoc(TypeLoc TL) { - llvm::llvm_unreachable("unsupported TypeLoc kind in declarator!"); + llvm_unreachable("unsupported TypeLoc kind in declarator!"); } }; } -/// \brief Create and instantiate a DeclaratorInfo with type source information. +/// \brief Create and instantiate a TypeSourceInfo with type source information. /// /// \param T QualType referring to the type as written in source code. -DeclaratorInfo * -Sema::GetDeclaratorInfoForDeclarator(Declarator &D, QualType T) { - DeclaratorInfo *DInfo = Context.CreateDeclaratorInfo(T); - UnqualTypeLoc CurrTL = DInfo->getTypeLoc().getUnqualifiedLoc(); +TypeSourceInfo * +Sema::GetTypeSourceInfoForDeclarator(Declarator &D, QualType T) { + TypeSourceInfo *TInfo = Context.CreateTypeSourceInfo(T); + UnqualTypeLoc CurrTL = TInfo->getTypeLoc().getUnqualifiedLoc(); for (unsigned i = 0, e = D.getNumTypeObjects(); i != e; ++i) { DeclaratorLocFiller(D.getTypeObject(i)).Visit(CurrTL); @@ -1428,16 +1435,16 @@ Sema::GetDeclaratorInfoForDeclarator(Declarator &D, QualType T) { TypeSpecLocFiller(D.getDeclSpec()).Visit(CurrTL); - return DInfo; + return TInfo; } -/// \brief Create a LocInfoType to hold the given QualType and DeclaratorInfo. -QualType Sema::CreateLocInfoType(QualType T, DeclaratorInfo *DInfo) { +/// \brief Create a LocInfoType to hold the given QualType and TypeSourceInfo. +QualType Sema::CreateLocInfoType(QualType T, TypeSourceInfo *TInfo) { // FIXME: LocInfoTypes are "transient", only needed for passing to/from Parser // and Sema during declaration parsing. Try deallocating/caching them when // it's appropriate, instead of allocating them and keeping them around. LocInfoType *LocT = (LocInfoType*)BumpAlloc.Allocate(sizeof(LocInfoType), 8); - new (LocT) LocInfoType(T, DInfo); + new (LocT) LocInfoType(T, TInfo); assert(LocT->getTypeClass() != T->getTypeClass() && "LocInfoType's TypeClass conflicts with an existing Type class"); return QualType(LocT, 0); @@ -1512,9 +1519,9 @@ Sema::TypeResult Sema::ActOnTypeName(Scope *S, Declarator &D) { // the parser. assert(D.getIdentifier() == 0 && "Type name should have no identifier!"); - DeclaratorInfo *DInfo = 0; + TypeSourceInfo *TInfo = 0; TagDecl *OwnedTag = 0; - QualType T = GetTypeForDeclarator(D, S, &DInfo, &OwnedTag); + QualType T = GetTypeForDeclarator(D, S, &TInfo, &OwnedTag); if (D.isInvalidType()) return true; @@ -1531,8 +1538,8 @@ Sema::TypeResult Sema::ActOnTypeName(Scope *S, Declarator &D) { << Context.getTypeDeclType(OwnedTag); } - if (DInfo) - T = CreateLocInfoType(T, DInfo); + if (TInfo) + T = CreateLocInfoType(T, TInfo); return T.getAsOpaquePtr(); } @@ -1640,6 +1647,53 @@ static void HandleNoReturnTypeAttribute(QualType &Type, Type = S.Context.getNoReturnType(Type); } +/// HandleVectorSizeAttribute - this attribute is only applicable to integral +/// and float scalars, although arrays, pointers, and function return values are +/// allowed in conjunction with this construct. Aggregates with this attribute +/// are invalid, even if they are of the same size as a corresponding scalar. +/// The raw attribute should contain precisely 1 argument, the vector size for +/// the variable, measured in bytes. If curType and rawAttr are well formed, +/// this routine will return a new vector type. +static void HandleVectorSizeAttr(QualType& CurType, const AttributeList &Attr, Sema &S) { + // Check the attribute arugments. + if (Attr.getNumArgs() != 1) { + S.Diag(Attr.getLoc(), diag::err_attribute_wrong_number_arguments) << 1; + return; + } + Expr *sizeExpr = static_cast(Attr.getArg(0)); + llvm::APSInt vecSize(32); + if (!sizeExpr->isIntegerConstantExpr(vecSize, S.Context)) { + S.Diag(Attr.getLoc(), diag::err_attribute_argument_not_int) + << "vector_size" << sizeExpr->getSourceRange(); + return; + } + // the base type must be integer or float, and can't already be a vector. + if (CurType->isVectorType() || + (!CurType->isIntegerType() && !CurType->isRealFloatingType())) { + S.Diag(Attr.getLoc(), diag::err_attribute_invalid_vector_type) << CurType; + return; + } + unsigned typeSize = static_cast(S.Context.getTypeSize(CurType)); + // vecSize is specified in bytes - convert to bits. + unsigned vectorSize = static_cast(vecSize.getZExtValue() * 8); + + // the vector size needs to be an integral multiple of the type size. + if (vectorSize % typeSize) { + S.Diag(Attr.getLoc(), diag::err_attribute_invalid_size) + << sizeExpr->getSourceRange(); + return; + } + if (vectorSize == 0) { + S.Diag(Attr.getLoc(), diag::err_attribute_zero_size) + << sizeExpr->getSourceRange(); + return; + } + + // Success! Instantiate the vector type, the number of elements is > 0, and + // not required to be a power of 2, unlike GCC. + CurType = S.Context.getVectorType(CurType, vectorSize/typeSize); +} + void Sema::ProcessTypeAttributeList(QualType &Result, const AttributeList *AL) { // Scan through and apply attributes to this type where it makes sense. Some // attributes (such as __address_space__, __vector_size__, etc) apply to the @@ -1659,6 +1713,9 @@ void Sema::ProcessTypeAttributeList(QualType &Result, const AttributeList *AL) { case AttributeList::AT_noreturn: HandleNoReturnTypeAttribute(Result, *AL, *this); break; + case AttributeList::AT_vector_size: + HandleVectorSizeAttr(Result, *AL, *this); + break; } } } diff --git a/lib/Sema/TreeTransform.h b/lib/Sema/TreeTransform.h index 28b217403564..fd1998734437 100644 --- a/lib/Sema/TreeTransform.h +++ b/lib/Sema/TreeTransform.h @@ -172,13 +172,23 @@ class TreeTransform { return T.isNull(); } + /// \brief Determine whether the given call argument should be dropped, e.g., + /// because it is a default argument. + /// + /// Subclasses can provide an alternative implementation of this routine to + /// determine which kinds of call arguments get dropped. By default, + /// CXXDefaultArgument nodes are dropped (prior to transformation). + bool DropCallArgument(Expr *E) { + return E->isDefaultArgument(); + } + /// \brief Transforms the given type into another type. /// /// By default, this routine transforms a type by creating a - /// DeclaratorInfo for it and delegating to the appropriate + /// TypeSourceInfo for it and delegating to the appropriate /// function. This is expensive, but we don't mind, because /// this method is deprecated anyway; all users should be - /// switched to storing DeclaratorInfos. + /// switched to storing TypeSourceInfos. /// /// \returns the transformed type. QualType TransformType(QualType T); @@ -191,7 +201,7 @@ class TreeTransform { /// may override this function (to take over all type /// transformations) or some set of the TransformXXXType functions /// to alter the transformation. - DeclaratorInfo *TransformType(DeclaratorInfo *DI); + TypeSourceInfo *TransformType(TypeSourceInfo *DI); /// \brief Transform the given type-with-location into a new /// type, collecting location information in the given builder @@ -218,19 +228,7 @@ class TreeTransform { /// other mechanism. /// /// \returns the transformed expression. - OwningExprResult TransformExpr(Expr *E) { - return getDerived().TransformExpr(E, /*isAddressOfOperand=*/false); - } - - /// \brief Transform the given expression. - /// - /// By default, this routine transforms an expression by delegating to the - /// appropriate TransformXXXExpr function to build a new expression. - /// Subclasses may override this function to transform expressions using some - /// other mechanism. - /// - /// \returns the transformed expression. - OwningExprResult TransformExpr(Expr *E, bool isAddressOfOperand); + OwningExprResult TransformExpr(Expr *E); /// \brief Transform the given declaration, which is referenced from a type /// or expression. @@ -301,9 +299,9 @@ class TreeTransform { void InventTemplateArgumentLoc(const TemplateArgument &Arg, TemplateArgumentLoc &ArgLoc); - /// \brief Fakes up a DeclaratorInfo for a type. - DeclaratorInfo *InventDeclaratorInfo(QualType T) { - return SemaRef.Context.getTrivialDeclaratorInfo(T, + /// \brief Fakes up a TypeSourceInfo for a type. + TypeSourceInfo *InventTypeSourceInfo(QualType T) { + return SemaRef.Context.getTrivialTypeSourceInfo(T, getDerived().getBaseLocation()); } @@ -328,7 +326,7 @@ class TreeTransform { #define STMT(Node, Parent) \ OwningStmtResult Transform##Node(Node *S); #define EXPR(Node, Parent) \ - OwningExprResult Transform##Node(Node *E, bool isAddressOfOperand); + OwningExprResult Transform##Node(Node *E); #define ABSTRACT_EXPR(Node, Parent) #include "clang/AST/StmtNodes.def" @@ -461,6 +459,10 @@ class TreeTransform { /// \brief Build a new unprototyped function type. QualType RebuildFunctionNoProtoType(QualType ResultType); + /// \brief Rebuild an unresolved typename type, given the decl that + /// the UnresolvedUsingTypenameDecl was transformed to. + QualType RebuildUnresolvedUsingType(Decl *D); + /// \brief Build a new typedef type. QualType RebuildTypedefType(TypedefDecl *Typedef) { return SemaRef.Context.getTypeDeclType(Typedef); @@ -779,7 +781,7 @@ class TreeTransform { /// By default, performs semantic analysis to build the new decaration. /// Subclasses may override this routine to provide different behavior. VarDecl *RebuildExceptionDecl(VarDecl *ExceptionDecl, QualType T, - DeclaratorInfo *Declarator, + TypeSourceInfo *Declarator, IdentifierInfo *Name, SourceLocation Loc, SourceRange TypeRange) { @@ -826,15 +828,15 @@ class TreeTransform { /// Subclasses may override this routine to provide different behavior. OwningExprResult RebuildDeclRefExpr(NestedNameSpecifier *Qualifier, SourceRange QualifierRange, - NamedDecl *ND, SourceLocation Loc, - bool isAddressOfOperand) { + ValueDecl *VD, SourceLocation Loc, + TemplateArgumentListInfo *TemplateArgs) { CXXScopeSpec SS; SS.setScopeRep(Qualifier); SS.setRange(QualifierRange); - return getSema().BuildDeclarationNameExpr(Loc, ND, - /*FIXME:*/false, - &SS, - isAddressOfOperand); + + // FIXME: loses template args. + + return getSema().BuildDeclarationNameExpr(SS, Loc, VD); } /// \brief Build a new expression in parentheses. @@ -863,11 +865,14 @@ class TreeTransform { SS.setScopeRep(Qualifier); } + QualType BaseType = ((Expr*) Base.get())->getType(); + DeclarationName Name = SemaRef.Context.DeclarationNames.getCXXDestructorName( SemaRef.Context.getCanonicalType(DestroyedType)); - return getSema().BuildMemberReferenceExpr(move(Base), OperatorLoc, isArrow, + return getSema().BuildMemberReferenceExpr(move(Base), BaseType, + OperatorLoc, isArrow, SS, /*FIXME: FirstQualifier*/ 0, Name, DestroyedTypeLoc, /*TemplateArgs*/ 0); @@ -887,10 +892,10 @@ class TreeTransform { /// /// By default, performs semantic analysis to build the new expression. /// Subclasses may override this routine to provide different behavior. - OwningExprResult RebuildSizeOfAlignOf(DeclaratorInfo *DInfo, + OwningExprResult RebuildSizeOfAlignOf(TypeSourceInfo *TInfo, SourceLocation OpLoc, bool isSizeOf, SourceRange R) { - return getSema().CreateSizeOfAlignOfExpr(DInfo, OpLoc, isSizeOf, R); + return getSema().CreateSizeOfAlignOfExpr(TInfo, OpLoc, isSizeOf, R); } /// \brief Build a new sizeof or alignof expression with an expression @@ -944,7 +949,7 @@ class TreeTransform { NestedNameSpecifier *Qualifier, SourceRange QualifierRange, SourceLocation MemberLoc, - NamedDecl *Member, + ValueDecl *Member, const TemplateArgumentListInfo *ExplicitTemplateArgs, NamedDecl *FirstQualifierInScope) { if (!Member->getDeclName()) { @@ -964,7 +969,11 @@ class TreeTransform { SS.setScopeRep(Qualifier); } - return getSema().BuildMemberReferenceExpr(move(Base), OpLoc, isArrow, + QualType BaseType = ((Expr*) Base.get())->getType(); + + // FIXME: wait, this is re-performing lookup? + return getSema().BuildMemberReferenceExpr(move(Base), BaseType, + OpLoc, isArrow, SS, FirstQualifierInScope, Member->getDeclName(), MemberLoc, ExplicitTemplateArgs); @@ -994,19 +1003,6 @@ class TreeTransform { move(LHS), move(RHS)); } - /// \brief Build a new implicit cast expression. - /// - /// By default, builds a new implicit cast without any semantic analysis. - /// Subclasses may override this routine to provide different behavior. - OwningExprResult RebuildImplicitCastExpr(QualType T, CastExpr::CastKind Kind, - ExprArg SubExpr, bool isLvalue) { - ImplicitCastExpr *ICE - = new (getSema().Context) ImplicitCastExpr(T, Kind, - (Expr *)SubExpr.release(), - isLvalue); - return getSema().Owned(ICE); - } - /// \brief Build a new C-style cast expression. /// /// By default, performs semantic analysis to build the new expression. @@ -1042,8 +1038,10 @@ class TreeTransform { SourceLocation OpLoc, SourceLocation AccessorLoc, IdentifierInfo &Accessor) { + CXXScopeSpec SS; - return getSema().BuildMemberReferenceExpr(move(Base), + QualType BaseType = ((Expr*) Base.get())->getType(); + return getSema().BuildMemberReferenceExpr(move(Base), BaseType, OpLoc, /*IsArrow*/ false, SS, /*FirstQualifierInScope*/ 0, DeclarationName(&Accessor), @@ -1471,13 +1469,17 @@ class TreeTransform { /// By default, performs semantic analysis to build the new expression. /// Subclasses may override this routine to provide different behavior. OwningExprResult RebuildCXXConstructExpr(QualType T, + SourceLocation Loc, CXXConstructorDecl *Constructor, bool IsElidable, MultiExprArg Args) { - return getSema().BuildCXXConstructExpr(/*FIXME:ConstructLoc*/ - SourceLocation(), - T, Constructor, IsElidable, - move(Args)); + ASTOwningVector<&ActionBase::DeleteExpr> ConvertedArgs(SemaRef); + if (getSema().CompleteConstructorCall(Constructor, move(Args), Loc, + ConvertedArgs)) + return getSema().ExprError(); + + return getSema().BuildCXXConstructExpr(Loc, T, Constructor, IsElidable, + move_arg(ConvertedArgs)); } /// \brief Build a new object-construction expression. @@ -1522,6 +1524,7 @@ class TreeTransform { /// By default, performs semantic analysis to build the new expression. /// Subclasses may override this routine to provide different behavior. OwningExprResult RebuildCXXDependentScopeMemberExpr(ExprArg BaseE, + QualType BaseType, bool IsArrow, SourceLocation OperatorLoc, NestedNameSpecifier *Qualifier, @@ -1534,7 +1537,8 @@ class TreeTransform { SS.setRange(QualifierRange); SS.setScopeRep(Qualifier); - return SemaRef.BuildMemberReferenceExpr(move(BaseE), OperatorLoc, IsArrow, + return SemaRef.BuildMemberReferenceExpr(move(BaseE), BaseType, + OperatorLoc, IsArrow, SS, FirstQualifierInScope, Name, MemberLoc, TemplateArgs); } @@ -1544,19 +1548,19 @@ class TreeTransform { /// By default, performs semantic analysis to build the new expression. /// Subclasses may override this routine to provide different behavior. OwningExprResult RebuildUnresolvedMemberExpr(ExprArg BaseE, + QualType BaseType, SourceLocation OperatorLoc, bool IsArrow, NestedNameSpecifier *Qualifier, SourceRange QualifierRange, LookupResult &R, const TemplateArgumentListInfo *TemplateArgs) { - OwningExprResult Base = move(BaseE); - CXXScopeSpec SS; SS.setRange(QualifierRange); SS.setScopeRep(Qualifier); - return SemaRef.BuildMemberReferenceExpr(move(Base), OperatorLoc, IsArrow, + return SemaRef.BuildMemberReferenceExpr(move(BaseE), BaseType, + OperatorLoc, IsArrow, SS, R, TemplateArgs); } @@ -1660,8 +1664,7 @@ Sema::OwningStmtResult TreeTransform::TransformStmt(Stmt *S) { template -Sema::OwningExprResult TreeTransform::TransformExpr(Expr *E, - bool isAddressOfOperand) { +Sema::OwningExprResult TreeTransform::TransformExpr(Expr *E) { if (!E) return SemaRef.Owned(E); @@ -1669,8 +1672,7 @@ Sema::OwningExprResult TreeTransform::TransformExpr(Expr *E, case Stmt::NoStmtClass: break; #define STMT(Node, Parent) case Stmt::Node##Class: break; #define EXPR(Node, Parent) \ - case Stmt::Node##Class: return getDerived().Transform##Node(cast(E), \ - isAddressOfOperand); + case Stmt::Node##Class: return getDerived().Transform##Node(cast(E)); #include "clang/AST/StmtNodes.def" } @@ -1870,12 +1872,12 @@ void TreeTransform::InventTemplateArgumentLoc( SourceLocation Loc = getDerived().getBaseLocation(); switch (Arg.getKind()) { case TemplateArgument::Null: - llvm::llvm_unreachable("null template argument in TreeTransform"); + llvm_unreachable("null template argument in TreeTransform"); break; case TemplateArgument::Type: Output = TemplateArgumentLoc(Arg, - SemaRef.Context.getTrivialDeclaratorInfo(Arg.getAsType(), Loc)); + SemaRef.Context.getTrivialTypeSourceInfo(Arg.getAsType(), Loc)); break; @@ -1907,9 +1909,9 @@ bool TreeTransform::TransformTemplateArgument( return false; case TemplateArgument::Type: { - DeclaratorInfo *DI = Input.getSourceDeclaratorInfo(); + TypeSourceInfo *DI = Input.getTypeSourceInfo(); if (DI == NULL) - DI = InventDeclaratorInfo(Input.getArgument().getAsType()); + DI = InventTypeSourceInfo(Input.getArgument().getAsType()); DI = getDerived().TransformType(DI); if (!DI) return true; @@ -2016,10 +2018,10 @@ QualType TreeTransform::TransformType(QualType T) { // Temporary workaround. All of these transformations should // eventually turn into transformations on TypeLocs. - DeclaratorInfo *DI = getSema().Context.CreateDeclaratorInfo(T); + TypeSourceInfo *DI = getSema().Context.CreateTypeSourceInfo(T); DI->getTypeLoc().initialize(getDerived().getBaseLocation()); - DeclaratorInfo *NewDI = getDerived().TransformType(DI); + TypeSourceInfo *NewDI = getDerived().TransformType(DI); if (!NewDI) return QualType(); @@ -2028,7 +2030,7 @@ QualType TreeTransform::TransformType(QualType T) { } template -DeclaratorInfo *TreeTransform::TransformType(DeclaratorInfo *DI) { +TypeSourceInfo *TreeTransform::TransformType(TypeSourceInfo *DI) { if (getDerived().AlreadyTransformed(DI->getType())) return DI; @@ -2041,7 +2043,7 @@ DeclaratorInfo *TreeTransform::TransformType(DeclaratorInfo *DI) { if (Result.isNull()) return 0; - return TLB.getDeclaratorInfo(SemaRef.Context, Result); + return TLB.getTypeSourceInfo(SemaRef.Context, Result); } template @@ -2055,7 +2057,7 @@ TreeTransform::TransformType(TypeLocBuilder &TLB, TypeLoc T) { #include "clang/AST/TypeLocNodes.def" } - llvm::llvm_unreachable("unhandled type loc!"); + llvm_unreachable("unhandled type loc!"); return QualType(); } @@ -2489,10 +2491,10 @@ TreeTransform::TransformFunctionProtoType(TypeLocBuilder &TLB, ParmVarDecl *NewParm; if (OldParm) { - DeclaratorInfo *OldDI = OldParm->getDeclaratorInfo(); + TypeSourceInfo *OldDI = OldParm->getTypeSourceInfo(); assert(OldDI->getType() == T->getArgType(i)); - DeclaratorInfo *NewDI = getDerived().TransformType(OldDI); + TypeSourceInfo *NewDI = getDerived().TransformType(OldDI); if (!NewDI) return QualType(); @@ -2567,6 +2569,29 @@ QualType TreeTransform::TransformFunctionNoProtoType( return Result; } +template QualType +TreeTransform::TransformUnresolvedUsingType(TypeLocBuilder &TLB, + UnresolvedUsingTypeLoc TL) { + UnresolvedUsingType *T = TL.getTypePtr(); + Decl *D = getDerived().TransformDecl(T->getDecl()); + if (!D) + return QualType(); + + QualType Result = TL.getType(); + if (getDerived().AlwaysRebuild() || D != T->getDecl()) { + Result = getDerived().RebuildUnresolvedUsingType(D); + if (Result.isNull()) + return QualType(); + } + + // We might get an arbitrary type spec type back. We should at + // least always get a type spec type, though. + TypeSpecTypeLoc NewTL = TLB.pushTypeSpec(Result); + NewTL.setNameLoc(TL.getNameLoc()); + + return Result; +} + template QualType TreeTransform::TransformTypedefType(TypeLocBuilder &TLB, TypedefTypeLoc TL) { @@ -2622,7 +2647,7 @@ QualType TreeTransform::TransformTypeOfType(TypeLocBuilder &TLB, TypeOfTypeLoc TL) { TypeOfType *T = TL.getTypePtr(); - // FIXME: should be an inner type, or at least have a DeclaratorInfo. + // FIXME: should be an inner type, or at least have a TypeSourceInfo. QualType Underlying = getDerived().TransformType(T->getUnderlyingType()); if (Underlying.isNull()) return QualType(); @@ -3364,7 +3389,7 @@ TreeTransform::TransformCXXCatchStmt(CXXCatchStmt *S) { Var = getDerived().RebuildExceptionDecl(ExceptionDecl, T, - ExceptionDecl->getDeclaratorInfo(), + ExceptionDecl->getTypeSourceInfo(), ExceptionDecl->getIdentifier(), ExceptionDecl->getLocation(), /*FIXME: Inaccurate*/ @@ -3430,15 +3455,13 @@ TreeTransform::TransformCXXTryStmt(CXXTryStmt *S) { //===----------------------------------------------------------------------===// template Sema::OwningExprResult -TreeTransform::TransformPredefinedExpr(PredefinedExpr *E, - bool isAddressOfOperand) { +TreeTransform::TransformPredefinedExpr(PredefinedExpr *E) { return SemaRef.Owned(E->Retain()); } template Sema::OwningExprResult -TreeTransform::TransformDeclRefExpr(DeclRefExpr *E, - bool isAddressOfOperand) { +TreeTransform::TransformDeclRefExpr(DeclRefExpr *E) { NestedNameSpecifier *Qualifier = 0; if (E->getQualifier()) { Qualifier = getDerived().TransformNestedNameSpecifier(E->getQualifier(), @@ -3446,72 +3469,74 @@ TreeTransform::TransformDeclRefExpr(DeclRefExpr *E, if (!Qualifier) return SemaRef.ExprError(); } - - NamedDecl *ND - = dyn_cast_or_null(getDerived().TransformDecl(E->getDecl())); + + ValueDecl *ND + = cast_or_null(getDerived().TransformDecl(E->getDecl())); if (!ND) return SemaRef.ExprError(); if (!getDerived().AlwaysRebuild() && Qualifier == E->getQualifier() && ND == E->getDecl() && - !E->hasExplicitTemplateArgumentList()) + !E->hasExplicitTemplateArgumentList()) { + + // Mark it referenced in the new context regardless. + // FIXME: this is a bit instantiation-specific. + SemaRef.MarkDeclarationReferenced(E->getLocation(), ND); + return SemaRef.Owned(E->Retain()); - - // FIXME: We're losing the explicit template arguments in this transformation. - - llvm::SmallVector TransArgs(E->getNumTemplateArgs()); - for (unsigned I = 0, N = E->getNumTemplateArgs(); I != N; ++I) { - if (getDerived().TransformTemplateArgument(E->getTemplateArgs()[I], - TransArgs[I])) - return SemaRef.ExprError(); } - - // FIXME: Pass the qualifier/qualifier range along. + + TemplateArgumentListInfo TransArgs, *TemplateArgs = 0; + if (E->hasExplicitTemplateArgumentList()) { + TemplateArgs = &TransArgs; + TransArgs.setLAngleLoc(E->getLAngleLoc()); + TransArgs.setRAngleLoc(E->getRAngleLoc()); + for (unsigned I = 0, N = E->getNumTemplateArgs(); I != N; ++I) { + TemplateArgumentLoc Loc; + if (getDerived().TransformTemplateArgument(E->getTemplateArgs()[I], Loc)) + return SemaRef.ExprError(); + TransArgs.addArgument(Loc); + } + } + return getDerived().RebuildDeclRefExpr(Qualifier, E->getQualifierRange(), - ND, E->getLocation(), - isAddressOfOperand); + ND, E->getLocation(), TemplateArgs); } template Sema::OwningExprResult -TreeTransform::TransformIntegerLiteral(IntegerLiteral *E, - bool isAddressOfOperand) { +TreeTransform::TransformIntegerLiteral(IntegerLiteral *E) { return SemaRef.Owned(E->Retain()); } template Sema::OwningExprResult -TreeTransform::TransformFloatingLiteral(FloatingLiteral *E, - bool isAddressOfOperand) { +TreeTransform::TransformFloatingLiteral(FloatingLiteral *E) { return SemaRef.Owned(E->Retain()); } template Sema::OwningExprResult -TreeTransform::TransformImaginaryLiteral(ImaginaryLiteral *E, - bool isAddressOfOperand) { +TreeTransform::TransformImaginaryLiteral(ImaginaryLiteral *E) { return SemaRef.Owned(E->Retain()); } template Sema::OwningExprResult -TreeTransform::TransformStringLiteral(StringLiteral *E, - bool isAddressOfOperand) { +TreeTransform::TransformStringLiteral(StringLiteral *E) { return SemaRef.Owned(E->Retain()); } template Sema::OwningExprResult -TreeTransform::TransformCharacterLiteral(CharacterLiteral *E, - bool isAddressOfOperand) { +TreeTransform::TransformCharacterLiteral(CharacterLiteral *E) { return SemaRef.Owned(E->Retain()); } template Sema::OwningExprResult -TreeTransform::TransformParenExpr(ParenExpr *E, - bool isAddressOfOperand) { +TreeTransform::TransformParenExpr(ParenExpr *E) { OwningExprResult SubExpr = getDerived().TransformExpr(E->getSubExpr()); if (SubExpr.isInvalid()) return SemaRef.ExprError(); @@ -3525,10 +3550,8 @@ TreeTransform::TransformParenExpr(ParenExpr *E, template Sema::OwningExprResult -TreeTransform::TransformUnaryOperator(UnaryOperator *E, - bool isAddressOfOperand) { - OwningExprResult SubExpr = getDerived().TransformExpr(E->getSubExpr(), - E->getOpcode() == UnaryOperator::AddrOf); +TreeTransform::TransformUnaryOperator(UnaryOperator *E) { + OwningExprResult SubExpr = getDerived().TransformExpr(E->getSubExpr()); if (SubExpr.isInvalid()) return SemaRef.ExprError(); @@ -3542,12 +3565,11 @@ TreeTransform::TransformUnaryOperator(UnaryOperator *E, template Sema::OwningExprResult -TreeTransform::TransformSizeOfAlignOfExpr(SizeOfAlignOfExpr *E, - bool isAddressOfOperand) { +TreeTransform::TransformSizeOfAlignOfExpr(SizeOfAlignOfExpr *E) { if (E->isArgumentType()) { - DeclaratorInfo *OldT = E->getArgumentTypeInfo(); + TypeSourceInfo *OldT = E->getArgumentTypeInfo(); - DeclaratorInfo *NewT = getDerived().TransformType(OldT); + TypeSourceInfo *NewT = getDerived().TransformType(OldT); if (!NewT) return SemaRef.ExprError(); @@ -3581,8 +3603,7 @@ TreeTransform::TransformSizeOfAlignOfExpr(SizeOfAlignOfExpr *E, template Sema::OwningExprResult -TreeTransform::TransformArraySubscriptExpr(ArraySubscriptExpr *E, - bool isAddressOfOperand) { +TreeTransform::TransformArraySubscriptExpr(ArraySubscriptExpr *E) { OwningExprResult LHS = getDerived().TransformExpr(E->getLHS()); if (LHS.isInvalid()) return SemaRef.ExprError(); @@ -3605,8 +3626,7 @@ TreeTransform::TransformArraySubscriptExpr(ArraySubscriptExpr *E, template Sema::OwningExprResult -TreeTransform::TransformCallExpr(CallExpr *E, - bool isAddressOfOperand) { +TreeTransform::TransformCallExpr(CallExpr *E) { // Transform the callee. OwningExprResult Callee = getDerived().TransformExpr(E->getCallee()); if (Callee.isInvalid()) @@ -3645,8 +3665,7 @@ TreeTransform::TransformCallExpr(CallExpr *E, template Sema::OwningExprResult -TreeTransform::TransformMemberExpr(MemberExpr *E, - bool isAddressOfOperand) { +TreeTransform::TransformMemberExpr(MemberExpr *E) { OwningExprResult Base = getDerived().TransformExpr(E->getBase()); if (Base.isInvalid()) return SemaRef.ExprError(); @@ -3660,8 +3679,8 @@ TreeTransform::TransformMemberExpr(MemberExpr *E, return SemaRef.ExprError(); } - NamedDecl *Member - = cast_or_null(getDerived().TransformDecl(E->getMemberDecl())); + ValueDecl *Member + = cast_or_null(getDerived().TransformDecl(E->getMemberDecl())); if (!Member) return SemaRef.ExprError(); @@ -3701,16 +3720,14 @@ TreeTransform::TransformMemberExpr(MemberExpr *E, template Sema::OwningExprResult -TreeTransform::TransformCastExpr(CastExpr *E, - bool isAddressOfOperand) { +TreeTransform::TransformCastExpr(CastExpr *E) { assert(false && "Cannot transform abstract class"); return SemaRef.Owned(E->Retain()); } template Sema::OwningExprResult -TreeTransform::TransformBinaryOperator(BinaryOperator *E, - bool isAddressOfOperand) { +TreeTransform::TransformBinaryOperator(BinaryOperator *E) { OwningExprResult LHS = getDerived().TransformExpr(E->getLHS()); if (LHS.isInvalid()) return SemaRef.ExprError(); @@ -3731,15 +3748,13 @@ TreeTransform::TransformBinaryOperator(BinaryOperator *E, template Sema::OwningExprResult TreeTransform::TransformCompoundAssignOperator( - CompoundAssignOperator *E, - bool isAddressOfOperand) { - return getDerived().TransformBinaryOperator(E, isAddressOfOperand); + CompoundAssignOperator *E) { + return getDerived().TransformBinaryOperator(E); } template Sema::OwningExprResult -TreeTransform::TransformConditionalOperator(ConditionalOperator *E, - bool isAddressOfOperand) { +TreeTransform::TransformConditionalOperator(ConditionalOperator *E) { OwningExprResult Cond = getDerived().TransformExpr(E->getCond()); if (Cond.isInvalid()) return SemaRef.ExprError(); @@ -3767,42 +3782,22 @@ TreeTransform::TransformConditionalOperator(ConditionalOperator *E, template Sema::OwningExprResult -TreeTransform::TransformImplicitCastExpr(ImplicitCastExpr *E, - bool isAddressOfOperand) { - TemporaryBase Rebase(*this, E->getLocStart(), DeclarationName()); - - // FIXME: Will we ever have type information here? It seems like we won't, - // so do we even need to transform the type? - QualType T = getDerived().TransformType(E->getType()); - if (T.isNull()) - return SemaRef.ExprError(); - - OwningExprResult SubExpr = getDerived().TransformExpr(E->getSubExpr()); - if (SubExpr.isInvalid()) - return SemaRef.ExprError(); - - if (!getDerived().AlwaysRebuild() && - T == E->getType() && - SubExpr.get() == E->getSubExpr()) - return SemaRef.Owned(E->Retain()); - - return getDerived().RebuildImplicitCastExpr(T, E->getCastKind(), - move(SubExpr), - E->isLvalueCast()); +TreeTransform::TransformImplicitCastExpr(ImplicitCastExpr *E) { + // Implicit casts are eliminated during transformation, since they + // will be recomputed by semantic analysis after transformation. + return getDerived().TransformExpr(E->getSubExprAsWritten()); } template Sema::OwningExprResult -TreeTransform::TransformExplicitCastExpr(ExplicitCastExpr *E, - bool isAddressOfOperand) { +TreeTransform::TransformExplicitCastExpr(ExplicitCastExpr *E) { assert(false && "Cannot transform abstract class"); return SemaRef.Owned(E->Retain()); } template Sema::OwningExprResult -TreeTransform::TransformCStyleCastExpr(CStyleCastExpr *E, - bool isAddressOfOperand) { +TreeTransform::TransformCStyleCastExpr(CStyleCastExpr *E) { QualType T; { // FIXME: Source location isn't quite accurate. @@ -3815,7 +3810,8 @@ TreeTransform::TransformCStyleCastExpr(CStyleCastExpr *E, return SemaRef.ExprError(); } - OwningExprResult SubExpr = getDerived().TransformExpr(E->getSubExpr()); + OwningExprResult SubExpr + = getDerived().TransformExpr(E->getSubExprAsWritten()); if (SubExpr.isInvalid()) return SemaRef.ExprError(); @@ -3831,8 +3827,7 @@ TreeTransform::TransformCStyleCastExpr(CStyleCastExpr *E, template Sema::OwningExprResult -TreeTransform::TransformCompoundLiteralExpr(CompoundLiteralExpr *E, - bool isAddressOfOperand) { +TreeTransform::TransformCompoundLiteralExpr(CompoundLiteralExpr *E) { QualType T; { // FIXME: Source location isn't quite accurate. @@ -3861,8 +3856,7 @@ TreeTransform::TransformCompoundLiteralExpr(CompoundLiteralExpr *E, template Sema::OwningExprResult -TreeTransform::TransformExtVectorElementExpr(ExtVectorElementExpr *E, - bool isAddressOfOperand) { +TreeTransform::TransformExtVectorElementExpr(ExtVectorElementExpr *E) { OwningExprResult Base = getDerived().TransformExpr(E->getBase()); if (Base.isInvalid()) return SemaRef.ExprError(); @@ -3881,8 +3875,7 @@ TreeTransform::TransformExtVectorElementExpr(ExtVectorElementExpr *E, template Sema::OwningExprResult -TreeTransform::TransformInitListExpr(InitListExpr *E, - bool isAddressOfOperand) { +TreeTransform::TransformInitListExpr(InitListExpr *E) { bool InitChanged = false; ASTOwningVector<&ActionBase::DeleteExpr, 4> Inits(SemaRef); @@ -3904,8 +3897,7 @@ TreeTransform::TransformInitListExpr(InitListExpr *E, template Sema::OwningExprResult -TreeTransform::TransformDesignatedInitExpr(DesignatedInitExpr *E, - bool isAddressOfOperand) { +TreeTransform::TransformDesignatedInitExpr(DesignatedInitExpr *E) { Designation Desig; // transform the initializer value @@ -3974,8 +3966,7 @@ TreeTransform::TransformDesignatedInitExpr(DesignatedInitExpr *E, template Sema::OwningExprResult TreeTransform::TransformImplicitValueInitExpr( - ImplicitValueInitExpr *E, - bool isAddressOfOperand) { + ImplicitValueInitExpr *E) { TemporaryBase Rebase(*this, E->getLocStart(), DeclarationName()); // FIXME: Will we ever have proper type location here? Will we actually @@ -3993,8 +3984,7 @@ TreeTransform::TransformImplicitValueInitExpr( template Sema::OwningExprResult -TreeTransform::TransformVAArgExpr(VAArgExpr *E, - bool isAddressOfOperand) { +TreeTransform::TransformVAArgExpr(VAArgExpr *E) { // FIXME: Do we want the type as written? QualType T; @@ -4021,8 +4011,7 @@ TreeTransform::TransformVAArgExpr(VAArgExpr *E, template Sema::OwningExprResult -TreeTransform::TransformParenListExpr(ParenListExpr *E, - bool isAddressOfOperand) { +TreeTransform::TransformParenListExpr(ParenListExpr *E) { bool ArgumentChanged = false; ASTOwningVector<&ActionBase::DeleteExpr, 4> Inits(SemaRef); for (unsigned I = 0, N = E->getNumExprs(); I != N; ++I) { @@ -4046,16 +4035,14 @@ TreeTransform::TransformParenListExpr(ParenListExpr *E, /// the corresponding label statement by semantic analysis. template Sema::OwningExprResult -TreeTransform::TransformAddrLabelExpr(AddrLabelExpr *E, - bool isAddressOfOperand) { +TreeTransform::TransformAddrLabelExpr(AddrLabelExpr *E) { return getDerived().RebuildAddrLabelExpr(E->getAmpAmpLoc(), E->getLabelLoc(), E->getLabel()); } template Sema::OwningExprResult -TreeTransform::TransformStmtExpr(StmtExpr *E, - bool isAddressOfOperand) { +TreeTransform::TransformStmtExpr(StmtExpr *E) { OwningStmtResult SubStmt = getDerived().TransformCompoundStmt(E->getSubStmt(), true); if (SubStmt.isInvalid()) @@ -4072,8 +4059,7 @@ TreeTransform::TransformStmtExpr(StmtExpr *E, template Sema::OwningExprResult -TreeTransform::TransformTypesCompatibleExpr(TypesCompatibleExpr *E, - bool isAddressOfOperand) { +TreeTransform::TransformTypesCompatibleExpr(TypesCompatibleExpr *E) { QualType T1, T2; { // FIXME: Source location isn't quite accurate. @@ -4099,8 +4085,7 @@ TreeTransform::TransformTypesCompatibleExpr(TypesCompatibleExpr *E, template Sema::OwningExprResult -TreeTransform::TransformChooseExpr(ChooseExpr *E, - bool isAddressOfOperand) { +TreeTransform::TransformChooseExpr(ChooseExpr *E) { OwningExprResult Cond = getDerived().TransformExpr(E->getCond()); if (Cond.isInvalid()) return SemaRef.ExprError(); @@ -4126,22 +4111,83 @@ TreeTransform::TransformChooseExpr(ChooseExpr *E, template Sema::OwningExprResult -TreeTransform::TransformGNUNullExpr(GNUNullExpr *E, - bool isAddressOfOperand) { +TreeTransform::TransformGNUNullExpr(GNUNullExpr *E) { return SemaRef.Owned(E->Retain()); } template Sema::OwningExprResult -TreeTransform::TransformCXXOperatorCallExpr(CXXOperatorCallExpr *E, - bool isAddressOfOperand) { +TreeTransform::TransformCXXOperatorCallExpr(CXXOperatorCallExpr *E) { + switch (E->getOperator()) { + case OO_New: + case OO_Delete: + case OO_Array_New: + case OO_Array_Delete: + llvm_unreachable("new and delete operators cannot use CXXOperatorCallExpr"); + return SemaRef.ExprError(); + + case OO_Call: { + // This is a call to an object's operator(). + assert(E->getNumArgs() >= 1 && "Object call is missing arguments"); + + // Transform the object itself. + OwningExprResult Object = getDerived().TransformExpr(E->getArg(0)); + if (Object.isInvalid()) + return SemaRef.ExprError(); + + // FIXME: Poor location information + SourceLocation FakeLParenLoc + = SemaRef.PP.getLocForEndOfToken( + static_cast(Object.get())->getLocEnd()); + + // Transform the call arguments. + ASTOwningVector<&ActionBase::DeleteExpr> Args(SemaRef); + llvm::SmallVector FakeCommaLocs; + for (unsigned I = 1, N = E->getNumArgs(); I != N; ++I) { + if (getDerived().DropCallArgument(E->getArg(I))) + break; + + OwningExprResult Arg = getDerived().TransformExpr(E->getArg(I)); + if (Arg.isInvalid()) + return SemaRef.ExprError(); + + // FIXME: Poor source location information. + SourceLocation FakeCommaLoc + = SemaRef.PP.getLocForEndOfToken( + static_cast(Arg.get())->getLocEnd()); + FakeCommaLocs.push_back(FakeCommaLoc); + Args.push_back(Arg.release()); + } + + return getDerived().RebuildCallExpr(move(Object), FakeLParenLoc, + move_arg(Args), + FakeCommaLocs.data(), + E->getLocEnd()); + } + +#define OVERLOADED_OPERATOR(Name,Spelling,Token,Unary,Binary,MemberOnly) \ + case OO_##Name: +#define OVERLOADED_OPERATOR_MULTI(Name,Spelling,Unary,Binary,MemberOnly) +#include "clang/Basic/OperatorKinds.def" + case OO_Subscript: + // Handled below. + break; + + case OO_Conditional: + llvm_unreachable("conditional operator is not actually overloadable"); + return SemaRef.ExprError(); + + case OO_None: + case NUM_OVERLOADED_OPERATORS: + llvm_unreachable("not an overloaded operator?"); + return SemaRef.ExprError(); + } + OwningExprResult Callee = getDerived().TransformExpr(E->getCallee()); if (Callee.isInvalid()) return SemaRef.ExprError(); - OwningExprResult First - = getDerived().TransformExpr(E->getArg(0), - E->getNumArgs() == 1 && E->getOperator() == OO_Amp); + OwningExprResult First = getDerived().TransformExpr(E->getArg(0)); if (First.isInvalid()) return SemaRef.ExprError(); @@ -4167,15 +4213,13 @@ TreeTransform::TransformCXXOperatorCallExpr(CXXOperatorCallExpr *E, template Sema::OwningExprResult -TreeTransform::TransformCXXMemberCallExpr(CXXMemberCallExpr *E, - bool isAddressOfOperand) { - return getDerived().TransformCallExpr(E, isAddressOfOperand); +TreeTransform::TransformCXXMemberCallExpr(CXXMemberCallExpr *E) { + return getDerived().TransformCallExpr(E); } template Sema::OwningExprResult -TreeTransform::TransformCXXNamedCastExpr(CXXNamedCastExpr *E, - bool isAddressOfOperand) { +TreeTransform::TransformCXXNamedCastExpr(CXXNamedCastExpr *E) { QualType ExplicitTy; { // FIXME: Source location isn't quite accurate. @@ -4188,7 +4232,8 @@ TreeTransform::TransformCXXNamedCastExpr(CXXNamedCastExpr *E, return SemaRef.ExprError(); } - OwningExprResult SubExpr = getDerived().TransformExpr(E->getSubExpr()); + OwningExprResult SubExpr + = getDerived().TransformExpr(E->getSubExprAsWritten()); if (SubExpr.isInvalid()) return SemaRef.ExprError(); @@ -4216,38 +4261,33 @@ TreeTransform::TransformCXXNamedCastExpr(CXXNamedCastExpr *E, template Sema::OwningExprResult -TreeTransform::TransformCXXStaticCastExpr(CXXStaticCastExpr *E, - bool isAddressOfOperand) { - return getDerived().TransformCXXNamedCastExpr(E, isAddressOfOperand); +TreeTransform::TransformCXXStaticCastExpr(CXXStaticCastExpr *E) { + return getDerived().TransformCXXNamedCastExpr(E); } template Sema::OwningExprResult -TreeTransform::TransformCXXDynamicCastExpr(CXXDynamicCastExpr *E, - bool isAddressOfOperand) { - return getDerived().TransformCXXNamedCastExpr(E, isAddressOfOperand); +TreeTransform::TransformCXXDynamicCastExpr(CXXDynamicCastExpr *E) { + return getDerived().TransformCXXNamedCastExpr(E); } template Sema::OwningExprResult TreeTransform::TransformCXXReinterpretCastExpr( - CXXReinterpretCastExpr *E, - bool isAddressOfOperand) { - return getDerived().TransformCXXNamedCastExpr(E, isAddressOfOperand); + CXXReinterpretCastExpr *E) { + return getDerived().TransformCXXNamedCastExpr(E); } template Sema::OwningExprResult -TreeTransform::TransformCXXConstCastExpr(CXXConstCastExpr *E, - bool isAddressOfOperand) { - return getDerived().TransformCXXNamedCastExpr(E, isAddressOfOperand); +TreeTransform::TransformCXXConstCastExpr(CXXConstCastExpr *E) { + return getDerived().TransformCXXNamedCastExpr(E); } template Sema::OwningExprResult TreeTransform::TransformCXXFunctionalCastExpr( - CXXFunctionalCastExpr *E, - bool isAddressOfOperand) { + CXXFunctionalCastExpr *E) { QualType ExplicitTy; { TemporaryBase Rebase(*this, E->getTypeBeginLoc(), DeclarationName()); @@ -4257,7 +4297,8 @@ TreeTransform::TransformCXXFunctionalCastExpr( return SemaRef.ExprError(); } - OwningExprResult SubExpr = getDerived().TransformExpr(E->getSubExpr()); + OwningExprResult SubExpr + = getDerived().TransformExpr(E->getSubExprAsWritten()); if (SubExpr.isInvalid()) return SemaRef.ExprError(); @@ -4277,8 +4318,7 @@ TreeTransform::TransformCXXFunctionalCastExpr( template Sema::OwningExprResult -TreeTransform::TransformCXXTypeidExpr(CXXTypeidExpr *E, - bool isAddressOfOperand) { +TreeTransform::TransformCXXTypeidExpr(CXXTypeidExpr *E) { if (E->isTypeOperand()) { TemporaryBase Rebase(*this, /*FIXME*/E->getLocStart(), DeclarationName()); @@ -4318,23 +4358,20 @@ TreeTransform::TransformCXXTypeidExpr(CXXTypeidExpr *E, template Sema::OwningExprResult -TreeTransform::TransformCXXBoolLiteralExpr(CXXBoolLiteralExpr *E, - bool isAddressOfOperand) { +TreeTransform::TransformCXXBoolLiteralExpr(CXXBoolLiteralExpr *E) { return SemaRef.Owned(E->Retain()); } template Sema::OwningExprResult TreeTransform::TransformCXXNullPtrLiteralExpr( - CXXNullPtrLiteralExpr *E, - bool isAddressOfOperand) { + CXXNullPtrLiteralExpr *E) { return SemaRef.Owned(E->Retain()); } template Sema::OwningExprResult -TreeTransform::TransformCXXThisExpr(CXXThisExpr *E, - bool isAddressOfOperand) { +TreeTransform::TransformCXXThisExpr(CXXThisExpr *E) { TemporaryBase Rebase(*this, E->getLocStart(), DeclarationName()); QualType T = getDerived().TransformType(E->getType()); @@ -4350,8 +4387,7 @@ TreeTransform::TransformCXXThisExpr(CXXThisExpr *E, template Sema::OwningExprResult -TreeTransform::TransformCXXThrowExpr(CXXThrowExpr *E, - bool isAddressOfOperand) { +TreeTransform::TransformCXXThrowExpr(CXXThrowExpr *E) { OwningExprResult SubExpr = getDerived().TransformExpr(E->getSubExpr()); if (SubExpr.isInvalid()) return SemaRef.ExprError(); @@ -4365,8 +4401,7 @@ TreeTransform::TransformCXXThrowExpr(CXXThrowExpr *E, template Sema::OwningExprResult -TreeTransform::TransformCXXDefaultArgExpr(CXXDefaultArgExpr *E, - bool isAddressOfOperand) { +TreeTransform::TransformCXXDefaultArgExpr(CXXDefaultArgExpr *E) { ParmVarDecl *Param = cast_or_null(getDerived().TransformDecl(E->getParam())); if (!Param) @@ -4381,8 +4416,7 @@ TreeTransform::TransformCXXDefaultArgExpr(CXXDefaultArgExpr *E, template Sema::OwningExprResult -TreeTransform::TransformCXXZeroInitValueExpr(CXXZeroInitValueExpr *E, - bool isAddressOfOperand) { +TreeTransform::TransformCXXZeroInitValueExpr(CXXZeroInitValueExpr *E) { TemporaryBase Rebase(*this, E->getTypeBeginLoc(), DeclarationName()); QualType T = getDerived().TransformType(E->getType()); @@ -4401,8 +4435,7 @@ TreeTransform::TransformCXXZeroInitValueExpr(CXXZeroInitValueExpr *E, template Sema::OwningExprResult -TreeTransform::TransformCXXNewExpr(CXXNewExpr *E, - bool isAddressOfOperand) { +TreeTransform::TransformCXXNewExpr(CXXNewExpr *E) { // Transform the type that we're allocating TemporaryBase Rebase(*this, E->getLocStart(), DeclarationName()); QualType AllocType = getDerived().TransformType(E->getAllocatedType()); @@ -4460,8 +4493,7 @@ TreeTransform::TransformCXXNewExpr(CXXNewExpr *E, template Sema::OwningExprResult -TreeTransform::TransformCXXDeleteExpr(CXXDeleteExpr *E, - bool isAddressOfOperand) { +TreeTransform::TransformCXXDeleteExpr(CXXDeleteExpr *E) { OwningExprResult Operand = getDerived().TransformExpr(E->getArgument()); if (Operand.isInvalid()) return SemaRef.ExprError(); @@ -4479,8 +4511,7 @@ TreeTransform::TransformCXXDeleteExpr(CXXDeleteExpr *E, template Sema::OwningExprResult TreeTransform::TransformCXXPseudoDestructorExpr( - CXXPseudoDestructorExpr *E, - bool isAddressOfOperand) { + CXXPseudoDestructorExpr *E) { OwningExprResult Base = getDerived().TransformExpr(E->getBase()); if (Base.isInvalid()) return SemaRef.ExprError(); @@ -4517,8 +4548,7 @@ TreeTransform::TransformCXXPseudoDestructorExpr( template Sema::OwningExprResult TreeTransform::TransformUnresolvedLookupExpr( - UnresolvedLookupExpr *Old, - bool isAddressOfOperand) { + UnresolvedLookupExpr *Old) { TemporaryBase Rebase(*this, Old->getNameLoc(), DeclarationName()); LookupResult R(SemaRef, Old->getName(), Old->getNameLoc(), @@ -4528,8 +4558,14 @@ TreeTransform::TransformUnresolvedLookupExpr( for (UnresolvedLookupExpr::decls_iterator I = Old->decls_begin(), E = Old->decls_end(); I != E; ++I) { NamedDecl *InstD = static_cast(getDerived().TransformDecl(*I)); - if (!InstD) - return SemaRef.ExprError(); + if (!InstD) { + // Silently ignore these if a UsingShadowDecl instantiated to nothing. + // This can happen because of dependent hiding. + if (isa(*I)) + continue; + else + return SemaRef.ExprError(); + } // Expand using declarations. if (isa(InstD)) { @@ -4580,8 +4616,7 @@ TreeTransform::TransformUnresolvedLookupExpr( template Sema::OwningExprResult -TreeTransform::TransformUnaryTypeTraitExpr(UnaryTypeTraitExpr *E, - bool isAddressOfOperand) { +TreeTransform::TransformUnaryTypeTraitExpr(UnaryTypeTraitExpr *E) { TemporaryBase Rebase(*this, /*FIXME*/E->getLocStart(), DeclarationName()); QualType T = getDerived().TransformType(E->getQueriedType()); @@ -4606,8 +4641,7 @@ TreeTransform::TransformUnaryTypeTraitExpr(UnaryTypeTraitExpr *E, template Sema::OwningExprResult TreeTransform::TransformDependentScopeDeclRefExpr( - DependentScopeDeclRefExpr *E, - bool isAddressOfOperand) { + DependentScopeDeclRefExpr *E) { NestedNameSpecifier *NNS = getDerived().TransformNestedNameSpecifier(E->getQualifier(), E->getQualifierRange()); @@ -4647,8 +4681,7 @@ TreeTransform::TransformDependentScopeDeclRefExpr( template Sema::OwningExprResult -TreeTransform::TransformCXXConstructExpr(CXXConstructExpr *E, - bool isAddressOfOperand) { +TreeTransform::TransformCXXConstructExpr(CXXConstructExpr *E) { TemporaryBase Rebase(*this, /*FIXME*/E->getLocStart(), DeclarationName()); QualType T = getDerived().TransformType(E->getType()); @@ -4666,6 +4699,11 @@ TreeTransform::TransformCXXConstructExpr(CXXConstructExpr *E, for (CXXConstructExpr::arg_iterator Arg = E->arg_begin(), ArgEnd = E->arg_end(); Arg != ArgEnd; ++Arg) { + if (getDerived().DropCallArgument(*Arg)) { + ArgumentChanged = true; + break; + } + OwningExprResult TransArg = getDerived().TransformExpr(*Arg); if (TransArg.isInvalid()) return SemaRef.ExprError(); @@ -4680,7 +4718,8 @@ TreeTransform::TransformCXXConstructExpr(CXXConstructExpr *E, !ArgumentChanged) return SemaRef.Owned(E->Retain()); - return getDerived().RebuildCXXConstructExpr(T, Constructor, E->isElidable(), + return getDerived().RebuildCXXConstructExpr(T, /*FIXME:*/E->getLocStart(), + Constructor, E->isElidable(), move_arg(Args)); } @@ -4692,8 +4731,7 @@ TreeTransform::TransformCXXConstructExpr(CXXConstructExpr *E, /// must be unique. template Sema::OwningExprResult -TreeTransform::TransformCXXBindTemporaryExpr(CXXBindTemporaryExpr *E, - bool isAddressOfOperand) { +TreeTransform::TransformCXXBindTemporaryExpr(CXXBindTemporaryExpr *E) { OwningExprResult SubExpr = getDerived().TransformExpr(E->getSubExpr()); if (SubExpr.isInvalid()) return SemaRef.ExprError(); @@ -4711,8 +4749,7 @@ TreeTransform::TransformCXXBindTemporaryExpr(CXXBindTemporaryExpr *E, template Sema::OwningExprResult TreeTransform::TransformCXXExprWithTemporaries( - CXXExprWithTemporaries *E, - bool isAddressOfOperand) { + CXXExprWithTemporaries *E) { OwningExprResult SubExpr = getDerived().TransformExpr(E->getSubExpr()); if (SubExpr.isInvalid()) return SemaRef.ExprError(); @@ -4725,8 +4762,7 @@ TreeTransform::TransformCXXExprWithTemporaries( template Sema::OwningExprResult TreeTransform::TransformCXXTemporaryObjectExpr( - CXXTemporaryObjectExpr *E, - bool isAddressOfOperand) { + CXXTemporaryObjectExpr *E) { TemporaryBase Rebase(*this, E->getTypeBeginLoc(), DeclarationName()); QualType T = getDerived().TransformType(E->getType()); if (T.isNull()) @@ -4776,8 +4812,7 @@ TreeTransform::TransformCXXTemporaryObjectExpr( template Sema::OwningExprResult TreeTransform::TransformCXXUnresolvedConstructExpr( - CXXUnresolvedConstructExpr *E, - bool isAddressOfOperand) { + CXXUnresolvedConstructExpr *E) { TemporaryBase Rebase(*this, E->getTypeBeginLoc(), DeclarationName()); QualType T = getDerived().TransformType(E->getTypeAsWritten()); if (T.isNull()) @@ -4816,21 +4851,34 @@ TreeTransform::TransformCXXUnresolvedConstructExpr( template Sema::OwningExprResult TreeTransform::TransformCXXDependentScopeMemberExpr( - CXXDependentScopeMemberExpr *E, - bool isAddressOfOperand) { + CXXDependentScopeMemberExpr *E) { // Transform the base of the expression. - OwningExprResult Base = getDerived().TransformExpr(E->getBase()); - if (Base.isInvalid()) - return SemaRef.ExprError(); + OwningExprResult Base(SemaRef, (Expr*) 0); + Expr *OldBase; + QualType BaseType; + QualType ObjectType; + if (!E->isImplicitAccess()) { + OldBase = E->getBase(); + Base = getDerived().TransformExpr(OldBase); + if (Base.isInvalid()) + return SemaRef.ExprError(); - // Start the member reference and compute the object's type. - Sema::TypeTy *ObjectType = 0; - Base = SemaRef.ActOnStartCXXMemberReference(0, move(Base), - E->getOperatorLoc(), + // Start the member reference and compute the object's type. + Sema::TypeTy *ObjectTy = 0; + Base = SemaRef.ActOnStartCXXMemberReference(0, move(Base), + E->getOperatorLoc(), E->isArrow()? tok::arrow : tok::period, - ObjectType); - if (Base.isInvalid()) - return SemaRef.ExprError(); + ObjectTy); + if (Base.isInvalid()) + return SemaRef.ExprError(); + + ObjectType = QualType::getFromOpaquePtr(ObjectTy); + BaseType = ((Expr*) Base.get())->getType(); + } else { + OldBase = 0; + BaseType = getDerived().TransformType(E->getBaseType()); + ObjectType = BaseType->getAs()->getPointeeType(); + } // Transform the first part of the nested-name-specifier that qualifies // the member name. @@ -4843,29 +4891,31 @@ TreeTransform::TransformCXXDependentScopeMemberExpr( if (E->getQualifier()) { Qualifier = getDerived().TransformNestedNameSpecifier(E->getQualifier(), E->getQualifierRange(), - QualType::getFromOpaquePtr(ObjectType), - FirstQualifierInScope); + ObjectType, + FirstQualifierInScope); if (!Qualifier) return SemaRef.ExprError(); } DeclarationName Name = getDerived().TransformDeclarationName(E->getMember(), E->getMemberLoc(), - QualType::getFromOpaquePtr(ObjectType)); + ObjectType); if (!Name) return SemaRef.ExprError(); - if (!E->hasExplicitTemplateArgumentList()) { + if (!E->hasExplicitTemplateArgs()) { // This is a reference to a member without an explicitly-specified // template argument list. Optimize for this common case. if (!getDerived().AlwaysRebuild() && - Base.get() == E->getBase() && + Base.get() == OldBase && + BaseType == E->getBaseType() && Qualifier == E->getQualifier() && Name == E->getMember() && FirstQualifierInScope == E->getFirstQualifierFoundInScope()) return SemaRef.Owned(E->Retain()); return getDerived().RebuildCXXDependentScopeMemberExpr(move(Base), + BaseType, E->isArrow(), E->getOperatorLoc(), Qualifier, @@ -4885,6 +4935,7 @@ TreeTransform::TransformCXXDependentScopeMemberExpr( } return getDerived().RebuildCXXDependentScopeMemberExpr(move(Base), + BaseType, E->isArrow(), E->getOperatorLoc(), Qualifier, @@ -4897,12 +4948,18 @@ TreeTransform::TransformCXXDependentScopeMemberExpr( template Sema::OwningExprResult -TreeTransform::TransformUnresolvedMemberExpr(UnresolvedMemberExpr *Old, - bool isAddressOfOperand) { +TreeTransform::TransformUnresolvedMemberExpr(UnresolvedMemberExpr *Old) { // Transform the base of the expression. - OwningExprResult Base = getDerived().TransformExpr(Old->getBase()); - if (Base.isInvalid()) - return SemaRef.ExprError(); + OwningExprResult Base(SemaRef, (Expr*) 0); + QualType BaseType; + if (!Old->isImplicitAccess()) { + Base = getDerived().TransformExpr(Old->getBase()); + if (Base.isInvalid()) + return SemaRef.ExprError(); + BaseType = ((Expr*) Base.get())->getType(); + } else { + BaseType = getDerived().TransformType(Old->getBaseType()); + } NestedNameSpecifier *Qualifier = 0; if (Old->getQualifier()) { @@ -4920,8 +4977,14 @@ TreeTransform::TransformUnresolvedMemberExpr(UnresolvedMemberExpr *Old, for (UnresolvedMemberExpr::decls_iterator I = Old->decls_begin(), E = Old->decls_end(); I != E; ++I) { NamedDecl *InstD = static_cast(getDerived().TransformDecl(*I)); - if (!InstD) - return SemaRef.ExprError(); + if (!InstD) { + // Silently ignore these if a UsingShadowDecl instantiated to nothing. + // This can happen because of dependent hiding. + if (isa(*I)) + continue; + else + return SemaRef.ExprError(); + } // Expand using declarations. if (isa(InstD)) { @@ -4951,6 +5014,7 @@ TreeTransform::TransformUnresolvedMemberExpr(UnresolvedMemberExpr *Old, } return getDerived().RebuildUnresolvedMemberExpr(move(Base), + BaseType, Old->getOperatorLoc(), Old->isArrow(), Qualifier, @@ -4962,15 +5026,13 @@ TreeTransform::TransformUnresolvedMemberExpr(UnresolvedMemberExpr *Old, template Sema::OwningExprResult -TreeTransform::TransformObjCStringLiteral(ObjCStringLiteral *E, - bool isAddressOfOperand) { +TreeTransform::TransformObjCStringLiteral(ObjCStringLiteral *E) { return SemaRef.Owned(E->Retain()); } template Sema::OwningExprResult -TreeTransform::TransformObjCEncodeExpr(ObjCEncodeExpr *E, - bool isAddressOfOperand) { +TreeTransform::TransformObjCEncodeExpr(ObjCEncodeExpr *E) { // FIXME: poor source location TemporaryBase Rebase(*this, E->getAtLoc(), DeclarationName()); QualType EncodedType = getDerived().TransformType(E->getEncodedType()); @@ -4988,8 +5050,7 @@ TreeTransform::TransformObjCEncodeExpr(ObjCEncodeExpr *E, template Sema::OwningExprResult -TreeTransform::TransformObjCMessageExpr(ObjCMessageExpr *E, - bool isAddressOfOperand) { +TreeTransform::TransformObjCMessageExpr(ObjCMessageExpr *E) { // FIXME: Implement this! assert(false && "Cannot transform Objective-C expressions yet"); return SemaRef.Owned(E->Retain()); @@ -4997,15 +5058,13 @@ TreeTransform::TransformObjCMessageExpr(ObjCMessageExpr *E, template Sema::OwningExprResult -TreeTransform::TransformObjCSelectorExpr(ObjCSelectorExpr *E, - bool isAddressOfOperand) { +TreeTransform::TransformObjCSelectorExpr(ObjCSelectorExpr *E) { return SemaRef.Owned(E->Retain()); } template Sema::OwningExprResult -TreeTransform::TransformObjCProtocolExpr(ObjCProtocolExpr *E, - bool isAddressOfOperand) { +TreeTransform::TransformObjCProtocolExpr(ObjCProtocolExpr *E) { ObjCProtocolDecl *Protocol = cast_or_null( getDerived().TransformDecl(E->getProtocol())); @@ -5026,8 +5085,7 @@ TreeTransform::TransformObjCProtocolExpr(ObjCProtocolExpr *E, template Sema::OwningExprResult -TreeTransform::TransformObjCIvarRefExpr(ObjCIvarRefExpr *E, - bool isAddressOfOperand) { +TreeTransform::TransformObjCIvarRefExpr(ObjCIvarRefExpr *E) { // FIXME: Implement this! assert(false && "Cannot transform Objective-C expressions yet"); return SemaRef.Owned(E->Retain()); @@ -5035,8 +5093,7 @@ TreeTransform::TransformObjCIvarRefExpr(ObjCIvarRefExpr *E, template Sema::OwningExprResult -TreeTransform::TransformObjCPropertyRefExpr(ObjCPropertyRefExpr *E, - bool isAddressOfOperand) { +TreeTransform::TransformObjCPropertyRefExpr(ObjCPropertyRefExpr *E) { // FIXME: Implement this! assert(false && "Cannot transform Objective-C expressions yet"); return SemaRef.Owned(E->Retain()); @@ -5045,8 +5102,7 @@ TreeTransform::TransformObjCPropertyRefExpr(ObjCPropertyRefExpr *E, template Sema::OwningExprResult TreeTransform::TransformObjCImplicitSetterGetterRefExpr( - ObjCImplicitSetterGetterRefExpr *E, - bool isAddressOfOperand) { + ObjCImplicitSetterGetterRefExpr *E) { // FIXME: Implement this! assert(false && "Cannot transform Objective-C expressions yet"); return SemaRef.Owned(E->Retain()); @@ -5054,8 +5110,7 @@ TreeTransform::TransformObjCImplicitSetterGetterRefExpr( template Sema::OwningExprResult -TreeTransform::TransformObjCSuperExpr(ObjCSuperExpr *E, - bool isAddressOfOperand) { +TreeTransform::TransformObjCSuperExpr(ObjCSuperExpr *E) { // FIXME: Implement this! assert(false && "Cannot transform Objective-C expressions yet"); return SemaRef.Owned(E->Retain()); @@ -5063,8 +5118,7 @@ TreeTransform::TransformObjCSuperExpr(ObjCSuperExpr *E, template Sema::OwningExprResult -TreeTransform::TransformObjCIsaExpr(ObjCIsaExpr *E, - bool isAddressOfOperand) { +TreeTransform::TransformObjCIsaExpr(ObjCIsaExpr *E) { // FIXME: Implement this! assert(false && "Cannot transform Objective-C expressions yet"); return SemaRef.Owned(E->Retain()); @@ -5072,8 +5126,7 @@ TreeTransform::TransformObjCIsaExpr(ObjCIsaExpr *E, template Sema::OwningExprResult -TreeTransform::TransformShuffleVectorExpr(ShuffleVectorExpr *E, - bool isAddressOfOperand) { +TreeTransform::TransformShuffleVectorExpr(ShuffleVectorExpr *E) { bool ArgumentChanged = false; ASTOwningVector<&ActionBase::DeleteExpr> SubExprs(SemaRef); for (unsigned I = 0, N = E->getNumSubExprs(); I != N; ++I) { @@ -5096,8 +5149,7 @@ TreeTransform::TransformShuffleVectorExpr(ShuffleVectorExpr *E, template Sema::OwningExprResult -TreeTransform::TransformBlockExpr(BlockExpr *E, - bool isAddressOfOperand) { +TreeTransform::TransformBlockExpr(BlockExpr *E) { // FIXME: Implement this! assert(false && "Cannot transform block expressions yet"); return SemaRef.Owned(E->Retain()); @@ -5105,8 +5157,7 @@ TreeTransform::TransformBlockExpr(BlockExpr *E, template Sema::OwningExprResult -TreeTransform::TransformBlockDeclRefExpr(BlockDeclRefExpr *E, - bool isAddressOfOperand) { +TreeTransform::TransformBlockDeclRefExpr(BlockDeclRefExpr *E) { // FIXME: Implement this! assert(false && "Cannot transform block-related expressions yet"); return SemaRef.Owned(E->Retain()); @@ -5281,6 +5332,30 @@ QualType TreeTransform::RebuildFunctionNoProtoType(QualType T) { return SemaRef.Context.getFunctionNoProtoType(T); } +template +QualType TreeTransform::RebuildUnresolvedUsingType(Decl *D) { + assert(D && "no decl found"); + if (D->isInvalidDecl()) return QualType(); + + TypeDecl *Ty; + if (isa(D)) { + UsingDecl *Using = cast(D); + assert(Using->isTypeName() && + "UnresolvedUsingTypenameDecl transformed to non-typename using"); + + // A valid resolved using typename decl points to exactly one type decl. + assert(++Using->shadow_begin() == Using->shadow_end()); + Ty = cast((*Using->shadow_begin())->getTargetDecl()); + + } else { + assert(isa(D) && + "UnresolvedUsingTypenameDecl transformed to non-using decl"); + Ty = cast(D); + } + + return SemaRef.Context.getTypeDeclType(Ty); +} + template QualType TreeTransform::RebuildTypeOfExprType(ExprArg E) { return SemaRef.BuildTypeofExprType(E.takeAs()); @@ -5320,7 +5395,7 @@ TreeTransform::RebuildNestedNameSpecifier(NestedNameSpecifier *Prefix, Range.getEnd(), II, ObjectType, FirstQualifierInScope, - false)); + false, false)); } template diff --git a/test/Analysis/CFDateGC.m b/test/Analysis/CFDateGC.m index b23998cfc68f..3c11465157ae 100644 --- a/test/Analysis/CFDateGC.m +++ b/test/Analysis/CFDateGC.m @@ -1,8 +1,8 @@ -// RUN: clang-cc -analyze -analyzer-experimental-internal-checks -checker-cfref -analyzer-store=basic -verify -fobjc-gc -analyzer-constraints=basic %s -// RUN: clang-cc -analyze -analyzer-experimental-internal-checks -checker-cfref -analyzer-store=basic -verify -fobjc-gc -analyzer-constraints=range %s -// RUN: clang-cc -analyze -analyzer-experimental-internal-checks -checker-cfref -analyzer-store=basic -verify -fobjc-gc -disable-free %s -// RUN: clang-cc -analyze -analyzer-experimental-internal-checks -checker-cfref -analyzer-store=region -analyzer-constraints=basic -verify -fobjc-gc %s -// RUN: clang-cc -analyze -analyzer-experimental-internal-checks -checker-cfref -analyzer-store=region -analyzer-constraints=range -verify -fobjc-gc %s +// RUN: clang -cc1 -analyze -analyzer-experimental-internal-checks -checker-cfref -analyzer-store=basic -verify -fobjc-gc -analyzer-constraints=basic %s +// RUN: clang -cc1 -analyze -analyzer-experimental-internal-checks -checker-cfref -analyzer-store=basic -verify -fobjc-gc -analyzer-constraints=range %s +// RUN: clang -cc1 -analyze -analyzer-experimental-internal-checks -checker-cfref -analyzer-store=basic -verify -fobjc-gc -disable-free %s +// RUN: clang -cc1 -analyze -analyzer-experimental-internal-checks -checker-cfref -analyzer-store=region -analyzer-constraints=basic -verify -fobjc-gc %s +// RUN: clang -cc1 -analyze -analyzer-experimental-internal-checks -checker-cfref -analyzer-store=region -analyzer-constraints=range -verify -fobjc-gc %s //===----------------------------------------------------------------------===// // The following code is reduced using delta-debugging from diff --git a/test/Analysis/CFNumber.c b/test/Analysis/CFNumber.c index f3d371cbde46..76d7ebbf15fc 100644 --- a/test/Analysis/CFNumber.c +++ b/test/Analysis/CFNumber.c @@ -1,7 +1,7 @@ -// RUN: clang-cc -analyze -analyzer-experimental-internal-checks -checker-cfref -analyzer-store=basic -analyzer-constraints=basic -verify -triple x86_64-apple-darwin9 %s -// RUN: clang-cc -analyze -analyzer-experimental-internal-checks -checker-cfref -analyzer-store=basic -analyzer-constraints=range -verify -triple x86_64-apple-darwin9 %s -// RUN: clang-cc -analyze -analyzer-experimental-internal-checks -checker-cfref -analyzer-store=region -analyzer-constraints=basic -verify -triple x86_64-apple-darwin9 %s -// RUN: clang-cc -analyze -analyzer-experimental-internal-checks -checker-cfref -analyzer-store=region -analyzer-constraints=range -verify -triple x86_64-apple-darwin9 %s +// RUN: clang -cc1 -analyze -analyzer-experimental-internal-checks -checker-cfref -analyzer-store=basic -analyzer-constraints=basic -verify -triple x86_64-apple-darwin9 %s +// RUN: clang -cc1 -analyze -analyzer-experimental-internal-checks -checker-cfref -analyzer-store=basic -analyzer-constraints=range -verify -triple x86_64-apple-darwin9 %s +// RUN: clang -cc1 -analyze -analyzer-experimental-internal-checks -checker-cfref -analyzer-store=region -analyzer-constraints=basic -verify -triple x86_64-apple-darwin9 %s +// RUN: clang -cc1 -analyze -analyzer-experimental-internal-checks -checker-cfref -analyzer-store=region -analyzer-constraints=range -verify -triple x86_64-apple-darwin9 %s typedef signed long CFIndex; typedef const struct __CFAllocator * CFAllocatorRef; diff --git a/test/Analysis/CFRetainRelease_NSAssertionHandler.m b/test/Analysis/CFRetainRelease_NSAssertionHandler.m index 04e9add58b5a..16f8db21e835 100644 --- a/test/Analysis/CFRetainRelease_NSAssertionHandler.m +++ b/test/Analysis/CFRetainRelease_NSAssertionHandler.m @@ -1,7 +1,7 @@ -// RUN: clang-cc -analyze -analyzer-experimental-internal-checks -checker-cfref -verify %s -analyzer-constraints=basic -analyzer-store=basic -// RUN: clang-cc -analyze -analyzer-experimental-internal-checks -checker-cfref -verify %s -analyzer-constraints=range -analyzer-store=basic -// RUN: clang-cc -analyze -analyzer-experimental-internal-checks -checker-cfref -verify %s -analyzer-constraints=basic -analyzer-store=region -// RUN: clang-cc -analyze -analyzer-experimental-internal-checks -checker-cfref -verify %s -analyzer-constraints=range -analyzer-store=region +// RUN: clang -cc1 -analyze -analyzer-experimental-internal-checks -checker-cfref -verify %s -analyzer-constraints=basic -analyzer-store=basic +// RUN: clang -cc1 -analyze -analyzer-experimental-internal-checks -checker-cfref -verify %s -analyzer-constraints=range -analyzer-store=basic +// RUN: clang -cc1 -analyze -analyzer-experimental-internal-checks -checker-cfref -verify %s -analyzer-constraints=basic -analyzer-store=region +// RUN: clang -cc1 -analyze -analyzer-experimental-internal-checks -checker-cfref -verify %s -analyzer-constraints=range -analyzer-store=region typedef struct objc_selector *SEL; typedef signed char BOOL; diff --git a/test/Analysis/CGColorSpace.c b/test/Analysis/CGColorSpace.c index ae628989cd61..d69f86e9fd4a 100644 --- a/test/Analysis/CGColorSpace.c +++ b/test/Analysis/CGColorSpace.c @@ -1,7 +1,7 @@ -// RUN: clang-cc -analyze -analyzer-experimental-internal-checks -checker-cfref -analyzer-store=basic -analyzer-constraints=basic -verify %s -// RUN: clang-cc -analyze -analyzer-experimental-internal-checks -checker-cfref -analyzer-store=basic -analyzer-constraints=range -verify %s -// RUN: clang-cc -analyze -analyzer-experimental-internal-checks -checker-cfref -analyzer-store=region -analyzer-constraints=basic -verify %s -// RUN: clang-cc -analyze -analyzer-experimental-internal-checks -checker-cfref -analyzer-store=region -analyzer-constraints=range -verify %s +// RUN: clang -cc1 -analyze -analyzer-experimental-internal-checks -checker-cfref -analyzer-store=basic -analyzer-constraints=basic -verify %s +// RUN: clang -cc1 -analyze -analyzer-experimental-internal-checks -checker-cfref -analyzer-store=basic -analyzer-constraints=range -verify %s +// RUN: clang -cc1 -analyze -analyzer-experimental-internal-checks -checker-cfref -analyzer-store=region -analyzer-constraints=basic -verify %s +// RUN: clang -cc1 -analyze -analyzer-experimental-internal-checks -checker-cfref -analyzer-store=region -analyzer-constraints=range -verify %s typedef struct CGColorSpace *CGColorSpaceRef; extern CGColorSpaceRef CGColorSpaceCreateDeviceRGB(void); diff --git a/test/Analysis/CheckNSError.m b/test/Analysis/CheckNSError.m index 219354b20fdf..ec44b22aa4fc 100644 --- a/test/Analysis/CheckNSError.m +++ b/test/Analysis/CheckNSError.m @@ -1,7 +1,7 @@ -// RUN: clang-cc -analyze -analyzer-experimental-internal-checks -checker-cfref -analyzer-store=basic -analyzer-constraints=basic -verify %s -// RUN: clang-cc -analyze -analyzer-experimental-internal-checks -checker-cfref -analyzer-store=region -analyzer-constraints=basic -verify %s -// RUN: clang-cc -analyze -analyzer-experimental-internal-checks -checker-cfref -analyzer-store=basic -analyzer-constraints=range -verify %s -// RUN: clang-cc -analyze -analyzer-experimental-internal-checks -checker-cfref -analyzer-store=region -analyzer-constraints=range -verify %s +// RUN: clang -cc1 -analyze -analyzer-experimental-internal-checks -checker-cfref -analyzer-store=basic -analyzer-constraints=basic -verify %s +// RUN: clang -cc1 -analyze -analyzer-experimental-internal-checks -checker-cfref -analyzer-store=region -analyzer-constraints=basic -verify %s +// RUN: clang -cc1 -analyze -analyzer-experimental-internal-checks -checker-cfref -analyzer-store=basic -analyzer-constraints=range -verify %s +// RUN: clang -cc1 -analyze -analyzer-experimental-internal-checks -checker-cfref -analyzer-store=region -analyzer-constraints=range -verify %s typedef signed char BOOL; diff --git a/test/Analysis/MissingDealloc.m b/test/Analysis/MissingDealloc.m index 21460a1a324d..cb5339a4cdab 100644 --- a/test/Analysis/MissingDealloc.m +++ b/test/Analysis/MissingDealloc.m @@ -1,4 +1,4 @@ -// RUN: clang-cc -analyze -analyzer-experimental-internal-checks -warn-objc-missing-dealloc '-DIBOutlet=__attribute__((iboutlet))' %s -verify +// RUN: clang -cc1 -analyze -analyzer-experimental-internal-checks -warn-objc-missing-dealloc '-DIBOutlet=__attribute__((iboutlet))' %s -verify typedef signed char BOOL; @protocol NSObject - (BOOL)isEqual:(id)object; diff --git a/test/Analysis/NSPanel.m b/test/Analysis/NSPanel.m index 20e3efff4c60..c98a685b1f40 100644 --- a/test/Analysis/NSPanel.m +++ b/test/Analysis/NSPanel.m @@ -1,7 +1,7 @@ -// RUN: clang-cc -analyze -analyzer-experimental-internal-checks -checker-cfref -analyzer-store=basic -analyzer-constraints=basic -verify %s -// RUN: clang-cc -analyze -analyzer-experimental-internal-checks -checker-cfref -analyzer-store=basic -analyzer-constraints=range -verify %s -// RUN: clang-cc -analyze -analyzer-experimental-internal-checks -checker-cfref -analyzer-store=region -analyzer-constraints=basic -verify %s -// RUN: clang-cc -analyze -analyzer-experimental-internal-checks -checker-cfref -analyzer-store=region -analyzer-constraints=range -verify %s +// RUN: clang -cc1 -analyze -analyzer-experimental-internal-checks -checker-cfref -analyzer-store=basic -analyzer-constraints=basic -verify %s +// RUN: clang -cc1 -analyze -analyzer-experimental-internal-checks -checker-cfref -analyzer-store=basic -analyzer-constraints=range -verify %s +// RUN: clang -cc1 -analyze -analyzer-experimental-internal-checks -checker-cfref -analyzer-store=region -analyzer-constraints=basic -verify %s +// RUN: clang -cc1 -analyze -analyzer-experimental-internal-checks -checker-cfref -analyzer-store=region -analyzer-constraints=range -verify %s // BEGIN delta-debugging reduced header stuff diff --git a/test/Analysis/NSString-failed-cases.m b/test/Analysis/NSString-failed-cases.m new file mode 100644 index 000000000000..b7f8be07cbcd --- /dev/null +++ b/test/Analysis/NSString-failed-cases.m @@ -0,0 +1,115 @@ +// 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 {} +- (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 +- (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 - (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/NSString.m b/test/Analysis/NSString.m index 481a94055ffd..d7804dc5f42a 100644 --- a/test/Analysis/NSString.m +++ b/test/Analysis/NSString.m @@ -1,13 +1,13 @@ -// RUN: clang-cc -triple i386-apple-darwin10 -analyze -analyzer-experimental-internal-checks -checker-cfref -analyzer-store=region -analyzer-constraints=basic -verify %s -// RUN: clang-cc -triple i386-apple-darwin10 -analyze -analyzer-experimental-internal-checks -checker-cfref -analyzer-store=region -analyzer-constraints=range -verify %s -// RUN: clang-cc -DTEST_64 -triple x86_64-apple-darwin10 -analyze -analyzer-experimental-internal-checks -checker-cfref -analyzer-store=region -analyzer-constraints=basic -verify %s -// RUN: clang-cc -DTEST_64 -triple x86_64-apple-darwin10 -analyze -analyzer-experimental-internal-checks -checker-cfref -analyzer-store=region -analyzer-constraints=range -verify %s +// 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 // ==-- FIXME: -analyzer-store=basic fails on this file (false negatives). --== -// NOTWORK: clang-cc -triple i386-apple-darwin10 -analyze -analyzer-experimental-internal-checks -checker-cfref -analyzer-store=basic -analyzer-constraints=range -verify %s && -// NOTWORK: clang-cc -triple i386-apple-darwin10 -analyze -analyzer-experimental-internal-checks -checker-cfref -analyzer-store=basic -analyzer-constraints=basic -verify %s && -// NOTWORK: clang-cc -DTEST_64 -triple x86_64-apple-darwin10 -analyze -analyzer-experimental-internal-checks -checker-cfref -analyzer-store=basic -analyzer-constraints=basic -verify %s && -// NOTWORK: clang-cc -DTEST_64 -triple x86_64-apple-darwin10 -analyze -analyzer-experimental-internal-checks -checker-cfref -analyzer-store=basic -analyzer-constraints=range -verify %s +// NOTWORK: clang -cc1 -triple i386-apple-darwin10 -analyze -analyzer-experimental-internal-checks -checker-cfref -analyzer-store=basic -analyzer-constraints=range -verify %s && +// NOTWORK: clang -cc1 -triple i386-apple-darwin10 -analyze -analyzer-experimental-internal-checks -checker-cfref -analyzer-store=basic -analyzer-constraints=basic -verify %s && +// NOTWORK: clang -cc1 -DTEST_64 -triple x86_64-apple-darwin10 -analyze -analyzer-experimental-internal-checks -checker-cfref -analyzer-store=basic -analyzer-constraints=basic -verify %s && +// NOTWORK: clang -cc1 -DTEST_64 -triple x86_64-apple-darwin10 -analyze -analyzer-experimental-internal-checks -checker-cfref -analyzer-store=basic -analyzer-constraints=range -verify %s //===----------------------------------------------------------------------===// // The following code is reduced using delta-debugging from @@ -291,7 +291,7 @@ void testOSCompareAndSwap() { [old release]; } -void testOSCompareAndSwapXXBarrier() { +void testOSCompareAndSwapXXBarrier_local() { NSString *old = 0; NSString *s = [[NSString alloc] init]; // no-warning if (!COMPARE_SWAP_BARRIER((intptr_t) 0, (intptr_t) s, (intptr_t*) &old)) @@ -300,9 +300,9 @@ void testOSCompareAndSwapXXBarrier() { [old release]; } -void testOSCompareAndSwapXXBarrier_positive() { +void testOSCompareAndSwapXXBarrier_local_no_direct_release() { NSString *old = 0; - NSString *s = [[NSString alloc] init]; // expected-warning{{leak}} + NSString *s = [[NSString alloc] init]; // no-warning if (!COMPARE_SWAP_BARRIER((intptr_t) 0, (intptr_t) s, (intptr_t*) &old)) return; else @@ -315,7 +315,7 @@ int testOSCompareAndSwapXXBarrier_id(Class myclass, id xclass) { return 0; } -void test_objc_atomicCompareAndSwap() { +void test_objc_atomicCompareAndSwap_local() { NSString *old = 0; NSString *s = [[NSString alloc] init]; // no-warning if (!objc_atomicCompareAndSwapPtr(0, s, &old)) @@ -324,15 +324,31 @@ void test_objc_atomicCompareAndSwap() { [old release]; } -void test_objc_atomicCompareAndSwap_positive() { +void test_objc_atomicCompareAndSwap_local_no_direct_release() { NSString *old = 0; - NSString *s = [[NSString alloc] init]; // expected-warning{{leak}} + NSString *s = [[NSString alloc] init]; // no-warning if (!objc_atomicCompareAndSwapPtr(0, s, &old)) return; else [old release]; } +void test_objc_atomicCompareAndSwap_parameter(NSString **old) { + NSString *s = [[NSString alloc] init]; // no-warning + if (!objc_atomicCompareAndSwapPtr(0, s, old)) + [s release]; + else + [*old release]; +} + +void test_objc_atomicCompareAndSwap_parameter_no_direct_release(NSString **old) { + NSString *s = [[NSString alloc] init]; // expected-warning{{leak}} + if (!objc_atomicCompareAndSwapPtr(0, s, old)) + return; + else + [*old release]; +} + // Test stringWithFormat () void test_stringWithFormat() { diff --git a/test/Analysis/NSWindow.m b/test/Analysis/NSWindow.m index 5eb6cf1e4770..6d017293cc68 100644 --- a/test/Analysis/NSWindow.m +++ b/test/Analysis/NSWindow.m @@ -1,7 +1,7 @@ -// RUN: clang-cc -analyze -analyzer-experimental-internal-checks -checker-cfref -warn-dead-stores -analyzer-store=basic -analyzer-constraints=basic -verify %s -// RUN: clang-cc -analyze -analyzer-experimental-internal-checks -checker-cfref -warn-dead-stores -analyzer-store=basic -analyzer-constraints=range -verify %s -// RUN: clang-cc -analyze -analyzer-experimental-internal-checks -checker-cfref -warn-dead-stores -analyzer-store=region -analyzer-constraints=basic -verify %s -// RUN: clang-cc -analyze -analyzer-experimental-internal-checks -checker-cfref -warn-dead-stores -analyzer-store=region -analyzer-constraints=range -verify %s +// RUN: clang -cc1 -analyze -analyzer-experimental-internal-checks -checker-cfref -warn-dead-stores -analyzer-store=basic -analyzer-constraints=basic -verify %s +// RUN: clang -cc1 -analyze -analyzer-experimental-internal-checks -checker-cfref -warn-dead-stores -analyzer-store=basic -analyzer-constraints=range -verify %s +// RUN: clang -cc1 -analyze -analyzer-experimental-internal-checks -checker-cfref -warn-dead-stores -analyzer-store=region -analyzer-constraints=basic -verify %s +// RUN: clang -cc1 -analyze -analyzer-experimental-internal-checks -checker-cfref -warn-dead-stores -analyzer-store=region -analyzer-constraints=range -verify %s // These declarations were reduced using Delta-Debugging from Foundation.h // on Mac OS X. The test cases are below. diff --git a/test/Analysis/NoReturn.m b/test/Analysis/NoReturn.m index cf708b4f8970..ad441a3b9b84 100644 --- a/test/Analysis/NoReturn.m +++ b/test/Analysis/NoReturn.m @@ -1,7 +1,7 @@ -// RUN: clang-cc -analyze -analyzer-experimental-internal-checks -checker-cfref -analyzer-store=basic -analyzer-constraints=basic -verify %s -// RUN: clang-cc -analyze -analyzer-experimental-internal-checks -checker-cfref -analyzer-store=basic -analyzer-constraints=range -verify %s -// RUN: clang-cc -analyze -analyzer-experimental-internal-checks -checker-cfref -analyzer-store=region -analyzer-constraints=basic -verify %s -// RUN: clang-cc -analyze -analyzer-experimental-internal-checks -checker-cfref -analyzer-store=region -analyzer-constraints=range -verify %s +// RUN: clang -cc1 -analyze -analyzer-experimental-internal-checks -checker-cfref -analyzer-store=basic -analyzer-constraints=basic -verify %s +// RUN: clang -cc1 -analyze -analyzer-experimental-internal-checks -checker-cfref -analyzer-store=basic -analyzer-constraints=range -verify %s +// RUN: clang -cc1 -analyze -analyzer-experimental-internal-checks -checker-cfref -analyzer-store=region -analyzer-constraints=basic -verify %s +// RUN: clang -cc1 -analyze -analyzer-experimental-internal-checks -checker-cfref -analyzer-store=region -analyzer-constraints=range -verify %s #include diff --git a/test/Analysis/ObjCProperties.m b/test/Analysis/ObjCProperties.m index 6c367f427d46..89d8f9b297b1 100644 --- a/test/Analysis/ObjCProperties.m +++ b/test/Analysis/ObjCProperties.m @@ -1,7 +1,7 @@ -// RUN: clang-cc -analyze -analyzer-experimental-internal-checks -checker-cfref -analyzer-store=basic -analyzer-constraints=basic %s -verify -// RUN: clang-cc -analyze -analyzer-experimental-internal-checks -checker-cfref -analyzer-store=basic -analyzer-constraints=range %s -verify -// RUN: clang-cc -analyze -analyzer-experimental-internal-checks -checker-cfref -analyzer-store=region -analyzer-constraints=basic %s -verify -// RUN: clang-cc -analyze -analyzer-experimental-internal-checks -checker-cfref -analyzer-store=region -analyzer-constraints=range %s -verify +// RUN: clang -cc1 -analyze -analyzer-experimental-internal-checks -checker-cfref -analyzer-store=basic -analyzer-constraints=basic %s -verify +// RUN: clang -cc1 -analyze -analyzer-experimental-internal-checks -checker-cfref -analyzer-store=basic -analyzer-constraints=range %s -verify +// RUN: clang -cc1 -analyze -analyzer-experimental-internal-checks -checker-cfref -analyzer-store=region -analyzer-constraints=basic %s -verify +// RUN: clang -cc1 -analyze -analyzer-experimental-internal-checks -checker-cfref -analyzer-store=region -analyzer-constraints=range %s -verify // The point of this test cases is to exercise properties in the static // analyzer diff --git a/test/Analysis/ObjCRetSigs.m b/test/Analysis/ObjCRetSigs.m index 60a85fd791ed..416ef1c8eed8 100644 --- a/test/Analysis/ObjCRetSigs.m +++ b/test/Analysis/ObjCRetSigs.m @@ -1,4 +1,4 @@ -// RUN: clang-cc -analyze -analyzer-experimental-internal-checks -warn-objc-methodsigs -verify %s +// RUN: clang -cc1 -analyze -analyzer-experimental-internal-checks -warn-objc-methodsigs -verify %s int printf(const char *, ...); diff --git a/test/Analysis/PR2599.m b/test/Analysis/PR2599.m index fd5ae95d5842..ea71ad2a237b 100644 --- a/test/Analysis/PR2599.m +++ b/test/Analysis/PR2599.m @@ -1,7 +1,7 @@ -// RUN: clang-cc -analyze -analyzer-experimental-internal-checks -analyzer-constraints=basic -analyzer-store=basic -checker-cfref -fobjc-gc -verify %s -// RUN: clang-cc -analyze -analyzer-experimental-internal-checks -analyzer-constraints=range -analyzer-store=basic -checker-cfref -fobjc-gc -verify %s -// RUN: clang-cc -analyze -analyzer-experimental-internal-checks -analyzer-constraints=basic -analyzer-store=basic -checker-cfref -fobjc-gc -verify %s -// RUN: clang-cc -analyze -analyzer-experimental-internal-checks -analyzer-constraints=range -analyzer-store=region -checker-cfref -fobjc-gc -verify %s +// RUN: clang -cc1 -analyze -analyzer-experimental-internal-checks -analyzer-constraints=basic -analyzer-store=basic -checker-cfref -fobjc-gc -verify %s +// RUN: clang -cc1 -analyze -analyzer-experimental-internal-checks -analyzer-constraints=range -analyzer-store=basic -checker-cfref -fobjc-gc -verify %s +// RUN: clang -cc1 -analyze -analyzer-experimental-internal-checks -analyzer-constraints=basic -analyzer-store=basic -checker-cfref -fobjc-gc -verify %s +// RUN: clang -cc1 -analyze -analyzer-experimental-internal-checks -analyzer-constraints=range -analyzer-store=region -checker-cfref -fobjc-gc -verify %s typedef const void * CFTypeRef; typedef const struct __CFString * CFStringRef; diff --git a/test/Analysis/PR2978.m b/test/Analysis/PR2978.m index 8a94fe848993..428997f709c6 100644 --- a/test/Analysis/PR2978.m +++ b/test/Analysis/PR2978.m @@ -1,4 +1,4 @@ -// RUN: clang-cc -analyze -analyzer-experimental-internal-checks -warn-objc-missing-dealloc %s -verify +// RUN: clang -cc1 -analyze -analyzer-experimental-internal-checks -warn-objc-missing-dealloc %s -verify // Tests for the checker which checks missing/extra ivar 'release' calls // in dealloc. diff --git a/test/Analysis/PR3991.m b/test/Analysis/PR3991.m index 53a6b5257a77..a1d465734df7 100644 --- a/test/Analysis/PR3991.m +++ b/test/Analysis/PR3991.m @@ -1,7 +1,7 @@ -// RUN: clang-cc -analyze -analyzer-experimental-internal-checks -checker-cfref -analyzer-store=basic -analyzer-constraints=basic -verify -triple x86_64-apple-darwin9 %s -// RUN: clang-cc -analyze -analyzer-experimental-internal-checks -checker-cfref -analyzer-store=basic -analyzer-constraints=range -verify -triple x86_64-apple-darwin9 %s -// RUN: clang-cc -analyze -analyzer-experimental-internal-checks -checker-cfref -analyzer-store=region -analyzer-constraints=basic -verify -triple x86_64-apple-darwin9 %s -// RUN: clang-cc -analyze -analyzer-experimental-internal-checks -checker-cfref -analyzer-store=region -analyzer-constraints=range -verify -triple x86_64-apple-darwin9 %s +// RUN: clang -cc1 -analyze -analyzer-experimental-internal-checks -checker-cfref -analyzer-store=basic -analyzer-constraints=basic -verify -triple x86_64-apple-darwin9 %s +// RUN: clang -cc1 -analyze -analyzer-experimental-internal-checks -checker-cfref -analyzer-store=basic -analyzer-constraints=range -verify -triple x86_64-apple-darwin9 %s +// RUN: clang -cc1 -analyze -analyzer-experimental-internal-checks -checker-cfref -analyzer-store=region -analyzer-constraints=basic -verify -triple x86_64-apple-darwin9 %s +// RUN: clang -cc1 -analyze -analyzer-experimental-internal-checks -checker-cfref -analyzer-store=region -analyzer-constraints=range -verify -triple x86_64-apple-darwin9 %s //===----------------------------------------------------------------------===// // Delta-debugging produced forward declarations. diff --git a/test/Analysis/array-struct.c b/test/Analysis/array-struct.c index c3822cdb443a..2a833c48ff13 100644 --- a/test/Analysis/array-struct.c +++ b/test/Analysis/array-struct.c @@ -1,7 +1,7 @@ -// RUN: clang-cc -analyze -analyzer-experimental-internal-checks -checker-cfref -analyzer-store=basic -analyzer-constraints=basic -verify %s -// RUN: clang-cc -analyze -analyzer-experimental-internal-checks -checker-cfref -analyzer-store=basic -analyzer-constraints=range -verify %s -// RUN: clang-cc -analyze -analyzer-experimental-internal-checks -checker-cfref -analyzer-store=region -analyzer-constraints=basic -verify %s -// RUN: clang-cc -analyze -analyzer-experimental-internal-checks -checker-cfref -analyzer-store=region -analyzer-constraints=range -verify %s +// RUN: clang -cc1 -analyze -analyzer-experimental-internal-checks -checker-cfref -analyzer-store=basic -analyzer-constraints=basic -verify %s +// RUN: clang -cc1 -analyze -analyzer-experimental-internal-checks -checker-cfref -analyzer-store=basic -analyzer-constraints=range -verify %s +// RUN: clang -cc1 -analyze -analyzer-experimental-internal-checks -checker-cfref -analyzer-store=region -analyzer-constraints=basic -verify %s +// RUN: clang -cc1 -analyze -analyzer-experimental-internal-checks -checker-cfref -analyzer-store=region -analyzer-constraints=range -verify %s struct s { int data; diff --git a/test/Analysis/blocks.m b/test/Analysis/blocks.m new file mode 100644 index 000000000000..50a9d06e8f93 --- /dev/null +++ b/test/Analysis/blocks.m @@ -0,0 +1,69 @@ +// RUN: clang -cc1 -triple x86_64-apple-darwin10 -analyze -checker-cfref -analyzer-store=region -fblocks -verify %s + +//===----------------------------------------------------------------------===// +// The following code is reduced using delta-debugging from Mac OS X headers: +//===----------------------------------------------------------------------===// + +typedef __builtin_va_list va_list; +typedef unsigned int uint32_t; +typedef struct dispatch_queue_s *dispatch_queue_t; +typedef struct dispatch_queue_attr_s *dispatch_queue_attr_t; +typedef void (^dispatch_block_t)(void); +void dispatch_async(dispatch_queue_t queue, dispatch_block_t block); +__attribute__((visibility("default"))) __attribute__((__malloc__)) __attribute__((__warn_unused_result__)) __attribute__((__nothrow__)) dispatch_queue_t dispatch_queue_create(const char *label, dispatch_queue_attr_t attr); +typedef long dispatch_once_t; +void dispatch_once(dispatch_once_t *predicate, dispatch_block_t block); +typedef signed char BOOL; +typedef unsigned long NSUInteger; +typedef struct _NSZone NSZone; +@class NSInvocation, NSMethodSignature, NSCoder, NSString, NSEnumerator; +@protocol NSObject +- (BOOL)isEqual:(id)object; +- (oneway void)release; +@end +@protocol NSCopying - (id)copyWithZone:(NSZone *)zone; @end +@protocol NSMutableCopying - (id)mutableCopyWithZone:(NSZone *)zone; @end +@protocol NSCoding - (void)encodeWithCoder:(NSCoder *)aCoder; @end +@interface NSObject {} ++ (id)alloc; +@end +extern id NSAllocateObject(Class aClass, NSUInteger extraBytes, NSZone *zone); +@interface NSString : NSObject - (NSUInteger)length; +- ( const char *)UTF8String; +- (id)initWithFormat:(NSString *)format arguments:(va_list)argList __attribute__((format(__NSString__, 1, 0))); +@end +@class NSString, NSData; +typedef struct cssm_sample {} CSSM_SAMPLEGROUP, *CSSM_SAMPLEGROUP_PTR; +typedef struct __aslclient *aslclient; +typedef struct __aslmsg *aslmsg; +aslclient asl_open(const char *ident, const char *facility, uint32_t opts); +int asl_log(aslclient asl, aslmsg msg, int level, const char *format, ...) __attribute__((__format__ (__printf__, 4, 5))); + +//===----------------------------------------------------------------------===// +// Begin actual test cases. +//===----------------------------------------------------------------------===// + +// test1 - This test case exposed logic that caused the analyzer to crash because of a memory bug +// in BlockDataRegion. It represents real code that contains two block literals. Eventually +// via IPA 'logQueue' and 'client' should be updated after the call to 'dispatch_once'. +void test1(NSString *format, ...) { + static dispatch_queue_t logQueue; + static aslclient client; + static dispatch_once_t pred; + do { + if (__builtin_expect(*(&pred), ~0l) != ~0l) + dispatch_once(&pred, ^{ + logQueue = dispatch_queue_create("com.mycompany.myproduct.asl", ((void*)0)); + client = asl_open(((void*)0), "com.mycompany.myproduct", 0); + }); + } while (0); + + va_list args; + __builtin_va_start(args, format); + + NSString *str = [[NSString alloc] initWithFormat:format arguments:args]; + dispatch_async(logQueue, ^{ asl_log(client, ((void*)0), 4, "%s", [str UTF8String]); }); + [str release]; + + __builtin_va_end(args); +} diff --git a/test/Analysis/casts.c b/test/Analysis/casts.c index bee337a44572..3c6b83b72391 100644 --- a/test/Analysis/casts.c +++ b/test/Analysis/casts.c @@ -1,4 +1,4 @@ -// RUN: clang-cc -triple x86_64-apple-darwin9 -analyze -analyzer-experimental-internal-checks -checker-cfref -analyzer-store=region -verify %s +// RUN: clang -cc1 -triple x86_64-apple-darwin9 -analyze -analyzer-experimental-internal-checks -checker-cfref -analyzer-store=region -verify %s // Test if the 'storage' region gets properly initialized after it is cast to // 'struct sockaddr *'. diff --git a/test/Analysis/casts.m b/test/Analysis/casts.m index 69a4260537bd..fb4252014b01 100644 --- a/test/Analysis/casts.m +++ b/test/Analysis/casts.m @@ -1,5 +1,5 @@ -// RUN: clang-cc -analyze -analyzer-experimental-internal-checks -checker-cfref -analyzer-store=basic -verify %s -// RUN: clang-cc -analyze -analyzer-experimental-internal-checks -checker-cfref -analyzer-store=region -verify %s +// RUN: clang -cc1 -analyze -analyzer-experimental-internal-checks -checker-cfref -analyzer-store=basic -verify %s +// RUN: clang -cc1 -analyze -analyzer-experimental-internal-checks -checker-cfref -analyzer-store=region -verify %s // Test function pointer casts. Currently we track function addresses using // loc::FunctionVal. Because casts can be arbitrary, do we need to model diff --git a/test/Analysis/cfref_PR2519.c b/test/Analysis/cfref_PR2519.c index d9367d4af61c..48f757e51a71 100644 --- a/test/Analysis/cfref_PR2519.c +++ b/test/Analysis/cfref_PR2519.c @@ -1,7 +1,7 @@ -// RUN: clang-cc -analyze -analyzer-experimental-internal-checks -checker-cfref -analyzer-store=basic -analyzer-constraints=basic -verify %s -// RUN: clang-cc -analyze -analyzer-experimental-internal-checks -checker-cfref -analyzer-store=basic -analyzer-constraints=range -verify %s -// RUN: clang-cc -analyze -analyzer-experimental-internal-checks -checker-cfref -analyzer-store=region -analyzer-constraints=basic -verify %s -// RUN: clang-cc -analyze -analyzer-experimental-internal-checks -checker-cfref -analyzer-store=region -analyzer-constraints=range -verify %s +// RUN: clang -cc1 -analyze -analyzer-experimental-internal-checks -checker-cfref -analyzer-store=basic -analyzer-constraints=basic -verify %s +// RUN: clang -cc1 -analyze -analyzer-experimental-internal-checks -checker-cfref -analyzer-store=basic -analyzer-constraints=range -verify %s +// RUN: clang -cc1 -analyze -analyzer-experimental-internal-checks -checker-cfref -analyzer-store=region -analyzer-constraints=basic -verify %s +// RUN: clang -cc1 -analyze -analyzer-experimental-internal-checks -checker-cfref -analyzer-store=region -analyzer-constraints=range -verify %s typedef unsigned char Boolean; typedef signed long CFIndex; diff --git a/test/Analysis/cfref_rdar6080742.c b/test/Analysis/cfref_rdar6080742.c index a2b7477db8bc..27b4c51f96b7 100644 --- a/test/Analysis/cfref_rdar6080742.c +++ b/test/Analysis/cfref_rdar6080742.c @@ -1,7 +1,7 @@ -// RUN: clang-cc -analyze -analyzer-experimental-internal-checks -checker-cfref -analyzer-store=basic -analyzer-constraints=basic -verify %s -// RUN: clang-cc -analyze -analyzer-experimental-internal-checks -checker-cfref -analyzer-store=basic -analyzer-constraints=range -verify %s -// RUN: clang-cc -analyze -analyzer-experimental-internal-checks -checker-cfref -analyzer-store=region -analyzer-constraints=basic -verify %s -// RUN: clang-cc -analyze -analyzer-experimental-internal-checks -checker-cfref -analyzer-store=region -analyzer-constraints=range -verify %s +// RUN: clang -cc1 -analyze -analyzer-experimental-internal-checks -checker-cfref -analyzer-store=basic -analyzer-constraints=basic -verify %s +// RUN: clang -cc1 -analyze -analyzer-experimental-internal-checks -checker-cfref -analyzer-store=basic -analyzer-constraints=range -verify %s +// RUN: clang -cc1 -analyze -analyzer-experimental-internal-checks -checker-cfref -analyzer-store=region -analyzer-constraints=basic -verify %s +// RUN: clang -cc1 -analyze -analyzer-experimental-internal-checks -checker-cfref -analyzer-store=region -analyzer-constraints=range -verify %s // This test case was reported in . // It tests path-sensitivity with respect to '!(cfstring != 0)' (negation of inequality). diff --git a/test/Analysis/complex.c b/test/Analysis/complex.c index 6b71a93e65a9..605255e555ab 100644 --- a/test/Analysis/complex.c +++ b/test/Analysis/complex.c @@ -1,7 +1,7 @@ -// RUN: clang-cc -analyze -analyzer-experimental-internal-checks -checker-cfref -analyzer-store=basic -analyzer-constraints=basic -verify %s -// RUN: clang-cc -analyze -analyzer-experimental-internal-checks -checker-cfref -analyzer-store=basic -analyzer-constraints=range -verify %s -// RUN: clang-cc -analyze -analyzer-experimental-internal-checks -checker-cfref -analyzer-store=region -analyzer-constraints=basic -verify %s -// RUN: clang-cc -analyze -analyzer-experimental-internal-checks -checker-cfref -analyzer-store=region -analyzer-constraints=range -verify %s +// RUN: clang -cc1 -analyze -analyzer-experimental-internal-checks -checker-cfref -analyzer-store=basic -analyzer-constraints=basic -verify %s +// RUN: clang -cc1 -analyze -analyzer-experimental-internal-checks -checker-cfref -analyzer-store=basic -analyzer-constraints=range -verify %s +// RUN: clang -cc1 -analyze -analyzer-experimental-internal-checks -checker-cfref -analyzer-store=region -analyzer-constraints=basic -verify %s +// RUN: clang -cc1 -analyze -analyzer-experimental-internal-checks -checker-cfref -analyzer-store=region -analyzer-constraints=range -verify %s #include diff --git a/test/Analysis/concrete-address.c b/test/Analysis/concrete-address.c index 96080bec3243..fdede4beec70 100644 --- a/test/Analysis/concrete-address.c +++ b/test/Analysis/concrete-address.c @@ -1,5 +1,5 @@ -// RUN: clang-cc -analyze -analyzer-experimental-internal-checks -checker-cfref -analyzer-store=basic -verify %s -// RUN: clang-cc -analyze -analyzer-experimental-internal-checks -checker-cfref -analyzer-store=region -verify %s +// RUN: clang -cc1 -analyze -analyzer-experimental-internal-checks -checker-cfref -analyzer-store=basic -verify %s +// RUN: clang -cc1 -analyze -analyzer-experimental-internal-checks -checker-cfref -analyzer-store=region -verify %s void foo() { int *p = (int*) 0x10000; // Should not crash here. diff --git a/test/Analysis/conditional-op-missing-lhs.c b/test/Analysis/conditional-op-missing-lhs.c index ed81d7b67200..4b0378579901 100644 --- a/test/Analysis/conditional-op-missing-lhs.c +++ b/test/Analysis/conditional-op-missing-lhs.c @@ -1,4 +1,4 @@ -// RUN: clang-cc -analyze -analyzer-experimental-internal-checks -warn-dead-stores -warn-uninit-values -verify %s +// RUN: clang -cc1 -analyze -analyzer-experimental-internal-checks -warn-dead-stores -warn-uninit-values -verify %s void f1() { diff --git a/test/Analysis/dead-stores.c b/test/Analysis/dead-stores.c index e29eefd8eb8b..a0e889f2daa0 100644 --- a/test/Analysis/dead-stores.c +++ b/test/Analysis/dead-stores.c @@ -1,8 +1,8 @@ -// RUN: clang-cc -analyze -analyzer-experimental-internal-checks -warn-dead-stores -fblocks -verify %s -// RUN: clang-cc -analyze -analyzer-experimental-internal-checks -checker-cfref -analyzer-store=basic -analyzer-constraints=basic -warn-dead-stores -fblocks -verify %s -// RUN: clang-cc -analyze -analyzer-experimental-internal-checks -checker-cfref -analyzer-store=basic -analyzer-constraints=range -warn-dead-stores -fblocks -verify %s -// RUN: clang-cc -analyze -analyzer-experimental-internal-checks -checker-cfref -analyzer-store=region -analyzer-constraints=basic -warn-dead-stores -fblocks -verify %s -// RUN: clang-cc -analyze -analyzer-experimental-internal-checks -checker-cfref -analyzer-store=region -analyzer-constraints=range -warn-dead-stores -fblocks -verify %s +// RUN: clang -cc1 -analyze -analyzer-experimental-internal-checks -warn-dead-stores -fblocks -verify %s +// RUN: clang -cc1 -analyze -analyzer-experimental-internal-checks -checker-cfref -analyzer-store=basic -analyzer-constraints=basic -warn-dead-stores -fblocks -verify %s +// RUN: clang -cc1 -analyze -analyzer-experimental-internal-checks -checker-cfref -analyzer-store=basic -analyzer-constraints=range -warn-dead-stores -fblocks -verify %s +// RUN: clang -cc1 -analyze -analyzer-experimental-internal-checks -checker-cfref -analyzer-store=region -analyzer-constraints=basic -warn-dead-stores -fblocks -verify %s +// RUN: clang -cc1 -analyze -analyzer-experimental-internal-checks -checker-cfref -analyzer-store=region -analyzer-constraints=range -warn-dead-stores -fblocks -verify %s void f1() { int k, y; @@ -370,3 +370,60 @@ void f23_pos(int argc, char **argv) { f23_aux("I did too use it!\n"); }(); } + +void f24_A(int y) { + // FIXME: One day this should be reported as dead since 'z = x + y' is dead. + int x = (y > 2); // no-warning + ^ { + int z = x + y; // FIXME: Eventually this should be reported as a dead store. + }(); +} + +void f24_B(int y) { + // FIXME: One day this should be reported as dead since 'x' is just overwritten. + __block int x = (y > 2); // no-warning + ^{ + // FIXME: This should eventually be a dead store since it is never read either. + x = 5; // no-warning + }(); +} + +int f24_C(int y) { + // FIXME: One day this should be reported as dead since 'x' is just overwritten. + __block int x = (y > 2); // no-warning + ^{ + x = 5; // no-warning + }(); + return x; +} + +int f24_D(int y) { + __block int x = (y > 2); // no-warning + ^{ + if (y > 4) + x = 5; // no-warning + }(); + return x; +} + +// This example shows that writing to a variable captured by a block means that it might +// not be dead. +int f25(int y) { + __block int x = (y > 2); + __block int z = 0; + void (^foo)() = ^{ z = x + y; }; + x = 4; // no-warning + foo(); + return z; +} + +// This test is mostly the same as 'f25', but shows that the heuristic of pruning out dead +// stores for variables that are just marked '__block' is overly conservative. +int f25_b(int y) { + // FIXME: we should eventually report a dead store here. + __block int x = (y > 2); + __block int z = 0; + x = 4; // no-warning + return z; +} + diff --git a/test/Analysis/dead-stores.cpp b/test/Analysis/dead-stores.cpp index 0bf32567f9db..363cfdd98cc6 100644 --- a/test/Analysis/dead-stores.cpp +++ b/test/Analysis/dead-stores.cpp @@ -1,8 +1,12 @@ -// RUN: clang-cc -analyze -analyzer-experimental-internal-checks -warn-dead-stores -verify %s -// RUN: clang-cc -analyze -analyzer-experimental-internal-checks -checker-cfref -analyzer-store=basic -analyzer-constraints=basic -warn-dead-stores -verify %s -// RUN: clang-cc -analyze -analyzer-experimental-internal-checks -checker-cfref -analyzer-store=basic -analyzer-constraints=range -warn-dead-stores -verify %s -// RUN: clang-cc -analyze -analyzer-experimental-internal-checks -checker-cfref -analyzer-store=region -analyzer-constraints=basic -warn-dead-stores -verify %s -// RUN: clang-cc -analyze -analyzer-experimental-internal-checks -checker-cfref -analyzer-store=region -analyzer-constraints=range -warn-dead-stores -verify %s +// RUN: clang -cc1 -analyze -analyzer-experimental-internal-checks -warn-dead-stores -verify %s +// RUN: clang -cc1 -analyze -analyzer-experimental-internal-checks -checker-cfref -analyzer-store=basic -analyzer-constraints=basic -warn-dead-stores -verify %s +// RUN: clang -cc1 -analyze -analyzer-experimental-internal-checks -checker-cfref -analyzer-store=basic -analyzer-constraints=range -warn-dead-stores -verify %s +// RUN: clang -cc1 -analyze -analyzer-experimental-internal-checks -checker-cfref -analyzer-store=region -analyzer-constraints=basic -warn-dead-stores -verify %s +// RUN: clang -cc1 -analyze -analyzer-experimental-internal-checks -checker-cfref -analyzer-store=region -analyzer-constraints=range -warn-dead-stores -verify %s + +//===----------------------------------------------------------------------===// +// Basic dead store checking (but in C++ mode). +//===----------------------------------------------------------------------===// int j; void f1() { @@ -17,3 +21,19 @@ void f1() { break; } } + +//===----------------------------------------------------------------------===// +// Dead store checking involving constructors. +//===----------------------------------------------------------------------===// + +class Test1 { + int &x; +public: + Test1(int &y) : x(y) {} + ~Test1() { ++x; } +}; + +int test_ctor_1(int x) { + { Test1 a(x); } // no-warning + return x; +} diff --git a/test/Analysis/dead-stores.m b/test/Analysis/dead-stores.m index 0a5c0f837301..4ad3c0a42da4 100644 --- a/test/Analysis/dead-stores.m +++ b/test/Analysis/dead-stores.m @@ -1,4 +1,4 @@ -// RUN: clang-cc -analyze -analyzer-experimental-internal-checks -warn-dead-stores -verify %s +// RUN: clang -cc1 -analyze -analyzer-experimental-internal-checks -warn-dead-stores -verify %s typedef signed char BOOL; typedef unsigned int NSUInteger; diff --git a/test/Analysis/delegates.m b/test/Analysis/delegates.m index b854da6ec330..df97866b8558 100644 --- a/test/Analysis/delegates.m +++ b/test/Analysis/delegates.m @@ -1,5 +1,5 @@ -// RUN: clang-cc -analyze -analyzer-experimental-internal-checks -checker-cfref -analyzer-store=basic -verify %s -// RUN: clang-cc -analyze -analyzer-experimental-internal-checks -checker-cfref -analyzer-store=region -verify %s +// RUN: clang -cc1 -analyze -analyzer-experimental-internal-checks -checker-cfref -analyzer-store=basic -verify %s +// RUN: clang -cc1 -analyze -analyzer-experimental-internal-checks -checker-cfref -analyzer-store=region -verify %s //===----------------------------------------------------------------------===// diff --git a/test/Analysis/elementtype.c b/test/Analysis/elementtype.c index b6873ad89980..f3eee2634241 100644 --- a/test/Analysis/elementtype.c +++ b/test/Analysis/elementtype.c @@ -1,4 +1,4 @@ -// RUN: clang-cc -analyze -analyzer-experimental-internal-checks -checker-cfref -analyzer-store=region %s +// RUN: clang -cc1 -analyze -analyzer-experimental-internal-checks -checker-cfref -analyzer-store=region %s typedef struct added_obj_st { int type; diff --git a/test/Analysis/exercise-ps.c b/test/Analysis/exercise-ps.c index 098ec48f4ea3..13f075de5ea1 100644 --- a/test/Analysis/exercise-ps.c +++ b/test/Analysis/exercise-ps.c @@ -1,5 +1,5 @@ -// RUN: clang-cc -analyze -analyzer-experimental-internal-checks -checker-cfref -analyzer-store=basic -verify %s -// RUN: clang-cc -analyze -analyzer-experimental-internal-checks -checker-cfref -analyzer-store=region -verify %s +// RUN: clang -cc1 -analyze -analyzer-experimental-internal-checks -checker-cfref -analyzer-store=basic -verify %s +// RUN: clang -cc1 -analyze -analyzer-experimental-internal-checks -checker-cfref -analyzer-store=region -verify %s // // Just exercise the analyzer on code that has at one point caused issues // (i.e., no assertions or crashes). diff --git a/test/Analysis/fields.c b/test/Analysis/fields.c index 7ea6111bd48c..e34191850036 100644 --- a/test/Analysis/fields.c +++ b/test/Analysis/fields.c @@ -1,5 +1,5 @@ -// RUN: clang-cc -analyze -analyzer-experimental-internal-checks -checker-cfref %s -analyzer-store=basic -verify -// RUN: clang-cc -analyze -analyzer-experimental-internal-checks -checker-cfref %s -analyzer-store=region -verify +// RUN: clang -cc1 -analyze -analyzer-experimental-internal-checks -checker-cfref %s -analyzer-store=basic -verify +// RUN: clang -cc1 -analyze -analyzer-experimental-internal-checks -checker-cfref %s -analyzer-store=region -verify unsigned foo(); typedef struct bf { unsigned x:2; } bf; diff --git a/test/Analysis/func.c b/test/Analysis/func.c index 390a2793a497..449a4c29ced8 100644 --- a/test/Analysis/func.c +++ b/test/Analysis/func.c @@ -1,5 +1,5 @@ -// RUN: clang-cc -analyze -analyzer-experimental-internal-checks -checker-cfref -analyzer-store=basic -verify %s -// RUN: clang-cc -analyze -analyzer-experimental-internal-checks -checker-cfref -analyzer-store=region -verify %s +// RUN: clang -cc1 -analyze -analyzer-experimental-internal-checks -checker-cfref -analyzer-store=basic -verify %s +// RUN: clang -cc1 -analyze -analyzer-experimental-internal-checks -checker-cfref -analyzer-store=region -verify %s void f(void) { void (*p)(void); diff --git a/test/Analysis/malloc.c b/test/Analysis/malloc.c index 6a17cba3497b..0c5142ba4d3f 100644 --- a/test/Analysis/malloc.c +++ b/test/Analysis/malloc.c @@ -1,7 +1,9 @@ -// RUN: clang-cc -analyze -analyzer-experimental-internal-checks -checker-cfref -analyzer-experimental-checks -analyzer-store=region -verify %s +// RUN: clang -cc1 -analyze -analyzer-experimental-internal-checks -checker-cfref -analyzer-experimental-checks -analyzer-store=region -verify %s typedef __typeof(sizeof(int)) size_t; void *malloc(size_t); void free(void *); +void *realloc(void *ptr, size_t size); +void *calloc(size_t nmemb, size_t size); void f1() { int *p = malloc(10); @@ -35,3 +37,9 @@ int *f4() { p_f4 = malloc(10); return p_f4; // no-warning } + +int *f5() { + int *q = malloc(10); + q = realloc(q, 20); + return q; // no-warning +} diff --git a/test/Analysis/misc-ps-64.m b/test/Analysis/misc-ps-64.m index f520784e11d3..ec4c3b4c65e9 100644 --- a/test/Analysis/misc-ps-64.m +++ b/test/Analysis/misc-ps-64.m @@ -1,7 +1,7 @@ -// RUN: clang-cc -triple x86_64-apple-darwin9 -analyze -analyzer-experimental-internal-checks -checker-cfref -analyzer-store=basic -analyzer-constraints=basic -verify -fblocks %s -// RUN: clang-cc -triple x86_64-apple-darwin9 -analyze -analyzer-experimental-internal-checks -checker-cfref -analyzer-store=basic -analyzer-constraints=range -verify -fblocks %s -// RUN: clang-cc -triple x86_64-apple-darwin9 -analyze -analyzer-experimental-internal-checks -checker-cfref -analyzer-store=region -analyzer-constraints=basic -verify -fblocks %s -// RUN: clang-cc -triple x86_64-apple-darwin9 -analyze -analyzer-experimental-internal-checks -checker-cfref -analyzer-store=region -analyzer-constraints=range -verify -fblocks %s +// RUN: clang -cc1 -triple x86_64-apple-darwin9 -analyze -analyzer-experimental-internal-checks -checker-cfref -analyzer-store=basic -analyzer-constraints=basic -verify -fblocks %s +// RUN: clang -cc1 -triple x86_64-apple-darwin9 -analyze -analyzer-experimental-internal-checks -checker-cfref -analyzer-store=basic -analyzer-constraints=range -verify -fblocks %s +// RUN: clang -cc1 -triple x86_64-apple-darwin9 -analyze -analyzer-experimental-internal-checks -checker-cfref -analyzer-store=region -analyzer-constraints=basic -verify -fblocks %s +// RUN: clang -cc1 -triple x86_64-apple-darwin9 -analyze -analyzer-experimental-internal-checks -checker-cfref -analyzer-store=region -analyzer-constraints=range -verify -fblocks %s // - A bunch of misc. failures involving evaluating // these expressions and building CFGs. These tests are here to prevent diff --git a/test/Analysis/misc-ps-basic-store.m b/test/Analysis/misc-ps-basic-store.m index 2a982347a7b6..6af63f947291 100644 --- a/test/Analysis/misc-ps-basic-store.m +++ b/test/Analysis/misc-ps-basic-store.m @@ -1,4 +1,4 @@ -// RUN: clang-cc -analyze -analyzer-experimental-internal-checks -checker-cfref -analyzer-store=basic -verify -fblocks %s +// RUN: clang -cc1 -analyze -analyzer-experimental-internal-checks -checker-cfref -analyzer-store=basic -verify -fblocks %s //--------------------------------------------------------------------------- // Test case 'checkaccess_union' differs for region store and basic store. diff --git a/test/Analysis/misc-ps-eager-assume.m b/test/Analysis/misc-ps-eager-assume.m index e702cb968a57..e636c21b9490 100644 --- a/test/Analysis/misc-ps-eager-assume.m +++ b/test/Analysis/misc-ps-eager-assume.m @@ -1,4 +1,4 @@ -// RUN: clang-cc -analyze -analyzer-experimental-internal-checks -checker-cfref -analyzer-store=region -analyzer-constraints=range -verify -fblocks %s -analyzer-eagerly-assume +// RUN: clang -cc1 -analyze -analyzer-experimental-internal-checks -checker-cfref -analyzer-store=region -analyzer-constraints=range -verify -fblocks %s -analyzer-eagerly-assume // Delta-reduced header stuff (needed for test cases). typedef signed char BOOL; @@ -120,3 +120,26 @@ void rdar7342806() { // be true when Pointer is not NULL. rdar7342806_aux(*Pointer); // no-warning } + +//===---------------------------------------------------------------------===// +// PR 5627 - http://llvm.org/bugs/show_bug.cgi?id=5627 +// This test case depends on using -analyzer-eagerly-assume and +// -analyzer-store=region. The '-analyzer-eagerly-assume' causes the path +// to bifurcate when evaluating the function call argument, and a state +// caching bug in GRExprEngine::CheckerVisit (and friends) caused the store +// to 'p' to not be evaluated along one path, but then an autotransition caused +// the path to keep on propagating with 'p' still set to an undefined value. +// We would then get a bogus report of returning uninitialized memory. +// Note: CheckerVisit mistakenly cleared an existing node, and the cleared +// node was resurrected by GRStmtNodeBuilder::~GRStmtNodeBuilder(), where +// 'p' was not assigned. +//===---------------------------------------------------------------------===// + +float *pr5627_f(int y); + +float *pr5627_g(int x) { + float *p; + p = pr5627_f(!x); + return p; // no-warning +} + diff --git a/test/Analysis/misc-ps-ranges.m b/test/Analysis/misc-ps-ranges.m index 058c903722c0..92e20d647deb 100644 --- a/test/Analysis/misc-ps-ranges.m +++ b/test/Analysis/misc-ps-ranges.m @@ -1,5 +1,5 @@ -// RUN: clang-cc -analyze -analyzer-experimental-internal-checks -checker-cfref -analyzer-store=basic -analyzer-constraints=range -verify -fblocks %s -// RUN: clang-cc -analyze -analyzer-experimental-internal-checks -checker-cfref -analyzer-store=region -analyzer-constraints=range -verify -fblocks %s +// RUN: clang -cc1 -analyze -analyzer-experimental-internal-checks -checker-cfref -analyzer-store=basic -analyzer-constraints=range -verify -fblocks %s +// RUN: clang -cc1 -analyze -analyzer-experimental-internal-checks -checker-cfref -analyzer-store=region -analyzer-constraints=range -verify -fblocks %s // // main's 'argc' argument is always > 0 diff --git a/test/Analysis/misc-ps-region-store-i386.m b/test/Analysis/misc-ps-region-store-i386.m index 7b0d61bcbaeb..f9df55270b66 100644 --- a/test/Analysis/misc-ps-region-store-i386.m +++ b/test/Analysis/misc-ps-region-store-i386.m @@ -1,4 +1,4 @@ -// RUN: clang-cc -triple i386-apple-darwin9 -analyze -analyzer-experimental-internal-checks -checker-cfref -analyzer-store=region -verify -fblocks %s +// RUN: clang -cc1 -triple i386-apple-darwin9 -analyze -analyzer-experimental-internal-checks -checker-cfref -analyzer-store=region -verify -fblocks %s // Here is a case where a pointer is treated as integer, invalidated as an // integer, and then used again as a pointer. This test just makes sure diff --git a/test/Analysis/misc-ps-region-store-x86_64.m b/test/Analysis/misc-ps-region-store-x86_64.m index 8c865ab27ff2..01d99f24c68f 100644 --- a/test/Analysis/misc-ps-region-store-x86_64.m +++ b/test/Analysis/misc-ps-region-store-x86_64.m @@ -1,4 +1,4 @@ -// RUN: clang-cc -triple x86_64-apple-darwin9 -analyze -analyzer-experimental-internal-checks -checker-cfref -analyzer-store=region -verify -fblocks %s +// RUN: clang -cc1 -triple x86_64-apple-darwin9 -analyze -analyzer-experimental-internal-checks -checker-cfref -analyzer-store=region -verify -fblocks %s // Here is a case where a pointer is treated as integer, invalidated as an // integer, and then used again as a pointer. This test just makes sure diff --git a/test/Analysis/misc-ps-region-store.m b/test/Analysis/misc-ps-region-store.m index e5113ba351c8..e736e0f37cdb 100644 --- a/test/Analysis/misc-ps-region-store.m +++ b/test/Analysis/misc-ps-region-store.m @@ -1,5 +1,5 @@ -// RUN: clang-cc -triple i386-apple-darwin9 -analyze -analyzer-experimental-internal-checks -checker-cfref -analyzer-store=region -verify -fblocks %s -// RUN: clang-cc -triple x86_64-apple-darwin9 -analyze -analyzer-experimental-internal-checks -checker-cfref -analyzer-store=region -verify -fblocks %s +// RUN: clang -cc1 -triple i386-apple-darwin9 -analyze -analyzer-experimental-internal-checks -checker-cfref -analyzer-store=region -verify -fblocks -analyzer-opt-analyze-nested-blocks %s +// RUN: clang -cc1 -triple x86_64-apple-darwin9 -analyze -analyzer-experimental-internal-checks -checker-cfref -analyzer-store=region -verify -fblocks -analyzer-opt-analyze-nested-blocks %s typedef struct objc_selector *SEL; typedef signed char BOOL; @@ -541,3 +541,98 @@ double rdar_6811085(void) { return u + 10; // expected-warning{{The left operand of '+' is a garbage value}} } +//===----------------------------------------------------------------------===// +// Path-sensitive tests for blocks. +//===----------------------------------------------------------------------===// + +void indirect_block_call(void (^f)()); + +int blocks_1(int *p, int z) { + __block int *q = 0; + void (^bar)() = ^{ q = p; }; + + if (z == 1) { + // The call to 'bar' might cause 'q' to be invalidated. + bar(); + *q = 0x1; // no-warning + } + else if (z == 2) { + // The function 'indirect_block_call' might invoke bar, thus causing + // 'q' to possibly be invalidated. + indirect_block_call(bar); + *q = 0x1; // no-warning + } + else { + *q = 0xDEADBEEF; // expected-warning{{Dereference of null pointer}} + } + return z; +} + +int blocks_2(int *p, int z) { + int *q = 0; + void (^bar)(int **) = ^(int **r){ *r = p; }; + + if (z) { + // The call to 'bar' might cause 'q' to be invalidated. + bar(&q); + *q = 0x1; // no-warning + } + else { + *q = 0xDEADBEEF; // expected-warning{{Dereference of null pointer}} + } + return z; +} + +//===----------------------------------------------------------------------===// +// - Test that variables passed using __blocks +// are not treated as being uninitialized. +//===----------------------------------------------------------------------===// + +typedef void (^RDar_7462324_Callback)(id obj); + +@interface RDar7462324 +- (void) foo:(id)target; +- (void) foo_positive:(id)target; + +@end + +@implementation RDar7462324 +- (void) foo:(id)target { + __block RDar_7462324_Callback builder = ((void*) 0); + builder = ^(id object) { + if (object) { + builder(self); // no-warning + } + }; + builder(target); +} +- (void) foo_positive:(id)target { + __block RDar_7462324_Callback builder = ((void*) 0); + builder = ^(id object) { + id x; + if (object) { + builder(x); // expected-warning{{Pass-by-value argument in function call is undefined}} + } + }; + builder(target); +} +@end + +//===----------------------------------------------------------------------===// +// - Scanning for live variables within a block should +// not crash on variables passed by reference via __block. +//===----------------------------------------------------------------------===// + +int rdar7468209_aux(); +void rdar7468209_aux2(); + +void rdar7468209() { + __block int x = 0; + ^{ + x = rdar7468209_aux(); + // We need a second statement so that 'x' would be removed from the store if it wasn't + // passed by reference. + rdar7468209_aux_2(); + }(); +} + diff --git a/test/Analysis/misc-ps.m b/test/Analysis/misc-ps.m index 42168b9e3e4b..c97ef951c5aa 100644 --- a/test/Analysis/misc-ps.m +++ b/test/Analysis/misc-ps.m @@ -1,8 +1,8 @@ // NOTE: Use '-fobjc-gc' to test the analysis being run twice, and multiple reports are not issued. -// RUN: clang-cc -analyze -analyzer-experimental-internal-checks -checker-cfref -analyzer-store=basic -fobjc-gc -analyzer-constraints=basic -verify -fblocks %s -// RUN: clang-cc -analyze -analyzer-experimental-internal-checks -checker-cfref -analyzer-store=basic -analyzer-constraints=range -verify -fblocks %s -// RUN: clang-cc -analyze -analyzer-experimental-internal-checks -checker-cfref -analyzer-store=region -analyzer-constraints=basic -verify -fblocks %s -// RUN: clang-cc -analyze -analyzer-experimental-internal-checks -checker-cfref -analyzer-store=region -analyzer-constraints=range -verify -fblocks %s +// RUN: clang -cc1 -analyze -analyzer-experimental-internal-checks -checker-cfref -analyzer-store=basic -fobjc-gc -analyzer-constraints=basic -verify -fblocks %s +// RUN: clang -cc1 -analyze -analyzer-experimental-internal-checks -checker-cfref -analyzer-store=basic -analyzer-constraints=range -verify -fblocks %s +// RUN: clang -cc1 -analyze -analyzer-experimental-internal-checks -checker-cfref -analyzer-store=region -analyzer-constraints=basic -verify -fblocks %s +// RUN: clang -cc1 -analyze -analyzer-experimental-internal-checks -checker-cfref -analyzer-store=region -analyzer-constraints=range -verify -fblocks %s typedef struct objc_ivar *Ivar; typedef struct objc_selector *SEL; diff --git a/test/Analysis/nil-receiver-undefined-larger-than-voidptr-ret.m b/test/Analysis/nil-receiver-undefined-larger-than-voidptr-ret.m index 75cdf6ed3932..227945620d78 100644 --- a/test/Analysis/nil-receiver-undefined-larger-than-voidptr-ret.m +++ b/test/Analysis/nil-receiver-undefined-larger-than-voidptr-ret.m @@ -1,7 +1,7 @@ -// RUN: clang-cc -triple i386-apple-darwin8 -analyze -analyzer-experimental-internal-checks -checker-cfref -analyzer-constraints=basic -analyzer-store=basic %s 2>&1 | FileCheck -check-prefix=darwin8 %s -// RUN: clang-cc -triple i386-apple-darwin8 -analyze -analyzer-experimental-internal-checks -checker-cfref -analyzer-constraints=basic -analyzer-store=region %s 2>&1 | FileCheck -check-prefix=darwin8 %s -// RUN: clang-cc -triple i386-apple-darwin9 -analyze -analyzer-experimental-internal-checks -checker-cfref -analyzer-constraints=basic -analyzer-store=basic %s 2>&1 | FileCheck -check-prefix=darwin9 %s -// RUN: clang-cc -triple i386-apple-darwin9 -analyze -analyzer-experimental-internal-checks -checker-cfref -analyzer-constraints=basic -analyzer-store=region %s 2>&1 | FileCheck -check-prefix=darwin9 %s +// RUN: clang -cc1 -triple i386-apple-darwin8 -analyze -analyzer-experimental-internal-checks -checker-cfref -analyzer-constraints=basic -analyzer-store=basic %s 2>&1 | FileCheck -check-prefix=darwin8 %s +// RUN: clang -cc1 -triple i386-apple-darwin8 -analyze -analyzer-experimental-internal-checks -checker-cfref -analyzer-constraints=basic -analyzer-store=region %s 2>&1 | FileCheck -check-prefix=darwin8 %s +// RUN: clang -cc1 -triple i386-apple-darwin9 -analyze -analyzer-experimental-internal-checks -checker-cfref -analyzer-constraints=basic -analyzer-store=basic %s 2>&1 | FileCheck -check-prefix=darwin9 %s +// RUN: clang -cc1 -triple i386-apple-darwin9 -analyze -analyzer-experimental-internal-checks -checker-cfref -analyzer-constraints=basic -analyzer-store=region %s 2>&1 | FileCheck -check-prefix=darwin9 %s @interface MyClass {} - (void *)voidPtrM; diff --git a/test/Analysis/no-exit-cfg.c b/test/Analysis/no-exit-cfg.c index af8db135926f..eb4fc8d41aae 100644 --- a/test/Analysis/no-exit-cfg.c +++ b/test/Analysis/no-exit-cfg.c @@ -1,5 +1,5 @@ -// RUN: clang-cc -analyze -analyzer-experimental-internal-checks -checker-cfref -analyzer-store=basic -verify %s -// RUN: clang-cc -analyze -analyzer-experimental-internal-checks -checker-cfref -analyzer-store=region -verify %s +// RUN: clang -cc1 -analyze -analyzer-experimental-internal-checks -checker-cfref -analyzer-store=basic -verify %s +// RUN: clang -cc1 -analyze -analyzer-experimental-internal-checks -checker-cfref -analyzer-store=region -verify %s // This is a test case for the issue reported in PR 2819: // http://llvm.org/bugs/show_bug.cgi?id=2819 diff --git a/test/Analysis/no-outofbounds.c b/test/Analysis/no-outofbounds.c index 475a2116a7c8..8aa194d31b87 100644 --- a/test/Analysis/no-outofbounds.c +++ b/test/Analysis/no-outofbounds.c @@ -1,5 +1,5 @@ -// RUN: clang-cc -checker-cfref -analyze -analyzer-experimental-internal-checks -analyzer-store=basic -verify %s -// RUN: clang-cc -checker-cfref -analyze -analyzer-experimental-internal-checks -analyzer-store=region -verify %s +// RUN: clang -cc1 -checker-cfref -analyze -analyzer-experimental-internal-checks -analyzer-store=basic -verify %s +// RUN: clang -cc1 -checker-cfref -analyze -analyzer-experimental-internal-checks -analyzer-store=region -verify %s // XFAIL: * //===----------------------------------------------------------------------===// diff --git a/test/Analysis/null-deref-ps-region.c b/test/Analysis/null-deref-ps-region.c index ab1151382573..8f5fe9fb10c1 100644 --- a/test/Analysis/null-deref-ps-region.c +++ b/test/Analysis/null-deref-ps-region.c @@ -1,4 +1,4 @@ -// RUN: clang-cc -analyze -analyzer-experimental-internal-checks -std=gnu99 -checker-cfref -analyzer-store=region -verify %s +// RUN: clang -cc1 -analyze -analyzer-experimental-internal-checks -std=gnu99 -checker-cfref -analyzer-store=region -verify %s // The store for 'a[1]' should not be removed mistakenly. SymbolicRegions may diff --git a/test/Analysis/null-deref-ps.c b/test/Analysis/null-deref-ps.c index c604653ea516..8bfc1f337aa1 100644 --- a/test/Analysis/null-deref-ps.c +++ b/test/Analysis/null-deref-ps.c @@ -1,7 +1,7 @@ -// RUN: clang-cc -triple i386-apple-darwin10 -analyze -analyzer-experimental-internal-checks -std=gnu99 -checker-cfref -verify %s -analyzer-constraints=basic -analyzer-store=basic -// RUN: clang-cc -triple i386-apple-darwin10 -analyze -analyzer-experimental-internal-checks -std=gnu99 -checker-cfref -verify %s -analyzer-constraints=range -analyzer-store=basic -// RUN: clang-cc -triple i386-apple-darwin10 -analyze -analyzer-experimental-internal-checks -std=gnu99 -checker-cfref -analyzer-store=region -analyzer-constraints=range -analyzer-no-purge-dead -verify %s -// RUN: clang-cc -triple i386-apple-darwin10 -analyze -analyzer-experimental-internal-checks -std=gnu99 -checker-cfref -analyzer-store=region -analyzer-constraints=range -verify %s +// RUN: clang -cc1 -triple i386-apple-darwin10 -analyze -analyzer-experimental-internal-checks -std=gnu99 -checker-cfref -verify %s -analyzer-constraints=basic -analyzer-store=basic +// RUN: clang -cc1 -triple i386-apple-darwin10 -analyze -analyzer-experimental-internal-checks -std=gnu99 -checker-cfref -verify %s -analyzer-constraints=range -analyzer-store=basic +// RUN: clang -cc1 -triple i386-apple-darwin10 -analyze -analyzer-experimental-internal-checks -std=gnu99 -checker-cfref -analyzer-store=region -analyzer-constraints=range -analyzer-no-purge-dead -verify %s +// RUN: clang -cc1 -triple i386-apple-darwin10 -analyze -analyzer-experimental-internal-checks -std=gnu99 -checker-cfref -analyzer-store=region -analyzer-constraints=range -verify %s typedef unsigned uintptr_t; diff --git a/test/Analysis/outofbound.c b/test/Analysis/outofbound.c index d1a07abf527f..a866ad905b3b 100644 --- a/test/Analysis/outofbound.c +++ b/test/Analysis/outofbound.c @@ -1,4 +1,4 @@ -// RUN: clang-cc -analyze -analyzer-experimental-internal-checks -checker-cfref -analyzer-store=region -verify %s +// RUN: clang -cc1 -analyze -analyzer-experimental-internal-checks -checker-cfref -analyzer-store=region -verify %s char f1() { char* s = "abcd"; diff --git a/test/Analysis/override-werror.c b/test/Analysis/override-werror.c index e8ce7bdc66dd..e17361ebe418 100644 --- a/test/Analysis/override-werror.c +++ b/test/Analysis/override-werror.c @@ -1,5 +1,5 @@ -// RUN: clang-cc -analyze -analyzer-experimental-internal-checks -checker-cfref -Werror %s -analyzer-store=basic -verify -// RUN: clang-cc -analyze -analyzer-experimental-internal-checks -checker-cfref -Werror %s -analyzer-store=region -verify +// RUN: clang -cc1 -analyze -analyzer-experimental-internal-checks -checker-cfref -Werror %s -analyzer-store=basic -verify +// RUN: clang -cc1 -analyze -analyzer-experimental-internal-checks -checker-cfref -Werror %s -analyzer-store=region -verify // This test case illustrates that using '-analyze' overrides the effect of // -Werror. This allows basic warnings not to interfere with producing diff --git a/test/Analysis/plist-output.m b/test/Analysis/plist-output.m index 971d47654fdd..7f49340b7885 100644 --- a/test/Analysis/plist-output.m +++ b/test/Analysis/plist-output.m @@ -1,4 +1,4 @@ -// RUN: clang-cc -analyze -analyzer-experimental-internal-checks -checker-cfref -analyzer-store=region -analyzer-constraints=range -fblocks -analyzer-output=plist -o - %s | FileCheck %s +// RUN: clang -cc1 -analyze -analyzer-experimental-internal-checks -checker-cfref -analyzer-store=region -analyzer-constraints=range -fblocks -analyzer-output=plist -o - %s | FileCheck %s void test_null_init(void) { int *p = 0; diff --git a/test/Analysis/pr4209.m b/test/Analysis/pr4209.m index 60161b1b08a8..3a32649ee722 100644 --- a/test/Analysis/pr4209.m +++ b/test/Analysis/pr4209.m @@ -1,5 +1,5 @@ -// RUN: clang-cc -triple i386-apple-darwin9 -analyze -analyzer-experimental-internal-checks -checker-cfref -analyzer-store=basic -verify %s -// RUN: clang-cc -triple i386-apple-darwin9 -analyze -analyzer-experimental-internal-checks -checker-cfref -analyzer-store=region -verify %s +// RUN: clang -cc1 -triple i386-apple-darwin9 -analyze -analyzer-experimental-internal-checks -checker-cfref -analyzer-store=basic -verify %s +// RUN: clang -cc1 -triple i386-apple-darwin9 -analyze -analyzer-experimental-internal-checks -checker-cfref -analyzer-store=region -verify %s // This test case was crashing due to how CFRefCount.cpp resolved the // ObjCInterfaceDecl* and ClassName in EvalObjCMessageExpr. diff --git a/test/Analysis/pr_2542_rdar_6793404.m b/test/Analysis/pr_2542_rdar_6793404.m index ebb69028a709..761448caf952 100644 --- a/test/Analysis/pr_2542_rdar_6793404.m +++ b/test/Analysis/pr_2542_rdar_6793404.m @@ -1,5 +1,5 @@ -// RUN: clang-cc -analyze -analyzer-experimental-internal-checks -checker-cfref -pedantic -analyzer-store=basic -verify %s -// RUN: clang-cc -analyze -analyzer-experimental-internal-checks -checker-cfref -pedantic -analyzer-store=region -verify %s +// RUN: clang -cc1 -analyze -analyzer-experimental-internal-checks -checker-cfref -pedantic -analyzer-store=basic -verify %s +// RUN: clang -cc1 -analyze -analyzer-experimental-internal-checks -checker-cfref -pedantic -analyzer-store=region -verify %s // BEGIN delta-debugging reduced header stuff diff --git a/test/Analysis/pr_4164.c b/test/Analysis/pr_4164.c index 176871773959..d38f4b3e2de2 100644 --- a/test/Analysis/pr_4164.c +++ b/test/Analysis/pr_4164.c @@ -1,5 +1,5 @@ -// RUN: clang-cc -triple x86_64-apple-darwin9 -analyze -analyzer-experimental-internal-checks -checker-cfref -analyzer-store=basic -verify %s -// RUN: clang-cc -triple x86_64-apple-darwin9 -analyze -analyzer-experimental-internal-checks -checker-cfref -analyzer-store=region -verify %s +// RUN: clang -cc1 -triple x86_64-apple-darwin9 -analyze -analyzer-experimental-internal-checks -checker-cfref -analyzer-store=basic -verify %s +// RUN: clang -cc1 -triple x86_64-apple-darwin9 -analyze -analyzer-experimental-internal-checks -checker-cfref -analyzer-store=region -verify %s // PR 4164: http://llvm.org/bugs/show_bug.cgi?id=4164 // diff --git a/test/Analysis/ptr-arith.c b/test/Analysis/ptr-arith.c index b585c85d67fe..2adbbe211d7f 100644 --- a/test/Analysis/ptr-arith.c +++ b/test/Analysis/ptr-arith.c @@ -1,5 +1,5 @@ -// RUN: clang-cc -analyze -analyzer-experimental-internal-checks -checker-cfref -analyzer-store=region -verify -triple x86_64-apple-darwin9 %s -// RUN: clang-cc -analyze -analyzer-experimental-internal-checks -checker-cfref -analyzer-store=region -verify -triple i686-apple-darwin9 %s +// RUN: clang -cc1 -analyze -analyzer-experimental-internal-checks -checker-cfref -analyzer-store=region -verify -triple x86_64-apple-darwin9 %s +// RUN: clang -cc1 -analyze -analyzer-experimental-internal-checks -checker-cfref -analyzer-store=region -verify -triple i686-apple-darwin9 %s void f1() { int a[10]; diff --git a/test/Analysis/rdar-6442306-1.m b/test/Analysis/rdar-6442306-1.m index 1d8bbd39d8d1..28fa83a3af6e 100644 --- a/test/Analysis/rdar-6442306-1.m +++ b/test/Analysis/rdar-6442306-1.m @@ -1,5 +1,5 @@ -// RUN: clang-cc -analyze -analyzer-experimental-internal-checks -checker-cfref %s -analyzer-store=basic -verify -// RUN: clang-cc -analyze -analyzer-experimental-internal-checks -checker-cfref %s -analyzer-store=region -verify +// RUN: clang -cc1 -analyze -analyzer-experimental-internal-checks -checker-cfref %s -analyzer-store=basic -verify +// RUN: clang -cc1 -analyze -analyzer-experimental-internal-checks -checker-cfref %s -analyzer-store=region -verify typedef int bar_return_t; typedef struct { diff --git a/test/Analysis/rdar-6540084.m b/test/Analysis/rdar-6540084.m index 4d191d2f1e35..7940fc637b07 100644 --- a/test/Analysis/rdar-6540084.m +++ b/test/Analysis/rdar-6540084.m @@ -1,4 +1,4 @@ -// RUN: clang-cc -analyze -analyzer-experimental-internal-checks -warn-dead-stores -verify %s +// RUN: clang -cc1 -analyze -analyzer-experimental-internal-checks -warn-dead-stores -verify %s // // This test exercises the live variables analysis (LiveVariables.cpp). // The case originally identified a non-termination bug. diff --git a/test/Analysis/rdar-6541136-region.c b/test/Analysis/rdar-6541136-region.c index 5190a032df8a..fbbf40814c9a 100644 --- a/test/Analysis/rdar-6541136-region.c +++ b/test/Analysis/rdar-6541136-region.c @@ -1,4 +1,4 @@ -// RUN: clang-cc -verify -analyze -analyzer-experimental-internal-checks -checker-cfref -analyzer-store=region %s +// RUN: clang -cc1 -verify -analyze -analyzer-experimental-internal-checks -checker-cfref -analyzer-store=region %s struct tea_cheese { unsigned magic; }; typedef struct tea_cheese kernel_tea_cheese_t; diff --git a/test/Analysis/rdar-6541136.c b/test/Analysis/rdar-6541136.c index d5fc2e0ff1bd..18dc3c846002 100644 --- a/test/Analysis/rdar-6541136.c +++ b/test/Analysis/rdar-6541136.c @@ -1,4 +1,4 @@ -// RUN: clang-cc -verify -analyze -analyzer-experimental-internal-checks -checker-cfref -analyzer-store=basic %s +// RUN: clang -cc1 -verify -analyze -analyzer-experimental-internal-checks -checker-cfref -analyzer-store=basic %s struct tea_cheese { unsigned magic; }; typedef struct tea_cheese kernel_tea_cheese_t; diff --git a/test/Analysis/rdar-6562655.m b/test/Analysis/rdar-6562655.m index 0b837c6fa6e7..95f876efee50 100644 --- a/test/Analysis/rdar-6562655.m +++ b/test/Analysis/rdar-6562655.m @@ -1,5 +1,5 @@ -// RUN: clang-cc -analyze -analyzer-experimental-internal-checks -checker-cfref -analyzer-constraints=basic -analyzer-store=basic -verify %s -// RUN: clang-cc -analyze -analyzer-experimental-internal-checks -checker-cfref -analyzer-constraints=basic -analyzer-store=region -verify %s +// RUN: clang -cc1 -analyze -analyzer-experimental-internal-checks -checker-cfref -analyzer-constraints=basic -analyzer-store=basic -verify %s +// RUN: clang -cc1 -analyze -analyzer-experimental-internal-checks -checker-cfref -analyzer-constraints=basic -analyzer-store=region -verify %s // // This test case mainly checks that the retain/release checker doesn't crash // on this file. diff --git a/test/Analysis/rdar-6582778-basic-store.c b/test/Analysis/rdar-6582778-basic-store.c index a4850c133201..e1a06947d04b 100644 --- a/test/Analysis/rdar-6582778-basic-store.c +++ b/test/Analysis/rdar-6582778-basic-store.c @@ -1,4 +1,4 @@ -// RUN: clang-cc -analyze -analyzer-experimental-internal-checks -checker-cfref -analyzer-store=basic -verify %s +// RUN: clang -cc1 -analyze -analyzer-experimental-internal-checks -checker-cfref -analyzer-store=basic -verify %s typedef const void * CFTypeRef; typedef double CFTimeInterval; diff --git a/test/Analysis/rdar-6600344-nil-receiver-undefined-struct-ret.m b/test/Analysis/rdar-6600344-nil-receiver-undefined-struct-ret.m index 9d6fe5b27d34..060a91a49e85 100644 --- a/test/Analysis/rdar-6600344-nil-receiver-undefined-struct-ret.m +++ b/test/Analysis/rdar-6600344-nil-receiver-undefined-struct-ret.m @@ -1,5 +1,5 @@ -// RUN: clang-cc -analyze -analyzer-experimental-internal-checks -checker-cfref -analyzer-constraints=basic -analyzer-store=basic %s -verify -// RUN: clang-cc -analyze -analyzer-experimental-internal-checks -checker-cfref -analyzer-constraints=basic -analyzer-store=region %s -verify +// RUN: clang -cc1 -analyze -analyzer-experimental-internal-checks -checker-cfref -analyzer-constraints=basic -analyzer-store=basic %s -verify +// RUN: clang -cc1 -analyze -analyzer-experimental-internal-checks -checker-cfref -analyzer-constraints=basic -analyzer-store=region %s -verify typedef struct Foo { int x; } Bar; diff --git a/test/Analysis/rdar-7168531.m b/test/Analysis/rdar-7168531.m index 6c34125d056c..683dc745c6c4 100644 --- a/test/Analysis/rdar-7168531.m +++ b/test/Analysis/rdar-7168531.m @@ -1,5 +1,5 @@ -// RUN: clang-cc -analyze -analyzer-experimental-internal-checks -checker-cfref -triple i386-apple-darwin10 -analyzer-store=region -// RUN: clang-cc -analyze -analyzer-experimental-internal-checks -checker-cfref -triple i386-apple-darwin10 -analyzer-store=basic +// RUN: clang -cc1 -analyze -analyzer-experimental-internal-checks -checker-cfref -triple i386-apple-darwin10 -analyzer-store=region +// RUN: clang -cc1 -analyze -analyzer-experimental-internal-checks -checker-cfref -triple i386-apple-darwin10 -analyzer-store=basic // Note that the target triple is important for this test case. It specifies that we use the // fragile Objective-C ABI. diff --git a/test/Analysis/refcnt_naming.m b/test/Analysis/refcnt_naming.m index a4c290442a57..417162b6dbf6 100644 --- a/test/Analysis/refcnt_naming.m +++ b/test/Analysis/refcnt_naming.m @@ -1,5 +1,5 @@ -// RUN: clang-cc -analyze -analyzer-experimental-internal-checks -checker-cfref -analyzer-store=basic -verify %s -// RUN: clang-cc -analyze -analyzer-experimental-internal-checks -checker-cfref -analyzer-store=region -verify %s +// RUN: clang -cc1 -analyze -analyzer-experimental-internal-checks -checker-cfref -analyzer-store=basic -verify %s +// RUN: clang -cc1 -analyze -analyzer-experimental-internal-checks -checker-cfref -analyzer-store=region -verify %s typedef const struct __CFString * CFStringRef; typedef const struct __CFAllocator * CFAllocatorRef; diff --git a/test/Analysis/region-1.m b/test/Analysis/region-1.m index 6a8ae49bba4b..8d332cfb7501 100644 --- a/test/Analysis/region-1.m +++ b/test/Analysis/region-1.m @@ -1,5 +1,5 @@ -// RUN: clang-cc -analyze -analyzer-experimental-internal-checks -checker-cfref -analyzer-store=basic -verify %s -// RUN: clang-cc -analyze -analyzer-experimental-internal-checks -checker-cfref -analyzer-store=region -verify %s +// RUN: clang -cc1 -analyze -analyzer-experimental-internal-checks -checker-cfref -analyzer-store=basic -verify %s +// RUN: clang -cc1 -analyze -analyzer-experimental-internal-checks -checker-cfref -analyzer-store=region -verify %s // // This test case simply should not crash. It evaluates the logic of not // using MemRegion::getRValueType in incorrect places. diff --git a/test/Analysis/retain-release-basic-store.m b/test/Analysis/retain-release-basic-store.m index b16c231ce23b..744032ba77c5 100644 --- a/test/Analysis/retain-release-basic-store.m +++ b/test/Analysis/retain-release-basic-store.m @@ -1,4 +1,4 @@ -// RUN: clang-cc -analyze -checker-cfref -analyzer-store=basic -verify %s +// RUN: clang -cc1 -analyze -checker-cfref -analyzer-store=basic -verify %s //===----------------------------------------------------------------------===// // The following code is reduced using delta-debugging from diff --git a/test/Analysis/retain-release-gc-only.m b/test/Analysis/retain-release-gc-only.m index ab52938505f6..97fa6124484c 100644 --- a/test/Analysis/retain-release-gc-only.m +++ b/test/Analysis/retain-release-gc-only.m @@ -1,5 +1,5 @@ -// RUN: clang-cc -analyze -checker-cfref -analyzer-store=basic -verify -fobjc-gc-only -fblocks %s -// RUN: clang-cc -analyze -checker-cfref -analyzer-store=region -fobjc-gc-only -fblocks -verify %s +// RUN: clang -cc1 -analyze -checker-cfref -analyzer-store=basic -verify -fobjc-gc-only -fblocks %s +// RUN: clang -cc1 -analyze -checker-cfref -analyzer-store=region -fobjc-gc-only -fblocks -verify %s //===----------------------------------------------------------------------===// // Header stuff. diff --git a/test/Analysis/retain-release-region-store.m b/test/Analysis/retain-release-region-store.m index eacac49c8127..2b75ff9ea89b 100644 --- a/test/Analysis/retain-release-region-store.m +++ b/test/Analysis/retain-release-region-store.m @@ -1,4 +1,4 @@ -// RUN: clang-cc -analyze -checker-cfref -analyzer-store=region -verify %s +// RUN: clang -cc1 -analyze -checker-cfref -analyzer-store=region -verify %s //===----------------------------------------------------------------------===// // The following code is reduced using delta-debugging from diff --git a/test/Analysis/retain-release.m b/test/Analysis/retain-release.m index bc9f0b7ef444..969249cdeeb3 100644 --- a/test/Analysis/retain-release.m +++ b/test/Analysis/retain-release.m @@ -1,5 +1,5 @@ -// RUN: clang-cc -triple x86_64-apple-darwin10 -analyze -checker-cfref -analyzer-store=basic -fblocks -verify %s -// RUN: clang-cc -triple x86_64-apple-darwin10 -analyze -checker-cfref -analyzer-store=region -fblocks -verify %s +// RUN: clang -cc1 -triple x86_64-apple-darwin10 -analyze -checker-cfref -analyzer-store=basic -fblocks -verify %s +// RUN: clang -cc1 -triple x86_64-apple-darwin10 -analyze -checker-cfref -analyzer-store=region -fblocks -verify %s #if __has_feature(attribute_ns_returns_retained) #define NS_RETURNS_RETAINED __attribute__((ns_returns_retained)) diff --git a/test/Analysis/security-syntax-checks.m b/test/Analysis/security-syntax-checks.m index bcdc65ebd459..c63d58901e46 100644 --- a/test/Analysis/security-syntax-checks.m +++ b/test/Analysis/security-syntax-checks.m @@ -1,4 +1,4 @@ -// RUN: clang-cc -triple i386-apple-darwin10 -analyze -warn-security-syntactic %s -verify +// RUN: clang -cc1 -triple i386-apple-darwin10 -analyze -warn-security-syntactic %s -verify // rule request: floating point used as loop // condition (FLP30-C, FLP-30-CPP) @@ -96,3 +96,9 @@ void test_rand() rand_r(&b); // expected-warning{{Function 'rand_r' is obsolete because it implements a poor random number generator. Use 'arc4random' instead}} random(); // expected-warning{{The 'random' function produces a sequence of values that an adversary may be able to predict. Use 'arc4random' instead}} } + +char *mktemp(char *buf); + +void test_mktemp() { + char *x = mktemp("/tmp/zxcv"); // expected-warning{{Call to function 'mktemp' is insecure as it always creates or uses insecure temporary file}} +} diff --git a/test/Analysis/sizeofpointer.c b/test/Analysis/sizeofpointer.c index e40c71857242..eace4f873bc2 100644 --- a/test/Analysis/sizeofpointer.c +++ b/test/Analysis/sizeofpointer.c @@ -1,4 +1,4 @@ -// RUN: clang-cc -analyze -warn-sizeof-pointer -verify %s +// RUN: clang -cc1 -analyze -warn-sizeof-pointer -verify %s struct s { }; diff --git a/test/Analysis/stack-addr-ps.c b/test/Analysis/stack-addr-ps.c index 5d1ce253fc35..a358165a22de 100644 --- a/test/Analysis/stack-addr-ps.c +++ b/test/Analysis/stack-addr-ps.c @@ -1,5 +1,5 @@ -// RUN: clang-cc -analyze -checker-cfref -analyzer-store=basic -fblocks -verify %s -// RUN: clang-cc -analyze -checker-cfref -analyzer-store=region -fblocks -verify %s +// RUN: clang -cc1 -analyze -checker-cfref -analyzer-store=basic -fblocks -verify %s +// RUN: clang -cc1 -analyze -checker-cfref -analyzer-store=region -fblocks -verify %s int* f1() { int x = 0; diff --git a/test/Analysis/uninit-msg-expr.m b/test/Analysis/uninit-msg-expr.m index 46e441f608d7..6a2ada536f8a 100644 --- a/test/Analysis/uninit-msg-expr.m +++ b/test/Analysis/uninit-msg-expr.m @@ -1,5 +1,5 @@ -// RUN: clang-cc -analyze -checker-cfref -analyzer-store=basic -verify %s -// RUN: clang-cc -analyze -checker-cfref -analyzer-store=region -verify %s +// RUN: clang -cc1 -analyze -checker-cfref -analyzer-store=basic -verify %s +// RUN: clang -cc1 -analyze -checker-cfref -analyzer-store=region -verify %s //===----------------------------------------------------------------------===// // The following code is reduced using delta-debugging from diff --git a/test/Analysis/uninit-ps-rdar6145427.m b/test/Analysis/uninit-ps-rdar6145427.m index 7be32b4d157e..594a6f0dcd88 100644 --- a/test/Analysis/uninit-ps-rdar6145427.m +++ b/test/Analysis/uninit-ps-rdar6145427.m @@ -1,5 +1,5 @@ -// RUN: clang-cc -analyze -verify -analyzer-store=basic -checker-cfref %s -// RUN: clang-cc -analyze -verify -analyzer-store=region -checker-cfref %s +// RUN: clang -cc1 -analyze -verify -analyzer-store=basic -checker-cfref %s +// RUN: clang -cc1 -analyze -verify -analyzer-store=region -checker-cfref %s // Delta-Debugging reduced preamble. typedef signed char BOOL; diff --git a/test/Analysis/uninit-vals-ps-region.c b/test/Analysis/uninit-vals-ps-region.c index e927a92576e2..5bcf74dcabc8 100644 --- a/test/Analysis/uninit-vals-ps-region.c +++ b/test/Analysis/uninit-vals-ps-region.c @@ -1,4 +1,4 @@ -// RUN: clang-cc -analyze -checker-cfref -analyzer-store=region -verify %s +// RUN: clang -cc1 -analyze -checker-cfref -analyzer-store=region -verify %s struct s { int data; diff --git a/test/Analysis/uninit-vals-ps.c b/test/Analysis/uninit-vals-ps.c index c8632a50300a..a2824c023396 100644 --- a/test/Analysis/uninit-vals-ps.c +++ b/test/Analysis/uninit-vals-ps.c @@ -1,5 +1,5 @@ -// RUN: clang-cc -analyze -checker-cfref -analyzer-store=basic -verify %s -// RUN: clang-cc -analyze -checker-cfref -analyzer-store=region -verify %s +// RUN: clang -cc1 -analyze -checker-cfref -analyzer-store=basic -verify %s +// RUN: clang -cc1 -analyze -checker-cfref -analyzer-store=region -verify %s struct FPRec { void (*my_func)(int * x); diff --git a/test/Analysis/uninit-vals.c b/test/Analysis/uninit-vals.c index 8428ca4f81cd..c48544e3c555 100644 --- a/test/Analysis/uninit-vals.c +++ b/test/Analysis/uninit-vals.c @@ -1,4 +1,4 @@ -// RUN: clang-cc -analyze -warn-uninit-values -verify %s +// RUN: clang -cc1 -analyze -warn-uninit-values -verify %s int f1() { int x; diff --git a/test/Analysis/uninit-vals.m b/test/Analysis/uninit-vals.m index 6d1561eeb511..43bab9e79134 100644 --- a/test/Analysis/uninit-vals.m +++ b/test/Analysis/uninit-vals.m @@ -1,5 +1,5 @@ -// RUN: clang-cc -analyze -checker-cfref -analyzer-store=basic -verify %s -// RUN: clang-cc -analyze -checker-cfref -analyzer-store=region -verify %s +// RUN: clang -cc1 -analyze -checker-cfref -analyzer-store=basic -verify %s +// RUN: clang -cc1 -analyze -checker-cfref -analyzer-store=region -verify %s typedef unsigned int NSUInteger; diff --git a/test/Analysis/unions-region.m b/test/Analysis/unions-region.m index be4f1852bf02..1c48e798808d 100644 --- a/test/Analysis/unions-region.m +++ b/test/Analysis/unions-region.m @@ -1,4 +1,4 @@ -// RUN: clang-cc -analyze -checker-cfref -analyzer-store=region -analyzer-constraints=range %s -verify +// RUN: clang -cc1 -analyze -checker-cfref -analyzer-store=region -analyzer-constraints=range %s -verify //===-- unions-region.m ---------------------------------------------------===// // diff --git a/test/Analysis/unused-ivars.m b/test/Analysis/unused-ivars.m index bbbf6aec23dd..55c482aa8b3f 100644 --- a/test/Analysis/unused-ivars.m +++ b/test/Analysis/unused-ivars.m @@ -1,4 +1,4 @@ -// RUN: clang-cc -fblocks -analyze -warn-objc-unused-ivars %s -verify +// RUN: clang -cc1 -fblocks -analyze -warn-objc-unused-ivars %s -verify //===--- BEGIN: Delta-debugging reduced headers. --------------------------===// diff --git a/test/CMakeLists.txt b/test/CMakeLists.txt index f39eb2accb45..6796bbf60f39 100644 --- a/test/CMakeLists.txt +++ b/test/CMakeLists.txt @@ -53,7 +53,7 @@ if(PYTHONINTERP_FOUND) --param build_config=${CMAKE_CFG_INTDIR} -sv ${CLANG_TEST_EXTRA_ARGS} ${CMAKE_CURRENT_BINARY_DIR}/${testdir} - DEPENDS clang clang-cc index-test c-index-test + DEPENDS clang index-test c-index-test COMMENT "Running Clang regression tests in ${testdir}") endforeach() @@ -64,7 +64,7 @@ if(PYTHONINTERP_FOUND) --param build_config=${CMAKE_CFG_INTDIR} -sv ${CLANG_TEST_EXTRA_ARGS} ${CMAKE_CURRENT_BINARY_DIR} - DEPENDS clang clang-cc index-test c-index-test + DEPENDS clang index-test c-index-test COMMENT "Running Clang regression tests") add_custom_target(clang-c++tests @@ -74,6 +74,6 @@ if(PYTHONINTERP_FOUND) --param build_config=${CMAKE_CFG_INTDIR} -sv ${CLANG_TEST_EXTRA_ARGS} ${CMAKE_CURRENT_SOURCE_DIR}/../utils/C++Tests - DEPENDS clang clang-cc index-test c-index-test + DEPENDS clang index-test c-index-test COMMENT "Running Clang regression tests") endif() diff --git a/test/CXX/basic/basic.lookup/basic.lookup.argdep/p3.cpp b/test/CXX/basic/basic.lookup/basic.lookup.argdep/p3.cpp new file mode 100644 index 000000000000..ae5590cd3c14 --- /dev/null +++ b/test/CXX/basic/basic.lookup/basic.lookup.argdep/p3.cpp @@ -0,0 +1,20 @@ +// RUN: clang-cc -fsyntax-only -verify %s + +// FIXME: embellish + +namespace test0 { + namespace A { + class Foo { + }; + + void foo(const Foo &foo); + } + + class Test { + enum E { foo = 0 }; + + void test() { + foo(A::Foo()); // expected-error {{not a function}} + } + }; +} diff --git a/test/CXX/basic/basic.stc/basic.stc.dynamic/basic.stc.dynamic.allocation/p1.cpp b/test/CXX/basic/basic.stc/basic.stc.dynamic/basic.stc.dynamic.allocation/p1.cpp new file mode 100644 index 000000000000..c752cec634a2 --- /dev/null +++ b/test/CXX/basic/basic.stc/basic.stc.dynamic/basic.stc.dynamic.allocation/p1.cpp @@ -0,0 +1,44 @@ +// RUN: clang-cc -fsyntax-only -verify %s +#include + +struct A { + void *operator new(size_t); +}; + +namespace NS { + void *operator new(size_t);; // expected-error {{'operator new' cannot be declared inside a namespace}} +} + +static void *operator new(size_t); // expected-error {{'operator new' cannot be declared static in global scope}} + +struct B { + void operator new(size_t); // expected-error {{'operator new' must return type 'void *'}} +}; + +struct C { + void *operator new(); // expected-error {{'operator new' must have at least one parameter}} +}; + +struct D { + void *operator new(bool); // expected-error {{'operator new' takes type size_t}} +}; + +struct E { + void *operator new(size_t = 0); // expected-error {{parameter of 'operator new' cannot have a default argument}} +}; + +struct F { + template void *operator new(size_t, int); +}; + +struct G { + template T operator new(size_t, int); // expected-error {{'operator new' cannot have a dependent return type; use 'void *' instead}} +}; + +struct H { + template void *operator new(T, int); // expected-error {{'operator new' cannot take a dependent type as first parameter; use size_t}} +}; + +struct I { + template void *operator new(size_t); // expected-error {{'operator new' template must have at least two parameters}} +}; diff --git a/test/CXX/basic/basic.stc/basic.stc.dynamic/basic.stc.dynamic.deallocation/p1.cpp b/test/CXX/basic/basic.stc/basic.stc.dynamic/basic.stc.dynamic.deallocation/p1.cpp new file mode 100644 index 000000000000..04af5bc82ec5 --- /dev/null +++ b/test/CXX/basic/basic.stc/basic.stc.dynamic/basic.stc.dynamic.deallocation/p1.cpp @@ -0,0 +1,11 @@ +// RUN: clang-cc -fsyntax-only -verify %s + +struct A { + void operator delete(void*); +}; + +namespace NS { + void operator delete(void *); // expected-error {{'operator delete' cannot be declared inside a namespace}} +} + +static void operator delete(void *); // expected-error {{'operator delete' cannot be declared static in global scope}} diff --git a/test/CXX/class.access/class.access.dcl/p1.cpp b/test/CXX/class.access/class.access.dcl/p1.cpp new file mode 100644 index 000000000000..043a9bfb4e0d --- /dev/null +++ b/test/CXX/class.access/class.access.dcl/p1.cpp @@ -0,0 +1,199 @@ +// RUN: clang-cc -fsyntax-only -verify + +// This is just the test for [namespace.udecl]p4 with 'using' +// uniformly stripped out. + +// C++03 [namespace.udecl]p4: +// A using-declaration used as a member-declaration shall refer to a +// member of a base class of the class being defined, shall refer to +// a member of an anonymous union that is a member of a base class +// of the class being defined, or shall refer to an enumerator for +// an enumeration type that is a member of a base class of the class +// being defined. + +// There is no directly analogous paragraph in C++0x, and the feature +// works sufficiently differently there that it needs a separate test. + +namespace test0 { + namespace NonClass { + typedef int type; + struct hiding {}; + int hiding; + static union { double union_member; }; + enum tagname { enumerator }; + } + + class Test0 { + NonClass::type; // expected-error {{not a class}} expected-warning {{access declarations are deprecated}} + NonClass::hiding; // expected-error {{not a class}} expected-warning {{access declarations are deprecated}} + NonClass::union_member; // expected-error {{not a class}} expected-warning {{access declarations are deprecated}} + NonClass::enumerator; // expected-error {{not a class}} expected-warning {{access declarations are deprecated}} + }; +} + +struct Opaque0 {}; + +namespace test1 { + struct A { + typedef int type; + struct hiding {}; // expected-note {{previous use is here}} + Opaque0 hiding; + union { double union_member; }; + enum tagname { enumerator }; + }; + + struct B : A { + A::type; // expected-warning {{access declarations are deprecated}} + A::hiding; // expected-warning {{access declarations are deprecated}} + A::union_member; // expected-warning {{access declarations are deprecated}} + A::enumerator; // expected-warning {{access declarations are deprecated}} + A::tagname; // expected-warning {{access declarations are deprecated}} + + void test0() { + type t = 0; + } + + void test1() { + typedef struct A::hiding local; + struct hiding _ = local(); + } + + void test2() { + union hiding _; // expected-error {{tag type that does not match previous}} + } + + void test3() { + char array[sizeof(union_member) == sizeof(double) ? 1 : -1]; + } + + void test4() { + enum tagname _ = enumerator; + } + + void test5() { + Opaque0 _ = hiding; + } + }; +} + +namespace test2 { + struct A { + typedef int type; + struct hiding {}; // expected-note {{previous use is here}} + int hiding; + union { double union_member; }; + enum tagname { enumerator }; + }; + + template struct B : A { + A::type; // expected-warning {{access declarations are deprecated}} + A::hiding; // expected-warning {{access declarations are deprecated}} + A::union_member; // expected-warning {{access declarations are deprecated}} + A::enumerator; // expected-warning {{access declarations are deprecated}} + A::tagname; // expected-warning {{access declarations are deprecated}} + + void test0() { + type t = 0; + } + + void test1() { + typedef struct A::hiding local; + struct hiding _ = local(); + } + + void test2() { + union hiding _; // expected-error {{tag type that does not match previous}} + } + + void test3() { + char array[sizeof(union_member) == sizeof(double) ? 1 : -1]; + } + + void test4() { + enum tagname _ = enumerator; + } + + void test5() { + Opaque0 _ = hiding; + } + }; +} + +namespace test3 { + struct hiding {}; + + template struct A { + typedef int type; // expected-note {{target of using declaration}} + struct hiding {}; + Opaque0 hiding; + union { double union_member; }; + enum tagname { enumerator }; // expected-note {{target of using declaration}} + }; + + template struct B : A { + A::type; // expected-error {{dependent using declaration resolved to type without 'typename'}} // expected-warning {{access declarations are deprecated}} + A::hiding; // expected-warning {{access declarations are deprecated}} + A::union_member; // expected-warning {{access declarations are deprecated}} + A::enumerator; // expected-warning {{access declarations are deprecated}} + A::tagname; // expected-error {{dependent using declaration resolved to type without 'typename'}} // expected-warning {{access declarations are deprecated}} + + // FIXME: re-enable these when the various bugs involving tags are fixed +#if 0 + void test1() { + typedef struct A::hiding local; + struct hiding _ = local(); + } + + void test2() { + typedef struct A::hiding local; + union hiding _ = local(); + } +#endif + + void test3() { + char array[sizeof(union_member) == sizeof(double) ? 1 : -1]; + } + +#if 0 + void test4() { + enum tagname _ = enumerator; + } +#endif + + void test5() { + Opaque0 _ = hiding; + } + }; + + template struct B; // expected-note {{in instantiation}} +} + +namespace test4 { + struct Base { + int foo(); + }; + + struct Unrelated { + int foo(); + }; + + struct Subclass : Base { + }; + + namespace InnerNS { + int foo(); + } + + // We should be able to diagnose these without instantiation. + template struct C : Base { + InnerNS::foo; // expected-error {{not a class}} expected-warning {{access declarations are deprecated}} + Base::bar; // expected-error {{no member named 'bar'}} expected-warning {{access declarations are deprecated}} + Unrelated::foo; // expected-error {{not a base class}} expected-warning {{access declarations are deprecated}} + C::foo; // legal in C++03 // expected-warning {{access declarations are deprecated}} + Subclass::foo; // legal in C++03 // expected-warning {{access declarations are deprecated}} + + int bar(); //expected-note {{target of using declaration}} + C::bar; // expected-error {{refers to its own class}} expected-warning {{access declarations are deprecated}} + }; +} + diff --git a/test/CXX/class/class.mfct/class.mfct.non-static/p3.cpp b/test/CXX/class/class.mfct/class.mfct.non-static/p3.cpp new file mode 100644 index 000000000000..b90661deefe6 --- /dev/null +++ b/test/CXX/class/class.mfct/class.mfct.non-static/p3.cpp @@ -0,0 +1,93 @@ +// RUN: clang-cc -fsyntax-only -verify %s + +// [class.mfct.non-static]p3: +// When an id-expression (5.1) that is not part of a class member +// access syntax (5.2.5) and not used to form a pointer to member +// (5.3.1) is used in the body of a non-static member function of +// class X, if name lookup (3.4.1) resolves the name in the +// id-expression to a non-static non-type member of some class C, +// the id-expression is transformed into a class member access +// expression (5.2.5) using (*this) (9.3.2) as the +// postfix-expression to the left of the . operator. [ Note: if C is +// not X or a base class of X, the class member access expression is +// ill-formed. --end note] Similarly during name lookup, when an +// unqualified-id (5.1) used in the definition of a member function +// for class X resolves to a static member, an enumerator or a +// nested type of class X or of a base class of X, the +// unqualified-id is transformed into a qualified-id (5.1) in which +// the nested-name-specifier names the class of the member function. + +namespace test0 { + class A { + int data_member; + int instance_method(); + static int static_method(); + + bool test() { + return data_member + instance_method() < static_method(); + } + }; +} + +namespace test1 { + struct Opaque1 {}; struct Opaque2 {}; struct Opaque3 {}; + + struct A { + void foo(Opaque1); // expected-note {{candidate}} + void foo(Opaque2); // expected-note {{candidate}} + void test(); + }; + + struct B : A { + + }; + + void A::test() { + B::foo(Opaque1()); + B::foo(Opaque2()); + B::foo(Opaque3()); // expected-error {{no matching member function}} + } +} + +namespace test2 { + class Unrelated { + void foo(); + }; + + template struct B; + template struct C; + + template struct A { + void foo(); + + void test0() { + Unrelated::foo(); // expected-error {{call to non-static member function without an object argument}} + } + + void test1() { + B::foo(); + } + + static void test2() { + B::foo(); // expected-error {{call to non-static member function without an object argument}} + } + + void test3() { + C::foo(); // expected-error {{no member named 'foo'}} + } + }; + + template struct B : A { + }; + + template struct C { + }; + + int test() { + A a; + a.test0(); // no instantiation note here, decl is ill-formed + a.test1(); + a.test2(); // expected-note {{in instantiation}} + a.test3(); // expected-note {{in instantiation}} + } +} diff --git a/test/CXX/dcl.dcl/basic.namespace/namespace.udecl/p10.cpp b/test/CXX/dcl.dcl/basic.namespace/namespace.udecl/p10.cpp new file mode 100644 index 000000000000..00d109e67516 --- /dev/null +++ b/test/CXX/dcl.dcl/basic.namespace/namespace.udecl/p10.cpp @@ -0,0 +1,33 @@ +// RUN: clang -fsyntax-only -verify %s + +namespace test0 { + namespace ns0 { + class tag; + int tag(); + } + + namespace ns1 { + using ns0::tag; + } + + namespace ns2 { + using ns0::tag; + } + + using ns1::tag; + using ns2::tag; +} + +// PR 5752 +namespace test1 { + namespace ns { + void foo(); + } + + using ns::foo; + void foo(int); + + namespace ns { + using test1::foo; + } +} diff --git a/test/CXX/dcl.dcl/basic.namespace/namespace.udecl/p11.cpp b/test/CXX/dcl.dcl/basic.namespace/namespace.udecl/p11.cpp new file mode 100644 index 000000000000..b4302d5b4b90 --- /dev/null +++ b/test/CXX/dcl.dcl/basic.namespace/namespace.udecl/p11.cpp @@ -0,0 +1,94 @@ +// RUN: clang-cc -fsyntax-only -verify %s + +// C++03 [namespace.udecl]p11: +// If a function declaration in namespace scope or block scope has +// the same name and the same parameter types as a function +// introduced by a using-declaration, the program is +// ill-formed. [Note: two using-declarations may introduce functions +// with the same name and the same parameter types. If, for a call +// to an unqualified function name, function overload resolution +// selects the functions introduced by such using-declarations, the +// function call is ill-formed. + +namespace test0 { + namespace ns { void foo(); } // expected-note {{target of using declaration}} + int foo(); // expected-note {{conflicting declaration}} + using ns::foo; // expected-error {{target of using declaration conflicts with declaration already in scope}} +} + +namespace test1 { + namespace ns { void foo(); } // expected-note {{target of using declaration}} + using ns::foo; //expected-note {{using declaration}} + int foo(); // expected-error {{declaration conflicts with target of using declaration already in scope}} +} + +namespace test2 { + namespace ns { void foo(); } // expected-note 2 {{target of using declaration}} + void test0() { + int foo(); // expected-note {{conflicting declaration}} + using ns::foo; // expected-error {{target of using declaration conflicts with declaration already in scope}} + } + + void test1() { + using ns::foo; //expected-note {{using declaration}} + int foo(); // expected-error {{declaration conflicts with target of using declaration already in scope}} + } +} + +namespace test3 { + namespace ns { void foo(); } // expected-note 2 {{target of using declaration}} + class Test0 { + void test() { + int foo(); // expected-note {{conflicting declaration}} + using ns::foo; // expected-error {{target of using declaration conflicts with declaration already in scope}} + } + }; + + class Test1 { + void test() { + using ns::foo; //expected-note {{using declaration}} + int foo(); // expected-error {{declaration conflicts with target of using declaration already in scope}} + } + }; +} + +namespace test4 { + namespace ns { void foo(); } // expected-note 2 {{target of using declaration}} + template class Test0 { + void test() { + int foo(); // expected-note {{conflicting declaration}} + using ns::foo; // expected-error {{target of using declaration conflicts with declaration already in scope}} + } + }; + + template class Test1 { + void test() { + using ns::foo; //expected-note {{using declaration}} + int foo(); // expected-error {{declaration conflicts with target of using declaration already in scope}} + } + }; +} + +// FIXME: we should be able to diagnose both of these, but we can't. +// ...I'm actually not sure why we can diagnose either of them; it's +// probably a bug. +namespace test5 { + namespace ns { void foo(int); } // expected-note {{target of using declaration}} + template class Test0 { + void test() { + int foo(T); + using ns::foo; + } + }; + + template class Test1 { + void test() { + using ns::foo; // expected-note {{using declaration}} + int foo(T); // expected-error {{declaration conflicts with target of using declaration already in scope}} + } + }; + + template class Test0; + template class Test1; // expected-note {{in instantiation of member function}} +} + diff --git a/test/CXX/dcl.dcl/basic.namespace/namespace.udecl/p12.cpp b/test/CXX/dcl.dcl/basic.namespace/namespace.udecl/p12.cpp new file mode 100644 index 000000000000..4cbe1be056e4 --- /dev/null +++ b/test/CXX/dcl.dcl/basic.namespace/namespace.udecl/p12.cpp @@ -0,0 +1,144 @@ +// RUN: clang-cc -fsyntax-only -verify %s + +// C++03 [namespace.udecl]p12: +// When a using-declaration brings names from a base class into a +// derived class scope, member functions in the derived class +// override and/or hide member functions with the same name and +// parameter types in a base class (rather than conflicting). + +template struct Opaque {}; +template void expect(Opaque _) {} + +// PR5727 +// This just shouldn't crash. +namespace test0 { + template struct RefPtr { }; + template struct PtrHash { + static void f() { } + }; + template struct PtrHash > : PtrHash { + using PtrHash::f; + static void f() { f(); } + }; +} + +// Simple hiding. +namespace test1 { + struct Base { + Opaque<0> foo(Opaque<0>); + Opaque<0> foo(Opaque<1>); + Opaque<0> foo(Opaque<2>); + }; + + // using before decls + struct Test0 : Base { + using Base::foo; + Opaque<1> foo(Opaque<1>); + Opaque<1> foo(Opaque<3>); + + void test0() { Opaque<0> _ = foo(Opaque<0>()); } + void test1() { Opaque<1> _ = foo(Opaque<1>()); } + void test2() { Opaque<0> _ = foo(Opaque<2>()); } + void test3() { Opaque<1> _ = foo(Opaque<3>()); } + }; + + // using after decls + struct Test1 : Base { + Opaque<1> foo(Opaque<1>); + Opaque<1> foo(Opaque<3>); + using Base::foo; + + void test0() { Opaque<0> _ = foo(Opaque<0>()); } + void test1() { Opaque<1> _ = foo(Opaque<1>()); } + void test2() { Opaque<0> _ = foo(Opaque<2>()); } + void test3() { Opaque<1> _ = foo(Opaque<3>()); } + }; + + // using between decls + struct Test2 : Base { + Opaque<1> foo(Opaque<0>); + using Base::foo; + Opaque<1> foo(Opaque<2>); + Opaque<1> foo(Opaque<3>); + + void test0() { Opaque<1> _ = foo(Opaque<0>()); } + void test1() { Opaque<0> _ = foo(Opaque<1>()); } + void test2() { Opaque<1> _ = foo(Opaque<2>()); } + void test3() { Opaque<1> _ = foo(Opaque<3>()); } + }; +} + +// Crazy dependent hiding. +namespace test2 { + struct Base { + void foo(int); + }; + + template struct Derived1 : Base { + using Base::foo; + void foo(T); + + void testUnresolved(int i) { foo(i); } + }; + + void test0(int i) { + Derived1 d1; + d1.foo(i); + d1.testUnresolved(i); + } + + // Same thing, except with the order of members reversed. + template struct Derived2 : Base { + void foo(T); + using Base::foo; + + void testUnresolved(int i) { foo(i); } + }; + + void test1(int i) { + Derived2 d2; + d2.foo(i); + d2.testUnresolved(i); + } +} + +// Hiding of member templates. +namespace test3 { + struct Base { + template Opaque<0> foo() { return Opaque<0>(); } + template Opaque<1> foo() { return Opaque<1>(); } + }; + + struct Derived1 : Base { + using Base::foo; + template Opaque<2> foo() { return Opaque<2>(); } + }; + + struct Derived2 : Base { + template Opaque<2> foo() { return Opaque<2>(); } + using Base::foo; + }; + + struct Derived3 : Base { + using Base::foo; + template Opaque<3> foo() { return Opaque<3>(); } + }; + + struct Derived4 : Base { + template Opaque<3> foo() { return Opaque<3>(); } + using Base::foo; + }; + + void test() { + expect<0>(Base().foo()); + expect<1>(Base().foo<0>()); + expect<0>(Derived1().foo()); + expect<2>(Derived1().foo<0>()); + expect<0>(Derived2().foo()); + expect<2>(Derived2().foo<0>()); + expect<3>(Derived3().foo()); + expect<1>(Derived3().foo<0>()); + expect<3>(Derived4().foo()); + expect<1>(Derived4().foo<0>()); + } +} diff --git a/test/CXX/dcl.dcl/basic.namespace/namespace.udecl/p13.cpp b/test/CXX/dcl.dcl/basic.namespace/namespace.udecl/p13.cpp new file mode 100644 index 000000000000..1a05aae3afd6 --- /dev/null +++ b/test/CXX/dcl.dcl/basic.namespace/namespace.udecl/p13.cpp @@ -0,0 +1,63 @@ +// RUN: clang-cc -fsyntax-only -verify %s + +// C++03 [namespace.udecl]p3: +// For the purpose of overload resolution, the functions which are +// introduced by a using-declaration into a derived class will be +// treated as though they were members of the derived class. In +// particular, the implicit this parameter shall be treated as if it +// were a pointer to the derived class rather than to the base +// class. This has no effect on the type of the function, and in all +// other respects the function remains a member of the base class. + +namespace test0 { + struct Opaque0 {}; + struct Opaque1 {}; + + struct Base { + Opaque0 test0(int*); + Opaque0 test1(const int*); + Opaque0 test2(int*); + Opaque0 test3(int*) const; + }; + + struct Derived : Base { + using Base::test0; + Opaque1 test0(const int*); + + using Base::test1; + Opaque1 test1(int*); + + using Base::test2; + Opaque1 test2(int*) const; + + using Base::test3; + Opaque1 test3(int*); + }; + + void test0() { + Opaque0 a = Derived().test0((int*) 0); + Opaque1 b = Derived().test0((const int*) 0); + } + + void test1() { + Opaque1 a = Derived().test1((int*) 0); + Opaque0 b = Derived().test1((const int*) 0); + } + + void test2() { + Opaque0 a = ((Derived*) 0)->test2((int*) 0); + Opaque1 b = ((const Derived*) 0)->test2((int*) 0); + } + + void test3() { + Opaque1 a = ((Derived*) 0)->test3((int*) 0); + Opaque0 b = ((const Derived*) 0)->test3((int*) 0); + } +} + +// Things to test: +// member operators +// conversion operators +// call operators +// call-surrogate conversion operators +// everything, but in dependent contexts diff --git a/test/CXX/dcl.dcl/basic.namespace/namespace.udecl/p3-cxx0x.cpp b/test/CXX/dcl.dcl/basic.namespace/namespace.udecl/p3-cxx0x.cpp index d701f885fba1..8257330dcf35 100644 --- a/test/CXX/dcl.dcl/basic.namespace/namespace.udecl/p3-cxx0x.cpp +++ b/test/CXX/dcl.dcl/basic.namespace/namespace.udecl/p3-cxx0x.cpp @@ -1,4 +1,4 @@ -// RUN: clang-cc -fsyntax-only -verify %s +// RUN: clang-cc -std=c++0x -fsyntax-only -verify %s // C++0x N2914. struct B { @@ -18,3 +18,29 @@ class D2 : public B { using B::x; using C::g; // expected-error{{using declaration refers into 'C::', which is not a base class of 'D2'}} }; + +namespace test1 { + struct Base { + int foo(); + }; + + struct Unrelated { + int foo(); + }; + + struct Subclass : Base { + }; + + namespace InnerNS { + int foo(); + } + + // We should be able to diagnose these without instantiation. + template struct C : Base { + using InnerNS::foo; // expected-error {{not a class}} + using Base::bar; // expected-error {{no member named 'bar'}} + using Unrelated::foo; // expected-error {{not a base class}} + using C::foo; // expected-error {{refers to its own class}} + using Subclass::foo; // expected-error {{not a base class}} + }; +} diff --git a/test/CXX/dcl.dcl/basic.namespace/namespace.udecl/p4.cpp b/test/CXX/dcl.dcl/basic.namespace/namespace.udecl/p4.cpp new file mode 100644 index 000000000000..bf314c41b5fb --- /dev/null +++ b/test/CXX/dcl.dcl/basic.namespace/namespace.udecl/p4.cpp @@ -0,0 +1,212 @@ +// RUN: clang-cc -fsyntax-only -verify %s + +// C++03 [namespace.udecl]p4: +// A using-declaration used as a member-declaration shall refer to a +// member of a base class of the class being defined, shall refer to +// a member of an anonymous union that is a member of a base class +// of the class being defined, or shall refer to an enumerator for +// an enumeration type that is a member of a base class of the class +// being defined. + +// There is no directly analogous paragraph in C++0x, and the feature +// works sufficiently differently there that it needs a separate test. + +namespace test0 { + namespace NonClass { + typedef int type; + struct hiding {}; + int hiding; + static union { double union_member; }; + enum tagname { enumerator }; + } + + class Test0 { + using NonClass::type; // expected-error {{not a class}} + using NonClass::hiding; // expected-error {{not a class}} + using NonClass::union_member; // expected-error {{not a class}} + using NonClass::enumerator; // expected-error {{not a class}} + }; +} + +struct Opaque0 {}; + +namespace test1 { + struct A { + typedef int type; + struct hiding {}; // expected-note {{previous use is here}} + Opaque0 hiding; + union { double union_member; }; + enum tagname { enumerator }; + }; + + struct B : A { + using A::type; + using A::hiding; + using A::union_member; + using A::enumerator; + using A::tagname; + + void test0() { + type t = 0; + } + + void test1() { + typedef struct A::hiding local; + struct hiding _ = local(); + } + + void test2() { + union hiding _; // expected-error {{tag type that does not match previous}} + } + + void test3() { + char array[sizeof(union_member) == sizeof(double) ? 1 : -1]; + } + + void test4() { + enum tagname _ = enumerator; + } + + void test5() { + Opaque0 _ = hiding; + } + }; +} + +namespace test2 { + struct A { + typedef int type; + struct hiding {}; // expected-note {{previous use is here}} + int hiding; + union { double union_member; }; + enum tagname { enumerator }; + }; + + template struct B : A { + using A::type; + using A::hiding; + using A::union_member; + using A::enumerator; + using A::tagname; + + void test0() { + type t = 0; + } + + void test1() { + typedef struct A::hiding local; + struct hiding _ = local(); + } + + void test2() { + union hiding _; // expected-error {{tag type that does not match previous}} + } + + void test3() { + char array[sizeof(union_member) == sizeof(double) ? 1 : -1]; + } + + void test4() { + enum tagname _ = enumerator; + } + + void test5() { + Opaque0 _ = hiding; + } + }; +} + +namespace test3 { + struct hiding {}; + + template struct A { + typedef int type; // expected-note {{target of using declaration}} + struct hiding {}; + Opaque0 hiding; // expected-note {{target of using declaration}} + union { double union_member; }; // expected-note {{target of using declaration}} + enum tagname { enumerator }; // expected-note 2 {{target of using declaration}} + }; + + template struct B : A { + using A::type; // expected-error {{dependent using declaration resolved to type without 'typename'}} + using A::hiding; + using A::union_member; + using A::enumerator; + using A::tagname; // expected-error {{dependent using declaration resolved to type without 'typename'}} + + // FIXME: re-enable these when the various bugs involving tags are fixed +#if 0 + void test1() { + typedef struct A::hiding local; + struct hiding _ = local(); + } + + void test2() { + typedef struct A::hiding local; + union hiding _ = local(); + } +#endif + + void test3() { + char array[sizeof(union_member) == sizeof(double) ? 1 : -1]; + } + +#if 0 + void test4() { + enum tagname _ = enumerator; + } +#endif + + void test5() { + Opaque0 _ = hiding; + } + }; + + template struct B; // expected-note {{in instantiation}} + + template struct C : A { + using typename A::type; + using typename A::hiding; // expected-error {{'typename' keyword used on a non-type}} + using typename A::union_member; // expected-error {{'typename' keyword used on a non-type}} + using typename A::enumerator; // expected-error {{'typename' keyword used on a non-type}} + + void test6() { + type t = 0; + } + + void test7() { + Opaque0 _ = hiding; // expected-error {{expected '(' for function-style cast or type construction}} + } + }; + + template struct C; // expected-note {{in instantiation}} +} + +namespace test4 { + struct Base { + int foo(); + }; + + struct Unrelated { + int foo(); + }; + + struct Subclass : Base { + }; + + namespace InnerNS { + int foo(); + } + + // We should be able to diagnose these without instantiation. + template struct C : Base { + using InnerNS::foo; // expected-error {{not a class}} + using Base::bar; // expected-error {{no member named 'bar'}} + using Unrelated::foo; // expected-error {{not a base class}} + using C::foo; // legal in C++03 + using Subclass::foo; // legal in C++03 + + int bar(); //expected-note {{target of using declaration}} + using C::bar; // expected-error {{refers to its own class}} + }; +} diff --git a/test/CXX/dcl.dcl/basic.namespace/namespace.udecl/p8.cpp b/test/CXX/dcl.dcl/basic.namespace/namespace.udecl/p8.cpp new file mode 100644 index 000000000000..bf0f330777d1 --- /dev/null +++ b/test/CXX/dcl.dcl/basic.namespace/namespace.udecl/p8.cpp @@ -0,0 +1,83 @@ +// RUN: clang-cc -fsyntax-only -verify %s + +struct Opaque0 {}; +struct Opaque1 {}; + +// Redeclarations are okay in a namespace. +namespace test0 { + namespace ns { + void foo(Opaque0); // expected-note 2 {{candidate function}} + } + + using ns::foo; + using ns::foo; + + void test0() { + foo(Opaque1()); // expected-error {{no matching function for call}} + } + + namespace ns { + void foo(Opaque1); + } + + void test1() { + foo(Opaque1()); // expected-error {{no matching function for call}} + } + + using ns::foo; + + void test2() { + foo(Opaque1()); + } + + using ns::foo; +} + +// Make sure we handle transparent contexts the same way. +namespace test1 { + namespace ns { + void foo(Opaque0); // expected-note 2 {{candidate function}} + } + + extern "C++" { + using ns::foo; + } + + void test0() { + foo(Opaque1()); // expected-error {{no matching function for call}} + } + + namespace ns { + void foo(Opaque1); + } + + void test1() { + foo(Opaque1()); // expected-error {{no matching function for call}} + } + + extern "C++" { + using ns::foo; + } + + void test2() { + foo(Opaque1()); + } +} + +// Make sure we detect invalid redeclarations that can't be detected +// until template instantiation. +namespace test2 { + template struct Base { + typedef Base type; + void foo(); + }; + + template struct Derived : Base { + // These are invalid redeclarations, detectable only after + // instantiation. + using Base::foo; // expected-note {{previous using decl}} + using Base::type::foo; //expected-error {{redeclaration of using decl}} + }; + + template struct Derived; // expected-note {{in instantiation of template class}} +} diff --git a/test/CXX/dcl.decl/dcl.init/dcl.init.list/basic.cpp b/test/CXX/dcl.decl/dcl.init/dcl.init.list/basic.cpp new file mode 100644 index 000000000000..f62b4250eef0 --- /dev/null +++ b/test/CXX/dcl.decl/dcl.init/dcl.init.list/basic.cpp @@ -0,0 +1,5 @@ +// RUN: clang-cc -fsyntax-only -verify %s + +void f0() { + int &ir = { 17 }; // expected-error{{reference to type 'int' cannot bind to an initializer list}} +} diff --git a/test/CXX/dcl.decl/dcl.init/dcl.init.ref/p1.cpp b/test/CXX/dcl.decl/dcl.init/dcl.init.ref/p1.cpp new file mode 100644 index 000000000000..66fa2d139844 --- /dev/null +++ b/test/CXX/dcl.decl/dcl.init/dcl.init.ref/p1.cpp @@ -0,0 +1,14 @@ +// RUN: clang-cc -fsyntax-only -verify -std=c++0x %s +int g(int); +void f() { + int i; + int& r = i; + r = 1; + int* p = &r; + int &rr=r; + int (&rg)(int) = g; + rg(i); + int a[3]; + int (&ra)[3] = a; + ra[1] = i; +} diff --git a/test/CXX/dcl.decl/dcl.init/dcl.init.ref/p3.cpp b/test/CXX/dcl.decl/dcl.init/dcl.init.ref/p3.cpp new file mode 100644 index 000000000000..54840f52663f --- /dev/null +++ b/test/CXX/dcl.decl/dcl.init/dcl.init.ref/p3.cpp @@ -0,0 +1,3 @@ +// RUN: clang-cc -fsyntax-only -verify %s +int& r1; // expected-error{{declaration of reference variable 'r1' requires an initializer}} +extern int& r2; diff --git a/test/CXX/dcl.decl/dcl.init/dcl.init.ref/p5-examples.cpp b/test/CXX/dcl.decl/dcl.init/dcl.init.ref/p5-examples.cpp new file mode 100644 index 000000000000..5d34345c49fd --- /dev/null +++ b/test/CXX/dcl.decl/dcl.init/dcl.init.ref/p5-examples.cpp @@ -0,0 +1,53 @@ +// RUN: clang-cc -ast-dump %s 2>&1 | FileCheck %s + +// CHECK: example0 +void example0() { + double d = 2.0; + // CHECK: double &rd = + // CHECK-NEXT: DeclRefExpr + double &rd = d; + // CHECK: double const &rcd = + // CHECK-NEXT: ImplicitCastExpr{{.*}}'double const' + const double &rcd = d; +} + +struct A { }; +struct B : A { } b; + +// CHECK: example1 +void example1() { + // CHECK: struct A &ra = + // CHECK: ImplicitCastExpr{{.*}}'struct A' lvalue + A &ra = b; + // CHECK: struct A const &rca = + // CHECK: ImplicitCastExpr{{.*}}'struct A const' + // CHECK: ImplicitCastExpr{{.*}}'struct A' + const A& rca = b; +} + +extern B f(); + +struct X { + operator B(); +} x; + +// CHECK: example2 +void example2() { + // CHECK: struct A const &rca = + // CHECK: ImplicitCastExpr{{.*}}'struct A const' + // CHECK: ImplicitCastExpr{{.*}}'struct A' + // CHECK: CallExpr{{.*}}struct B + const A &rca = f(); + // CHECK: struct A const &r = + // CHECK: ImplicitCastExpr{{.*}}'struct A const' + // CHECK: ImplicitCastExpr{{.*}}'struct A' + // CHECK: CXXMemberCallExpr{{.*}}'struct B' + const A& r = x; +} + +// CHECK: example3 +void example3() { + // CHECK: double const &rcd2 = + // CHECK: ImplicitCastExpr{{.*}} + const double& rcd2 = 2; +} diff --git a/test/CXX/dcl.decl/dcl.init/dcl.init.ref/p5-var.cpp b/test/CXX/dcl.decl/dcl.init/dcl.init.ref/p5-var.cpp new file mode 100644 index 000000000000..5fa1fff8c86e --- /dev/null +++ b/test/CXX/dcl.decl/dcl.init/dcl.init.ref/p5-var.cpp @@ -0,0 +1,129 @@ +// RUN: clang-cc -fsyntax-only -verify %s + +struct Base { }; // expected-note{{candidate function}} +struct Derived : Base { }; // expected-note{{candidate function}} +struct Unrelated { }; +struct Derived2 : Base { }; +struct Diamond : Derived, Derived2 { }; + +struct ConvertibleToBaseRef { + operator Base&() const; +}; + +struct ConvertibleToDerivedRef { + operator Derived&() const; +}; + +struct ConvertibleToBothDerivedRef { + operator Derived&(); // expected-note{{candidate function}} + operator Derived2&(); // expected-note{{candidate function}} +}; + +struct ConvertibleToIntRef { + operator int&(); +}; + +struct ConvertibleToBase { + operator Base() const; +}; + +struct ConvertibleToDerived { + operator Derived() const; +}; + +struct ConvertibleToBothDerived { + operator Derived(); // expected-note{{candidate function}} + operator Derived2(); // expected-note{{candidate function}} +}; + +struct ConvertibleToInt { + operator int(); +}; + +template T create(); + +// First bullet: lvalue references binding to lvalues (the simple cases). +void bind_lvalue_to_lvalue(Base b, Derived d, + const Base bc, const Derived dc, + Diamond diamond, + int i) { + // Reference-compatible + Base &br1 = b; + Base &br2 = d; + Derived &dr1 = d; + Derived &dr2 = b; // expected-error{{non-const lvalue reference to type 'struct Derived' cannot bind to a value of unrelated type 'struct Base'}} + Base &br3 = bc; // expected-error{{drops qualifiers}} + Base &br4 = dc; // expected-error{{drops qualifiers}} + Base &br5 = diamond; // expected-error{{ambiguous conversion from derived class 'struct Diamond' to base class 'struct Base'}} + int &ir = i; + long &lr = i; // expected-error{{non-const lvalue reference to type 'long' cannot bind to a value of unrelated type 'int'}} +} + +void bind_lvalue_quals(volatile Base b, volatile Derived d, + volatile const Base bvc, volatile const Derived dvc, + volatile const int ivc) { + volatile Base &bvr1 = b; + volatile Base &bvr2 = d; + volatile Base &bvr3 = bvc; // expected-error{{binding of reference to type 'struct Base volatile' to a value of type 'struct Base const volatile' drops qualifiers}} + volatile Base &bvr4 = dvc; // expected-error{{binding of reference to type 'struct Base volatile' to a value of type 'struct Derived const volatile' drops qualifiers}} + + volatile int &ir = ivc; // expected-error{{binding of reference to type 'int volatile' to a value of type 'int const volatile' drops qualifiers}} +} + +void bind_lvalue_to_rvalue() { + Base &br1 = Base(); // expected-error{{non-const lvalue reference to type 'struct Base' cannot bind to a temporary of type 'struct Base'}} + Base &br2 = Derived(); // expected-error{{non-const lvalue reference to type 'struct Base' cannot bind to a temporary of type 'struct Derived'}} + + int &ir = 17; // expected-error{{non-const lvalue reference to type 'int' cannot bind to a temporary of type 'int'}} +} + +void bind_lvalue_to_unrelated(Unrelated ur) { + Base &br1 = ur; // expected-error{{non-const lvalue reference to type 'struct Base' cannot bind to a value of unrelated type 'struct Unrelated'}} +} + +void bind_lvalue_to_conv_lvalue() { + // Not reference-related, but convertible + Base &nbr1 = ConvertibleToBaseRef(); + Base &nbr2 = ConvertibleToDerivedRef(); + Derived &ndr1 = ConvertibleToDerivedRef(); + int &ir = ConvertibleToIntRef(); +} + +void bind_lvalue_to_conv_lvalue_ambig(ConvertibleToBothDerivedRef both) { + Derived &dr1 = both; + Base &br1 = both; // expected-error{{error: conversion from 'struct ConvertibleToBothDerivedRef' to 'struct Base' is ambiguous}} +} + +struct IntBitfield { + int i : 17; // expected-note{{bit-field is declared here}} +}; + +void test_bitfield(IntBitfield ib) { + int & ir1 = (ib.i); // expected-error{{non-const reference cannot bind to bit-field 'i'}} +} + +// Second bullet: const lvalue reference binding to an rvalue with +// similar type (both of which are class types). +void bind_const_lvalue_to_rvalue() { + const Base &br1 = create(); + const Base &br2 = create(); + const Derived &dr1 = create(); // expected-error{{no viable conversion}} + + const Base &br3 = create(); + const Base &br4 = create(); + + const Base &br5 = create(); // expected-error{{binding of reference to type 'struct Base const' to a value of type 'struct Base const volatile' drops qualifiers}} + const Base &br6 = create(); // expected-error{{binding of reference to type 'struct Base const' to a value of type 'struct Derived const volatile' drops qualifiers}} + + const int &ir = create(); +} + +// Second bullet: const lvalue reference binds to the result of a conversion. +void bind_const_lvalue_to_class_conv_temporary() { + const Base &br1 = ConvertibleToBase(); + const Base &br2 = ConvertibleToDerived(); +} +void bind_lvalue_to_conv_rvalue_ambig(ConvertibleToBothDerived both) { + const Derived &dr1 = both; + const Base &br1 = both; // expected-error{{error: conversion from 'struct ConvertibleToBothDerived' to 'struct Base const' is ambiguous}} +} diff --git a/test/CXX/special/class.free/p6.cpp b/test/CXX/special/class.free/p6.cpp index 8334817ca2b5..b082b85d18c4 100644 --- a/test/CXX/special/class.free/p6.cpp +++ b/test/CXX/special/class.free/p6.cpp @@ -2,7 +2,7 @@ #include struct A { - void operator delete(size_t) { + void operator delete(void*) { (void)this; // expected-error {{invalid use of 'this' outside of a nonstatic member function}} } void operator delete[](void*) { diff --git a/test/CXX/temp/temp.spec/temp.expl.spec/p17.cpp b/test/CXX/temp/temp.spec/temp.expl.spec/p17.cpp index 883cb71d5686..06653044c3bb 100644 --- a/test/CXX/temp/temp.spec/temp.expl.spec/p17.cpp +++ b/test/CXX/temp/temp.spec/temp.expl.spec/p17.cpp @@ -10,3 +10,15 @@ template<> template<> class A::B; template<> template<> void A::B::mf(); template<> void A::B::mf(); // expected-error{{requires 'template<>'}} + +namespace test1 { + template class A { + static int foo; + static int bar; + }; + typedef A AA; + + template <> int AA::foo = 0; // expected-error {{cannot use typedef}} + int AA::bar = 1; // expected-error {{cannot use typedef}} expected-error {{template specialization requires 'template<>'}} + int A::bar = 2; // expected-error {{template specialization requires 'template<>'}} +} diff --git a/test/CodeCompletion/function-templates.cpp b/test/CodeCompletion/function-templates.cpp index d291bbe12bad..302b95516f3b 100644 --- a/test/CodeCompletion/function-templates.cpp +++ b/test/CodeCompletion/function-templates.cpp @@ -6,9 +6,18 @@ namespace std { X* dyn_cast(Y *Val); } +class Foo { +public: + template T &getAs(); +}; + void f() { - std:: - // RUN: clang-cc -fsyntax-only -code-completion-at=%s:10:8 %s -o - | FileCheck -check-prefix=CC1 %s + std::sort(1, 2); + Foo().getAs(); + // RUN: clang-cc -fsyntax-only -code-completion-at=%s:15:8 %s -o - | FileCheck -check-prefix=CHECK-CC1 %s // CHECK-CC1: dyn_cast<<#class X#>>(<#Y *Val#>) - // CHECK-CC1: sort(<#RandomAccessIterator first#>, <#RandomAccessIterator last#>) + // CHECK-CC1: sort(<#RandomAccessIterator first#>, <#RandomAccessIterator last#> + // RUN: clang-cc -fsyntax-only -code-completion-at=%s:16:9 %s -o - | FileCheck -check-prefix=CHECK-CC2 %s + // CHECK-CC2: getAs<<#typename T#>>() +) diff --git a/test/CodeCompletion/member-access.cpp b/test/CodeCompletion/member-access.cpp index e445b4503aa3..d03180b182de 100644 --- a/test/CodeCompletion/member-access.cpp +++ b/test/CodeCompletion/member-access.cpp @@ -11,7 +11,7 @@ struct Base2 { struct Base3 : Base1, Base2 { void memfun1(float); - void memfun1(double); + void memfun1(double) const; void memfun2(int); }; @@ -34,9 +34,9 @@ void test(const Proxy &p) { // CHECK-CC1: member3 : 0 // CHECK-CC1: member4 : 0 // CHECK-CC1: memfun1 : 0 : [#Base3::#]memfun1(<#float#>) - // CHECK-CC1: memfun1 : 0 : [#Base3::#]memfun1(<#double#>) + // CHECK-CC1: memfun1 : 0 : [#Base3::#]memfun1(<#double#>)[# const#] // CHECK-CC1: memfun2 : 0 : [#Base3::#]memfun2(<#int#>) // CHECK-CC1: memfun3 : 0 : memfun3(<#int#>) - // CHECK-CC1: Base1 : 0 : Base1:: // CHECK-CC1: memfun1 : 0 (Hidden) : Base2::memfun1(<#int#>) + // CHECK-CC1: Base1 : 3 : Base1:: diff --git a/test/CodeCompletion/objc-message.m b/test/CodeCompletion/objc-message.m index d16a745b71f5..58fc4f5d68f2 100644 --- a/test/CodeCompletion/objc-message.m +++ b/test/CodeCompletion/objc-message.m @@ -23,13 +23,13 @@ void func() { Foo *obj = [Foo new]; [obj xx]; } -// RUN: clang-cc -fsyntax-only -code-completion-at=%s:23:19 %s -o - | FileCheck -check-prefix=CHECK-CC1 %s +// RUN: clang -cc1 -fsyntax-only -code-completion-at=%s:23:19 %s -o - | FileCheck -check-prefix=CHECK-CC1 %s // CHECK-CC1: categoryClassMethod : 0 // CHECK-CC1: classMethod1:withKeyword: : 0 // CHECK-CC1: classMethod2 : 0 // CHECK-CC1: new : 0 // CHECK-CC1: protocolClassMethod : 0 -// RUN: clang-cc -fsyntax-only -code-completion-at=%s:24:8 %s -o - | FileCheck -check-prefix=CHECK-CC2 %s +// RUN: clang -cc1 -fsyntax-only -code-completion-at=%s:24:8 %s -o - | FileCheck -check-prefix=CHECK-CC2 %s // CHECK-CC2: categoryInstanceMethod : 0 // CHECK-CC2: instanceMethod1 : 0 // CHECK-CC2: protocolInstanceMethod : 0 diff --git a/test/CodeCompletion/templates.cpp b/test/CodeCompletion/templates.cpp index d35e0bb8dcde..ff5611823d72 100644 --- a/test/CodeCompletion/templates.cpp +++ b/test/CodeCompletion/templates.cpp @@ -1,16 +1,28 @@ namespace std { template - class allocator; + class allocator { + public: + void in_base(); + }; template > - class vector; + class vector : Alloc { + public: + void foo(); + void stop(); + }; + template class vector; } void f() { - std:: - // RUN: clang-cc -fsyntax-only -code-completion-at=%s:10:8 %s -o - | FileCheck -check-prefix=CC1 %s + std::vector v; + v.foo(); + // RUN: clang-cc -fsyntax-only -code-completion-at=%s:18:8 %s -o - | FileCheck -check-prefix=CHECK-CC1 %s // CHECK-CC1: allocator<<#typename T#>> - // CHECK-CC1: vector<<#typename T#>{#, <#typename Alloc#>#}> - + // CHECK-CC1-NEXT: vector<<#typename T#>{#, <#typename Alloc#>#}> + // RUN: clang-cc -fsyntax-only -code-completion-at=%s:19:5 %s -o - | FileCheck -check-prefix=CHECK-CC2 %s + // CHECK-CC2: foo + // CHECK-CC2: in_base + // CHECK-CC2: stop diff --git a/test/CodeGen/2008-08-25-incompatible-cond-expr.m b/test/CodeGen/2008-08-25-incompatible-cond-expr.m index 3cc42d89f6fa..fa9b1970f7fd 100644 --- a/test/CodeGen/2008-08-25-incompatible-cond-expr.m +++ b/test/CodeGen/2008-08-25-incompatible-cond-expr.m @@ -1,4 +1,4 @@ -// RUN: clang-cc -emit-llvm -o %t %s +// RUN: clang -cc1 -emit-llvm -o %t %s @protocol P0 @end diff --git a/test/CodeGen/2009-01-21-invalid-debug-info.m b/test/CodeGen/2009-01-21-invalid-debug-info.m index 2662b922a03c..1c1028b4ea98 100644 --- a/test/CodeGen/2009-01-21-invalid-debug-info.m +++ b/test/CodeGen/2009-01-21-invalid-debug-info.m @@ -1,4 +1,4 @@ -// RUN: clang-cc -S -g -o %t.s %s +// RUN: clang -cc1 -S -g -o %t.s %s // FIXME: This test case can be removed at some point (since it will // no longer effectively test anything). The reason it was causing diff --git a/test/CodeGen/arm_asm_clobber.c b/test/CodeGen/arm_asm_clobber.c index 34e2517aefab..05eb2e211f24 100644 --- a/test/CodeGen/arm_asm_clobber.c +++ b/test/CodeGen/arm_asm_clobber.c @@ -1,4 +1,4 @@ -// RUN: clang -ccc-host-triple armv6-unknown-unknown -emit-llvm -S -o %t %s +// RUN: clang-cc -triple armv6-unknown-unknown -emit-llvm -o %t %s void test0(void) { asm volatile("mov r0, r0" :: ); diff --git a/test/CodeGen/cast-to-union.c b/test/CodeGen/cast-to-union.c deleted file mode 100644 index 1f7e0457706d..000000000000 --- a/test/CodeGen/cast-to-union.c +++ /dev/null @@ -1,14 +0,0 @@ -// RUN: clang-cc -emit-llvm %s -o - | FileCheck %s -// CHECK: w = global %0 { i32 2, [4 x i8] undef } -// CHECK: y = global %union.u { double 7.300000e+0{{[0]*}}1 } -// CHECK: store i32 351, i32 - -union u { int i; double d; }; - -void foo() { - union u ola = (union u) 351; - union u olb = (union u) 1.0; -} - -union u w = (union u)2; -union u y = (union u)73.0; diff --git a/test/CodeGen/decl.c b/test/CodeGen/decl.c new file mode 100644 index 000000000000..f7a001e47ce4 --- /dev/null +++ b/test/CodeGen/decl.c @@ -0,0 +1,61 @@ +// RUN: clang-cc -emit-llvm < %s | FileCheck %s + +// CHECK: @test1.x = internal constant [12 x i32] [i32 1 +// CHECK: @test2.x = internal constant [13 x i32] [i32 1, +// CHECK: @test5w = global %0 { i32 2, [4 x i8] undef } +// CHECK: @test5y = global %union.test5u { double 7.300000e+0{{[0]*}}1 } + +void test1() { + // This should codegen as a "@test1.x" global. + const int x[] = { 1, 2, 3, 4, 6, 8, 9, 10, 123, 231, 123,23 }; + foo(x); + +// CHECK: @test1() +// CHECK: {{call.*@foo.*@test1.x}} +} + + +// rdar://7346691 +void test2() { + // This should codegen as a "@test2.x" global + memcpy. + int x[] = { 1, 2, 3, 4, 6, 8, 9, 10, 123, 231, 123,23, 24 }; + foo(x); + + // CHECK: @test2() + // CHECK: %x = alloca [13 x i32] + // CHECK: call void @llvm.memcpy + // CHECK: call{{.*}}@foo{{.*}}i32* % +} + + +void test3() { + // This should codegen as a memset. + int x[100] = { 0 }; + foo(x); + + // CHECK: @test3() + // CHECK: %x = alloca [100 x i32] + // CHECK: call void @llvm.memset +} + +void test4(void) { + char a[10] = "asdf"; + char b[10] = { "asdf" }; + // CHECK: @test4() + // CHECK: %a = alloca [10 x i8] + // CHECK: %b = alloca [10 x i8] + // CHECK: call void @llvm.memcpy + // CHECK: call void @llvm.memcpy +} + + +union test5u { int i; double d; }; + +void test5() { + union test5u ola = (union test5u) 351; + union test5u olb = (union test5u) 1.0; +} + +union test5u test5w = (union test5u)2; +union test5u test5y = (union test5u)73.0; + diff --git a/test/CodeGen/exprs.c b/test/CodeGen/exprs.c index a0e5b7644aeb..c1a5995dfc8d 100644 --- a/test/CodeGen/exprs.c +++ b/test/CodeGen/exprs.c @@ -116,3 +116,6 @@ void f9(struct S *x) { foo(((void)1, x->c).tab[0]); } +void f10() { + __builtin_sin(0); +} diff --git a/test/CodeGen/function-decay.m b/test/CodeGen/function-decay.m index 5652fdbb21ea..4b8e3602d460 100644 --- a/test/CodeGen/function-decay.m +++ b/test/CodeGen/function-decay.m @@ -1,4 +1,4 @@ -// RUN: clang-cc %s -emit-llvm -o - +// RUN: clang -cc1 %s -emit-llvm -o - @interface I0 @end @implementation I0 diff --git a/test/CodeGen/object-size.c b/test/CodeGen/object-size.c index 038d8f98e5d5..45747de6c921 100644 --- a/test/CodeGen/object-size.c +++ b/test/CodeGen/object-size.c @@ -1,4 +1,4 @@ -// RUN: clang-cc -triple x86_64-apple-darwin -S %s -o - | FileCheck %s +// RUN: clang-cc -triple x86_64-apple-darwin -emit-llvm %s -o - | FileCheck %s #define strcpy(dest, src) \ ((__builtin_object_size(dest, 0) != -1ULL) \ @@ -14,113 +14,98 @@ char *gp; int gi, gj; void test1() { - // CHECK: movabsq $59, %rdx - // CHECK-NEXT: movq - // CHECK-NEXT: movq - // CHECK-NEXT: call ___strcpy_chk + // CHECK: %call = call i8* @__strcpy_chk(i8* getelementptr inbounds ([63 x i8]* @gbuf, i32 0, i64 4), i8* getelementptr inbounds ([9 x i8]* @.str, i32 0, i32 0), i64 59) strcpy(&gbuf[4], "Hi there"); } void test2() { - // CHECK: movabsq $63, %rdx - // CHECK-NEXT: movq - // CHECK-NEXT: movq - // CHECK-NEXT: call ___strcpy_chk + // CHECK: %call = call i8* @__strcpy_chk(i8* getelementptr inbounds ([63 x i8]* @gbuf, i32 0, i32 0), i8* getelementptr inbounds ([9 x i8]* @.str, i32 0, i32 0), i64 63) strcpy(gbuf, "Hi there"); } void test3() { - // CHECK: movabsq $0, %rdx - // CHECK-NEXT: movq - // CHECK-NEXT: movq - // CHECK-NEXT: call ___strcpy_chk + // CHECK: %call = call i8* @__strcpy_chk(i8* getelementptr inbounds ([63 x i8]* @gbuf, i64 1, i64 37), i8* getelementptr inbounds ([9 x i8]* @.str, i32 0, i32 0), i64 0) strcpy(&gbuf[100], "Hi there"); } void test4() { - // CHECK: movabsq $0, %rdx - // CHECK-NEXT: movq - // CHECK-NEXT: movq - // CHECK-NEXT: call ___strcpy_chk + // CHECK: %call = call i8* @__strcpy_chk(i8* getelementptr inbounds ([63 x i8]* @gbuf, i32 0, i64 -1), i8* getelementptr inbounds ([9 x i8]* @.str, i32 0, i32 0), i64 0) strcpy((char*)(void*)&gbuf[-1], "Hi there"); } void test5() { - // CHECK: movq $-1, %rax - // CHECK-NEXT: cmpq $-1, %rax - // CHECK: call ___inline_strcpy_chk + // CHECK: %tmp = load i8** @gp + // CHECK-NEXT:%0 = call i64 @llvm.objectsize.i64(i8* %tmp, i32 0) + // CHECK-NEXT:%cmp = icmp ne i64 %0, -1 strcpy(gp, "Hi there"); } void test6() { char buf[57]; - // CHECK: movabsq $53, %rdx - // CHECK-NEXT: movq - // CHECK-NEXT: movq - // CHECK-NEXT: call ___strcpy_chk + // CHECK: %call = call i8* @__strcpy_chk(i8* %arrayidx, i8* getelementptr inbounds ([9 x i8]* @.str, i32 0, i32 0), i64 53) strcpy(&buf[4], "Hi there"); } void test7() { int i; - // CHECK-NOT: call ___strcpy_chk - // CHECK: call ___inline_strcpy_chk + // CHECK-NOT: __strcpy_chk + // CHECK: %call = call i8* @__inline_strcpy_chk(i8* getelementptr inbounds ([63 x i8]* @gbuf, i32 0, i32 0), i8* getelementptr inbounds ([9 x i8]* @.str, i32 0, i32 0)) strcpy((++i, gbuf), "Hi there"); } void test8() { char *buf[50]; - // CHECK-NOT: call ___strcpy_chk - // CHECK: call ___inline_strcpy_chk + // CHECK-NOT: __strcpy_chk + // CHECK: %call = call i8* @__inline_strcpy_chk(i8* %tmp1, i8* getelementptr inbounds ([9 x i8]* @.str, i32 0, i32 0)) strcpy(buf[++gi], "Hi there"); } void test9() { - // CHECK-NOT: call ___strcpy_chk - // CHECK: call ___inline_strcpy_chk + // CHECK-NOT: __strcpy_chk + // CHECK: %call = call i8* @__inline_strcpy_chk(i8* %0, i8* getelementptr inbounds ([9 x i8]* @.str, i32 0, i32 0)) strcpy((char *)((++gi) + gj), "Hi there"); } char **p; void test10() { - // CHECK-NOT: call ___strcpy_chk - // CHECK: call ___inline_strcpy_chk + // CHECK-NOT: __strcpy_chk + // CHECK: %call = call i8* @__inline_strcpy_chk(i8* %tmp1, i8* getelementptr inbounds ([9 x i8]* @.str, i32 0, i32 0)) strcpy(*(++p), "Hi there"); } void test11() { - // CHECK-NOT: call ___strcpy_chk - // CHECK: call ___inline_strcpy_chk + // CHECK-NOT: __strcpy_chk + // CHECK: %call = call i8* @__inline_strcpy_chk(i8* %tmp, i8* getelementptr inbounds ([9 x i8]* @.str, i32 0, i32 0)) strcpy(gp = gbuf, "Hi there"); } void test12() { - // CHECK-NOT: call ___strcpy_chk - // CHECK: call ___inline_strcpy_chk + // CHECK-NOT: __strcpy_chk + // CHECK: %call = call i8* @__inline_strcpy_chk(i8* %ptrincdec, i8* getelementptr inbounds ([9 x i8]* @.str, i32 0, i32 0)) strcpy(++gp, "Hi there"); } void test13() { - // CHECK-NOT: call ___strcpy_chk - // CHECK: call ___inline_strcpy_chk + // CHECK-NOT: __strcpy_chk + // CHECK: %call = call i8* @__inline_strcpy_chk(i8* %tmp, i8* getelementptr inbounds ([9 x i8]* @.str, i32 0, i32 0)) strcpy(gp++, "Hi there"); } void test14() { - // CHECK-NOT: call ___strcpy_chk - // CHECK: call ___inline_strcpy_chk + // CHECK-NOT: __strcpy_chk + // CHECK: %call = call i8* @__inline_strcpy_chk(i8* %ptrincdec, i8* getelementptr inbounds ([9 x i8]* @.str, i32 0, i32 0)) strcpy(--gp, "Hi there"); } void test15() { - // CHECK-NOT: call ___strcpy_chk - // CHECK: call ___inline_strcpy_chk + // CHECK-NOT: __strcpy_chk + // CHECK: %call = call i8* @__inline_strcpy_chk(i8* %tmp, i8* getelementptr inbounds ([9 x i8]* @.str, i32 0, i32 0)) strcpy(gp--, "Hi there"); } void test16() { - // CHECK-NOT: call ___strcpy_chk - // CHECK: call ___inline_strcpy_chk + // CHECK-NOT: __strcpy_chk + // CHECK: %call = call i8* @__inline_strcpy_chk(i8* %tmp1, i8* getelementptr inbounds ([9 x i8]* @.str, i32 0, i32 0)) strcpy(gp += 1, "Hi there"); } diff --git a/test/CodeGen/palignr.c b/test/CodeGen/palignr.c new file mode 100644 index 000000000000..41e48bd2854d --- /dev/null +++ b/test/CodeGen/palignr.c @@ -0,0 +1,19 @@ +// RUN: clang-cc %s -triple=i686-apple-darwin -target-feature +ssse3 -O1 -S -o - | FileCheck %s + +#define _mm_alignr_epi8(a, b, n) (__builtin_ia32_palignr128((a), (b), (n))) +#define _mm_alignr_pi8(a, b, n) (__builtin_ia32_palignr((a), (b), (n*8))) +typedef __attribute__((vector_size(8))) int int2; +typedef __attribute__((vector_size(16))) int int4; + +// CHECK: palignr +int2 mmx_align1(int2 a, int2 b) { return _mm_alignr_pi8(a, b, 7); } +// CHECK: palignr +int4 align1(int4 a, int4 b) { return _mm_alignr_epi8(a, b, 15); } +// CHECK: ret +// CHECK: ret +// CHECK-NOT: palignr +int4 align2(int4 a, int4 b) { return _mm_alignr_epi8(a, b, 16); } +// CHECK: psrldq +int4 align3(int4 a, int4 b) { return _mm_alignr_epi8(a, b, 17); } +// CHECK: xorps +int4 align4(int4 a, int4 b) { return _mm_alignr_epi8(a, b, 32); } diff --git a/test/CodeGen/rdr-6732143-dangling-block-reference.m b/test/CodeGen/rdr-6732143-dangling-block-reference.m index 2d1baa622009..90641dd083cb 100644 --- a/test/CodeGen/rdr-6732143-dangling-block-reference.m +++ b/test/CodeGen/rdr-6732143-dangling-block-reference.m @@ -1,4 +1,4 @@ -// RUN: clang-cc -triple x86_64-apple-darwin9 -emit-llvm %s -o - +// RUN: clang -cc1 -triple x86_64-apple-darwin9 -emit-llvm %s -o - void f0(id x) { @synchronized (x) { diff --git a/test/CodeGen/string-init.c b/test/CodeGen/string-init.c deleted file mode 100644 index 0cb6afff611d..000000000000 --- a/test/CodeGen/string-init.c +++ /dev/null @@ -1,10 +0,0 @@ -// RUN: clang-cc -emit-llvm %s -o %t -// RUN: grep 'private constant \[10 x i8\]' %t -// RUN: not grep -F "[5 x i8]" %t -// RUN: not grep "store " %t - -void test(void) { - char a[10] = "asdf"; - char b[10] = { "asdf" }; -} - diff --git a/test/CodeGen/vfprintf.c b/test/CodeGen/vfprintf.c new file mode 100644 index 000000000000..89261c7469c6 --- /dev/null +++ b/test/CodeGen/vfprintf.c @@ -0,0 +1,8 @@ +// RUN: clang-cc -emit-llvm-only %s + +typedef struct _IO_FILE FILE; +int vfprintf(FILE*restrict,const char*restrict, __builtin_va_list); +void foo(__builtin_va_list ap) { + vfprintf(0, " ", ap); +} + diff --git a/test/CodeGenCXX/class-layout.cpp b/test/CodeGenCXX/class-layout.cpp index 7663d2e541b2..d4fc627082d2 100644 --- a/test/CodeGenCXX/class-layout.cpp +++ b/test/CodeGenCXX/class-layout.cpp @@ -1,5 +1,9 @@ -// RUN: clang-cc %s -emit-llvm -o %t +// RUN: clang-cc %s -emit-llvm -o - | FileCheck %s // An extra byte shoudl be allocated for an empty class. -// RUN: grep '%.truct.A = type { i8 }' %t +// CHECK: %struct.A = type { i8 } struct A { } a; + +// No need to add tail padding here. +// CHECK: %struct.B = type { i8*, i32 } +struct B { void *a; int b; } b; diff --git a/test/CodeGenCXX/constructor-convert.cpp b/test/CodeGenCXX/constructor-convert.cpp new file mode 100644 index 000000000000..6fa6d556dc50 --- /dev/null +++ b/test/CodeGenCXX/constructor-convert.cpp @@ -0,0 +1,19 @@ +// RUN: clang -emit-llvm -S -o - %s + +// PR5775 +class Twine { + Twine(const char *Str) { } +}; + +static void error(const Twine &Message); + +template +struct opt_storage { + void f() { + error("cl::location(x) specified more than once!"); + } +}; + +void f(opt_storage o) { + o.f(); +} diff --git a/test/CodeGenCXX/constructor-template.cpp b/test/CodeGenCXX/constructor-template.cpp index 66ec9eac212c..1142aac30e24 100644 --- a/test/CodeGenCXX/constructor-template.cpp +++ b/test/CodeGenCXX/constructor-template.cpp @@ -44,12 +44,10 @@ int main() { delete node; } -// CHECK-LP64: __ZN4ListIP12BinomialNodeIiEED1Ev: -// CHECK-LP64: __ZN4ListIP12BinomialNodeIiEED2Ev: // CHECK-LP64: __ZN4NodeIP12BinomialNodeIiEEC1Ev: // CHECK-LP64: __ZN4ListIP12BinomialNodeIiEEC1Ev: +// CHECK-LP64: __ZN4ListIP12BinomialNodeIiEED1Ev: -// CHECK-LP32: __ZN4ListIP12BinomialNodeIiEED1Ev: -// CHECK-LP32: __ZN4ListIP12BinomialNodeIiEED2Ev: // CHECK-LP32: __ZN4NodeIP12BinomialNodeIiEEC1Ev: // CHECK-LP32: __ZN4ListIP12BinomialNodeIiEEC1Ev: +// CHECK-LP32: __ZN4ListIP12BinomialNodeIiEED1Ev: diff --git a/test/CodeGenCXX/conversion-operator-base.cpp b/test/CodeGenCXX/conversion-operator-base.cpp new file mode 100644 index 000000000000..49796d08a87f --- /dev/null +++ b/test/CodeGenCXX/conversion-operator-base.cpp @@ -0,0 +1,7 @@ +// RUN: clang-cc -emit-llvm-only %s -verify +// PR5730 + +struct A { operator int(); float y; }; +struct B : A { double z; }; +void a() { switch(B()) {} } + diff --git a/test/CodeGenCXX/copy-assign-synthesis-3.cpp b/test/CodeGenCXX/copy-assign-synthesis-3.cpp new file mode 100644 index 000000000000..3dab0f2a81b3 --- /dev/null +++ b/test/CodeGenCXX/copy-assign-synthesis-3.cpp @@ -0,0 +1,16 @@ +// RUN: clang-cc -emit-llvm-only -verify %s + +struct A { + A& operator=(const A&); +}; + +struct B { + A a; + float b; + int (A::*c)(); + _Complex float d; +}; +void a(B& x, B& y) { + x = y; +} + diff --git a/test/CodeGenCXX/copy-constructor-synthesis-2.cpp b/test/CodeGenCXX/copy-constructor-synthesis-2.cpp new file mode 100644 index 000000000000..b4add46db85a --- /dev/null +++ b/test/CodeGenCXX/copy-constructor-synthesis-2.cpp @@ -0,0 +1,7 @@ +// RUN: clang-cc -emit-llvm -o - %s | FileCheck %s + +struct A { virtual void a(); }; +A x(A& y) { return y; } + +// CHECK: define linkonce_odr void @_ZN1AC1ERKS_( +// CHECK: store i8** getelementptr inbounds ([3 x i8*]* @_ZTV1A, i64 0, i64 2) diff --git a/test/CodeGenCXX/debug-info.cpp b/test/CodeGenCXX/debug-info.cpp index b89435a99044..c5e3c79b0aab 100644 --- a/test/CodeGenCXX/debug-info.cpp +++ b/test/CodeGenCXX/debug-info.cpp @@ -11,3 +11,10 @@ template struct A { A *next; }; void f(A) { } + +struct B { }; + +void f() { + int B::*a = 0; + void (B::*b)() = 0; +} diff --git a/test/CodeGenCXX/default-constructor-template-member.cpp b/test/CodeGenCXX/default-constructor-template-member.cpp new file mode 100644 index 000000000000..e0a17e0e4f71 --- /dev/null +++ b/test/CodeGenCXX/default-constructor-template-member.cpp @@ -0,0 +1,10 @@ +// RUN: clang-cc -emit-llvm %s -o - | FileCheck %s + +template struct A { A(); }; +struct B { A x; }; +void a() { + B b; +} +// CHECK: call void @_ZN1BC1Ev +// CHECK: define linkonce_odr void @_ZN1BC1Ev +// CHECK: call void @_ZN1AIiEC1Ev diff --git a/test/CodeGenCXX/eh.cpp b/test/CodeGenCXX/eh.cpp index 3dd7219d9afd..5570fb44c24c 100644 --- a/test/CodeGenCXX/eh.cpp +++ b/test/CodeGenCXX/eh.cpp @@ -11,7 +11,9 @@ void test1() { // CHECK: define void @_Z5test1v() nounwind { // CHECK-NEXT:entry: +// CHECK-NEXT: %exception.ptr = alloca i8* // CHECK-NEXT: %exception = call i8* @__cxa_allocate_exception(i64 8) +// CHECK-NEXT: store i8* %exception, i8** %exception.ptr // CHECK-NEXT: %0 = bitcast i8* %exception to %struct.test1_D* // CHECK-NEXT: %tmp = bitcast %struct.test1_D* %0 to i8* // CHECK-NEXT: call void @llvm.memcpy.i64(i8* %tmp, i8* bitcast (%struct.test1_D* @d1 to i8*), i64 8, i32 8) @@ -32,10 +34,13 @@ void test2() { // CHECK: define void @_Z5test2v() nounwind { // CHECK-NEXT:entry: +// CHECK-NEXT: %exception.ptr = alloca i8* // CHECK-NEXT: %exception = call i8* @__cxa_allocate_exception(i64 16) +// CHECK-NEXT: store i8* %exception, i8** %exception.ptr // CHECK-NEXT: %0 = bitcast i8* %exception to %struct.test2_D* -// CHECK-NEXT: call void @_ZN7test2_DC1ERKS_(%struct.test2_D* %0, %struct.test2_D* @d2) -// CHECK-NEXT: call void @__cxa_throw(i8* %exception, i8* bitcast (%0* @_ZTI7test2_D to i8*), i8* null) noreturn +// CHECK: invoke void @_ZN7test2_DC1ERKS_(%struct.test2_D* %0, %struct.test2_D* @d2) +// CHECK-NEXT: to label %invoke.cont unwind label %terminate.handler +// CHECK: call void @__cxa_throw(i8* %exception, i8* bitcast (%0* @_ZTI7test2_D to i8*), i8* null) noreturn // CHECK-NEXT: unreachable @@ -51,7 +56,9 @@ void test3() { // CHECK: define void @_Z5test3v() nounwind { // CHECK-NEXT: entry: +// CHECK-NEXT: %exception.ptr = alloca i8* // CHECK-NEXT: %exception = call i8* @__cxa_allocate_exception(i64 8) +// CHECK-NEXT: store i8* %exception, i8** %exception.ptr // CHECK-NEXT: %0 = bitcast i8* %exception to %struct.test3_D** // CHECK-NEXT: store %struct.test3_D* null, %struct.test3_D** %0 // CHECK-NEXT: call void @__cxa_throw(i8* %exception, i8* bitcast (%1* @_ZTIPV7test3_D to i8*), i8* null) noreturn diff --git a/test/CodeGenCXX/elide-call-reference.cpp b/test/CodeGenCXX/elide-call-reference.cpp new file mode 100644 index 000000000000..863e69c9cc02 --- /dev/null +++ b/test/CodeGenCXX/elide-call-reference.cpp @@ -0,0 +1,11 @@ +// RUN: clang-cc %s -emit-llvm -o - | FileCheck %s +// PR5695 + +struct A { A(const A&); ~A(); }; +A& a(); +void b() { + A x = a(); +} + +// CHECK: call void @_ZN1AC1ERKS_ +// CHECK: call void @_ZN1AD1Ev diff --git a/test/CodeGenCXX/enum.cpp b/test/CodeGenCXX/enum.cpp new file mode 100644 index 000000000000..6ce04a3a532b --- /dev/null +++ b/test/CodeGenCXX/enum.cpp @@ -0,0 +1,4 @@ +// RUN: clang-cc -emit-llvm-only -verify %s + +enum A { a } __attribute((packed)); +int func(A x) { return x==a; } diff --git a/test/CodeGenCXX/eval-recursive-constant.cpp b/test/CodeGenCXX/eval-recursive-constant.cpp new file mode 100644 index 000000000000..b60070fa1f4e --- /dev/null +++ b/test/CodeGenCXX/eval-recursive-constant.cpp @@ -0,0 +1,5 @@ +// RUN: clang-cc %s -emit-llvm-only + +extern const int a,b; +const int a=b,b=a; +int c() { if (a) return 1; return 0; } diff --git a/test/CodeGenCXX/exceptions.cpp b/test/CodeGenCXX/exceptions.cpp new file mode 100644 index 000000000000..396ff441ef9a --- /dev/null +++ b/test/CodeGenCXX/exceptions.cpp @@ -0,0 +1,18 @@ +// RUN: clang-cc %s -triple=x86_64-apple-darwin10 -emit-llvm -o - -fexceptions + +struct allocator { + allocator(); + allocator(const allocator&); + ~allocator(); +}; + +void f(); +void g(bool b, bool c) { + if (b) { + if (!c) + throw allocator(); + + return; + } + f(); +} diff --git a/test/CodeGenCXX/function-template-explicit-specialization.cpp b/test/CodeGenCXX/function-template-explicit-specialization.cpp new file mode 100644 index 000000000000..046bc325a5d9 --- /dev/null +++ b/test/CodeGenCXX/function-template-explicit-specialization.cpp @@ -0,0 +1,13 @@ +// RUN: clang-cc -emit-llvm %s -o - | FileCheck %s + +template void a(T); +template<> void a(int) {} + +// CHECK: define void @_Z1aIiEvT_ + +namespace X { +template void b(T); +template<> void b(int) {} +} + +// CHECK: define void @_ZN1X1bIiEEvT_ diff --git a/test/CodeGenCXX/global-llvm-constant.cpp b/test/CodeGenCXX/global-llvm-constant.cpp new file mode 100644 index 000000000000..bd4319667e8f --- /dev/null +++ b/test/CodeGenCXX/global-llvm-constant.cpp @@ -0,0 +1,10 @@ +// RUN: clang-cc -emit-llvm -o - %s | FileCheck %s + +struct A { + A() { x = 10; } + int x; +}; + +const A x; + +// CHECK: @x = internal global diff --git a/test/CodeGenCXX/inline-functions.cpp b/test/CodeGenCXX/inline-functions.cpp new file mode 100644 index 000000000000..9af4c6e5bec7 --- /dev/null +++ b/test/CodeGenCXX/inline-functions.cpp @@ -0,0 +1,23 @@ +// RUN: clang-cc %s -triple=x86_64-apple-darwin10 -emit-llvm -o - | FileCheck %s +// CHECK: ; ModuleID + +struct A { + inline void f(); +}; + +// CHECK-NOT: define void @_ZN1A1fEv +void A::f() { } + +template struct B { }; + +template<> struct B { + inline void f(); +}; + +// CHECK-NOT: _ZN1BIcE1fEv +void B::f() { } + +// We need a final CHECK line here. + +// CHECK: define void @_Z1fv +void f() { } diff --git a/test/CodeGenCXX/key-function-vtable.cpp b/test/CodeGenCXX/key-function-vtable.cpp new file mode 100644 index 000000000000..e61f33a4cfc3 --- /dev/null +++ b/test/CodeGenCXX/key-function-vtable.cpp @@ -0,0 +1,42 @@ +// RUN: clang-cc %s -emit-llvm -o - | FileCheck %s + +// Simple key function test +struct testa { virtual void a(); }; +void testa::a() {} + +// Simple key function test +struct testb { virtual void a() {} }; +testb *testbvar = new testb; + +// Key function with out-of-line inline definition +struct testc { virtual void a(); }; +inline void testc::a() {} + +// Key functions with inline specifier (PR5705) +struct testd { inline virtual void a(); }; +void testd::a() {} + +// Key functions with inline specifier (PR5705) +struct teste { inline virtual void a(); }; +teste *testevar = new teste; + +// Key functions with namespace (PR5711) +namespace { + struct testf { virtual void a(); }; +} +void testf::a() {} + +// Key functions with namespace (PR5711) +namespace { + struct testg { virtual void a(); }; +} +testg *testgvar = new testg; + +// FIXME: The checks are extremely difficult to get right when the globals +// aren't alphabetized +// CHECK: @_ZTV5testa = constant [3 x i8*] [i8* null +// CHECK: @_ZTV5testc = weak_odr constant [3 x i8*] [i8* null +// CHECK: @_ZTVN12_GLOBAL__N_15testgE = internal constant [3 x i8*] [i8* null +// CHECK: @_ZTV5teste = weak_odr constant [3 x i8*] [i8* null +// CHECK: @_ZTV5testb = weak_odr constant [3 x i8*] [i8* null + diff --git a/test/CodeGenCXX/mangle-extern-local.cpp b/test/CodeGenCXX/mangle-extern-local.cpp new file mode 100644 index 000000000000..7c25859a9a6c --- /dev/null +++ b/test/CodeGenCXX/mangle-extern-local.cpp @@ -0,0 +1,45 @@ +// RUN: clang-cc %s -emit-llvm -o - | FileCheck %s + +// CHECK: @var1 = external global i32 +// CHECK: @_ZN1N4var2E = external global i32 +// CHECK: @var5 = external global i32 +// CHECK: @_ZN1N4var3E = external global i32 +// CHECK: @_ZN1N4var4E = external global i32 + +// CHECK: declare i32 @_Z5func1v() +// CHECK: declare i32 @_ZN1N5func2Ev() +// CHECK: declare i32 @func4() +// CHECK: declare i32 @_ZN1N5func3Ev() + +int f1() { + extern int var1, func1(); + return var1 + func1(); +} + +namespace N { + +int f2() { + extern int var2, func2(); + return var2 + func2(); +} + +struct S { + static int f3() { + extern int var3, func3(); + struct LC { int localfunc() { extern int var4; return var4; } }; + LC localobj; + return var3 + func3() + localobj.localfunc(); + } +}; + +int anchorf3() { return S::f3(); } + +extern "C" { +int f4() { + extern int var5, func4(); + return var5 + func4(); +} +} + +} + diff --git a/test/CodeGenCXX/mangle-subst-std.cpp b/test/CodeGenCXX/mangle-subst-std.cpp index fbce20451264..a2994c4abf23 100644 --- a/test/CodeGenCXX/mangle-subst-std.cpp +++ b/test/CodeGenCXX/mangle-subst-std.cpp @@ -32,8 +32,26 @@ namespace std { void f(std::string) { } namespace std { + template struct basic_istream { }; template struct basic_ostream { }; + template struct basic_iostream { }; } +// CHECK: _Z1fSi +void f(std::basic_istream >) { } + // CHECK: _Z1fSo void f(std::basic_ostream >) { } + +// CHECK: _Z1fSd +void f(std::basic_iostream >) { } + +extern "C++" { +namespace std +{ + typedef void (*terminate_handler) (); + + // CHECK: _ZSt13set_terminatePFvvE + terminate_handler set_terminate(terminate_handler) { return 0; } +} +} diff --git a/test/CodeGenCXX/mangle-unnamed.cpp b/test/CodeGenCXX/mangle-unnamed.cpp new file mode 100644 index 000000000000..66c81e593225 --- /dev/null +++ b/test/CodeGenCXX/mangle-unnamed.cpp @@ -0,0 +1,39 @@ +// RUN: clang-cc -emit-llvm-only -verify %s + +struct S { + virtual ~S() { } +}; + +// PR5706 +// Make sure this doesn't crash; the mangling doesn't matter because the name +// doesn't have linkage. +static struct : S { } obj8; + +void f() { + // Make sure this doesn't crash; the mangling doesn't matter because the + // generated vtable/etc. aren't modifiable (although it would be nice for + // codesize to make it consistent inside inline functions). + static struct : S { } obj8; +} + +inline int f2() { + // FIXME: We don't mangle the names of a or x correctly! + static struct { int a() { static int x; return ++x; } } obj; + return obj.a(); +} + +int f3() { return f2(); } + +struct A { + typedef struct { int x; } *ptr; + ptr m; + int a() { + static struct x { + // FIXME: We don't mangle the names of a or x correctly! + int a(ptr A::*memp) { static int x; return ++x; } + } a; + return a.a(&A::m); + } +}; + +int f4() { return A().a(); } diff --git a/test/CodeGenCXX/mangle.cpp b/test/CodeGenCXX/mangle.cpp index 03e405ecba1d..62d8c6cc1e48 100644 --- a/test/CodeGenCXX/mangle.cpp +++ b/test/CodeGenCXX/mangle.cpp @@ -208,8 +208,9 @@ void extern_f(void); void extern_f(void) { } struct S7 { - struct S { S(); }; + S7(); + struct S { S(); }; struct { S s; } a; @@ -227,3 +228,31 @@ template typename __enable_if<(__is_scalar::__value), void>::__ty template void ft8(); // CHECK: @_Z3ft8IPvEN11__enable_ifIXsr11__is_scalarIT_E7__valueEvE6__typeEv template void ft8(); + +namespace Expressions { +// Unary operators. + +// CHECK: define void @_ZN11Expressions2f1ILi1EEEvPAplngT_Li2E_i +template void f1(int (*)[(-i) + 2]) { }; +template void f1<1>(int (*)[1]); + +// CHECK: define void @_ZN11Expressions2f2ILi1EEEvPApsT__i +template void f2(int (*)[+i]) { }; +template void f2<1>(int (*)[1]); + +// Binary operators. + +// CHECK: define void @_ZN11Expressions2f3ILi1EEEvPAplT_T__i +template void f3(int (*)[i+i]) { }; +template void f3<1>(int (*)[2]); + +// CHECK: define void @_ZN11Expressions2f4ILi1EEEvPAplplLi2ET_T__i +template void f4(int (*)[2 + i+i]) { }; +template void f4<1>(int (*)[4]); + +// The ternary operator. +// CHECK: define void @_ZN11Expressions2f4ILb1EEEvPAquT_Li1ELi2E_i +template void f4(int (*)[b ? 1 : 2]) { }; +template void f4(int (*)[1]); + +} diff --git a/test/CodeGenCXX/member-call-parens.cpp b/test/CodeGenCXX/member-call-parens.cpp new file mode 100644 index 000000000000..0b808e044459 --- /dev/null +++ b/test/CodeGenCXX/member-call-parens.cpp @@ -0,0 +1,12 @@ +// RUN: clang-cc -emit-llvm-only -verify %s + +struct A { int a(); }; +typedef int B; +void a() { + A x; + ((x.a))(); + ((x.*&A::a))(); + B y; + // FIXME: Sema doesn't like this for some reason... + //(y.~B)(); +} diff --git a/test/CodeGenCXX/member-function-pointers.cpp b/test/CodeGenCXX/member-function-pointers.cpp index 05bf39632517..491ca5345afa 100644 --- a/test/CodeGenCXX/member-function-pointers.cpp +++ b/test/CodeGenCXX/member-function-pointers.cpp @@ -105,3 +105,26 @@ namespace PR5593 { return f && f; } } + +namespace PR5718 { + struct A { }; + + bool f(void (A::*f)(), void (A::*g)()) { + return f == g; + } +} + +namespace BoolMemberPointer { + struct A { }; + + bool f(void (A::*f)()) { + return !f; + } + + bool g(void (A::*f)()) { + if (!!f) + return true; + return false; + } +} + diff --git a/test/CodeGenCXX/member-pointer-type-convert.cpp b/test/CodeGenCXX/member-pointer-type-convert.cpp new file mode 100644 index 000000000000..290daf2b4f12 --- /dev/null +++ b/test/CodeGenCXX/member-pointer-type-convert.cpp @@ -0,0 +1,10 @@ +// RUN: clang-cc -emit-llvm %s -o - | FileCheck %s + +struct A; +typedef int A::*param_t; +struct { + const char *name; + param_t par; +} *ptr; + +// CHECK: type { i8*, {{i..}} } diff --git a/test/CodeGenCXX/predefined-expr.cpp b/test/CodeGenCXX/predefined-expr.cpp index 95bc255bdde0..45b4e9f5402f 100644 --- a/test/CodeGenCXX/predefined-expr.cpp +++ b/test/CodeGenCXX/predefined-expr.cpp @@ -12,12 +12,12 @@ // CHECK: private constant [38 x i8] c"void NS::Base::functionTemplate1(int)\00" // CHECK: private constant [12 x i8] c"~Destructor\00" -// CHECK: private constant [35 x i8] c"void NS::Destructor::~Destructor()\00" +// CHECK: private constant [30 x i8] c"NS::Destructor::~Destructor()\00" // CHECK: private constant [12 x i8] c"Constructor\00" -// CHECK: private constant [46 x i8] c"void NS::Constructor::Constructor(NS::Base *)\00" -// CHECK: private constant [39 x i8] c"void NS::Constructor::Constructor(int)\00" -// CHECK: private constant [36 x i8] c"void NS::Constructor::Constructor()\00" +// CHECK: private constant [41 x i8] c"NS::Constructor::Constructor(NS::Base *)\00" +// CHECK: private constant [34 x i8] c"NS::Constructor::Constructor(int)\00" +// CHECK: private constant [31 x i8] c"NS::Constructor::Constructor()\00" // CHECK: private constant [16 x i8] c"virtualFunction\00" // CHECK: private constant [44 x i8] c"virtual void NS::Derived::virtualFunction()\00" diff --git a/test/CodeGenCXX/reference-init.cpp b/test/CodeGenCXX/reference-init.cpp new file mode 100644 index 000000000000..9baad94a96e7 --- /dev/null +++ b/test/CodeGenCXX/reference-init.cpp @@ -0,0 +1,9 @@ +// RUN: clang-cc -emit-llvm-only -verify %s + +struct XPTParamDescriptor {}; +struct nsXPTParamInfo { + nsXPTParamInfo(const XPTParamDescriptor& desc); +}; +void a(XPTParamDescriptor *params) { + const nsXPTParamInfo& paramInfo = params[0]; +} diff --git a/test/CodeGenCXX/references.cpp b/test/CodeGenCXX/references.cpp index eaaf346d7ccd..74dc0ea6d7b0 100644 --- a/test/CodeGenCXX/references.cpp +++ b/test/CodeGenCXX/references.cpp @@ -1,5 +1,4 @@ // RUN: clang-cc -verify -emit-llvm -o - %s | FileCheck %s - void t1() { extern int& a; int b = a; @@ -19,7 +18,6 @@ void t3() { // Test reference binding. struct C { int a; }; - void f(const bool&); void f(const int&); void f(const _Complex int&); diff --git a/test/CodeGenCXX/rtti-linkage.cpp b/test/CodeGenCXX/rtti-linkage.cpp new file mode 100644 index 000000000000..a2a1cdd48c10 --- /dev/null +++ b/test/CodeGenCXX/rtti-linkage.cpp @@ -0,0 +1,16 @@ +// RUN: clang-cc %s -triple=x86_64-apple-darwin10 -emit-llvm -o - | FileCheck %s + +// CHECK: _ZTS1B = constant +// CHECK: _ZTS1A = weak_odr constant +// CHECK: _ZTI1A = weak_odr constant +// CHECK: _ZTI1B = constant + +// A has no key function, so its RTTI data should be weak_odr. +struct A { }; + +// B has a key function defined in the translation unit, so the RTTI data should +// be emitted in this translation unit and have external linkage. +struct B : A { + virtual void f(); +}; +void B::f() { } diff --git a/test/CodeGenCXX/rtti.cpp b/test/CodeGenCXX/rtti.cpp index a1ff1ff68729..7ba4d56b6633 100644 --- a/test/CodeGenCXX/rtti.cpp +++ b/test/CodeGenCXX/rtti.cpp @@ -3,6 +3,7 @@ // RUN: clang-cc -I%S -triple x86_64-apple-darwin -std=c++0x -emit-llvm %s -o %t.ll // RUN: FileCheck -check-prefix LL --input-file=%t.ll %s +// XFAIL: * #include @@ -31,6 +32,11 @@ class test1_D : public test1_B7 { virtual void foo() { } } d1; +// CHECK:__ZTI7test1_D: +// CHECK-NEXT: .quad (__ZTVN10__cxxabiv120__si_class_type_infoE) + 16 +// CHECK-NEXT: .quad __ZTS7test1_D +// CHECK-NEXT: .quad __ZTI8test1_B7 + // CHECK: __ZTSPVi: // CHECK-NEXT: .asciz "PVi" @@ -77,13 +83,6 @@ class test1_D : public test1_B7 { // CHECK-NEXT: .quad __ZTIFvvE // CHECK-NEXT: .quad __ZTI7test3_A - - -// CHECK:__ZTI7test1_D: -// CHECK-NEXT: .quad (__ZTVN10__cxxabiv120__si_class_type_infoE) + 16 -// CHECK-NEXT: .quad __ZTS7test1_D -// CHECK-NEXT: .quad __ZTI8test1_B7 - // CHECK:__ZTI8test1_B7: // CHECK-NEXT: .quad (__ZTVN10__cxxabiv121__vmi_class_type_infoE) + 16 // CHECK-NEXT: .quad __ZTS8test1_B7 @@ -141,7 +140,6 @@ class test1_D : public test1_B7 { // CHECK-NEXT: .quad __ZTS8test1_B2 // CHECK-NEXT: .quad __ZTI8test1_B1 - class NP { }; void test2_1(); void test2_2(test1_D *dp) { @@ -166,7 +164,7 @@ void test2_2(test1_D *dp) { // CHECK-LL-NEXT: %2 = load %"class.std::type_info"** %1 // CHECK-LL-NEXT: %call = call zeroext i1 @_ZNKSt9type_infoeqERKS_(%"class.std::type_info"* %2, %"class.std::type_info"* bitcast (%{{[0-9]*}}* @_ZTI7test1_D to %"class.std::type_info"*)) -// CHECK-LL: %call2 = call zeroext i1 @_ZNKSt9type_infoeqERKS_(%"class.std::type_info"* bitcast (%0* @_ZTI2NP to %"class.std::type_info"*), %"class.std::type_info"* bitcast (%{{[0-9]*}}* @_ZTI7test1_D to %"class.std::type_info"*)) +// CHECK-LL: %call2 = call zeroext i1 @_ZNKSt9type_infoeqERKS_(%"class.std::type_info"* bitcast (%{{[0-9]*}}* @_ZTI2NP to %"class.std::type_info"*), %"class.std::type_info"* bitcast (%{{[0-9]*}}* @_ZTI7test1_D to %"class.std::type_info"*)) // CHECK-LL: %3 = bitcast %class.test1_B7* %tmp5 to %"class.std::type_info"*** // CHECK-LL-NEXT: %4 = icmp ne %"class.std::type_info"*** %3, null diff --git a/test/CodeGenCXX/static-assert.cpp b/test/CodeGenCXX/static-assert.cpp index 7757acd83887..e103b9906257 100644 --- a/test/CodeGenCXX/static-assert.cpp +++ b/test/CodeGenCXX/static-assert.cpp @@ -1,3 +1,7 @@ -// RUN: clang-cc %s -emit-llvm -o - -std=c++0x +// RUN: clang-cc %s -emit-llvm -o - -std=c++0x -verify static_assert(true, ""); + +void f() { + static_assert(true, ""); +} diff --git a/test/CodeGenCXX/static-init.cpp b/test/CodeGenCXX/static-init.cpp index 55877b2a71a9..91085440ae78 100644 --- a/test/CodeGenCXX/static-init.cpp +++ b/test/CodeGenCXX/static-init.cpp @@ -1,13 +1,17 @@ -// RUN: clang-cc -triple=x86_64-apple-darwin9 -emit-llvm %s -o %t -// RUN: grep "call void @_ZN1AC1Ev" %t | count 1 -// RUN: grep "call i32 @__cxa_atexit(void (i8\*)\* bitcast (void (%.truct.A\*)\* @_ZN1AD1Ev to void (i8\*)\*), i8\* getelementptr inbounds (%.truct.A\* @_ZZ1fvE1a, i32 0, i32 0), i8\* bitcast (i8\*\* @__dso_handle to i8\*))" %t | count 1 - +// RUN: clang-cc %s -triple=x86_64-apple-darwin10 -emit-llvm -o - | FileCheck %s struct A { A(); ~A(); }; void f() { + // CHECK: call void @_ZN1AC1Ev( + // CHECK: call i32 @__cxa_atexit(void (i8*)* bitcast (void (%struct.A*)* @_ZN1AD1Ev to void (i8*)*), i8* getelementptr inbounds (%struct.A* @_ZZ1fvE1a, i32 0, i32 0), i8* bitcast (i8** @__dso_handle to i8*)) static A a; } +void g() { + // CHECK: call i8* @_Znwm(i64 1) + // CHECK: call void @_ZN1AC1Ev( + static A& a = *new A; +} diff --git a/test/CodeGenCXX/static-member-variable-explicit-specialization.cpp b/test/CodeGenCXX/static-member-variable-explicit-specialization.cpp new file mode 100644 index 000000000000..d439cbd50049 --- /dev/null +++ b/test/CodeGenCXX/static-member-variable-explicit-specialization.cpp @@ -0,0 +1,11 @@ +// RUN: clang-cc %s -triple=x86_64-apple-darwin10 -emit-llvm -o - | FileCheck %s +// CHECK: ; ModuleID +template struct A { static int a; }; + +// CHECK-NOT: @_ZN1AIcE1aE +template<> int A::a; + +// CHECK: @_ZN1AIbE1aE = global i32 10 +template<> int A::a = 10; + + diff --git a/test/CodeGenCXX/template-linkage.cpp b/test/CodeGenCXX/template-linkage.cpp new file mode 100644 index 000000000000..8013ba44c533 --- /dev/null +++ b/test/CodeGenCXX/template-linkage.cpp @@ -0,0 +1,24 @@ +// RUN: clang-cc %s -triple=x86_64-apple-darwin10 -emit-llvm -o - | FileCheck %s +template struct A { + virtual void f(T) { } + inline void g() { } +}; + +// Explicit instantiations have external linkage. + +// CHECK: define void @_ZN1AIiE1gEv( +template void A::g(); + +// CHECK: define void @_ZN1AIfE1fEf( +// CHECK: define void @_ZN1AIfE1gEv( +// FIXME: This should also emit the vtable. +template struct A; + +// CHECK: define void @_Z1fIiEvT_ +template void f(T) { } +template void f(int); + +// CHECK: define void @_Z1gIiEvT_ +template inline void g(T) { } +template void g(int); + diff --git a/test/CodeGenCXX/throw-expressions.cpp b/test/CodeGenCXX/throw-expressions.cpp new file mode 100644 index 000000000000..7fe556312bab --- /dev/null +++ b/test/CodeGenCXX/throw-expressions.cpp @@ -0,0 +1,10 @@ +// RUN: clang-cc -emit-llvm-only -verify %s + +int val = 42; +int& test1() { + return throw val, val; +} + +int test2() { + return val ? throw val : val; +} diff --git a/test/CodeGenCXX/unary-type-trait.cpp b/test/CodeGenCXX/unary-type-trait.cpp new file mode 100644 index 000000000000..b65b9f9d4f2f --- /dev/null +++ b/test/CodeGenCXX/unary-type-trait.cpp @@ -0,0 +1,3 @@ +// RUN: clang-cc -emit-llvm-only -verify %s + +bool a() { return __is_pod(int); } diff --git a/test/CodeGenCXX/virt-call-offsets.cpp b/test/CodeGenCXX/virt-call-offsets.cpp new file mode 100644 index 000000000000..db0ba2f483b8 --- /dev/null +++ b/test/CodeGenCXX/virt-call-offsets.cpp @@ -0,0 +1,8 @@ +// RUN: clang -cc1 %s -emit-llvm -o - | FileCheck %s + +struct A { virtual void a(); }; +struct B : A {}; +struct C : B { virtual void a(); }; +void (C::*x)() = &C::a; + +// CHECK: @x = global %0 { i{{[0-9]+}} 1, i{{[0-9]+}} 0 } diff --git a/test/CodeGenCXX/virt-canonical-decl.cpp b/test/CodeGenCXX/virt-canonical-decl.cpp new file mode 100644 index 000000000000..c1a8c236af8d --- /dev/null +++ b/test/CodeGenCXX/virt-canonical-decl.cpp @@ -0,0 +1,19 @@ +// RUN: clang-cc %s -emit-llvm-only + +class Base { +public: + virtual ~Base(); +}; + +Base::~Base() +{ +} + +class Foo : public Base { +public: + virtual ~Foo(); +}; + +Foo::~Foo() +{ +} diff --git a/test/CodeGenCXX/virt-dtor-key.cpp b/test/CodeGenCXX/virt-dtor-key.cpp index 30f3563d8a2f..9cfd58dae2d3 100644 --- a/test/CodeGenCXX/virt-dtor-key.cpp +++ b/test/CodeGenCXX/virt-dtor-key.cpp @@ -1,5 +1,5 @@ // RUN: clang-cc -emit-llvm %s -o - | FileCheck %s -// CHECK: @_ZTI3foo = linkonce_odr constant +// CHECK: @_ZTI3foo = constant class foo { foo(); virtual ~foo(); diff --git a/test/CodeGenCXX/virt-template-vtable.cpp b/test/CodeGenCXX/virt-template-vtable.cpp new file mode 100644 index 000000000000..3fbdd2d9cde0 --- /dev/null +++ b/test/CodeGenCXX/virt-template-vtable.cpp @@ -0,0 +1,12 @@ +// RUN: clang-cc %s -emit-llvm -o - | FileCheck %s + +template class A { + A() {} + virtual void a() {} +}; +class B : A { + B(); +}; +B::B() {} + +// CHECK: @_ZTV1AIiE = weak_odr constant diff --git a/test/CodeGenCXX/virt-thunk-reference.cpp b/test/CodeGenCXX/virt-thunk-reference.cpp new file mode 100644 index 000000000000..4b361cfc3d2c --- /dev/null +++ b/test/CodeGenCXX/virt-thunk-reference.cpp @@ -0,0 +1,7 @@ +// RUN: clang-cc -emit-llvm-only %s + +struct A { int a; virtual void aa(int&); }; +struct B { int b; virtual void bb(int&); }; +struct C : A,B { virtual void aa(int&), bb(int&); }; +void C::aa(int&) {} +void C::bb(int&) {} diff --git a/test/CodeGenCXX/virt.cpp b/test/CodeGenCXX/virt.cpp index 7135aaf81ec7..e3b2afe2f770 100644 --- a/test/CodeGenCXX/virt.cpp +++ b/test/CodeGenCXX/virt.cpp @@ -768,7 +768,7 @@ struct test16_D : test16_NV1, virtual test16_B2 { // 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:define weak %class.test8_D* @_ZTcvn16_n72_v16_n32_N8test16_D4foo1Ev(%class.test8_D*) // CHECK-LPLL64:entry: // CHECK-LPLL64: %retval = alloca %class.test8_D* // CHECK-LPLL64: %.addr = alloca %class.test8_D* @@ -790,7 +790,7 @@ struct test16_D : test16_NV1, virtual test16_B2 { // CHECK-LPLL64: ret %class.test8_D* %10 // CHECK-LPLL64:} -// CHECK-LPLL64:define weak %class.test8_D* @_ZTch0_v16_n32_N8test16_D4foo1Ev(%class.test8_D*) { +// CHECK-LPLL64:define weak %class.test8_D* @_ZTch0_v16_n32_N8test16_D4foo1Ev(%class.test8_D*) // CHECK-LPLL64:entry: // CHECK-LPLL64: %retval = alloca %class.test8_D* // CHECK-LPLL64: %.addr = alloca %class.test8_D* diff --git a/test/CodeGenCXX/virtual-destructor-calls.cpp b/test/CodeGenCXX/virtual-destructor-calls.cpp new file mode 100644 index 000000000000..976f56278ee0 --- /dev/null +++ b/test/CodeGenCXX/virtual-destructor-calls.cpp @@ -0,0 +1,24 @@ +// RUN: clang-cc -emit-llvm %s -o - -triple=x86_64-apple-darwin10 | FileCheck %s + +struct A { + virtual ~A(); +}; + +struct B : A { + virtual ~B(); +}; + +// Deleting dtor. +// CHECK: define void @_ZN1BD0Ev +// CHECK: call void @_ZN1AD2Ev +// check: call void @_ZdlPv + +// Complete dtor. +// CHECK: define void @_ZN1BD1Ev +// CHECK: call void @_ZN1AD2Ev + +// Base dtor. +// CHECK: define void @_ZN1BD2Ev +// CHECK: call void @_ZN1AD2Ev + +B::~B() { } diff --git a/test/CodeGenCXX/virtual-destructor-synthesis.cpp b/test/CodeGenCXX/virtual-destructor-synthesis.cpp new file mode 100644 index 000000000000..b95218a322f6 --- /dev/null +++ b/test/CodeGenCXX/virtual-destructor-synthesis.cpp @@ -0,0 +1,16 @@ +// RUN: clang-cc %s -emit-llvm -o - | FileCheck %s + +struct box { + virtual ~box(); +}; + +struct pile_box : public box { + pile_box(box *); +}; + +pile_box::pile_box(box *pp) +{ +} + +// CHECK: call void @_ZdlPv + diff --git a/test/CodeGenCXX/virtual-implicit-copy-assignment.cpp b/test/CodeGenCXX/virtual-implicit-copy-assignment.cpp new file mode 100644 index 000000000000..d179e9b78607 --- /dev/null +++ b/test/CodeGenCXX/virtual-implicit-copy-assignment.cpp @@ -0,0 +1,11 @@ +// RUN: clang-cc -emit-llvm -o - %s | FileCheck %s + +struct D; +struct B { + virtual D& operator = (const D&); +}; +struct D : B { D(); virtual void a(); }; +void D::a() {} + +// CHECK: @_ZTV1D = {{.*}} @_ZN1DaSERKS_ +// CHECK: define linkonce_odr {{.*}} @_ZN1DaSERKS_ diff --git a/test/CodeGenCXX/virtual-inherited-destructor.cpp b/test/CodeGenCXX/virtual-inherited-destructor.cpp new file mode 100644 index 000000000000..52b62edd2944 --- /dev/null +++ b/test/CodeGenCXX/virtual-inherited-destructor.cpp @@ -0,0 +1,8 @@ +// RUN: clang-cc %s -emit-llvm-only + +struct A { virtual ~A(); }; +struct B : A { + ~B() { } +}; +B x; + diff --git a/test/CodeGenCXX/vtable-key-function.cpp b/test/CodeGenCXX/vtable-key-function.cpp new file mode 100644 index 000000000000..b0371c0e0ba7 --- /dev/null +++ b/test/CodeGenCXX/vtable-key-function.cpp @@ -0,0 +1,15 @@ +// RUN: clang-cc %s -triple=x86_64-apple-darwin10 -emit-llvm -o - | FileCheck %s +// PR5697 +namespace PR5697 { +struct A { + virtual void f() { } + A(); + A(int); +}; + +// A does not have a key function, so the first constructor we emit should +// cause the vtable to be defined (without assertions.) +// CHECK: @_ZTVN6PR56971AE = weak_odr constant +A::A() { } +A::A(int) { } +} diff --git a/test/CodeGenCXX/vtable-linkage.cpp b/test/CodeGenCXX/vtable-linkage.cpp new file mode 100644 index 000000000000..f2d914feed9e --- /dev/null +++ b/test/CodeGenCXX/vtable-linkage.cpp @@ -0,0 +1,58 @@ +// RUN: clang-cc %s -triple=x86_64-apple-darwin10 -emit-llvm -o - | FileCheck %s + +namespace { + struct A { + virtual void f() { } + }; +} + +void f() { A b; } + +struct B { + B(); + virtual void f(); +}; + +B::B() { } + +struct C { + C(); + virtual void f() { } +}; + +C::C() { } + +struct D { + virtual void f(); +}; + +void D::f() { } + +static struct : D { } e; + +// B has a key function that is not defined in this translation unit so its vtable +// has external linkage. +// CHECK: @_ZTV1B = external constant + +// C has no key function, so its vtable should have weak_odr linkage. +// CHECK: @_ZTS1C = weak_odr constant +// CHECK: @_ZTI1C = weak_odr constant +// CHECK: @_ZTV1C = weak_odr constant + +// D has a key function that is defined in this translation unit so its vtable is +// defined in the translation unit. +// CHECK: @_ZTS1D = constant +// CHECK: @_ZTI1D = constant +// CHECK: @_ZTV1D = constant + +// The anonymous struct for e has no linkage, so the vtable should have +// internal linkage. +// CHECK: @"_ZTS3$_0" = internal constant +// CHECK: @"_ZTI3$_0" = internal constant +// CHECK: @"_ZTV3$_0" = internal constant + +// The A vtable should have internal linkage since it is inside an anonymous +// namespace. +// CHECK: @_ZTSN12_GLOBAL__N_11AE = internal constant +// CHECK: @_ZTIN12_GLOBAL__N_11AE = internal constant +// CHECK: @_ZTVN12_GLOBAL__N_11AE = internal constant diff --git a/test/CodeGenObjC/2008-10-23-invalid-icmp.m b/test/CodeGenObjC/2008-10-23-invalid-icmp.m index 2c58b9217675..65fbf9bc092c 100644 --- a/test/CodeGenObjC/2008-10-23-invalid-icmp.m +++ b/test/CodeGenObjC/2008-10-23-invalid-icmp.m @@ -1,4 +1,4 @@ -// RUN: clang-cc -emit-llvm -o %t %s +// RUN: clang -cc1 -emit-llvm -o %t %s @protocol P @end diff --git a/test/CodeGenObjC/PR4541.m b/test/CodeGenObjC/PR4541.m index 9a651162c1e1..2d2adeb3d88e 100644 --- a/test/CodeGenObjC/PR4541.m +++ b/test/CodeGenObjC/PR4541.m @@ -1,4 +1,4 @@ -// RUN: clang-cc -o %t -w -g %s +// RUN: clang -cc1 -o %t -w -g %s @class NSString; diff --git a/test/CodeGenObjC/PR4894-recursive-debug-crash.m b/test/CodeGenObjC/PR4894-recursive-debug-crash.m index d7379111c11a..91ae9b3c870f 100644 --- a/test/CodeGenObjC/PR4894-recursive-debug-crash.m +++ b/test/CodeGenObjC/PR4894-recursive-debug-crash.m @@ -1,4 +1,4 @@ -// RUN: clang-cc -triple i386-apple-darwin9 -g -emit-llvm %s -o - | FileCheck %s +// RUN: clang -cc1 -triple i386-apple-darwin9 -g -emit-llvm %s -o - | FileCheck %s // PR4894 // // This test is actually just making sure we can generate the debug info for the diff --git a/test/CodeGenObjC/bitfield-1.m b/test/CodeGenObjC/bitfield-1.m index 3f605ebc4e24..107361f9975d 100644 --- a/test/CodeGenObjC/bitfield-1.m +++ b/test/CodeGenObjC/bitfield-1.m @@ -1,6 +1,6 @@ -// RUN: clang-cc -triple x86_64-apple-darwin9 -emit-llvm -o %t %s -// RUN: clang-cc -triple i386-apple-darwin9 -emit-llvm -o %t %s -// RUN: clang-cc -triple i386-pc-linux-gnu -emit-llvm -o %t %s +// RUN: clang -cc1 -triple x86_64-apple-darwin9 -emit-llvm -o %t %s +// RUN: clang -cc1 -triple i386-apple-darwin9 -emit-llvm -o %t %s +// RUN: clang -cc1 -triple i386-pc-linux-gnu -emit-llvm -o %t %s @interface Object - (id) alloc; diff --git a/test/CodeGenObjC/bitfield-ivar-metadata.m b/test/CodeGenObjC/bitfield-ivar-metadata.m index f720bcc5b5b6..52fd3098bacf 100644 --- a/test/CodeGenObjC/bitfield-ivar-metadata.m +++ b/test/CodeGenObjC/bitfield-ivar-metadata.m @@ -1,4 +1,4 @@ -// RUN: clang-cc -emit-llvm -o %t %s +// RUN: clang -cc1 -emit-llvm -o %t %s @interface INTF { diff --git a/test/CodeGenObjC/bitfield-ivar-offsets.m b/test/CodeGenObjC/bitfield-ivar-offsets.m index f4bc39d4fb05..2a8c31cde757 100644 --- a/test/CodeGenObjC/bitfield-ivar-offsets.m +++ b/test/CodeGenObjC/bitfield-ivar-offsets.m @@ -1,5 +1,5 @@ // RUNX: llvm-gcc -m64 -emit-llvm -S -o %t %s && -// RUN: clang-cc -triple x86_64-apple-darwin10 -fobjc-nonfragile-abi -emit-llvm -o %t %s +// RUN: clang -cc1 -triple x86_64-apple-darwin10 -fobjc-nonfragile-abi -emit-llvm -o %t %s // RUN: grep -F '@"OBJC_IVAR_$_I0._b0" = global i64 0, section "__DATA, __objc_const", align 8' %t // RUN: grep -F '@"OBJC_IVAR_$_I0._b1" = global i64 0, section "__DATA, __objc_const", align 8' %t // RUN: grep -F '@"OBJC_IVAR_$_I0._b2" = global i64 1, section "__DATA, __objc_const", align 8' %t diff --git a/test/CodeGenObjC/blocks-1.m b/test/CodeGenObjC/blocks-1.m index ee1b97801b42..c1b001b66306 100644 --- a/test/CodeGenObjC/blocks-1.m +++ b/test/CodeGenObjC/blocks-1.m @@ -1,4 +1,4 @@ -// RUN: clang-cc %s -emit-llvm -o %t -fobjc-gc -fblocks -triple i386-apple-darwin10 +// RUN: clang -cc1 %s -emit-llvm -o %t -fobjc-gc -fblocks -triple i386-apple-darwin10 // RUN: grep "_Block_object_dispose" %t | count 6 // RUN: grep "__copy_helper_block_" %t | count 4 // RUN: grep "__destroy_helper_block_" %t | count 4 diff --git a/test/CodeGenObjC/blocks-2.m b/test/CodeGenObjC/blocks-2.m index bb7af99416f3..4949b45cddee 100644 --- a/test/CodeGenObjC/blocks-2.m +++ b/test/CodeGenObjC/blocks-2.m @@ -1,4 +1,4 @@ -// RUN: clang-cc %s -emit-llvm -o %t -fobjc-gc -fblocks -triple i386-apple-darwin10 +// RUN: clang -cc1 %s -emit-llvm -o %t -fobjc-gc -fblocks -triple i386-apple-darwin10 // RUN: grep "objc_assign_strongCast" %t | count 2 // This should generate a strong cast. diff --git a/test/CodeGenObjC/blocks-3.m b/test/CodeGenObjC/blocks-3.m index 16da55ed6322..279f21a52822 100644 --- a/test/CodeGenObjC/blocks-3.m +++ b/test/CodeGenObjC/blocks-3.m @@ -1,4 +1,4 @@ -// RUN: clang-cc -triple x86_64-apple-darwin9 -emit-llvm -fblocks -o %t %s +// RUN: clang -cc1 -triple x86_64-apple-darwin9 -emit-llvm -fblocks -o %t %s // RUN: grep 'object_assign' %t | count 11 // RUN: grep 'object_dispose' %t | count 29 diff --git a/test/CodeGenObjC/blocks.m b/test/CodeGenObjC/blocks.m index def4c9dd7a70..536d158046b0 100644 --- a/test/CodeGenObjC/blocks.m +++ b/test/CodeGenObjC/blocks.m @@ -1,4 +1,4 @@ -// RUN: clang-cc -triple i386-apple-darwin9 -emit-llvm -fblocks -o %t %s +// RUN: clang -cc1 -triple i386-apple-darwin9 -emit-llvm -fblocks -o %t %s // rdar://6676764 struct S { diff --git a/test/CodeGenObjC/category-super-class-meth.m b/test/CodeGenObjC/category-super-class-meth.m index ce27e87bbf50..595d2af29857 100644 --- a/test/CodeGenObjC/category-super-class-meth.m +++ b/test/CodeGenObjC/category-super-class-meth.m @@ -1,4 +1,4 @@ -// RUN: clang-cc -emit-llvm -o %t %s +// RUN: clang -cc1 -emit-llvm -o %t %s @interface BASE + (int) BaseMeth; diff --git a/test/CodeGenObjC/class-getter-dotsyntax.m b/test/CodeGenObjC/class-getter-dotsyntax.m index 1e1a7596795e..599e6e7154aa 100644 --- a/test/CodeGenObjC/class-getter-dotsyntax.m +++ b/test/CodeGenObjC/class-getter-dotsyntax.m @@ -1,4 +1,4 @@ -// RUN: clang-cc -emit-llvm -o %t %s +// RUN: clang -cc1 -emit-llvm -o %t %s @interface Test { } + (Test *)crash; diff --git a/test/CodeGenObjC/class-type.m b/test/CodeGenObjC/class-type.m index d63f8420d280..45d7a8671ba7 100644 --- a/test/CodeGenObjC/class-type.m +++ b/test/CodeGenObjC/class-type.m @@ -1,6 +1,6 @@ -// RUN: clang-cc -triple x86_64-unknown-unknown -emit-llvm -o - %s -// RUN: clang-cc -triple i386-apple-darwin9 -emit-llvm -o - %s -// RUN: clang-cc -triple x86_64-apple-darwin9 -emit-llvm -o - %s +// RUN: clang -cc1 -triple x86_64-unknown-unknown -emit-llvm -o - %s +// RUN: clang -cc1 -triple i386-apple-darwin9 -emit-llvm -o - %s +// RUN: clang -cc1 -triple x86_64-apple-darwin9 -emit-llvm -o - %s @interface I0 { diff --git a/test/CodeGenObjC/compatibility-alias.m b/test/CodeGenObjC/compatibility-alias.m index 11e5a27ab713..aca274515940 100644 --- a/test/CodeGenObjC/compatibility-alias.m +++ b/test/CodeGenObjC/compatibility-alias.m @@ -1,4 +1,4 @@ -// RUN: clang-cc -emit-llvm -o %t %s +// RUN: clang -cc1 -emit-llvm -o %t %s @interface Int1 @end diff --git a/test/CodeGenObjC/constant-strings.m b/test/CodeGenObjC/constant-strings.m index 8204adc51886..08d30ba20f84 100644 --- a/test/CodeGenObjC/constant-strings.m +++ b/test/CodeGenObjC/constant-strings.m @@ -1,6 +1,6 @@ -// RUN: clang-cc -emit-llvm -o %t %s -// RUN: clang-cc -fgnu-runtime -emit-llvm -o %t %s && grep NXConstantString %t | count 1 -// RUN: clang-cc -fgnu-runtime -fconstant-string-class NSConstantString -emit-llvm -o %t %s && grep NSConstantString %t | count 1 +// RUN: clang -cc1 -emit-llvm -o %t %s +// RUN: clang -cc1 -fgnu-runtime -emit-llvm -o %t %s && grep NXConstantString %t | count 1 +// RUN: clang -cc1 -fgnu-runtime -fconstant-string-class NSConstantString -emit-llvm -o %t %s && grep NSConstantString %t | count 1 id a = @"Hello World!"; diff --git a/test/CodeGenObjC/continuation-class.m b/test/CodeGenObjC/continuation-class.m index c22231063afa..9ee61028322e 100644 --- a/test/CodeGenObjC/continuation-class.m +++ b/test/CodeGenObjC/continuation-class.m @@ -1,4 +1,4 @@ -// RUN: clang-cc -emit-llvm -o %t %s +// RUN: clang -cc1 -emit-llvm -o %t %s @interface Object - (id)new; diff --git a/test/CodeGenObjC/deadcode_strip_used_var.m b/test/CodeGenObjC/deadcode_strip_used_var.m index d2548fdec85b..679d6da66101 100644 --- a/test/CodeGenObjC/deadcode_strip_used_var.m +++ b/test/CodeGenObjC/deadcode_strip_used_var.m @@ -1,6 +1,6 @@ -// RUN: clang-cc %s -emit-llvm -o %t -triple i386-apple-darwin10 +// RUN: clang -cc1 %s -emit-llvm -o %t -triple i386-apple-darwin10 // RUN: grep "llvm.used" %t | count 1 -// RUN: clang-cc %s -emit-llvm -o %t -triple x86_64-apple-darwin10 +// RUN: clang -cc1 %s -emit-llvm -o %t -triple x86_64-apple-darwin10 // RUN: grep "llvm.used" %t | count 1 diff --git a/test/CodeGenObjC/debug-info-linkagename.m b/test/CodeGenObjC/debug-info-linkagename.m index bda98eec49b5..bace9db1b824 100644 --- a/test/CodeGenObjC/debug-info-linkagename.m +++ b/test/CodeGenObjC/debug-info-linkagename.m @@ -1,4 +1,4 @@ -// RUN: clang-cc -g -S -o %t %s +// RUN: clang -cc1 -g -S -o %t %s // RUN: not grep 001 %t @interface F diff --git a/test/CodeGenObjC/dot-syntax-1.m b/test/CodeGenObjC/dot-syntax-1.m index 18b972f04850..96d4cdf4b500 100644 --- a/test/CodeGenObjC/dot-syntax-1.m +++ b/test/CodeGenObjC/dot-syntax-1.m @@ -1,4 +1,4 @@ -// RUN: clang-cc -emit-llvm -o %t %s +// RUN: clang -cc1 -emit-llvm -o %t %s int printf(const char *, ...); diff --git a/test/CodeGenObjC/dot-syntax.m b/test/CodeGenObjC/dot-syntax.m index 01b71898a7a7..5a40fd8726d2 100644 --- a/test/CodeGenObjC/dot-syntax.m +++ b/test/CodeGenObjC/dot-syntax.m @@ -1,4 +1,4 @@ -// RUN: clang-cc -emit-llvm -o %t %s +// RUN: clang -cc1 -emit-llvm -o %t %s int printf(const char *, ...); diff --git a/test/CodeGenObjC/encode-test-1.m b/test/CodeGenObjC/encode-test-1.m index 8e6fd861f9cc..dd4867cfb79e 100644 --- a/test/CodeGenObjC/encode-test-1.m +++ b/test/CodeGenObjC/encode-test-1.m @@ -1,4 +1,4 @@ -// RUN: clang-cc -triple=i686-apple-darwin9 -emit-llvm -o %t %s +// RUN: clang -cc1 -triple=i686-apple-darwin9 -emit-llvm -o %t %s // RUN: grep -e "{Base=b2b3b4b5}" %t | count 1 // RUN: grep -e "{Derived=b2b3b4b5b5b4b3}" %t | count 1 diff --git a/test/CodeGenObjC/encode-test-2.m b/test/CodeGenObjC/encode-test-2.m index b53ea6677ebd..6c20c424058b 100644 --- a/test/CodeGenObjC/encode-test-2.m +++ b/test/CodeGenObjC/encode-test-2.m @@ -1,4 +1,4 @@ -// RUN: clang-cc -triple=i686-apple-darwin9 -emit-llvm -o %t %s +// RUN: clang -cc1 -triple=i686-apple-darwin9 -emit-llvm -o %t %s // RUN: grep -e "@\\\22\\\22" %t // RUN: grep -e "@\\\22\\\22" %t // RUN: grep -e "@\\\22\\\22" %t diff --git a/test/CodeGenObjC/encode-test-3.m b/test/CodeGenObjC/encode-test-3.m index 79a024fe1f7b..3706ab6a2683 100644 --- a/test/CodeGenObjC/encode-test-3.m +++ b/test/CodeGenObjC/encode-test-3.m @@ -1,4 +1,4 @@ -// RUN: clang-cc -triple=i686-apple-darwin9 -emit-llvm -o %t %s +// RUN: clang -cc1 -triple=i686-apple-darwin9 -emit-llvm -o %t %s // RUN: grep -e "\^i" %t | count 1 // RUN: grep -e "\[0i\]" %t | count 1 diff --git a/test/CodeGenObjC/encode-test-4.m b/test/CodeGenObjC/encode-test-4.m index 90b300200a06..149205cdecaa 100644 --- a/test/CodeGenObjC/encode-test-4.m +++ b/test/CodeGenObjC/encode-test-4.m @@ -1,4 +1,4 @@ -// RUN: clang-cc -emit-llvm -o - %s -O2 | grep "ret i32 1" +// RUN: clang -cc1 -emit-llvm -o - %s -O2 | grep "ret i32 1" int a() { return @encode(int) == @encode(int); diff --git a/test/CodeGenObjC/encode-test-5.m b/test/CodeGenObjC/encode-test-5.m index d5ec9b3909c7..a12d90058964 100644 --- a/test/CodeGenObjC/encode-test-5.m +++ b/test/CodeGenObjC/encode-test-5.m @@ -1,4 +1,4 @@ -// RUN: clang-cc -triple=x86_64-apple-darwin9 -emit-llvm -o %t %s +// RUN: clang -cc1 -triple=x86_64-apple-darwin9 -emit-llvm -o %t %s // RUN: grep ji.00 %t | count 1 char *a = @encode(_Complex int); diff --git a/test/CodeGenObjC/encode-test.m b/test/CodeGenObjC/encode-test.m index db8470b6bb2a..060161d1a998 100644 --- a/test/CodeGenObjC/encode-test.m +++ b/test/CodeGenObjC/encode-test.m @@ -1,4 +1,4 @@ -// RUN: clang-cc -triple=i686-apple-darwin9 -emit-llvm -o %t %s +// RUN: clang -cc1 -triple=i686-apple-darwin9 -emit-llvm -o %t %s // RUN: grep -e "\^{Innermost=CC}" %t | count 1 // RUN: grep -e "{Derived=#ib32b8b3b8sb16b8b8b2b8ccb6}" %t | count 1 // RUN: grep -e "{B1=#@c}" %t | count 1 diff --git a/test/CodeGenObjC/for-in.m b/test/CodeGenObjC/for-in.m index 434ff796b335..fab0ee47b501 100644 --- a/test/CodeGenObjC/for-in.m +++ b/test/CodeGenObjC/for-in.m @@ -1,4 +1,4 @@ -// RUN: clang-cc -emit-llvm %s -o %t +// RUN: clang -cc1 -emit-llvm %s -o %t void p(const char*, ...); diff --git a/test/CodeGenObjC/forward-class-impl-metadata.m b/test/CodeGenObjC/forward-class-impl-metadata.m index 5dfddde89486..fae745b1ff84 100644 --- a/test/CodeGenObjC/forward-class-impl-metadata.m +++ b/test/CodeGenObjC/forward-class-impl-metadata.m @@ -1,4 +1,4 @@ -// RUN: clang-cc -fobjc-nonfragile-abi -emit-llvm -o %t %s +// RUN: clang -cc1 -fobjc-nonfragile-abi -emit-llvm -o %t %s @interface BASE { @private diff --git a/test/CodeGenObjC/hidden-visibility.m b/test/CodeGenObjC/hidden-visibility.m index 8596b41a79a7..e265e6f754e8 100644 --- a/test/CodeGenObjC/hidden-visibility.m +++ b/test/CodeGenObjC/hidden-visibility.m @@ -1,4 +1,4 @@ -// RUN: clang-cc -fvisibility hidden -fobjc-nonfragile-abi -emit-llvm -o - %s | FileCheck %s +// RUN: clang -cc1 -fvisibility hidden -fobjc-nonfragile-abi -emit-llvm -o - %s | FileCheck %s // CHECK: @"OBJC_IVAR_$_I.P" = hidden // CHECK: @"OBJC_CLASS_$_I" = hidden // CHECK: @"OBJC_METACLASS_$_I" = hidden diff --git a/test/CodeGenObjC/hidden.m b/test/CodeGenObjC/hidden.m index 0c0dbb3aa50e..502aaebb6964 100644 --- a/test/CodeGenObjC/hidden.m +++ b/test/CodeGenObjC/hidden.m @@ -1,4 +1,4 @@ -// RUN: clang-cc -emit-llvm -o %t %s +// RUN: clang -cc1 -emit-llvm -o %t %s __attribute__((visibility("hidden"))) @interface Hidden diff --git a/test/CodeGenObjC/id-isa-codegen.m b/test/CodeGenObjC/id-isa-codegen.m new file mode 100644 index 000000000000..73b21b0c652d --- /dev/null +++ b/test/CodeGenObjC/id-isa-codegen.m @@ -0,0 +1,27 @@ +// RUN: clang -cc1 -emit-llvm -o %t %s + +typedef struct objc_class *Class; + +typedef struct objc_object { + Class isa; +} *id; + +@interface I ++ (Class) class; +- (void)meth : (id)object : (id)src_object; ++ (unsigned char) isSubclassOfClass:(Class)aClass ; +@end + +@implementation I ++ (Class) class {return 0;} ++ (unsigned char) isSubclassOfClass:(Class)aClass {return 0;} +- (void)meth : (id)object : (id)src_object { + [object->isa isSubclassOfClass:[I class]]; + + [(*object).isa isSubclassOfClass:[I class]]; + + object->isa = src_object->isa; + (*src_object).isa = (*object).isa; +} +@end + diff --git a/test/CodeGenObjC/image-info.m b/test/CodeGenObjC/image-info.m index c16f11d8bc01..8167ef68ca2e 100644 --- a/test/CodeGenObjC/image-info.m +++ b/test/CodeGenObjC/image-info.m @@ -1,2 +1,2 @@ -// RUN: clang-cc -triple x86_64-apple-darwin-10 -emit-llvm -o %t %s +// RUN: clang -cc1 -triple x86_64-apple-darwin-10 -emit-llvm -o %t %s // RUN: grep -F '@"\01L_OBJC_IMAGE_INFO" = internal constant [2 x i32] [i32 0, i32 16], section "__OBJC, __image_info,regular"' %t diff --git a/test/CodeGenObjC/implicit-objc_msgSend.m b/test/CodeGenObjC/implicit-objc_msgSend.m index f2fba58f4b57..25d0b8f66984 100644 --- a/test/CodeGenObjC/implicit-objc_msgSend.m +++ b/test/CodeGenObjC/implicit-objc_msgSend.m @@ -1,4 +1,4 @@ -// RUN: clang-cc -triple x86_64-apple-darwin9 -emit-llvm -o %t %s +// RUN: clang -cc1 -triple x86_64-apple-darwin9 -emit-llvm -o %t %s // RUN: grep -F 'declare i8* @objc_msgSend(...)' %t typedef struct objc_selector *SEL; diff --git a/test/CodeGenObjC/implicit-property.m b/test/CodeGenObjC/implicit-property.m index 206d496252d8..9d17d8745142 100644 --- a/test/CodeGenObjC/implicit-property.m +++ b/test/CodeGenObjC/implicit-property.m @@ -1,5 +1,5 @@ -// RUN: clang-cc -emit-llvm -triple=i686-apple-darwin8 -o %t %s -// RUNX: clang-cc -emit-llvm -o %t %s +// RUN: clang -cc1 -emit-llvm -triple=i686-apple-darwin8 -o %t %s +// RUNX: clang -cc1 -emit-llvm -o %t %s @interface A -(void) setOk:(int)arg; diff --git a/test/CodeGenObjC/interface-layout-64.m b/test/CodeGenObjC/interface-layout-64.m index ac29839a7920..a8a7c6310863 100644 --- a/test/CodeGenObjC/interface-layout-64.m +++ b/test/CodeGenObjC/interface-layout-64.m @@ -1,4 +1,4 @@ -// RUN: clang-cc -triple x86_64-apple-darwin10 -fobjc-nonfragile-abi -emit-llvm -o %t %s +// RUN: clang -cc1 -triple x86_64-apple-darwin10 -fobjc-nonfragile-abi -emit-llvm -o %t %s // RUNX: llvm-gcc -m64 -emit-llvm -S -o %t %s && // RUN: grep '@"OBJC_IVAR_$_I3._iv2" = global i64 8, section "__DATA, __objc_const", align 8' %t diff --git a/test/CodeGenObjC/interface.m b/test/CodeGenObjC/interface.m index 543c5354c372..37efed096050 100644 --- a/test/CodeGenObjC/interface.m +++ b/test/CodeGenObjC/interface.m @@ -1,4 +1,4 @@ -// RUN: clang-cc -triple i386-apple-darwin9 -O3 -emit-llvm -o %t %s +// RUN: clang -cc1 -triple i386-apple-darwin9 -O3 -emit-llvm -o %t %s // RUN: grep 'ret i32 385' %t void *alloca(); diff --git a/test/CodeGenObjC/ivar-layout-64-bitfields.m b/test/CodeGenObjC/ivar-layout-64-bitfields.m index cb5611835f62..9a7d4aa8d3a6 100644 --- a/test/CodeGenObjC/ivar-layout-64-bitfields.m +++ b/test/CodeGenObjC/ivar-layout-64-bitfields.m @@ -1,4 +1,4 @@ -// RUN: clang-cc -triple x86_64-apple-darwin9 -fobjc-gc -emit-llvm -o %t %s +// RUN: clang -cc1 -triple x86_64-apple-darwin9 -fobjc-gc -emit-llvm -o %t %s @interface I { struct { diff --git a/test/CodeGenObjC/ivar-layout-64.m b/test/CodeGenObjC/ivar-layout-64.m index 190575316928..833f6dd07245 100644 --- a/test/CodeGenObjC/ivar-layout-64.m +++ b/test/CodeGenObjC/ivar-layout-64.m @@ -1,5 +1,5 @@ // RUNX: llvm-gcc -m64 -fobjc-gc -emit-llvm -S -o %t %s && -// RUN: clang-cc -triple x86_64-apple-darwin10 -fobjc-nonfragile-abi -fobjc-gc -emit-llvm -o %t %s +// RUN: clang -cc1 -triple x86_64-apple-darwin10 -fobjc-nonfragile-abi -fobjc-gc -emit-llvm -o %t %s // RUN: grep '@"\\01L_OBJC_CLASS_NAME_.*" = internal global .* c"A\\00"' %t // RUN: grep '@"\\01L_OBJC_CLASS_NAME_.*" = internal global .* c"\\11q\\10\\00"' %t // RUN: grep '@"\\01L_OBJC_CLASS_NAME_.*" = internal global .* c"!q\\00"' %t diff --git a/test/CodeGenObjC/ivar-layout-no-optimize.m b/test/CodeGenObjC/ivar-layout-no-optimize.m index 2e04d7eaecb1..54c37e0ac056 100644 --- a/test/CodeGenObjC/ivar-layout-no-optimize.m +++ b/test/CodeGenObjC/ivar-layout-no-optimize.m @@ -1,4 +1,4 @@ -// RUN: clang-cc -fobjc-gc -triple x86_64-apple-darwin -O0 -S %s -o %t-64.s +// RUN: clang -cc1 -fobjc-gc -triple x86_64-apple-darwin -O0 -S %s -o %t-64.s // RUN: FileCheck -check-prefix LP64 --input-file=%t-64.s %s @interface NSObject { diff --git a/test/CodeGenObjC/ivars.m b/test/CodeGenObjC/ivars.m index c7fcafd5353d..0f6e7ca91612 100644 --- a/test/CodeGenObjC/ivars.m +++ b/test/CodeGenObjC/ivars.m @@ -1,5 +1,5 @@ -// RUN: clang-cc -triple x86_64-apple-darwin9 -emit-llvm -o - %s -// RUN: clang-cc -triple i386-apple-darwin9 -emit-llvm -o - %s +// RUN: clang -cc1 -triple x86_64-apple-darwin9 -emit-llvm -o - %s +// RUN: clang -cc1 -triple i386-apple-darwin9 -emit-llvm -o - %s // rdar://6800926 @interface ITF { diff --git a/test/CodeGenObjC/link-errors.m b/test/CodeGenObjC/link-errors.m index 4944f1b0782a..5ab66ae45950 100644 --- a/test/CodeGenObjC/link-errors.m +++ b/test/CodeGenObjC/link-errors.m @@ -1,8 +1,8 @@ -// RUN: clang-cc -triple i386-apple-darwin9 -emit-llvm -o %t %s +// RUN: clang -cc1 -triple i386-apple-darwin9 -emit-llvm -o %t %s // RUN: grep '.lazy_reference .objc_class_name_A' %t | count 1 // RUN: grep '.lazy_reference .objc_class_name_Unknown' %t | count 1 // RUN: grep '.lazy_reference .objc_class_name_Protocol' %t | count 1 -// RUN: clang-cc -triple i386-apple-darwin9 -DWITH_IMPL -emit-llvm -o %t %s +// RUN: clang -cc1 -triple i386-apple-darwin9 -DWITH_IMPL -emit-llvm -o %t %s // RUN: grep '.lazy_reference .objc_class_name_Root' %t | count 1 @interface Root diff --git a/test/CodeGenObjC/message-arrays.m b/test/CodeGenObjC/message-arrays.m index 1ae6bf648c8a..47d010f2f502 100644 --- a/test/CodeGenObjC/message-arrays.m +++ b/test/CodeGenObjC/message-arrays.m @@ -1,4 +1,4 @@ -// RUN: clang-cc -emit-llvm -o %t %s +// RUN: clang -cc1 -emit-llvm -o %t %s void f0(id a) { // This should have an implicit cast diff --git a/test/CodeGenObjC/messages-2.m b/test/CodeGenObjC/messages-2.m index 87f7cc6cc14a..55bc23324996 100644 --- a/test/CodeGenObjC/messages-2.m +++ b/test/CodeGenObjC/messages-2.m @@ -1,4 +1,4 @@ -// RUN: clang-cc -emit-llvm -o %t %s +// RUN: clang -cc1 -emit-llvm -o %t %s int printf(const char *, ...); diff --git a/test/CodeGenObjC/messages.m b/test/CodeGenObjC/messages.m index ac3b81dead62..113486dde452 100644 --- a/test/CodeGenObjC/messages.m +++ b/test/CodeGenObjC/messages.m @@ -1,8 +1,8 @@ -// RUN: clang-cc -emit-llvm -o %t %s +// RUN: clang -cc1 -emit-llvm -o %t %s // RUN: grep "objc_msgSend" %t | count 6 -// RUN: clang-cc -fgnu-runtime -emit-llvm -o %t %s +// RUN: clang -cc1 -fgnu-runtime -emit-llvm -o %t %s // RUN: grep "objc_msg_lookup" %t | count 6 -// RUN: clang-cc -fgnu-runtime -fobjc-nonfragile-abi -emit-llvm -o %t %s +// RUN: clang -cc1 -fgnu-runtime -fobjc-nonfragile-abi -emit-llvm -o %t %s // RUN: grep "objc_msg_lookup_sender" %t | count 6 typedef struct { diff --git a/test/CodeGenObjC/metadata-symbols-32.m b/test/CodeGenObjC/metadata-symbols-32.m index 288fa8c65a80..4956cdb8e4c3 100644 --- a/test/CodeGenObjC/metadata-symbols-32.m +++ b/test/CodeGenObjC/metadata-symbols-32.m @@ -1,4 +1,4 @@ -// RUN: clang-cc -triple i386-apple-darwin9 -emit-llvm -o %t %s +// RUN: clang -cc1 -triple i386-apple-darwin9 -emit-llvm -o %t %s // RUNX: llvm-gcc -m32 -emit-llvm -S -o %t %s && // RUN: grep '@"\\01L_OBJC_CATEGORY_A_Cat" = internal global .*section "__OBJC,__category,regular,no_dead_strip", align 4' %t diff --git a/test/CodeGenObjC/metadata-symbols-64.m b/test/CodeGenObjC/metadata-symbols-64.m index 1bc8be8fbba4..7a3e341a312a 100644 --- a/test/CodeGenObjC/metadata-symbols-64.m +++ b/test/CodeGenObjC/metadata-symbols-64.m @@ -1,4 +1,4 @@ -// RUN: clang-cc -triple x86_64-apple-darwin10 -fobjc-nonfragile-abi -emit-llvm -o %t %s +// RUN: clang -cc1 -triple x86_64-apple-darwin10 -fobjc-nonfragile-abi -emit-llvm -o %t %s // RUNX: llvm-gcc -m64 -emit-llvm -S -o %t %s && // RUN: grep '@"OBJC_CLASS_$_A" = global' %t diff --git a/test/CodeGenObjC/metadata_symbols.m b/test/CodeGenObjC/metadata_symbols.m index 9cc2296dd1ba..5d4841e366be 100644 --- a/test/CodeGenObjC/metadata_symbols.m +++ b/test/CodeGenObjC/metadata_symbols.m @@ -1,4 +1,4 @@ -// RUN: clang-cc -fobjc-nonfragile-abi -emit-llvm -o %t %s +// RUN: clang -cc1 -fobjc-nonfragile-abi -emit-llvm -o %t %s // RUN: grep '@"OBJC_METACLASS_$_A" = global .*section "__DATA, __objc_data", align 8' %t // RUN: grep '@"OBJC_CLASS_$_A" = global .*section "__DATA, __objc_data", align 8' %t @@ -10,7 +10,7 @@ // RUN: grep -F 'define internal void @"\01-[A im0]"' %t // RUN: grep -F 'define internal void @"\01-[A(Cat) im1]"' %t -// RUN: clang-cc -fobjc-nonfragile-abi -fvisibility hidden -emit-llvm -o %t %s +// RUN: clang -cc1 -fobjc-nonfragile-abi -fvisibility hidden -emit-llvm -o %t %s // RUN: grep '@"OBJC_METACLASS_$_A" = hidden global .*section "__DATA, __objc_data", align 8' %t // RUN: grep '@"OBJC_CLASS_$_A" = hidden global .*section "__DATA, __objc_data", align 8' %t diff --git a/test/CodeGenObjC/missing-atend-metadata.m b/test/CodeGenObjC/missing-atend-metadata.m index 664b6f0b16b7..fd759e351029 100644 --- a/test/CodeGenObjC/missing-atend-metadata.m +++ b/test/CodeGenObjC/missing-atend-metadata.m @@ -1,4 +1,4 @@ -// RUN: clang-cc -triple i386-apple-darwin9 -emit-llvm %s -o - | FileCheck %s +// RUN: clang -cc1 -triple i386-apple-darwin9 -emit-llvm %s -o - | FileCheck %s @interface I0 @end diff --git a/test/CodeGenObjC/nested-rethrow.m b/test/CodeGenObjC/nested-rethrow.m new file mode 100644 index 000000000000..dd7439def218 --- /dev/null +++ b/test/CodeGenObjC/nested-rethrow.m @@ -0,0 +1,25 @@ +// RUN: clang -cc1 -triple i386-apple-darwin9 -emit-llvm %s -o - | FileCheck %s + + +extern int printf(const char*, ...); + +int main() +{ + @try { + @throw @"foo"; + } @catch (id e) { + @try { +// CHECK: call void @objc_exception_throw + @throw; + } @catch (id e) { + if (e) { + printf("caught \n"); + } else { + printf("caught (WRONG)\n"); + } + } @catch (...) { + printf("caught nothing (WRONG)\n"); + } + } +} + diff --git a/test/CodeGenObjC/newproperty-nested-synthesis-1.m b/test/CodeGenObjC/newproperty-nested-synthesis-1.m index 898c81add5e9..3e8e5ba56e0c 100644 --- a/test/CodeGenObjC/newproperty-nested-synthesis-1.m +++ b/test/CodeGenObjC/newproperty-nested-synthesis-1.m @@ -1,4 +1,4 @@ -// RUN: clang-cc -emit-llvm -o %t %s +// RUN: clang -cc1 -emit-llvm -o %t %s @interface Object - (id) new; diff --git a/test/CodeGenObjC/no-category-class.m b/test/CodeGenObjC/no-category-class.m index 34bf603da57d..38ea739053fa 100644 --- a/test/CodeGenObjC/no-category-class.m +++ b/test/CodeGenObjC/no-category-class.m @@ -1,4 +1,4 @@ -// RUN: clang-cc -triple x86_64-unknown-unknown -emit-llvm -o %t %s +// RUN: clang -cc1 -triple x86_64-unknown-unknown -emit-llvm -o %t %s @interface NSObject @end diff --git a/test/CodeGenObjC/non-lazy-classes.m b/test/CodeGenObjC/non-lazy-classes.m index 367705f26218..0bca6401c999 100644 --- a/test/CodeGenObjC/non-lazy-classes.m +++ b/test/CodeGenObjC/non-lazy-classes.m @@ -1,5 +1,5 @@ // RUNX: llvm-gcc -m64 -emit-llvm -S -o %t %s && -// RUN: clang-cc -fobjc-nonfragile-abi -emit-llvm -o %t %s +// RUN: clang -cc1 -fobjc-nonfragile-abi -emit-llvm -o %t %s // RUN: grep '@".01L_OBJC_LABEL_NONLAZY_CLASS_$" = internal global \[1 x .*\] .*@"OBJC_CLASS_$_A".*, section "__DATA, __objc_nlclslist, regular, no_dead_strip", align 8' %t // RUN: grep '@".01L_OBJC_LABEL_NONLAZY_CATEGORY_$" = internal global \[1 x .*\] .*@".01l_OBJC_$_CATEGORY_A_$_Cat".*, section "__DATA, __objc_nlcatlist, regular, no_dead_strip", align 8' %t diff --git a/test/CodeGenObjC/objc-align.m b/test/CodeGenObjC/objc-align.m index c029d48ea3a0..785378ae5af8 100644 --- a/test/CodeGenObjC/objc-align.m +++ b/test/CodeGenObjC/objc-align.m @@ -1,7 +1,7 @@ // 32-bit // RUNX: llvm-gcc -m32 -emit-llvm -S -o %t %s && -// RUN: clang-cc -triple i386-apple-darwin9 -emit-llvm -o %t %s +// RUN: clang -cc1 -triple i386-apple-darwin9 -emit-llvm -o %t %s // RUN: grep '@"\\01L_OBJC_CATEGORY_A_Cat" = internal global .*, section "__OBJC,__category,regular,no_dead_strip", align 4' %t // RUN: grep '@"\\01L_OBJC_CLASS_A" = internal global .*, section "__OBJC,__class,regular,no_dead_strip", align 4' %t // RUN: grep '@"\\01L_OBJC_CLASS_C" = internal global .*, section "__OBJC,__class,regular,no_dead_strip", align 4' %t @@ -14,7 +14,7 @@ // 64-bit -// RUNX: clang-cc -triple i386-apple-darwin9 -emit-llvm -o %t %s && +// RUNX: clang -cc1 -triple i386-apple-darwin9 -emit-llvm -o %t %s && // RUNX: grep '@"OBJC_CLASS_$_A" = global' %t && // RUNX: grep '@"OBJC_CLASS_$_C" = global' %t && // RUNX: grep '@"OBJC_METACLASS_$_A" = global' %t && diff --git a/test/CodeGenObjC/objc-assign-ivar.m b/test/CodeGenObjC/objc-assign-ivar.m index 795dec0d7ea1..d54b8026414f 100644 --- a/test/CodeGenObjC/objc-assign-ivar.m +++ b/test/CodeGenObjC/objc-assign-ivar.m @@ -1,4 +1,4 @@ -// RUN: clang-cc -triple x86_64-apple-darwin10 -fobjc-gc -emit-llvm -o %t %s +// RUN: clang -cc1 -triple x86_64-apple-darwin10 -fobjc-gc -emit-llvm -o %t %s // RUN: grep -F '@objc_assign_ivar' %t | count 14 typedef struct { diff --git a/test/CodeGenObjC/objc-gc-aggr-assign.m b/test/CodeGenObjC/objc-gc-aggr-assign.m index 1646cde89202..9ed6fdf0f04e 100644 --- a/test/CodeGenObjC/objc-gc-aggr-assign.m +++ b/test/CodeGenObjC/objc-gc-aggr-assign.m @@ -1,4 +1,4 @@ -// RUN: clang-cc -fobjc-gc -emit-llvm -o %t %s +// RUN: clang -cc1 -fobjc-gc -emit-llvm -o %t %s // RUN: grep objc_memmove_collectable %t | grep call | count 3 static int count; diff --git a/test/CodeGenObjC/objc-read-weak-byref.m b/test/CodeGenObjC/objc-read-weak-byref.m index 3edaf4c749ed..35854f234ef6 100644 --- a/test/CodeGenObjC/objc-read-weak-byref.m +++ b/test/CodeGenObjC/objc-read-weak-byref.m @@ -1,6 +1,6 @@ -// RUN: clang-cc -fblocks -fobjc-gc -triple x86_64-apple-darwin -S %s -o %t-64.s +// RUN: clang -cc1 -fblocks -fobjc-gc -triple x86_64-apple-darwin -S %s -o %t-64.s // RUN: FileCheck -check-prefix LP64 --input-file=%t-64.s %s -// RUN: clang-cc -fblocks -fobjc-gc -triple i386-apple-darwin -S %s -o %t-32.s +// RUN: clang -cc1 -fblocks -fobjc-gc -triple i386-apple-darwin -S %s -o %t-32.s // RUN: FileCheck -check-prefix LP32 --input-file=%t-32.s %s @interface NSObject diff --git a/test/CodeGenObjC/objc2-assign-global.m b/test/CodeGenObjC/objc2-assign-global.m index 6b34796983ff..fab4f82f39ae 100644 --- a/test/CodeGenObjC/objc2-assign-global.m +++ b/test/CodeGenObjC/objc2-assign-global.m @@ -1,4 +1,4 @@ -// RUN: clang-cc -triple x86_64-apple-darwin10 -fobjc-gc -emit-llvm -o %t %s +// RUN: clang -cc1 -triple x86_64-apple-darwin10 -fobjc-gc -emit-llvm -o %t %s // RUN: grep -F '@objc_assign_global' %t | count 26 @class NSObject; diff --git a/test/CodeGenObjC/objc2-ivar-assign.m b/test/CodeGenObjC/objc2-ivar-assign.m index 8e9a872f93f3..1d5b97316b8d 100644 --- a/test/CodeGenObjC/objc2-ivar-assign.m +++ b/test/CodeGenObjC/objc2-ivar-assign.m @@ -1,4 +1,4 @@ -// RUN: clang-cc -fobjc-nonfragile-abi -fobjc-gc -emit-llvm -o %t %s +// RUN: clang -cc1 -fobjc-nonfragile-abi -fobjc-gc -emit-llvm -o %t %s // RUN: grep objc_assign_ivar %t | count 6 @interface I @end diff --git a/test/CodeGenObjC/objc2-new-gc-api-strongcast.m b/test/CodeGenObjC/objc2-new-gc-api-strongcast.m index b6a0c03ac35b..2992cef1ed80 100644 --- a/test/CodeGenObjC/objc2-new-gc-api-strongcast.m +++ b/test/CodeGenObjC/objc2-new-gc-api-strongcast.m @@ -1,4 +1,4 @@ -// RUN: clang-cc -triple x86_64-apple-darwin10 -fblocks -fobjc-gc -emit-llvm -o %t %s +// RUN: clang -cc1 -triple x86_64-apple-darwin10 -fblocks -fobjc-gc -emit-llvm -o %t %s // RUN: grep -F '@objc_assign_strongCast' %t | count 4 @interface DSATextSearch @end diff --git a/test/CodeGenObjC/objc2-no-strong-cast.m b/test/CodeGenObjC/objc2-no-strong-cast.m index bce50cd4544c..649c3e925e31 100644 --- a/test/CodeGenObjC/objc2-no-strong-cast.m +++ b/test/CodeGenObjC/objc2-no-strong-cast.m @@ -1,4 +1,4 @@ -// RUN: clang-cc -emit-llvm -o %t %s +// RUN: clang -cc1 -emit-llvm -o %t %s @interface PDFViewPrivateVars { diff --git a/test/CodeGenObjC/objc2-no-write-barrier.m b/test/CodeGenObjC/objc2-no-write-barrier.m index b41f63fe4528..17d4e1046e46 100644 --- a/test/CodeGenObjC/objc2-no-write-barrier.m +++ b/test/CodeGenObjC/objc2-no-write-barrier.m @@ -1,4 +1,4 @@ -// RUN: clang-cc -triple x86_64-apple-darwin9 -fobjc-gc -emit-llvm -o %t %s +// RUN: clang -cc1 -triple x86_64-apple-darwin9 -fobjc-gc -emit-llvm -o %t %s // RUN: grep 'objc_assign' %t | count 0 typedef struct { diff --git a/test/CodeGenObjC/objc2-property-encode.m b/test/CodeGenObjC/objc2-property-encode.m index f1c1024cece5..c5f68d2c5b0e 100644 --- a/test/CodeGenObjC/objc2-property-encode.m +++ b/test/CodeGenObjC/objc2-property-encode.m @@ -1,4 +1,4 @@ -// RUN: clang-cc -triple=i686-apple-darwin9 -emit-llvm -o %t %s +// RUN: clang -cc1 -triple=i686-apple-darwin9 -emit-llvm -o %t %s // RUN: grep -e "T@\\\\22NSString\\\\22" %t @interface NSString @end diff --git a/test/CodeGenObjC/objc2-protocol-enc.m b/test/CodeGenObjC/objc2-protocol-enc.m index 2174792bd920..d8b86bc72ff7 100644 --- a/test/CodeGenObjC/objc2-protocol-enc.m +++ b/test/CodeGenObjC/objc2-protocol-enc.m @@ -1,4 +1,4 @@ -// RUN: clang-cc -triple=i686-apple-darwin9 -emit-llvm -o %t %s +// RUN: clang -cc1 -triple=i686-apple-darwin9 -emit-llvm -o %t %s // RUN: grep -e "T@\\\22\\\22" %t // RUN: grep -e "T@\\\22\\\22" %t // RUN: grep -e "T@\\\22\\\22" %t diff --git a/test/CodeGenObjC/objc2-retain-codegen.m b/test/CodeGenObjC/objc2-retain-codegen.m index d78bc366d398..2d49ef78d7cf 100644 --- a/test/CodeGenObjC/objc2-retain-codegen.m +++ b/test/CodeGenObjC/objc2-retain-codegen.m @@ -1,4 +1,4 @@ -// RUN: clang-cc -triple x86_64-unknown-unknown -fobjc-gc-only -emit-llvm -o %t %s +// RUN: clang -cc1 -triple x86_64-unknown-unknown -fobjc-gc-only -emit-llvm -o %t %s @interface I0 { I0 *_f0; diff --git a/test/CodeGenObjC/objc2-strong-cast-1.m b/test/CodeGenObjC/objc2-strong-cast-1.m index 8cad08c88a60..ed083c9de929 100644 --- a/test/CodeGenObjC/objc2-strong-cast-1.m +++ b/test/CodeGenObjC/objc2-strong-cast-1.m @@ -1,4 +1,4 @@ -// RUN: clang-cc -triple x86_64-unknown-unknown -fobjc-gc -emit-llvm -o %t %s +// RUN: clang -cc1 -triple x86_64-unknown-unknown -fobjc-gc -emit-llvm -o %t %s @interface I { __attribute__((objc_gc(strong))) int *i_IdocumentIDs; diff --git a/test/CodeGenObjC/objc2-strong-cast.m b/test/CodeGenObjC/objc2-strong-cast.m index 73fe16af4f73..e8cacd1d6fb0 100644 --- a/test/CodeGenObjC/objc2-strong-cast.m +++ b/test/CodeGenObjC/objc2-strong-cast.m @@ -1,4 +1,4 @@ -// RUN: clang-cc -fobjc-gc -emit-llvm -o %t %s +// RUN: clang -cc1 -fobjc-gc -emit-llvm -o %t %s @interface I { __attribute__((objc_gc(strong))) signed long *_documentIDs; diff --git a/test/CodeGenObjC/objc2-weak-assign.m b/test/CodeGenObjC/objc2-weak-assign.m index ea53b020124c..41a76f0152eb 100644 --- a/test/CodeGenObjC/objc2-weak-assign.m +++ b/test/CodeGenObjC/objc2-weak-assign.m @@ -1,4 +1,4 @@ -// RUN: clang-cc -triple x86_64-apple-darwin9 -fobjc-gc -emit-llvm -o %t %s +// RUN: clang -cc1 -triple x86_64-apple-darwin9 -fobjc-gc -emit-llvm -o %t %s // RUN: grep -e "objc_assign_weak" %t | grep -e "call" | count 6 __weak id* x; diff --git a/test/CodeGenObjC/objc2-weak-compare.m b/test/CodeGenObjC/objc2-weak-compare.m index 82cc558b567b..346485a3668b 100644 --- a/test/CodeGenObjC/objc2-weak-compare.m +++ b/test/CodeGenObjC/objc2-weak-compare.m @@ -1,4 +1,4 @@ -// RUN: clang-cc -triple i386-apple-darwin9 -fobjc-gc -emit-llvm -o %t %s +// RUN: clang -cc1 -triple i386-apple-darwin9 -fobjc-gc -emit-llvm -o %t %s @interface PBXTarget { diff --git a/test/CodeGenObjC/objc2-weak-import-attribute.m b/test/CodeGenObjC/objc2-weak-import-attribute.m index 4a5f14e2e0f7..b5bb87052e45 100644 --- a/test/CodeGenObjC/objc2-weak-import-attribute.m +++ b/test/CodeGenObjC/objc2-weak-import-attribute.m @@ -1,6 +1,8 @@ -// RUN: clang-cc -fobjc-nonfragile-abi -triple x86_64-apple-darwin10 -emit-llvm -o - %s | FileCheck -check-prefix=CHECK-X86-64 %s +// RUN: clang -cc1 -fobjc-nonfragile-abi -triple x86_64-apple-darwin10 -emit-llvm -o - %s | FileCheck -check-prefix=CHECK-X86-64 %s -__attribute__((weak_import)) @interface WeakClass +__attribute__((weak_import)) @interface WeakRootClass @end + +__attribute__((weak_import)) @interface WeakClass : WeakRootClass @end @interface MySubclass : WeakClass @end @@ -26,9 +28,21 @@ int main() { [WeakClass3 message]; } +// CHECK-X86-64: OBJC_METACLASS_$_WeakRootClass" = extern_weak global // CHECK-X86-64: OBJC_METACLASS_$_WeakClass" = extern_weak global // CHECK-X86-64: OBJC_CLASS_$_WeakClass" = extern_weak global // CHECK-X86-64: OBJC_CLASS_$_WeakClass1" = extern_weak global // CHECK-X86-64: OBJC_CLASS_$_WeakClass3" = extern_weak global +// Root is being implemented here. No extern_weak. +__attribute__((weak_import)) @interface Root @end +@interface Super : Root @end + +@interface Sub : Super @end + +@implementation Sub @end + +@implementation Root @end + +// CHECK-NOT-X86-64: OBJC_METACLASS_$_Root" = extern_weak global diff --git a/test/CodeGenObjC/objc2-weak-ivar-debug.m b/test/CodeGenObjC/objc2-weak-ivar-debug.m index 3930989f44df..dc8ced1b0c31 100644 --- a/test/CodeGenObjC/objc2-weak-ivar-debug.m +++ b/test/CodeGenObjC/objc2-weak-ivar-debug.m @@ -1,5 +1,5 @@ -// RUN: clang-cc -triple x86_64-apple-darwin9 -fobjc-gc -g -emit-llvm -o - %s -// RUN: clang-cc -triple i386-apple-darwin9 -fobjc-gc -g -emit-llvm -o - %s +// RUN: clang -cc1 -triple x86_64-apple-darwin9 -fobjc-gc -g -emit-llvm -o - %s +// RUN: clang -cc1 -triple i386-apple-darwin9 -fobjc-gc -g -emit-llvm -o - %s // rdar://7252252 @interface Loop { diff --git a/test/CodeGenObjC/objc2-weak-ivar.m b/test/CodeGenObjC/objc2-weak-ivar.m index 592c1f05474b..bcdb25c03068 100644 --- a/test/CodeGenObjC/objc2-weak-ivar.m +++ b/test/CodeGenObjC/objc2-weak-ivar.m @@ -1,4 +1,4 @@ -// RUN: clang-cc -triple x86_64-apple-darwin9 -fobjc-gc -emit-llvm -o %t %s +// RUN: clang -cc1 -triple x86_64-apple-darwin9 -fobjc-gc -emit-llvm -o %t %s @class NSObject; @interface Foo { diff --git a/test/CodeGenObjC/objc2-write-barrier-2.m b/test/CodeGenObjC/objc2-write-barrier-2.m index cdb135f0150c..35a812f9620c 100644 --- a/test/CodeGenObjC/objc2-write-barrier-2.m +++ b/test/CodeGenObjC/objc2-write-barrier-2.m @@ -1,4 +1,4 @@ -// RUN: clang-cc -triple x86_64-apple-darwin10 -fobjc-gc -emit-llvm -o %t %s +// RUN: clang -cc1 -triple x86_64-apple-darwin10 -fobjc-gc -emit-llvm -o %t %s // RUN: grep -F '@objc_assign_global' %t | count 7 // RUN: grep -F '@objc_assign_ivar' %t | count 5 // RUN: grep -F '@objc_assign_strongCast' %t | count 8 diff --git a/test/CodeGenObjC/objc2-write-barrier-3.m b/test/CodeGenObjC/objc2-write-barrier-3.m index 7058302f98a8..ecb038586cac 100644 --- a/test/CodeGenObjC/objc2-write-barrier-3.m +++ b/test/CodeGenObjC/objc2-write-barrier-3.m @@ -1,4 +1,4 @@ -// RUN: clang-cc -triple x86_64-apple-darwin10 -fobjc-nonfragile-abi -fblocks -fobjc-gc -emit-llvm -o %t %s +// RUN: clang -cc1 -triple x86_64-apple-darwin10 -fobjc-nonfragile-abi -fblocks -fobjc-gc -emit-llvm -o %t %s // RUN: grep objc_assign_ivar %t | count 3 // RUN: grep objc_assign_strongCast %t | count 6 diff --git a/test/CodeGenObjC/objc2-write-barrier-4.m b/test/CodeGenObjC/objc2-write-barrier-4.m index 4c863f4a7639..8b672cc6f0fa 100644 --- a/test/CodeGenObjC/objc2-write-barrier-4.m +++ b/test/CodeGenObjC/objc2-write-barrier-4.m @@ -1,4 +1,4 @@ -// RUN: clang-cc -triple x86_64-apple-darwin10 -fobjc-gc -emit-llvm -o %t %s +// RUN: clang -cc1 -triple x86_64-apple-darwin10 -fobjc-gc -emit-llvm -o %t %s // RUN: grep objc_assign_global %t | count 3 // RUN: grep objc_assign_strongCast %t | count 2 diff --git a/test/CodeGenObjC/objc2-write-barrier-5.m b/test/CodeGenObjC/objc2-write-barrier-5.m index 2e51b44093a3..8241af7b3026 100644 --- a/test/CodeGenObjC/objc2-write-barrier-5.m +++ b/test/CodeGenObjC/objc2-write-barrier-5.m @@ -1,4 +1,4 @@ -// RUN: clang-cc -triple x86_64-apple-darwin10 -fobjc-gc -emit-llvm -o %t %s +// RUN: clang -cc1 -triple x86_64-apple-darwin10 -fobjc-gc -emit-llvm -o %t %s // RUN: grep objc_assign_ivar %t | count 0 // RUN: grep objc_assign_strongCast %t | count 5 diff --git a/test/CodeGenObjC/objc2-write-barrier.m b/test/CodeGenObjC/objc2-write-barrier.m index bff6d8fdd012..5877064cf310 100644 --- a/test/CodeGenObjC/objc2-write-barrier.m +++ b/test/CodeGenObjC/objc2-write-barrier.m @@ -1,4 +1,4 @@ -// RUN: clang-cc -triple x86_64-apple-darwin10 -fobjc-gc -emit-llvm -o %t %s +// RUN: clang -cc1 -triple x86_64-apple-darwin10 -fobjc-gc -emit-llvm -o %t %s // RUN: grep -F '@objc_assign_global' %t | count 21 // RUN: grep -F '@objc_assign_ivar' %t | count 11 diff --git a/test/CodeGenObjC/object-incr-decr-1.m b/test/CodeGenObjC/object-incr-decr-1.m index 25b969886023..7e1870e1e346 100644 --- a/test/CodeGenObjC/object-incr-decr-1.m +++ b/test/CodeGenObjC/object-incr-decr-1.m @@ -1,4 +1,4 @@ -// RUN: clang-cc -triple i386-apple-darwin9 -emit-llvm %s -o %t +// RUN: clang -cc1 -triple i386-apple-darwin9 -emit-llvm %s -o %t @interface Foo { diff --git a/test/CodeGenObjC/overloadable.m b/test/CodeGenObjC/overloadable.m index bd3aff81b97d..abf1e27e18b8 100644 --- a/test/CodeGenObjC/overloadable.m +++ b/test/CodeGenObjC/overloadable.m @@ -1,5 +1,5 @@ // rdar://6657613 -// RUN: clang-cc -emit-llvm %s -o %t +// RUN: clang -cc1 -emit-llvm %s -o %t @class C; diff --git a/test/CodeGenObjC/predefined-expr.m b/test/CodeGenObjC/predefined-expr.m index b27bb3488a5a..f75eef320da1 100644 --- a/test/CodeGenObjC/predefined-expr.m +++ b/test/CodeGenObjC/predefined-expr.m @@ -1,4 +1,4 @@ -// RUN: clang-cc -triple i386-apple-darwin9 %s -emit-llvm -o - | FileCheck %s +// RUN: clang -cc1 -triple i386-apple-darwin9 %s -emit-llvm -o - | FileCheck %s // CHECK: @"__func__.-[Foo instanceTest1]" = private constant [21 x i8] c"-[Foo instanceTest1]\00" // CHECK: @"__func__.-[Foo instanceTest2:]" = private constant [22 x i8] c"-[Foo instanceTest2:]\00" diff --git a/test/CodeGenObjC/property-aggr-type.m b/test/CodeGenObjC/property-aggr-type.m index e2890b6ee80e..263f76dda59c 100644 --- a/test/CodeGenObjC/property-aggr-type.m +++ b/test/CodeGenObjC/property-aggr-type.m @@ -1,4 +1,4 @@ -// RUN: clang-cc -emit-llvm -o %t %s +// RUN: clang -cc1 -emit-llvm -o %t %s @interface Object - (id) new; diff --git a/test/CodeGenObjC/property-agrr-getter.m b/test/CodeGenObjC/property-agrr-getter.m index e25429ed7525..a5c95c7fba6f 100644 --- a/test/CodeGenObjC/property-agrr-getter.m +++ b/test/CodeGenObjC/property-agrr-getter.m @@ -1,4 +1,4 @@ -// RUN: clang-cc -emit-llvm -o %t %s +// RUN: clang -cc1 -emit-llvm -o %t %s typedef struct { unsigned f0; diff --git a/test/CodeGenObjC/property-complex.m b/test/CodeGenObjC/property-complex.m index aedb1fac6c2f..6d1b775408c9 100644 --- a/test/CodeGenObjC/property-complex.m +++ b/test/CodeGenObjC/property-complex.m @@ -1,5 +1,5 @@ -// RUN: clang-cc -triple i386-apple-darwin9 -emit-llvm -S -o - %s -// RUN: clang-cc -triple x86_64-apple-darwin9 -emit-llvm -S -o - %s +// RUN: clang -cc1 -triple i386-apple-darwin9 -emit-llvm -S -o - %s +// RUN: clang -cc1 -triple x86_64-apple-darwin9 -emit-llvm -S -o - %s @interface I0 { @public diff --git a/test/CodeGenObjC/property-getter-dot-syntax.m b/test/CodeGenObjC/property-getter-dot-syntax.m index 8701b580af6e..8d8ae90b3537 100644 --- a/test/CodeGenObjC/property-getter-dot-syntax.m +++ b/test/CodeGenObjC/property-getter-dot-syntax.m @@ -1,4 +1,4 @@ -// RUN: clang-cc -emit-llvm -o %t %s +// RUN: clang -cc1 -emit-llvm -o %t %s @protocol NSObject - (void *)description; diff --git a/test/CodeGenObjC/property-incr-decr-1.m b/test/CodeGenObjC/property-incr-decr-1.m index eb227dde19d5..f2660fe7a791 100644 --- a/test/CodeGenObjC/property-incr-decr-1.m +++ b/test/CodeGenObjC/property-incr-decr-1.m @@ -1,4 +1,4 @@ -// RUN: clang-cc -emit-llvm -o %t %s +// RUN: clang -cc1 -emit-llvm -o %t %s @interface Object - (id) new; diff --git a/test/CodeGenObjC/property-list-in-class.m b/test/CodeGenObjC/property-list-in-class.m new file mode 100644 index 000000000000..2d753b2bbb0d --- /dev/null +++ b/test/CodeGenObjC/property-list-in-class.m @@ -0,0 +1,32 @@ +// RUN: clang -cc1 -triple x86_64-apple-darwin10 -fobjc-nonfragile-abi -emit-llvm -o %t %s +// RUN: grep -F 'l_OBJC_$_PROP_LIST_C2" = internal global %8 { i32 16, i32 3' %t + +@protocol P +@property int i; +@end + +@protocol P1 +@property int i1; +@end + +@protocol P2 < P1> +@property int i2; +@end + +@interface C1 { id isa; } @end + +@interface C2 : C1 { + int i; +} +@property int i2; +@end + +@implementation C1 ++(void)initialize { } +@end + +@implementation C2 +@synthesize i; +@synthesize i1; +@synthesize i2; +@end diff --git a/test/CodeGenObjC/property-setter-attr.m b/test/CodeGenObjC/property-setter-attr.m index 390392415d73..43f74fb07b43 100644 --- a/test/CodeGenObjC/property-setter-attr.m +++ b/test/CodeGenObjC/property-setter-attr.m @@ -1,4 +1,4 @@ -// RUN: clang-cc -emit-llvm -triple=i686-apple-darwin8 -o %t %s +// RUN: clang -cc1 -emit-llvm -triple=i686-apple-darwin8 -o %t %s // RUN: grep -e "SiSetOtherThings:" %t @interface A diff --git a/test/CodeGenObjC/property.m b/test/CodeGenObjC/property.m index 2ab10541a7d0..d4868245156a 100644 --- a/test/CodeGenObjC/property.m +++ b/test/CodeGenObjC/property.m @@ -1,4 +1,4 @@ -// RUN: clang-cc -emit-llvm -o %t %s +// RUN: clang -cc1 -emit-llvm -o %t %s int printf(const char *, ...); diff --git a/test/CodeGenObjC/protocol-in-extended-class.m b/test/CodeGenObjC/protocol-in-extended-class.m index cad59b0fcdb9..ce1d0f3cea39 100644 --- a/test/CodeGenObjC/protocol-in-extended-class.m +++ b/test/CodeGenObjC/protocol-in-extended-class.m @@ -1,6 +1,6 @@ -// RUN: clang-cc -triple x86_64-apple-darwin10 -fobjc-nonfragile-abi -S %s -o %t-64.s +// RUN: clang -cc1 -triple x86_64-apple-darwin10 -fobjc-nonfragile-abi -S %s -o %t-64.s // RUN: FileCheck -check-prefix LP64 --input-file=%t-64.s %s -// RUN: clang-cc -triple i386-apple-darwin -S %s -o %t-32.s +// RUN: clang -cc1 -triple i386-apple-darwin -S %s -o %t-32.s // RUN: FileCheck -check-prefix LP32 --input-file=%t-32.s %s @protocol MyProtocol diff --git a/test/CodeGenObjC/protocol-property-synth.m b/test/CodeGenObjC/protocol-property-synth.m index ab230af23211..f59de81f8b37 100644 --- a/test/CodeGenObjC/protocol-property-synth.m +++ b/test/CodeGenObjC/protocol-property-synth.m @@ -1,4 +1,4 @@ -// RUN: clang-cc -fobjc-nonfragile-abi -emit-llvm -o %t %s +// RUN: clang -cc1 -fobjc-nonfragile-abi -emit-llvm -o %t %s @interface BaseClass { id _delegate; diff --git a/test/CodeGenObjC/protocols-lazy.m b/test/CodeGenObjC/protocols-lazy.m index 54ca19ceb46a..7e4c45d398e1 100644 --- a/test/CodeGenObjC/protocols-lazy.m +++ b/test/CodeGenObjC/protocols-lazy.m @@ -1,4 +1,4 @@ -// RUN: clang-cc -emit-llvm -triple=i686-apple-darwin8 -o %t %s +// RUN: clang -cc1 -emit-llvm -triple=i686-apple-darwin8 -o %t %s // RUNX: llvm-gcc -S -emit-llvm -o %t %s && // No object generated diff --git a/test/CodeGenObjC/protocols.m b/test/CodeGenObjC/protocols.m index c510685e521d..1e765df14bef 100644 --- a/test/CodeGenObjC/protocols.m +++ b/test/CodeGenObjC/protocols.m @@ -1,4 +1,4 @@ -// RUN: clang-cc -emit-llvm %s -o %t +// RUN: clang -cc1 -emit-llvm %s -o %t void p(const char*, ...); diff --git a/test/CodeGenObjC/runtime-fns.m b/test/CodeGenObjC/runtime-fns.m index 3c6894dddd17..d5832bc87842 100644 --- a/test/CodeGenObjC/runtime-fns.m +++ b/test/CodeGenObjC/runtime-fns.m @@ -1,6 +1,6 @@ -// RUN: clang-cc -emit-llvm -o %t %s +// RUN: clang -cc1 -emit-llvm -o %t %s // RUN: grep -e "^de.*objc_msgSend[0-9]*(" %t | count 1 -// RUN: clang-cc -DWITHDEF -emit-llvm -o %t %s +// RUN: clang -cc1 -DWITHDEF -emit-llvm -o %t %s // RUN: grep -e "^de.*objc_msgSend[0-9]*(" %t | count 1 id objc_msgSend(int x); diff --git a/test/CodeGenObjC/sel-as-builtin-type.m b/test/CodeGenObjC/sel-as-builtin-type.m index c65a5b280542..317c5d3ca97c 100644 --- a/test/CodeGenObjC/sel-as-builtin-type.m +++ b/test/CodeGenObjC/sel-as-builtin-type.m @@ -1,4 +1,4 @@ -// RUN: clang-cc -emit-llvm -o %t %s +// RUN: clang -cc1 -emit-llvm -o %t %s // pr5025 // radar 7405040 diff --git a/test/CodeGenObjC/super-classmethod-category.m b/test/CodeGenObjC/super-classmethod-category.m index 033bc972a348..64ba1419c0f4 100644 --- a/test/CodeGenObjC/super-classmethod-category.m +++ b/test/CodeGenObjC/super-classmethod-category.m @@ -1,4 +1,4 @@ -// RUN: clang-cc -emit-llvm -o %t %s +// RUN: clang -cc1 -emit-llvm -o %t %s @interface SUPER + (void)Meth; diff --git a/test/CodeGenObjC/super-dotsyntax-property.m b/test/CodeGenObjC/super-dotsyntax-property.m index 6e4f176724c8..0f811040d546 100644 --- a/test/CodeGenObjC/super-dotsyntax-property.m +++ b/test/CodeGenObjC/super-dotsyntax-property.m @@ -1,4 +1,4 @@ -// RUN: clang-cc -emit-llvm -o %t %s +// RUN: clang -cc1 -emit-llvm -o %t %s @interface B { diff --git a/test/CodeGenObjC/super-message-fragileabi.m b/test/CodeGenObjC/super-message-fragileabi.m index edc26a1157fd..ebb443b81aff 100644 --- a/test/CodeGenObjC/super-message-fragileabi.m +++ b/test/CodeGenObjC/super-message-fragileabi.m @@ -1,4 +1,4 @@ -// RUN: clang-cc -triple i386-apple-darwin9 -emit-llvm %s -o - | FileCheck %s +// RUN: clang -cc1 -triple i386-apple-darwin9 -emit-llvm %s -o - | FileCheck %s @class Some; diff --git a/test/CodeGenObjC/synchronized.m b/test/CodeGenObjC/synchronized.m index 8147cd1e235f..8bb19142bdcd 100644 --- a/test/CodeGenObjC/synchronized.m +++ b/test/CodeGenObjC/synchronized.m @@ -1,4 +1,4 @@ -// RUN: clang-cc -emit-llvm -triple=i686-apple-darwin9 -o %t %s -O2 +// RUN: clang -cc1 -emit-llvm -triple=i686-apple-darwin9 -o %t %s -O2 // RUN: grep 'ret i32' %t | count 1 // RUN: grep 'ret i32 1' %t | count 1 diff --git a/test/CodeGenObjC/synthesize_ivar-cont-class.m b/test/CodeGenObjC/synthesize_ivar-cont-class.m index dd444c358b7e..fb61137df49d 100644 --- a/test/CodeGenObjC/synthesize_ivar-cont-class.m +++ b/test/CodeGenObjC/synthesize_ivar-cont-class.m @@ -1,4 +1,4 @@ -// RUN: clang-cc -fobjc-nonfragile-abi -emit-llvm -o %t %s +// RUN: clang -cc1 -fobjc-nonfragile-abi -emit-llvm -o %t %s // RUN: grep '@"OBJC_IVAR_$_XCOrganizerDeviceNodeInfo.viewController"' %t @interface XCOrganizerNodeInfo diff --git a/test/CodeGenObjC/synthesize_ivar.m b/test/CodeGenObjC/synthesize_ivar.m index 9ed08d9ce559..ae21044a4ebe 100644 --- a/test/CodeGenObjC/synthesize_ivar.m +++ b/test/CodeGenObjC/synthesize_ivar.m @@ -1,4 +1,4 @@ -// RUN: clang-cc -fobjc-nonfragile-abi -emit-llvm -o %t %s +// RUN: clang -cc1 -fobjc-nonfragile-abi -emit-llvm -o %t %s @interface I @property int IP; diff --git a/test/CodeGenObjC/try.m b/test/CodeGenObjC/try.m index eebc482e4608..01106a9c2101 100644 --- a/test/CodeGenObjC/try.m +++ b/test/CodeGenObjC/try.m @@ -1,5 +1,5 @@ -// RUN: clang-cc %s -S -o - -triple=i686-apple-darwin9 -// RUN: clang-cc %s -S -o - -triple=x86_64-apple-darwin9 +// RUN: clang -cc1 %s -S -o - -triple=i686-apple-darwin9 +// RUN: clang -cc1 %s -S -o - -triple=x86_64-apple-darwin9 // rdar://6757213 - Don't crash if the internal proto for // __objc_personality_v0 mismatches with an actual one. diff --git a/test/CodeGenObjC/undefined-protocol.m b/test/CodeGenObjC/undefined-protocol.m index 7fe0790032aa..c57f53dd0b61 100644 --- a/test/CodeGenObjC/undefined-protocol.m +++ b/test/CodeGenObjC/undefined-protocol.m @@ -1,4 +1,4 @@ -// RUN: clang-cc -emit-llvm-only -fgnu-runtime %s +// RUN: clang -cc1 -emit-llvm-only -fgnu-runtime %s @protocol MadeUpProtocol; diff --git a/test/CodeGenObjC/unname-bf-metadata.m b/test/CodeGenObjC/unname-bf-metadata.m index 605d09b03322..48d37f13ce70 100644 --- a/test/CodeGenObjC/unname-bf-metadata.m +++ b/test/CodeGenObjC/unname-bf-metadata.m @@ -1,4 +1,4 @@ -// RUN: clang-cc -emit-llvm -o %t %s +// RUN: clang -cc1 -emit-llvm -o %t %s // Test that meta-data for ivar lists with unnamed bitfield are generated. // @interface Foo { diff --git a/test/CodeGenObjC/variadic-sends.m b/test/CodeGenObjC/variadic-sends.m index ab0beef71453..1979e3fc293c 100644 --- a/test/CodeGenObjC/variadic-sends.m +++ b/test/CodeGenObjC/variadic-sends.m @@ -1,5 +1,5 @@ -// RUN: clang-cc -triple i386-unknown-unknown -emit-llvm -o - %s | FileCheck -check-prefix=CHECK-X86-32 %s -// RUN: clang-cc -triple x86_64-unknown-unknown -emit-llvm -o - %s | FileCheck -check-prefix=CHECK-X86-64 %s +// RUN: clang -cc1 -triple i386-unknown-unknown -emit-llvm -o - %s | FileCheck -check-prefix=CHECK-X86-32 %s +// RUN: clang -cc1 -triple x86_64-unknown-unknown -emit-llvm -o - %s | FileCheck -check-prefix=CHECK-X86-64 %s @interface A -(void) im0; diff --git a/test/CodeGenObjCXX/mangle.mm b/test/CodeGenObjCXX/mangle.mm new file mode 100644 index 000000000000..90d2407838ad --- /dev/null +++ b/test/CodeGenObjCXX/mangle.mm @@ -0,0 +1,32 @@ +// RUN: clang -cc1 %s -triple=x86_64-apple-darwin10 -emit-llvm -o - | FileCheck %s + +// CHECK: @"_ZZ11+[A shared]E1a" = internal global +// CHECK: @"_ZZ11-[A(Foo) f]E1a" = internal global + +@interface A +@end + +@implementation A + ++ (A *)shared { + static A* a; + + return a; +} + +@end + +@interface A(Foo) +@end + +@implementation A(Foo) +- (int)f { + // FIXME: Add a member function to s and make sure that it's mangled correctly. + struct s { + }; + + static s a; + + return 0; +} +@end diff --git a/test/Coverage/ast-printing.m b/test/Coverage/ast-printing.m index 1b812288fed2..a864e2d72b88 100644 --- a/test/Coverage/ast-printing.m +++ b/test/Coverage/ast-printing.m @@ -1,5 +1,5 @@ -// RUN: clang-cc -fsyntax-only %s -// RUN: clang-cc -ast-print %s -// RUN: clang-cc -ast-dump %s +// RUN: clang -cc1 -fsyntax-only %s +// RUN: clang -cc1 -ast-print %s +// RUN: clang -cc1 -ast-dump %s #include "objc-language-features.inc" diff --git a/test/Coverage/codegen-gnu.m b/test/Coverage/codegen-gnu.m index bc8d6d642e41..194809261458 100644 --- a/test/Coverage/codegen-gnu.m +++ b/test/Coverage/codegen-gnu.m @@ -1,3 +1,3 @@ -// RUN: clang-cc -triple i386-unknown-unknown -fgnu-runtime -emit-llvm -o %t %s +// RUN: clang -cc1 -triple i386-unknown-unknown -fgnu-runtime -emit-llvm -o %t %s #include "objc-language-features.inc" diff --git a/test/Coverage/codegen-next.m b/test/Coverage/codegen-next.m index f211a5914e55..d78f93e61d2d 100644 --- a/test/Coverage/codegen-next.m +++ b/test/Coverage/codegen-next.m @@ -1,4 +1,4 @@ -// RUN: clang-cc -emit-llvm -o %t %s -// RUN: clang-cc -g -emit-llvm -o %t %s +// RUN: clang -cc1 -emit-llvm -o %t %s +// RUN: clang -cc1 -g -emit-llvm -o %t %s #include "objc-language-features.inc" diff --git a/test/Coverage/parse-callbacks.m b/test/Coverage/parse-callbacks.m index 310a1a6f6e28..7666d19432d3 100644 --- a/test/Coverage/parse-callbacks.m +++ b/test/Coverage/parse-callbacks.m @@ -1,4 +1,4 @@ -// RUN: clang-cc -parse-noop %s -// RUN: clang-cc -parse-print-callbacks %s +// RUN: clang -cc1 -parse-noop %s +// RUN: clang -cc1 -parse-print-callbacks %s #include "objc-language-features.inc" diff --git a/test/Driver/ccc-add-args.c b/test/Driver/ccc-add-args.c index 21e4471c1276..afd9bd6f7650 100644 --- a/test/Driver/ccc-add-args.c +++ b/test/Driver/ccc-add-args.c @@ -1,3 +1,5 @@ // RUN: env CCC_ADD_ARGS="-ccc-echo,-ccc-print-options,,-v" clang -### 2>&1 | FileCheck %s -// CHECK: Option 0 - Name: "-v", Values: {} -// CHECK: Option 1 - Name: "-###", Values: {} +// CHECK: Option 0 - Name: "-ccc-echo", Values: {} +// CHECK: Option 1 - Name: "-ccc-print-options", Values: {} +// CHECK: Option 2 - Name: "-v", Values: {} +// CHECK: Option 3 - Name: "-###", Values: {} diff --git a/test/Driver/clang-translation.c b/test/Driver/clang-translation.c index f7f8b5ef5f80..762ebb7944b2 100644 --- a/test/Driver/clang-translation.c +++ b/test/Driver/clang-translation.c @@ -1,4 +1,4 @@ -// RUN: clang -ccc-host-triple i386-unknown-unknown -### -S -O0 -Os %s -o %t.s -fverbose-asm -funwind-tables 2> %t.log +// RUN: clang -ccc-host-triple i386-unknown-unknown -### -S -O0 -Os %s -o %t.s -fverbose-asm -funwind-tables -fvisibility=hidden 2> %t.log // RUN: grep '"-triple" "i386-unknown-unknown"' %t.log // RUN: grep '"-S"' %t.log // RUN: grep '"-disable-free"' %t.log @@ -8,7 +8,37 @@ // RUN: grep '"-Os"' %t.log // RUN: grep '"-o" .*clang-translation.*' %t.log // RUN: grep '"-masm-verbose"' %t.log +// RUN: grep '"-fvisibility" "hidden"' %t.log // RUN: clang -ccc-host-triple i386-apple-darwin9 -### -S %s -o %t.s 2> %t.log // RUN: grep '"-mcpu" "yonah"' %t.log // RUN: clang -ccc-host-triple x86_64-apple-darwin9 -### -S %s -o %t.s 2> %t.log // RUN: grep '"-mcpu" "core2"' %t.log + +// RUN: clang -ccc-host-triple x86_64-apple-darwin10 -### -S %s 2> %t.log \ +// RUN: -arch armv7 +// RUN: FileCheck -check-prefix=ARMV7_DEFAULT %s < %t.log +// ARMV7_DEFAULT: clang +// ARMV7_DEFAULT: "-cc1" +// ARMV7_DEFAULT-NOT: "-msoft-float" +// ARMV7_DEFAULT: "-mfloat-abi" "soft" +// ARMV7_DEFAULT-NOT: "-msoft-float" +// ARMV7_DEFAULT: "-x" "c" + +// RUN: clang -ccc-host-triple x86_64-apple-darwin10 -### -S %s 2> %t.log \ +// RUN: -arch armv7 -msoft-float +// RUN: FileCheck -check-prefix=ARMV7_SOFTFLOAT %s < %t.log +// ARMV7_SOFTFLOAT: clang +// ARMV7_SOFTFLOAT: "-cc1" +// ARMV7_SOFTFLOAT: "-msoft-float" +// ARMV7_SOFTFLOAT: "-mfloat-abi" "soft" +// ARMV7_SOFTFLOAT: "-x" "c" + +// RUN: clang -ccc-host-triple x86_64-apple-darwin10 -### -S %s 2> %t.log \ +// RUN: -arch armv7 -mhard-float +// RUN: FileCheck -check-prefix=ARMV7_HARDFLOAT %s < %t.log +// ARMV7_HARDFLOAT: clang +// ARMV7_HARDFLOAT: "-cc1" +// ARMV7_HARDFLOAT-NOT: "-msoft-float" +// ARMV7_HARDFLOAT: "-mfloat-abi" "hard" +// ARMV7_HARDFLOAT-NOT: "-msoft-float" +// ARMV7_HARDFLOAT: "-x" "c" diff --git a/test/Driver/clang_f_opts.c b/test/Driver/clang_f_opts.c index 3756a2f4d163..66853422dd1d 100644 --- a/test/Driver/clang_f_opts.c +++ b/test/Driver/clang_f_opts.c @@ -1,9 +1,14 @@ -// RUN: clang -### -S -x c /dev/null -fblocks -fbuiltin -fmath-errno -fcommon -fpascal-strings -fno-blocks -fno-builtin -fno-math-errno -fno-common -fno-pascal-strings -fblocks -fbuiltin -fmath-errno -fcommon -fpascal-strings %s 2> %t -// RUN: grep -F '"-fblocks"' %t -// RUN: grep -F '"-fpascal-strings"' %t -// RUN: clang -### -S -x c /dev/null -fblocks -fbuiltin -fmath-errno -fcommon -fpascal-strings -fno-blocks -fno-builtin -fno-math-errno -fno-common -fno-pascal-strings -fno-show-source-location -fshort-wchar %s 2> %t -// RUN: grep -F '"-fno-builtin"' %t -// RUN: grep -F '"-fno-common"' %t -// RUN: grep -F '"-fno-math-errno"' %t -// RUN: grep -F '"-fno-show-source-location"' %t -// RUN: grep -F '"-fshort-wchar"' %t +// RUN: clang -### -S -fblocks -fbuiltin -fmath-errno -fcommon -fpascal-strings -fno-blocks -fno-builtin -fno-math-errno -fno-common -fno-pascal-strings -fblocks -fbuiltin -fmath-errno -fcommon -fpascal-strings %s 2>&1 | FileCheck -check-prefix=CHECK-OPTIONS1 %s +// RUN: clang -### -S -fblocks -fbuiltin -fmath-errno -fcommon -fpascal-strings -fno-blocks -fno-builtin -fno-math-errno -fno-common -fno-pascal-strings -fno-show-source-location -fshort-wchar %s 2>&1 | FileCheck -check-prefix=CHECK-OPTIONS2 %s +// RUN: clang -### -fshort-enums %s 2>&1 | FileCheck -check-prefix=CHECK-SHORT-ENUMS %s + +// CHECK-OPTIONS1: -fblocks +// CHECK-OPTIONS1: -fpascal-strings + +// CHECK-OPTIONS2: -fno-math-errno +// CHECK-OPTIONS2: -fno-builtin +// CHECK-OPTIONS2: -fshort-wchar +// CHECK-OPTIONS2: -fno-common +// CHECK-OPTIONS2: -fno-show-source-location + +// CHECK-SHORT-ENUMS: compiler does not support '-fshort-enums' diff --git a/test/Driver/cxx-pth.cpp b/test/Driver/cxx-pth.cpp index 508696ade885..e5b69c118fb3 100644 --- a/test/Driver/cxx-pth.cpp +++ b/test/Driver/cxx-pth.cpp @@ -3,10 +3,10 @@ // RUN: clang -x c++-header %s -### 2> %t.log // RUN: FileCheck -check-prefix EMIT -input-file %t.log %s -// EMIT: "{{.*}}/clang-cc{{.*}}" {{.*}} "-emit-pth" "{{.*}}.cpp.gch" "-x" "c++-header" "{{.*}}.cpp" +// EMIT: "{{.*}}/clang{{.*}}" {{.*}} "-emit-pth" "{{.*}}.cpp.gch" "-x" "c++-header" "{{.*}}.cpp" // RUN: touch %t.h.gch // RUN: clang -E -include %t.h %s -### 2> %t.log // RUN: FileCheck -check-prefix USE -input-file %t.log %s -// USE: "{{.*}}/clang-cc{{.*}}" {{.*}}"-include-pth" "{{.*}}.h.gch" {{.*}}"-x" "c++" "{{.*}}.cpp" +// USE: "{{.*}}/clang{{.*}}" {{.*}}"-include-pth" "{{.*}}.h.gch" {{.*}}"-x" "c++" "{{.*}}.cpp" diff --git a/test/Driver/dragonfly.c b/test/Driver/dragonfly.c index 40f12e4d7f86..2eb3b1808ee8 100644 --- a/test/Driver/dragonfly.c +++ b/test/Driver/dragonfly.c @@ -1,7 +1,7 @@ // RUN: clang -ccc-host-triple amd64-pc-dragonfly %s -### 2> %t.log // RUN: FileCheck -input-file %t.log %s -// CHECK: clang-cc{{.*}}" "-triple" "amd64-pc-dragonfly" +// CHECK: clang{{.*}}" "-cc1" "-triple" "amd64-pc-dragonfly" // CHECK: as{{.*}}" "-o" "{{.*}}.o" "{{.*}}.s // CHECK: ld{{.*}}" "-dynamic-linker" "{{.*}}ld-elf.{{.*}}" "-o" "a.out" "{{.*}}crt1.o" "{{.*}}crti.o" "{{.*}}crtbegin.o" "{{.*}}.o" "-L{{.*}}/gcc{{.*}}" {{.*}} "-lc" "-lgcc" "{{.*}}crtend.o" "{{.*}}crtn.o" diff --git a/test/Driver/freebsd.c b/test/Driver/freebsd.c index 8c03bbcfe3d6..9700540f46bb 100644 --- a/test/Driver/freebsd.c +++ b/test/Driver/freebsd.c @@ -2,6 +2,6 @@ // RUN: cat %t.log // RUN: FileCheck -input-file %t.log %s -// CHECK: clang-cc{{.*}}" "-triple" "powerpc64-pc-freebsd8" +// CHECK: clang{{.*}}" "-cc1" "-triple" "powerpc64-pc-freebsd8" // CHECK: as{{.*}}" "-o" "{{.*}}.o" "{{.*}}.s // CHECK: ld{{.*}}" "--eh-frame-hdr" "-dynamic-linker" "{{.*}}ld-elf{{.*}}" "-o" "a.out" "{{.*}}crt1.o" "{{.*}}crti.o" "{{.*}}crtbegin.o" "{{.*}}.o" "-lgcc" "--as-needed" "-lgcc_s" "--no-as-needed" "-lc" "-lgcc" "--as-needed" "-lgcc_s" "--no-as-needed" "{{.*}}crtend.o" "{{.*}}crtn.o" diff --git a/test/Driver/hello.c b/test/Driver/hello.c index 0df1341e4ea8..e1b6f1a0fd7a 100644 --- a/test/Driver/hello.c +++ b/test/Driver/hello.c @@ -1,7 +1,7 @@ // RUN: clang -ccc-echo -o %t %s 2> %t.log // Make sure we used clang. -// RUN: grep 'clang-cc" .*hello.c' %t.log +// RUN: grep 'clang" -cc1 .*hello.c' %t.log // RUN: %t > %t.out // RUN: grep "I'm a little driver, short and stout." %t.out diff --git a/test/Driver/openbsd.c b/test/Driver/openbsd.c index 8b0706b28fdc..97ba30bb69c2 100644 --- a/test/Driver/openbsd.c +++ b/test/Driver/openbsd.c @@ -1,6 +1,6 @@ // RUN: clang -ccc-clang-archs "" -ccc-host-triple i686-pc-openbsd %s -### 2> %t.log // RUN: FileCheck -input-file %t.log %s -// CHECK: clang-cc{{.*}}" "-triple" "i686-pc-openbsd" +// CHECK: clang{{.*}}" "-cc1" "-triple" "i686-pc-openbsd" // CHECK: as{{.*}}" "-o" "{{.*}}.o" "{{.*}}.s // CHECK: ld{{.*}}" "-e" "__start" "--eh-frame-hdr" "-Bdynamic" "-dynamic-linker" "{{.*}}ld.so" "-o" "a.out" "{{.*}}crt0.o" "{{.*}}crtbegin.o" "{{.*}}.o" "-lgcc" "-lc" "-lgcc" "{{.*}}crtend.o" diff --git a/test/Driver/parsing.c b/test/Driver/parsing.c index 8e37128e3ed9..48b9d6a23f1f 100644 --- a/test/Driver/parsing.c +++ b/test/Driver/parsing.c @@ -1,14 +1,15 @@ // RUN: clang -ccc-print-options input -Yunknown -m32 -arch ppc -djoined -A separate -Ajoined -Wp,one,two -Xarch_joined AndSeparate -sectalign 1 2 3 2> %t -// RUN: grep 'Option 0 - Name: "", Values: {"input"}' %t -// RUN: grep 'Option 1 - Name: "", Values: {"-Yunknown"}' %t -// RUN: grep 'Option 2 - Name: "-m32", Values: {}' %t -// RUN: grep 'Option 3 - Name: "-arch", Values: {"ppc"}' %t -// RUN: grep 'Option 4 - Name: "-d", Values: {"joined"}' %t -// RUN: grep 'Option 5 - Name: "-A", Values: {"separate"}' %t -// RUN: grep 'Option 6 - Name: "-A", Values: {"joined"}' %t -// RUN: grep 'Option 7 - Name: "-Wp,", Values: {"one", "two"}' %t -// RUN: grep 'Option 8 - Name: "-Xarch_", Values: {"joined", "AndSeparate"}' %t -// RUN: grep 'Option 9 - Name: "-sectalign", Values: {"1", "2", "3"}' %t +// RUN: grep 'Option 0 - Name: "-ccc-print-options", Values: {}' %t +// RUN: grep 'Option 1 - Name: "", Values: {"input"}' %t +// RUN: grep 'Option 2 - Name: "", Values: {"-Yunknown"}' %t +// RUN: grep 'Option 3 - Name: "-m32", Values: {}' %t +// RUN: grep 'Option 4 - Name: "-arch", Values: {"ppc"}' %t +// RUN: grep 'Option 5 - Name: "-d", Values: {"joined"}' %t +// RUN: grep 'Option 6 - Name: "-A", Values: {"separate"}' %t +// RUN: grep 'Option 7 - Name: "-A", Values: {"joined"}' %t +// RUN: grep 'Option 8 - Name: "-Wp,", Values: {"one", "two"}' %t +// RUN: grep 'Option 9 - Name: "-Xarch_", Values: {"joined", "AndSeparate"}' %t +// RUN: grep 'Option 10 - Name: "-sectalign", Values: {"1", "2", "3"}' %t // RUN: not clang -V 2> %t // RUN: grep "error: argument to '-V' is missing (expected 1 value)" %t @@ -17,7 +18,8 @@ // Verify that search continues after find the first option. // RUN: clang -ccc-print-options -Wally 2> %t -// RUN: grep 'Option 0 - Name: "-W", Values: {"ally"}' %t +// RUN: grep 'Option 0 - Name: "-ccc-print-options", Values: {}' %t +// RUN: grep 'Option 1 - Name: "-W", Values: {"ally"}' %t diff --git a/test/Driver/pth.c b/test/Driver/pth.c index 8e8b2dda32ba..938675a900d8 100644 --- a/test/Driver/pth.c +++ b/test/Driver/pth.c @@ -3,10 +3,10 @@ // RUN: clang -ccc-pch-is-pth -x c-header %s -o %t.h.pth -### 2> %t.log // RUN: FileCheck -check-prefix CHECK1 -input-file %t.log %s -// CHECK1: "{{.*}}/clang-cc{{.*}}" {{.*}} "-o" "{{.*}}.h.pth" "-x" "c-header" "{{.*}}pth.c" +// CHECK1: "{{.*}}/clang{{.*}}" "-cc1" {{.*}} "-o" "{{.*}}.h.pth" "-x" "c-header" "{{.*}}pth.c" // RUN: touch %t.h.pth // RUN: clang -ccc-pch-is-pth -E -include %t.h %s -### 2> %t.log // RUN: FileCheck -check-prefix CHECK2 -input-file %t.log %s -// CHECK2: "{{.*}}/clang-cc{{.*}}" {{.*}}"-include-pth" "{{.*}}.h.pth" {{.*}}"-x" "c" "{{.*}}pth.c" +// CHECK2: "{{.*}}/clang{{.*}}" "-cc1" {{.*}}"-include-pth" "{{.*}}.h.pth" {{.*}}"-x" "c" "{{.*}}pth.c" diff --git a/test/Driver/qa_override.c b/test/Driver/qa_override.c index 6f72078f12af..822410659ead 100644 --- a/test/Driver/qa_override.c +++ b/test/Driver/qa_override.c @@ -1,5 +1,6 @@ // RUN: env QA_OVERRIDE_GCC3_OPTIONS="#+-Os +-Oz +-O +-O3 +-Oignore +a +b +c xb Xa Omagic ^-ccc-print-options " clang x -O2 b -O3 2>&1 | FileCheck %s // CHECK-NOT: ### -// CHECK: Option 0 - Name: "", Values: {"x"} -// CHECK-NEXT: Option 1 - Name: "-O", Values: {"ignore"} -// CHECK-NEXT: Option 2 - Name: "-O", Values: {"magic"} +// CHECK: Option 0 - Name: "-ccc-print-options", Values: {} +// CHECK-NEXT: Option 1 - Name: "", Values: {"x"} +// CHECK-NEXT: Option 2 - Name: "-O", Values: {"ignore"} +// CHECK-NEXT: Option 3 - Name: "-O", Values: {"magic"} diff --git a/test/FixIt/fixit-objc.m b/test/FixIt/fixit-objc.m index 21aebfe3a968..cdf2057290e3 100644 --- a/test/FixIt/fixit-objc.m +++ b/test/FixIt/fixit-objc.m @@ -1,5 +1,5 @@ -// RUN: clang-cc -pedantic -fixit %s -o %t -// RUN: clang-cc -pedantic -x objective-c %t -verify +// RUN: clang -cc1 -pedantic -fixit %s -o %t +// RUN: clang -cc1 -pedantic -x objective-c %t -verify /* This is a test of the various code modification hints that are provided as part of warning or extension diagnostics. All of the diff --git a/test/Index/Inputs/remap-complete-to.c b/test/Index/Inputs/remap-complete-to.c new file mode 100644 index 000000000000..9f8be2cbec29 --- /dev/null +++ b/test/Index/Inputs/remap-complete-to.c @@ -0,0 +1 @@ +void f0() { } diff --git a/test/Index/TestClassDecl.m b/test/Index/TestClassDecl.m index 9009f78e574e..12ae4f451620 100644 --- a/test/Index/TestClassDecl.m +++ b/test/Index/TestClassDecl.m @@ -1,4 +1,4 @@ -// RUN: clang-cc -triple x86_64-apple-darwin10 -fobjc-nonfragile-abi -fblocks -emit-pch -x objective-c %s -o %t.ast +// 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-file-scan %t.ast %s | FileCheck -check-prefix=scan %s // RUN: c-index-test -test-load-tu %t.ast local | FileCheck -check-prefix=load %s diff --git a/test/Index/TestClassForwardDecl.m b/test/Index/TestClassForwardDecl.m index 31b7c6c170c0..db9a1eb5c7af 100644 --- a/test/Index/TestClassForwardDecl.m +++ b/test/Index/TestClassForwardDecl.m @@ -1,4 +1,4 @@ -// RUN: clang-cc -triple x86_64-apple-darwin10 -fobjc-nonfragile-abi -fblocks -emit-pch -x objective-c %s -o %t.ast +// 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-file-scan %t.ast %s | FileCheck -check-prefix=scan %s // RUN: c-index-test -test-load-tu %t.ast local | FileCheck -check-prefix=load %s diff --git a/test/Index/c-index-api-fn-scan.m b/test/Index/c-index-api-fn-scan.m index 3e2c9c272a20..0350d87b39e4 100644 --- a/test/Index/c-index-api-fn-scan.m +++ b/test/Index/c-index-api-fn-scan.m @@ -1,4 +1,4 @@ -// RUN: clang-cc -triple x86_64-apple-darwin10 -fobjc-nonfragile-abi -fblocks -emit-pch -x objective-c %s -o %t.ast +// 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 diff --git a/test/Index/c-index-api-loadTU-test.m b/test/Index/c-index-api-loadTU-test.m index 1d5a9a893156..446f588c4f9d 100644 --- a/test/Index/c-index-api-loadTU-test.m +++ b/test/Index/c-index-api-loadTU-test.m @@ -1,4 +1,4 @@ -// RUN: clang-cc -triple x86_64-apple-darwin10 -fobjc-nonfragile-abi -fblocks -emit-pch -x objective-c %s -o %t.ast +// 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 all | FileCheck %s diff --git a/test/Index/c-index-getCursor-test.m b/test/Index/c-index-getCursor-test.m index 3653a9c2e214..d6081bc9de8c 100644 --- a/test/Index/c-index-getCursor-test.m +++ b/test/Index/c-index-getCursor-test.m @@ -1,4 +1,4 @@ -// RUN: clang-cc -triple x86_64-apple-darwin10 -fobjc-nonfragile-abi -fblocks -emit-pch -x objective-c %s -o %t.ast +// 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-file-scan %t.ast %s | FileCheck %s @interface Foo { diff --git a/test/Index/cindex-from-source.m b/test/Index/cindex-from-source.m new file mode 100644 index 000000000000..8d6a1de4bbdc --- /dev/null +++ b/test/Index/cindex-from-source.m @@ -0,0 +1,9 @@ +// RUN: echo 'typedef int t0;' > %t.pfx.h +// 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] + +struct s0 {}; +t0 g0; diff --git a/test/Index/cindex-on-invalid.m b/test/Index/cindex-on-invalid.m new file mode 100644 index 000000000000..651c40a33539 --- /dev/null +++ b/test/Index/cindex-on-invalid.m @@ -0,0 +1,8 @@ +// RUN: not c-index-test -test-load-source local %s > %t 2> %t.err +// RUN: FileCheck %s < %t.err + +// CHECK: error: expected identifier or '(' +// CHECK: Unable to load translation unit! + +int foo; +int diff --git a/test/Index/code-completion.cpp b/test/Index/code-completion.cpp index 44bd9d28932e..c286c82d0480 100644 --- a/test/Index/code-completion.cpp +++ b/test/Index/code-completion.cpp @@ -33,20 +33,19 @@ void test_overloaded() { overloaded(Z(), 0); } -// CHECK-MEMBER: EnumDecl:{Informative X::}{TypedText E} // CHECK-MEMBER: FieldDecl:{TypedText member} // CHECK-MEMBER: FunctionDecl:{Informative Y::}{TypedText memfunc}{LeftParen (}{Optional {Placeholder int i}}{RightParen )} // CHECK-MEMBER: EnumConstantDecl:{Informative E::}{TypedText Val1} // CHECK-MEMBER: FunctionDecl:{Informative X::}{TypedText ~X}{LeftParen (}{RightParen )} // CHECK-MEMBER: FunctionDecl:{TypedText operator int}{LeftParen (}{RightParen )} // CHECK-MEMBER: FunctionDecl:{TypedText operator=}{LeftParen (}{Placeholder struct Z const &}{RightParen )} -// CHECK-MEMBER: StructDecl:{TypedText X}{Text ::} -// CHECK-MEMBER: StructDecl:{TypedText Y}{Text ::} -// CHECK-MEMBER: StructDecl:{TypedText Z}{Text ::} // CHECK-MEMBER: FieldDecl:{Text X::}{TypedText member} // CHECK-MEMBER: FieldDecl:{Text Y::}{TypedText member} // CHECK-MEMBER: FunctionDecl:{Text X::}{TypedText operator=}{LeftParen (}{Placeholder struct X const &}{RightParen )} // CHECK-MEMBER: FunctionDecl:{Text Y::}{TypedText operator=}{LeftParen (}{Placeholder struct Y const &}{RightParen )} +// CHECK-MEMBER: StructDecl:{TypedText X}{Text ::} +// CHECK-MEMBER: StructDecl:{TypedText Y}{Text ::} +// CHECK-MEMBER: StructDecl:{TypedText Z}{Text ::} // CHECK-OVERLOAD: NotImplemented:{Text overloaded}{LeftParen (}{Text struct Z z}{Comma , }{CurrentParameter int second}{RightParen )} // CHECK-OVERLOAD: NotImplemented:{Text overloaded}{LeftParen (}{Text int i}{Comma , }{CurrentParameter long second}{RightParen )} diff --git a/test/Index/complete-at-directives.m b/test/Index/complete-at-directives.m new file mode 100644 index 000000000000..68d1ef42f863 --- /dev/null +++ b/test/Index/complete-at-directives.m @@ -0,0 +1,24 @@ +/* Run lines are at the end, since line/column matter in this test. */ +@interface MyClass { } +@end + +@implementation MyClass +@end + +// RUN: c-index-test -code-completion-at=%s:2:2 %s | FileCheck -check-prefix=CHECK-CC1 %s +// CHECK-CC1: {TypedText class}{Text }{Placeholder identifier}{Text ;} +// CHECK-CC1: {TypedText compatibility_alias}{Text }{Placeholder alias}{Text }{Placeholder class} +// CHECK-CC1: {TypedText implementation}{Text }{Placeholder class} +// CHECK-CC1: {TypedText interface}{Text }{Placeholder class} +// CHECK-CC1: {TypedText protocol}{Text }{Placeholder protocol} + +// RUN: c-index-test -code-completion-at=%s:3:2 %s | FileCheck -check-prefix=CHECK-CC2 %s +// CHECK-CC2: {TypedText end} +// CHECK-CC2: {TypedText optional} +// CHECK-CC2: {TypedText property} +// CHECK-CC2: {TypedText required} + +// RUN: c-index-test -code-completion-at=%s:6:2 %s | FileCheck -check-prefix=CHECK-CC3 %s +// CHECK-CC3: {TypedText dynamic}{Text }{Placeholder property} +// CHECK-CC3: {TypedText end} +// CHECK-CC3: {TypedText synthesize}{Text }{Placeholder property} diff --git a/test/Index/complete-at-exprstmt.m b/test/Index/complete-at-exprstmt.m new file mode 100644 index 000000000000..82c3983e82b2 --- /dev/null +++ b/test/Index/complete-at-exprstmt.m @@ -0,0 +1,23 @@ +/* The run lines are below, because this test is line- and + column-number sensitive. */ +@interface MyClass { } +- (int)myMethod:(int)arg; +@end + +@implementation MyClass +- (int)myMethod:(int)arg { + @synchronized (@encode(MyClass)) { } +} +@end +// RUN: c-index-test -code-completion-at=%s:9:4 %s | FileCheck -check-prefix=CHECK-CC1 %s +// CHECK-CC1: {TypedText encode}{LeftParen (}{Placeholder type-name}{RightParen )} +// CHECK-CC1: {TypedText protocol}{LeftParen (}{Placeholder protocol-name}{RightParen )} +// CHECK-CC1: {TypedText selector}{LeftParen (}{Placeholder selector}{RightParen )} +// CHECK-CC1: {TypedText synchronized}{Text }{LeftParen (}{Placeholder expression}{RightParen )}{LeftBrace {}{Placeholder statements}{RightBrace }} +// CHECK-CC1: {TypedText throw}{Text }{Placeholder expression}{Text ;} +// CHECK-CC1: {TypedText try}{LeftBrace {}{Placeholder statements}{RightBrace }}{Text @catch}{LeftParen (}{Placeholder parameter}{RightParen )}{LeftBrace {}{Placeholder statements}{RightBrace }}{Text @finally}{LeftBrace {}{Placeholder statements}{RightBrace }} +// RUN: c-index-test -code-completion-at=%s:9:19 %s | FileCheck -check-prefix=CHECK-CC2 %s +// CHECK-CC2: {TypedText encode}{LeftParen (}{Placeholder type-name}{RightParen )} +// CHECK-CC2: {TypedText protocol}{LeftParen (}{Placeholder protocol-name}{RightParen )} +// CHECK-CC2: {TypedText selector}{LeftParen (}{Placeholder selector}{RightParen )} + diff --git a/test/Index/complete-objc-message.m b/test/Index/complete-objc-message.m index b692986cfda9..1c03095e2a01 100644 --- a/test/Index/complete-objc-message.m +++ b/test/Index/complete-objc-message.m @@ -132,3 +132,14 @@ void test_overload(Overload *ovl) { // RUN: c-index-test -code-completion-at=%s:95:24 %s | FileCheck -check-prefix=CHECK-CC9 %s // CHECK-CC9: ObjCInstanceMethodDecl:{Informative Method:}{Informative Arg1:}{TypedText Arg2:}{Placeholder (int)i2} // CHECK-CC9: ObjCInstanceMethodDecl:{Informative Method:}{Informative Arg1:}{TypedText OtherArg:}{Placeholder (id)obj} +// RUN: c-index-test -code-completion-at=%s:61:11 %s | FileCheck -check-prefix=CHECK-CCA %s +// CHECK-CCA: {TypedText _cmd} +// CHECK-CCA: {TypedText self} +// CHECK-CCA: TypedefDecl:{TypedText Class} +// CHECK-CCA: ObjCInterfaceDecl:{TypedText Foo} +// CHECK-CCA: FunctionDecl:{TypedText func}{LeftParen (}{RightParen )} +// CHECK-CCA: TypedefDecl:{TypedText id} +// CHECK-CCA: ObjCInterfaceDecl:{TypedText MyClass} +// CHECK-CCA: ObjCInterfaceDecl:{TypedText MySubClass} +// CHECK-CCA: TypedefDecl:{TypedText SEL} +// CHECK-CCA: {TypedText super} diff --git a/test/Index/objc-decls.m b/test/Index/objc-decls.m index ff396788771d..62a43da007b3 100644 --- a/test/Index/objc-decls.m +++ b/test/Index/objc-decls.m @@ -1,5 +1,5 @@ -// RUN: clang-cc -emit-pch %S/Inputs/t1.m -o %t1.m.ast -// RUN: clang-cc -emit-pch %S/Inputs/t2.m -o %t2.m.ast +// 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 diff --git a/test/Index/objc-message.m b/test/Index/objc-message.m index de61278af87e..568ca9494f55 100644 --- a/test/Index/objc-message.m +++ b/test/Index/objc-message.m @@ -1,5 +1,5 @@ -// RUN: clang-cc -emit-pch %S/Inputs/t1.m -o %t1.m.ast -// RUN: clang-cc -emit-pch %S/Inputs/t2.m -o %t2.m.ast +// 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 diff --git a/test/Index/remap-complete.c b/test/Index/remap-complete.c new file mode 100644 index 000000000000..cfafd3051d8f --- /dev/null +++ b/test/Index/remap-complete.c @@ -0,0 +1,5 @@ +// RUN: c-index-test -code-completion-at=%s:1:12 -remap-file="%s;%S/Inputs/remap-complete-to.c" %s | FileCheck %s +// XFAIL: win32 + +// CHECK: FunctionDecl:{TypedText f0}{LeftParen (}{RightParen )} +void f() { } diff --git a/test/Lexer/has_feature_exceptions.cpp b/test/Lexer/has_feature_exceptions.cpp new file mode 100644 index 000000000000..231a6c56a45b --- /dev/null +++ b/test/Lexer/has_feature_exceptions.cpp @@ -0,0 +1,11 @@ +// RUN: clang -E -fexceptions %s -o - | FileCheck --check-prefix=CHECK-EXCEPTIONS %s +// RUN: clang -E -fno-exceptions %s -o - | FileCheck --check-prefix=CHECK-NO-EXCEPTIONS %s + +#if __has_feature(cxx_exceptions) +int foo(); +#else +int bar(); +#endif + +// CHECK-EXCEPTIONS: foo +// CHECK-NO-EXCEPTIONS: bar diff --git a/test/Lexer/has_feature_rtti.cpp b/test/Lexer/has_feature_rtti.cpp new file mode 100644 index 000000000000..cc01f61cba67 --- /dev/null +++ b/test/Lexer/has_feature_rtti.cpp @@ -0,0 +1,11 @@ +// RUN: clang -E -frtti %s -o - | FileCheck --check-prefix=CHECK-RTTI %s +// RUN: clang -E -fno-rtti %s -o - | FileCheck --check-prefix=CHECK-NO-RTTI %s + +#if __has_feature(cxx_rtti) +int foo(); +#else +int bar(); +#endif + +// CHECK-RTTI: foo +// CHECK-NO-RTTI: bar diff --git a/test/Lexer/msdos-cpm-eof.c b/test/Lexer/msdos-cpm-eof.c new file mode 100644 index 000000000000..e4dacd9802f2 --- /dev/null +++ b/test/Lexer/msdos-cpm-eof.c @@ -0,0 +1,5 @@ +// RUN: clang-cc -fsyntax-only -verify -fms-extensions %s + +int a; + + diff --git a/test/Misc/Inputs/remapped-file b/test/Misc/Inputs/remapped-file new file mode 100644 index 000000000000..657613ed145a --- /dev/null +++ b/test/Misc/Inputs/remapped-file @@ -0,0 +1 @@ +int *f(float *fp) { return fp; } diff --git a/test/Misc/Inputs/remapped-file-2 b/test/Misc/Inputs/remapped-file-2 new file mode 100644 index 000000000000..9ac034a3b979 --- /dev/null +++ b/test/Misc/Inputs/remapped-file-2 @@ -0,0 +1,3 @@ +#include "nonexistent.h" + +int *f() { return fp; } diff --git a/test/Misc/Inputs/remapped-file-3 b/test/Misc/Inputs/remapped-file-3 new file mode 100644 index 000000000000..b7ab613367df --- /dev/null +++ b/test/Misc/Inputs/remapped-file-3 @@ -0,0 +1,2 @@ +extern float *fp; + diff --git a/test/Misc/message-length.c b/test/Misc/message-length.c index 841ffc9f615d..24f623394d88 100644 --- a/test/Misc/message-length.c +++ b/test/Misc/message-length.c @@ -1,5 +1,5 @@ -// RUN: clang -fsyntax-only -fmessage-length=72 %s 2>&1 | FileCheck -strict-whitespace %s -// RUN: clang -fsyntax-only -fmessage-length=1 %s +// RUN: clang-cc -fmessage-length 72 %s 2>&1 | FileCheck -strict-whitespace %s +// RUN: clang-cc -fmessage-length 1 %s // Hack so we can check things better, force the file name and line. # 1 "FILE" 1 diff --git a/test/Misc/remap-file.c b/test/Misc/remap-file.c new file mode 100644 index 000000000000..f12fe9501265 --- /dev/null +++ b/test/Misc/remap-file.c @@ -0,0 +1,8 @@ +// RUN: clang-cc -remap-file "%s;%S/Inputs/remapped-file" -fsyntax-only %s 2>&1 | FileCheck -check-prefix=CHECK-EXIST %s +// RUN: clang-cc -remap-file "%S/nonexistent.c;%S/Inputs/remapped-file" -fsyntax-only %S/nonexistent.c 2>&1 | FileCheck -check-prefix=CHECK-NONEXIST %s +// RUN: clang-cc -remap-file "%S/nonexistent.c;%S/Inputs/remapped-file-2" -remap-file "%S/nonexistent.h;%S/Inputs/remapped-file-3" -fsyntax-only %S/nonexistent.c 2>&1 | FileCheck -check-prefix=CHECK-HEADER %s + +// CHECK-EXIST: remap-file.c:1:28: warning: incompatible pointer types +// CHECK-NONEXIST: nonexistent.c:1:28: warning: incompatible pointer types +// CHECK-HEADER: nonexistent.c:3:19: warning: incompatible pointer types +int diff --git a/test/PCH/method_pool.m b/test/PCH/method_pool.m index 053438828e36..17e2420081ff 100644 --- a/test/PCH/method_pool.m +++ b/test/PCH/method_pool.m @@ -1,9 +1,9 @@ // Test this without pch. -// RUN: clang-cc -include %S/method_pool.h -fsyntax-only -verify %s +// RUN: clang -cc1 -include %S/method_pool.h -fsyntax-only -verify %s // Test with pch. -// RUN: clang-cc -x objective-c -emit-pch -o %t %S/method_pool.h -// RUN: clang-cc -include-pch %t -fsyntax-only -verify %s +// RUN: clang -cc1 -x objective-c -emit-pch -o %t %S/method_pool.h +// RUN: clang -cc1 -include-pch %t -fsyntax-only -verify %s int message_id(id x) { return [x instMethod:17]; // expected-warning{{multiple methods}} diff --git a/test/PCH/objc_exprs.m b/test/PCH/objc_exprs.m index 9eb5a113a247..0c12b8e177fc 100644 --- a/test/PCH/objc_exprs.m +++ b/test/PCH/objc_exprs.m @@ -1,9 +1,9 @@ // Test this without pch. -// RUN: clang-cc -fblocks -include %S/objc_exprs.h -fsyntax-only -verify %s +// RUN: clang -cc1 -fblocks -include %S/objc_exprs.h -fsyntax-only -verify %s // Test with pch. -// RUN: clang-cc -x objective-c-header -emit-pch -fblocks -o %t %S/objc_exprs.h -// RUN: clang-cc -fblocks -include-pch %t -fsyntax-only -verify %s +// RUN: clang -cc1 -x objective-c-header -emit-pch -fblocks -o %t %S/objc_exprs.h +// RUN: clang -cc1 -fblocks -include-pch %t -fsyntax-only -verify %s // Expressions int *A1 = (objc_string)0; // expected-warning {{aka 'id'}} diff --git a/test/PCH/objc_import.m b/test/PCH/objc_import.m index 12893861585a..c109f4083660 100644 --- a/test/PCH/objc_import.m +++ b/test/PCH/objc_import.m @@ -1,9 +1,9 @@ // Test this without pch. -// RUN: clang-cc -include %S/objc_import.h -fsyntax-only -verify %s +// RUN: clang -cc1 -include %S/objc_import.h -fsyntax-only -verify %s // Test with pch. -// RUN: clang-cc -x objective-c -emit-pch -o %t %S/objc_import.h -// RUN: clang-cc -include-pch %t -fsyntax-only -verify %s +// RUN: clang -cc1 -x objective-c -emit-pch -o %t %S/objc_import.h +// RUN: clang -cc1 -include-pch %t -fsyntax-only -verify %s #import "objc_import.h" diff --git a/test/PCH/objc_methods.m b/test/PCH/objc_methods.m index 136e39706c82..a60ffad4f2a1 100644 --- a/test/PCH/objc_methods.m +++ b/test/PCH/objc_methods.m @@ -1,9 +1,9 @@ // Test this without pch. -// RUN: clang-cc -include %S/objc_methods.h -fsyntax-only -verify %s +// RUN: clang -cc1 -include %S/objc_methods.h -fsyntax-only -verify %s // Test with pch. -// RUN: clang-cc -x objective-c -emit-pch -o %t %S/objc_methods.h -// RUN: clang-cc -include-pch %t -fsyntax-only -verify %s +// RUN: clang -cc1 -x objective-c -emit-pch -o %t %S/objc_methods.h +// RUN: clang -cc1 -include-pch %t -fsyntax-only -verify %s void func() { TestPCH *xx; diff --git a/test/PCH/objc_property.m b/test/PCH/objc_property.m index 5992787fa422..17c3a729c5c6 100644 --- a/test/PCH/objc_property.m +++ b/test/PCH/objc_property.m @@ -1,9 +1,9 @@ // Test this without pch. -// RUN: clang-cc -include %S/objc_property.h -fsyntax-only -verify %s +// RUN: clang -cc1 -include %S/objc_property.h -fsyntax-only -verify %s // Test with pch. -// RUN: clang-cc -x objective-c -emit-pch -o %t %S/objc_property.h -// RUN: clang-cc -include-pch %t -fsyntax-only -verify %s +// RUN: clang -cc1 -x objective-c -emit-pch -o %t %S/objc_property.h +// RUN: clang -cc1 -include-pch %t -fsyntax-only -verify %s void func() { TestProperties *xx = [TestProperties alloc]; diff --git a/test/PCH/source-manager-stack.c b/test/PCH/source-manager-stack.c new file mode 100644 index 000000000000..72084d9760ed --- /dev/null +++ b/test/PCH/source-manager-stack.c @@ -0,0 +1,12 @@ +// Test that the source manager has the "proper" idea about the include stack +// when using PCH. + +// RUN: echo 'int x;' > %t.prefix.h +// RUN: not clang-cc -fsyntax-only -include %t.prefix.h %s 2> %t.diags.no_pch.txt +// RUN: clang-cc -emit-pch -o %t.prefix.pch %t.prefix.h +// RUN: not clang-cc -fsyntax-only -include-pch %t.prefix.pch %s 2> %t.diags.pch.txt +// RUN: diff %t.diags.no_pch.txt %t.diags.pch.txt +// XFAIL: * +// PR5662 + +float x; diff --git a/test/Parser/check-objc2-syntax-1.m b/test/Parser/check-objc2-syntax-1.m index f596e9ba0f37..aafb2e090a6a 100644 --- a/test/Parser/check-objc2-syntax-1.m +++ b/test/Parser/check-objc2-syntax-1.m @@ -1,4 +1,4 @@ -// RUN: clang-cc -fsyntax-only -verify %s +// RUN: clang -cc1 -fsyntax-only -verify %s @interface Subclass + (int)magicNumber; diff --git a/test/Parser/check-syntax-1.m b/test/Parser/check-syntax-1.m index af1b7a8b714a..8ad207270c3f 100644 --- a/test/Parser/check-syntax-1.m +++ b/test/Parser/check-syntax-1.m @@ -1,4 +1,4 @@ -// RUN: clang-cc -fsyntax-only -verify %s +// RUN: clang -cc1 -fsyntax-only -verify %s int @interface bla ; // expected-error {{cannot combine with previous 'int' declaration specifier}} @end diff --git a/test/Parser/cxx-decl.cpp b/test/Parser/cxx-decl.cpp index 3fa284282ad6..6f3fd391b95a 100644 --- a/test/Parser/cxx-decl.cpp +++ b/test/Parser/cxx-decl.cpp @@ -1,3 +1,54 @@ // RUN: clang-cc -verify -fsyntax-only %s int x(*g); // expected-error {{use of undeclared identifier 'g'}} + +struct Type { + int Type; +}; + + +// PR4451 - We should recover well from the typo of '::' as ':' in a2. +namespace y { + struct a { }; + typedef int b; +} + +y::a a1; +y:a a2; // expected-error {{unexpected ':' in nested name specifier}} +y::a a3 = a2; + +// Some valid colons: +void foo() { +y: // label + y::a s; + + int a = 4; + a = a ? a : a+1; +} + +struct b : y::a {}; + +template +class someclass { + + int bar() { + T *P; + return 1 ? P->x : P->y; + } +}; + +enum { fooenum = 1 }; + +struct a { + int Type : fooenum; +}; + +void test(struct Type *P) { + int Type; + Type = 1 ? P->Type : Type; + + Type = (y:b) 4; // expected-error {{unexpected ':' in nested name specifier}} + Type = 1 ? ( + (y:b) // expected-error {{unexpected ':' in nested name specifier}} + 4) : 5; +} \ No newline at end of file diff --git a/test/Parser/cxx-extern-c-array.cpp b/test/Parser/cxx-extern-c-array.cpp new file mode 100644 index 000000000000..1a04fa05c24e --- /dev/null +++ b/test/Parser/cxx-extern-c-array.cpp @@ -0,0 +1,7 @@ +// RUN: clang-cc -fsyntax-only -verify %s + +extern "C" int myarray[]; +int myarray[12] = {0}; + +extern "C" int anotherarray[][3]; +int anotherarray[2][3] = {1,2,3,4,5,6}; diff --git a/test/Parser/cxx-friend.cpp b/test/Parser/cxx-friend.cpp index 14b31af761d3..6505ad0f6f76 100644 --- a/test/Parser/cxx-friend.cpp +++ b/test/Parser/cxx-friend.cpp @@ -30,3 +30,11 @@ class B { void f(A *a) { a->f(); } }; + + + + +template class some_template; +friend // expected-error {{'friend' used outside of class}} +some_template& // expected-error {{use of undeclared identifier 'foo'}} + ; // expected-error {{expected unqualified-id}} diff --git a/test/Parser/cxx-try.cpp b/test/Parser/cxx-stmt.cpp similarity index 77% rename from test/Parser/cxx-try.cpp rename to test/Parser/cxx-stmt.cpp index 535f40d78057..cc35ba153f6b 100644 --- a/test/Parser/cxx-try.cpp +++ b/test/Parser/cxx-stmt.cpp @@ -1,6 +1,6 @@ // RUN: clang-cc -fsyntax-only -verify %s -void f() +void f1() { try { ; @@ -10,7 +10,7 @@ void f() } } -void g() +void f2() { try; // expected-error {{expected '{'}} @@ -24,7 +24,7 @@ void g() catch {} // expected-error {{expected '('}} } -void h() try { +void f3() try { } catch(...) { } @@ -39,3 +39,16 @@ struct A { A::A(char) : i(0) try {} // expected-error {{expected '{' or ','}} A::A(int j) try : i(j) {} catch(...) {} + + + +// PR5740 +struct Type { }; + +enum { Type } Kind; +void f4() { + int i = 0; + switch (Kind) { + case Type: i = 7; break; // no error. + } +} \ No newline at end of file diff --git a/test/Parser/cxx-using-declaration.cpp b/test/Parser/cxx-using-declaration.cpp index 461b9e597d25..20c9fb391a80 100644 --- a/test/Parser/cxx-using-declaration.cpp +++ b/test/Parser/cxx-using-declaration.cpp @@ -1,5 +1,4 @@ // RUN: clang-cc -fsyntax-only -verify %s -// XFAIL: * namespace A { int VA; diff --git a/test/Parser/encode.m b/test/Parser/encode.m index 1e088a011511..15e9fe9828be 100644 --- a/test/Parser/encode.m +++ b/test/Parser/encode.m @@ -1,4 +1,4 @@ -// RUN: clang-cc -fsyntax-only -verify %s +// RUN: clang -cc1 -fsyntax-only -verify %s int main(void) { const char ch = @encode(char *)[2]; diff --git a/test/Parser/enhanced-proto-1.m b/test/Parser/enhanced-proto-1.m index 1f42ec2efbb4..b80eb7d09d8f 100644 --- a/test/Parser/enhanced-proto-1.m +++ b/test/Parser/enhanced-proto-1.m @@ -1,4 +1,4 @@ -// RUN: clang-cc -fsyntax-only -verify %s +// RUN: clang -cc1 -fsyntax-only -verify %s @protocol MyProto1 @optional diff --git a/test/Parser/expressions.m b/test/Parser/expressions.m index e9e41216f986..9adc34af1fc7 100644 --- a/test/Parser/expressions.m +++ b/test/Parser/expressions.m @@ -1,4 +1,4 @@ -// RUN: clang-cc -parse-noop %s +// RUN: clang -cc1 -parse-noop %s void test1() { @"s"; // expected-warning {{expression result unused}} diff --git a/test/Parser/method-prototype-1.m b/test/Parser/method-prototype-1.m index 1d535de8c140..86a912f46eb7 100644 --- a/test/Parser/method-prototype-1.m +++ b/test/Parser/method-prototype-1.m @@ -1,4 +1,4 @@ -// RUN: clang-cc %s -parse-noop +// RUN: clang -cc1 %s -parse-noop @interface MyObject - (void) bycopy : (int) woodo, ... ; - (void) break : (int) woodo, ... ; diff --git a/test/Parser/objc-alias-printing.m b/test/Parser/objc-alias-printing.m index e121bed0aea8..afb522cfa3d9 100644 --- a/test/Parser/objc-alias-printing.m +++ b/test/Parser/objc-alias-printing.m @@ -1,4 +1,4 @@ -// RUN: clang-cc -ast-print %s +// RUN: clang -cc1 -ast-print %s @protocol P1 @end @protocol P2 @end diff --git a/test/Parser/objc-category-neg-1.m b/test/Parser/objc-category-neg-1.m index 6c1bd2951736..957dbde2d7fa 100644 --- a/test/Parser/objc-category-neg-1.m +++ b/test/Parser/objc-category-neg-1.m @@ -1,4 +1,4 @@ -// RUN: clang-cc -fsyntax-only -verify %s +// RUN: clang -cc1 -fsyntax-only -verify %s void __assert_rtn(const char *, const char *, int, const char *) __attribute__((__noreturn__)); static __inline__ int __inline_isfinitef (float ) __attribute__ ((always_inline)); diff --git a/test/Parser/objc-forcollection-1.m b/test/Parser/objc-forcollection-1.m index 21ec308a28a1..6075332dcd5b 100644 --- a/test/Parser/objc-forcollection-1.m +++ b/test/Parser/objc-forcollection-1.m @@ -1,4 +1,4 @@ -// RUN: clang-cc -fsyntax-only %s +// RUN: clang -cc1 -fsyntax-only %s typedef struct objc_class *Class; typedef struct objc_object { diff --git a/test/Parser/objc-forcollection-neg-2.m b/test/Parser/objc-forcollection-neg-2.m index ddb279b6f7c1..9019d441a60a 100644 --- a/test/Parser/objc-forcollection-neg-2.m +++ b/test/Parser/objc-forcollection-neg-2.m @@ -1,4 +1,4 @@ -// RUN: clang-cc -fsyntax-only -verify %s +// RUN: clang -cc1 -fsyntax-only -verify %s typedef struct objc_class *Class; typedef struct objc_object { diff --git a/test/Parser/objc-forcollection-neg.m b/test/Parser/objc-forcollection-neg.m index 0f2bb90df85f..464759e0d175 100644 --- a/test/Parser/objc-forcollection-neg.m +++ b/test/Parser/objc-forcollection-neg.m @@ -1,4 +1,4 @@ -// RUN: clang-cc -fsyntax-only -verify %s +// RUN: clang -cc1 -fsyntax-only -verify %s typedef struct objc_class *Class; typedef struct objc_object { diff --git a/test/Parser/objc-foreach-syntax.m b/test/Parser/objc-foreach-syntax.m index 977dccc88b1d..294a6029378c 100644 --- a/test/Parser/objc-foreach-syntax.m +++ b/test/Parser/objc-foreach-syntax.m @@ -1,4 +1,4 @@ -// RUN: clang-cc -fsyntax-only -verify %s +// RUN: clang -cc1 -fsyntax-only -verify %s diff --git a/test/Parser/objc-init.m b/test/Parser/objc-init.m index bc88e33e3720..b3f033ea25f1 100644 --- a/test/Parser/objc-init.m +++ b/test/Parser/objc-init.m @@ -1,4 +1,4 @@ -// RUN: clang-cc -fsyntax-only -verify %s -pedantic +// RUN: clang -cc1 -fsyntax-only -verify %s -pedantic // rdar://5707001 @interface NSNumber; diff --git a/test/Parser/objc-interfaces.m b/test/Parser/objc-interfaces.m index 7aa672901fff..fdb52e763f2c 100644 --- a/test/Parser/objc-interfaces.m +++ b/test/Parser/objc-interfaces.m @@ -1,4 +1,4 @@ -// RUN: clang-cc %s -fsyntax-only -verify +// RUN: clang -cc1 %s -fsyntax-only -verify // Test features and error recovery for objc interfaces. diff --git a/test/Parser/objc-messaging-1.m b/test/Parser/objc-messaging-1.m index 4a36fc950fa8..2ee3639b06cb 100644 --- a/test/Parser/objc-messaging-1.m +++ b/test/Parser/objc-messaging-1.m @@ -1,4 +1,4 @@ -// RUN: clang-cc %s -parse-noop +// RUN: clang -cc1 %s -parse-noop int main () { int i,j; diff --git a/test/Parser/objc-messaging-neg-1.m b/test/Parser/objc-messaging-neg-1.m index 0344566aa87a..4dcbb79a996a 100644 --- a/test/Parser/objc-messaging-neg-1.m +++ b/test/Parser/objc-messaging-neg-1.m @@ -1,4 +1,4 @@ -// RUN: clang-cc -fsyntax-only -verify %s +// RUN: clang -cc1 -fsyntax-only -verify %s int main() { id a; diff --git a/test/Parser/objc-missing-impl.m b/test/Parser/objc-missing-impl.m index 9108451f1bff..392b26f63838 100644 --- a/test/Parser/objc-missing-impl.m +++ b/test/Parser/objc-missing-impl.m @@ -1,2 +1,2 @@ -// RUN: clang-cc -fsyntax-only -verify %s +// RUN: clang -cc1 -fsyntax-only -verify %s @end // expected-warning {{@end must appear in an @implementation context}} diff --git a/test/Parser/objc-property-syntax.m b/test/Parser/objc-property-syntax.m index cf75aaa2d5a2..294fb541e474 100644 --- a/test/Parser/objc-property-syntax.m +++ b/test/Parser/objc-property-syntax.m @@ -1,4 +1,4 @@ -// RUN: clang-cc -fsyntax-only -verify %s +// RUN: clang -cc1 -fsyntax-only -verify %s @interface MyClass { diff --git a/test/Parser/objc-quirks.m b/test/Parser/objc-quirks.m index 2913b580c5fc..233739bc38d0 100644 --- a/test/Parser/objc-quirks.m +++ b/test/Parser/objc-quirks.m @@ -1,4 +1,4 @@ -// RUN: clang-cc -fsyntax-only -verify %s +// RUN: clang -cc1 -fsyntax-only -verify %s // FIXME: This is a horrible error message here. Fix. int @"s" = 5; // expected-error {{prefix attribute must be}} diff --git a/test/Parser/objc-synthesized-recover.m b/test/Parser/objc-synthesized-recover.m index 7de1a5794222..dbe9b1d93b61 100644 --- a/test/Parser/objc-synthesized-recover.m +++ b/test/Parser/objc-synthesized-recover.m @@ -1,4 +1,4 @@ -// RUN: clang-cc -fsyntax-only -verify %s +// RUN: clang -cc1 -fsyntax-only -verify %s @interface I1 { diff --git a/test/Parser/objc-try-catch-1.m b/test/Parser/objc-try-catch-1.m index 98c6d16ff698..25b52794a77d 100644 --- a/test/Parser/objc-try-catch-1.m +++ b/test/Parser/objc-try-catch-1.m @@ -1,5 +1,5 @@ -// RUN: clang-cc -fsyntax-only -verify %s -// RUN: clang-cc -fsyntax-only -verify -x objective-c++ %s +// RUN: clang -cc1 -fsyntax-only -verify %s +// RUN: clang -cc1 -fsyntax-only -verify -x objective-c++ %s void * proc(); @interface NSConstantString diff --git a/test/Parser/objc-type-printing.m b/test/Parser/objc-type-printing.m index d9ad70474f2b..e619b72ab6b1 100644 --- a/test/Parser/objc-type-printing.m +++ b/test/Parser/objc-type-printing.m @@ -1,4 +1,4 @@ -// RUN: clang-cc -ast-print %s +// RUN: clang -cc1 -ast-print %s @protocol P1 @end @protocol P2 @end diff --git a/test/Parser/prefix-attributes.m b/test/Parser/prefix-attributes.m index bb6d04da2a08..31be34076fe3 100644 --- a/test/Parser/prefix-attributes.m +++ b/test/Parser/prefix-attributes.m @@ -1,4 +1,4 @@ -// RUN: clang-cc -verify -fsyntax-only %s +// RUN: clang -cc1 -verify -fsyntax-only %s __attribute__((deprecated)) @class B; // expected-error {{prefix attribute must be followed by an interface or protocol}} diff --git a/test/Parser/selector-1.m b/test/Parser/selector-1.m index 85ef919689df..fdc74ff4b424 100644 --- a/test/Parser/selector-1.m +++ b/test/Parser/selector-1.m @@ -1,4 +1,4 @@ -// RUN: clang-cc -parse-noop %s +// RUN: clang -cc1 -parse-noop %s int main() { SEL s = @selector(retain); diff --git a/test/Preprocessor/dump_macros.c b/test/Preprocessor/dump_macros.c index bdc69536778d..5908fec4b681 100644 --- a/test/Preprocessor/dump_macros.c +++ b/test/Preprocessor/dump_macros.c @@ -1,31 +1,38 @@ -// RUN: clang-cc -E -dM %s -o %t +// RUN: clang-cc -E -dM %s -o - | FileCheck %s -strict-whitespace -// Space even without expansion tokens -// RUN: grep "#define A(x) " %t +// Space at end even without expansion tokens +// CHECK: #define A(x) #define A(x) // Space before expansion list. -// RUN: grep "#define B(x,y) x y" %t +// CHECK: #define B(x,y) x y #define B(x,y)x y -// No space in expansion list. -// RUN: grep "#define C(x,y) x y" %t +// No space in argument list. +// CHECK: #define C(x,y) x y #define C(x, y) x y // No paste avoidance. -// RUN: grep "#define X() .." %t -#define X() .. +// CHECK: #define D() .. +#define D() .. // Simple test. -// RUN: grep "#define Y ." %t -// RUN: grep "#define Z X()Y" %t -#define Y . -#define Z X()Y +// CHECK: #define E . +// CHECK: #define F X()Y +#define E . +#define F X()Y // gcc prints macros at end of translation unit, so last one wins. -// RUN: grep "#define foo 2" %t -// RUN: not grep "#define foo 1" %t -#define foo 1 -#undef foo -#define foo 2 +// CHECK: #define G 2 +#define G 1 +#undef G +#define G 2 +// Variadic macros of various sorts. PR5699 + +// CHECK: H(x,...) __VA_ARGS__ +#define H(x, ...) __VA_ARGS__ +// CHECK: I(...) __VA_ARGS__ +#define I(...) __VA_ARGS__ +// CHECK: J(x...) __VA_ARGS__ +#define J(x ...) __VA_ARGS__ diff --git a/test/Preprocessor/header_lookup1.c b/test/Preprocessor/header_lookup1.c index 10049adcd374..961e55161418 100644 --- a/test/Preprocessor/header_lookup1.c +++ b/test/Preprocessor/header_lookup1.c @@ -1,2 +1,2 @@ -// RUN: clang -I /usr/include %s -E | grep 'stdio.h.*3.*4' +// RUN: clang -fno-ms-extensions -I /usr/include %s -E | grep 'stdio.h.*3.*4' #include diff --git a/test/Preprocessor/macro_fn_disable_expand.c b/test/Preprocessor/macro_fn_disable_expand.c index c3b067dfc965..d40ee2aa6ec7 100644 --- a/test/Preprocessor/macro_fn_disable_expand.c +++ b/test/Preprocessor/macro_fn_disable_expand.c @@ -1,11 +1,30 @@ -// RUN: clang-cc %s -E | grep 'bar foo (2)' -// RUN: clang-cc %s -E | grep 'm(ABCD)' +// RUN: clang-cc %s -E | FileCheck %s #define foo(x) bar x foo(foo) (2) - +// CHECK: bar foo (2) #define m(a) a(w) #define w ABCD -m(m) // m(ABCD) +m(m) +// CHECK: m(ABCD) + + +// rdar://7466570 PR4438, PR5163 + +// We should get '42' in the argument list for gcc compatibility. +#define A 1 +#define B 2 +#define C(x) (x + 1) + +X: C( +#ifdef A +#if A == 1 +#if B + 42 +#endif +#endif +#endif + ) +// CHECK: X: (42 + 1) diff --git a/test/Preprocessor/non_fragile_feature.m b/test/Preprocessor/non_fragile_feature.m index cb6bc012f1c2..dbf1f9a797e2 100644 --- a/test/Preprocessor/non_fragile_feature.m +++ b/test/Preprocessor/non_fragile_feature.m @@ -1,4 +1,4 @@ -// RUN: clang-cc -fobjc-nonfragile-abi %s +// RUN: clang -cc1 -fobjc-nonfragile-abi %s #ifndef __has_feature #error Should have __has_feature #endif diff --git a/test/Preprocessor/non_fragile_feature1.m b/test/Preprocessor/non_fragile_feature1.m index 59f665b54649..5943e01b517e 100644 --- a/test/Preprocessor/non_fragile_feature1.m +++ b/test/Preprocessor/non_fragile_feature1.m @@ -1,4 +1,4 @@ -// RUN: clang-cc -triple i386-unknown-unknown %s +// RUN: clang -cc1 -triple i386-unknown-unknown %s #ifndef __has_feature #error Should have __has_feature #endif diff --git a/test/Preprocessor/objc-pp.m b/test/Preprocessor/objc-pp.m index 977789e38f1c..9f375efec2c0 100644 --- a/test/Preprocessor/objc-pp.m +++ b/test/Preprocessor/objc-pp.m @@ -1,4 +1,4 @@ -// RUN: clang-cc %s -fsyntax-only -verify -pedantic +// RUN: clang -cc1 %s -fsyntax-only -verify -pedantic #import // no warning on #import in objc mode. diff --git a/test/Rewriter/block-test.c b/test/Rewriter/block-test.c index 9b24e6323d45..5057056eb3d0 100644 --- a/test/Rewriter/block-test.c +++ b/test/Rewriter/block-test.c @@ -1,4 +1,4 @@ -// RUN: clang-cc -rewrite-blocks %s -fblocks -o - +// RUN: clang -cc1 -rewrite-blocks %s -fblocks -o - static int (^block)(const void *, const void *) = (int (^)(const void *, const void *))0; static int (*func)(int (^block)(void *, void *)) = (int (*)(int (^block)(void *, void *)))0; diff --git a/test/Rewriter/crash.m b/test/Rewriter/crash.m index d4aba58c7b60..60d6d1534cdc 100644 --- a/test/Rewriter/crash.m +++ b/test/Rewriter/crash.m @@ -1,4 +1,4 @@ -// RUN: clang-cc -rewrite-objc -o - %s +// RUN: clang -cc1 -rewrite-objc -o - %s // rdar://5950938 @interface NSArray {} + (id)arrayWithObjects:(id)firstObj, ...; diff --git a/test/Rewriter/finally.m b/test/Rewriter/finally.m index bdc5a34fdf2d..ae650568abf1 100644 --- a/test/Rewriter/finally.m +++ b/test/Rewriter/finally.m @@ -1,4 +1,4 @@ -// RUN: clang-cc -rewrite-objc -verify %s -o - +// RUN: clang -cc1 -rewrite-objc -verify %s -o - int main() { @try { @@ -11,7 +11,7 @@ int main() { while (1) { @try { printf("executing try"); - break; // expected-warning{{rewriter doesn't support user-specified control flow semantics for @try/@finally (code may not execute properly)}} + break; } @finally { printf("executing finally"); } @@ -25,3 +25,18 @@ int main() { return 0; } +void test_sync_with_implicit_finally() { + id foo; + @synchronized (foo) { + return; // The rewriter knows how to generate code for implicit finally + } +} + +void test2_try_with_implicit_finally() { + @try { + return; // The rewriter knows how to generate code for implicit finally + } @catch (id e) { + + } +} + diff --git a/test/Rewriter/id-test-3.m b/test/Rewriter/id-test-3.m index aecabe6f30ab..0edd041197ab 100644 --- a/test/Rewriter/id-test-3.m +++ b/test/Rewriter/id-test-3.m @@ -1,4 +1,4 @@ -// RUN: clang-cc -rewrite-objc %s -o - +// RUN: clang -cc1 -rewrite-objc %s -o - @protocol P - (id

    ) Meth: (id

    ) Arg; diff --git a/test/Rewriter/ivar-encoding-1.m b/test/Rewriter/ivar-encoding-1.m index 10665b838ff7..667c7270e835 100644 --- a/test/Rewriter/ivar-encoding-1.m +++ b/test/Rewriter/ivar-encoding-1.m @@ -1,4 +1,4 @@ -// RUN: clang-cc -rewrite-objc %s -o - +// RUN: clang -cc1 -rewrite-objc %s -o - @interface Intf { diff --git a/test/Rewriter/ivar-encoding-2.m b/test/Rewriter/ivar-encoding-2.m index 6cd0e2729874..6a4966bb2760 100644 --- a/test/Rewriter/ivar-encoding-2.m +++ b/test/Rewriter/ivar-encoding-2.m @@ -1,4 +1,4 @@ -// RUN: clang-cc -rewrite-objc %s -o - +// RUN: clang -cc1 -rewrite-objc %s -o - @implementation Intf { diff --git a/test/Rewriter/metadata-test-1.m b/test/Rewriter/metadata-test-1.m index 54413f2650f7..bfbe486ea487 100644 --- a/test/Rewriter/metadata-test-1.m +++ b/test/Rewriter/metadata-test-1.m @@ -1,4 +1,4 @@ -// RUN: clang-cc -rewrite-objc %s -o - +// RUN: clang -cc1 -rewrite-objc %s -o - @interface Intf @end diff --git a/test/Rewriter/metadata-test-2.m b/test/Rewriter/metadata-test-2.m index af26545fa69d..c9f937f18798 100644 --- a/test/Rewriter/metadata-test-2.m +++ b/test/Rewriter/metadata-test-2.m @@ -1,4 +1,4 @@ -// RUN: clang-cc -rewrite-objc %s -o - +// RUN: clang -cc1 -rewrite-objc %s -o - typedef struct _NSPoint { float x; diff --git a/test/Rewriter/method-encoding-1.m b/test/Rewriter/method-encoding-1.m index 4726061d1a61..77bbd8c25cb2 100644 --- a/test/Rewriter/method-encoding-1.m +++ b/test/Rewriter/method-encoding-1.m @@ -1,4 +1,4 @@ -// RUN: clang-cc -rewrite-objc %s -o - +// RUN: clang -cc1 -rewrite-objc %s -o - @protocol P1 - (void) MyProtoMeth : (int **) arg1 : (void*) arg2; diff --git a/test/Rewriter/objc-encoding-bug-1.m b/test/Rewriter/objc-encoding-bug-1.m index d2099883b1de..797b5bbc03a4 100644 --- a/test/Rewriter/objc-encoding-bug-1.m +++ b/test/Rewriter/objc-encoding-bug-1.m @@ -1,4 +1,4 @@ -// RUN: clang-cc -rewrite-objc %s -o - +// RUN: clang -cc1 -rewrite-objc %s -o - typedef struct NSMethodFrameArgInfo { struct NSMethodFrameArgInfo *subInfo; diff --git a/test/Rewriter/objc-ivar-receiver-1.m b/test/Rewriter/objc-ivar-receiver-1.m index 3898f715b71f..7bf3544a36ea 100644 --- a/test/Rewriter/objc-ivar-receiver-1.m +++ b/test/Rewriter/objc-ivar-receiver-1.m @@ -1,5 +1,5 @@ -// RUN: clang-cc -rewrite-objc %s -o - -// RUN: clang-cc -rewrite-objc %s -o - | grep 'newInv->_container' +// RUN: clang -cc1 -rewrite-objc %s -o - +// RUN: clang -cc1 -rewrite-objc %s -o - | grep 'newInv->_container' @interface NSMutableArray - (void)addObject:(id)addObject; diff --git a/test/Rewriter/objc-string-concat-1.m b/test/Rewriter/objc-string-concat-1.m index b1f95e052cb8..bf189beef251 100644 --- a/test/Rewriter/objc-string-concat-1.m +++ b/test/Rewriter/objc-string-concat-1.m @@ -1,4 +1,4 @@ -// RUN: clang-cc -rewrite-objc %s -o - +// RUN: clang -cc1 -rewrite-objc %s -o - @class NSString; diff --git a/test/Rewriter/objc-super-test.m b/test/Rewriter/objc-super-test.m index 500933d835da..7a3b3af656ae 100644 --- a/test/Rewriter/objc-super-test.m +++ b/test/Rewriter/objc-super-test.m @@ -1,4 +1,4 @@ -// RUN: clang-cc -rewrite-objc %s -o - | grep objc_msgSendSuper | grep MainMethod +// RUN: clang -cc1 -rewrite-objc %s -o - | grep objc_msgSendSuper | grep MainMethod typedef struct objc_selector *SEL; typedef struct objc_object *id; diff --git a/test/Rewriter/objc-synchronized-1.m b/test/Rewriter/objc-synchronized-1.m index df24518d65e4..3359660e112d 100644 --- a/test/Rewriter/objc-synchronized-1.m +++ b/test/Rewriter/objc-synchronized-1.m @@ -1,4 +1,4 @@ -// RUN: clang-cc -rewrite-objc %s -o - +// RUN: clang -cc1 -rewrite-objc %s -o - id SYNCH_EXPR(); void SYNCH_BODY(); diff --git a/test/Rewriter/properties.m b/test/Rewriter/properties.m index ac8ee9ff8c97..3b49c22f8e26 100644 --- a/test/Rewriter/properties.m +++ b/test/Rewriter/properties.m @@ -1,4 +1,4 @@ -// RUN: clang-cc -rewrite-objc %s -o - +// RUN: clang -cc1 -rewrite-objc %s -o - @interface Foo { int i; diff --git a/test/Rewriter/protocol-rewrite-1.m b/test/Rewriter/protocol-rewrite-1.m index 3f2bb6f190cd..66280ca1b0f2 100644 --- a/test/Rewriter/protocol-rewrite-1.m +++ b/test/Rewriter/protocol-rewrite-1.m @@ -1,4 +1,4 @@ -// RUN: clang-cc -rewrite-objc %s -o - +// RUN: clang -cc1 -rewrite-objc %s -o - typedef struct MyWidget { int a; diff --git a/test/Rewriter/rewrite-api-bug.m b/test/Rewriter/rewrite-api-bug.m index e2dfe38afe44..745efec5bd9e 100644 --- a/test/Rewriter/rewrite-api-bug.m +++ b/test/Rewriter/rewrite-api-bug.m @@ -1,4 +1,4 @@ -// RUN: clang-cc -rewrite-objc %s -o - +// RUN: clang -cc1 -rewrite-objc %s -o - @interface MyDerived - (void) instanceMethod; diff --git a/test/Rewriter/rewrite-foreach-1.m b/test/Rewriter/rewrite-foreach-1.m index 686d73fca5b4..9cf084c502ae 100644 --- a/test/Rewriter/rewrite-foreach-1.m +++ b/test/Rewriter/rewrite-foreach-1.m @@ -1,4 +1,4 @@ -// RUN: clang-cc -rewrite-objc %s -o - +// RUN: clang -cc1 -rewrite-objc %s -o - @protocol P @end diff --git a/test/Rewriter/rewrite-foreach-2.m b/test/Rewriter/rewrite-foreach-2.m index 4de64bc87ded..5567d0169b93 100644 --- a/test/Rewriter/rewrite-foreach-2.m +++ b/test/Rewriter/rewrite-foreach-2.m @@ -1,4 +1,4 @@ -// RUN: clang-cc -rewrite-objc %s -o - +// RUN: clang -cc1 -rewrite-objc %s -o - @protocol P @end diff --git a/test/Rewriter/rewrite-foreach-3.m b/test/Rewriter/rewrite-foreach-3.m index 0de31021d820..804f0204f5e9 100644 --- a/test/Rewriter/rewrite-foreach-3.m +++ b/test/Rewriter/rewrite-foreach-3.m @@ -1,4 +1,4 @@ -// RUN: clang-cc -rewrite-objc %s -o - +// RUN: clang -cc1 -rewrite-objc %s -o - @protocol P @end diff --git a/test/Rewriter/rewrite-foreach-4.m b/test/Rewriter/rewrite-foreach-4.m index 70f3eb874497..9870690325b2 100644 --- a/test/Rewriter/rewrite-foreach-4.m +++ b/test/Rewriter/rewrite-foreach-4.m @@ -1,4 +1,4 @@ -// RUN: clang-cc -rewrite-objc %s -o - +// RUN: clang -cc1 -rewrite-objc %s -o - @interface MyList - (id) allKeys; diff --git a/test/Rewriter/rewrite-foreach-5.m b/test/Rewriter/rewrite-foreach-5.m index 14d18d130d89..141cb6a2c0aa 100644 --- a/test/Rewriter/rewrite-foreach-5.m +++ b/test/Rewriter/rewrite-foreach-5.m @@ -1,4 +1,4 @@ -// RUN: clang-cc -rewrite-objc %s -o - +// RUN: clang -cc1 -rewrite-objc %s -o - @interface MyList - (id) allKeys; diff --git a/test/Rewriter/rewrite-foreach-6.m b/test/Rewriter/rewrite-foreach-6.m index 66d411001e13..bbc9a94a13f9 100644 --- a/test/Rewriter/rewrite-foreach-6.m +++ b/test/Rewriter/rewrite-foreach-6.m @@ -1,4 +1,4 @@ -// RUN: clang-cc %s -rewrite-objc -o - +// RUN: clang -cc1 %s -rewrite-objc -o - // rdar://5716356 // FIXME: Should be able to pipe into clang, but code is not // yet correct for other reasons: rdar://5716940 diff --git a/test/Rewriter/rewrite-nest.m b/test/Rewriter/rewrite-nest.m index e35baf6ce852..594e1b1629a9 100644 --- a/test/Rewriter/rewrite-nest.m +++ b/test/Rewriter/rewrite-nest.m @@ -1,4 +1,4 @@ -// RUN: clang-cc -rewrite-objc %s -o - +// RUN: clang -cc1 -rewrite-objc %s -o - @interface NSMapTable @end @interface NSEnumerator @end diff --git a/test/Rewriter/rewrite-protocol-type-1.m b/test/Rewriter/rewrite-protocol-type-1.m index 63b605d7ed61..e46a3badfeef 100644 --- a/test/Rewriter/rewrite-protocol-type-1.m +++ b/test/Rewriter/rewrite-protocol-type-1.m @@ -1,4 +1,4 @@ -// RUN: clang-cc -rewrite-objc %s -o - +// RUN: clang -cc1 -rewrite-objc %s -o - @protocol MyProto1 @end diff --git a/test/Rewriter/rewrite-try-catch.m b/test/Rewriter/rewrite-try-catch.m index f69e8ef35496..e9b002b2be39 100644 --- a/test/Rewriter/rewrite-try-catch.m +++ b/test/Rewriter/rewrite-try-catch.m @@ -1,4 +1,4 @@ -// RUN: clang-cc -rewrite-objc %s -o - +// RUN: clang -cc1 -rewrite-objc %s -o - @interface Foo @end @interface GARF @end diff --git a/test/Rewriter/static-type-protocol-1.m b/test/Rewriter/static-type-protocol-1.m index 986627d37a89..735c94278dc5 100644 --- a/test/Rewriter/static-type-protocol-1.m +++ b/test/Rewriter/static-type-protocol-1.m @@ -1,4 +1,4 @@ -// RUN: clang-cc -rewrite-objc %s -o - +// RUN: clang -cc1 -rewrite-objc %s -o - @protocol Proto - (void) ProtoDidget; diff --git a/test/Rewriter/undecl-objc-h.m b/test/Rewriter/undecl-objc-h.m index 12f38112c9cd..b68c6b175705 100644 --- a/test/Rewriter/undecl-objc-h.m +++ b/test/Rewriter/undecl-objc-h.m @@ -1,4 +1,4 @@ -// RUN: clang-cc -rewrite-objc %s -o - +// RUN: clang -cc1 -rewrite-objc %s -o - typedef struct S { int * pint; diff --git a/test/Rewriter/undeclared-method-1.m b/test/Rewriter/undeclared-method-1.m index 499d9114e1a7..6c1460d02ec8 100644 --- a/test/Rewriter/undeclared-method-1.m +++ b/test/Rewriter/undeclared-method-1.m @@ -1,4 +1,4 @@ -// RUN: clang-cc -rewrite-objc %s -o - +// RUN: clang -cc1 -rewrite-objc %s -o - @interface Derived @end diff --git a/test/Rewriter/undef-field-reference-1.m b/test/Rewriter/undef-field-reference-1.m index 17f448dcae20..ef80c26d7c50 100644 --- a/test/Rewriter/undef-field-reference-1.m +++ b/test/Rewriter/undef-field-reference-1.m @@ -1,4 +1,4 @@ -// RUN: clang-cc -rewrite-objc %s -o - +// RUN: clang -cc1 -rewrite-objc %s -o - @interface MyDerived { diff --git a/test/Rewriter/va-method.m b/test/Rewriter/va-method.m index b4fdac553ded..f808b8f59641 100644 --- a/test/Rewriter/va-method.m +++ b/test/Rewriter/va-method.m @@ -1,4 +1,4 @@ -// RUN: clang-cc -rewrite-objc %s -o - +// RUN: clang -cc1 -rewrite-objc %s -o - #include diff --git a/test/Sema/block-as-object.m b/test/Sema/block-as-object.m index 219b1a065325..1197a1972fec 100644 --- a/test/Sema/block-as-object.m +++ b/test/Sema/block-as-object.m @@ -1,4 +1,4 @@ -// RUN: clang-cc %s -fsyntax-only -verify -fblocks +// RUN: clang -cc1 %s -fsyntax-only -verify -fblocks @interface Whatever - copy; diff --git a/test/Sema/builtin-prefetch.c b/test/Sema/builtin-prefetch.c index bf28277acb81..4ee9f8947bbb 100644 --- a/test/Sema/builtin-prefetch.c +++ b/test/Sema/builtin-prefetch.c @@ -6,7 +6,8 @@ void foo() { __builtin_prefetch(&a, 1); __builtin_prefetch(&a, 1, 2); __builtin_prefetch(&a, 1, 9, 3); // expected-error{{too many arguments to function}} - __builtin_prefetch(&a, "hello", 2); // expected-error{{argument to __builtin_prefetch must be a constant integer}} + __builtin_prefetch(&a, "hello", 2); // expected-error{{argument to __builtin_prefetch must be of integer type}} + __builtin_prefetch(&a, a, 2); // expected-error{{argument to __builtin_prefetch must be a constant integer}} __builtin_prefetch(&a, 2); // expected-error{{argument should be a value from 0 to 1}} __builtin_prefetch(&a, 0, 4); // expected-error{{argument should be a value from 0 to 3}} __builtin_prefetch(&a, -1, 4); // expected-error{{argument should be a value from 0 to 1}} diff --git a/test/Sema/compare.c b/test/Sema/compare.c index 01a216ffec22..fa2d3a062ed1 100644 --- a/test/Sema/compare.c +++ b/test/Sema/compare.c @@ -225,3 +225,8 @@ int void_pointers(void* foo) { return foo == (void*) 0; return foo == (void*) 1; } + +int test1(int i) { + enum en { zero }; + return i > zero; +} diff --git a/test/Sema/exprs.c b/test/Sema/exprs.c index 299b0a267dc2..10fcde6e7576 100644 --- a/test/Sema/exprs.c +++ b/test/Sema/exprs.c @@ -111,4 +111,6 @@ test15_t test15(void) { return (test15_t)0 + (test15_t)0; // expected-error {{invalid operands to binary expression ('test15_t' (aka 'unsigned long *') and 'test15_t')}} } +// rdar://7446395 +void test16(float x) { x == ((void*) 0); } // expected-error {{invalid operands to binary expression}} diff --git a/test/Sema/init.c b/test/Sema/init.c index 840b24fd30b0..4ba6867d0b0f 100644 --- a/test/Sema/init.c +++ b/test/Sema/init.c @@ -126,3 +126,7 @@ uintptr_t ptrasintadd3 = 4 + (uintptr_t)&a; // PR4285 const wchar_t widestr[] = L"asdf"; + +// PR5447 +const double pr5447 = (0.05 < -1.0) ? -1.0 : 0.0499878; + diff --git a/test/Sema/ms-fuzzy-asm.c b/test/Sema/ms-fuzzy-asm.c index 58dcbcfc5232..2113949f237b 100644 --- a/test/Sema/ms-fuzzy-asm.c +++ b/test/Sema/ms-fuzzy-asm.c @@ -6,4 +6,4 @@ void t1(void) { M } void t2(void) { __asm int 0x2c } void t3(void) { __asm M2 0x2c } - +void* t4(void) { __asm mov eax, fs:[0x10] } diff --git a/test/Sema/nested-redef.c b/test/Sema/nested-redef.c index ea180910128b..54a970f04421 100644 --- a/test/Sema/nested-redef.c +++ b/test/Sema/nested-redef.c @@ -1,6 +1,7 @@ // RUN: clang-cc -fsyntax-only -verify %s struct X { // expected-note{{previous definition is here}} - struct X { } x; // expected-error{{nested redefinition of 'X'}} + struct X { } x; // expected-error{{nested redefinition of 'X'}} \ + // expected-error{{field has incomplete type}} }; struct Y { }; diff --git a/test/Sema/rdar6248119.m b/test/Sema/rdar6248119.m index 631c7b35a992..d4ee305c2912 100644 --- a/test/Sema/rdar6248119.m +++ b/test/Sema/rdar6248119.m @@ -1,4 +1,4 @@ -// RUN: clang-cc -fsyntax-only %s -verify +// RUN: clang -cc1 -fsyntax-only %s -verify // Test case for: // @finally doesn't introduce a new scope diff --git a/test/Sema/return.c b/test/Sema/return.c index ad75cf1a0b6d..2e8120a7542e 100644 --- a/test/Sema/return.c +++ b/test/Sema/return.c @@ -222,3 +222,7 @@ void test32() { void test33() { if (j) while (1) { } } + +int test34() { + asm("nop"); +} diff --git a/test/Sema/vector-init.c b/test/Sema/vector-init.c index 9dac6c7114da..1eec6c57a68c 100644 --- a/test/Sema/vector-init.c +++ b/test/Sema/vector-init.c @@ -16,10 +16,15 @@ float4 array2[2] = { 1.0, 2.0, 3.0, 4.0, 5.0, 6.0, 7.0, 8.0, float4 array3[2] = { {1.0, 2.0, 3.0}, 5.0, 6.0, 7.0, 8.0, 9.0 }; // expected-warning {{excess elements in array initializer}} +// PR5650 +__attribute__((vector_size(16))) float f1(void) { + __attribute__((vector_size(16))) float vec = {0.0f, 0.0f, 0.0f}; + return(vec); +} -// rdar://6881069 -__attribute__((vector_size(16))) // expected-error {{unsupported type 'float (void)' for vector_size attribute, please use on typedef}} -float f1(void) { +__attribute__((vector_size(16))) float f2( + __attribute__((vector_size(16))) float a1) { + return(a1); } diff --git a/test/SemaCXX/array-bound-merge.cpp b/test/SemaCXX/array-bound-merge.cpp new file mode 100644 index 000000000000..579c7933684d --- /dev/null +++ b/test/SemaCXX/array-bound-merge.cpp @@ -0,0 +1,9 @@ +// RUN: clang-cc -fsyntax-only -verify %s +// PR5515 + +extern int a[]; +int a[10]; +extern int b[10]; +int b[]; +extern int c[1]; +int c[] = {1,2}; // expected-error {{excess elements in array initializer}} diff --git a/test/SemaCXX/attr-cxx0x.cpp b/test/SemaCXX/attr-cxx0x.cpp index da52d338cfbc..d68779cc8886 100644 --- a/test/SemaCXX/attr-cxx0x.cpp +++ b/test/SemaCXX/attr-cxx0x.cpp @@ -2,7 +2,7 @@ int final_fail [[final]]; //expected-error {{'final' attribute only applies to virtual method or class types}} -struct [[final]] final_base { }; // expected-note {{struct final_base declared here}} +struct [[final]] final_base { }; // expected-note {{'struct final_base' declared here}} struct final_child : final_base { }; // expected-error {{derivation from 'final' struct final_base}} struct final_member { virtual void quux [[final]] (); }; // expected-note {{overridden virtual function is here}} @@ -33,4 +33,4 @@ struct base { }; struct [[base_check, base_check]] bc : base { // expected-error {{'base_check' attribute cannot be repeated}} -}; \ No newline at end of file +}; diff --git a/test/SemaCXX/attr-noreturn.cpp b/test/SemaCXX/attr-noreturn.cpp new file mode 100644 index 000000000000..e4fdc08ae9e7 --- /dev/null +++ b/test/SemaCXX/attr-noreturn.cpp @@ -0,0 +1,30 @@ +// RUN: clang-cc -fsyntax-only -verify %s + +// PR5620 +void f0() __attribute__((__noreturn__)); +void f1(void (*)()); +void f2() { f1(f0); } + +// Taking the address of a noreturn function +void test_f0a() { + void (*fp)() = f0; + void (*fp1)() __attribute__((noreturn)) = f0; +} + +// Taking the address of an overloaded noreturn function +void f0(int) __attribute__((__noreturn__)); + +void test_f0b() { + void (*fp)() = f0; + void (*fp1)() __attribute__((noreturn)) = f0; +} + +// No-returned function pointers +typedef void (* noreturn_fp)() __attribute__((noreturn)); + +void f3(noreturn_fp); // expected-note{{candidate function}} + +void test_f3() { + f3(f0); // okay + f3(f2); // expected-error{{no matching function for call}} +} diff --git a/test/SemaCXX/compare.cpp b/test/SemaCXX/compare.cpp index e38b6b312f98..7188678b74db 100644 --- a/test/SemaCXX/compare.cpp +++ b/test/SemaCXX/compare.cpp @@ -49,8 +49,8 @@ int test0(long a, unsigned long b) { ((signed char) A == (unsigned char) b) + (A < (unsigned long) b) + (A < (unsigned int) b) + - (A < (unsigned short) b) + // expected-warning {{comparison of integers of different signs}} - (A < (unsigned char) b) + // expected-warning {{comparison of integers of different signs}} + (A < (unsigned short) b) + + (A < (unsigned char) b) + ((long) A < b) + ((int) A < b) + ((short) A < b) + @@ -78,9 +78,9 @@ int test0(long a, unsigned long b) { (a < (unsigned short) B) + (a < (unsigned char) B) + ((long) a < B) + - ((int) a < B) + // expected-warning {{comparison of integers of different signs}} - ((short) a < B) + // expected-warning {{comparison of integers of different signs}} - ((signed char) a < B) + // expected-warning {{comparison of integers of different signs}} + ((int) a < B) + + ((short) a < B) + + ((signed char) a < B) + ((long) a < (unsigned long) B) + // expected-warning {{comparison of integers of different signs}} ((int) a < (unsigned int) B) + // expected-warning {{comparison of integers of different signs}} ((short) a < (unsigned short) B) + // expected-warning {{comparison of integers of different signs}} @@ -101,8 +101,8 @@ int test0(long a, unsigned long b) { ((signed char) C == (unsigned char) b) + (C < (unsigned long) b) + (C < (unsigned int) b) + - (C < (unsigned short) b) + // expected-warning {{comparison of integers of different signs}} - (C < (unsigned char) b) + // expected-warning {{comparison of integers of different signs}} + (C < (unsigned short) b) + + (C < (unsigned char) b) + ((long) C < b) + ((int) C < b) + ((short) C < b) + @@ -130,9 +130,9 @@ int test0(long a, unsigned long b) { (a < (unsigned short) C) + (a < (unsigned char) C) + ((long) a < C) + - ((int) a < C) + // expected-warning {{comparison of integers of different signs}} - ((short) a < C) + // expected-warning {{comparison of integers of different signs}} - ((signed char) a < C) + // expected-warning {{comparison of integers of different signs}} + ((int) a < C) + + ((short) a < C) + + ((signed char) a < C) + ((long) a < (unsigned long) C) + // expected-warning {{comparison of integers of different signs}} ((int) a < (unsigned int) C) + // expected-warning {{comparison of integers of different signs}} ((short) a < (unsigned short) C) + // expected-warning {{comparison of integers of different signs}} @@ -193,3 +193,8 @@ int test0(long a, unsigned long b) { 10 ; } + +int test1(int i) { + enum en { zero }; + return i > zero; +} diff --git a/test/SemaCXX/convert-to-bool.cpp b/test/SemaCXX/convert-to-bool.cpp index 937b2729d1c3..277bfc6c6888 100644 --- a/test/SemaCXX/convert-to-bool.cpp +++ b/test/SemaCXX/convert-to-bool.cpp @@ -49,7 +49,7 @@ void test_explicit_bool(ExplicitConvToBool ecb) { } void test_explicit_conv_to_ref(ExplicitConvToRef ecr) { - int& i1 = ecr; // expected-error{{non-const lvalue reference to type 'int' cannot be initialized with a value of type 'struct ExplicitConvToRef'}} + int& i1 = ecr; // expected-error{{non-const lvalue reference to type 'int' cannot bind to a value of unrelated type 'struct ExplicitConvToRef'}} int& i2(ecr); // okay } @@ -57,11 +57,11 @@ struct A { }; struct B { }; struct C { explicit operator A&(); // expected-warning{{explicit conversion functions are a C++0x extension}} - operator B&(); + operator B&(); // expected-note{{candidate}} }; void test_copy_init_conversions(C c) { - A &a = c; // expected-error{{non-const lvalue reference to type 'struct A' cannot be initialized with a value of type 'struct C'}} + A &a = c; // expected-error{{no viable conversion from 'struct C' to 'struct A'}} B &b = b; // okay } diff --git a/test/SemaCXX/decl-init-ref.cpp b/test/SemaCXX/decl-init-ref.cpp index d7db647cd11a..20eb91a608ca 100644 --- a/test/SemaCXX/decl-init-ref.cpp +++ b/test/SemaCXX/decl-init-ref.cpp @@ -1,6 +1,6 @@ // RUN: clang-cc -fsyntax-only -verify -std=c++0x %s -struct A {}; +struct A {}; // expected-note {{candidate function}} struct BASE { operator A(); // expected-note {{candidate function}} @@ -21,6 +21,6 @@ extern B f(); const int& ri = (void)0; // expected-error {{invalid initialization of reference of type 'int const &' from expression of type 'void'}} int main() { - const A& rca = f(); // expected-error {{rvalue reference cannot bind to lvalue due to multiple conversion functions}} - A& ra = f(); // expected-error {{non-const lvalue reference to type 'struct A' cannot be initialized with a temporary of type 'class B'}} + const A& rca = f(); // expected-error {{conversion from 'class B' to 'struct A const' is ambiguous}} + A& ra = f(); // expected-error {{non-const lvalue reference to type 'struct A' cannot bind to a temporary of type 'class B'}} } diff --git a/test/SemaCXX/default-assignment-operator.cpp b/test/SemaCXX/default-assignment-operator.cpp index e627fefdef6d..0377657a82d2 100644 --- a/test/SemaCXX/default-assignment-operator.cpp +++ b/test/SemaCXX/default-assignment-operator.cpp @@ -1,7 +1,6 @@ // RUN: clang-cc -fsyntax-only -verify %s -class Base { // expected-error {{cannot define the implicit default assignment operator for 'class Base'}} \ - // expected-note {{synthesized method is first required here}} +class Base { // expected-error {{cannot define the implicit default assignment operator for 'class Base'}} int &ref; // expected-note {{declared at}} }; @@ -26,7 +25,7 @@ Z z2; // Test1 void f(X x, const X cx) { - x = cx; // expected-note {{synthesized method is first required here}} + x = cx; // expected-note 2 {{synthesized method is first required here}} x = cx; z1 = z2; } diff --git a/test/SemaCXX/enum.cpp b/test/SemaCXX/enum.cpp index db256812ab80..3315de00ca83 100644 --- a/test/SemaCXX/enum.cpp +++ b/test/SemaCXX/enum.cpp @@ -1,4 +1,5 @@ // RUN: clang-cc -fsyntax-only -verify %s + enum E { Val1, Val2 @@ -25,13 +26,42 @@ void bar() { /// PR3688 struct s1 { - enum e1 (*bar)(void); // expected-error{{ISO C++ forbids forward references to 'enum' types}} expected-note{{forward declaration of 'enum s1::e1'}} + enum e1 (*bar)(void); // expected-error{{ISO C++ forbids forward references to 'enum' types}} }; enum e1 { YES, NO }; static enum e1 badfunc(struct s1 *q) { - return q->bar(); // expected-error{{calling function with incomplete return type 'enum s1::e1'}} + return q->bar(); } enum e2; // expected-error{{ISO C++ forbids forward references to 'enum' types}} + +namespace test1 { + template struct is_same { static const int value = -1; }; + template struct is_same { static const int value = 1; }; + + enum enum0 { v0 }; + int test0[is_same::value]; + + enum enum1 { v1 = __INT_MAX__ }; + int test1[is_same::value]; + + enum enum2 { v2 = __INT_MAX__ * 2U }; + int test2[is_same::value]; + + // This kindof assumes that 'int' is smaller than 'long long'. +#if defined(__LP64__) + enum enum3 { v3 = __LONG_LONG_MAX__ }; + int test3[is_same::value]; + + enum enum4 { v4 = __LONG_LONG_MAX__ * 2ULL }; + int test4[is_same::value]; +#else + enum enum3 { v3 = __LONG_LONG_MAX__ }; + int test3[is_same::value]; + + enum enum4 { v4 = __LONG_LONG_MAX__ * 2ULL }; + int test4[is_same::value]; +#endif +} diff --git a/test/SemaCXX/exception-spec.cpp b/test/SemaCXX/exception-spec.cpp index 56cc435f7db3..efc983322ae5 100644 --- a/test/SemaCXX/exception-spec.cpp +++ b/test/SemaCXX/exception-spec.cpp @@ -186,5 +186,18 @@ template struct TEx; // expected-note {{template is declared here}} void tf() throw(TEx); // expected-error {{implicit instantiation of undefined template}} -// DR 437, class throws itself. FIXME: See Sema::CheckSpecifiedExceptionType. -//struct DR437 { void f() throw(DR437); }; +// DR 437, class throws itself. +struct DR437 { + void f() throw(DR437); + void g() throw(DR437*); + void h() throw(DR437&); +}; + +// DR 437 within a nested class +struct DR437_out { + struct DR437_in { + void f() throw(DR437_out); + void g() throw(DR437_out*); + void h() throw(DR437_out&); + }; +}; diff --git a/test/SemaCXX/friend.cpp b/test/SemaCXX/friend.cpp index 76e84e5fbe84..d1c42eb9fbb5 100644 --- a/test/SemaCXX/friend.cpp +++ b/test/SemaCXX/friend.cpp @@ -4,3 +4,14 @@ friend class A; // expected-error {{'friend' used outside of class}} void f() { friend class A; } // expected-error {{'friend' used outside of class}} class C { friend class A; }; class D { void f() { friend class A; } }; // expected-error {{'friend' used outside of class}} + +// PR5760 +namespace test0 { + namespace ns { + void f(int); + } + + struct A { + friend void ns::f(int a); + }; +} diff --git a/test/SemaCXX/i-c-e-cxx.cpp b/test/SemaCXX/i-c-e-cxx.cpp index 785ea0efa401..b7db907e2216 100644 --- a/test/SemaCXX/i-c-e-cxx.cpp +++ b/test/SemaCXX/i-c-e-cxx.cpp @@ -14,3 +14,10 @@ void f() { int array[value]; } } + +int a() { + const int t=t; // expected-note {{subexpression not valid}} + switch(1) { + case t:; // expected-error {{not an integer constant expression}} + } +} diff --git a/test/SemaCXX/implicit-member-functions.cpp b/test/SemaCXX/implicit-member-functions.cpp new file mode 100644 index 000000000000..186780833d39 --- /dev/null +++ b/test/SemaCXX/implicit-member-functions.cpp @@ -0,0 +1,14 @@ +// RUN: clang-cc -fsyntax-only -verify %s + +struct A { }; // expected-note {{previous implicit declaration is here}} +A::A() { } // expected-error {{definition of implicitly declared constructor}} + +struct B { }; // expected-note {{previous implicit declaration is here}} +B::B(const B&) { } // expected-error {{definition of implicitly declared copy constructor}} + +struct C { }; // expected-note {{previous implicit declaration is here}} +C& C::operator=(const C&) { return *this; } // expected-error {{definition of implicitly declared copy assignment operator}} + +struct D { }; // expected-note {{previous implicit declaration is here}} +D::~D() { } // expected-error {{definition of implicitly declared destructor}} + diff --git a/test/SemaCXX/implicit-virtual-member-functions.cpp b/test/SemaCXX/implicit-virtual-member-functions.cpp new file mode 100644 index 000000000000..30fe2786ba46 --- /dev/null +++ b/test/SemaCXX/implicit-virtual-member-functions.cpp @@ -0,0 +1,29 @@ +// RUN: clang-cc -fsyntax-only -verify %s +struct A { + virtual ~A(); +}; + +struct B : A { // expected-error {{no suitable member 'operator delete' in 'B'}} + virtual void f(); + + void operator delete (void *, int); // expected-note {{'operator delete' declared here}} +}; + +void B::f() { // expected-note {{implicit default destructor for 'struct B' first required here}} +} + +struct C : A { // expected-error {{no suitable member 'operator delete' in 'C'}} + C(); + void operator delete(void *, int); // expected-note {{'operator delete' declared here}} +}; + +C::C() { } // expected-note {{implicit default destructor for 'struct C' first required here}} + +struct D : A { // expected-error {{no suitable member 'operator delete' in 'D'}} + void operator delete(void *, int); // expected-note {{'operator delete' declared here}} +}; + +void f() { + new D; // expected-note {{implicit default destructor for 'struct D' first required here}} +} + diff --git a/test/SemaCXX/linkage-spec.cpp b/test/SemaCXX/linkage-spec.cpp index fc9b3ab51ead..d19727ac0766 100644 --- a/test/SemaCXX/linkage-spec.cpp +++ b/test/SemaCXX/linkage-spec.cpp @@ -40,3 +40,17 @@ namespace pr5430 { } using namespace pr5430; extern "C" void pr5430::func(void) { } + +// PR5404 +int f2(char *) +{ + return 0; +} + +extern "C" +{ + int f2(int) + { + return f2((char *)0); + } +} diff --git a/test/SemaCXX/literal-type.cpp b/test/SemaCXX/literal-type.cpp new file mode 100644 index 000000000000..0dca9c9a92b3 --- /dev/null +++ b/test/SemaCXX/literal-type.cpp @@ -0,0 +1,10 @@ +// RUN: clang-cc -fsyntax-only -verify -std=c++0x %s + +static_assert(__is_literal(int), "fail"); +static_assert(__is_literal(void*), "fail"); +enum E { E1 }; +static_assert(__is_literal(E), "fail"); +static_assert(__is_literal(decltype(E1)), "fail"); +typedef int IAR[10]; +static_assert(__is_literal(IAR), "fail"); +// FIXME: Records diff --git a/test/SemaCXX/member-expr-anonymous-union.cpp b/test/SemaCXX/member-expr-anonymous-union.cpp new file mode 100644 index 000000000000..9566df4a20ff --- /dev/null +++ b/test/SemaCXX/member-expr-anonymous-union.cpp @@ -0,0 +1,9 @@ +// RUN: clang-cc %s -fsyntax-only -verify +// PR5543 + +struct A { int x; union { int* y; float& z; }; }; struct B : A {int a;}; +int* a(B* x) { return x->y; } + +struct x { union { int y; }; }; x y; template int f() { return X+y.y; } +int g() { return f<2>(); } + diff --git a/test/SemaCXX/member-expr.cpp b/test/SemaCXX/member-expr.cpp index cd13bcc3670e..9cd6855ccd55 100644 --- a/test/SemaCXX/member-expr.cpp +++ b/test/SemaCXX/member-expr.cpp @@ -41,3 +41,18 @@ void test2(X *xp) { xp->::i = 7; // expected-error{{qualified member access refers to a member in the global namespace}} xp->C::i = 7; // expected-error{{qualified member access refers to a member in namespace 'C'}} } + + +namespace test3 { + struct NamespaceDecl; + + struct NamedDecl { + void *getIdentifier() const; + }; + + struct NamespaceDecl : NamedDecl { + bool isAnonymousNamespace() const { + return !getIdentifier(); + } + }; +} diff --git a/test/SemaCXX/nested-name-spec.cpp b/test/SemaCXX/nested-name-spec.cpp index 83c72417d590..6a51261e26fc 100644 --- a/test/SemaCXX/nested-name-spec.cpp +++ b/test/SemaCXX/nested-name-spec.cpp @@ -186,12 +186,10 @@ class foo { }; -// PR4452 -// FIXME: This error recovery sucks. -foo a2; // expected-error {{unexpected namespace name 'somens': expected expression}} \ -expected-error {{C++ requires a type specifier for all declarations}} +// PR4452 / PR4451 +foo a2; // expected-error {{unexpected ':' in nested name specifier}} -somens::a a3 = a2; +somens::a a3 = a2; // expected-error {{cannot initialize 'a3' with an lvalue of type 'foo'}} diff --git a/test/SemaCXX/new-delete.cpp b/test/SemaCXX/new-delete.cpp index f2fe0a78e388..8a3ec8b16a26 100644 --- a/test/SemaCXX/new-delete.cpp +++ b/test/SemaCXX/new-delete.cpp @@ -140,10 +140,8 @@ class X5 { class Base { public: - static int operator new(signed char) throw(); // expected-error {{'operator new' takes type size_t}} \ - // expected-error {{operator new' must return type 'void *'}} - static int operator new[] (signed char) throw(); // expected-error {{'operator new[]' takes type size_t}} \ - // expected-error {{operator new[]' must return type 'void *'}} + static void *operator new(signed char) throw(); // expected-error {{'operator new' takes type size_t}} + static int operator new[] (size_t) throw(); // expected-error {{operator new[]' must return type 'void *'}} }; class Tier {}; @@ -160,9 +158,11 @@ void loadEngineFor() { } template struct TBase { - void* operator new(T size, int); // expected-error {{'operator new' takes type size_t}} + void* operator new(T size, int); // expected-error {{'operator new' cannot take a dependent type as first parameter; use size_t}}\ + // expected-error {{'operator new' takes type size_t}} }; +// FIXME: We should not try to instantiate operator new, since it is invalid. TBase t1; // expected-note {{in instantiation of template class 'struct TBase' requested here}} class X6 { @@ -202,3 +202,17 @@ struct X11 : X10 { // expected-error {{no suitable member 'operator delete' in ' void f() { X11 x11; // expected-note {{implicit default destructor for 'struct X11' first required here}} } + +struct X12 { + void* operator new(size_t, void*); +}; + +struct X13 : X12 { + using X12::operator new; +}; + +static void* f(void* g) +{ + return new (g) X13(); +} + diff --git a/test/SemaCXX/offsetof.cpp b/test/SemaCXX/offsetof.cpp index f0290e889a29..bc7a707ee546 100644 --- a/test/SemaCXX/offsetof.cpp +++ b/test/SemaCXX/offsetof.cpp @@ -13,3 +13,8 @@ void f() { int i = __builtin_offsetof(P, fieldThatPointsToANonPODType.m); // expected-warning{{offset of on non-POD type 'struct P'}} } +struct Base { int x; }; +struct Derived : Base { int y; }; +int o = __builtin_offsetof(Derived, x); // expected-warning{{offset of on non-POD type}} + +const int o2 = sizeof(__builtin_offsetof(Derived, x)); diff --git a/test/SemaCXX/overload-call-copycon.cpp b/test/SemaCXX/overload-call-copycon.cpp index 755e27adbac8..6436236b81e9 100644 --- a/test/SemaCXX/overload-call-copycon.cpp +++ b/test/SemaCXX/overload-call-copycon.cpp @@ -1,4 +1,4 @@ -// RUN: clang-cc -fsyntax-only %s +// RUN: clang-cc -fsyntax-only %s -Wnon-pod-varargs class X { }; int& copycon(X x); @@ -23,10 +23,10 @@ float& copycon2(...); void test_copycon2(A a, const A ac, B b, B const bc, B volatile bv) { int& i1 = copycon2(b); - float& f1 = copycon2(bc); - float& f2 = copycon2(bv); + float& f1 = copycon2(bc); // expected-warning {{cannot pass object of non-POD type}} + float& f2 = copycon2(bv); // expected-warning {{cannot pass object of non-POD type}} short& s1 = copycon2(a); - float& f3 = copycon2(ac); + float& f3 = copycon2(ac); // expected-warning {{cannot pass object of non-POD type}} } int& copycon3(A a); @@ -34,7 +34,7 @@ float& copycon3(...); void test_copycon3(B b, const B bc) { int& i1 = copycon3(b); - float& f1 = copycon3(bc); + float& f1 = copycon3(bc); // expected-warning {{cannot pass object of non-POD type}} } diff --git a/test/SemaCXX/overload-call.cpp b/test/SemaCXX/overload-call.cpp index 3a0bf3008d6c..5d2718208f2b 100644 --- a/test/SemaCXX/overload-call.cpp +++ b/test/SemaCXX/overload-call.cpp @@ -92,7 +92,7 @@ enum PromotesToInt { }; enum PromotesToUnsignedInt { - PromotesToUnsignedIntValue = 1u + PromotesToUnsignedIntValue = __INT_MAX__ * 2U }; int* o(int); @@ -291,3 +291,13 @@ void f(SR) { } void g(opt o) { f(o); } + + +namespace PR5756 { + int &a(void*, int); + float &a(void*, float); + void b() { + int &ir = a(0,0); + (void)ir; + } +} diff --git a/test/SemaCXX/overloaded-operator.cpp b/test/SemaCXX/overloaded-operator.cpp index 16d37040f140..672b8b4fc266 100644 --- a/test/SemaCXX/overloaded-operator.cpp +++ b/test/SemaCXX/overloaded-operator.cpp @@ -67,7 +67,7 @@ void enum_test(Enum1 enum1, Enum2 enum2, E1 e1, E2 e2) { float &f1 = (e1 == e2); float &f2 = (enum1 == e2); float &f3 = (e1 == enum2); - float &f4 = (enum1 == enum2); // expected-error{{non-const lvalue reference to type 'float' cannot be initialized with a temporary of type 'bool'}} + float &f4 = (enum1 == enum2); // expected-error{{non-const lvalue reference to type 'float' cannot bind to a temporary of type 'bool'}} } // PR5244 - Argument-dependent lookup would include the two operators below, diff --git a/test/SemaCXX/prefetch-enum.cpp b/test/SemaCXX/prefetch-enum.cpp new file mode 100644 index 000000000000..829321fb0e91 --- /dev/null +++ b/test/SemaCXX/prefetch-enum.cpp @@ -0,0 +1,9 @@ +// RUN: clang-cc -fsyntax-only %s -verify +// PR5679 + +enum X { A = 3 }; + +void Test() { + char ch; + __builtin_prefetch(&ch, 0, A); +} diff --git a/test/SemaCXX/qualified-id-lookup.cpp b/test/SemaCXX/qualified-id-lookup.cpp index 254a18de1f32..5a11a0cd07b8 100644 --- a/test/SemaCXX/qualified-id-lookup.cpp +++ b/test/SemaCXX/qualified-id-lookup.cpp @@ -109,3 +109,18 @@ struct Undef { // expected-note{{definition of 'struct Undef' is not complete un int Undef::f() { return sizeof(Undef); } + +// PR clang/5667 +namespace test1 { + template struct is_class { + enum { value = 0 }; + }; + + template class ClassChecker { + bool isClass() { + return is_class::value; + } + }; + + template class ClassChecker; +} diff --git a/test/SemaCXX/ref-init-ambiguous.cpp b/test/SemaCXX/ref-init-ambiguous.cpp index dda1ead7b622..60620993b43c 100644 --- a/test/SemaCXX/ref-init-ambiguous.cpp +++ b/test/SemaCXX/ref-init-ambiguous.cpp @@ -3,18 +3,19 @@ enum E2 { }; struct A { - operator E2&(); // expected-note 3 {{candidate function}} + operator E2&(); // expected-note 2 {{candidate function}} }; struct B { - operator E2&(); // expected-note 3 {{candidate function}} + operator E2&(); // expected-note 2 {{candidate function}} }; struct C : B, A { }; void test(C c) { - const E2 &e2 = c; // expected-error {{reference initialization of type 'enum E2 const &' with initializer of type 'struct C' is ambiguous}} + // FIXME: state that there was an ambiguity in the conversion! + const E2 &e2 = c; // expected-error {{reference to type 'enum E2 const' could not bind to an lvalue of type 'struct C'}} } void foo(const E2 &); diff --git a/test/SemaCXX/references.cpp b/test/SemaCXX/references.cpp index e03abf4300a3..45d3923ff0ad 100644 --- a/test/SemaCXX/references.cpp +++ b/test/SemaCXX/references.cpp @@ -44,17 +44,17 @@ B fB(); // C++ [dcl.init.ref]p5b2 void test4() { - double& rd2 = 2.0; // expected-error{{non-const lvalue reference to type 'double' cannot be initialized with a temporary of type 'double'}} + double& rd2 = 2.0; // expected-error{{non-const lvalue reference to type 'double' cannot bind to a temporary of type 'double'}} int i = 2; - double& rd3 = i; // expected-error{{non-const lvalue reference to type 'double' cannot be initialized with a value of type 'int'}} + double& rd3 = i; // expected-error{{non-const lvalue reference to type 'double' cannot bind to a value of unrelated type 'int'}} const A& rca = fB(); } void test5() { - const double& rcd2 = 2; // rcd2 refers to temporary with value 2.0 + // const double& rcd2 = 2; // rcd2 refers to temporary with value 2.0 const volatile int cvi = 1; - const int& r = cvi; // expected-error{{initialization of reference to type 'int const' with a value of type 'int const volatile' drops qualifiers}} + const int& r = cvi; // expected-error{{binding of reference to type 'int const' to a value of type 'int const volatile' drops qualifiers}} } // C++ [dcl.init.ref]p3 diff --git a/test/SemaCXX/rval-references.cpp b/test/SemaCXX/rval-references.cpp index 5132c2a69beb..7a71607707c8 100644 --- a/test/SemaCXX/rval-references.cpp +++ b/test/SemaCXX/rval-references.cpp @@ -44,7 +44,7 @@ void f() { conv_to_not_int_rvalue cnir; not_int &&ni4 = cnir; // expected-error {{rvalue reference cannot bind to lvalue}} - not_int &ni5 = cnir; // expected-error{{non-const lvalue reference to type 'struct not_int' cannot be initialized with a value of type 'struct conv_to_not_int_rvalue'}} + not_int &ni5 = cnir; // expected-error{{non-const lvalue reference to type 'struct not_int' cannot bind to a value of unrelated type 'struct conv_to_not_int_rvalue'}} not_int &&ni6 = conv_to_not_int_rvalue(); diff --git a/test/SemaCXX/type-traits.cpp b/test/SemaCXX/type-traits.cpp index 340c0ae4899b..dfb4edce67c8 100644 --- a/test/SemaCXX/type-traits.cpp +++ b/test/SemaCXX/type-traits.cpp @@ -250,3 +250,11 @@ void has_trivial_destructor() { int t17[T(__has_trivial_destructor(NonPODAr))]; int t18[T(__has_trivial_destructor(VirtAr))]; } + +struct A { ~A() {} }; +template struct B : A { }; + +void f() { + int t01[T(!__has_trivial_destructor(A))]; + int t02[T(!__has_trivial_destructor(B))]; +} \ No newline at end of file diff --git a/test/SemaCXX/using-decl-1.cpp b/test/SemaCXX/using-decl-1.cpp index 42deb27027bf..0235624a8ea5 100644 --- a/test/SemaCXX/using-decl-1.cpp +++ b/test/SemaCXX/using-decl-1.cpp @@ -38,3 +38,7 @@ struct X1 : X0 { (*this)(1); } }; + +struct A { void f(); }; +struct B : A { }; +class C : B { using B::f; }; diff --git a/test/SemaCXX/using-decl-templates.cpp b/test/SemaCXX/using-decl-templates.cpp index 684009b78a43..a19223d479d0 100644 --- a/test/SemaCXX/using-decl-templates.cpp +++ b/test/SemaCXX/using-decl-templates.cpp @@ -10,7 +10,7 @@ template struct B : A { using A::N; // expected-error{{dependent using declaration resolved to type without 'typename'}} using A::foo; // expected-error{{no member named 'foo'}} - using A::f; // expected-error{{using declaration refers into 'A::', which is not a base class of 'B'}} + using A::f; // expected-error{{using declaration refers into 'A::', which is not a base class of 'B'}} }; B a; // expected-note{{in instantiation of template class 'struct B' requested here}} @@ -34,3 +34,14 @@ template struct E : A { void g() { f(); } }; + +namespace test0 { + struct Base { + int foo; + }; + template struct E : Base { + using Base::foo; + }; + + template struct E; +} diff --git a/test/SemaCXX/using-directive.cpp b/test/SemaCXX/using-directive.cpp index 51f347dc7a73..b7583f27cb64 100644 --- a/test/SemaCXX/using-directive.cpp +++ b/test/SemaCXX/using-directive.cpp @@ -112,3 +112,12 @@ using namespace Alias; void testAlias() { inAliased(); } + +namespace N { void f2(int); } + +extern "C++" { + using namespace N; + void f3() { f2(1); } +} + +void f4() { f2(1); } diff --git a/test/SemaCXX/vararg-non-pod.cpp b/test/SemaCXX/vararg-non-pod.cpp index 977df144fa11..f913531a27d0 100644 --- a/test/SemaCXX/vararg-non-pod.cpp +++ b/test/SemaCXX/vararg-non-pod.cpp @@ -1,4 +1,4 @@ -// RUN: clang-cc -fsyntax-only -verify -fblocks %s +// RUN: clang-cc -fsyntax-only -verify -fblocks %s -Wnon-pod-varargs extern char version[]; @@ -66,3 +66,25 @@ void t5() E e(10, c); // expected-warning{{cannot pass object of non-POD type 'class C' through variadic constructor; call will abort at runtime}} (void)E(10, c); // expected-warning{{cannot pass object of non-POD type 'class C' through variadic constructor; call will abort at runtime}} } + +// PR5761: unevaluated operands and the non-POD warning +class Foo { + public: + Foo() {} +}; + +int Helper(...); +const int size = sizeof(Helper(Foo())); + +namespace std { + class type_info { }; +} + +struct Base { virtual ~Base(); }; +Base &get_base(...); +int eat_base(...); + +void test_typeid(Base &base) { + (void)typeid(get_base(base)); // expected-warning{{cannot pass object of non-POD type 'struct Base' through variadic function; call will abort at runtime}} + (void)typeid(eat_base(base)); // okay +} diff --git a/test/SemaCXX/virtual-member-functions-key-function.cpp b/test/SemaCXX/virtual-member-functions-key-function.cpp new file mode 100644 index 000000000000..4e7ff69b2edf --- /dev/null +++ b/test/SemaCXX/virtual-member-functions-key-function.cpp @@ -0,0 +1,22 @@ +// RUN: clang-cc -fsyntax-only -verify %s +struct A { + virtual ~A(); +}; + +struct B : A { // expected-error {{no suitable member 'operator delete' in 'B'}} + B() { } // expected-note {{implicit default destructor for 'struct B' first required here}} + void operator delete(void *, int); // expected-note {{'operator delete' declared here}} +}; + +struct C : A { // expected-error {{no suitable member 'operator delete' in 'C'}} + void operator delete(void *, int); // expected-note {{'operator delete' declared here}} +}; + +void f() { + // new B should mark the constructor as used, which then marks + // all the virtual members as used, because B has no key function. + (void)new B; + + // Same here, except that C has an implicit constructor. + (void)new C; // expected-note {{implicit default destructor for 'struct C' first required here}} +} diff --git a/test/SemaCXX/virtual-override.cpp b/test/SemaCXX/virtual-override.cpp index 4a3b10fa9764..c18a77f036bb 100644 --- a/test/SemaCXX/virtual-override.cpp +++ b/test/SemaCXX/virtual-override.cpp @@ -1,5 +1,4 @@ // RUN: clang-cc -fsyntax-only -faccess-control -verify %s - namespace T1 { class A { @@ -104,3 +103,50 @@ namespace T7 { virtual b* f(); }; } + +// PR5656 +class X0 { + virtual void f0(); +}; +class X1 : public X0 { + void f0() = 0; +}; + +template +struct Foo : Base { + void f(int) = 0; // expected-error{{not virtual and cannot be declared pure}} +}; + +struct Base1 { virtual void f(int); }; +struct Base2 { }; + +void test() { + (void)sizeof(Foo); + (void)sizeof(Foo); // expected-note{{instantiation}} +} + +template +struct Foo2 : Base { + template int f(T); +}; + +void test2() { + Foo2 f1; + Foo2 f2; + f1.f(17); + f2.f(17); +}; + +struct Foo3 { + virtual void f(int) = 0; // expected-note{{pure virtual function}} +}; + +template +struct Bar3 : Foo3 { + void f(T); +}; + +void test3() { + Bar3 b3i; // okay + Bar3 b3f; // expected-error{{is an abstract class}} +} diff --git a/test/SemaCXX/warn-missing-prototypes.cpp b/test/SemaCXX/warn-missing-prototypes.cpp new file mode 100644 index 000000000000..079a83725223 --- /dev/null +++ b/test/SemaCXX/warn-missing-prototypes.cpp @@ -0,0 +1,26 @@ +// RUN: clang-cc -fsyntax-only -verify -Wmissing-prototypes %s + +void f() { } // expected-warning {{no previous prototype for function 'f'}} + +namespace NS { + void f() { } // expected-warning {{no previous prototype for function 'f'}} +} + +namespace { + // Don't warn about functions in anonymous namespaces. + void f() { } +} + +struct A { + // Don't warn about member functions. + void f() { } +}; + +// Don't warn about inline functions. +inline void g() { } + +// Don't warn about function templates. +template void h() { } + +// Don't warn when instantiating function templates. +template void h(); diff --git a/test/SemaObjC/ContClassPropertyLookup.m b/test/SemaObjC/ContClassPropertyLookup.m index aa5afa7854f0..46bcc5365fdd 100644 --- a/test/SemaObjC/ContClassPropertyLookup.m +++ b/test/SemaObjC/ContClassPropertyLookup.m @@ -1,4 +1,4 @@ -// RUN: clang-cc -fsyntax-only -verify %s +// RUN: clang -cc1 -fsyntax-only -verify %s @interface MyObject { int _foo; diff --git a/test/SemaObjC/DoubleMethod.m b/test/SemaObjC/DoubleMethod.m index e43c1a0ab032..e92a017f2930 100644 --- a/test/SemaObjC/DoubleMethod.m +++ b/test/SemaObjC/DoubleMethod.m @@ -1,4 +1,4 @@ -// RUN: clang-cc -fsyntax-only -verify %s +// RUN: clang -cc1 -fsyntax-only -verify %s @interface Subclass { diff --git a/test/SemaObjC/access-property-getter.m b/test/SemaObjC/access-property-getter.m index 225d63b0173c..1bd5c33f5106 100644 --- a/test/SemaObjC/access-property-getter.m +++ b/test/SemaObjC/access-property-getter.m @@ -1,4 +1,4 @@ -// RUN: clang-cc -verify %s +// RUN: clang -cc1 -verify %s @protocol NSObject - (oneway void)release; diff --git a/test/SemaObjC/alias-test-1.m b/test/SemaObjC/alias-test-1.m index 39358cd62a6c..e946c3eb1ecb 100644 --- a/test/SemaObjC/alias-test-1.m +++ b/test/SemaObjC/alias-test-1.m @@ -1,4 +1,4 @@ -// RUN: clang-cc -fsyntax-only -verify %s +// RUN: clang -cc1 -fsyntax-only -verify %s @compatibility_alias alias4 foo; // expected-warning {{cannot find interface declaration for 'foo'}} diff --git a/test/SemaObjC/alias-test-2.m b/test/SemaObjC/alias-test-2.m index e0baf4e4d374..976e2a3758c7 100644 --- a/test/SemaObjC/alias-test-2.m +++ b/test/SemaObjC/alias-test-2.m @@ -1,4 +1,4 @@ -// RUN: clang-cc -fsyntax-only -verify %s +// RUN: clang -cc1 -fsyntax-only -verify %s // Note: GCC doesn't produce any of the following errors. @interface Super @end // expected-note {{previous definition is here}} diff --git a/test/SemaObjC/argument-checking.m b/test/SemaObjC/argument-checking.m index 1b6c10d29c6b..c4ada44c5122 100644 --- a/test/SemaObjC/argument-checking.m +++ b/test/SemaObjC/argument-checking.m @@ -1,4 +1,4 @@ -// RUN: clang-cc -fsyntax-only -verify -pedantic %s +// RUN: clang -cc1 -fsyntax-only -verify -pedantic %s struct S { int a; }; diff --git a/test/SemaObjC/at-defs.m b/test/SemaObjC/at-defs.m index 78ce63cd5299..03c9c76e3b2c 100644 --- a/test/SemaObjC/at-defs.m +++ b/test/SemaObjC/at-defs.m @@ -1,4 +1,4 @@ -// RUN: clang-cc -triple i386-unknown-unknown %s -fsyntax-only +// RUN: clang -cc1 -triple i386-unknown-unknown %s -fsyntax-only @interface Test { double a; diff --git a/test/SemaObjC/atomoic-property-synnthesis-rules.m b/test/SemaObjC/atomoic-property-synnthesis-rules.m index 429d6c0f804d..42b173b78704 100644 --- a/test/SemaObjC/atomoic-property-synnthesis-rules.m +++ b/test/SemaObjC/atomoic-property-synnthesis-rules.m @@ -1,4 +1,4 @@ -// RUN: clang-cc -fsyntax-only -verify %s +// RUN: clang -cc1 -fsyntax-only -verify %s /* Conditions for warning: diff --git a/test/SemaObjC/attr-cleanup.m b/test/SemaObjC/attr-cleanup.m index f4d057b2b830..821da000a3c1 100644 --- a/test/SemaObjC/attr-cleanup.m +++ b/test/SemaObjC/attr-cleanup.m @@ -1,4 +1,4 @@ -// RUN: clang-cc %s -verify -fsyntax-only +// RUN: clang -cc1 %s -verify -fsyntax-only @class NSString; diff --git a/test/SemaObjC/attr-deprecated.m b/test/SemaObjC/attr-deprecated.m index e385a977f55b..675f96963280 100644 --- a/test/SemaObjC/attr-deprecated.m +++ b/test/SemaObjC/attr-deprecated.m @@ -1,4 +1,4 @@ -// RUN: clang-cc %s -fsyntax-only -verify +// RUN: clang -cc1 %s -fsyntax-only -verify @interface A { int X __attribute__((deprecated)); diff --git a/test/SemaObjC/attr-malloc.m b/test/SemaObjC/attr-malloc.m index 6cd6be00a8cf..4d2093fa3d4f 100644 --- a/test/SemaObjC/attr-malloc.m +++ b/test/SemaObjC/attr-malloc.m @@ -1,4 +1,4 @@ -// RUN: clang-cc -verify -fsyntax-only -fblocks %s +// RUN: clang -cc1 -verify -fsyntax-only -fblocks %s @interface TestAttrMallocOnMethods {} - (id) test1 __attribute((malloc)); // expected-warning {{functions returning a pointer type}} diff --git a/test/SemaObjC/attr-objc-exception.m b/test/SemaObjC/attr-objc-exception.m index 3efb8cfa40ce..3e012c748230 100644 --- a/test/SemaObjC/attr-objc-exception.m +++ b/test/SemaObjC/attr-objc-exception.m @@ -1,4 +1,4 @@ -// RUN: clang-cc %s -fsyntax-only -verify +// RUN: clang -cc1 %s -fsyntax-only -verify __attribute__((__objc_exception__)) @interface NSException { diff --git a/test/SemaObjC/attr-objc-gc.m b/test/SemaObjC/attr-objc-gc.m index 20da639c3cb9..90ca4e3280c2 100644 --- a/test/SemaObjC/attr-objc-gc.m +++ b/test/SemaObjC/attr-objc-gc.m @@ -1,4 +1,4 @@ -// RUN: clang-cc -fsyntax-only -verify %s +// RUN: clang -cc1 -fsyntax-only -verify %s static id __attribute((objc_gc(weak))) a; static id __attribute((objc_gc(strong))) b; diff --git a/test/SemaObjC/bad-receiver-1.m b/test/SemaObjC/bad-receiver-1.m index 64ff3d199314..52509753d8a2 100644 --- a/test/SemaObjC/bad-receiver-1.m +++ b/test/SemaObjC/bad-receiver-1.m @@ -1,4 +1,4 @@ -// RUN: clang-cc -fsyntax-only -verify %s +// RUN: clang -cc1 -fsyntax-only -verify %s @interface I - (id) retain; diff --git a/test/SemaObjC/block-attr.m b/test/SemaObjC/block-attr.m index d67fd3543548..885a94649393 100644 --- a/test/SemaObjC/block-attr.m +++ b/test/SemaObjC/block-attr.m @@ -1,4 +1,4 @@ -// RUN: clang-cc -triple x86_64-apple-darwin10 -fsyntax-only -verify -fblocks -fobjc-gc-only %s +// RUN: clang -cc1 -triple x86_64-apple-darwin10 -fsyntax-only -verify -fblocks -fobjc-gc-only %s @interface Thing {} diff --git a/test/SemaObjC/block-explicit-return-type.m b/test/SemaObjC/block-explicit-return-type.m index cfe72de39523..6e9728613a8e 100644 --- a/test/SemaObjC/block-explicit-return-type.m +++ b/test/SemaObjC/block-explicit-return-type.m @@ -1,4 +1,4 @@ -// RUN: clang-cc -fsyntax-only %s -verify -fblocks +// RUN: clang -cc1 -fsyntax-only %s -verify -fblocks // FIXME: should compile // Test for blocks with explicit return type specified. diff --git a/test/SemaObjC/block-ivar.m b/test/SemaObjC/block-ivar.m index 231c9a23f8ad..5dbefdcbaad9 100644 --- a/test/SemaObjC/block-ivar.m +++ b/test/SemaObjC/block-ivar.m @@ -1,4 +1,4 @@ -// RUN: clang-cc -fsyntax-only -verify %s -fblocks +// RUN: clang -cc1 -fsyntax-only -verify %s -fblocks @interface NSObject { struct objc_object *isa; diff --git a/test/SemaObjC/blocks.m b/test/SemaObjC/blocks.m index aecdfd1f5e4e..c16372bcc421 100644 --- a/test/SemaObjC/blocks.m +++ b/test/SemaObjC/blocks.m @@ -1,4 +1,4 @@ -// RUN: clang-cc -fsyntax-only -verify -fblocks %s +// RUN: clang -cc1 -fsyntax-only -verify -fblocks %s @protocol NSObject; void bar(id(^)(void)); diff --git a/test/SemaObjC/call-super-2.m b/test/SemaObjC/call-super-2.m index afd35a8e2630..f3d0a9676039 100644 --- a/test/SemaObjC/call-super-2.m +++ b/test/SemaObjC/call-super-2.m @@ -1,4 +1,4 @@ -// RUN: clang-cc -fsyntax-only -verify %s +// RUN: clang -cc1 -fsyntax-only -verify %s #include diff --git a/test/SemaObjC/catch-stmt.m b/test/SemaObjC/catch-stmt.m index 6dcbcdebfba4..eb570c02edfc 100644 --- a/test/SemaObjC/catch-stmt.m +++ b/test/SemaObjC/catch-stmt.m @@ -1,4 +1,4 @@ -// RUN: clang-cc -verify %s +// RUN: clang -cc1 -verify %s @protocol P; diff --git a/test/SemaObjC/category-1.m b/test/SemaObjC/category-1.m index dcbda42cd136..588261891131 100644 --- a/test/SemaObjC/category-1.m +++ b/test/SemaObjC/category-1.m @@ -1,4 +1,4 @@ -// RUN: clang-cc -fsyntax-only -verify %s +// RUN: clang -cc1 -fsyntax-only -verify %s @interface MyClass1 @end diff --git a/test/SemaObjC/category-method-lookup-2.m b/test/SemaObjC/category-method-lookup-2.m index 15da63783fee..ea828d9a3bcb 100644 --- a/test/SemaObjC/category-method-lookup-2.m +++ b/test/SemaObjC/category-method-lookup-2.m @@ -1,4 +1,4 @@ -// RUN: clang-cc -fsyntax-only -verify %s +// RUN: clang -cc1 -fsyntax-only -verify %s typedef struct objc_class *Class; @interface NSObject diff --git a/test/SemaObjC/category-method-lookup.m b/test/SemaObjC/category-method-lookup.m index bda465783b5d..9b880c4ac707 100644 --- a/test/SemaObjC/category-method-lookup.m +++ b/test/SemaObjC/category-method-lookup.m @@ -1,4 +1,4 @@ -// RUN: clang-cc -fsyntax-only -verify %s +// RUN: clang -cc1 -fsyntax-only -verify %s @interface Foo @end diff --git a/test/SemaObjC/check-dup-decl-methods-1.m b/test/SemaObjC/check-dup-decl-methods-1.m index ae0cab0b5d41..edcd3be518a3 100644 --- a/test/SemaObjC/check-dup-decl-methods-1.m +++ b/test/SemaObjC/check-dup-decl-methods-1.m @@ -1,4 +1,4 @@ -// RUN: clang-cc -fsyntax-only -verify %s +// RUN: clang -cc1 -fsyntax-only -verify %s @interface SUPER - (int) meth; diff --git a/test/SemaObjC/check-dup-objc-decls-1.m b/test/SemaObjC/check-dup-objc-decls-1.m index 1dfaf0905083..434f8ddae51e 100644 --- a/test/SemaObjC/check-dup-objc-decls-1.m +++ b/test/SemaObjC/check-dup-objc-decls-1.m @@ -1,4 +1,4 @@ -// RUN: clang-cc -fsyntax-only -verify %s +// RUN: clang -cc1 -fsyntax-only -verify %s @interface Foo // expected-note {{previous definition is here}} @end diff --git a/test/SemaObjC/class-bitfield.m b/test/SemaObjC/class-bitfield.m index 82209121b183..d6d9855b2952 100644 --- a/test/SemaObjC/class-bitfield.m +++ b/test/SemaObjC/class-bitfield.m @@ -1,4 +1,4 @@ -// RUN: clang-cc %s -fsyntax-only -verify +// RUN: clang -cc1 %s -fsyntax-only -verify @interface X { diff --git a/test/SemaObjC/class-conforming-protocol-1.m b/test/SemaObjC/class-conforming-protocol-1.m index a9712b23a6a8..e2889c3f9d3b 100644 --- a/test/SemaObjC/class-conforming-protocol-1.m +++ b/test/SemaObjC/class-conforming-protocol-1.m @@ -1,4 +1,4 @@ -// RUN: clang-cc -fsyntax-only -verify %s +// RUN: clang -cc1 -fsyntax-only -verify %s @protocol P1 @end @protocol P2 @end diff --git a/test/SemaObjC/class-conforming-protocol-2.m b/test/SemaObjC/class-conforming-protocol-2.m index 7b218bdbd803..550bafd60f71 100644 --- a/test/SemaObjC/class-conforming-protocol-2.m +++ b/test/SemaObjC/class-conforming-protocol-2.m @@ -1,4 +1,4 @@ -// RUN: clang-cc -fsyntax-only -verify %s +// RUN: clang -cc1 -fsyntax-only -verify %s @protocol NSWindowDelegate @end diff --git a/test/SemaObjC/class-def-test-1.m b/test/SemaObjC/class-def-test-1.m index da8a3267662f..0cf49ddd1b9a 100644 --- a/test/SemaObjC/class-def-test-1.m +++ b/test/SemaObjC/class-def-test-1.m @@ -1,4 +1,4 @@ -// RUN: clang-cc -fsyntax-only -verify %s +// RUN: clang -cc1 -fsyntax-only -verify %s @protocol SUPER; diff --git a/test/SemaObjC/class-extension-dup-methods.m b/test/SemaObjC/class-extension-dup-methods.m index f50b293ade36..929ad0665a89 100644 --- a/test/SemaObjC/class-extension-dup-methods.m +++ b/test/SemaObjC/class-extension-dup-methods.m @@ -1,4 +1,4 @@ -// RUN: clang-cc -fsyntax-only -verify %s +// RUN: clang -cc1 -fsyntax-only -verify %s @interface Foo - (int) garf; // expected-note {{ previous declaration is here}} diff --git a/test/SemaObjC/class-getter-using-dotsyntax.m b/test/SemaObjC/class-getter-using-dotsyntax.m index ba42590c3419..049c6ce62737 100644 --- a/test/SemaObjC/class-getter-using-dotsyntax.m +++ b/test/SemaObjC/class-getter-using-dotsyntax.m @@ -1,4 +1,4 @@ -// RUN: clang-cc -fsyntax-only -verify %s +// RUN: clang -cc1 -fsyntax-only -verify %s typedef struct objc_class *Class; diff --git a/test/SemaObjC/class-impl-1.m b/test/SemaObjC/class-impl-1.m index 09ad1556c035..80d6915d7557 100644 --- a/test/SemaObjC/class-impl-1.m +++ b/test/SemaObjC/class-impl-1.m @@ -1,4 +1,4 @@ -// RUN: clang-cc -fsyntax-only -verify %s +// RUN: clang -cc1 -fsyntax-only -verify %s typedef int INTF3; // expected-note {{previous definition is here}} diff --git a/test/SemaObjC/class-method-lookup.m b/test/SemaObjC/class-method-lookup.m index 6f745d48ab62..ef9df5a1461b 100644 --- a/test/SemaObjC/class-method-lookup.m +++ b/test/SemaObjC/class-method-lookup.m @@ -1,4 +1,4 @@ -// RUN: clang-cc -fsyntax-only -verify %s +// RUN: clang -cc1 -fsyntax-only -verify %s @interface MyBase - (void) rootInstanceMethod; diff --git a/test/SemaObjC/class-method-self.m b/test/SemaObjC/class-method-self.m index d36bc8cbc91b..ea4de84dae91 100644 --- a/test/SemaObjC/class-method-self.m +++ b/test/SemaObjC/class-method-self.m @@ -1,4 +1,4 @@ -// RUN: clang-cc -verify %s +// RUN: clang -cc1 -verify %s typedef struct objc_class *Class; @interface XX diff --git a/test/SemaObjC/class-property-access.m b/test/SemaObjC/class-property-access.m index 663b87d2ff18..ce34a233f7b4 100644 --- a/test/SemaObjC/class-property-access.m +++ b/test/SemaObjC/class-property-access.m @@ -1,4 +1,4 @@ -// RUN: clang -fsyntax-only -verify %s +// RUN: clang -cc1 -fsyntax-only -verify %s @interface Test {} + (Test*)one; diff --git a/test/SemaObjC/class-proto-1.m b/test/SemaObjC/class-proto-1.m index 8f0f3d8826c2..5e9ee6063e74 100644 --- a/test/SemaObjC/class-proto-1.m +++ b/test/SemaObjC/class-proto-1.m @@ -1,4 +1,4 @@ -// RUN: clang-cc -fsyntax-only -verify %s +// RUN: clang -cc1 -fsyntax-only -verify %s @interface INTF1 @end diff --git a/test/SemaObjC/class-protocol.m b/test/SemaObjC/class-protocol.m index 12b638175137..c2eded75f97a 100644 --- a/test/SemaObjC/class-protocol.m +++ b/test/SemaObjC/class-protocol.m @@ -1,4 +1,4 @@ -// RUN: clang-cc -fsyntax-only -verify %s +// RUN: clang -cc1 -fsyntax-only -verify %s // pr5552 @interface Protocol diff --git a/test/SemaObjC/cocoa.m b/test/SemaObjC/cocoa.m index 7dab9f55e734..a0715453dfff 100644 --- a/test/SemaObjC/cocoa.m +++ b/test/SemaObjC/cocoa.m @@ -1,4 +1,4 @@ -// RUN: clang-cc -mcpu pentium4 %s -print-stats +// RUN: clang -cc1 -mcpu pentium4 %s -print-stats #ifdef __APPLE__ #include #endif diff --git a/test/SemaObjC/compare-qualified-id.m b/test/SemaObjC/compare-qualified-id.m index 22bec504a558..c9776d0f41c3 100644 --- a/test/SemaObjC/compare-qualified-id.m +++ b/test/SemaObjC/compare-qualified-id.m @@ -1,4 +1,4 @@ -// RUN: clang-cc -fsyntax-only -verify %s +// RUN: clang -cc1 -fsyntax-only -verify %s typedef signed char BOOL; typedef unsigned int NSUInteger; diff --git a/test/SemaObjC/compatible-protocol-qualified-types.m b/test/SemaObjC/compatible-protocol-qualified-types.m index 71f00542b1c6..54d6a04085d9 100644 --- a/test/SemaObjC/compatible-protocol-qualified-types.m +++ b/test/SemaObjC/compatible-protocol-qualified-types.m @@ -1,4 +1,4 @@ -// RUN: clang-cc -pedantic -fsyntax-only -verify %s +// RUN: clang -cc1 -pedantic -fsyntax-only -verify %s typedef signed char BOOL; @class NSInvocation, NSMethodSignature, NSCoder, NSString, NSEnumerator; diff --git a/test/SemaObjC/comptypes-1.m b/test/SemaObjC/comptypes-1.m index df0785bf89e1..bffbd763ad98 100644 --- a/test/SemaObjC/comptypes-1.m +++ b/test/SemaObjC/comptypes-1.m @@ -1,4 +1,4 @@ -// RUN: clang-cc -fsyntax-only -verify -pedantic %s +// RUN: clang -cc1 -fsyntax-only -verify -pedantic %s #define nil (void *)0; #define Nil (void *)0; diff --git a/test/SemaObjC/comptypes-2.m b/test/SemaObjC/comptypes-2.m index c24b67b15ed1..a53b942930e5 100644 --- a/test/SemaObjC/comptypes-2.m +++ b/test/SemaObjC/comptypes-2.m @@ -1,4 +1,4 @@ -// RUN: clang-cc -fsyntax-only -verify %s +// RUN: clang -cc1 -fsyntax-only -verify %s #define nil (void *)0; #define Nil (void *)0; diff --git a/test/SemaObjC/comptypes-3.m b/test/SemaObjC/comptypes-3.m index 0506bce7ad1a..2d1b6236e3d7 100644 --- a/test/SemaObjC/comptypes-3.m +++ b/test/SemaObjC/comptypes-3.m @@ -1,4 +1,4 @@ -// RUN: clang-cc -fsyntax-only -verify %s +// RUN: clang -cc1 -fsyntax-only -verify %s #define nil (void *)0; diff --git a/test/SemaObjC/comptypes-4.m b/test/SemaObjC/comptypes-4.m index 598901148a8a..794ede25962f 100644 --- a/test/SemaObjC/comptypes-4.m +++ b/test/SemaObjC/comptypes-4.m @@ -1,4 +1,4 @@ -// RUN: clang-cc -fsyntax-only -verify %s +// RUN: clang -cc1 -fsyntax-only -verify %s extern void foo(); diff --git a/test/SemaObjC/comptypes-5.m b/test/SemaObjC/comptypes-5.m index 478e8c8114ac..4b8f48968514 100644 --- a/test/SemaObjC/comptypes-5.m +++ b/test/SemaObjC/comptypes-5.m @@ -1,4 +1,4 @@ -// RUN: clang-cc -fsyntax-only -pedantic -verify %s +// RUN: clang -cc1 -fsyntax-only -pedantic -verify %s #define nil (void *)0; diff --git a/test/SemaObjC/comptypes-6.m b/test/SemaObjC/comptypes-6.m index 32176755ef76..ad3da26185a7 100644 --- a/test/SemaObjC/comptypes-6.m +++ b/test/SemaObjC/comptypes-6.m @@ -1,4 +1,4 @@ -// RUN: clang-cc -fsyntax-only -verify -pedantic %s +// RUN: clang -cc1 -fsyntax-only -verify -pedantic %s @interface Derived @end diff --git a/test/SemaObjC/comptypes-7.m b/test/SemaObjC/comptypes-7.m index 881fd2b5553b..ea1aa06292de 100644 --- a/test/SemaObjC/comptypes-7.m +++ b/test/SemaObjC/comptypes-7.m @@ -1,4 +1,4 @@ -// RUN: clang-cc -fsyntax-only -verify -pedantic %s +// RUN: clang -cc1 -fsyntax-only -verify -pedantic %s #define nil (void *)0; #define Nil (void *)0; diff --git a/test/SemaObjC/comptypes-8.m b/test/SemaObjC/comptypes-8.m index af9267e499f6..b19bc302b223 100644 --- a/test/SemaObjC/comptypes-8.m +++ b/test/SemaObjC/comptypes-8.m @@ -1,4 +1,4 @@ -// RUN: clang-cc -fsyntax-only -verify %s +// RUN: clang -cc1 -fsyntax-only -verify %s @protocol MyProtocol @end diff --git a/test/SemaObjC/comptypes-9.m b/test/SemaObjC/comptypes-9.m index caa93b49e6f3..89647b5b9826 100644 --- a/test/SemaObjC/comptypes-9.m +++ b/test/SemaObjC/comptypes-9.m @@ -1,4 +1,4 @@ -// RUN: clang-cc -fsyntax-only %s +// RUN: clang -cc1 -fsyntax-only %s // FIXME: This test case tests the patch applied in: http://lists.cs.uiuc.edu/pipermail/cfe-commits/Week-of-Mon-20080602/006017.html // Eventually that logic should be treated as an extension. diff --git a/test/SemaObjC/comptypes-a.m b/test/SemaObjC/comptypes-a.m index 5570d56b0b83..4c7967d89c0a 100644 --- a/test/SemaObjC/comptypes-a.m +++ b/test/SemaObjC/comptypes-a.m @@ -1,4 +1,4 @@ -// RUN: clang-cc -fsyntax-only -verify -pedantic %s +// RUN: clang -cc1 -fsyntax-only -verify -pedantic %s typedef signed char BOOL; typedef int NSInteger; diff --git a/test/SemaObjC/comptypes-legal.m b/test/SemaObjC/comptypes-legal.m index cd7f89b61d0d..6a837b6aa8fa 100644 --- a/test/SemaObjC/comptypes-legal.m +++ b/test/SemaObjC/comptypes-legal.m @@ -1,4 +1,4 @@ -// RUN: clang-cc -fsyntax-only -verify -pedantic %s +// RUN: clang -cc1 -fsyntax-only -verify -pedantic %s @protocol NSObject @end diff --git a/test/SemaObjC/conditional-expr-2.m b/test/SemaObjC/conditional-expr-2.m index 08758488c540..9835f3ea31c2 100644 --- a/test/SemaObjC/conditional-expr-2.m +++ b/test/SemaObjC/conditional-expr-2.m @@ -1,4 +1,4 @@ -// RUN: clang-cc -fsyntax-only -verify %s +// RUN: clang -cc1 -fsyntax-only -verify %s @interface A @end diff --git a/test/SemaObjC/conditional-expr-3.m b/test/SemaObjC/conditional-expr-3.m index 9f1ee68c6f94..b7dae6bc48e7 100644 --- a/test/SemaObjC/conditional-expr-3.m +++ b/test/SemaObjC/conditional-expr-3.m @@ -1,4 +1,4 @@ -// RUN: clang-cc -fsyntax-only -verify %s +// RUN: clang -cc1 -fsyntax-only -verify %s @protocol P0 @end diff --git a/test/SemaObjC/conditional-expr-4.m b/test/SemaObjC/conditional-expr-4.m index 87209581534c..19215e3c36cc 100644 --- a/test/SemaObjC/conditional-expr-4.m +++ b/test/SemaObjC/conditional-expr-4.m @@ -1,4 +1,4 @@ -// RUN: clang-cc -fsyntax-only -verify %s +// RUN: clang -cc1 -fsyntax-only -verify %s // #define nil ((void*) 0) diff --git a/test/SemaObjC/conditional-expr-5.m b/test/SemaObjC/conditional-expr-5.m index d9c1a9474fe7..74f866be0034 100644 --- a/test/SemaObjC/conditional-expr-5.m +++ b/test/SemaObjC/conditional-expr-5.m @@ -1,4 +1,4 @@ -// RUN: clang-cc -fsyntax-only -verify %s +// RUN: clang -cc1 -fsyntax-only -verify %s @interface PBXBuildSettingsDictionary { diff --git a/test/SemaObjC/conditional-expr-6.m b/test/SemaObjC/conditional-expr-6.m index bba51bb8178f..dcd2f958f23a 100644 --- a/test/SemaObjC/conditional-expr-6.m +++ b/test/SemaObjC/conditional-expr-6.m @@ -1,4 +1,4 @@ -// RUN: clang-cc -fsyntax-only -verify %s +// RUN: clang -cc1 -fsyntax-only -verify %s @protocol MyProtocol @end diff --git a/test/SemaObjC/conditional-expr.m b/test/SemaObjC/conditional-expr.m index 2043503ddf7b..8fdb2810eddf 100644 --- a/test/SemaObjC/conditional-expr.m +++ b/test/SemaObjC/conditional-expr.m @@ -1,4 +1,4 @@ -// RUN: clang-cc -fsyntax-only -verify -pedantic %s +// RUN: clang -cc1 -fsyntax-only -verify -pedantic %s @protocol NSObject @end diff --git a/test/SemaObjC/conflicting-ivar-test-1.m b/test/SemaObjC/conflicting-ivar-test-1.m index 20ed15722477..acba8e431ab8 100644 --- a/test/SemaObjC/conflicting-ivar-test-1.m +++ b/test/SemaObjC/conflicting-ivar-test-1.m @@ -1,4 +1,4 @@ -// RUN: clang-cc -fsyntax-only -verify %s +// RUN: clang -cc1 -fsyntax-only -verify %s @interface INTF { diff --git a/test/SemaObjC/continuation-class-err.m b/test/SemaObjC/continuation-class-err.m index 4559696b7f2d..c251d460cdf2 100644 --- a/test/SemaObjC/continuation-class-err.m +++ b/test/SemaObjC/continuation-class-err.m @@ -1,4 +1,4 @@ -// RUN: clang-cc -fsyntax-only -verify %s +// RUN: clang -cc1 -fsyntax-only -verify %s @interface ReadOnly { diff --git a/test/SemaObjC/crash-label.m b/test/SemaObjC/crash-label.m index ff40cc67c5dc..477c9a12c142 100644 --- a/test/SemaObjC/crash-label.m +++ b/test/SemaObjC/crash-label.m @@ -1,4 +1,4 @@ -// RUN: clang-cc -fsyntax-only -verify %s +// RUN: clang -cc1 -fsyntax-only -verify %s - (NSDictionary*) _executeScript:(NSString *)source { // expected-error 2 {{expected a type}} \ // expected-error {{missing context for method declaration}} diff --git a/test/SemaObjC/deref-interface.m b/test/SemaObjC/deref-interface.m index 57750a5a4396..2308677ab825 100644 --- a/test/SemaObjC/deref-interface.m +++ b/test/SemaObjC/deref-interface.m @@ -1,4 +1,4 @@ -// RUN: clang-cc -fobjc-nonfragile-abi -verify -fsyntax-only %s +// RUN: clang -cc1 -fobjc-nonfragile-abi -verify -fsyntax-only %s @interface NSView - (id)initWithView:(id)realView; diff --git a/test/SemaObjC/duplicate-ivar-check.m b/test/SemaObjC/duplicate-ivar-check.m index 7cab982e6e21..b4a9df282d44 100644 --- a/test/SemaObjC/duplicate-ivar-check.m +++ b/test/SemaObjC/duplicate-ivar-check.m @@ -1,4 +1,4 @@ -// RUN: clang-cc -fsyntax-only -verify %s +// RUN: clang -cc1 -fsyntax-only -verify %s @interface B1 { @public diff --git a/test/SemaObjC/enhanced-proto-2.m b/test/SemaObjC/enhanced-proto-2.m index 0450d7ba9deb..a83ef23afd5a 100644 --- a/test/SemaObjC/enhanced-proto-2.m +++ b/test/SemaObjC/enhanced-proto-2.m @@ -1,4 +1,4 @@ -// RUN: clang-cc -verify %s +// RUN: clang -cc1 -verify %s @protocol MyProto1 @optional diff --git a/test/SemaObjC/error-property-gc-attr.m b/test/SemaObjC/error-property-gc-attr.m index a44ba4f3768d..da742e7f7331 100644 --- a/test/SemaObjC/error-property-gc-attr.m +++ b/test/SemaObjC/error-property-gc-attr.m @@ -1,4 +1,4 @@ -// RUN: clang-cc -triple i386-apple-darwin9 -fobjc-gc -fsyntax-only -verify %s +// RUN: clang -cc1 -triple i386-apple-darwin9 -fobjc-gc -fsyntax-only -verify %s @interface INTF { diff --git a/test/SemaObjC/exprs.m b/test/SemaObjC/exprs.m index d51d135fa27a..52bd61877080 100644 --- a/test/SemaObjC/exprs.m +++ b/test/SemaObjC/exprs.m @@ -1,4 +1,4 @@ -// RUN: clang-cc %s -fsyntax-only -verify +// RUN: clang -cc1 %s -fsyntax-only -verify // rdar://6597252 Class test1(Class X) { diff --git a/test/SemaObjC/foreach.m b/test/SemaObjC/foreach.m index 2b62b1744ce2..315202f5eba6 100644 --- a/test/SemaObjC/foreach.m +++ b/test/SemaObjC/foreach.m @@ -1,4 +1,4 @@ -/* RUN: clang-cc -Wall -fsyntax-only -verify -std=c89 -pedantic %s +/* RUN: clang -cc1 -Wall -fsyntax-only -verify -std=c89 -pedantic %s */ @class NSArray; diff --git a/test/SemaObjC/format-arg-attribute.m b/test/SemaObjC/format-arg-attribute.m index dc5aa8932cda..7de9e9f139c2 100644 --- a/test/SemaObjC/format-arg-attribute.m +++ b/test/SemaObjC/format-arg-attribute.m @@ -1,4 +1,4 @@ -// RUN: clang-cc -verify -fsyntax-only %s +// RUN: clang -cc1 -verify -fsyntax-only %s @class NSString; diff --git a/test/SemaObjC/format-strings-objc.m b/test/SemaObjC/format-strings-objc.m index 4b8490291ad0..b0d5b513dc7a 100644 --- a/test/SemaObjC/format-strings-objc.m +++ b/test/SemaObjC/format-strings-objc.m @@ -1,4 +1,4 @@ -// RUN: clang-cc -fsyntax-only -verify %s +// RUN: clang -cc1 -fsyntax-only -verify %s //===----------------------------------------------------------------------===// // The following code is reduced using delta-debugging from diff --git a/test/SemaObjC/forward-class-1.m b/test/SemaObjC/forward-class-1.m index f5f950566672..e3d2c157d6ad 100644 --- a/test/SemaObjC/forward-class-1.m +++ b/test/SemaObjC/forward-class-1.m @@ -1,4 +1,4 @@ -// RUN: clang-cc -fsyntax-only -verify %s +// RUN: clang -cc1 -fsyntax-only -verify %s @class FOO, BAR; @class FOO, BAR; diff --git a/test/SemaObjC/forward-class-receiver.m b/test/SemaObjC/forward-class-receiver.m index ebba0fd896dc..7f8aec9a39e2 100644 --- a/test/SemaObjC/forward-class-receiver.m +++ b/test/SemaObjC/forward-class-receiver.m @@ -1,4 +1,4 @@ -// RUN: clang-cc -fsyntax-only -verify %s +// RUN: clang -cc1 -fsyntax-only -verify %s @interface I + new; // expected-note {{method 'new' is used for the forward class}} diff --git a/test/SemaObjC/gcc-cast-ext.m b/test/SemaObjC/gcc-cast-ext.m index 5d6670e0f67c..6b4cbafcf817 100644 --- a/test/SemaObjC/gcc-cast-ext.m +++ b/test/SemaObjC/gcc-cast-ext.m @@ -1,4 +1,4 @@ -// RUN: clang-cc %s -verify -fms-extensions +// RUN: clang -cc1 %s -verify -fms-extensions @class NSInvocation, NSMethodSignature, NSCoder, NSString, NSEnumerator; typedef struct _NSRange { } NSRange; diff --git a/test/SemaObjC/id-isa-ref.m b/test/SemaObjC/id-isa-ref.m index fa3293ce79b5..c80f0809c53f 100644 --- a/test/SemaObjC/id-isa-ref.m +++ b/test/SemaObjC/id-isa-ref.m @@ -1,7 +1,4 @@ -// RUN: clang-cc -fsyntax-only -verify %s - -// Failing currently due to Obj-C type representation changes. 2009-09-17 -// XFAIL: * +// RUN: clang -cc1 -fsyntax-only -verify %s typedef struct objc_object { struct objc_class *isa; diff --git a/test/SemaObjC/id.m b/test/SemaObjC/id.m index 70d981c42b17..aa99cfa6471e 100644 --- a/test/SemaObjC/id.m +++ b/test/SemaObjC/id.m @@ -1,4 +1,4 @@ -// RUN: clang-cc -fsyntax-only -verify %s +// RUN: clang -cc1 -fsyntax-only -verify %s @protocol Foo; diff --git a/test/SemaObjC/id_builtin.m b/test/SemaObjC/id_builtin.m index 134753726cbb..1ec049b9ff79 100644 --- a/test/SemaObjC/id_builtin.m +++ b/test/SemaObjC/id_builtin.m @@ -1,4 +1,4 @@ -// RUN: clang-cc %s -fsyntax-only -verify +// RUN: clang -cc1 %s -fsyntax-only -verify // id is now builtin. There should be no errors. id obj; diff --git a/test/SemaObjC/idiomatic-parentheses.m b/test/SemaObjC/idiomatic-parentheses.m index b4c52fa0d146..ec1d3638410e 100644 --- a/test/SemaObjC/idiomatic-parentheses.m +++ b/test/SemaObjC/idiomatic-parentheses.m @@ -1,4 +1,4 @@ -// RUN: clang-cc -fsyntax-only -verify %s +// RUN: clang -cc1 -fsyntax-only -verify %s // Don't warn about some common ObjC idioms unless we have -Wparentheses on. // diff --git a/test/SemaObjC/ignore-weakimport-method.m b/test/SemaObjC/ignore-weakimport-method.m index 369d9023acfb..f745e443cf1e 100644 --- a/test/SemaObjC/ignore-weakimport-method.m +++ b/test/SemaObjC/ignore-weakimport-method.m @@ -1,4 +1,4 @@ -// RUN: clang-cc -fsyntax-only -verify %s +// RUN: clang -cc1 -fsyntax-only -verify %s @interface foo + (void) cx __attribute__((weak_import)); diff --git a/test/SemaObjC/incompatible-protocol-qualified-types.m b/test/SemaObjC/incompatible-protocol-qualified-types.m index 862265ca6476..624377fbf968 100644 --- a/test/SemaObjC/incompatible-protocol-qualified-types.m +++ b/test/SemaObjC/incompatible-protocol-qualified-types.m @@ -1,4 +1,4 @@ -// RUN: clang-cc -pedantic -fsyntax-only -verify %s +// RUN: clang -cc1 -pedantic -fsyntax-only -verify %s @protocol MyProto1 @end diff --git a/test/SemaObjC/inst-method-lookup-in-root.m b/test/SemaObjC/inst-method-lookup-in-root.m index 93f28e69f945..8980d3709e47 100644 --- a/test/SemaObjC/inst-method-lookup-in-root.m +++ b/test/SemaObjC/inst-method-lookup-in-root.m @@ -1,4 +1,4 @@ -// RUN: clang-cc -fsyntax-only -verify %s +// RUN: clang -cc1 -fsyntax-only -verify %s @protocol P - (id) inst_in_proto; diff --git a/test/SemaObjC/interface-1.m b/test/SemaObjC/interface-1.m index 85a2a91a8c13..989893684874 100644 --- a/test/SemaObjC/interface-1.m +++ b/test/SemaObjC/interface-1.m @@ -1,4 +1,4 @@ -// RUN: clang-cc -triple i386-apple-darwin9 %s -fsyntax-only -verify +// RUN: clang -cc1 -triple i386-apple-darwin9 %s -fsyntax-only -verify // rdar://5957506 @interface NSWhatever : diff --git a/test/SemaObjC/interface-layout-2.m b/test/SemaObjC/interface-layout-2.m index ec03a00ca75e..cad71428da45 100644 --- a/test/SemaObjC/interface-layout-2.m +++ b/test/SemaObjC/interface-layout-2.m @@ -1,4 +1,4 @@ -// RUN: clang-cc %s -fsyntax-only -verify +// RUN: clang -cc1 %s -fsyntax-only -verify @interface A { int ivar; diff --git a/test/SemaObjC/interface-layout.m b/test/SemaObjC/interface-layout.m index 6ad891554844..b2c6f0d95fc2 100644 --- a/test/SemaObjC/interface-layout.m +++ b/test/SemaObjC/interface-layout.m @@ -1,4 +1,4 @@ -// RUN: clang-cc %s -fsyntax-only -verify -triple i386-apple-darwin9 +// RUN: clang -cc1 %s -fsyntax-only -verify -triple i386-apple-darwin9 typedef struct objc_object {} *id; typedef signed char BOOL; typedef unsigned int NSUInteger; diff --git a/test/SemaObjC/interface-scope-2.m b/test/SemaObjC/interface-scope-2.m index c9025903940c..bdf28f46360f 100644 --- a/test/SemaObjC/interface-scope-2.m +++ b/test/SemaObjC/interface-scope-2.m @@ -1,4 +1,4 @@ -// RUN: clang-cc -fsyntax-only -verify -triple i686-apple-darwin9 %s +// RUN: clang -cc1 -fsyntax-only -verify -triple i686-apple-darwin9 %s // FIXME: must also compile as Objective-C++ // diff --git a/test/SemaObjC/interface-scope.m b/test/SemaObjC/interface-scope.m index b4dfff683bb1..bc80722febfb 100644 --- a/test/SemaObjC/interface-scope.m +++ b/test/SemaObjC/interface-scope.m @@ -1,4 +1,4 @@ -// RUN: clang-cc -fsyntax-only -verify %s +// RUN: clang -cc1 -fsyntax-only -verify %s @interface I1 { @private diff --git a/test/SemaObjC/interface-tu-variable.m b/test/SemaObjC/interface-tu-variable.m index 9bf816ab69fb..b451d3634929 100644 --- a/test/SemaObjC/interface-tu-variable.m +++ b/test/SemaObjC/interface-tu-variable.m @@ -1,4 +1,4 @@ -// RUN: clang-cc -fsyntax-only -verify %s +// RUN: clang -cc1 -fsyntax-only -verify %s @interface XX int x; // expected-error {{cannot declare variable inside @interface or @protocol}} diff --git a/test/SemaObjC/invalid-code.m b/test/SemaObjC/invalid-code.m index 6eacba05f4ae..d0679a3f98c5 100644 --- a/test/SemaObjC/invalid-code.m +++ b/test/SemaObjC/invalid-code.m @@ -1,4 +1,4 @@ -// RUN: clang-cc %s -fsyntax-only -verify +// RUN: clang -cc1 %s -fsyntax-only -verify // rdar://6124613 void test1() { diff --git a/test/SemaObjC/invalid-objc-decls-1.m b/test/SemaObjC/invalid-objc-decls-1.m index 4a3732eff188..b58fa68337be 100644 --- a/test/SemaObjC/invalid-objc-decls-1.m +++ b/test/SemaObjC/invalid-objc-decls-1.m @@ -1,4 +1,4 @@ -// RUN: clang-cc -fsyntax-only -verify %s +// RUN: clang -cc1 -fsyntax-only -verify %s @interface Super @end Super s1; // expected-error{{interface type cannot be statically allocated}} diff --git a/test/SemaObjC/invalid-receiver.m b/test/SemaObjC/invalid-receiver.m index e79df96942cc..366f71400856 100644 --- a/test/SemaObjC/invalid-receiver.m +++ b/test/SemaObjC/invalid-receiver.m @@ -1,4 +1,4 @@ -// RUN: clang-cc -fsyntax-only -verify %s +// RUN: clang -cc1 -fsyntax-only -verify %s typedef struct NotAClass { int a, b; diff --git a/test/SemaObjC/invalid-typename.m b/test/SemaObjC/invalid-typename.m index 4077f91a9a66..ecc03ba9813a 100644 --- a/test/SemaObjC/invalid-typename.m +++ b/test/SemaObjC/invalid-typename.m @@ -1,4 +1,4 @@ -// RUN: clang-cc -fsyntax-only -verify %s +// RUN: clang -cc1 -fsyntax-only -verify %s @class NSString, NSArray; diff --git a/test/SemaObjC/ivar-access-package.m b/test/SemaObjC/ivar-access-package.m index 77a15cca5142..077b0cf57c68 100644 --- a/test/SemaObjC/ivar-access-package.m +++ b/test/SemaObjC/ivar-access-package.m @@ -1,4 +1,4 @@ -// RUN: clang-cc -fsyntax-only -verify %s +// RUN: clang -cc1 -fsyntax-only -verify %s typedef unsigned char BOOL; diff --git a/test/SemaObjC/ivar-access-tests.m b/test/SemaObjC/ivar-access-tests.m index ca3cc4cf1d46..1dc33db5b1e8 100644 --- a/test/SemaObjC/ivar-access-tests.m +++ b/test/SemaObjC/ivar-access-tests.m @@ -1,4 +1,4 @@ -// RUN: clang-cc -fsyntax-only -verify %s +// RUN: clang -cc1 -fsyntax-only -verify %s @interface MySuperClass { diff --git a/test/SemaObjC/ivar-lookup.m b/test/SemaObjC/ivar-lookup.m index b168976da136..63bf040d636f 100644 --- a/test/SemaObjC/ivar-lookup.m +++ b/test/SemaObjC/ivar-lookup.m @@ -1,4 +1,4 @@ -// RUN: clang-cc %s -fsyntax-only -verify +// RUN: clang -cc1 %s -fsyntax-only -verify @interface Test { int x; diff --git a/test/SemaObjC/ivar-ref-misuse.m b/test/SemaObjC/ivar-ref-misuse.m index 707e1893bf8e..04047533af43 100644 --- a/test/SemaObjC/ivar-ref-misuse.m +++ b/test/SemaObjC/ivar-ref-misuse.m @@ -1,4 +1,4 @@ -// RUN: clang-cc -fsyntax-only -verify %s +// RUN: clang -cc1 -fsyntax-only -verify %s @interface Sprite { int sprite, spree; diff --git a/test/SemaObjC/ivar-sem-check-1.m b/test/SemaObjC/ivar-sem-check-1.m index 957abc397e89..318f510672ce 100644 --- a/test/SemaObjC/ivar-sem-check-1.m +++ b/test/SemaObjC/ivar-sem-check-1.m @@ -1,4 +1,4 @@ -// RUN: clang-cc -fsyntax-only -verify %s +// RUN: clang -cc1 -fsyntax-only -verify %s struct S; // expected-note{{forward declaration of 'struct S'}} typedef int FOO(); @@ -9,7 +9,8 @@ typedef int FOO(); int arr[]; // expected-error {{field has incomplete type}} struct S IC; // expected-error {{field has incomplete type}} struct T { // expected-note {{previous definition is here}} - struct T {} X; // expected-error {{nested redefinition of 'T'}} + struct T {} X; // expected-error {{nested redefinition of 'T'}} \ + // expected-error {{field has incomplete type}} }YYY; FOO BADFUNC; // expected-error {{field 'BADFUNC' declared as a function}} int kaka; // expected-note {{previous declaration is here}} diff --git a/test/SemaObjC/ivar-sem-check-2.m b/test/SemaObjC/ivar-sem-check-2.m index a5a830d6a3f6..242504f0a177 100644 --- a/test/SemaObjC/ivar-sem-check-2.m +++ b/test/SemaObjC/ivar-sem-check-2.m @@ -1,4 +1,4 @@ -// RUN: clang-cc -fsyntax-only -fobjc-nonfragile-abi -verify %s +// RUN: clang -cc1 -fsyntax-only -fobjc-nonfragile-abi -verify %s @interface Super { id value2; // expected-note {{previously declared 'value2' here}} diff --git a/test/SemaObjC/legacy-implementation-1.m b/test/SemaObjC/legacy-implementation-1.m index 63768ffb50ea..e480561693a4 100644 --- a/test/SemaObjC/legacy-implementation-1.m +++ b/test/SemaObjC/legacy-implementation-1.m @@ -1,4 +1,4 @@ -// RUN: clang-cc -fsyntax-only -verify %s +// RUN: clang -cc1 -fsyntax-only -verify %s @implementation INTF // expected-warning {{cannot find interface declaration for 'INTF'}} @end diff --git a/test/SemaObjC/message.m b/test/SemaObjC/message.m index 02901238f17f..244f5d7b74e6 100644 --- a/test/SemaObjC/message.m +++ b/test/SemaObjC/message.m @@ -1,4 +1,4 @@ -// RUN: clang-cc -fsyntax-only -verify %s +// RUN: clang -cc1 -fsyntax-only -verify %s typedef struct objc_object { Class isa; diff --git a/test/SemaObjC/method-arg-decay.m b/test/SemaObjC/method-arg-decay.m index e81bcdf7b75f..09949de3293d 100644 --- a/test/SemaObjC/method-arg-decay.m +++ b/test/SemaObjC/method-arg-decay.m @@ -1,4 +1,4 @@ -// RUN: clang-cc -checker-cfref -verify %s +// RUN: clang -cc1 -checker-cfref -verify %s typedef signed char BOOL; typedef int NSInteger; typedef unsigned int NSUInteger; diff --git a/test/SemaObjC/method-arg-qualifier-warning.m b/test/SemaObjC/method-arg-qualifier-warning.m new file mode 100644 index 000000000000..2d9499f2fdbe --- /dev/null +++ b/test/SemaObjC/method-arg-qualifier-warning.m @@ -0,0 +1,20 @@ +// RUN: clang -cc1 -fsyntax-only -verify %s + +typedef signed char BOOL; + +@interface NSString +- (BOOL)isEqualToString:(NSString *)aString; +@end + +static const NSString * Identifier1 = @"Identifier1"; +static NSString const * Identifier2 = @"Identifier2"; +static NSString * const Identifier3 = @"Identifier3"; + +int main () { + + [@"Identifier1" isEqualToString:Identifier1]; // expected-warning {{sending 'NSString const *' discards qualifiers, expected 'NSString *'}} + [@"Identifier2" isEqualToString:Identifier2]; // expected-warning {{sending 'NSString const *' discards qualifiers, expected 'NSString *'}} + [@"Identifier3" isEqualToString:Identifier3]; + return 0; +} + diff --git a/test/SemaObjC/method-attributes.m b/test/SemaObjC/method-attributes.m index c4d4fba25d6e..d5f92edee40c 100644 --- a/test/SemaObjC/method-attributes.m +++ b/test/SemaObjC/method-attributes.m @@ -1,4 +1,4 @@ -// RUN: clang-cc -verify -fsyntax-only %s +// RUN: clang -cc1 -verify -fsyntax-only %s @class NSString; diff --git a/test/SemaObjC/method-bad-param.m b/test/SemaObjC/method-bad-param.m index f797188669ad..8ef7be9d403b 100644 --- a/test/SemaObjC/method-bad-param.m +++ b/test/SemaObjC/method-bad-param.m @@ -1,4 +1,4 @@ -// RUN: clang-cc -fsyntax-only -verify %s +// RUN: clang -cc1 -fsyntax-only -verify %s @interface foo @end diff --git a/test/SemaObjC/method-conflict.m b/test/SemaObjC/method-conflict.m index a4213f6c63c9..0f7fd61fe164 100644 --- a/test/SemaObjC/method-conflict.m +++ b/test/SemaObjC/method-conflict.m @@ -1,4 +1,4 @@ -// RUN: clang-cc -fsyntax-only -verify %s +// RUN: clang -cc1 -fsyntax-only -verify %s typedef signed char BOOL; typedef unsigned int NSUInteger; diff --git a/test/SemaObjC/method-def-1.m b/test/SemaObjC/method-def-1.m index 3eb94b9153d9..f98ba896db40 100644 --- a/test/SemaObjC/method-def-1.m +++ b/test/SemaObjC/method-def-1.m @@ -1,4 +1,4 @@ -// RUN: clang-cc -fsyntax-only -verify %s +// RUN: clang -cc1 -fsyntax-only -verify %s @interface foo - (int)meth; diff --git a/test/SemaObjC/method-def-2.m b/test/SemaObjC/method-def-2.m index 84cdd70259fa..e595589695ea 100644 --- a/test/SemaObjC/method-def-2.m +++ b/test/SemaObjC/method-def-2.m @@ -1,4 +1,4 @@ -// RUN: clang-cc -ast-print %s +// RUN: clang -cc1 -ast-print %s extern void abort(void); #define CHECK_IF(expr) if(!(expr)) abort() diff --git a/test/SemaObjC/method-encoding-2.m b/test/SemaObjC/method-encoding-2.m index b3ffdcd0585c..50d2d9250dd4 100644 --- a/test/SemaObjC/method-encoding-2.m +++ b/test/SemaObjC/method-encoding-2.m @@ -1,4 +1,4 @@ -// RUN: clang-cc %s +// RUN: clang -cc1 %s // TODO: We don't support rewrite of method definitions @interface Intf diff --git a/test/SemaObjC/method-lookup-2.m b/test/SemaObjC/method-lookup-2.m index cca757509ad1..5493653f3eca 100644 --- a/test/SemaObjC/method-lookup-2.m +++ b/test/SemaObjC/method-lookup-2.m @@ -1,4 +1,4 @@ -// RUN: clang-cc -fsyntax-only -verify %s +// RUN: clang -cc1 -fsyntax-only -verify %s typedef signed char BOOL; @protocol NSObject diff --git a/test/SemaObjC/method-lookup-3.m b/test/SemaObjC/method-lookup-3.m index 8ed583faebc7..9e7c4c93abeb 100644 --- a/test/SemaObjC/method-lookup-3.m +++ b/test/SemaObjC/method-lookup-3.m @@ -1,4 +1,4 @@ -// RUN: clang-cc -fsyntax-only -verify %s +// RUN: clang -cc1 -fsyntax-only -verify %s typedef struct { int y; } Abstract; diff --git a/test/SemaObjC/method-lookup-4.m b/test/SemaObjC/method-lookup-4.m index 3b2548b92c11..20b4e60b018f 100644 --- a/test/SemaObjC/method-lookup-4.m +++ b/test/SemaObjC/method-lookup-4.m @@ -1,4 +1,4 @@ -// RUN: clang-cc -fsyntax-only -verify %s +// RUN: clang -cc1 -fsyntax-only -verify %s @interface NSObject {} diff --git a/test/SemaObjC/method-lookup.m b/test/SemaObjC/method-lookup.m index 49dc789af783..b9607eb690c3 100644 --- a/test/SemaObjC/method-lookup.m +++ b/test/SemaObjC/method-lookup.m @@ -1,4 +1,4 @@ -// RUN: clang-cc -fsyntax-only -verify %s +// RUN: clang -cc1 -fsyntax-only -verify %s typedef signed char BOOL; typedef int NSInteger; diff --git a/test/SemaObjC/method-no-context.m b/test/SemaObjC/method-no-context.m index 9351cb91579a..63caa7e399cc 100644 --- a/test/SemaObjC/method-no-context.m +++ b/test/SemaObjC/method-no-context.m @@ -1,4 +1,4 @@ -// RUN: clang-cc -fsyntax-only -verify %s +// RUN: clang -cc1 -fsyntax-only -verify %s - im0 { int a; return 0; // expected-error{{missing context for method declaration}} // expected-error{{expected '}'}} diff --git a/test/SemaObjC/method-not-defined.m b/test/SemaObjC/method-not-defined.m index 3848fa28c927..37171af2e889 100644 --- a/test/SemaObjC/method-not-defined.m +++ b/test/SemaObjC/method-not-defined.m @@ -1,4 +1,4 @@ -// RUN: clang-cc -fsyntax-only -verify %s +// RUN: clang -cc1 -fsyntax-only -verify %s @interface Foo @end diff --git a/test/SemaObjC/method-sentinel-attr.m b/test/SemaObjC/method-sentinel-attr.m index 8f31e9ab5e41..080d6649cc04 100644 --- a/test/SemaObjC/method-sentinel-attr.m +++ b/test/SemaObjC/method-sentinel-attr.m @@ -1,4 +1,4 @@ -// RUN: clang-cc -fsyntax-only -verify %s +// RUN: clang -cc1 -fsyntax-only -verify %s #define NULL (void*)0 diff --git a/test/SemaObjC/method-typecheck-1.m b/test/SemaObjC/method-typecheck-1.m index a53c4d9f416a..bd62ded3c413 100644 --- a/test/SemaObjC/method-typecheck-1.m +++ b/test/SemaObjC/method-typecheck-1.m @@ -1,4 +1,4 @@ -// RUN: clang-cc -fsyntax-only -verify %s +// RUN: clang -cc1 -fsyntax-only -verify %s @interface A - (void) setMoo: (int) x; // expected-note {{previous definition is here}} diff --git a/test/SemaObjC/method-typecheck-2.m b/test/SemaObjC/method-typecheck-2.m index d0a091d85615..642893da804d 100644 --- a/test/SemaObjC/method-typecheck-2.m +++ b/test/SemaObjC/method-typecheck-2.m @@ -1,4 +1,4 @@ -// RUN: clang-cc -fsyntax-only -verify %s +// RUN: clang -cc1 -fsyntax-only -verify %s @protocol P - (void) doSomethingInProtocol: (float) x; // expected-note {{previous definition is here}} diff --git a/test/SemaObjC/method-undef-category-warn-1.m b/test/SemaObjC/method-undef-category-warn-1.m index 82fd3c8ba6ff..8f5d1ace4c88 100644 --- a/test/SemaObjC/method-undef-category-warn-1.m +++ b/test/SemaObjC/method-undef-category-warn-1.m @@ -1,4 +1,4 @@ -// RUN: clang-cc -fsyntax-only -verify %s +// RUN: clang -cc1 -fsyntax-only -verify %s @interface MyClass1 @end diff --git a/test/SemaObjC/method-undef-extension-warn-1.m b/test/SemaObjC/method-undef-extension-warn-1.m index 7ce015f886ec..c1efe5a44fdc 100644 --- a/test/SemaObjC/method-undef-extension-warn-1.m +++ b/test/SemaObjC/method-undef-extension-warn-1.m @@ -1,4 +1,4 @@ -// RUN: clang-cc -fsyntax-only -verify %s +// RUN: clang -cc1 -fsyntax-only -verify %s @interface MyClass @end diff --git a/test/SemaObjC/method-undefined-warn-1.m b/test/SemaObjC/method-undefined-warn-1.m index fbb01dfb1f79..bbf993f13665 100644 --- a/test/SemaObjC/method-undefined-warn-1.m +++ b/test/SemaObjC/method-undefined-warn-1.m @@ -1,4 +1,4 @@ -// RUN: clang-cc -fsyntax-only -verify %s +// RUN: clang -cc1 -fsyntax-only -verify %s @interface INTF - (void) meth; diff --git a/test/SemaObjC/missing-method-context.m b/test/SemaObjC/missing-method-context.m index 2d0758b1fa8d..506cccf512a9 100644 --- a/test/SemaObjC/missing-method-context.m +++ b/test/SemaObjC/missing-method-context.m @@ -1,4 +1,4 @@ -// RUN: clang-cc %s -verify -fsyntax-only +// RUN: clang -cc1 %s -verify -fsyntax-only - (void)compilerTestAgainst; // expected-error {{missing context for method declaration}} void xx(); // expected-error {{expected method body}} diff --git a/test/SemaObjC/newproperty-class-method-1.m b/test/SemaObjC/newproperty-class-method-1.m index 4946210c8dcc..972f0909693d 100644 --- a/test/SemaObjC/newproperty-class-method-1.m +++ b/test/SemaObjC/newproperty-class-method-1.m @@ -1,4 +1,4 @@ -// RUN: clang-cc %s -verify -fsyntax-only +// RUN: clang -cc1 %s -verify -fsyntax-only @interface Subclass + (int)magicNumber; diff --git a/test/SemaObjC/no-gc-weak-test.m b/test/SemaObjC/no-gc-weak-test.m index f494929ce02d..498278ec91d7 100644 --- a/test/SemaObjC/no-gc-weak-test.m +++ b/test/SemaObjC/no-gc-weak-test.m @@ -1,4 +1,4 @@ -// RUN: clang-cc -triple i386-apple-darwin9 -fsyntax-only -verify %s +// RUN: clang -cc1 -triple i386-apple-darwin9 -fsyntax-only -verify %s @interface Subtask { diff --git a/test/SemaObjC/no-warn-qual-mismatch.m b/test/SemaObjC/no-warn-qual-mismatch.m index 3bd4dba545f5..73b56711e388 100644 --- a/test/SemaObjC/no-warn-qual-mismatch.m +++ b/test/SemaObjC/no-warn-qual-mismatch.m @@ -1,4 +1,4 @@ -// RUN: clang-cc -fsyntax-only -verify %s +// RUN: clang -cc1 -fsyntax-only -verify %s // radar 7211563 @interface X diff --git a/test/SemaObjC/no-warn-synth-protocol-meth.m b/test/SemaObjC/no-warn-synth-protocol-meth.m index 860a0ca2befe..8c8f33b56058 100644 --- a/test/SemaObjC/no-warn-synth-protocol-meth.m +++ b/test/SemaObjC/no-warn-synth-protocol-meth.m @@ -1,4 +1,4 @@ -// RUN: clang-cc -fsyntax-only -verify %s +// RUN: clang -cc1 -fsyntax-only -verify %s @protocol CYCdef - (int)name; diff --git a/test/SemaObjC/no-warn-unimpl-method.m b/test/SemaObjC/no-warn-unimpl-method.m index 2fcb06ff5e92..4345914092af 100644 --- a/test/SemaObjC/no-warn-unimpl-method.m +++ b/test/SemaObjC/no-warn-unimpl-method.m @@ -1,4 +1,4 @@ -// RUN: clang-cc -triple x86_64-apple-darwin10 -fsyntax-only -verify %s +// RUN: clang -cc1 -triple x86_64-apple-darwin10 -fsyntax-only -verify %s // This program tests that if class implements the forwardInvocation method, then // every method possible is implemented in the class and should not issue // warning of the "Method definition not found" kind. */ diff --git a/test/SemaObjC/nonnull.m b/test/SemaObjC/nonnull.m index 869bbbd57e85..e657707790d5 100644 --- a/test/SemaObjC/nonnull.m +++ b/test/SemaObjC/nonnull.m @@ -1,4 +1,4 @@ -// RUN: clang-cc -fblocks -fsyntax-only -verify %s +// RUN: clang -cc1 -fblocks -fsyntax-only -verify %s @class NSObject; diff --git a/test/SemaObjC/nsobject-attribute-1.m b/test/SemaObjC/nsobject-attribute-1.m index d1f673a9fba9..6eb5d63db2d1 100644 --- a/test/SemaObjC/nsobject-attribute-1.m +++ b/test/SemaObjC/nsobject-attribute-1.m @@ -1,4 +1,4 @@ -// RUN: clang-cc -fblocks -fsyntax-only -verify %s +// RUN: clang -cc1 -fblocks -fsyntax-only -verify %s @interface NSObject - (id)self; diff --git a/test/SemaObjC/nsobject-attribute.m b/test/SemaObjC/nsobject-attribute.m index c47b909846c1..896c44a3dc74 100644 --- a/test/SemaObjC/nsobject-attribute.m +++ b/test/SemaObjC/nsobject-attribute.m @@ -1,4 +1,4 @@ -// RUN: clang-cc -fsyntax-only -verify %s +// RUN: clang -cc1 -fsyntax-only -verify %s typedef struct CGColor * __attribute__ ((NSObject)) CGColorRef; static int count; diff --git a/test/SemaObjC/objc-string-constant.m b/test/SemaObjC/objc-string-constant.m index c6461dd1c25b..46d1242cc5e5 100644 --- a/test/SemaObjC/objc-string-constant.m +++ b/test/SemaObjC/objc-string-constant.m @@ -1,4 +1,4 @@ -// RUN: clang-cc -Wsemicolon-before-method-body %s -verify -fsyntax-only +// RUN: clang -cc1 -Wsemicolon-before-method-body %s -verify -fsyntax-only #define nil 0 /* id of Nil instance */ diff --git a/test/SemaObjC/objc2-merge-gc-attribue-decl.m b/test/SemaObjC/objc2-merge-gc-attribue-decl.m index 0da0ce876d3e..c15e10781a3d 100644 --- a/test/SemaObjC/objc2-merge-gc-attribue-decl.m +++ b/test/SemaObjC/objc2-merge-gc-attribue-decl.m @@ -1,4 +1,4 @@ -// RUN: clang-cc -triple i386-apple-darwin9 -fobjc-gc -fsyntax-only -verify %s +// RUN: clang -cc1 -triple i386-apple-darwin9 -fobjc-gc -fsyntax-only -verify %s @interface INTF @end extern INTF* p2; diff --git a/test/SemaObjC/objc2-warn-weak-decl.m b/test/SemaObjC/objc2-warn-weak-decl.m index 5de52ba2203c..bd59c6613304 100644 --- a/test/SemaObjC/objc2-warn-weak-decl.m +++ b/test/SemaObjC/objc2-warn-weak-decl.m @@ -1,4 +1,4 @@ -// RUN: clang-cc -triple i386-apple-darwin9 -fsyntax-only -fobjc-gc -verify %s +// RUN: clang -cc1 -triple i386-apple-darwin9 -fsyntax-only -fobjc-gc -verify %s struct S { __weak id p; // expected-warning {{__weak attribute cannot be specified on a field declaration}} }; diff --git a/test/SemaObjC/property-10.m b/test/SemaObjC/property-10.m index 81b8ee199cb2..cf615bcde7cd 100644 --- a/test/SemaObjC/property-10.m +++ b/test/SemaObjC/property-10.m @@ -1,4 +1,4 @@ -// RUN: clang-cc -fsyntax-only -Wreadonly-setter-attrs -verify %s -fblocks +// RUN: clang -cc1 -fsyntax-only -Wreadonly-setter-attrs -verify %s -fblocks // Check property attribute consistency. diff --git a/test/SemaObjC/property-11.m b/test/SemaObjC/property-11.m index bb36c2766e75..c9b35402ae77 100644 --- a/test/SemaObjC/property-11.m +++ b/test/SemaObjC/property-11.m @@ -1,4 +1,4 @@ -// RUN: clang-cc -fsyntax-only -verify %s +// RUN: clang -cc1 -fsyntax-only -verify %s @interface NSSound @end diff --git a/test/SemaObjC/property-12.m b/test/SemaObjC/property-12.m index 50fb63bc006b..f022dcda4389 100644 --- a/test/SemaObjC/property-12.m +++ b/test/SemaObjC/property-12.m @@ -1,4 +1,4 @@ -// RUN: clang-cc -fsyntax-only -Wreadonly-setter-attrs -verify %s +// RUN: clang -cc1 -fsyntax-only -Wreadonly-setter-attrs -verify %s @protocol P0 @property(readonly,assign) id X; // expected-warning {{property attributes 'readonly' and 'assign' are mutually exclusive}} diff --git a/test/SemaObjC/property-13.m b/test/SemaObjC/property-13.m index d0e40dcf86ed..23e3714accf9 100644 --- a/test/SemaObjC/property-13.m +++ b/test/SemaObjC/property-13.m @@ -1,4 +1,4 @@ -// RUN: clang-cc -fsyntax-only -verify %s +// RUN: clang -cc1 -fsyntax-only -verify %s @interface NSObject + alloc; diff --git a/test/SemaObjC/property-2.m b/test/SemaObjC/property-2.m index 159e06b07afa..01fcdb9fa881 100644 --- a/test/SemaObjC/property-2.m +++ b/test/SemaObjC/property-2.m @@ -1,4 +1,4 @@ -// RUN: clang-cc -fsyntax-only -verify %s +// RUN: clang -cc1 -fsyntax-only -verify %s @interface Tester @property char PropertyAtomic_char; diff --git a/test/SemaObjC/property-3.m b/test/SemaObjC/property-3.m index a66b3d5e1e16..c79efc823a13 100644 --- a/test/SemaObjC/property-3.m +++ b/test/SemaObjC/property-3.m @@ -1,4 +1,4 @@ -// RUN: clang-cc -verify %s +// RUN: clang -cc1 -verify %s @interface I { diff --git a/test/SemaObjC/property-4.m b/test/SemaObjC/property-4.m index 56db28274c1a..b70514f1ae63 100644 --- a/test/SemaObjC/property-4.m +++ b/test/SemaObjC/property-4.m @@ -1,4 +1,4 @@ -// RUN: clang-cc -verify %s +// RUN: clang -cc1 -verify %s @interface Object @end diff --git a/test/SemaObjC/property-5.m b/test/SemaObjC/property-5.m index f463aae62910..40b9e67f6311 100644 --- a/test/SemaObjC/property-5.m +++ b/test/SemaObjC/property-5.m @@ -1,4 +1,4 @@ -// RUN: clang-cc -verify %s +// RUN: clang -cc1 -verify %s @protocol P1 @end @protocol P2 @end diff --git a/test/SemaObjC/property-6.m b/test/SemaObjC/property-6.m index 8f77cf1ad212..0253fe889b1a 100644 --- a/test/SemaObjC/property-6.m +++ b/test/SemaObjC/property-6.m @@ -1,4 +1,4 @@ -// RUN: clang-cc -fsyntax-only -verify %s +// RUN: clang -cc1 -fsyntax-only -verify %s # 1 "" # 1 "/System/Library/Frameworks/Foundation.framework/Headers/Foundation.h" 1 3 typedef signed char BOOL; diff --git a/test/SemaObjC/property-7.m b/test/SemaObjC/property-7.m index 99c16cef73d8..63eb3cf2cb80 100644 --- a/test/SemaObjC/property-7.m +++ b/test/SemaObjC/property-7.m @@ -1,4 +1,4 @@ -// RUN: clang-cc -fsyntax-only -verify %s +// RUN: clang -cc1 -fsyntax-only -verify %s typedef signed char BOOL; typedef struct _NSZone NSZone; diff --git a/test/SemaObjC/property-8.m b/test/SemaObjC/property-8.m index 49bd409f27c5..82d8c6b00208 100644 --- a/test/SemaObjC/property-8.m +++ b/test/SemaObjC/property-8.m @@ -1,4 +1,4 @@ -// RUN: clang-cc -fsyntax-only -verify %s +// RUN: clang -cc1 -fsyntax-only -verify %s typedef signed char BOOL; typedef unsigned int NSUInteger; typedef struct _NSZone NSZone; diff --git a/test/SemaObjC/property-9-impl-method.m b/test/SemaObjC/property-9-impl-method.m index 06cb30482c82..c7b149717ec5 100644 --- a/test/SemaObjC/property-9-impl-method.m +++ b/test/SemaObjC/property-9-impl-method.m @@ -1,4 +1,4 @@ -// RUN: clang-cc %s -fsyntax-only -verify +// RUN: clang -cc1 %s -fsyntax-only -verify // rdar://5967199 typedef signed char BOOL; diff --git a/test/SemaObjC/property-9.m b/test/SemaObjC/property-9.m index 752f9c09ebf6..a3faa4822f31 100644 --- a/test/SemaObjC/property-9.m +++ b/test/SemaObjC/property-9.m @@ -1,4 +1,4 @@ -// RUN: clang-cc -fsyntax-only -verify %s +// RUN: clang -cc1 -fsyntax-only -verify %s typedef signed char BOOL; @protocol NSObject - (BOOL)isEqual:(id)object; @end diff --git a/test/SemaObjC/property-category-1.m b/test/SemaObjC/property-category-1.m index fa9d4c8c4bb9..d6b580080d48 100644 --- a/test/SemaObjC/property-category-1.m +++ b/test/SemaObjC/property-category-1.m @@ -1,4 +1,4 @@ -// RUN: clang-cc -fsyntax-only -verify %s +// RUN: clang -cc1 -fsyntax-only -verify %s @interface Object + (id)new; diff --git a/test/SemaObjC/property-category-2.m b/test/SemaObjC/property-category-2.m index c245e36819cc..6a3883a35b77 100644 --- a/test/SemaObjC/property-category-2.m +++ b/test/SemaObjC/property-category-2.m @@ -1,4 +1,4 @@ -// RUN: clang-cc -fsyntax-only -verify %s +// RUN: clang -cc1 -fsyntax-only -verify %s // Test that a property can be synthesize in a category // implementation with no error. diff --git a/test/SemaObjC/property-category-3.m b/test/SemaObjC/property-category-3.m index bf9e8cbd9d9f..de0f302bc5d7 100644 --- a/test/SemaObjC/property-category-3.m +++ b/test/SemaObjC/property-category-3.m @@ -1,4 +1,4 @@ -// RUN: clang-cc -fsyntax-only -verify %s +// RUN: clang -cc1 -fsyntax-only -verify %s @protocol P @property(readonly) int X; diff --git a/test/SemaObjC/property-category-4.m b/test/SemaObjC/property-category-4.m index ee08b09c0137..c807f394544b 100644 --- a/test/SemaObjC/property-category-4.m +++ b/test/SemaObjC/property-category-4.m @@ -1,4 +1,4 @@ -// RUN: clang-cc -fsyntax-only -verify %s +// RUN: clang -cc1 -fsyntax-only -verify %s @interface IDELogNavigator { diff --git a/test/SemaObjC/property-error-readonly-assign.m b/test/SemaObjC/property-error-readonly-assign.m index d5cef78f18f4..482ae2cb8189 100644 --- a/test/SemaObjC/property-error-readonly-assign.m +++ b/test/SemaObjC/property-error-readonly-assign.m @@ -1,4 +1,4 @@ -// RUN: clang-cc -fsyntax-only -verify %s +// RUN: clang -cc1 -fsyntax-only -verify %s @interface A -(int) x; diff --git a/test/SemaObjC/property-expression-error.m b/test/SemaObjC/property-expression-error.m index b648ee939dbe..f03244dc79fb 100644 --- a/test/SemaObjC/property-expression-error.m +++ b/test/SemaObjC/property-expression-error.m @@ -1,4 +1,4 @@ -// RUN: clang-cc -fsyntax-only -verify %s +// RUN: clang -cc1 -fsyntax-only -verify %s @interface AddressMyProperties { diff --git a/test/SemaObjC/property-impl-misuse.m b/test/SemaObjC/property-impl-misuse.m index 7b956b5f7b4d..5bbc3f19c090 100644 --- a/test/SemaObjC/property-impl-misuse.m +++ b/test/SemaObjC/property-impl-misuse.m @@ -1,4 +1,4 @@ -// RUN: clang-cc -fsyntax-only -verify %s +// RUN: clang -cc1 -fsyntax-only -verify %s @interface I { int Y; diff --git a/test/SemaObjC/property-inherited.m b/test/SemaObjC/property-inherited.m index 6c06b90a9f0a..67897526224d 100644 --- a/test/SemaObjC/property-inherited.m +++ b/test/SemaObjC/property-inherited.m @@ -1,4 +1,4 @@ -// RUN: clang-cc %s -fsyntax-only -verify +// RUN: clang -cc1 %s -fsyntax-only -verify // Inherited overridden protocol declared objects don't work diff --git a/test/SemaObjC/property-ivar-mismatch.m b/test/SemaObjC/property-ivar-mismatch.m index 75c1e97c4ee9..d4f6e1a4f4e1 100644 --- a/test/SemaObjC/property-ivar-mismatch.m +++ b/test/SemaObjC/property-ivar-mismatch.m @@ -1,4 +1,4 @@ -// RUN: clang-cc -fsyntax-only -verify %s +// RUN: clang -cc1 -fsyntax-only -verify %s // Test that arithmatic types on property and its ivar have exact match. @interface Test4 diff --git a/test/SemaObjC/property-method-lookup-impl.m b/test/SemaObjC/property-method-lookup-impl.m index 295bba524009..f85babafbdbd 100644 --- a/test/SemaObjC/property-method-lookup-impl.m +++ b/test/SemaObjC/property-method-lookup-impl.m @@ -1,4 +1,4 @@ -// RUN: clang-cc -fsyntax-only -verify %s +// RUN: clang -cc1 -fsyntax-only -verify %s @interface SSyncCEList { diff --git a/test/SemaObjC/property-missing.m b/test/SemaObjC/property-missing.m index 301907ad1c7d..a74cf6236dbe 100644 --- a/test/SemaObjC/property-missing.m +++ b/test/SemaObjC/property-missing.m @@ -1,4 +1,4 @@ -// RUN: clang-cc -fsyntax-only -verify %s +// RUN: clang -cc1 -fsyntax-only -verify %s // PR3234 diff --git a/test/SemaObjC/property-nonfragile-abi.m b/test/SemaObjC/property-nonfragile-abi.m index 835209102199..ede9515123c1 100644 --- a/test/SemaObjC/property-nonfragile-abi.m +++ b/test/SemaObjC/property-nonfragile-abi.m @@ -1,4 +1,4 @@ -// RUN: clang-cc -fsyntax-only -fobjc-nonfragile-abi -verify %s +// RUN: clang -cc1 -fsyntax-only -fobjc-nonfragile-abi -verify %s typedef signed char BOOL; diff --git a/test/SemaObjC/property-noprotocol-warning.m b/test/SemaObjC/property-noprotocol-warning.m index 95ec15aa1e0c..20234a0b2ab3 100644 --- a/test/SemaObjC/property-noprotocol-warning.m +++ b/test/SemaObjC/property-noprotocol-warning.m @@ -1,4 +1,4 @@ -// RUN: clang-cc -fsyntax-only -verify %s +// RUN: clang -cc1 -fsyntax-only -verify %s @interface Object diff --git a/test/SemaObjC/property-redundant-decl-accessor.m b/test/SemaObjC/property-redundant-decl-accessor.m index ffd5129c8e5a..84fc8fa3be4f 100644 --- a/test/SemaObjC/property-redundant-decl-accessor.m +++ b/test/SemaObjC/property-redundant-decl-accessor.m @@ -1,4 +1,4 @@ -// RUN: clang-cc -fsyntax-only -Werror -verify %s +// RUN: clang -cc1 -fsyntax-only -Werror -verify %s @interface MyClass { const char *_myName; diff --git a/test/SemaObjC/property-typecheck-1.m b/test/SemaObjC/property-typecheck-1.m index ca8a1393b01b..c9562787983a 100644 --- a/test/SemaObjC/property-typecheck-1.m +++ b/test/SemaObjC/property-typecheck-1.m @@ -1,4 +1,4 @@ -// RUN: clang-cc -fsyntax-only -verify %s +// RUN: clang -cc1 -fsyntax-only -verify %s @interface A -(float) x; // expected-note {{declared at}} diff --git a/test/SemaObjC/property-user-setter.m b/test/SemaObjC/property-user-setter.m index 9b0380ede88e..94458dca6ee0 100644 --- a/test/SemaObjC/property-user-setter.m +++ b/test/SemaObjC/property-user-setter.m @@ -1,4 +1,4 @@ -// RUN: clang-cc -fsyntax-only -verify %s +// RUN: clang -cc1 -fsyntax-only -verify %s @interface I0 @property(readonly) int x; diff --git a/test/SemaObjC/property-weak.m b/test/SemaObjC/property-weak.m index 293432fc828f..2e4e1f0044fd 100644 --- a/test/SemaObjC/property-weak.m +++ b/test/SemaObjC/property-weak.m @@ -1,4 +1,4 @@ -// RUN: clang-cc -triple i386-apple-darwin9 -fsyntax-only -verify %s +// RUN: clang -cc1 -triple i386-apple-darwin9 -fsyntax-only -verify %s @interface foo @property(nonatomic) int foo __attribute__((weak_import)); diff --git a/test/SemaObjC/property.m b/test/SemaObjC/property.m index cf2624f8204d..b2f594fe3201 100644 --- a/test/SemaObjC/property.m +++ b/test/SemaObjC/property.m @@ -1,4 +1,4 @@ -// RUN: clang-cc -triple i386-apple-darwin9 -fsyntax-only -verify %s +// RUN: clang -cc1 -triple i386-apple-darwin9 -fsyntax-only -verify %s @interface I { diff --git a/test/SemaObjC/props-on-prots.m b/test/SemaObjC/props-on-prots.m index 7bee8a0bc319..dd92bfac49c1 100644 --- a/test/SemaObjC/props-on-prots.m +++ b/test/SemaObjC/props-on-prots.m @@ -1,4 +1,4 @@ -// RUN: clang-cc -fsyntax-only -verify %s +// RUN: clang -cc1 -fsyntax-only -verify %s typedef signed char BOOL; @class NSInvocation, NSMethodSignature, NSCoder, NSString, NSEnumerator; diff --git a/test/SemaObjC/protocol-archane.m b/test/SemaObjC/protocol-archane.m index 05f5103178f2..c24e9fb5ed16 100644 --- a/test/SemaObjC/protocol-archane.m +++ b/test/SemaObjC/protocol-archane.m @@ -1,4 +1,4 @@ -// RUN: clang-cc -fsyntax-only -verify %s +// RUN: clang -cc1 -fsyntax-only -verify %s // rdar://5986251 @protocol SomeProtocol diff --git a/test/SemaObjC/protocol-attribute.m b/test/SemaObjC/protocol-attribute.m index 6bd58dd9a03a..1bce37e49d84 100644 --- a/test/SemaObjC/protocol-attribute.m +++ b/test/SemaObjC/protocol-attribute.m @@ -1,4 +1,4 @@ -// RUN: clang-cc -fsyntax-only -verify %s +// RUN: clang -cc1 -fsyntax-only -verify %s __attribute ((unavailable)) @protocol FwProto; // expected-note{{marked unavailable}} diff --git a/test/SemaObjC/protocol-expr-1.m b/test/SemaObjC/protocol-expr-1.m index cc1c3231d5e5..22c0ed0ba4c3 100644 --- a/test/SemaObjC/protocol-expr-1.m +++ b/test/SemaObjC/protocol-expr-1.m @@ -1,4 +1,4 @@ -// RUN: clang-cc -fsyntax-only -verify %s +// RUN: clang -cc1 -fsyntax-only -verify %s @protocol fproto; diff --git a/test/SemaObjC/protocol-expr-neg-1.m b/test/SemaObjC/protocol-expr-neg-1.m index 9393fde3c3c7..2928a46bc07a 100644 --- a/test/SemaObjC/protocol-expr-neg-1.m +++ b/test/SemaObjC/protocol-expr-neg-1.m @@ -1,4 +1,4 @@ -// RUN: clang-cc -fsyntax-only -verify %s +// RUN: clang -cc1 -fsyntax-only -verify %s @class Protocol; diff --git a/test/SemaObjC/protocol-id-test-1.m b/test/SemaObjC/protocol-id-test-1.m index 5e737a8fae07..79220ea1a459 100644 --- a/test/SemaObjC/protocol-id-test-1.m +++ b/test/SemaObjC/protocol-id-test-1.m @@ -1,4 +1,4 @@ -// RUN: clang-cc -verify %s +// RUN: clang -cc1 -verify %s @interface FF - (void) Meth; diff --git a/test/SemaObjC/protocol-id-test-2.m b/test/SemaObjC/protocol-id-test-2.m index a55923c21058..b8f94a6d7579 100644 --- a/test/SemaObjC/protocol-id-test-2.m +++ b/test/SemaObjC/protocol-id-test-2.m @@ -1,4 +1,4 @@ -// RUN: clang-cc -verify %s +// RUN: clang -cc1 -verify %s @protocol P @end diff --git a/test/SemaObjC/protocol-id-test-3.m b/test/SemaObjC/protocol-id-test-3.m index 3c7f84a181f1..54c55cd4845e 100644 --- a/test/SemaObjC/protocol-id-test-3.m +++ b/test/SemaObjC/protocol-id-test-3.m @@ -1,4 +1,4 @@ -// RUN: clang-cc -pedantic -fsyntax-only -verify %s +// RUN: clang -cc1 -pedantic -fsyntax-only -verify %s @protocol MyProto1 @end diff --git a/test/SemaObjC/protocol-implementation-inherited.m b/test/SemaObjC/protocol-implementation-inherited.m index 55b92ae6684a..4fc60fe5c98f 100644 --- a/test/SemaObjC/protocol-implementation-inherited.m +++ b/test/SemaObjC/protocol-implementation-inherited.m @@ -1,4 +1,4 @@ -// RUN: clang-cc -fsyntax-only -verify %s +// RUN: clang -cc1 -fsyntax-only -verify %s @protocol P0 -bar; diff --git a/test/SemaObjC/protocol-lookup-2.m b/test/SemaObjC/protocol-lookup-2.m index 64d0c3acf036..744fbee9828d 100644 --- a/test/SemaObjC/protocol-lookup-2.m +++ b/test/SemaObjC/protocol-lookup-2.m @@ -1,4 +1,4 @@ -// RUN: clang-cc -fsyntax-only -verify %s +// RUN: clang -cc1 -fsyntax-only -verify %s @interface NSObject @end @protocol ProtocolA diff --git a/test/SemaObjC/protocol-lookup.m b/test/SemaObjC/protocol-lookup.m index 87655bd9e7a0..b2b354b7782d 100644 --- a/test/SemaObjC/protocol-lookup.m +++ b/test/SemaObjC/protocol-lookup.m @@ -1,4 +1,4 @@ -// RUN: clang-cc -fsyntax-only -verify %s +// RUN: clang -cc1 -fsyntax-only -verify %s @protocol NSObject - retain; - release; diff --git a/test/SemaObjC/protocol-qualified-class-unsupported.m b/test/SemaObjC/protocol-qualified-class-unsupported.m index 6e344c1f4414..e4e12d6a39d4 100644 --- a/test/SemaObjC/protocol-qualified-class-unsupported.m +++ b/test/SemaObjC/protocol-qualified-class-unsupported.m @@ -1,4 +1,4 @@ -// RUN: clang-cc -fsyntax-only -verify %s +// RUN: clang -cc1 -fsyntax-only -verify %s #include diff --git a/test/SemaObjC/protocol-typecheck.m b/test/SemaObjC/protocol-typecheck.m index de66dedda70a..e91cdfefb728 100644 --- a/test/SemaObjC/protocol-typecheck.m +++ b/test/SemaObjC/protocol-typecheck.m @@ -1,4 +1,4 @@ -// RUN: clang-cc -fsyntax-only -verify %s +// RUN: clang -cc1 -fsyntax-only -verify %s @interface NSObject @end @protocol XCElementP @end diff --git a/test/SemaObjC/protocols.m b/test/SemaObjC/protocols.m index 9fbdc16759dd..579feee7b9c2 100644 --- a/test/SemaObjC/protocols.m +++ b/test/SemaObjC/protocols.m @@ -1,4 +1,4 @@ -// RUN: clang-cc -fsyntax-only -verify %s +// RUN: clang -cc1 -fsyntax-only -verify %s @interface INTF1 @required // expected-error {{directive may only be specified in protocols only}} diff --git a/test/SemaObjC/rdr-6211479-array-property.m b/test/SemaObjC/rdr-6211479-array-property.m index 1781c5a40402..a5d177335cee 100644 --- a/test/SemaObjC/rdr-6211479-array-property.m +++ b/test/SemaObjC/rdr-6211479-array-property.m @@ -1,4 +1,4 @@ -// RUN: clang-cc -fsyntax-only -verify %s +// RUN: clang -cc1 -fsyntax-only -verify %s // typedef int T[2]; diff --git a/test/SemaObjC/restrict-id-type.m b/test/SemaObjC/restrict-id-type.m new file mode 100644 index 000000000000..9bd5612aba33 --- /dev/null +++ b/test/SemaObjC/restrict-id-type.m @@ -0,0 +1,9 @@ +// RUN: clang -cc1 -std=gnu99 -fsyntax-only -verify %s + +void f0(restrict id a0) {} + +void f1(restrict id *a0) {} + +void f2(restrict Class a0) {} + +void f3(restrict Class *a0) {} diff --git a/test/SemaObjC/return.m b/test/SemaObjC/return.m index ff6499479458..743f0f9fca30 100644 --- a/test/SemaObjC/return.m +++ b/test/SemaObjC/return.m @@ -1,4 +1,4 @@ -// RUN: clang-cc %s -fsyntax-only -verify -Wmissing-noreturn +// RUN: clang -cc1 %s -fsyntax-only -verify -Wmissing-noreturn int test1() { id a; diff --git a/test/SemaObjC/scope-check.m b/test/SemaObjC/scope-check.m index 0835373ba748..618bcd7bf1e3 100644 --- a/test/SemaObjC/scope-check.m +++ b/test/SemaObjC/scope-check.m @@ -1,4 +1,4 @@ -// RUN: clang-cc -fsyntax-only -verify %s +// RUN: clang -cc1 -fsyntax-only -verify %s @class A, B, C; diff --git a/test/SemaObjC/selector-1.m b/test/SemaObjC/selector-1.m index a969b100cc68..7df2bdaeb701 100644 --- a/test/SemaObjC/selector-1.m +++ b/test/SemaObjC/selector-1.m @@ -1,4 +1,4 @@ -// RUN: clang-cc -verify %s +// RUN: clang -cc1 -verify %s @interface Lancelot @end @implementation Lancelot diff --git a/test/SemaObjC/selector-error.m b/test/SemaObjC/selector-error.m index cc2a40472640..0df5df0bcc10 100644 --- a/test/SemaObjC/selector-error.m +++ b/test/SemaObjC/selector-error.m @@ -1,4 +1,4 @@ -// RUN: clang-cc -fsyntax-only -verify %s +// RUN: clang -cc1 -fsyntax-only -verify %s @interface Foo - (char*) foo; diff --git a/test/SemaObjC/selector-overload.m b/test/SemaObjC/selector-overload.m index 7c30f79ceaec..65c907eacded 100644 --- a/test/SemaObjC/selector-overload.m +++ b/test/SemaObjC/selector-overload.m @@ -1,4 +1,4 @@ -// RUN: clang-cc %s -fsyntax-only +// RUN: clang -cc1 %s -fsyntax-only @interface NSObject + alloc; diff --git a/test/SemaObjC/sizeof-interface.m b/test/SemaObjC/sizeof-interface.m index aeb1b3facb73..cb4195bbd99b 100644 --- a/test/SemaObjC/sizeof-interface.m +++ b/test/SemaObjC/sizeof-interface.m @@ -1,4 +1,4 @@ -// RUN: clang-cc -fobjc-nonfragile-abi -verify -fsyntax-only %s +// RUN: clang -cc1 -fobjc-nonfragile-abi -verify -fsyntax-only %s @class I0; diff --git a/test/SemaObjC/static-ivar-ref-1.m b/test/SemaObjC/static-ivar-ref-1.m index 7e07c7cb99a2..5c977580e702 100644 --- a/test/SemaObjC/static-ivar-ref-1.m +++ b/test/SemaObjC/static-ivar-ref-1.m @@ -1,5 +1,5 @@ -// RUN: clang-cc -triple i386-unknown-unknown -ast-print %s -// RUN: clang-cc -triple x86_64-apple-darwin10 -ast-print %s +// RUN: clang -cc1 -triple i386-unknown-unknown -ast-print %s +// RUN: clang -cc1 -triple x86_64-apple-darwin10 -ast-print %s @interface current { diff --git a/test/SemaObjC/stmts.m b/test/SemaObjC/stmts.m index 1d4ea0a77189..1402b288b3e8 100644 --- a/test/SemaObjC/stmts.m +++ b/test/SemaObjC/stmts.m @@ -1,4 +1,4 @@ -// RUN: clang-cc %s -verify -fsyntax-only +// RUN: clang -cc1 %s -verify -fsyntax-only struct some_struct; diff --git a/test/SemaObjC/string.m b/test/SemaObjC/string.m index 3c09c3c03622..077ba7d93e01 100644 --- a/test/SemaObjC/string.m +++ b/test/SemaObjC/string.m @@ -1,5 +1,5 @@ -// RUN: clang-cc %s -verify -fsyntax-only -// RUN: clang-cc %s -verify -fsyntax-only -DDECLAREIT +// RUN: clang -cc1 %s -verify -fsyntax-only +// RUN: clang -cc1 %s -verify -fsyntax-only -DDECLAREIT // a declaration of NSConstantString is not required. #ifdef DECLAREIT diff --git a/test/SemaObjC/super-cat-prot.m b/test/SemaObjC/super-cat-prot.m index 6ddc31fbb9e6..a7288bbc3bab 100644 --- a/test/SemaObjC/super-cat-prot.m +++ b/test/SemaObjC/super-cat-prot.m @@ -1,4 +1,4 @@ -// RUN: clang-cc -fsyntax-only -verify %s +// RUN: clang -cc1 -fsyntax-only -verify %s typedef signed char BOOL; typedef unsigned int NSUInteger; @class NSInvocation, NSMethodSignature, NSCoder, NSString, NSEnumerator; diff --git a/test/SemaObjC/super-property-message-expr.m b/test/SemaObjC/super-property-message-expr.m index 082d8bd5b48a..15d4db00414d 100644 --- a/test/SemaObjC/super-property-message-expr.m +++ b/test/SemaObjC/super-property-message-expr.m @@ -1,4 +1,4 @@ -// RUN: clang-cc -fsyntax-only -verify %s +// RUN: clang -cc1 -fsyntax-only -verify %s @interface SStoreNodeInfo diff --git a/test/SemaObjC/super-property-notation.m b/test/SemaObjC/super-property-notation.m index 3b0887f26eff..d67bdcb8e6f0 100644 --- a/test/SemaObjC/super-property-notation.m +++ b/test/SemaObjC/super-property-notation.m @@ -1,4 +1,4 @@ -// RUN: clang-cc -fsyntax-only -verify %s +// RUN: clang -cc1 -fsyntax-only -verify %s @interface B +(int) classGetter; diff --git a/test/SemaObjC/super.m b/test/SemaObjC/super.m index 83842afb9c3f..2896968e464d 100644 --- a/test/SemaObjC/super.m +++ b/test/SemaObjC/super.m @@ -1,4 +1,4 @@ -// RUN: clang-cc -fsyntax-only -verify %s +// RUN: clang -cc1 -fsyntax-only -verify %s @interface Foo - iMethod; diff --git a/test/SemaObjC/synchronized.m b/test/SemaObjC/synchronized.m index 01f82c168622..d1aa101c7dc2 100644 --- a/test/SemaObjC/synchronized.m +++ b/test/SemaObjC/synchronized.m @@ -1,4 +1,4 @@ -// RUN: clang-cc -fsyntax-only -verify %s +// RUN: clang -cc1 -fsyntax-only -verify %s @interface PBXTrackableTaskManager @end diff --git a/test/SemaObjC/synthesize-setter-contclass.m b/test/SemaObjC/synthesize-setter-contclass.m index 78490c8db0d3..184c4ead0785 100644 --- a/test/SemaObjC/synthesize-setter-contclass.m +++ b/test/SemaObjC/synthesize-setter-contclass.m @@ -1,4 +1,4 @@ -// RUN: clang-cc -fsyntax-only -verify %s +// RUN: clang -cc1 -fsyntax-only -verify %s @interface TestClass { diff --git a/test/SemaObjC/synthesized-ivar.m b/test/SemaObjC/synthesized-ivar.m index 305629b43ce6..c41884eef712 100644 --- a/test/SemaObjC/synthesized-ivar.m +++ b/test/SemaObjC/synthesized-ivar.m @@ -1,4 +1,4 @@ -// RUN: clang-cc -fsyntax-only -fobjc-nonfragile-abi -verify %s +// RUN: clang -cc1 -fsyntax-only -fobjc-nonfragile-abi -verify %s @interface I { } diff --git a/test/SemaObjC/try-catch.m b/test/SemaObjC/try-catch.m index 453d80fd5996..fb6182cc76d7 100644 --- a/test/SemaObjC/try-catch.m +++ b/test/SemaObjC/try-catch.m @@ -1,4 +1,4 @@ -// RUN: clang-cc -fsyntax-only -verify %s +// RUN: clang -cc1 -fsyntax-only -verify %s typedef signed char BOOL; typedef struct _NSZone NSZone; diff --git a/test/SemaObjC/typedef-class.m b/test/SemaObjC/typedef-class.m index 128815602d4d..0c48715f19bd 100644 --- a/test/SemaObjC/typedef-class.m +++ b/test/SemaObjC/typedef-class.m @@ -1,4 +1,4 @@ -// RUN: clang-cc -fsyntax-only -verify %s +// RUN: clang -cc1 -fsyntax-only -verify %s typedef signed char BOOL; typedef unsigned int NSUInteger; typedef struct _NSZone NSZone; diff --git a/test/SemaObjC/ucn-objc-string.m b/test/SemaObjC/ucn-objc-string.m index 1d94ea2363a1..7603199d0211 100644 --- a/test/SemaObjC/ucn-objc-string.m +++ b/test/SemaObjC/ucn-objc-string.m @@ -1,4 +1,4 @@ -// RUN: clang %s -verify -fsyntax-only +// RUN: clang -cc1 %s -verify -fsyntax-only @class NSString; extern void NSLog(NSString *format, ...) __attribute__((format(__NSString__, 1, 2))); diff --git a/test/SemaObjC/undeclared-selector.m b/test/SemaObjC/undeclared-selector.m index 354c3162c245..6791aaf0f361 100644 --- a/test/SemaObjC/undeclared-selector.m +++ b/test/SemaObjC/undeclared-selector.m @@ -1,4 +1,4 @@ -// RUN: clang-cc -fsyntax-only -Wundeclared-selector -verify %s +// RUN: clang -cc1 -fsyntax-only -Wundeclared-selector -verify %s typedef struct objc_selector *SEL; diff --git a/test/SemaObjC/undef-class-messagin-error.m b/test/SemaObjC/undef-class-messagin-error.m index 114b6ca5f6f4..d8e50a0acd22 100644 --- a/test/SemaObjC/undef-class-messagin-error.m +++ b/test/SemaObjC/undef-class-messagin-error.m @@ -1,4 +1,4 @@ -// RUN: clang-cc -fsyntax-only -verify %s +// RUN: clang -cc1 -fsyntax-only -verify %s @interface _Child + (int) flashCache; diff --git a/test/SemaObjC/undef-protocol-methods-1.m b/test/SemaObjC/undef-protocol-methods-1.m index 05245523fb6a..066d53218bbf 100644 --- a/test/SemaObjC/undef-protocol-methods-1.m +++ b/test/SemaObjC/undef-protocol-methods-1.m @@ -1,4 +1,4 @@ -// RUN: clang-cc -fsyntax-only -verify %s +// RUN: clang -cc1 -fsyntax-only -verify %s @protocol P1 - (void) P1proto; diff --git a/test/SemaObjC/undef-superclass-1.m b/test/SemaObjC/undef-superclass-1.m index cb15dc39a3dc..2deb0b1ae60f 100644 --- a/test/SemaObjC/undef-superclass-1.m +++ b/test/SemaObjC/undef-superclass-1.m @@ -1,4 +1,4 @@ -// RUN: clang-cc -fsyntax-only -verify %s +// RUN: clang -cc1 -fsyntax-only -verify %s @class SUPER, Y; diff --git a/test/SemaObjC/undefined-protocol-type-1.m b/test/SemaObjC/undefined-protocol-type-1.m index 572d55f26854..c2e2abc5bb60 100644 --- a/test/SemaObjC/undefined-protocol-type-1.m +++ b/test/SemaObjC/undefined-protocol-type-1.m @@ -1,4 +1,4 @@ -// RUN: clang-cc -fsyntax-only -verify %s +// RUN: clang -cc1 -fsyntax-only -verify %s @protocol p1, p4; @protocol p2 @end diff --git a/test/SemaObjC/unused.m b/test/SemaObjC/unused.m index 4e85894b0a1b..f492ac5d3789 100644 --- a/test/SemaObjC/unused.m +++ b/test/SemaObjC/unused.m @@ -1,4 +1,4 @@ -// RUN: clang-cc %s -verify -Wunused -fsyntax-only +// RUN: clang -cc1 %s -verify -Wunused -fsyntax-only int printf(const char *, ...); diff --git a/test/SemaObjC/va-method-1.m b/test/SemaObjC/va-method-1.m index 3c8998f983ce..424ecab006d6 100644 --- a/test/SemaObjC/va-method-1.m +++ b/test/SemaObjC/va-method-1.m @@ -1,4 +1,4 @@ -// RUN: clang-cc -fsyntax-only -verify %s +// RUN: clang -cc1 -fsyntax-only -verify %s #include diff --git a/test/SemaObjC/warn-assign-property-nscopying.m b/test/SemaObjC/warn-assign-property-nscopying.m index cf1acc466a27..ecf2c6a00a62 100644 --- a/test/SemaObjC/warn-assign-property-nscopying.m +++ b/test/SemaObjC/warn-assign-property-nscopying.m @@ -1,4 +1,4 @@ -// RUN: clang-cc -fobjc-gc -fsyntax-only -verify %s +// RUN: clang -cc1 -fobjc-gc -fsyntax-only -verify %s @protocol NSCopying @end diff --git a/test/SemaObjC/warn-selector-selection.m b/test/SemaObjC/warn-selector-selection.m index 4918de77dc7b..19c9154a36b2 100644 --- a/test/SemaObjC/warn-selector-selection.m +++ b/test/SemaObjC/warn-selector-selection.m @@ -1,4 +1,4 @@ -// RUN: clang-cc -fsyntax-only -verify %s +// RUN: clang -cc1 -fsyntax-only -verify %s @interface Object - (void)foo; diff --git a/test/SemaObjC/warn-superclass-method-mismatch.m b/test/SemaObjC/warn-superclass-method-mismatch.m index f123a3f2ddac..acca86797e9d 100644 --- a/test/SemaObjC/warn-superclass-method-mismatch.m +++ b/test/SemaObjC/warn-superclass-method-mismatch.m @@ -1,4 +1,4 @@ -// RUN: clang-cc -fsyntax-only -Wsuper-class-method-mismatch -verify %s +// RUN: clang -cc1 -fsyntax-only -Wsuper-class-method-mismatch -verify %s @interface Root -(void) method_r: (char)ch : (float*)f1 : (int*) x; // expected-note {{previous declaration is here}} diff --git a/test/SemaObjC/warn-weak-field.m b/test/SemaObjC/warn-weak-field.m index 3850f217beea..b688a1fea009 100644 --- a/test/SemaObjC/warn-weak-field.m +++ b/test/SemaObjC/warn-weak-field.m @@ -1,4 +1,4 @@ -// RUN: clang-cc -triple i386-apple-darwin9 -fsyntax-only -fobjc-gc -verify %s +// RUN: clang -cc1 -triple i386-apple-darwin9 -fsyntax-only -fobjc-gc -verify %s struct S { __weak id w; // expected-warning {{__weak attribute cannot be specified on a field declaration}} diff --git a/test/SemaObjC/weak-attr-ivar.m b/test/SemaObjC/weak-attr-ivar.m index 6af96ddb3c8b..84bdb967262d 100644 --- a/test/SemaObjC/weak-attr-ivar.m +++ b/test/SemaObjC/weak-attr-ivar.m @@ -1,4 +1,4 @@ -// RUN: clang-cc -fsyntax-only -verify %s +// RUN: clang -cc1 -fsyntax-only -verify %s typedef signed char BOOL; typedef unsigned int NSUInteger; diff --git a/test/SemaObjC/writable-property-in-superclass.m b/test/SemaObjC/writable-property-in-superclass.m index 182b1c47bb39..cc9295a9bc01 100644 --- a/test/SemaObjC/writable-property-in-superclass.m +++ b/test/SemaObjC/writable-property-in-superclass.m @@ -1,4 +1,4 @@ -// RUN: clang-cc -fsyntax-only -verify %s +// RUN: clang -cc1 -fsyntax-only -verify %s @interface MessageStore @property (assign, readonly) int P; diff --git a/test/SemaObjCXX/blocks.mm b/test/SemaObjCXX/blocks.mm index e3304a41b730..92a909621421 100644 --- a/test/SemaObjCXX/blocks.mm +++ b/test/SemaObjCXX/blocks.mm @@ -1,4 +1,4 @@ -// RUN: clang-cc -fsyntax-only -verify -fblocks %s +// RUN: clang -cc1 -fsyntax-only -verify -fblocks %s @protocol NSObject; void bar(id(^)(void)); @@ -44,3 +44,9 @@ namespace N { foo(N::X()); // okay } @end + +typedef signed char BOOL; +void foo6(void *block) { + void (^vb)(id obj, int idx, BOOL *stop) = (void (^)(id, int, BOOL *))block; + BOOL (^bb)(id obj, int idx, BOOL *stop) = (BOOL (^)(id, int, BOOL *))block; +} diff --git a/test/SemaObjCXX/category-lookup.mm b/test/SemaObjCXX/category-lookup.mm new file mode 100644 index 000000000000..0458752d9338 --- /dev/null +++ b/test/SemaObjCXX/category-lookup.mm @@ -0,0 +1,10 @@ +// RUN: clang -cc1 -fsyntax-only -verify %s + +@interface NSObject @end + +@interface NSObject (NSScriptClassDescription) +@end + +void f() { + NSScriptClassDescription *f; // expected-error {{use of undeclared identifier 'NSScriptClassDescription'}} +} diff --git a/test/SemaObjCXX/composite-objc-pointertype.mm b/test/SemaObjCXX/composite-objc-pointertype.mm new file mode 100644 index 000000000000..786315e0e7a3 --- /dev/null +++ b/test/SemaObjCXX/composite-objc-pointertype.mm @@ -0,0 +1,18 @@ +// RUN: clang -cc1 -fsyntax-only -verify %s + +@interface Foo +@end + +@implementation Foo +- (id)test { + id bar; + Class cl; + Foo *f; + + (void)((bar!= 0) ? bar : 0); + (void)((cl != 0) ? cl : 0); + (void)((f != 0) ? 0 : f); + return (0 == 1) ? 0 : bar; +} +@end + diff --git a/test/SemaObjCXX/conditional-expr.mm b/test/SemaObjCXX/conditional-expr.mm new file mode 100644 index 000000000000..e1f92cded3ac --- /dev/null +++ b/test/SemaObjCXX/conditional-expr.mm @@ -0,0 +1,67 @@ +// RUN: clang -cc1 -fsyntax-only -verify %s + +@protocol P0 +@end +@protocol P1 +@end +@protocol P2 +@end + +@interface A +@end + +@interface B : A +@end + +void bar(id x); +void barP0(id x); +void barP1(id x); +void barP2(id x); + +void f0(A *a) { + id l = a; +} + +void f1(id x, A *a) { + id l = a; +} + +void f2(id x) { + id l = x; // expected-error {{incompatible type initializing 'id', expected 'id'}} +} + +void f3(A *a) { + id l = a; // expected-error {{incompatible type initializing 'A *', expected 'id'}} +} + +void f4(int cond, id x, A *a) { + bar(cond ? x : a); +} + +void f5(int cond, A *a, B *b) { + bar(cond ? a : b); +} + +void f6(int cond, id x, A *a) { + bar(cond ? (id) x : a); +} + +void f7(int cond, id x, A *a) { + bar(cond ? a : (id) x); +} + +void f8(int cond, id x0, id x1) { + barP0(cond ? x0 : x1); // expected-warning {{incompatible operand types ('id' and 'id')}} +} + +void f9(int cond, id x0, id x1) { + barP1(cond ? x0 : x1); // expected-warning {{incompatible operand types ('id' and 'id')}} +} + +void f10(int cond, id x0, id x1) { + barP2(cond ? x0 : x1); // expected-warning {{incompatible operand types ('id' and 'id')}} +} + +int f11(int cond, A* a, B* b) { + return (cond? b : a)->x; // expected-error{{'A' does not have a member named 'x'}} +} diff --git a/test/SemaObjCXX/cstyle-cast.mm b/test/SemaObjCXX/cstyle-cast.mm new file mode 100644 index 000000000000..fca2ef5cb613 --- /dev/null +++ b/test/SemaObjCXX/cstyle-cast.mm @@ -0,0 +1,40 @@ +// RUN: clang -cc1 -fsyntax-only -verify %s + +@protocol P @end +@interface I @end + +struct X { X(); }; + +void test1(X x) { + void *cft; + id oct = (id)cft; + + Class ccct; + ccct = (Class)cft; + + I* iict = (I*)cft; + + id

    qid = (id

    )cft; + + I

    *ip = (I

    *)cft; + + (id)x; // expected-error {{C-style cast from 'struct X' to 'id' is not allowed}} + + id *pid = (id*)ccct; + + id

    *qpid = (id

    *)ccct; + + int **pii; + + ccct = (Class)pii; + + qpid = (id

    *)pii; + + iict = (I*)pii; + + pii = (int **)ccct; + + pii = (int **)qpid; + +} + diff --git a/test/SemaObjCXX/linkage-spec.mm b/test/SemaObjCXX/linkage-spec.mm index 2cc0936b2ed2..bbdea7b25873 100644 --- a/test/SemaObjCXX/linkage-spec.mm +++ b/test/SemaObjCXX/linkage-spec.mm @@ -1,4 +1,4 @@ -// RUN: clang-cc -fsyntax-only -verify %s +// RUN: clang -cc1 -fsyntax-only -verify %s extern "C" { @class Protocol; } diff --git a/test/SemaObjCXX/objc-decls-inside-namespace.mm b/test/SemaObjCXX/objc-decls-inside-namespace.mm index cedfcfdb9e4b..464b2871c85d 100644 --- a/test/SemaObjCXX/objc-decls-inside-namespace.mm +++ b/test/SemaObjCXX/objc-decls-inside-namespace.mm @@ -1,4 +1,4 @@ -// RUN: clang-cc -fsyntax-only -verify %s +// RUN: clang -cc1 -fsyntax-only -verify %s namespace C { diff --git a/test/SemaObjCXX/overload.mm b/test/SemaObjCXX/overload.mm index 56dc5108eb95..a15907ce421f 100644 --- a/test/SemaObjCXX/overload.mm +++ b/test/SemaObjCXX/overload.mm @@ -1,4 +1,4 @@ -// RUN: clang-cc -fsyntax-only -verify %s +// RUN: clang -cc1 -fsyntax-only -verify %s // XFAIL: * @interface Foo @end diff --git a/test/SemaObjCXX/protocol-lookup.mm b/test/SemaObjCXX/protocol-lookup.mm index 87655bd9e7a0..b2b354b7782d 100644 --- a/test/SemaObjCXX/protocol-lookup.mm +++ b/test/SemaObjCXX/protocol-lookup.mm @@ -1,4 +1,4 @@ -// RUN: clang-cc -fsyntax-only -verify %s +// RUN: clang -cc1 -fsyntax-only -verify %s @protocol NSObject - retain; - release; diff --git a/test/SemaObjCXX/references.mm b/test/SemaObjCXX/references.mm index e02f360f7876..c4961efc1a55 100644 --- a/test/SemaObjCXX/references.mm +++ b/test/SemaObjCXX/references.mm @@ -1,5 +1,5 @@ // FIXME: This crashes, disable it until fixed. -// RN: clang-cc -verify -emit-llvm -o - %s +// RN: clang -cc1 -verify -emit-llvm -o - %s // RUN: false // XFAIL: * diff --git a/test/SemaObjCXX/reserved-keyword-selectors.mm b/test/SemaObjCXX/reserved-keyword-selectors.mm index 2875f9352737..add8e75ef806 100644 --- a/test/SemaObjCXX/reserved-keyword-selectors.mm +++ b/test/SemaObjCXX/reserved-keyword-selectors.mm @@ -1,4 +1,4 @@ -// RUN: clang-cc -fsyntax-only -verify %s +// RUN: clang -cc1 -fsyntax-only -verify %s @interface A - (void)asm; diff --git a/test/SemaObjCXX/standard-conversion-to-bool.mm b/test/SemaObjCXX/standard-conversion-to-bool.mm new file mode 100644 index 000000000000..cb97546582d7 --- /dev/null +++ b/test/SemaObjCXX/standard-conversion-to-bool.mm @@ -0,0 +1,12 @@ +// RUN: clang -cc1 -fsyntax-only -verify %s + +@class NSString; +id a; +NSString *b; + +void f() { + bool b1 = a; + bool b2 = b; +} + + diff --git a/test/SemaObjCXX/vararg-non-pod.mm b/test/SemaObjCXX/vararg-non-pod.mm index eeed09e61637..ee6462b0e027 100644 --- a/test/SemaObjCXX/vararg-non-pod.mm +++ b/test/SemaObjCXX/vararg-non-pod.mm @@ -1,4 +1,4 @@ -// RUN: clang-cc -fsyntax-only -verify %s +// RUN: clang -cc1 -fsyntax-only -verify %s -Wnon-pod-varargs extern char version[]; diff --git a/test/SemaObjCXX/void_to_obj.mm b/test/SemaObjCXX/void_to_obj.mm index d1fbf6b69079..851ecf5db666 100644 --- a/test/SemaObjCXX/void_to_obj.mm +++ b/test/SemaObjCXX/void_to_obj.mm @@ -1,4 +1,4 @@ -// RUN: clang-cc -fsyntax-only -verify %s +// RUN: clang -cc1 -fsyntax-only -verify %s // @class XX; diff --git a/test/SemaTemplate/class-template-id.cpp b/test/SemaTemplate/class-template-id.cpp index e74a6f8dcca9..98ccbe7db6f8 100644 --- a/test/SemaTemplate/class-template-id.cpp +++ b/test/SemaTemplate/class-template-id.cpp @@ -36,3 +36,8 @@ namespace N { N::C c1; typedef N::C c2; + +// PR5655 +template struct Foo { }; // expected-note{{template is declared here}} + +void f(void) { Foo bar; } // expected-error{{without a template argument list}} diff --git a/test/SemaTemplate/constructor-template.cpp b/test/SemaTemplate/constructor-template.cpp index 203977e9edd7..0b6916fa485d 100644 --- a/test/SemaTemplate/constructor-template.cpp +++ b/test/SemaTemplate/constructor-template.cpp @@ -82,3 +82,15 @@ X4 test_X4(bool Cond, X4 x4) { X4 b(x4); // okay, copy constructor return X4(); // expected-error{{no viable conversion}} } + +// Instantiation of a non-dependent use of a constructor +struct DefaultCtorHasDefaultArg { + explicit DefaultCtorHasDefaultArg(int i = 17); +}; + +template +void default_ctor_inst() { + DefaultCtorHasDefaultArg def; +} + +template void default_ctor_inst(); diff --git a/test/SemaTemplate/friend-template.cpp b/test/SemaTemplate/friend-template.cpp index 84a8e899dbea..98992f6f6078 100644 --- a/test/SemaTemplate/friend-template.cpp +++ b/test/SemaTemplate/friend-template.cpp @@ -1,23 +1,20 @@ // RUN: clang-cc -fsyntax-only -verify %s // PR5057 -namespace std { - class X { - public: - template - friend struct Y; - }; +namespace test0 { + namespace std { + class X { + public: + template friend struct Y; + }; + } + + namespace std { + template struct Y {}; + } } -namespace std { - template - struct Y - { - }; -} - - -namespace N { +namespace test1 { template void f1(T) { } // expected-note{{here}} class X { @@ -30,64 +27,73 @@ namespace N { } // PR4768 -template -struct X0 { - template friend struct X0; -}; +namespace test2 { + template struct X0 { + template friend struct X0; + }; + + template struct X0 { + template friend struct X0; + }; -template -struct X0 { - template friend struct X0; -}; + template<> struct X0 { + template friend struct X0; + }; -template<> -struct X0 { - template friend struct X0; -}; + template struct X1 { + template friend void f2(U); + template friend void f3(U); + }; -template -struct X1 { - template friend void f2(U); - template friend void f3(U); -}; + template void f2(U); -template void f2(U); + X1 x1i; + X0 x0ip; -X1 x1i; -X0 x0ip; + template<> void f2(int); -template<> void f2(int); + // FIXME: Should this declaration of f3 be required for the specialization of + // f3 (further below) to work? GCC and EDG don't require it, we do... + template void f3(U); -// FIXME: Should this declaration of f3 be required for the specialization of -// f3 (further below) to work? GCC and EDG don't require it, we do... -template void f3(U); - -template<> void f3(int); + template<> void f3(int); +} // PR5332 -template -class Foo { - template - friend class Foo; -}; +namespace test3 { + template class Foo { + template + friend class Foo; + }; -Foo foo; + Foo foo; -template -struct X2a; + template struct X2a; -template -struct X2b; + template struct X2b; -template -class X3 { - template - friend struct X2a; + template + class X3 { + template friend struct X2a; + template friend struct X2b; + }; - template - friend struct X2b; -}; + X3 x3i; // okay -X3 x3i; // okay + X3 x3l; // FIXME: should cause an instantiation-time failure +} -X3 x3l; // FIXME: should cause an instantiation-time failure +// PR5716 +namespace test4 { + template struct A { + template friend void f(const A&); + }; + + template void f(const A&) { + int a[sizeof(T) ? -1 : -1]; // expected-error {{array size is negative}} + } + + void f() { + f(A()); // expected-note {{in instantiation of function template specialization}} + } +} diff --git a/test/SemaTemplate/instantiate-default-assignment-operator.cpp b/test/SemaTemplate/instantiate-default-assignment-operator.cpp new file mode 100644 index 000000000000..b0ac078893de --- /dev/null +++ b/test/SemaTemplate/instantiate-default-assignment-operator.cpp @@ -0,0 +1,17 @@ +// RUN: clang-cc -fsyntax-only -verify %s +template struct PassRefPtr { }; +template struct RefPtr { + RefPtr& operator=(const RefPtr&) { int a[sizeof(T) ? -1 : -1];} // expected-error 2 {{array size is negative}} + RefPtr& operator=(const PassRefPtr&); +}; + +struct A { RefPtr a; }; +struct B : RefPtr { }; + +void f() { + A a1, a2; + a1 = a2; // expected-note {{instantiation of member function 'RefPtr::operator=' requested here}} + + B b1, b2; + b1 = b2; // expected-note {{in instantiation of member function 'RefPtr::operator=' requested here}} +} diff --git a/test/SemaTemplate/instantiate-enum-2.cpp b/test/SemaTemplate/instantiate-enum-2.cpp new file mode 100644 index 000000000000..2b56a036e947 --- /dev/null +++ b/test/SemaTemplate/instantiate-enum-2.cpp @@ -0,0 +1,9 @@ +// RUN: clang-cc %s -fsyntax-only -verify + +template struct X { + enum { + IntShift = (unsigned long long)IntBits, + ShiftedIntMask = (1 << IntShift) + }; +}; +X<1> x; diff --git a/test/SemaTemplate/instantiate-exception-spec.cpp b/test/SemaTemplate/instantiate-exception-spec.cpp new file mode 100644 index 000000000000..31db4487a27a --- /dev/null +++ b/test/SemaTemplate/instantiate-exception-spec.cpp @@ -0,0 +1,11 @@ +// RUN: clang-cc -fsyntax-only -verify %s + +// FIXME: the "note" should be down at the call site! +template void f1(T*) throw(T); // expected-error{{incomplete type 'struct Incomplete' is not allowed in exception specification}} \ + // expected-note{{instantiation of}} +struct Incomplete; // expected-note{{forward}} + +void test_f1(Incomplete *incomplete_p, int *int_p) { + f1(int_p); + f1(incomplete_p); +} diff --git a/test/SemaTemplate/instantiate-expr-1.cpp b/test/SemaTemplate/instantiate-expr-1.cpp index fb88213c401b..1cd55d9ad257 100644 --- a/test/SemaTemplate/instantiate-expr-1.cpp +++ b/test/SemaTemplate/instantiate-expr-1.cpp @@ -94,3 +94,21 @@ struct Addable { void test_add(Addable &a) { add(a); } + +struct CallOperator { + int &operator()(int); + double &operator()(double); +}; + +template +Result test_call_operator(F f, Arg1 arg1) { + // PR5266: non-dependent invocations of a function call operator. + CallOperator call_op; + int &ir = call_op(17); + return f(arg1); +} + +void test_call_operator(CallOperator call_op, int i, double d) { + int &ir = test_call_operator(call_op, i); + double &dr = test_call_operator(call_op, d); +} diff --git a/test/SemaTemplate/instantiate-expr-4.cpp b/test/SemaTemplate/instantiate-expr-4.cpp index cd74a21d6dbc..b99ec3304c4d 100644 --- a/test/SemaTemplate/instantiate-expr-4.cpp +++ b/test/SemaTemplate/instantiate-expr-4.cpp @@ -96,6 +96,18 @@ template struct Delete0; template struct Delete0; template struct Delete0; // expected-note{{instantiation}} +namespace PR5755 { + template + void Foo() { + char* p = 0; + delete[] p; + } + + void Test() { + Foo(); + } +} + // --------------------------------------------------------------------- // throw expressions // --------------------------------------------------------------------- @@ -185,7 +197,7 @@ template struct InitList2; // expected-note{{instantiation template struct DotMemRef0 { void f(T t) { - Result result = t.m; // expected-error{{cannot be initialized}} + Result result = t.m; // expected-error{{non-const lvalue reference to type}} } }; @@ -207,7 +219,7 @@ template struct DotMemRef0; // expected-note{{instantiation}} template struct ArrowMemRef0 { void f(T t) { - Result result = t->m; // expected-error 2{{cannot be initialized}} + Result result = t->m; // expected-error 2{{non-const lvalue reference}} } }; @@ -269,7 +281,7 @@ template struct ThisMemberFuncCall0; template struct NonDepMemberCall0 { void foo(HasMemFunc0 x) { - T result = x.f(); // expected-error{{initialized}} + T result = x.f(); // expected-error{{non-const lvalue reference}} } }; diff --git a/test/SemaTemplate/instantiate-function-1.mm b/test/SemaTemplate/instantiate-function-1.mm index c119ab5da8b9..aa4b941d39cf 100644 --- a/test/SemaTemplate/instantiate-function-1.mm +++ b/test/SemaTemplate/instantiate-function-1.mm @@ -1,4 +1,4 @@ -// RUN: clang-cc -fsyntax-only -verify %s +// RUN: clang -cc1 -fsyntax-only -verify %s // XFAIL: * template struct Member0 { diff --git a/test/SemaTemplate/instantiate-method.cpp b/test/SemaTemplate/instantiate-method.cpp index 2351d882f9c2..231e2812f666 100644 --- a/test/SemaTemplate/instantiate-method.cpp +++ b/test/SemaTemplate/instantiate-method.cpp @@ -95,9 +95,7 @@ struct X0 : X0Base { template struct X1 : X0 { int &f2() { - // FIXME: We should be able to do this lookup and diagnose the error - // *despite* the fact that we can't decide the relationship yet. - return X0Base::f(); // expected-FIXME-error{{call to non-static member function without an object argument}} + return X0Base::f(); } }; diff --git a/test/SemaTemplate/instantiate-objc-1.mm b/test/SemaTemplate/instantiate-objc-1.mm index 829acb2e199b..093be4e27155 100644 --- a/test/SemaTemplate/instantiate-objc-1.mm +++ b/test/SemaTemplate/instantiate-objc-1.mm @@ -1,4 +1,4 @@ -// RUN: clang-cc -fsyntax-only -verify %s +// RUN: clang -cc1 -fsyntax-only -verify %s // Obj-C string literal expressions template struct StringTest { diff --git a/test/SemaTemplate/instantiate-static-var.cpp b/test/SemaTemplate/instantiate-static-var.cpp index 452fccf2244d..d4a7008b47bf 100644 --- a/test/SemaTemplate/instantiate-static-var.cpp +++ b/test/SemaTemplate/instantiate-static-var.cpp @@ -72,3 +72,23 @@ void Test() { Z1::value> x2; int y2[Y2::value]; } + +// PR5672 +template +struct X3 {}; + +class Y3 { + public: + ~Y3(); // The error isn't triggered without this dtor. + + void Foo(X3<1>); +}; + +template +struct SizeOf { + static const int value = sizeof(T); +}; + +void MyTest3() { + Y3().Foo(X3::value>()); +} diff --git a/test/SemaTemplate/instantiate-using-decl.cpp b/test/SemaTemplate/instantiate-using-decl.cpp index a1cf355c890e..de66f79242fc 100644 --- a/test/SemaTemplate/instantiate-using-decl.cpp +++ b/test/SemaTemplate/instantiate-using-decl.cpp @@ -1,20 +1,49 @@ // RUN: clang-cc -fsyntax-only -verify %s -namespace N { } +namespace test0 { + namespace N { } -template -struct A { - void f(); -}; + template + struct A { + void f(); + }; -template -struct B : A { - using A::f; - - void g() { - using namespace N; - f(); + template + struct B : A { + using A::f; + + void g() { + using namespace N; + f(); + } + }; + + template struct B; +} + +namespace test1 { + template struct Visitor1 { + void Visit(struct Object1*); + }; + template struct Visitor2 { + void Visit(struct Object2*); // expected-note {{candidate function}} + }; + + template struct JoinVisitor + : Visitor1, Visitor2 { + typedef Visitor1 Base1; + typedef Visitor2 Base2; + + void Visit(struct Object1*); // expected-note {{candidate function}} + using Base2::Visit; + }; + + class Knot : JoinVisitor { + }; + + void test() { + Knot().Visit((struct Object1*) 0); + Knot().Visit((struct Object2*) 0); + Knot().Visit((struct Object3*) 0); // expected-error {{no matching member function for call}} } -}; - -template struct B; +} diff --git a/test/SemaTemplate/qualified-id.cpp b/test/SemaTemplate/qualified-id.cpp index a07f05ca78ee..ab57950acff2 100644 --- a/test/SemaTemplate/qualified-id.cpp +++ b/test/SemaTemplate/qualified-id.cpp @@ -18,3 +18,14 @@ namespace test1 { } }; } + +namespace test2 { + class Impl { + int foo(); + }; + template class Magic : public Impl { + int foo() { + return Impl::foo(); + } + }; +} diff --git a/test/SemaTemplate/template-class-traits.cpp b/test/SemaTemplate/template-class-traits.cpp new file mode 100644 index 000000000000..7cf2004e727f --- /dev/null +++ b/test/SemaTemplate/template-class-traits.cpp @@ -0,0 +1,8 @@ +// RUN: clang-cc -fsyntax-only -verify %s +#define T(b) (b) ? 1 : -1 +#define F(b) (b) ? -1 : 1 + +struct HasVirt { virtual void a(); }; +template struct InheritPolymorph : HasVirt {}; +int t01[T(__is_polymorphic(InheritPolymorph))]; + diff --git a/test/SemaTemplate/virtual-member-functions.cpp b/test/SemaTemplate/virtual-member-functions.cpp new file mode 100644 index 000000000000..486c8b205141 --- /dev/null +++ b/test/SemaTemplate/virtual-member-functions.cpp @@ -0,0 +1,22 @@ +// RUN: clang-cc -fsyntax-only -verify %s + +namespace PR5557 { +template struct A { + A(); + virtual int a(T x); +}; +template A::A() {} +template int A::a(T x) { + return *x; // expected-error{{requires pointer operand}} +} + +A x; // expected-note{{instantiation}} + +template +struct X { + virtual void f(); +}; + +template<> +void X::f() { } +} diff --git a/test/lit.cfg b/test/lit.cfg index 6fa6742a4ac5..1421ec1a80cf 100644 --- a/test/lit.cfg +++ b/test/lit.cfg @@ -119,40 +119,8 @@ def inferClang(PATH): return clang -def inferClangCC(clang, PATH): - clangcc = os.getenv('CLANGCC') - - # If the user set clang in the environment, definitely use that and don't - # try to validate. - if clangcc: - return clangcc - - # Otherwise try adding -cc since we expect to be looking in a build - # directory. - if clang.endswith('.exe'): - clangccName = clang[:-4] + '-cc.exe' - else: - clangccName = clang + '-cc' - clangcc = lit.util.which(clangccName, PATH) - if not clangcc: - # Otherwise ask clang. - res = lit.util.capture([clang, '-print-prog-name=clang-cc']) - res = res.strip() - if res and os.path.exists(res): - clangcc = res - - if not clangcc: - lit.fatal("couldn't find 'clang-cc' program, try setting " - "CLANGCC in your environment") - - return clangcc - config.clang = inferClang(config.environment['PATH']) if not lit.quiet: lit.note('using clang: %r' % config.clang) config.substitutions.append( (' clang ', ' ' + config.clang + ' ') ) - -config.clang_cc = inferClangCC(config.clang, config.environment['PATH']) -if not lit.quiet: - lit.note('using clang-cc: %r' % config.clang_cc) -config.substitutions.append( (' clang-cc ', ' ' + config.clang_cc + ' ') ) +config.substitutions.append( (' clang-cc ', ' ' + config.clang + ' -cc1 ') ) diff --git a/tools/CIndex/CIndex.cpp b/tools/CIndex/CIndex.cpp index 4681b939cea2..fe3aa3769414 100644 --- a/tools/CIndex/CIndex.cpp +++ b/tools/CIndex/CIndex.cpp @@ -12,24 +12,26 @@ //===----------------------------------------------------------------------===// #include "clang-c/Index.h" -#include "clang/Index/Program.h" -#include "clang/Index/Indexer.h" -#include "clang/Index/ASTLocation.h" -#include "clang/Index/Utils.h" -#include "clang/Sema/CodeCompleteConsumer.h" +#include "clang/AST/Decl.h" #include "clang/AST/DeclVisitor.h" #include "clang/AST/StmtVisitor.h" -#include "clang/AST/Decl.h" #include "clang/Basic/FileManager.h" #include "clang/Basic/SourceManager.h" +#include "clang/Basic/Version.h" #include "clang/Frontend/ASTUnit.h" +#include "clang/Frontend/CompilerInstance.h" +#include "clang/Index/ASTLocation.h" +#include "clang/Index/Indexer.h" +#include "clang/Index/Program.h" +#include "clang/Index/Utils.h" +#include "clang/Sema/CodeCompleteConsumer.h" #include "llvm/ADT/StringExtras.h" #include "llvm/Config/config.h" #include "llvm/Support/Compiler.h" #include "llvm/Support/MemoryBuffer.h" +#include "llvm/Support/raw_ostream.h" #include "llvm/System/Path.h" #include "llvm/System/Program.h" -#include "llvm/Support/raw_ostream.h" #include #include @@ -291,10 +293,25 @@ class CDeclVisitor : public DeclVisitor { }; class CIndexer : public Indexer { + DiagnosticOptions DiagOpts; + IgnoreDiagnosticsClient IgnoreDiagClient; + llvm::OwningPtr TextDiags; + Diagnostic IgnoreDiags; + bool UseExternalASTGeneration; + bool OnlyLocalDecls; + bool DisplayDiagnostics; + + llvm::sys::Path ClangPath; + public: explicit CIndexer(Program *prog) : Indexer(*prog), + IgnoreDiags(&IgnoreDiagClient), + UseExternalASTGeneration(false), OnlyLocalDecls(false), - DisplayDiagnostics(false) {} + DisplayDiagnostics(false) { + TextDiags.reset( + CompilerInstance::createDiagnostics(DiagOpts, 0, 0)); + } virtual ~CIndexer() { delete &getProgram(); } @@ -304,18 +321,25 @@ class CIndexer : public Indexer { bool getOnlyLocalDecls() const { return OnlyLocalDecls; } void setOnlyLocalDecls(bool Local = true) { OnlyLocalDecls = Local; } + bool getDisplayDiagnostics() const { return DisplayDiagnostics; } void setDisplayDiagnostics(bool Display = true) { DisplayDiagnostics = Display; } - bool getDisplayDiagnostics() const { return DisplayDiagnostics; } + + bool getUseExternalASTGeneration() const { return UseExternalASTGeneration; } + void setUseExternalASTGeneration(bool Value) { + UseExternalASTGeneration = Value; + } + + Diagnostic &getDiags() { + return DisplayDiagnostics ? *TextDiags : IgnoreDiags; + } /// \brief Get the path of the clang binary. const llvm::sys::Path& getClangPath(); -private: - bool OnlyLocalDecls; - bool DisplayDiagnostics; - llvm::sys::Path ClangPath; + /// \brief Get the path of the clang resource files. + std::string getClangResourcesPath(); }; const llvm::sys::Path& CIndexer::getClangPath() { @@ -357,6 +381,22 @@ const llvm::sys::Path& CIndexer::getClangPath() { return ClangPath; } +std::string CIndexer::getClangResourcesPath() { + llvm::sys::Path P = getClangPath(); + + if (!P.empty()) { + P.eraseComponent(); // Remove /clang from foo/bin/clang + P.eraseComponent(); // Remove /bin from foo/bin + + // Get foo/lib/clang//include + P.appendComponent("lib"); + P.appendComponent("clang"); + P.appendComponent(CLANG_VERSION_STRING); + } + + return P.str(); +} + } static SourceLocation getLocationFromCursor(CXCursor C, @@ -452,25 +492,21 @@ void clang_disposeIndex(CXIndex CIdx) { delete static_cast(CIdx); } +void clang_setUseExternalASTGeneration(CXIndex CIdx, int value) { + assert(CIdx && "Passed null CXIndex"); + CIndexer *CXXIdx = static_cast(CIdx); + CXXIdx->setUseExternalASTGeneration(value); +} + // FIXME: need to pass back error info. CXTranslationUnit clang_createTranslationUnit(CXIndex CIdx, const char *ast_filename) { assert(CIdx && "Passed null CXIndex"); CIndexer *CXXIdx = static_cast(CIdx); - std::string astName(ast_filename); - std::string ErrMsg; - CXTranslationUnit TU = - ASTUnit::LoadFromPCHFile(astName, &ErrMsg, - CXXIdx->getDisplayDiagnostics() ? - NULL : new IgnoreDiagnosticsClient(), - CXXIdx->getOnlyLocalDecls(), - /* UseBumpAllocator = */ true); - - if (CXXIdx->getDisplayDiagnostics() && !ErrMsg.empty()) - llvm::errs() << "clang_createTranslationUnit: " << ErrMsg << '\n'; - - return TU; + return ASTUnit::LoadFromPCHFile(ast_filename, CXXIdx->getDiags(), + CXXIdx->getOnlyLocalDecls(), + /* UseBumpAllocator = */ true); } CXTranslationUnit @@ -481,6 +517,33 @@ clang_createTranslationUnitFromSourceFile(CXIndex CIdx, assert(CIdx && "Passed null CXIndex"); CIndexer *CXXIdx = static_cast(CIdx); + if (!CXXIdx->getUseExternalASTGeneration()) { + llvm::SmallVector Args; + + // The 'source_filename' argument is optional. If the caller does not + // specify it then it is assumed that the source file is specified + // in the actual argument list. + if (source_filename) + Args.push_back(source_filename); + Args.insert(Args.end(), command_line_args, + command_line_args + num_command_line_args); + + unsigned NumErrors = CXXIdx->getDiags().getNumErrors(); + llvm::OwningPtr Unit( + ASTUnit::LoadFromCommandLine(Args.data(), Args.data() + Args.size(), + CXXIdx->getDiags(), + CXXIdx->getClangResourcesPath(), + CXXIdx->getOnlyLocalDecls(), + /* UseBumpAllocator = */ true)); + + // FIXME: Until we have broader testing, just drop the entire AST if we + // encountered an error. + if (NumErrors != CXXIdx->getDiags().getNumErrors()) + return 0; + + return Unit.take(); + } + // Build up the arguments for invoking 'clang'. std::vector argv; @@ -568,9 +631,29 @@ void clang_loadTranslationUnit(CXTranslationUnit CTUnit, ASTUnit *CXXUnit = static_cast(CTUnit); ASTContext &Ctx = CXXUnit->getASTContext(); - TUVisitor DVisit(CTUnit, callback, CData, - CXXUnit->getOnlyLocalDecls()? 1 : Decl::MaxPCHLevel); - DVisit.Visit(Ctx.getTranslationUnitDecl()); + 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 &TLDs = CXXUnit->getTopLevelDecls(); + for (std::vector::const_iterator it = TLDs.begin(), + ie = TLDs.end(); it != ie; ++it) { + DVisit.Visit(*it); + } + } else + DVisit.Visit(Ctx.getTranslationUnitDecl()); } void clang_loadDeclaration(CXDecl Dcl, @@ -1082,7 +1165,7 @@ const char *clang_getCompletionChunkText(CXCompletionString completion_string, case CodeCompletionString::CK_Optional: // Note: treated as an empty text block. - return 0; + return ""; } // Should be unreachable, but let's be careful. @@ -1141,6 +1224,8 @@ void clang_codeComplete(CXIndex CIdx, const char *source_filename, int num_command_line_args, const char **command_line_args, + unsigned num_unsaved_files, + struct CXUnsavedFile *unsaved_files, const char *complete_filename, unsigned complete_line, unsigned complete_column, @@ -1149,6 +1234,9 @@ void clang_codeComplete(CXIndex CIdx, // The indexer, which is mainly used to determine where diagnostics go. CIndexer *CXXIdx = static_cast(CIdx); + // The set of temporary files that we've built. + std::vector TemporaryFiles; + // Build up the arguments for invoking 'clang'. std::vector argv; @@ -1163,17 +1251,53 @@ void clang_codeComplete(CXIndex CIdx, // Add the appropriate '-code-completion-at=file:line:column' argument // to perform code completion, with an "-Xclang" preceding it. std::string code_complete_at; - code_complete_at += "-code-completion-at="; code_complete_at += complete_filename; code_complete_at += ":"; code_complete_at += llvm::utostr(complete_line); code_complete_at += ":"; code_complete_at += llvm::utostr(complete_column); argv.push_back("-Xclang"); + argv.push_back("-code-completion-at"); + argv.push_back("-Xclang"); argv.push_back(code_complete_at.c_str()); argv.push_back("-Xclang"); argv.push_back("-no-code-completion-debug-printer"); + std::vector 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); + } + + // 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()); + // Add the source file name (FIXME: later, we'll want to build temporary // file from the buffer, or just feed the source text via standard input). if (source_filename) @@ -1203,6 +1327,7 @@ void clang_codeComplete(CXIndex CIdx, char tmpFile[L_tmpnam]; char *tmpFileName = tmpnam(tmpFile); llvm::sys::Path ResultsFile(tmpFileName); + TemporaryFiles.push_back(ResultsFile); // Invoke 'clang'. llvm::sys::Path DevNull; // leave empty, causes redirection to /dev/null @@ -1255,7 +1380,8 @@ void clang_codeComplete(CXIndex CIdx, delete F; } - ResultsFile.eraseFromDisk(); + for (unsigned i = 0, e = TemporaryFiles.size(); i != e; ++i) + TemporaryFiles[i].eraseFromDisk(); } } // end extern "C" diff --git a/tools/CIndex/CIndex.exports b/tools/CIndex/CIndex.exports index 2892ce50e70d..458ad1028359 100644 --- a/tools/CIndex/CIndex.exports +++ b/tools/CIndex/CIndex.exports @@ -6,6 +6,7 @@ _clang_disposeIndex _clang_disposeString _clang_disposeTranslationUnit _clang_equalCursors +_clang_getCString _clang_getCompletionChunkCompletionString _clang_getCompletionChunkKind _clang_getCompletionChunkText @@ -19,7 +20,6 @@ _clang_getCursorLine _clang_getCursorSource _clang_getCursorSourceFile _clang_getCursorSpelling -_clang_getCString _clang_getDeclColumn _clang_getDeclLine _clang_getDeclSource @@ -41,3 +41,4 @@ _clang_isInvalid _clang_isReference _clang_loadDeclaration _clang_loadTranslationUnit +_clang_setUseExternalASTGeneration diff --git a/tools/CIndex/CMakeLists.txt b/tools/CIndex/CMakeLists.txt index 69de8a1acffb..a3ff3db2d9b5 100644 --- a/tools/CIndex/CMakeLists.txt +++ b/tools/CIndex/CMakeLists.txt @@ -3,11 +3,20 @@ set(SHARED_LIBRARY TRUE) set(LLVM_NO_RTTI 1) set(LLVM_USED_LIBS - clangFrontend clangIndex clangSema clangAnalysis clangAST clangParse clangLex clangBasic) + clangIndex + clangFrontend + clangDriver + clangSema + clangAnalysis + clangAST + clangParse + clangLex + clangBasic) set( LLVM_LINK_COMPONENTS - MC - support + bitreader + mc + core ) add_clang_library(CIndex CIndex.cpp) diff --git a/tools/CIndex/Makefile b/tools/CIndex/Makefile index a34f68ba115b..94f04670000d 100644 --- a/tools/CIndex/Makefile +++ b/tools/CIndex/Makefile @@ -21,8 +21,9 @@ include $(LEVEL)/Makefile.config LINK_LIBS_IN_SHARED = 1 SHARED_LIBRARY = 1 -LINK_COMPONENTS := MC support -USEDLIBS = clangFrontend.a clangIndex.a clangSema.a clangAnalysis.a clangAST.a clangParse.a clangLex.a clangBasic.a +LINK_COMPONENTS := bitreader mc core +USEDLIBS = clangIndex.a 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 8c666dd71a0c..46e4ae946f19 100644 --- a/tools/CMakeLists.txt +++ b/tools/CMakeLists.txt @@ -1,5 +1,4 @@ add_subdirectory(CIndex) add_subdirectory(c-index-test) -add_subdirectory(clang-cc) add_subdirectory(driver) add_subdirectory(index-test) diff --git a/tools/Makefile b/tools/Makefile index 0e98439c3821..a30932b8996f 100644 --- a/tools/Makefile +++ b/tools/Makefile @@ -8,6 +8,6 @@ ##===----------------------------------------------------------------------===## LEVEL := ../../.. -DIRS := clang-cc driver index-test CIndex c-index-test +DIRS := driver index-test CIndex c-index-test include $(LEVEL)/Makefile.common diff --git a/tools/c-index-test/CMakeLists.txt b/tools/c-index-test/CMakeLists.txt index 4678461de1f4..f0a34a57987e 100644 --- a/tools/c-index-test/CMakeLists.txt +++ b/tools/c-index-test/CMakeLists.txt @@ -5,8 +5,8 @@ set( LLVM_USED_LIBS clangIndex clangFrontend clangDriver - clangAnalysis clangSema + clangAnalysis clangAST clangParse clangLex @@ -16,6 +16,7 @@ set( LLVM_USED_LIBS set( LLVM_LINK_COMPONENTS bitreader mc + core ) add_clang_executable(c-index-test diff --git a/tools/c-index-test/Makefile b/tools/c-index-test/Makefile index ae49bf4d7af9..06e24053aa0a 100644 --- a/tools/c-index-test/Makefile +++ b/tools/c-index-test/Makefile @@ -18,8 +18,8 @@ TOOL_NO_EXPORTS = 1 include $(LEVEL)/Makefile.config -LINK_COMPONENTS := bitreader mc -USEDLIBS = CIndex.a clangIndex.a clangFrontend.a clangDriver.a clangAnalysis.a \ - clangSema.a clangAST.a clangParse.a clangLex.a clangBasic.a +LINK_COMPONENTS := bitreader mc core +USEDLIBS = CIndex.a clangIndex.a clangFrontend.a clangDriver.a clangSema.a \ + clangAnalysis.a clangAST.a clangParse.a clangLex.a clangBasic.a include $(LLVM_SRC_ROOT)/Makefile.rules diff --git a/tools/c-index-test/c-index-test.c b/tools/c-index-test/c-index-test.c index 5364d7948c5d..7300585a1d88 100644 --- a/tools/c-index-test/c-index-test.c +++ b/tools/c-index-test/c-index-test.c @@ -179,12 +179,17 @@ int perform_test_load_tu(const char *file, const char *filter) { } int perform_test_load_source(int argc, const char **argv, const char *filter) { + const char *UseExternalASTs = + getenv("CINDEXTEST_USE_EXTERNAL_AST_GENERATION"); CXIndex Idx; CXTranslationUnit TU; Idx = clang_createIndex(/* excludeDeclsFromPCH */ !strcmp(filter, "local") ? 1 : 0, /* displayDiagnostics */ 1); + if (UseExternalASTs && strlen(UseExternalASTs)) + clang_setUseExternalASTGeneration(Idx, 1); + TU = clang_createTranslationUnitFromSourceFile(Idx, 0, argc, argv); if (!TU) { fprintf(stderr, "Unable to load translation unit!\n"); @@ -389,6 +394,91 @@ 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); + fread(contents, 1, unsaved->Length, to_file); + 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; @@ -396,17 +486,26 @@ int perform_code_completion(int argc, const char **argv) { unsigned column; CXIndex CIdx; int errorCode; + struct CXUnsavedFile *unsaved_files = 0; + int num_unsaved_files = 0; input += strlen("-code-completion-at="); if ((errorCode = parse_file_line_column(input, &filename, &line, &column))) return errorCode; + if (parse_remapped_files(argc, argv, 2, &unsaved_files, &num_unsaved_files)) + return -1; + CIdx = clang_createIndex(0, 0); - clang_codeComplete(CIdx, argv[argc - 1], argc - 3, argv + 2, + clang_codeComplete(CIdx, argv[argc - 1], argc - num_unsaved_files - 3, + argv + num_unsaved_files + 2, + num_unsaved_files, unsaved_files, filename, line, column, &print_completion_result, stdout); clang_disposeIndex(CIdx); free(filename); + free_remapped_files(unsaved_files, num_unsaved_files); + return 0; } diff --git a/tools/clang-cc/CMakeLists.txt b/tools/clang-cc/CMakeLists.txt deleted file mode 100644 index c96e8b1d068b..000000000000 --- a/tools/clang-cc/CMakeLists.txt +++ /dev/null @@ -1,32 +0,0 @@ -set(LLVM_NO_RTTI 1) - -set( LLVM_USED_LIBS - clangDriver - clangFrontend - clangCodeGen - clangAnalysis - clangRewrite - clangSema - clangAST - clangParse - clangLex - clangBasic - ) - -set( LLVM_LINK_COMPONENTS - ${LLVM_TARGETS_TO_BUILD} - bitreader - bitwriter - codegen - ipo - selectiondag - ) - -add_clang_executable(clang-cc - clang-cc.cpp - Options.cpp - ) -add_dependencies(clang-cc clang-headers) - -install(TARGETS clang-cc - RUNTIME DESTINATION libexec) diff --git a/tools/clang-cc/Makefile b/tools/clang-cc/Makefile deleted file mode 100644 index ebcc1d5fa0ba..000000000000 --- a/tools/clang-cc/Makefile +++ /dev/null @@ -1,32 +0,0 @@ -##===- tools/clang-cc/Makefile -----------------------------*- Makefile -*-===## -# -# The LLVM Compiler Infrastructure -# -# This file is distributed under the University of Illinois Open Source -# License. See LICENSE.TXT for details. -# -##===----------------------------------------------------------------------===## -LEVEL = ../../../.. - -TOOLNAME = clang-cc -CPPFLAGS += -I$(PROJ_SRC_DIR)/../../include -I$(PROJ_OBJ_DIR)/../../include -CXXFLAGS = -fno-rtti - -# Clang has no plugins, optimize startup time. -TOOL_NO_EXPORTS = 1 - -# Include this here so we can get the configuration of the targets -# that have been configured for construction. We have to do this -# early so we can set up LINK_COMPONENTS before including Makefile.rules -include $(LEVEL)/Makefile.config - -LINK_COMPONENTS := $(TARGETS_TO_BUILD) bitreader bitwriter codegen ipo selectiondag -USEDLIBS = clangDriver.a clangFrontend.a clangCodeGen.a clangAnalysis.a \ - clangRewrite.a clangSema.a clangAST.a clangParse.a \ - clangLex.a clangBasic.a - -# clang-cc lives in a special location; we can get away with this -# because nothing else gets installed from here. -PROJ_bindir := $(DESTDIR)$(PROJ_prefix)/libexec - -include $(LLVM_SRC_ROOT)/Makefile.rules diff --git a/tools/clang-cc/Options.cpp b/tools/clang-cc/Options.cpp deleted file mode 100644 index a18598ef7c21..000000000000 --- a/tools/clang-cc/Options.cpp +++ /dev/null @@ -1,1265 +0,0 @@ -//===--- Options.cpp - clang-cc Option Handling ---------------------------===// -// -// The LLVM Compiler Infrastructure -// -// This file is distributed under the University of Illinois Open Source -// License. See LICENSE.TXT for details. -// -//===----------------------------------------------------------------------===// - -// This file contains "pure" option handling, it is only responsible for turning -// the options into internal *Option classes, but shouldn't have any other -// logic. - -#include "Options.h" -#include "clang/Basic/LangOptions.h" -#include "clang/Basic/TargetInfo.h" -#include "clang/Basic/TargetOptions.h" -#include "clang/Frontend/AnalysisConsumer.h" -#include "clang/CodeGen/CodeGenOptions.h" -#include "clang/Frontend/DependencyOutputOptions.h" -#include "clang/Frontend/DiagnosticOptions.h" -#include "clang/Frontend/FrontendOptions.h" -#include "clang/Frontend/HeaderSearchOptions.h" -#include "clang/Frontend/LangStandard.h" -#include "clang/Frontend/PCHReader.h" -#include "clang/Frontend/PreprocessorOptions.h" -#include "clang/Frontend/PreprocessorOutputOptions.h" -#include "llvm/ADT/STLExtras.h" -#include "llvm/ADT/StringMap.h" -#include "llvm/Support/CommandLine.h" -#include "llvm/Support/RegistryParser.h" -#include "llvm/System/Host.h" -#include - -using namespace clang; - -//===----------------------------------------------------------------------===// -// Analyzer Options -//===----------------------------------------------------------------------===// - -namespace analyzeroptions { - -static llvm::cl::list -AnalysisList(llvm::cl::desc("Source Code Analysis - Checks and Analyses"), -llvm::cl::values( -#define ANALYSIS(NAME, CMDFLAG, DESC, SCOPE)\ -clEnumValN(NAME, CMDFLAG, DESC), -#include "clang/Frontend/Analyses.def" -clEnumValEnd)); - -static llvm::cl::opt -AnalysisStoreOpt("analyzer-store", - llvm::cl::desc("Source Code Analysis - Abstract Memory Store Models"), - llvm::cl::init(BasicStoreModel), - llvm::cl::values( -#define ANALYSIS_STORE(NAME, CMDFLAG, DESC, CREATFN)\ -clEnumValN(NAME##Model, CMDFLAG, DESC), -#include "clang/Frontend/Analyses.def" -clEnumValEnd)); - -static llvm::cl::opt -AnalysisConstraintsOpt("analyzer-constraints", - llvm::cl::desc("Source Code Analysis - Symbolic Constraint Engines"), - llvm::cl::init(RangeConstraintsModel), - llvm::cl::values( -#define ANALYSIS_CONSTRAINTS(NAME, CMDFLAG, DESC, CREATFN)\ -clEnumValN(NAME##Model, CMDFLAG, DESC), -#include "clang/Frontend/Analyses.def" -clEnumValEnd)); - -static llvm::cl::opt -AnalysisDiagOpt("analyzer-output", - llvm::cl::desc("Source Code Analysis - Output Options"), - llvm::cl::init(PD_HTML), - llvm::cl::values( -#define ANALYSIS_DIAGNOSTICS(NAME, CMDFLAG, DESC, CREATFN, AUTOCREATE)\ -clEnumValN(PD_##NAME, CMDFLAG, DESC), -#include "clang/Frontend/Analyses.def" -clEnumValEnd)); - -static llvm::cl::opt -AnalyzeAll("analyzer-opt-analyze-headers", - llvm::cl::desc("Force the static analyzer to analyze " - "functions defined in header files")); - -static llvm::cl::opt -AnalyzerDisplayProgress("analyzer-display-progress", - llvm::cl::desc("Emit verbose output about the analyzer's progress")); - -static llvm::cl::opt -AnalyzerExperimentalChecks("analyzer-experimental-checks", - llvm::cl::desc("Use experimental path-sensitive checks")); - -static llvm::cl::opt -AnalyzerExperimentalInternalChecks("analyzer-experimental-internal-checks", - llvm::cl::desc("Use new default path-sensitive checks currently in testing")); - -static llvm::cl::opt -AnalyzeSpecificFunction("analyze-function", - llvm::cl::desc("Run analysis on specific function")); - -static llvm::cl::opt -EagerlyAssume("analyzer-eagerly-assume", - llvm::cl::desc("Eagerly assume the truth/falseness of some " - "symbolic constraints")); - -static llvm::cl::opt -NoPurgeDead("analyzer-no-purge-dead", - llvm::cl::desc("Don't remove dead symbols, bindings, and constraints before" - " processing a statement")); - -static llvm::cl::opt -TrimGraph("trim-egraph", - llvm::cl::desc("Only show error-related paths in the analysis graph")); - -static llvm::cl::opt -VisualizeEGDot("analyzer-viz-egraph-graphviz", - llvm::cl::desc("Display exploded graph using GraphViz")); - -static llvm::cl::opt -VisualizeEGUbi("analyzer-viz-egraph-ubigraph", - llvm::cl::desc("Display exploded graph using Ubigraph")); - -} - -//===----------------------------------------------------------------------===// -// Code Generation Options -//===----------------------------------------------------------------------===// - -namespace codegenoptions { - -static llvm::cl::opt -DisableLLVMOptimizations("disable-llvm-optzns", - llvm::cl::desc("Don't run LLVM optimization passes")); - -static llvm::cl::opt -DisableRedZone("disable-red-zone", - llvm::cl::desc("Do not emit code that uses the red zone.")); - -static llvm::cl::opt -GenerateDebugInfo("g", - llvm::cl::desc("Generate source level debug information")); - -static llvm::cl::opt -MAsmVerbose("masm-verbose", llvm::cl::desc("Generate verbose assembly output")); - -static llvm::cl::opt -MCodeModel("mcode-model", llvm::cl::desc("The code model to use")); - -static llvm::cl::opt -MDebugPass("mdebu-pass", llvm::cl::desc("Output additional debug information")); - -static llvm::cl::opt -MDisableFPElim("mdisable-fp-elim", - llvm::cl::desc("Disable frame pointer elimination optimization")); - -static llvm::cl::opt -MFloatABI("mfloat-abi", llvm::cl::desc("The float ABI to use")); - -static llvm::cl::opt -MLimitFloatPrecision("mlimit-float-precision", - llvm::cl::desc("Limit float precision to the given value")); - -static llvm::cl::opt -MNoZeroInitializedInBSS("mno-zero-initialized-in-bss", - llvm::cl::desc("Do not put zero initialized data in the BSS")); - -static llvm::cl::opt -MSoftFloat("msoft-float", llvm::cl::desc("Use software floating point")); - -static llvm::cl::opt -MRelocationModel("mrelocation-model", - llvm::cl::desc("The relocation model to use"), - llvm::cl::init("pic")); - -static llvm::cl::opt -MUnwindTables("munwind-tables", - llvm::cl::desc("Generate unwinding tables for all functions")); - -static llvm::cl::opt -MainFileName("main-file-name", - llvm::cl::desc("Main file name to use for debug info")); - -static llvm::cl::opt -NoCommon("fno-common", - llvm::cl::desc("Compile common globals like normal definitions"), - llvm::cl::ValueDisallowed); - -static llvm::cl::opt -NoImplicitFloat("no-implicit-float", - llvm::cl::desc("Don't generate implicit floating point instructions (x86-only)")); - -static llvm::cl::opt -NoMergeConstants("fno-merge-all-constants", - llvm::cl::desc("Disallow merging of constants.")); - -// It might be nice to add bounds to the CommandLine library directly. -struct OptLevelParser : public llvm::cl::parser { - bool parse(llvm::cl::Option &O, llvm::StringRef ArgName, - llvm::StringRef Arg, unsigned &Val) { - if (llvm::cl::parser::parse(O, ArgName, Arg, Val)) - return true; - if (Val > 3) - return O.error("'" + Arg + "' invalid optimization level!"); - return false; - } -}; -static llvm::cl::opt -OptLevel("O", llvm::cl::Prefix, - llvm::cl::desc("Optimization level")); - -static llvm::cl::opt -OptSize("Os", llvm::cl::desc("Optimize for size")); - -} - -//===----------------------------------------------------------------------===// -// Dependency Output Options -//===----------------------------------------------------------------------===// - -namespace dependencyoutputoptions { - -static llvm::cl::opt -DependencyFile("dependency-file", - llvm::cl::desc("Filename (or -) to write dependency output to")); - -static llvm::cl::opt -DependenciesIncludeSystemHeaders("sys-header-deps", - llvm::cl::desc("Include system headers in dependency output")); - -static llvm::cl::list -DependencyTargets("MT", - llvm::cl::desc("Specify target for dependency")); - -static llvm::cl::opt -PhonyDependencyTarget("MP", - llvm::cl::desc("Create phony target for each dependency " - "(other than main file)")); - -} - -//===----------------------------------------------------------------------===// -// Diagnostic Options -//===----------------------------------------------------------------------===// - -namespace diagnosticoptions { - -static llvm::cl::opt -DumpBuildInformation("dump-build-information", - llvm::cl::value_desc("filename"), - llvm::cl::desc("output a dump of some build information to a file")); - -static llvm::cl::opt -NoShowColumn("fno-show-column", - llvm::cl::desc("Do not include column number on diagnostics")); - -static llvm::cl::opt -NoShowLocation("fno-show-source-location", - llvm::cl::desc("Do not include source location information with" - " diagnostics")); - -static llvm::cl::opt -NoCaretDiagnostics("fno-caret-diagnostics", - llvm::cl::desc("Do not include source line and caret with" - " diagnostics")); - -static llvm::cl::opt -NoDiagnosticsFixIt("fno-diagnostics-fixit-info", - llvm::cl::desc("Do not include fixit information in" - " diagnostics")); - -static llvm::cl::opt OptNoWarnings("w"); - -static llvm::cl::opt OptPedantic("pedantic"); - -static llvm::cl::opt OptPedanticErrors("pedantic-errors"); - -// This gets all -W options, including -Werror, -W[no-]system-headers, etc. The -// driver has stripped off -Wa,foo etc. The driver has also translated -W to -// -Wextra, so we don't need to worry about it. -static llvm::cl::list -OptWarnings("W", llvm::cl::Prefix, llvm::cl::ValueOptional); - -static llvm::cl::opt -PrintSourceRangeInfo("fdiagnostics-print-source-range-info", - llvm::cl::desc("Print source range spans in numeric form")); - -static llvm::cl::opt -PrintDiagnosticOption("fdiagnostics-show-option", - llvm::cl::desc("Print diagnostic name with mappable diagnostics")); - -static llvm::cl::opt -MessageLength("fmessage-length", - llvm::cl::desc("Format message diagnostics so that they fit " - "within N columns or fewer, when possible."), - llvm::cl::value_desc("N")); - -static llvm::cl::opt -PrintColorDiagnostic("fcolor-diagnostics", - llvm::cl::desc("Use colors in diagnostics")); - -static llvm::cl::opt -SilenceRewriteMacroWarning("Wno-rewrite-macros", - llvm::cl::desc("Silence ObjC rewriting warnings")); - -static llvm::cl::opt -VerifyDiagnostics("verify", - llvm::cl::desc("Verify emitted diagnostics and warnings")); - -} - -//===----------------------------------------------------------------------===// -// Frontend Options -//===----------------------------------------------------------------------===// - -namespace frontendoptions { - -using namespace clang::frontend; - -static llvm::cl::opt -CodeCompletionAt("code-completion-at", - llvm::cl::value_desc("file:line:column"), - llvm::cl::desc("Dump code-completion information at a location")); - -static llvm::cl::opt -NoCodeCompletionDebugPrinter("no-code-completion-debug-printer", - llvm::cl::desc("Don't the \"debug\" code-completion print")); - -static llvm::cl::opt -CodeCompletionWantsMacros("code-completion-macros", - llvm::cl::desc("Include macros in code-completion results")); - -static llvm::cl::opt -DisableFree("disable-free", - llvm::cl::desc("Disable freeing of memory on exit")); - -static llvm::cl::opt -EmptyInputOnly("empty-input-only", - llvm::cl::desc("Force running on an empty input file")); - -static llvm::cl::opt -InputType("x", llvm::cl::desc("Input language type"), - llvm::cl::init(FrontendOptions::IK_None), - llvm::cl::values(clEnumValN(FrontendOptions::IK_C, "c", "C"), - clEnumValN(FrontendOptions::IK_OpenCL, "cl", "OpenCL C"), - clEnumValN(FrontendOptions::IK_CXX, "c++", "C++"), - clEnumValN(FrontendOptions::IK_ObjC, "objective-c", - "Objective C"), - clEnumValN(FrontendOptions::IK_ObjCXX, "objective-c++", - "Objective C++"), - clEnumValN(FrontendOptions::IK_PreprocessedC, - "cpp-output", - "Preprocessed C"), - clEnumValN(FrontendOptions::IK_Asm, - "assembler-with-cpp", - "Assembly Source Codde"), - clEnumValN(FrontendOptions::IK_PreprocessedCXX, - "c++-cpp-output", - "Preprocessed C++"), - clEnumValN(FrontendOptions::IK_PreprocessedObjC, - "objective-c-cpp-output", - "Preprocessed Objective C"), - clEnumValN(FrontendOptions::IK_PreprocessedObjCXX, - "objective-c++-cpp-output", - "Preprocessed Objective C++"), - clEnumValN(FrontendOptions::IK_C, "c-header", - "C header"), - clEnumValN(FrontendOptions::IK_ObjC, "objective-c-header", - "Objective-C header"), - clEnumValN(FrontendOptions::IK_CXX, "c++-header", - "C++ header"), - clEnumValN(FrontendOptions::IK_ObjCXX, - "objective-c++-header", - "Objective-C++ header"), - clEnumValN(FrontendOptions::IK_AST, "ast", - "Clang AST"), - clEnumValEnd)); - -static llvm::cl::list -InputFilenames(llvm::cl::Positional, llvm::cl::desc("")); - -static llvm::cl::opt -InheritanceViewCls("cxx-inheritance-view", - llvm::cl::value_desc("class name"), - llvm::cl::desc("View C++ inheritance for a specified class")); - -static llvm::cl::list -FixItAtLocations("fixit-at", llvm::cl::value_desc("source-location"), - llvm::cl::desc("Perform Fix-It modifications at the given source location")); - -static llvm::cl::opt -OutputFile("o", - llvm::cl::value_desc("path"), - llvm::cl::desc("Specify output file")); - -static llvm::cl::opt -PluginActionName("plugin", - llvm::cl::desc("Use the named plugin action " - "(use \"help\" to list available options)")); - -static llvm::cl::opt -ProgAction(llvm::cl::desc("Choose output type:"), llvm::cl::ZeroOrMore, - llvm::cl::init(ParseSyntaxOnly), - llvm::cl::values( - clEnumValN(RunPreprocessorOnly, "Eonly", - "Just run preprocessor, no output (for timings)"), - clEnumValN(PrintPreprocessedInput, "E", - "Run preprocessor, emit preprocessed file"), - clEnumValN(DumpRawTokens, "dump-raw-tokens", - "Lex file in raw mode and dump raw tokens"), - clEnumValN(RunAnalysis, "analyze", - "Run static analysis engine"), - clEnumValN(DumpTokens, "dump-tokens", - "Run preprocessor, dump internal rep of tokens"), - clEnumValN(ParseNoop, "parse-noop", - "Run parser with noop callbacks (for timings)"), - clEnumValN(ParseSyntaxOnly, "fsyntax-only", - "Run parser and perform semantic analysis"), - clEnumValN(FixIt, "fixit", - "Apply fix-it advice to the input source"), - clEnumValN(ParsePrintCallbacks, "parse-print-callbacks", - "Run parser and print each callback invoked"), - clEnumValN(EmitHTML, "emit-html", - "Output input source as HTML"), - clEnumValN(ASTPrint, "ast-print", - "Build ASTs and then pretty-print them"), - clEnumValN(ASTPrintXML, "ast-print-xml", - "Build ASTs and then print them in XML format"), - clEnumValN(ASTDump, "ast-dump", - "Build ASTs and then debug dump them"), - clEnumValN(ASTView, "ast-view", - "Build ASTs and view them with GraphViz"), - clEnumValN(PrintDeclContext, "print-decl-contexts", - "Print DeclContexts and their Decls"), - clEnumValN(DumpRecordLayouts, "dump-record-layouts", - "Dump record layout information"), - clEnumValN(GeneratePTH, "emit-pth", - "Generate pre-tokenized header file"), - clEnumValN(GeneratePCH, "emit-pch", - "Generate pre-compiled header file"), - clEnumValN(EmitAssembly, "S", - "Emit native assembly code"), - clEnumValN(EmitLLVM, "emit-llvm", - "Build ASTs then convert to LLVM, emit .ll file"), - clEnumValN(EmitBC, "emit-llvm-bc", - "Build ASTs then convert to LLVM, emit .bc file"), - clEnumValN(EmitLLVMOnly, "emit-llvm-only", - "Build ASTs and convert to LLVM, discarding output"), - clEnumValN(RewriteTest, "rewrite-test", - "Rewriter playground"), - clEnumValN(RewriteObjC, "rewrite-objc", - "Rewrite ObjC into C (code rewriter example)"), - clEnumValN(RewriteMacros, "rewrite-macros", - "Expand macros without full preprocessing"), - clEnumValN(RewriteBlocks, "rewrite-blocks", - "Rewrite Blocks to C"), - clEnumValEnd)); - -static llvm::cl::opt -RelocatablePCH("relocatable-pch", - llvm::cl::desc("Whether to build a relocatable precompiled " - "header")); -static llvm::cl::opt -Stats("print-stats", - llvm::cl::desc("Print performance metrics and statistics")); - -static llvm::cl::opt -TimeReport("ftime-report", - llvm::cl::desc("Print the amount of time each " - "phase of compilation takes")); - -} - -//===----------------------------------------------------------------------===// -// Language Options -//===----------------------------------------------------------------------===// - -namespace langoptions { - -using namespace clang::frontend; - -static llvm::cl::opt -NoBuiltin("fno-builtin", - llvm::cl::desc("Disable implicit builtin knowledge of functions")); - -static llvm::cl::opt -AltiVec("faltivec", llvm::cl::desc("Enable AltiVec vector initializer syntax")); - -static llvm::cl::opt -AccessControl("faccess-control", - llvm::cl::desc("Enable C++ access control")); - -static llvm::cl::opt -NoSignedChar("fno-signed-char", - llvm::cl::desc("Char is unsigned")); - -static llvm::cl::opt -DollarsInIdents("fdollars-in-identifiers", - llvm::cl::desc("Allow '$' in identifiers")); - -static llvm::cl::opt -EmitAllDecls("femit-all-decls", - llvm::cl::desc("Emit all declarations, even if unused")); - -static llvm::cl::opt -EnableBlocks("fblocks", llvm::cl::desc("enable the 'blocks' language feature")); - -static llvm::cl::opt -EnableHeinousExtensions("fheinous-gnu-extensions", - llvm::cl::desc("enable GNU extensions that you really really shouldn't use"), - llvm::cl::ValueDisallowed, llvm::cl::Hidden); - -static llvm::cl::opt -Exceptions("fexceptions", - llvm::cl::desc("Enable support for exception handling")); - -static llvm::cl::opt -Freestanding("ffreestanding", - llvm::cl::desc("Assert that the compilation takes place in a " - "freestanding environment")); - -static llvm::cl::opt -GNURuntime("fgnu-runtime", - llvm::cl::desc("Generate output compatible with the standard GNU " - "Objective-C runtime")); - -static llvm::cl::opt -LangStd("std", llvm::cl::desc("Language standard to compile for"), - llvm::cl::init(LangStandard::lang_unspecified), llvm::cl::values( -#define LANGSTANDARD(id, name, desc, features) \ - clEnumValN(LangStandard::lang_##id, name, desc), -#include "clang/Frontend/LangStandards.def" - clEnumValEnd)); - -static llvm::cl::opt -MSExtensions("fms-extensions", - llvm::cl::desc("Accept some non-standard constructs used in " - "Microsoft header files ")); - -static llvm::cl::opt -NoMathErrno("fno-math-errno", - llvm::cl::desc("Don't require math functions to respect errno")); - -static llvm::cl::opt -NoElideConstructors("fno-elide-constructors", - llvm::cl::desc("Disable C++ copy constructor elision")); - -static llvm::cl::opt -NoLaxVectorConversions("fno-lax-vector-conversions", - llvm::cl::desc("Disallow implicit conversions between " - "vectors with a different number of " - "elements or different element types")); - - -static llvm::cl::opt -NoOperatorNames("fno-operator-names", - llvm::cl::desc("Do not treat C++ operator name keywords as " - "synonyms for operators")); - -static llvm::cl::opt -ObjCConstantStringClass("fconstant-string-class", - llvm::cl::value_desc("class name"), - llvm::cl::desc("Specify the class to use for constant " - "Objective-C string objects.")); - -static llvm::cl::opt -ObjCEnableGC("fobjc-gc", - llvm::cl::desc("Enable Objective-C garbage collection")); - -static llvm::cl::opt -ObjCExclusiveGC("fobjc-gc-only", - llvm::cl::desc("Use GC exclusively for Objective-C related " - "memory management")); - -static llvm::cl::opt -ObjCEnableGCBitmapPrint("print-ivar-layout", - llvm::cl::desc("Enable Objective-C Ivar layout bitmap print trace")); - -static llvm::cl::opt -ObjCNonFragileABI("fobjc-nonfragile-abi", - llvm::cl::desc("enable objective-c's nonfragile abi")); - -static llvm::cl::opt -OverflowChecking("ftrapv", - llvm::cl::desc("Trap on integer overflow")); - -static llvm::cl::opt -PICLevel("pic-level", llvm::cl::desc("Value for __PIC__")); - -static llvm::cl::opt -PThread("pthread", llvm::cl::desc("Support POSIX threads in generated code")); - -static llvm::cl::opt -PascalStrings("fpascal-strings", - llvm::cl::desc("Recognize and construct Pascal-style " - "string literals")); - -static llvm::cl::opt -NoRtti("fno-rtti", - llvm::cl::desc("Disable generation of rtti information")); - -static llvm::cl::opt -ShortWChar("fshort-wchar", - llvm::cl::desc("Force wchar_t to be a short unsigned int")); - -static llvm::cl::opt -StaticDefine("static-define", llvm::cl::desc("Should __STATIC__ be defined")); - -static llvm::cl::opt -StackProtector("stack-protector", - llvm::cl::desc("Enable stack protectors")); - -static llvm::cl::opt -SymbolVisibility("fvisibility", - llvm::cl::desc("Set the default symbol visibility:"), - llvm::cl::init(LangOptions::Default), - llvm::cl::values(clEnumValN(LangOptions::Default, "default", - "Use default symbol visibility"), - clEnumValN(LangOptions::Hidden, "hidden", - "Use hidden symbol visibility"), - clEnumValN(LangOptions::Protected,"protected", - "Use protected symbol visibility"), - clEnumValEnd)); - -static llvm::cl::opt -TemplateDepth("ftemplate-depth", - llvm::cl::desc("Maximum depth of recursive template " - "instantiation")); - -static llvm::cl::opt -Trigraphs("trigraphs", llvm::cl::desc("Process trigraph sequences")); - -static llvm::cl::opt -WritableStrings("fwritable-strings", - llvm::cl::desc("Store string literals as writable data")); - -} - -//===----------------------------------------------------------------------===// -// General Preprocessor Options -//===----------------------------------------------------------------------===// - -namespace preprocessoroptions { - -static llvm::cl::list -D_macros("D", llvm::cl::value_desc("macro"), llvm::cl::Prefix, - llvm::cl::desc("Predefine the specified macro")); - -static llvm::cl::list -ImplicitIncludes("include", llvm::cl::value_desc("file"), - llvm::cl::desc("Include file before parsing")); -static llvm::cl::list -ImplicitMacroIncludes("imacros", llvm::cl::value_desc("file"), - llvm::cl::desc("Include macros from file before parsing")); - -static llvm::cl::opt -ImplicitIncludePCH("include-pch", llvm::cl::value_desc("file"), - llvm::cl::desc("Include precompiled header file")); - -static llvm::cl::opt -ImplicitIncludePTH("include-pth", llvm::cl::value_desc("file"), - llvm::cl::desc("Include file before parsing")); - -static llvm::cl::opt -TokenCache("token-cache", llvm::cl::value_desc("path"), - llvm::cl::desc("Use specified token cache file")); - -static llvm::cl::list -U_macros("U", llvm::cl::value_desc("macro"), llvm::cl::Prefix, - llvm::cl::desc("Undefine the specified macro")); - -static llvm::cl::opt -UndefMacros("undef", llvm::cl::value_desc("macro"), - llvm::cl::desc("undef all system defines")); - -} - -//===----------------------------------------------------------------------===// -// Header Search Options -//===----------------------------------------------------------------------===// - -namespace headersearchoptions { - -static llvm::cl::opt -nostdinc("nostdinc", llvm::cl::desc("Disable standard #include directories")); - -static llvm::cl::opt -nobuiltininc("nobuiltininc", - llvm::cl::desc("Disable builtin #include directories")); - -// Various command line options. These four add directories to each chain. -static llvm::cl::list -F_dirs("F", llvm::cl::value_desc("directory"), llvm::cl::Prefix, - llvm::cl::desc("Add directory to framework include search path")); - -static llvm::cl::list -I_dirs("I", llvm::cl::value_desc("directory"), llvm::cl::Prefix, - llvm::cl::desc("Add directory to include search path")); - -static llvm::cl::list -idirafter_dirs("idirafter", llvm::cl::value_desc("directory"), llvm::cl::Prefix, - llvm::cl::desc("Add directory to AFTER include search path")); - -static llvm::cl::list -iquote_dirs("iquote", llvm::cl::value_desc("directory"), llvm::cl::Prefix, - llvm::cl::desc("Add directory to QUOTE include search path")); - -static llvm::cl::list -isystem_dirs("isystem", llvm::cl::value_desc("directory"), llvm::cl::Prefix, - llvm::cl::desc("Add directory to SYSTEM include search path")); - -// These handle -iprefix/-iwithprefix/-iwithprefixbefore. -static llvm::cl::list -iprefix_vals("iprefix", llvm::cl::value_desc("prefix"), llvm::cl::Prefix, - llvm::cl::desc("Set the -iwithprefix/-iwithprefixbefore prefix")); -static llvm::cl::list -iwithprefix_vals("iwithprefix", llvm::cl::value_desc("dir"), llvm::cl::Prefix, - llvm::cl::desc("Set directory to SYSTEM include search path with prefix")); -static llvm::cl::list -iwithprefixbefore_vals("iwithprefixbefore", llvm::cl::value_desc("dir"), - llvm::cl::Prefix, - llvm::cl::desc("Set directory to include search path with prefix")); - -static llvm::cl::opt -isysroot("isysroot", llvm::cl::value_desc("dir"), - llvm::cl::desc("Set the system root directory (usually /)")); - -static llvm::cl::opt -Verbose("v", llvm::cl::desc("Enable verbose output")); - -} - -//===----------------------------------------------------------------------===// -// Preprocessed Output Options -//===----------------------------------------------------------------------===// - -namespace preprocessoroutputoptions { - -static llvm::cl::opt -DisableLineMarkers("P", llvm::cl::desc("Disable linemarker output in -E mode")); - -static llvm::cl::opt -EnableCommentOutput("C", llvm::cl::desc("Enable comment output in -E mode")); - -static llvm::cl::opt -EnableMacroCommentOutput("CC", - llvm::cl::desc("Enable comment output in -E mode, " - "even from macro expansions")); -static llvm::cl::opt -DumpMacros("dM", llvm::cl::desc("Print macro definitions in -E mode instead of" - " normal output")); -static llvm::cl::opt -DumpDefines("dD", llvm::cl::desc("Print macro definitions in -E mode in " - "addition to normal output")); - -} - -//===----------------------------------------------------------------------===// -// Target Options -//===----------------------------------------------------------------------===// - -namespace targetoptions { - -static llvm::cl::opt -TargetABI("target-abi", - llvm::cl::desc("Target a particular ABI type")); - -static llvm::cl::opt -TargetCPU("mcpu", - llvm::cl::desc("Target a specific cpu type ('-mcpu help' for details)")); - -static llvm::cl::list -TargetFeatures("target-feature", llvm::cl::desc("Target specific attributes")); - -static llvm::cl::opt -TargetTriple("triple", - llvm::cl::desc("Specify target triple (e.g. i686-apple-darwin9)")); - -} - -//===----------------------------------------------------------------------===// -// Option Object Construction -//===----------------------------------------------------------------------===// - -void clang::InitializeAnalyzerOptions(AnalyzerOptions &Opts) { - using namespace analyzeroptions; - Opts.AnalysisList = AnalysisList; - Opts.AnalysisStoreOpt = AnalysisStoreOpt; - Opts.AnalysisConstraintsOpt = AnalysisConstraintsOpt; - Opts.AnalysisDiagOpt = AnalysisDiagOpt; - Opts.VisualizeEGDot = VisualizeEGDot; - Opts.VisualizeEGUbi = VisualizeEGUbi; - Opts.AnalyzeAll = AnalyzeAll; - Opts.AnalyzerDisplayProgress = AnalyzerDisplayProgress; - Opts.PurgeDead = !NoPurgeDead; - Opts.EagerlyAssume = EagerlyAssume; - Opts.AnalyzeSpecificFunction = AnalyzeSpecificFunction; - Opts.EnableExperimentalChecks = AnalyzerExperimentalChecks; - Opts.EnableExperimentalInternalChecks = AnalyzerExperimentalInternalChecks; - Opts.TrimGraph = TrimGraph; -} - -void clang::InitializeCodeGenOptions(CodeGenOptions &Opts, - const LangOptions &Lang) { - using namespace codegenoptions; - - // -Os implies -O2 - unsigned Opt = OptLevel.getPosition() ? OptLevel : 0; - Opts.OptimizationLevel = OptSize ? 2 : Opt; - - // We must always run at least the always inlining pass. - Opts.Inlining = (Opts.OptimizationLevel > 1) ? CodeGenOptions::NormalInlining - : CodeGenOptions::OnlyAlwaysInlining; - - Opts.DebugInfo = GenerateDebugInfo; - Opts.DisableLLVMOpts = DisableLLVMOptimizations; - Opts.DisableRedZone = DisableRedZone; - Opts.MergeAllConstants = !NoMergeConstants; - Opts.NoCommon = NoCommon; - Opts.NoImplicitFloat = NoImplicitFloat; - Opts.OptimizeSize = OptSize; - Opts.UnrollLoops = (Opts.OptimizationLevel > 1 && !OptSize); - - // LLVM Code Generator options. - - Opts.AsmVerbose = MAsmVerbose; - Opts.CodeModel = MCodeModel; - Opts.DebugPass = MDebugPass; - Opts.DisableFPElim = MDisableFPElim; - Opts.FloatABI = MFloatABI; - Opts.LimitFloatPrecision = MLimitFloatPrecision; - Opts.NoZeroInitializedInBSS = MNoZeroInitializedInBSS; - Opts.SoftFloat = MSoftFloat; - Opts.RelocationModel = MRelocationModel; - Opts.UnwindTables = MUnwindTables; - -#ifdef NDEBUG - Opts.VerifyModule = 0; -#endif - - if (MainFileName.getPosition()) - Opts.MainFileName = MainFileName; -} - -void clang::InitializeDependencyOutputOptions(DependencyOutputOptions &Opts) { - using namespace dependencyoutputoptions; - - Opts.OutputFile = DependencyFile; - Opts.Targets = DependencyTargets; - Opts.IncludeSystemHeaders = DependenciesIncludeSystemHeaders; - Opts.UsePhonyTargets = PhonyDependencyTarget; -} - -void clang::InitializeDiagnosticOptions(DiagnosticOptions &Opts) { - using namespace diagnosticoptions; - - Opts.Warnings = OptWarnings; - Opts.DumpBuildInformation = DumpBuildInformation; - Opts.IgnoreWarnings = OptNoWarnings; - Opts.MessageLength = MessageLength; - Opts.NoRewriteMacros = SilenceRewriteMacroWarning; - Opts.Pedantic = OptPedantic; - Opts.PedanticErrors = OptPedanticErrors; - Opts.ShowCarets = !NoCaretDiagnostics; - Opts.ShowColors = PrintColorDiagnostic; - Opts.ShowColumn = !NoShowColumn; - Opts.ShowFixits = !NoDiagnosticsFixIt; - Opts.ShowLocation = !NoShowLocation; - Opts.ShowOptionNames = PrintDiagnosticOption; - Opts.ShowSourceRanges = PrintSourceRangeInfo; - Opts.VerifyDiagnostics = VerifyDiagnostics; -} - -void clang::InitializeFrontendOptions(FrontendOptions &Opts) { - using namespace frontendoptions; - - Opts.ProgramAction = ProgAction; - Opts.ActionName = PluginActionName; - Opts.CodeCompletionAt = CodeCompletionAt; - Opts.DebugCodeCompletionPrinter = !NoCodeCompletionDebugPrinter; - Opts.DisableFree = DisableFree; - Opts.EmptyInputOnly = EmptyInputOnly; - Opts.FixItLocations = FixItAtLocations; - Opts.OutputFile = OutputFile; - Opts.RelocatablePCH = RelocatablePCH; - Opts.ShowMacrosInCodeCompletion = CodeCompletionWantsMacros; - Opts.ShowStats = Stats; - Opts.ShowTimers = TimeReport; - Opts.ViewClassInheritance = InheritanceViewCls; - - // Enforce certain program action implications. - if (!Opts.ActionName.empty()) - Opts.ProgramAction = frontend::PluginAction; - if (!Opts.ViewClassInheritance.empty()) - Opts.ProgramAction = frontend::InheritanceView; - if (!Opts.FixItLocations.empty()) - Opts.ProgramAction = frontend::FixIt; - - // '-' is the default input if none is given. - if (InputFilenames.empty()) { - FrontendOptions::InputKind IK = InputType; - if (IK == FrontendOptions::IK_None) IK = FrontendOptions::IK_C; - Opts.Inputs.push_back(std::make_pair(IK, "-")); - } else { - for (unsigned i = 0, e = InputFilenames.size(); i != e; ++i) { - FrontendOptions::InputKind IK = InputType; - llvm::StringRef Ext = - llvm::StringRef(InputFilenames[i]).rsplit('.').second; - if (IK == FrontendOptions::IK_None) - IK = FrontendOptions::getInputKindForExtension(Ext); - Opts.Inputs.push_back(std::make_pair(IK, InputFilenames[i])); - } - } -} - -void clang::InitializeHeaderSearchOptions(HeaderSearchOptions &Opts, - llvm::StringRef BuiltinIncludePath) { - using namespace headersearchoptions; - - if (isysroot.getPosition()) - Opts.Sysroot = isysroot; - Opts.Verbose = Verbose; - - // Handle -I... and -F... options, walking the lists in parallel. - unsigned Iidx = 0, Fidx = 0; - while (Iidx < I_dirs.size() && Fidx < F_dirs.size()) { - if (I_dirs.getPosition(Iidx) < F_dirs.getPosition(Fidx)) { - Opts.AddPath(I_dirs[Iidx], frontend::Angled, true, false); - ++Iidx; - } else { - Opts.AddPath(F_dirs[Fidx], frontend::Angled, true, true); - ++Fidx; - } - } - - // Consume what's left from whatever list was longer. - for (; Iidx != I_dirs.size(); ++Iidx) - Opts.AddPath(I_dirs[Iidx], frontend::Angled, true, false); - for (; Fidx != F_dirs.size(); ++Fidx) - Opts.AddPath(F_dirs[Fidx], frontend::Angled, true, true); - - // Handle -idirafter... options. - for (unsigned i = 0, e = idirafter_dirs.size(); i != e; ++i) - Opts.AddPath(idirafter_dirs[i], frontend::After, true, false); - - // Handle -iquote... options. - for (unsigned i = 0, e = iquote_dirs.size(); i != e; ++i) - Opts.AddPath(iquote_dirs[i], frontend::Quoted, true, false); - - // Handle -isystem... options. - for (unsigned i = 0, e = isystem_dirs.size(); i != e; ++i) - Opts.AddPath(isystem_dirs[i], frontend::System, true, false); - - // Walk the -iprefix/-iwithprefix/-iwithprefixbefore argument lists in - // parallel, processing the values in order of occurance to get the right - // prefixes. - { - std::string Prefix = ""; // FIXME: this isn't the correct default prefix. - unsigned iprefix_idx = 0; - unsigned iwithprefix_idx = 0; - unsigned iwithprefixbefore_idx = 0; - bool iprefix_done = iprefix_vals.empty(); - bool iwithprefix_done = iwithprefix_vals.empty(); - bool iwithprefixbefore_done = iwithprefixbefore_vals.empty(); - while (!iprefix_done || !iwithprefix_done || !iwithprefixbefore_done) { - if (!iprefix_done && - (iwithprefix_done || - iprefix_vals.getPosition(iprefix_idx) < - iwithprefix_vals.getPosition(iwithprefix_idx)) && - (iwithprefixbefore_done || - iprefix_vals.getPosition(iprefix_idx) < - iwithprefixbefore_vals.getPosition(iwithprefixbefore_idx))) { - Prefix = iprefix_vals[iprefix_idx]; - ++iprefix_idx; - iprefix_done = iprefix_idx == iprefix_vals.size(); - } else if (!iwithprefix_done && - (iwithprefixbefore_done || - iwithprefix_vals.getPosition(iwithprefix_idx) < - iwithprefixbefore_vals.getPosition(iwithprefixbefore_idx))) { - Opts.AddPath(Prefix+iwithprefix_vals[iwithprefix_idx], - frontend::System, false, false); - ++iwithprefix_idx; - iwithprefix_done = iwithprefix_idx == iwithprefix_vals.size(); - } else { - Opts.AddPath(Prefix+iwithprefixbefore_vals[iwithprefixbefore_idx], - frontend::Angled, false, false); - ++iwithprefixbefore_idx; - iwithprefixbefore_done = - iwithprefixbefore_idx == iwithprefixbefore_vals.size(); - } - } - } - - // Add CPATH environment paths. - if (const char *Env = getenv("CPATH")) - Opts.EnvIncPath = Env; - - // Add language specific environment paths. - if (const char *Env = getenv("OBJCPLUS_INCLUDE_PATH")) - Opts.ObjCXXEnvIncPath = Env; - if (const char *Env = getenv("CPLUS_INCLUDE_PATH")) - Opts.CXXEnvIncPath = Env; - if (const char *Env = getenv("OBJC_INCLUDE_PATH")) - Opts.CEnvIncPath = Env; - if (const char *Env = getenv("C_INCLUDE_PATH")) - Opts.CEnvIncPath = Env; - - if (!nobuiltininc) - Opts.BuiltinIncludePath = BuiltinIncludePath; - - Opts.UseStandardIncludes = !nostdinc; -} - -void clang::InitializePreprocessorOptions(PreprocessorOptions &Opts) { - using namespace preprocessoroptions; - - Opts.ImplicitPCHInclude = ImplicitIncludePCH; - Opts.ImplicitPTHInclude = ImplicitIncludePTH; - - // Select the token cache file, we don't support more than one currently so we - // can't have both an implicit-pth and a token cache file. - if (TokenCache.getPosition() && ImplicitIncludePTH.getPosition()) { - // FIXME: Don't fail like this. - fprintf(stderr, "error: cannot use both -token-cache and -include-pth " - "options\n"); - exit(1); - } - if (TokenCache.getPosition()) - Opts.TokenCache = TokenCache; - else - Opts.TokenCache = ImplicitIncludePTH; - - // Use predefines? - Opts.UsePredefines = !UndefMacros; - - // Add macros from the command line. - unsigned d = 0, D = D_macros.size(); - unsigned u = 0, U = U_macros.size(); - while (d < D || u < U) { - if (u == U || (d < D && D_macros.getPosition(d) < U_macros.getPosition(u))) - Opts.addMacroDef(D_macros[d++]); - else - Opts.addMacroUndef(U_macros[u++]); - } - - // If -imacros are specified, include them now. These are processed before - // any -include directives. - for (unsigned i = 0, e = ImplicitMacroIncludes.size(); i != e; ++i) - Opts.MacroIncludes.push_back(ImplicitMacroIncludes[i]); - - // Add the ordered list of -includes, sorting in the implicit include options - // at the appropriate location. - llvm::SmallVector, 8> OrderedPaths; - std::string OriginalFile; - - if (!ImplicitIncludePTH.empty()) - OrderedPaths.push_back(std::make_pair(ImplicitIncludePTH.getPosition(), - &ImplicitIncludePTH)); - if (!ImplicitIncludePCH.empty()) { - OriginalFile = PCHReader::getOriginalSourceFile(ImplicitIncludePCH); - // FIXME: Don't fail like this. - if (OriginalFile.empty()) - exit(1); - OrderedPaths.push_back(std::make_pair(ImplicitIncludePCH.getPosition(), - &OriginalFile)); - } - for (unsigned i = 0, e = ImplicitIncludes.size(); i != e; ++i) - OrderedPaths.push_back(std::make_pair(ImplicitIncludes.getPosition(i), - &ImplicitIncludes[i])); - llvm::array_pod_sort(OrderedPaths.begin(), OrderedPaths.end()); - - for (unsigned i = 0, e = OrderedPaths.size(); i != e; ++i) - Opts.Includes.push_back(*OrderedPaths[i].second); -} - -void clang::InitializeLangOptions(LangOptions &Options, - FrontendOptions::InputKind IK) { - using namespace langoptions; - - // Set some properties which depend soley on the input kind; it would be nice - // to move these to the language standard, and have the driver resolve the - // input kind + language standard. - if (IK == FrontendOptions::IK_Asm) { - Options.AsmPreprocessor = 1; - } else if (IK == FrontendOptions::IK_ObjC || - IK == FrontendOptions::IK_ObjCXX || - IK == FrontendOptions::IK_PreprocessedObjC || - IK == FrontendOptions::IK_PreprocessedObjCXX) { - Options.ObjC1 = Options.ObjC2 = 1; - } - - if (LangStd == LangStandard::lang_unspecified) { - // Based on the base language, pick one. - switch (IK) { - case FrontendOptions::IK_None: - case FrontendOptions::IK_AST: - assert(0 && "Invalid input kind!"); - case FrontendOptions::IK_OpenCL: - LangStd = LangStandard::lang_opencl; - break; - case FrontendOptions::IK_Asm: - case FrontendOptions::IK_C: - case FrontendOptions::IK_PreprocessedC: - case FrontendOptions::IK_ObjC: - case FrontendOptions::IK_PreprocessedObjC: - LangStd = LangStandard::lang_gnu99; - break; - case FrontendOptions::IK_CXX: - case FrontendOptions::IK_PreprocessedCXX: - case FrontendOptions::IK_ObjCXX: - case FrontendOptions::IK_PreprocessedObjCXX: - LangStd = LangStandard::lang_gnucxx98; - break; - } - } - - const LangStandard &Std = LangStandard::getLangStandardForKind(LangStd); - Options.BCPLComment = Std.hasBCPLComments(); - Options.C99 = Std.isC99(); - Options.CPlusPlus = Std.isCPlusPlus(); - Options.CPlusPlus0x = Std.isCPlusPlus0x(); - Options.Digraphs = Std.hasDigraphs(); - Options.GNUInline = !Std.isC99(); - Options.GNUMode = Std.isGNUMode(); - Options.HexFloats = Std.hasHexFloats(); - Options.ImplicitInt = Std.hasImplicitInt(); - - // OpenCL has some additional defaults. - if (LangStd == LangStandard::lang_opencl) { - Options.OpenCL = 1; - Options.AltiVec = 1; - Options.CXXOperatorNames = 1; - Options.LaxVectorConversions = 1; - } - - // OpenCL and C++ both have bool, true, false keywords. - Options.Bool = Options.OpenCL || Options.CPlusPlus; - - if (Options.CPlusPlus) - Options.CXXOperatorNames = !NoOperatorNames; - - if (ObjCExclusiveGC) - Options.setGCMode(LangOptions::GCOnly); - else if (ObjCEnableGC) - Options.setGCMode(LangOptions::HybridGC); - - if (ObjCEnableGCBitmapPrint) - Options.ObjCGCBitmapPrint = 1; - - if (AltiVec) - Options.AltiVec = 1; - - if (PThread) - Options.POSIXThreads = 1; - - Options.setVisibilityMode(SymbolVisibility); - Options.OverflowChecking = OverflowChecking; - - // Mimicing gcc's behavior, trigraphs are only enabled if -trigraphs - // is specified, or -std is set to a conforming mode. - Options.Trigraphs = !Options.GNUMode; - if (Trigraphs.getPosition()) - Options.Trigraphs = Trigraphs; // Command line option wins if specified. - - // Default to not accepting '$' in identifiers when preprocessing assembler. - Options.DollarIdents = !Options.AsmPreprocessor; - if (DollarsInIdents.getPosition()) // Explicit setting overrides default. - Options.DollarIdents = DollarsInIdents; - - if (PascalStrings.getPosition()) - Options.PascalStrings = PascalStrings; - if (MSExtensions.getPosition()) - Options.Microsoft = MSExtensions; - Options.WritableStrings = WritableStrings; - if (NoLaxVectorConversions.getPosition()) - Options.LaxVectorConversions = 0; - Options.Exceptions = Exceptions; - Options.Rtti = !NoRtti; - Options.Blocks = EnableBlocks; - Options.CharIsSigned = !NoSignedChar; - if (ShortWChar.getPosition()) - Options.ShortWChar = ShortWChar; - - Options.NoBuiltin = NoBuiltin; - if (Freestanding) - Options.Freestanding = Options.NoBuiltin = 1; - - if (EnableHeinousExtensions) - Options.HeinousExtensions = 1; - - if (AccessControl) - Options.AccessControl = 1; - - Options.ElideConstructors = !NoElideConstructors; - - Options.MathErrno = !NoMathErrno; - - if (TemplateDepth.getPosition()) - Options.InstantiationDepth = TemplateDepth; - - // Override the default runtime if the user requested it. - if (GNURuntime) - Options.NeXTRuntime = 0; - - if (!ObjCConstantStringClass.empty()) - Options.ObjCConstantStringClass = ObjCConstantStringClass; - - if (ObjCNonFragileABI) - Options.ObjCNonFragileABI = 1; - - if (EmitAllDecls) - Options.EmitAllDecls = 1; - - // The __OPTIMIZE_SIZE__ define is tied to -Oz, which we don't support. - unsigned Opt = - codegenoptions::OptLevel.getPosition() ? codegenoptions::OptLevel : 0; - Options.OptimizeSize = 0; - Options.Optimize = codegenoptions::OptSize || Opt; - - assert(PICLevel <= 2 && "Invalid value for -pic-level"); - Options.PICLevel = PICLevel; - - // This is the __NO_INLINE__ define, which just depends on things like the - // optimization level and -fno-inline, not actually whether the backend has - // inlining enabled. - // - // FIXME: This is affected by other options (-fno-inline). - Options.NoInline = !Opt; - - Options.Static = StaticDefine; - - if (StackProtector.getPosition()) { - switch (StackProtector) { - default: - assert(0 && "Invalid value for -stack-protector"); - case 0: Options.setStackProtectorMode(LangOptions::SSPOff); break; - case 1: Options.setStackProtectorMode(LangOptions::SSPOn); break; - case 2: Options.setStackProtectorMode(LangOptions::SSPReq); break; - } - } -} - -void -clang::InitializePreprocessorOutputOptions(PreprocessorOutputOptions &Opts) { - using namespace preprocessoroutputoptions; - - Opts.ShowCPP = !DumpMacros; - Opts.ShowMacros = DumpMacros || DumpDefines; - Opts.ShowLineMarkers = !DisableLineMarkers; - Opts.ShowComments = EnableCommentOutput; - Opts.ShowMacroComments = EnableMacroCommentOutput; -} - -void clang::InitializeTargetOptions(TargetOptions &Opts) { - using namespace targetoptions; - - Opts.ABI = TargetABI; - Opts.CPU = TargetCPU; - Opts.Triple = TargetTriple; - Opts.Features = TargetFeatures; - - // Use the host triple if unspecified. - if (Opts.Triple.empty()) - Opts.Triple = llvm::sys::getHostTriple(); -} diff --git a/tools/clang-cc/Options.h b/tools/clang-cc/Options.h deleted file mode 100644 index 91e37f261103..000000000000 --- a/tools/clang-cc/Options.h +++ /dev/null @@ -1,54 +0,0 @@ -//===-- Options.h - clang-cc Option Handling --------------------*- C++ -*-===// -// -// The LLVM Compiler Infrastructure -// -// This file is distributed under the University of Illinois Open Source -// License. See LICENSE.TXT for details. -// -//===----------------------------------------------------------------------===// - -#ifndef LLVM_CLANGCC_OPTIONS_H -#define LLVM_CLANGCC_OPTIONS_H - -#include "clang/Frontend/FrontendOptions.h" -#include "llvm/ADT/StringRef.h" - -namespace clang { - -class AnalyzerOptions; -class CodeGenOptions; -class DependencyOutputOptions; -class DiagnosticOptions; -class FrontendOptions; -class HeaderSearchOptions; -class LangOptions; -class PreprocessorOptions; -class PreprocessorOutputOptions; -class TargetInfo; -class TargetOptions; - -void InitializeAnalyzerOptions(AnalyzerOptions &Opts); - -void InitializeCodeGenOptions(CodeGenOptions &Opts, - const LangOptions &Lang); - -void InitializeDependencyOutputOptions(DependencyOutputOptions &Opts); - -void InitializeDiagnosticOptions(DiagnosticOptions &Opts); - -void InitializeFrontendOptions(FrontendOptions &Opts); - -void InitializeHeaderSearchOptions(HeaderSearchOptions &Opts, - llvm::StringRef BuiltinIncludePath); - -void InitializeLangOptions(LangOptions &Options, FrontendOptions::InputKind LK); - -void InitializePreprocessorOptions(PreprocessorOptions &Opts); - -void InitializePreprocessorOutputOptions(PreprocessorOutputOptions &Opts); - -void InitializeTargetOptions(TargetOptions &Opts); - -} // end namespace clang - -#endif diff --git a/tools/clang-cc/clang-cc.cpp b/tools/clang-cc/clang-cc.cpp deleted file mode 100644 index 2899684284a9..000000000000 --- a/tools/clang-cc/clang-cc.cpp +++ /dev/null @@ -1,408 +0,0 @@ -//===--- clang.cpp - C-Language Front-end ---------------------------------===// -// -// The LLVM Compiler Infrastructure -// -// This file is distributed under the University of Illinois Open Source -// License. See LICENSE.TXT for details. -// -//===----------------------------------------------------------------------===// -// -// This utility may be invoked in the following manner: -// clang-cc --help - Output help info. -// clang-cc [options] - Read from stdin. -// clang-cc [options] file - Read from "file". -// clang-cc [options] file1 file2 - Read these files. -// -//===----------------------------------------------------------------------===// - -#include "Options.h" -#include "clang/Basic/Diagnostic.h" -#include "clang/Basic/FileManager.h" -#include "clang/Basic/SourceManager.h" -#include "clang/Basic/TargetInfo.h" -#include "clang/Basic/Version.h" -#include "clang/Driver/Arg.h" -#include "clang/Driver/ArgList.h" -#include "clang/Driver/CC1Options.h" -#include "clang/Driver/DriverDiagnostic.h" -#include "clang/Driver/OptTable.h" -#include "clang/Frontend/CompilerInstance.h" -#include "clang/Frontend/CompilerInvocation.h" -#include "clang/Frontend/FrontendActions.h" -#include "clang/Frontend/FrontendDiagnostic.h" -#include "clang/Frontend/FrontendPluginRegistry.h" -#include "clang/Frontend/TextDiagnosticBuffer.h" -#include "clang/Frontend/TextDiagnosticPrinter.h" -#include "clang/Frontend/VerifyDiagnosticsClient.h" -#include "llvm/LLVMContext.h" -#include "llvm/ADT/OwningPtr.h" -#include "llvm/Support/ErrorHandling.h" -#include "llvm/Support/ManagedStatic.h" -#include "llvm/Support/PluginLoader.h" -#include "llvm/Support/PrettyStackTrace.h" -#include "llvm/Support/Timer.h" -#include "llvm/Support/raw_ostream.h" -#include "llvm/System/Host.h" -#include "llvm/System/Path.h" -#include "llvm/System/Signals.h" -#include "llvm/Target/TargetSelect.h" -#include -using namespace clang; - -//===----------------------------------------------------------------------===// -// Main driver -//===----------------------------------------------------------------------===// - -std::string GetBuiltinIncludePath(const char *Argv0) { - llvm::sys::Path P = - llvm::sys::Path::GetMainExecutable(Argv0, - (void*)(intptr_t) GetBuiltinIncludePath); - - if (!P.isEmpty()) { - P.eraseComponent(); // Remove /clang from foo/bin/clang - P.eraseComponent(); // Remove /bin from foo/bin - - // Get foo/lib/clang//include - P.appendComponent("lib"); - P.appendComponent("clang"); - P.appendComponent(CLANG_VERSION_STRING); - P.appendComponent("include"); - } - - return P.str(); -} - -static void LLVMErrorHandler(void *UserData, const std::string &Message) { - Diagnostic &Diags = *static_cast(UserData); - - Diags.Report(diag::err_fe_error_backend) << Message; - - // We cannot recover from llvm errors. - exit(1); -} - -static FrontendAction *CreateFrontendAction(CompilerInstance &CI) { - using namespace clang::frontend; - - switch (CI.getFrontendOpts().ProgramAction) { - default: - llvm::llvm_unreachable("Invalid program action!"); - - case ASTDump: return new ASTDumpAction(); - case ASTPrint: return new ASTPrintAction(); - case ASTPrintXML: return new ASTPrintXMLAction(); - case ASTView: return new ASTViewAction(); - case DumpRawTokens: return new DumpRawTokensAction(); - case DumpRecordLayouts: return new DumpRecordAction(); - case DumpTokens: return new DumpTokensAction(); - case EmitAssembly: return new EmitAssemblyAction(); - case EmitBC: return new EmitBCAction(); - case EmitHTML: return new HTMLPrintAction(); - case EmitLLVM: return new EmitLLVMAction(); - case EmitLLVMOnly: return new EmitLLVMOnlyAction(); - case FixIt: return new FixItAction(); - case GeneratePCH: return new GeneratePCHAction(); - case GeneratePTH: return new GeneratePTHAction(); - case InheritanceView: return new InheritanceViewAction(); - case ParseNoop: return new ParseOnlyAction(); - case ParsePrintCallbacks: return new PrintParseAction(); - case ParseSyntaxOnly: return new SyntaxOnlyAction(); - - case PluginAction: { - if (CI.getFrontendOpts().ActionName == "help") { - llvm::errs() << "clang-cc plugins:\n"; - for (FrontendPluginRegistry::iterator it = - FrontendPluginRegistry::begin(), - ie = FrontendPluginRegistry::end(); - it != ie; ++it) - llvm::errs() << " " << it->getName() << " - " << it->getDesc() << "\n"; - exit(1); - } - - for (FrontendPluginRegistry::iterator it = - FrontendPluginRegistry::begin(), ie = FrontendPluginRegistry::end(); - it != ie; ++it) { - if (it->getName() == CI.getFrontendOpts().ActionName) - return it->instantiate(); - } - - CI.getDiagnostics().Report(diag::err_fe_invalid_plugin_name) - << CI.getFrontendOpts().ActionName; - return 0; - } - - case PrintDeclContext: return new DeclContextPrintAction(); - case PrintPreprocessedInput: return new PrintPreprocessedAction(); - case RewriteBlocks: return new RewriteBlocksAction(); - case RewriteMacros: return new RewriteMacrosAction(); - case RewriteObjC: return new RewriteObjCAction(); - case RewriteTest: return new RewriteTestAction(); - case RunAnalysis: return new AnalysisAction(); - case RunPreprocessorOnly: return new PreprocessOnlyAction(); - } -} - -static bool ConstructCompilerInvocation(CompilerInvocation &Opts, - Diagnostic &Diags, const char *Argv0) { - // Initialize target options. - InitializeTargetOptions(Opts.getTargetOpts()); - - // Initialize frontend options. - InitializeFrontendOptions(Opts.getFrontendOpts()); - - // Determine the input language, we currently require all files to match. - FrontendOptions::InputKind IK = Opts.getFrontendOpts().Inputs[0].first; - for (unsigned i = 1, e = Opts.getFrontendOpts().Inputs.size(); i != e; ++i) { - if (Opts.getFrontendOpts().Inputs[i].first != IK) { - llvm::errs() << "error: cannot have multiple input files of distinct " - << "language kinds without -x\n"; - return false; - } - } - - // Initialize language options. - // - // FIXME: These aren't used during operations on ASTs. Split onto a separate - // code path to make this obvious. - if (IK != FrontendOptions::IK_AST) - InitializeLangOptions(Opts.getLangOpts(), IK); - - // Initialize the static analyzer options. - InitializeAnalyzerOptions(Opts.getAnalyzerOpts()); - - // Initialize the dependency output options (-M...). - InitializeDependencyOutputOptions(Opts.getDependencyOutputOpts()); - - // Initialize the header search options. - InitializeHeaderSearchOptions(Opts.getHeaderSearchOpts(), - GetBuiltinIncludePath(Argv0)); - - // Initialize the other preprocessor options. - InitializePreprocessorOptions(Opts.getPreprocessorOpts()); - - // Initialize the preprocessed output options. - InitializePreprocessorOutputOptions(Opts.getPreprocessorOutputOpts()); - - // Initialize backend options. - InitializeCodeGenOptions(Opts.getCodeGenOpts(), Opts.getLangOpts()); - - return true; -} - -static int cc1_main(Diagnostic &Diags, - const char **ArgBegin, const char **ArgEnd, - const char *Argv0, void *MainAddr) { - using namespace clang::driver; - - llvm::errs() << "cc1 argv:"; - for (const char **i = ArgBegin; i != ArgEnd; ++i) - llvm::errs() << " \"" << *i << '"'; - llvm::errs() << "\n"; - - // Parse the arguments. - OptTable *Opts = createCC1OptTable(); - unsigned MissingArgIndex, MissingArgCount; - InputArgList *Args = Opts->ParseArgs(ArgBegin, ArgEnd, - MissingArgIndex, MissingArgCount); - - // Check for missing argument error. - if (MissingArgCount) - Diags.Report(clang::diag::err_drv_missing_argument) - << Args->getArgString(MissingArgIndex) << MissingArgCount; - - // Dump the parsed arguments. - llvm::errs() << "cc1 parsed options:\n"; - for (ArgList::const_iterator it = Args->begin(), ie = Args->end(); - it != ie; ++it) - (*it)->dump(); - - // Create a compiler invocation. - llvm::errs() << "cc1 creating invocation.\n"; - CompilerInvocation Invocation; - CompilerInvocation::CreateFromArgs(Invocation, ArgBegin, ArgEnd, - Argv0, MainAddr, Diags); - - // Convert the invocation back to argument strings. - std::vector InvocationArgs; - Invocation.toArgs(InvocationArgs); - - // Dump the converted arguments. - llvm::SmallVector Invocation2Args; - llvm::errs() << "invocation argv :"; - for (unsigned i = 0, e = InvocationArgs.size(); i != e; ++i) { - Invocation2Args.push_back(InvocationArgs[i].c_str()); - llvm::errs() << " \"" << InvocationArgs[i] << '"'; - } - llvm::errs() << "\n"; - - // Convert those arguments to another invocation, and check that we got the - // same thing. - CompilerInvocation Invocation2; - CompilerInvocation::CreateFromArgs(Invocation2, Invocation2Args.begin(), - Invocation2Args.end(), Argv0, MainAddr, - Diags); - - // FIXME: Implement CompilerInvocation comparison. - if (true) { - //llvm::errs() << "warning: Invocations differ!\n"; - - std::vector Invocation2Args; - Invocation2.toArgs(Invocation2Args); - llvm::errs() << "invocation2 argv:"; - for (unsigned i = 0, e = Invocation2Args.size(); i != e; ++i) - llvm::errs() << " \"" << Invocation2Args[i] << '"'; - llvm::errs() << "\n"; - } - - return 0; -} - -int main(int argc, char **argv) { - llvm::sys::PrintStackTraceOnErrorSignal(); - llvm::PrettyStackTraceProgram X(argc, argv); - CompilerInstance Clang(&llvm::getGlobalContext(), false); - - // Run clang -cc1 test. - if (argc > 1 && llvm::StringRef(argv[1]) == "-cc1") { - TextDiagnosticPrinter DiagClient(llvm::errs(), DiagnosticOptions()); - Diagnostic Diags(&DiagClient); - return cc1_main(Diags, (const char**) argv + 2, (const char**) argv + argc, - argv[0], (void*) (intptr_t) GetBuiltinIncludePath); - } - - // Initialize targets first, so that --version shows registered targets. - llvm::InitializeAllTargets(); - llvm::InitializeAllAsmPrinters(); - -#if 1 - llvm::cl::ParseCommandLineOptions(argc, argv, - "LLVM 'Clang' Compiler: http://clang.llvm.org\n"); - - // Construct the diagnostic engine first, so that we can build a diagnostic - // client to use for any errors during option handling. - InitializeDiagnosticOptions(Clang.getDiagnosticOpts()); - Clang.createDiagnostics(argc, argv); - if (!Clang.hasDiagnostics()) - return 1; - - // Set an error handler, so that any LLVM backend diagnostics go through our - // error handler. - llvm::llvm_install_error_handler(LLVMErrorHandler, - static_cast(&Clang.getDiagnostics())); - - // Now that we have initialized the diagnostics engine, create the target and - // the compiler invocation object. - // - // FIXME: We should move .ast inputs to taking a separate path, they are - // really quite different. - if (!ConstructCompilerInvocation(Clang.getInvocation(), - Clang.getDiagnostics(), argv[0])) - return 1; -#else - // Buffer diagnostics from argument parsing. - TextDiagnosticBuffer DiagsBuffer; - Diagnostic Diags(&DiagsBuffer); - - CompilerInvocation::CreateFromArgs(Clang.getInvocation(), - (const char**) argv + 1, - (const char**) argv + argc, argv[0], - (void*)(intptr_t) GetBuiltinIncludePath, - Diags); - - // Create the actual diagnostics engine. - Clang.createDiagnostics(argc, argv); - if (!Clang.hasDiagnostics()) - return 1; - - // Set an error handler, so that any LLVM backend diagnostics go through our - // error handler. - llvm::llvm_install_error_handler(LLVMErrorHandler, - static_cast(&Clang.getDiagnostics())); - - DiagsBuffer.FlushDiagnostics(Clang.getDiagnostics()); - - // If there were any errors in processing arguments, exit now. - if (Clang.getDiagnostics().getNumErrors()) - return 1; -#endif - - // Create the target instance. - Clang.setTarget(TargetInfo::CreateTargetInfo(Clang.getDiagnostics(), - Clang.getTargetOpts())); - if (!Clang.hasTarget()) - return 1; - - // Inform the target of the language options - // - // FIXME: We shouldn't need to do this, the target should be immutable once - // created. This complexity should be lifted elsewhere. - Clang.getTarget().setForcedLangOptions(Clang.getLangOpts()); - - // Validate/process some options - if (Clang.getHeaderSearchOpts().Verbose) - llvm::errs() << "clang-cc version " CLANG_VERSION_STRING - << " based upon " << PACKAGE_STRING - << " hosted on " << llvm::sys::getHostTriple() << "\n"; - - if (Clang.getFrontendOpts().ShowTimers) - Clang.createFrontendTimer(); - - for (unsigned i = 0, e = Clang.getFrontendOpts().Inputs.size(); i != e; ++i) { - const std::string &InFile = Clang.getFrontendOpts().Inputs[i].second; - - // If we aren't using an AST file, setup the file and source managers and - // the preprocessor. - bool IsAST = - Clang.getFrontendOpts().Inputs[i].first == FrontendOptions::IK_AST; - if (!IsAST) { - if (!i) { - // Create a file manager object to provide access to and cache the - // filesystem. - Clang.createFileManager(); - - // Create the source manager. - Clang.createSourceManager(); - } else { - // Reset the ID tables if we are reusing the SourceManager. - Clang.getSourceManager().clearIDTables(); - } - - // Create the preprocessor. - Clang.createPreprocessor(); - } - - llvm::OwningPtr Act(CreateFrontendAction(Clang)); - if (!Act) - break; - - if (Act->BeginSourceFile(Clang, InFile, IsAST)) { - Act->Execute(); - Act->EndSourceFile(); - } - } - - if (Clang.getDiagnosticOpts().ShowCarets) - if (unsigned NumDiagnostics = Clang.getDiagnostics().getNumDiagnostics()) - fprintf(stderr, "%d diagnostic%s generated.\n", NumDiagnostics, - (NumDiagnostics == 1 ? "" : "s")); - - if (Clang.getFrontendOpts().ShowStats) { - Clang.getFileManager().PrintStats(); - fprintf(stderr, "\n"); - } - - // Return the appropriate status when verifying diagnostics. - // - // FIXME: If we could make getNumErrors() do the right thing, we wouldn't need - // this. - if (Clang.getDiagnosticOpts().VerifyDiagnostics) - return static_cast( - Clang.getDiagnosticClient()).HadErrors(); - - // Managed static deconstruction. Useful for making things like - // -time-passes usable. - llvm::llvm_shutdown(); - - return (Clang.getDiagnostics().getNumErrors() != 0); -} - diff --git a/tools/driver/CMakeLists.txt b/tools/driver/CMakeLists.txt index 790021181839..0815554521f0 100644 --- a/tools/driver/CMakeLists.txt +++ b/tools/driver/CMakeLists.txt @@ -2,18 +2,31 @@ set(LLVM_NO_RTTI 1) set( LLVM_USED_LIBS clangDriver + clangFrontend + clangCodeGen + clangAnalysis + clangRewrite + clangSema + clangAST + clangParse + clangLex clangBasic ) -set(LLVM_LINK_COMPONENTS system support bitreader bitwriter) +set( LLVM_LINK_COMPONENTS + ${LLVM_TARGETS_TO_BUILD} + bitreader + bitwriter + codegen + ipo + selectiondag + ) add_clang_executable(clang driver.cpp cc1_main.cpp ) -add_dependencies(clang clang-cc) - if(UNIX) set(CLANGXX_LINK_OR_COPY create_symlink) else() diff --git a/tools/driver/Makefile b/tools/driver/Makefile index f250651ed7e2..7dab2ac92378 100644 --- a/tools/driver/Makefile +++ b/tools/driver/Makefile @@ -1,10 +1,10 @@ ##===- tools/driver/Makefile -------------------------------*- Makefile -*-===## -# +# # The LLVM Compiler Infrastructure # # This file is distributed under the University of Illinois Open Source # License. See LICENSE.TXT for details. -# +# ##===----------------------------------------------------------------------===## LEVEL = ../../../.. @@ -13,15 +13,20 @@ TOOLALIAS = clang++ CPPFLAGS += -I$(PROJ_SRC_DIR)/../../include -I$(PROJ_OBJ_DIR)/../../include CXXFLAGS = -fno-rtti -# This tool has no plugins, optimize startup time. +# Clang tool has no plugins, optimize startup time. TOOL_NO_EXPORTS = 1 -# FIXME: It is unfortunate we need to pull in the bitcode reader and -# writer just to get the serializer stuff used by clangBasic. -LINK_COMPONENTS := system support bitreader bitwriter -USEDLIBS = clangDriver.a clangBasic.a +# Include this here so we can get the configuration of the targets that have +# been configured for construction. We have to do this early so we can set up +# LINK_COMPONENTS before including Makefile.rules +include $(LEVEL)/Makefile.config -include $(LEVEL)/Makefile.common +LINK_COMPONENTS := $(TARGETS_TO_BUILD) bitreader bitwriter codegen ipo selectiondag +USEDLIBS = clangFrontend.a clangDriver.a clangCodeGen.a clangAnalysis.a \ + clangRewrite.a clangSema.a clangAST.a clangParse.a \ + clangLex.a clangBasic.a + +include $(LLVM_SRC_ROOT)/Makefile.rules # Translate make variable to define when building a "production" clang. ifdef CLANG_IS_PRODUCTION diff --git a/tools/driver/cc1_main.cpp b/tools/driver/cc1_main.cpp index a9d27efb1c3b..6e82c51d3876 100644 --- a/tools/driver/cc1_main.cpp +++ b/tools/driver/cc1_main.cpp @@ -7,18 +7,331 @@ // //===----------------------------------------------------------------------===// // -// This is the entry point to the clang -cc1 functionality. +// This is the entry point to the clang -cc1 functionality, which implements the +// core compiler functionality along with a number of additional tools for +// demonstration and testing purposes. // //===----------------------------------------------------------------------===// +#include "clang/Basic/Diagnostic.h" +#include "clang/Basic/FileManager.h" +#include "clang/Basic/SourceManager.h" +#include "clang/Basic/TargetInfo.h" +#include "clang/Basic/Version.h" +#include "clang/Driver/Arg.h" +#include "clang/Driver/ArgList.h" +#include "clang/Driver/CC1Options.h" +#include "clang/Driver/DriverDiagnostic.h" +#include "clang/Driver/OptTable.h" +#include "clang/Frontend/CompilerInstance.h" +#include "clang/Frontend/CompilerInvocation.h" +#include "clang/Frontend/FrontendActions.h" +#include "clang/Frontend/FrontendDiagnostic.h" +#include "clang/Frontend/FrontendPluginRegistry.h" +#include "clang/Frontend/TextDiagnosticBuffer.h" +#include "clang/Frontend/TextDiagnosticPrinter.h" +#include "clang/Frontend/VerifyDiagnosticsClient.h" +#include "llvm/LLVMContext.h" +#include "llvm/ADT/OwningPtr.h" +#include "llvm/Support/ErrorHandling.h" +#include "llvm/Support/ManagedStatic.h" +#include "llvm/Support/PrettyStackTrace.h" #include "llvm/Support/raw_ostream.h" +#include "llvm/System/DynamicLibrary.h" +#include "llvm/System/Host.h" +#include "llvm/System/Path.h" +#include "llvm/System/Signals.h" +#include "llvm/Target/TargetSelect.h" +#include +using namespace clang; + +//===----------------------------------------------------------------------===// +// Main driver +//===----------------------------------------------------------------------===// + +void LLVMErrorHandler(void *UserData, const std::string &Message) { + Diagnostic &Diags = *static_cast(UserData); + + Diags.Report(diag::err_fe_error_backend) << Message; + + // We cannot recover from llvm errors. + exit(1); +} + +static FrontendAction *CreateFrontendAction(CompilerInstance &CI) { + using namespace clang::frontend; + + switch (CI.getFrontendOpts().ProgramAction) { + default: + llvm_unreachable("Invalid program action!"); + + case ASTDump: return new ASTDumpAction(); + case ASTPrint: return new ASTPrintAction(); + case ASTPrintXML: return new ASTPrintXMLAction(); + case ASTView: return new ASTViewAction(); + case DumpRawTokens: return new DumpRawTokensAction(); + case DumpRecordLayouts: return new DumpRecordAction(); + case DumpTokens: return new DumpTokensAction(); + case EmitAssembly: return new EmitAssemblyAction(); + case EmitBC: return new EmitBCAction(); + case EmitHTML: return new HTMLPrintAction(); + case EmitLLVM: return new EmitLLVMAction(); + case EmitLLVMOnly: return new EmitLLVMOnlyAction(); + case FixIt: return new FixItAction(); + case GeneratePCH: return new GeneratePCHAction(); + case GeneratePTH: return new GeneratePTHAction(); + case InheritanceView: return new InheritanceViewAction(); + case ParseNoop: return new ParseOnlyAction(); + case ParsePrintCallbacks: return new PrintParseAction(); + case ParseSyntaxOnly: return new SyntaxOnlyAction(); + + case PluginAction: { + if (CI.getFrontendOpts().ActionName == "help") { + llvm::errs() << "clang -cc1 plugins:\n"; + for (FrontendPluginRegistry::iterator it = + FrontendPluginRegistry::begin(), + ie = FrontendPluginRegistry::end(); + it != ie; ++it) + llvm::errs() << " " << it->getName() << " - " << it->getDesc() << "\n"; + return 0; + } + + for (FrontendPluginRegistry::iterator it = + FrontendPluginRegistry::begin(), ie = FrontendPluginRegistry::end(); + it != ie; ++it) { + if (it->getName() == CI.getFrontendOpts().ActionName) + return it->instantiate(); + } + + CI.getDiagnostics().Report(diag::err_fe_invalid_plugin_name) + << CI.getFrontendOpts().ActionName; + return 0; + } + + case PrintDeclContext: return new DeclContextPrintAction(); + case PrintPreprocessedInput: return new PrintPreprocessedAction(); + case RewriteBlocks: return new RewriteBlocksAction(); + case RewriteMacros: return new RewriteMacrosAction(); + case RewriteObjC: return new RewriteObjCAction(); + case RewriteTest: return new RewriteTestAction(); + case RunAnalysis: return new AnalysisAction(); + case RunPreprocessorOnly: return new PreprocessOnlyAction(); + } +} + +// FIXME: Define the need for this testing away. +static int cc1_test(Diagnostic &Diags, + const char **ArgBegin, const char **ArgEnd) { + using namespace clang::driver; -int cc1_main(const char **ArgBegin, const char **ArgEnd, - const char *Argv0, void *MainAddr) { llvm::errs() << "cc1 argv:"; for (const char **i = ArgBegin; i != ArgEnd; ++i) llvm::errs() << " \"" << *i << '"'; llvm::errs() << "\n"; + // Parse the arguments. + OptTable *Opts = createCC1OptTable(); + unsigned MissingArgIndex, MissingArgCount; + InputArgList *Args = Opts->ParseArgs(ArgBegin, ArgEnd, + MissingArgIndex, MissingArgCount); + + // Check for missing argument error. + if (MissingArgCount) + Diags.Report(clang::diag::err_drv_missing_argument) + << Args->getArgString(MissingArgIndex) << MissingArgCount; + + // Dump the parsed arguments. + llvm::errs() << "cc1 parsed options:\n"; + for (ArgList::const_iterator it = Args->begin(), ie = Args->end(); + it != ie; ++it) + (*it)->dump(); + + // Create a compiler invocation. + llvm::errs() << "cc1 creating invocation.\n"; + CompilerInvocation Invocation; + CompilerInvocation::CreateFromArgs(Invocation, ArgBegin, ArgEnd, Diags); + + // Convert the invocation back to argument strings. + std::vector InvocationArgs; + Invocation.toArgs(InvocationArgs); + + // Dump the converted arguments. + llvm::SmallVector Invocation2Args; + llvm::errs() << "invocation argv :"; + for (unsigned i = 0, e = InvocationArgs.size(); i != e; ++i) { + Invocation2Args.push_back(InvocationArgs[i].c_str()); + llvm::errs() << " \"" << InvocationArgs[i] << '"'; + } + llvm::errs() << "\n"; + + // Convert those arguments to another invocation, and check that we got the + // same thing. + CompilerInvocation Invocation2; + CompilerInvocation::CreateFromArgs(Invocation2, Invocation2Args.begin(), + Invocation2Args.end(), Diags); + + // FIXME: Implement CompilerInvocation comparison. + if (true) { + //llvm::errs() << "warning: Invocations differ!\n"; + + std::vector Invocation2Args; + Invocation2.toArgs(Invocation2Args); + llvm::errs() << "invocation2 argv:"; + for (unsigned i = 0, e = Invocation2Args.size(); i != e; ++i) + llvm::errs() << " \"" << Invocation2Args[i] << '"'; + llvm::errs() << "\n"; + } + return 0; } + +int cc1_main(const char **ArgBegin, const char **ArgEnd, + const char *Argv0, void *MainAddr) { + llvm::sys::PrintStackTraceOnErrorSignal(); + llvm::PrettyStackTraceProgram X(ArgBegin - ArgEnd, ArgBegin); + CompilerInstance Clang(&llvm::getGlobalContext(), false); + + // Run clang -cc1 test. + if (ArgBegin != ArgEnd && llvm::StringRef(ArgBegin[0]) == "-cc1test") { + TextDiagnosticPrinter DiagClient(llvm::errs(), DiagnosticOptions()); + Diagnostic Diags(&DiagClient); + return cc1_test(Diags, ArgBegin + 1, ArgEnd); + } + + // Initialize targets first, so that --version shows registered targets. + llvm::InitializeAllTargets(); + llvm::InitializeAllAsmPrinters(); + + // Buffer diagnostics from argument parsing so that we can output them using a + // well formed diagnostic object. + TextDiagnosticBuffer DiagsBuffer; + Diagnostic Diags(&DiagsBuffer); + CompilerInvocation::CreateFromArgs(Clang.getInvocation(), ArgBegin, ArgEnd, + Diags); + + // Infer the builtin include path if unspecified. + if (Clang.getInvocation().getHeaderSearchOpts().UseBuiltinIncludes && + Clang.getInvocation().getHeaderSearchOpts().ResourceDir.empty()) + Clang.getInvocation().getHeaderSearchOpts().ResourceDir = + CompilerInvocation::GetResourcesPath(Argv0, MainAddr); + + // Honor -help. + if (Clang.getInvocation().getFrontendOpts().ShowHelp) { + llvm::OwningPtr Opts(driver::createCC1OptTable()); + Opts->PrintHelp(llvm::outs(), "clang -cc1", + "LLVM 'Clang' Compiler: http://clang.llvm.org"); + return 0; + } + + // Honor -version. + // + // FIXME: Use a better -version message? + if (Clang.getInvocation().getFrontendOpts().ShowVersion) { + llvm::cl::PrintVersionMessage(); + return 0; + } + + // Create the actual diagnostics engine. + Clang.createDiagnostics(ArgEnd - ArgBegin, const_cast(ArgBegin)); + if (!Clang.hasDiagnostics()) + return 1; + + // Set an error handler, so that any LLVM backend diagnostics go through our + // error handler. + llvm::llvm_install_error_handler(LLVMErrorHandler, + static_cast(&Clang.getDiagnostics())); + + DiagsBuffer.FlushDiagnostics(Clang.getDiagnostics()); + + // Load any requested plugins. + for (unsigned i = 0, + e = Clang.getFrontendOpts().Plugins.size(); i != e; ++i) { + const std::string &Path = Clang.getFrontendOpts().Plugins[i]; + std::string Error; + if (llvm::sys::DynamicLibrary::LoadLibraryPermanently(Path.c_str(), &Error)) + Diags.Report(diag::err_fe_unable_to_load_plugin) << Path << Error; + } + + // If there were any errors in processing arguments, exit now. + if (Clang.getDiagnostics().getNumErrors()) + return 1; + + // Create the target instance. + Clang.setTarget(TargetInfo::CreateTargetInfo(Clang.getDiagnostics(), + Clang.getTargetOpts())); + if (!Clang.hasTarget()) + return 1; + + // Inform the target of the language options + // + // FIXME: We shouldn't need to do this, the target should be immutable once + // created. This complexity should be lifted elsewhere. + Clang.getTarget().setForcedLangOptions(Clang.getLangOpts()); + + // Validate/process some options + if (Clang.getHeaderSearchOpts().Verbose) + llvm::errs() << "clang -cc1 version " CLANG_VERSION_STRING + << " based upon " << PACKAGE_STRING + << " hosted on " << llvm::sys::getHostTriple() << "\n"; + + if (Clang.getFrontendOpts().ShowTimers) + Clang.createFrontendTimer(); + + for (unsigned i = 0, e = Clang.getFrontendOpts().Inputs.size(); i != e; ++i) { + const std::string &InFile = Clang.getFrontendOpts().Inputs[i].second; + + // If we aren't using an AST file, setup the file and source managers and + // the preprocessor. + bool IsAST = + Clang.getFrontendOpts().Inputs[i].first == FrontendOptions::IK_AST; + if (!IsAST) { + if (!i) { + // Create a file manager object to provide access to and cache the + // filesystem. + Clang.createFileManager(); + + // Create the source manager. + Clang.createSourceManager(); + } else { + // Reset the ID tables if we are reusing the SourceManager. + Clang.getSourceManager().clearIDTables(); + } + + // Create the preprocessor. + Clang.createPreprocessor(); + } + + llvm::OwningPtr Act(CreateFrontendAction(Clang)); + if (!Act) + break; + + if (Act->BeginSourceFile(Clang, InFile, IsAST)) { + Act->Execute(); + Act->EndSourceFile(); + } + } + + if (Clang.getDiagnosticOpts().ShowCarets) + if (unsigned NumDiagnostics = Clang.getDiagnostics().getNumDiagnostics()) + fprintf(stderr, "%d diagnostic%s generated.\n", NumDiagnostics, + (NumDiagnostics == 1 ? "" : "s")); + + if (Clang.getFrontendOpts().ShowStats) { + Clang.getFileManager().PrintStats(); + fprintf(stderr, "\n"); + } + + // Return the appropriate status when verifying diagnostics. + // + // FIXME: If we could make getNumErrors() do the right thing, we wouldn't need + // this. + if (Clang.getDiagnosticOpts().VerifyDiagnostics) + return static_cast( + Clang.getDiagnosticClient()).HadErrors(); + + // Managed static deconstruction. Useful for making things like + // -time-passes usable. + llvm::llvm_shutdown(); + + return (Clang.getDiagnostics().getNumErrors() != 0); +} diff --git a/tools/driver/driver.cpp b/tools/driver/driver.cpp index c61ee726449f..cfdd9c342acb 100644 --- a/tools/driver/driver.cpp +++ b/tools/driver/driver.cpp @@ -60,7 +60,10 @@ void DriverDiagnosticPrinter::HandleDiagnostic(Diagnostic::Level Level, OS << '\n'; } -llvm::sys::Path GetExecutablePath(const char *Argv0) { +llvm::sys::Path GetExecutablePath(const char *Argv0, bool CanonicalPrefixes) { + if (!CanonicalPrefixes) + return llvm::sys::Path(Argv0); + // This just needs to be some symbol in the binary; C++ doesn't // allow taking the address of ::main however. void *P = (void*) (intptr_t) GetExecutablePath; @@ -190,7 +193,16 @@ int main(int argc, const char **argv) { return cc1_main(argv+2, argv+argc, argv[0], (void*) (intptr_t) GetExecutablePath); - llvm::sys::Path Path = GetExecutablePath(argv[0]); + bool CanonicalPrefixes = true; + for (int i = 1; i < argc; ++i) { + if (llvm::StringRef(argv[i]) == "-no-canonical-prefixes") { + CanonicalPrefixes = false; + break; + } + } + + llvm::sys::Path Path = GetExecutablePath(argv[0], CanonicalPrefixes); + DriverDiagnosticPrinter DiagClient(Path.getBasename(), llvm::errs()); Diagnostic Diags(&DiagClient); @@ -200,8 +212,8 @@ int main(int argc, const char **argv) { #else bool IsProduction = false; #endif - Driver TheDriver(Path.getBasename().c_str(), Path.getDirname().c_str(), - llvm::sys::getHostTriple().c_str(), + Driver TheDriver(Path.getBasename(), Path.getDirname(), + llvm::sys::getHostTriple(), "a.out", IsProduction, Diags); // Check for ".*++" or ".*++-[^-]*" to determine if we are a C++ @@ -264,4 +276,3 @@ int main(int argc, const char **argv) { return Res; } - diff --git a/tools/index-test/CMakeLists.txt b/tools/index-test/CMakeLists.txt index 163afc4ac9f5..9472e580fbc5 100644 --- a/tools/index-test/CMakeLists.txt +++ b/tools/index-test/CMakeLists.txt @@ -3,8 +3,9 @@ set(LLVM_NO_RTTI 1) set( LLVM_USED_LIBS clangIndex clangFrontend - clangAnalysis + clangDriver clangSema + clangAnalysis clangAST clangParse clangLex @@ -14,6 +15,7 @@ set( LLVM_USED_LIBS set( LLVM_LINK_COMPONENTS bitreader mc + core ) add_clang_executable(index-test diff --git a/tools/index-test/Makefile b/tools/index-test/Makefile index 8e7bfe554009..4ee98fc7cc99 100644 --- a/tools/index-test/Makefile +++ b/tools/index-test/Makefile @@ -18,8 +18,8 @@ TOOL_NO_EXPORTS = 1 include $(LEVEL)/Makefile.config -LINK_COMPONENTS := bitreader mc -USEDLIBS = clangIndex.a clangFrontend.a clangDriver.a clangAnalysis.a clangSema.a \ - clangAST.a clangParse.a clangLex.a clangBasic.a +LINK_COMPONENTS := bitreader mc core +USEDLIBS = clangIndex.a clangFrontend.a clangDriver.a clangSema.a \ + clangAnalysis.a clangAST.a clangParse.a clangLex.a clangBasic.a include $(LLVM_SRC_ROOT)/Makefile.rules diff --git a/tools/index-test/index-test.cpp b/tools/index-test/index-test.cpp index dd7cbb21642c..ff9fd5431154 100644 --- a/tools/index-test/index-test.cpp +++ b/tools/index-test/index-test.cpp @@ -208,20 +208,26 @@ static void ProcessASTLocation(ASTLocation ASTLoc, Indexer &Idxer) { static llvm::cl::opt ASTFromSource("ast-from-source", - llvm::cl::desc("Treat the inputs as source files to parse.")); + llvm::cl::desc("Treat the inputs as source files to parse")); + +static llvm::cl::list +CompilerArgs("arg", llvm::cl::desc("Extra arguments to use during parsing")); static llvm::cl::list InputFilenames(llvm::cl::Positional, llvm::cl::desc("")); -void CreateCompilerInvocation(const std::string &Filename, - CompilerInvocation &CI, Diagnostic &Diags, - const char *argv0) { +ASTUnit *CreateFromSource(const std::string &Filename, Diagnostic &Diags, + const char *Argv0) { llvm::SmallVector Args; Args.push_back(Filename.c_str()); + for (unsigned i = 0, e = CompilerArgs.size(); i != e; ++i) + Args.push_back(CompilerArgs[i].c_str()); - void *MainAddr = (void*) (intptr_t) CreateCompilerInvocation; - CompilerInvocation::CreateFromArgs(CI, Args.data(), Args.data() + Args.size(), - argv0, MainAddr, Diags); + void *MainAddr = (void*) (intptr_t) CreateFromSource; + std::string ResourceDir = + CompilerInvocation::GetResourcesPath(Argv0, MainAddr); + return ASTUnit::LoadFromCommandLine(Args.data(), Args.data() + Args.size(), + Diags, ResourceDir); } int main(int argc, char **argv) { @@ -234,9 +240,9 @@ int main(int argc, char **argv) { Indexer Idxer(Prog); llvm::SmallVector TUnits; - TextDiagnosticPrinter DiagClient(llvm::errs(), DiagnosticOptions(), false); + DiagnosticOptions DiagOpts; llvm::OwningPtr Diags( - CompilerInstance::createDiagnostics(DiagnosticOptions(), argc, argv)); + CompilerInstance::createDiagnostics(DiagOpts, argc, argv)); // If no input was specified, read from stdin. if (InputFilenames.empty()) @@ -244,23 +250,13 @@ int main(int argc, char **argv) { for (unsigned i = 0, e = InputFilenames.size(); i != e; ++i) { const std::string &InFile = InputFilenames[i]; - - std::string ErrMsg; llvm::OwningPtr AST; - - if (ASTFromSource) { - CompilerInvocation CI; - CreateCompilerInvocation(InFile, CI, *Diags, argv[0]); - AST.reset(ASTUnit::LoadFromCompilerInvocation(CI, *Diags)); - if (!AST) - ErrMsg = "unable to create AST"; - } else - AST.reset(ASTUnit::LoadFromPCHFile(InFile, &ErrMsg)); - - if (!AST) { - llvm::errs() << "[" << InFile << "] Error: " << ErrMsg << '\n'; + if (ASTFromSource) + AST.reset(CreateFromSource(InFile, *Diags, argv[0])); + else + AST.reset(ASTUnit::LoadFromPCHFile(InFile, *Diags)); + if (!AST) return 1; - } TUnit *TU = new TUnit(AST.take(), InFile); TUnits.push_back(TU); diff --git a/tools/scan-build/ccc-analyzer b/tools/scan-build/ccc-analyzer index 25b980057408..aca411f67ae8 100755 --- a/tools/scan-build/ccc-analyzer +++ b/tools/scan-build/ccc-analyzer @@ -14,14 +14,38 @@ use strict; use warnings; +use FindBin; use Cwd qw/ getcwd abs_path /; use File::Temp qw/ tempfile /; use File::Path qw / mkpath /; use File::Basename; use Text::ParseWords; -my $CC = $ENV{'CCC_CC'}; -if (!defined $CC) { $CC = "gcc"; } +##===----------------------------------------------------------------------===## +# Compiler command setup. +##===----------------------------------------------------------------------===## + +my $Compiler; +my $Clang; + +if ($FindBin::Script =~ /c\+\+-analyzer/) { + $Compiler = $ENV{'CCC_CXX'}; + if (!defined $Compiler) { $Compiler = "g++"; } + + $Clang = $ENV{'CLANG_CXX'}; + if (!defined $Clang) { $Clang = 'clang++'; } +} +else { + $Compiler = $ENV{'CCC_CC'}; + if (!defined $Compiler) { $Compiler = "gcc"; } + + $Clang = $ENV{'CLANG'}; + if (!defined $Clang) { $Clang = 'clang'; } +} + +##===----------------------------------------------------------------------===## +# Cleanup. +##===----------------------------------------------------------------------===## my $ReportFailures = $ENV{'CCC_REPORT_FAILURES'}; if (!defined $ReportFailures) { $ReportFailures = 1; } @@ -53,7 +77,7 @@ my $ParserRejects = "Parser Rejects"; my $AttributeIgnored = "Attribute Ignored"; sub ProcessClangFailure { - my ($ClangCC, $Lang, $file, $Args, $HtmlDir, $ErrorType, $ofile) = @_; + my ($Clang, $Lang, $file, $Args, $HtmlDir, $ErrorType, $ofile) = @_; my $Dir = "$HtmlDir/failures"; mkpath $Dir; @@ -69,7 +93,7 @@ sub ProcessClangFailure { my ($PPH, $PPFile) = tempfile( $prefix . "_XXXXXX", SUFFIX => GetPPExt($Lang), DIR => $Dir); - system $ClangCC, @$Args, "-E", "-o", $PPFile; + system $Clang, @$Args, "-E", "-o", $PPFile; close ($PPH); # Create the info file. @@ -79,7 +103,7 @@ sub ProcessClangFailure { print OUT "@$Args\n"; close OUT; `uname -a >> $PPFile.info.txt 2>&1`; - `$CC -v >> $PPFile.info.txt 2>&1`; + `$Compiler -v >> $PPFile.info.txt 2>&1`; system 'mv',$ofile,"$PPFile.stderr.txt"; return (basename $PPFile); } @@ -88,10 +112,6 @@ sub ProcessClangFailure { # Running the analyzer. ##----------------------------------------------------------------------------## -# Determine what clang executable to use. -my $Clang = $ENV{'CLANG'}; -if (!defined $Clang) { $Clang = 'clang'; } - sub GetCCArgs { my $Args = shift; @@ -106,14 +126,14 @@ sub GetCCArgs { close(TO_PARENT); my $line; while () { - next if (!/clang-cc/); + next if (!/-cc1/); $line = $_; } waitpid($pid,0); close(FROM_CHILD); - die "could not find clang-cc line\n" if (!defined $line); + die "could not find clang line\n" if (!defined $line); # Strip the newline and initial whitspace chomp $line; $line =~ s/^\s+//; @@ -124,19 +144,16 @@ sub GetCCArgs { $items[$i] =~ s/\"$//; } my $cmd = shift @items; - die "cannot find 'clang-cc' in 'clang' command\n" if (!($cmd =~ /clang-cc/)); + die "cannot find 'clang' in 'clang' command\n" if (!($cmd =~ /clang/)); return \@items; } sub Analyze { - my ($ClangCC, $Args, $AnalyzeArgs, $Lang, $Output, $Verbose, $HtmlDir, + my ($Clang, $Args, $AnalyzeArgs, $Lang, $Output, $Verbose, $HtmlDir, $file, $Analyses) = @_; $Args = GetCCArgs($Args); - # Skip anything related to C++. - return if ($Lang =~ /c[+][+]/); - my $RunAnalyzer = 0; my $Cmd; my @CmdArgs; @@ -152,13 +169,15 @@ sub Analyze { @CmdArgsSansAnalyses = @CmdArgs; } else { - $Cmd = $ClangCC; + $Cmd = $Clang; + push @CmdArgs, "-cc1"; push @CmdArgs,'-DIBOutlet=__attribute__((iboutlet))'; - push @CmdArgs,@$Args; + push @CmdArgs, @$Args; @CmdArgsSansAnalyses = @CmdArgs; push @CmdArgs,'-analyze'; push @CmdArgs,"-analyzer-display-progress"; push @CmdArgs,"-analyzer-eagerly-assume"; + push @CmdArgs,"-analyzer-opt-analyze-nested-blocks"; push @CmdArgs,(split /\s/,$Analyses); if (defined $ENV{"CCC_EXPERIMENTAL_CHECKS"}) { @@ -236,13 +255,13 @@ sub Analyze { # Did the command die because of a signal? if ($ReportFailures) { - if ($Result & 127 and $Cmd eq $ClangCC and defined $HtmlDir) { - ProcessClangFailure($ClangCC, $Lang, $file, \@CmdArgsSansAnalyses, + if ($Result & 127 and $Cmd eq $Clang and defined $HtmlDir) { + ProcessClangFailure($Clang, $Lang, $file, \@CmdArgsSansAnalyses, $HtmlDir, "Crash", $ofile); } elsif ($Result) { if ($IncludeParserRejects && !($file =~/conftest/)) { - ProcessClangFailure($ClangCC, $Lang, $file, \@CmdArgsSansAnalyses, + ProcessClangFailure($Clang, $Lang, $file, \@CmdArgsSansAnalyses, $HtmlDir, $ParserRejects, $ofile); } } @@ -274,7 +293,7 @@ sub Analyze { # Add this file to the list of files that contained this attribute. # Generate a preprocessed file if we haven't already. if (!(defined $ppfile)) { - $ppfile = ProcessClangFailure($ClangCC, $Lang, $file, + $ppfile = ProcessClangFailure($Clang, $Lang, $file, \@CmdArgsSansAnalyses, $HtmlDir, $AttributeIgnored, $ofile); } @@ -359,7 +378,9 @@ my %UniqueOptions = ( my %LangsAccepted = ( "objective-c" => 1, - "c" => 1 + "c" => 1, + "c++" => 1, + "objective-c++" => 1 ); ##----------------------------------------------------------------------------## @@ -375,7 +396,7 @@ my $Output; my %Uniqued; # Forward arguments to gcc. -my $Status = system($CC,@ARGV); +my $Status = system($Compiler,@ARGV); if ($Status) { exit($Status >> 8); } # Get the analysis options. @@ -399,10 +420,6 @@ my $Verbose = 0; if (defined $ENV{CCC_ANALYZER_VERBOSE}) { $Verbose = 1; } if (defined $ENV{CCC_ANALYZER_LOG}) { $Verbose = 2; } -# Determine what clang-cc executable to use. -my $ClangCC = $ENV{'CLANG_CC'}; -if (!defined $ClangCC) { $ClangCC = 'clang-cc'; } - # Get the HTML output directory. my $HtmlDir = $ENV{'CCC_ANALYZER_HTML'}; @@ -617,12 +634,12 @@ if ($Action eq 'compile' or $Action eq 'link') { push @NewArgs, '-arch'; push @NewArgs, $arch; push @NewArgs, @CmdArgs; - Analyze($ClangCC, \@NewArgs, \@AnalyzeArgs, $FileLang, $Output, + Analyze($Clang, \@NewArgs, \@AnalyzeArgs, $FileLang, $Output, $Verbose, $HtmlDir, $file, $Analyses); } } else { - Analyze($ClangCC, \@CmdArgs, \@AnalyzeArgs, $FileLang, $Output, + Analyze($Clang, \@CmdArgs, \@AnalyzeArgs, $FileLang, $Output, $Verbose, $HtmlDir, $file, $Analyses); } } diff --git a/tools/scan-build/scan-build b/tools/scan-build/scan-build index 8d99f070eae9..f978a888be83 100755 --- a/tools/scan-build/scan-build +++ b/tools/scan-build/scan-build @@ -26,7 +26,6 @@ my $Verbose = 0; # Verbose output from this script. my $Prog = "scan-build"; my $BuildName; my $BuildDate; -my $CXX; # Leave undefined initially. my $TERM = $ENV{'TERM'}; my $UseColor = (defined $TERM and $TERM eq 'xterm-color' and -t STDOUT @@ -81,43 +80,26 @@ sub DieDiag { # Some initial preprocessing of Clang options. ##----------------------------------------------------------------------------## -# First, look for 'clang-cc' in libexec. -my $ClangCCSB = Cwd::realpath("$RealBin/libexec/clang-cc"); -# Second, look for 'clang-cc' in the same directory as scan-build. -if (!defined $ClangCCSB || ! -x $ClangCCSB) { - $ClangCCSB = Cwd::realpath("$RealBin/clang-cc"); -} -# Third, look for 'clang-cc' in ../libexec -if (!defined $ClangCCSB || ! -x $ClangCCSB) { - $ClangCCSB = Cwd::realpath("$RealBin/../libexec/clang-cc"); -} -# Finally, default to looking for 'clang-cc' in the path. -if (!defined $ClangCCSB || ! -x $ClangCCSB) { - $ClangCCSB = "clang-cc"; -} -my $ClangCC = $ClangCCSB; - -# Now find 'clang' +# Find 'clang' my $ClangSB = Cwd::realpath("$RealBin/bin/clang"); +my $ClangCXXSB; if (!defined $ClangSB || ! -x $ClangSB) { $ClangSB = Cwd::realpath("$RealBin/clang"); -} -# Third, look for 'clang' in ../bin -if (!defined $ClangSB || ! -x $ClangSB) { - $ClangSB = Cwd::realpath("$RealBin/../bin/clang"); -} -# Finally, default to looking for 'clang-cc' in the path. -if (!defined $ClangSB || ! -x $ClangSB) { - $ClangSB = "clang"; + if (defined $ClangSB) { $ClangCXXSB = $ClangSB . "++"; } } my $Clang = $ClangSB; - +my $ClangCXX = $ClangCXXSB; +# Default to looking for 'clang' in the path. +if (!defined $Clang || ! -x $Clang) { + $Clang = "clang"; + $ClangCXX = "clang++"; +} my %AvailableAnalyses; # Query clang for analysis options. -open(PIPE, "-|", $ClangCC, "--help") or - DieDiag("Cannot execute '$ClangCC'\n"); +open(PIPE, "-|", $Clang, "-cc1", "--help") or + DieDiag("Cannot execute '$Clang'\n"); my $FoundAnalysis = 0; @@ -128,17 +110,14 @@ while() { } next; } - if (/^\s\s\s\s([^\s]+)\s(.+)$/) { next if ($1 =~ /-dump/ or $1 =~ /-view/ - or $1 =~ /-warn-uninit/); - + or $1 =~ /-warn-uninit/); $AvailableAnalyses{$1} = $2; next; } last; } - close (PIPE); my %AnalysesDefaultEnabled = ( @@ -156,10 +135,8 @@ my %AnalysesDefaultEnabled = ( ##----------------------------------------------------------------------------## sub GetHTMLRunDir { - die "Not enough arguments." if (@_ == 0); - my $Dir = shift @_; - + my $Dir = shift @_; my $TmpMode = 0; if (!defined $Dir) { if (`uname` =~ /Darwin/) { @@ -168,8 +145,7 @@ sub GetHTMLRunDir { } else { $Dir = "/tmp"; - } - + } $TmpMode = 1; } @@ -177,42 +153,32 @@ sub GetHTMLRunDir { while ($Dir =~ /\/$/) { chop $Dir; } # Get current date and time. - - my @CurrentTime = localtime(); - + my @CurrentTime = localtime(); my $year = $CurrentTime[5] + 1900; my $day = $CurrentTime[3]; my $month = $CurrentTime[4] + 1; - my $DateString = sprintf("%d-%02d-%02d", $year, $month, $day); - # Determine the run number. - + # Determine the run number. my $RunNumber; - if (-d $Dir) { - + if (-d $Dir) { if (! -r $Dir) { DieDiag("directory '$Dir' exists but is not readable.\n"); - } - - # Iterate over all files in the specified directory. - - my $max = 0; - + } + # Iterate over all files in the specified directory. + my $max = 0; opendir(DIR, $Dir); my @FILES = grep { -d "$Dir/$_" } readdir(DIR); closedir(DIR); - - foreach my $f (@FILES) { + foreach my $f (@FILES) { # Strip the prefix '$Prog-' if we are dumping files to /tmp. if ($TmpMode) { next if (!($f =~ /^$Prog-(.+)/)); $f = $1; } - my @x = split/-/, $f; next if (scalar(@x) != 4); next if ($x[0] != $year); @@ -836,14 +802,26 @@ sub RunBuildCommand { $Cmd =~ /(.*\/?ccc-analyzer[^\/]*$)/) { if (!($Cmd =~ /ccc-analyzer/) and !defined $ENV{"CCC_CC"}) { - $ENV{"CCC_CC"} = $1; + $ENV{"CCC_CC"} = $1; } shift @$Args; unshift @$Args, $CCAnalyzer; } + elsif ($Cmd =~ /(.*\/?g\+\+[^\/]*$)/ or + $Cmd =~ /(.*\/?c\+\+[^\/]*$)/ or + $Cmd =~ /(.*\/?llvm-g\+\+[^\/]*$)/ or + $Cmd =~ /(.*\/?c\+\+-analyzer[^\/]*$)/) { + if (!($Cmd =~ /c\+\+-analyzer/) and !defined $ENV{"CCC_CXX"}) { + $ENV{"CCC_CXX"} = $1; + } + shift @$Args; + unshift @$Args, $CCAnalyzer; + } elsif ($IgnoreErrors) { if ($Cmd eq "make" or $Cmd eq "gmake") { + AddIfNotPresent($Args, "CC=$CCAnalyzer"); + AddIfNotPresent($Args, "CXX=$CCAnalyzer"); AddIfNotPresent($Args,"-k"); AddIfNotPresent($Args,"-i"); } @@ -860,6 +838,7 @@ sub RunBuildCommand { if ($Args->[$i] eq "-sdk" && $i + 1 < scalar(@$Args)) { if (@$Args[$i+1] =~ /^iphonesimulator3/) { $ENV{"CCC_CC"} = "gcc-4.2"; + $ENV{"CCC_CXX"} = "g++-4.2"; } } } @@ -874,10 +853,10 @@ sub RunBuildCommand { # When 'CC' is set, xcodebuild uses it to do all linking, even if we are # linking C++ object files. Set 'LDPLUSPLUS' so that xcodebuild uses 'g++' # when linking such files. - die if (!defined $CXX); - my $LDPLUSPLUS = `which $CXX`; - $LDPLUSPLUS =~ s/\015?\012//; # strip newlines - $ENV{'LDPLUSPLUS'} = $LDPLUSPLUS; + if (!defined $ENV{'CCC_CXX'}) { + $ENV{'CCC_CXX'} = 'g++'; + } + $ENV{'LDPLUSPLUS'} = $ENV{'CCC_CXX'}; } return (system(@$Args) >> 8); @@ -1125,16 +1104,19 @@ while (@ARGV) { if ($arg =~ /^--use-c\+\+(=(.+))?$/) { shift @ARGV; + my $cxx; if (!defined $2 || $2 eq "") { if (!@ARGV) { DieDiag("'--use-c++' option requires a compiler executable name.\n"); } - $CXX = shift @ARGV; + $cxx = shift @ARGV; } else { - $CXX = $2; + $cxx = $2; } + + $ENV{"CCC_CXX"} = $cxx; next; } @@ -1206,32 +1188,28 @@ $HtmlDir = GetHTMLRunDir($HtmlDir); # Set the appropriate environment variables. SetHtmlEnv(\@ARGV, $HtmlDir); -my $Cmd = Cwd::realpath("$RealBin/libexec/ccc-analyzer"); +my $AbsRealBin = Cwd::realpath($RealBin); +my $Cmd = "$AbsRealBin/libexec/ccc-analyzer"; +my $CmdCXX = "$AbsRealBin/libexec/c++-analyzer"; + if (!defined $Cmd || ! -x $Cmd) { - $Cmd = Cwd::realpath("$RealBin/ccc-analyzer"); + $Cmd = "$AbsRealBin/ccc-analyzer"; DieDiag("Executable 'ccc-analyzer' does not exist at '$Cmd'\n") if(! -x $Cmd); } - -if (!defined $ClangCCSB || ! -x $ClangCCSB) { - Diag("'clang-cc' executable not found in '$RealBin/libexec'.\n"); - Diag("Using 'clang-cc' from path.\n"); +if (!defined $CmdCXX || ! -x $CmdCXX) { + $CmdCXX = "$AbsRealBin/c++-analyzer"; + DieDiag("Executable 'c++-analyzer' does not exist at '$CmdCXX'\n") if(! -x $CmdCXX); } + if (!defined $ClangSB || ! -x $ClangSB) { Diag("'clang' executable not found in '$RealBin/bin'.\n"); Diag("Using 'clang' from path.\n"); } -if (defined $CXX) { - $ENV{'CXX'} = $CXX; -} -else { - $CXX = 'g++'; # This variable is used by other parts of scan-build - # that need to know a default C++ compiler to fall back to. -} - $ENV{'CC'} = $Cmd; -$ENV{'CLANG_CC'} = $ClangCC; +$ENV{'CXX'} = $CmdCXX; $ENV{'CLANG'} = $Clang; +$ENV{'CLANG_CXX'} = $ClangCXX; if ($Verbose >= 2) { $ENV{'CCC_ANALYZER_VERBOSE'} = 1; diff --git a/utils/C++Tests/LLVM-Code-Syntax/lit.local.cfg b/utils/C++Tests/LLVM-Code-Syntax/lit.local.cfg index 67bc5aede63d..c90f4f3db488 100644 --- a/utils/C++Tests/LLVM-Code-Syntax/lit.local.cfg +++ b/utils/C++Tests/LLVM-Code-Syntax/lit.local.cfg @@ -10,11 +10,36 @@ def getRoot(config): root = getRoot(config) # testFormat: The test format to use to interpret tests. +target_obj_root = root.llvm_obj_root cxxflags = ['-D__STDC_LIMIT_MACROS', '-D__STDC_CONSTANT_MACROS', - '-Wno-sign-compare', '-I%s/include' % root.llvm_src_root, - '-I%s/include' % root.llvm_obj_root] + '-I%s/include' % root.llvm_obj_root, + '-I%s/lib/Target/Alpha' % root.llvm_src_root, + '-I%s/lib/Target/ARM' % root.llvm_src_root, + '-I%s/lib/Target/Blackfin' % root.llvm_src_root, + '-I%s/lib/Target/CellSPU' % root.llvm_src_root, + '-I%s/lib/Target/Mips' % root.llvm_src_root, + '-I%s/lib/Target/MSP430' % root.llvm_src_root, + '-I%s/lib/Target/PIC16' % root.llvm_src_root, + '-I%s/lib/Target/PowerPC' % root.llvm_src_root, + '-I%s/lib/Target/Sparc' % root.llvm_src_root, + '-I%s/lib/Target/SystemZ' % root.llvm_src_root, + '-I%s/lib/Target/X86' % root.llvm_src_root, + '-I%s/lib/Target/XCore' % root.llvm_src_root, + '-I%s/lib/Target/Alpha' % target_obj_root, + '-I%s/lib/Target/ARM' % target_obj_root, + '-I%s/lib/Target/Blackfin' % target_obj_root, + '-I%s/lib/Target/CellSPU' % target_obj_root, + '-I%s/lib/Target/Mips' % target_obj_root, + '-I%s/lib/Target/MSP430' % target_obj_root, + '-I%s/lib/Target/PIC16' % target_obj_root, + '-I%s/lib/Target/PowerPC' % target_obj_root, + '-I%s/lib/Target/Sparc' % target_obj_root, + '-I%s/lib/Target/SystemZ' % target_obj_root, + '-I%s/lib/Target/X86' % target_obj_root, + '-I%s/lib/Target/XCore' % target_obj_root]; + config.test_format = \ lit.formats.OneCommandPerFileTest(command=[root.clang, '-fsyntax-only'] + cxxflags, diff --git a/utils/C++Tests/LLVM-Syntax/lit.local.cfg b/utils/C++Tests/LLVM-Syntax/lit.local.cfg index b67bb907e26b..cb0e566a7fd7 100644 --- a/utils/C++Tests/LLVM-Syntax/lit.local.cfg +++ b/utils/C++Tests/LLVM-Syntax/lit.local.cfg @@ -12,14 +12,13 @@ root = getRoot(config) # testFormat: The test format to use to interpret tests. config.test_format = lit.formats.SyntaxCheckTest(compiler=root.clang, dir='%s/include/llvm' % root.llvm_src_root, - recursive=False, + recursive=True, pattern='^(.*\\.h|[^.]*)$', extra_cxx_args=['-D__STDC_LIMIT_MACROS', '-D__STDC_CONSTANT_MACROS', - '-Wno-sign-compare', '-Werror', '-I%s/include' % root.llvm_src_root, '-I%s/include' % root.llvm_obj_root]) config.excludes = ['AbstractTypeUser.h', 'DAGISelHeader.h', - 'AIXDataTypesFix.h', 'LinkAllPasses.h', 'Solaris.h'] + 'AIXDataTypesFix.h', 'Solaris.h'] diff --git a/utils/TestUtils/deep-stack.py b/utils/TestUtils/deep-stack.py new file mode 100755 index 000000000000..1750a5fca031 --- /dev/null +++ b/utils/TestUtils/deep-stack.py @@ -0,0 +1,24 @@ +#!/usr/bin/env python + +def pcall(f, N): + if N == 0: + print >>f, ' f(0)' + return + + print >>f, ' f(' + pcall(f, N - 1) + print >>f, ' )' + +def main(): + f = open('t.c','w') + print >>f, 'int f(int n) { return n; }' + print >>f, 'int t() {' + print >>f, ' return' + pcall(f, 10000) + print >>f, ' ;' + print >>f, '}' + +if __name__ == "__main__": + import sys + sys.setrecursionlimit(100000) + main() diff --git a/utils/TestUtils/pch-test.pl b/utils/TestUtils/pch-test.pl new file mode 100755 index 000000000000..e097c5c00c09 --- /dev/null +++ b/utils/TestUtils/pch-test.pl @@ -0,0 +1,61 @@ +#!/usr/bin/perl -w + +# This tiny little script, which should be run from the clang +# directory (with clang in your patch), tries to take each +# compilable Clang test and build a PCH file from that test, then read +# and dump the contents of the PCH file just created. +use POSIX; + +$exitcode = 0; +sub testfiles($$) { + my $suffix = shift; + my $language = shift; + my $passed = 0; + my $failed = 0; + my $skipped = 0; + + @files = `ls test/*/*.$suffix`; + foreach $file (@files) { + chomp($file); + my $code = system("clang- -fsyntax-only -x $language $file > /dev/null 2>&1"); + if ($code == 0) { + print("."); + $code = system("clang -cc1 -emit-pch -x $language -o $file.pch $file > /dev/null 2>&1"); + if ($code == 0) { + $code = system("clang -cc1 -include-pch $file.pch -x $language -ast-dump /dev/null > /dev/null 2>&1"); + if ($code == 0) { + $passed++; + } elsif (($code & 0xFF) == SIGINT) { + exit($exitcode); + } else { + print("\n---Failed to dump AST file for \"$file\"---\n"); + $exitcode = 1; + $failed++; + } + unlink "$file.pch"; + } elsif (($code & 0xFF) == SIGINT) { + exit($exitcode); + } else { + print("\n---Failed to build PCH file for \"$file\"---\n"); + $exitcode = 1; + $failed++; + } + } elsif (($code & 0xFF) == SIGINT) { + exit($exitcode); + } else { + print("x"); + $skipped++; + } + } + + print("\n\n$passed tests passed\n"); + print("$failed tests failed\n"); + print("$skipped tests skipped ('x')\n") +} + +printf("-----Testing precompiled headers for C-----\n"); +testfiles("c", "c"); +printf("\n-----Testing precompiled headers for Objective-C-----\n"); +testfiles("m", "objective-c"); +print("\n"); +exit($exitcode); diff --git a/utils/clang-completion-mode.el b/utils/clang-completion-mode.el index 690fcda4c454..4164eac7ac84 100644 --- a/utils/clang-completion-mode.el +++ b/utils/clang-completion-mode.el @@ -15,7 +15,7 @@ ;; completion based on Clang. It needs your help to make it better! ;; ;; To use the Clang code completion mode, first make sure that the -;; "clang-cc" variable below refers to the "clang-cc" executable, +;; "clang" variable below refers to the "clang" executable, ;; which is typically installed in libexec/. Then, place ;; clang-completion-mode.el somewhere in your Emacs load path. You can ;; add a new load path to Emacs by adding some like the following to @@ -40,21 +40,20 @@ ;; file up to the point where the cursor is located. Therefore, Clang ;; needs all of the various compilation flags (include paths, dialect ;; options, etc.) to provide code-completion results. Currently, these -;; need to be placed into the clang-cc-flags variable in a format -;; acceptable to clang-cc. This is a hack: patches are welcome to +;; need to be placed into the clang-flags variable in a format +;; acceptable to clang. This is a hack: patches are welcome to ;; improve the interface between this Emacs mode and Clang! ;; ;;; Code: -;;; The clang-cc executable -(defcustom clang-cc "clang-cc" - "The location of the clang-cc executable of the Clang compiler. -This executable is typically installed into the libexec subdirectory." +;;; The clang executable +(defcustom clang "clang" + "The location of the Clang compiler executable" :type 'file :group 'clang-completion-mode) -;;; Extra compilation flags to pass to clang-cc. -(defcustom clang-cc-flags "" +;;; Extra compilation flags to pass to clang. +(defcustom clang-flags "" "Extra flags to pass to the Clang executable. This variable will typically contain include paths, e.g., -I~/MyProject." :type 'string @@ -69,7 +68,7 @@ This variable will typically contain include paths, e.g., -I~/MyProject." ;;; The current completion buffer (setq clang-completion-buffer nil) -(setq clang-cc-result-string "") +(setq clang-result-string "") ;;; Compute the current line in the buffer (defun current-line () @@ -89,7 +88,7 @@ This variable will typically contain include paths, e.g., -I~/MyProject." ;; produced. We store all of the results in a string, then the ;; sentinel processes the entire string at once. (defun clang-completion-stash-filter (proc string) - (setq clang-cc-result-string (concat clang-cc-result-string string))) + (setq clang-result-string (concat clang-result-string string))) ;; Filter the given list based on a predicate. (defun filter (condp lst) @@ -102,7 +101,7 @@ This variable will typically contain include paths, e.g., -I~/MyProject." (string-match (concat "COMPLETION: " clang-completion-substring) line))) (defun clang-completion-display (buffer) - (let* ((all-lines (split-string clang-cc-result-string "\n")) + (let* ((all-lines (split-string clang-result-string "\n")) (completion-lines (filter 'is-completion-line all-lines))) (if (consp completion-lines) (progn @@ -125,7 +124,7 @@ This variable will typically contain include paths, e.g., -I~/MyProject." ;; contents of the code-completion buffer with the new code-completion results ;; and ensures that the buffer is visible. (defun clang-completion-sentinel (proc event) - (let* ((all-lines (split-string clang-cc-result-string "\n")) + (let* ((all-lines (split-string clang-result-string "\n")) (completion-lines (filter 'is-completion-line all-lines))) (if (consp completion-lines) (progn @@ -145,8 +144,7 @@ This variable will typically contain include paths, e.g., -I~/MyProject." )))) (defun clang-complete () - (let ((ccstring (concat "-code-completion-at=" - (buffer-file-name) + (let ((ccstring (concat (buffer-file-name) ":" (number-to-string (+ 1 (current-line))) ":" @@ -161,16 +159,18 @@ This variable will typically contain include paths, e.g., -I~/MyProject." (delete-process cc-proc))) (setq clang-completion-substring "") - (setq clang-cc-result-string "") + (setq clang-result-string "") (setq clang-completion-buffer cc-buffer-name) (let ((cc-proc (if (equal clang-completion-prefix-header "") (start-process "Clang Code-Completion" cc-buffer-name - clang-cc "-fsyntax-only" ccstring + clang "-cc1" "-fsyntax-only" + "-code-completion-at" ccstring (buffer-file-name)) (start-process "Clang Code-Completion" cc-buffer-name - clang-cc "-fsyntax-only" ccstring + clang "-cc1" "-fsyntax-only" + "-code-completion-at" ccstring "-include-pch" (concat clang-completion-prefix-header ".pch") (buffer-file-name))))) @@ -252,6 +252,6 @@ This variable will typically contain include paths, e.g., -I~/MyProject." (define-minor-mode clang-completion-mode "Clang code-completion mode" nil - " Clang-CC" + " Clang" clang-completion-mode-map) diff --git a/www/analyzer/installation.html b/www/analyzer/installation.html index 81f45514fc01..d2be711a4860 100644 --- a/www/analyzer/installation.html +++ b/www/analyzer/installation.html @@ -87,13 +87,13 @@ source code.

      -
    • The locations of the clang-cc and clang binaries. +
    • The location of the clang binary.

      For example, if you built a Debug build of LLVM/Clang, the -resultant binaries will be in $(OBJDIR)/Debug (where $(OBJDIR) -is often the same as the root source directory). You can also do -make install to install the LLVM/Clang libaries and binaries to -the installation directory of your choice (specified when you run +resultantclang binary will be in $(OBJDIR)/Debug +(where $(OBJDIR) is often the same as the root source directory). You +can also do make install to install the LLVM/Clang libaries and +binaries to the installation directory of your choice (specified when you run configure).

    • The locations of the scan-build and scan-view diff --git a/www/analyzer/latest_checker.html.incl b/www/analyzer/latest_checker.html.incl index c2238e4aab96..cccedb5a88c0 100644 --- a/www/analyzer/latest_checker.html.incl +++ b/www/analyzer/latest_checker.html.incl @@ -1 +1 @@ -checker-228.tar.bz2 (built November 28, 2009) +checker-232.tar.bz2 (built December 14, 2009) diff --git a/www/get_started.html b/www/get_started.html index b7df928d27a8..f750fa09216c 100644 --- a/www/get_started.html +++ b/www/get_started.html @@ -73,22 +73,12 @@ follows:

  • Try it out (assuming you add llvm/Debug/bin to your path):
    • -
    • clang-cc --help
    • -
    • clang-cc file.c -fsyntax-only (check for correctness)
    • -
    • clang-cc file.c -ast-dump (internal debug dump of ast)
    • -
    • clang-cc file.c -ast-view (set up graphviz - and rebuild llvm first)
    • -
    • clang-cc file.c -emit-llvm (print out unoptimized llvm code)
    • -
    • clang-cc file.c -emit-llvm -o - | llvm-as | opt -std-compile-opts | - llvm-dis (print out optimized llvm code)
    • -
    • clang-cc file.c -emit-llvm -o - | llvm-as | opt -std-compile-opts | llc - > file.s (output native machine code)
    • +
    • clang --help
    • +
    • clang file.c -fsyntax-only (check for correctness)
    • +
    • clang file.c -S -emit-llvm -o - (print out unoptimized llvm code)
    • +
    • clang file.c -S -emit-llvm -o - -O3
    • +
    • clang file.c -S -O3 -o - (output native machine code)
    -

    Note: Here clang-cc is the "low-level" frontend - executable that is similar in purpose to cc1. Clang also has a high-level compiler driver that acts as a drop-in - replacement for gcc.

    Note that the C front-end uses LLVM, but does not depend on llvm-gcc. If you @@ -159,10 +149,8 @@ Visual Studio:

  • Build Clang:
    • Open LLVM.sln in Visual Studio.
    • -
    • Build the "clang-cc" project for just the compiler front end. - Alternatively, build the "clang" project for the compiler driver - (note that the driver is currently broken on Windows), - or the "ALL_BUILD" project to build everything, including tools.
    • +
    • Build the "clang" project for just the compiler driver and front end, or + the "ALL_BUILD" project to build everything, including tools.
  • Try it out (assuming you added llvm/debug/bin to your path). (See the running examples from above.)
  • @@ -175,13 +163,11 @@ Visual Studio:

    to the latest code base, use the svn update command in both the llvm and llvm\tools\clang directories, as they are separate repositories.

    -

    High-Level Compiler Driver (Drop-in Substitute for GCC)

    +

    Clang Compiler Driver (Drop-in Substitute for GCC)

    -

    While the clang-cc executable is a low-level frontend executable -that can perform code generation, program analysis, and other actions, it is not -designed to be a drop-in replacement for GCC's cc. For this purpose, -use the high-level driver, aptly named clang. Here are some -examples of how to use the high-level driver: +

    The clang tool is the compiler driver and front-end, which is +designed to be a drop-in replacement for the gcc command. Here are +some examples of how to use the high-level driver:

    @@ -201,12 +187,6 @@ hello world
     
     

    Examples of using Clang

    -

    The high-level driver clang is designed to understand most of GCC's -options, and the lower-level clang-cc executable also directly takes -many of GCC's options. You can see which options clang-cc accepts with -'clang-cc --help'. Here are a few examples of using clang and -clang-cc:

    -