[cfe-commits] r102031 - in /cfe/trunk: include/clang/Parse/Parser.h lib/Parse/ParseExpr.cpp lib/Parse/ParseExprCXX.cpp lib/Parse/ParseInit.cpp lib/Parse/ParseObjc.cpp test/Parser/objc-init.m test/SemaObjCXX/message.mm

Douglas Gregor dgregor at apple.com
Wed Apr 21 15:36:40 PDT 2010


Author: dgregor
Date: Wed Apr 21 17:36:40 2010
New Revision: 102031

URL: http://llvm.org/viewvc/llvm-project?rev=102031&view=rev
Log:
Implement parsing for message sends in Objective-C++. Message sends in
Objective-C++ have a more complex grammar than in Objective-C
(surprise!), because

  (1) The receiver of an instance message can be a qualified name such
  as ::I or identity<I>::type.
  (2) Expressions in C++ can start with a type.

The receiver grammar isn't actually ambiguous; it just takes a bit of
work to parse past the type before deciding whether we have a type or
expression. We do this in two places within the grammar: once for
message sends and once when we're determining whether a []'d clause in
an initializer list is a message send or a C99 designated initializer.

This implementation of Objective-C++ message sends contains one known
extension beyond GCC's implementation, which is to permit a
typename-specifier as the receiver type for a class message, e.g.,

  [typename compute_receiver_type<T>::type method];

Note that the same effect can be achieved in GCC by way of a typedef,
e.g.,

  typedef typename computed_receiver_type<T>::type Computed;
  [Computed method];

so this is merely a convenience.

Note also that message sends still cannot involve dependent types or
values.


Modified:
    cfe/trunk/include/clang/Parse/Parser.h
    cfe/trunk/lib/Parse/ParseExpr.cpp
    cfe/trunk/lib/Parse/ParseExprCXX.cpp
    cfe/trunk/lib/Parse/ParseInit.cpp
    cfe/trunk/lib/Parse/ParseObjc.cpp
    cfe/trunk/test/Parser/objc-init.m
    cfe/trunk/test/SemaObjCXX/message.mm

Modified: cfe/trunk/include/clang/Parse/Parser.h
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/include/clang/Parse/Parser.h?rev=102031&r1=102030&r2=102031&view=diff
==============================================================================
--- cfe/trunk/include/clang/Parse/Parser.h (original)
+++ cfe/trunk/include/clang/Parse/Parser.h Wed Apr 21 17:36:40 2010
@@ -41,6 +41,29 @@
   virtual void print(llvm::raw_ostream &OS) const;
 };
 
+/// PrecedenceLevels - These are precedences for the binary/ternary
+/// operators in the C99 grammar.  These have been named to relate
+/// with the C99 grammar productions.  Low precedences numbers bind
+/// more weakly than high numbers.
+namespace prec {
+  enum Level {
+    Unknown         = 0,    // Not binary operator.
+    Comma           = 1,    // ,
+    Assignment      = 2,    // =, *=, /=, %=, +=, -=, <<=, >>=, &=, ^=, |=
+    Conditional     = 3,    // ?
+    LogicalOr       = 4,    // ||
+    LogicalAnd      = 5,    // &&
+    InclusiveOr     = 6,    // |
+    ExclusiveOr     = 7,    // ^
+    And             = 8,    // &
+    Equality        = 9,    // ==, !=
+    Relational      = 10,   //  >=, <=, >, <
+    Shift           = 11,   // <<, >>
+    Additive        = 12,   // -, +
+    Multiplicative  = 13,   // *, /, %
+    PointerToMember = 14    // .*, ->*
+  };
+}
 
 /// Parser - This implements a parser for the C family of languages.  After
 /// parsing units of the grammar, productions are invoked to handle whatever has
@@ -460,9 +483,11 @@
   //===--------------------------------------------------------------------===//
   // Diagnostic Emission and Error recovery.
 
+public:
   DiagnosticBuilder Diag(SourceLocation Loc, unsigned DiagID);
   DiagnosticBuilder Diag(const Token &Tok, unsigned DiagID);
 
+private:
   void SuggestParentheses(SourceLocation Loc, unsigned DK,
                           SourceRange ParenRange);
 
@@ -846,7 +871,7 @@
 
   //===--------------------------------------------------------------------===//
   // C99 6.5: Expressions.
-
+  
   OwningExprResult ParseExpression();
   OwningExprResult ParseConstantExpression();
   // Expr that doesn't include commas.
@@ -857,7 +882,7 @@
   OwningExprResult ParseExpressionWithLeadingExtension(SourceLocation ExtLoc);
 
   OwningExprResult ParseRHSOfBinaryExpression(OwningExprResult LHS,
-                                              unsigned MinPrec);
+                                              prec::Level MinPrec);
   OwningExprResult ParseCastExpression(bool isUnaryExpression,
                                        bool isAddressOfOperand,
                                        bool &NotCastExpr,
@@ -954,6 +979,8 @@
   // C++ 5.2.3: Explicit type conversion (functional notation)
   OwningExprResult ParseCXXTypeConstructExpression(const DeclSpec &DS);
 
+  bool isCXXSimpleTypeSpecifier() const;
+
   /// ParseCXXSimpleTypeSpecifier - [C++ 7.1.5.2] Simple type specifiers.
   /// This should only be called when the current token is known to be part of
   /// simple-type-specifier.
@@ -1011,6 +1038,7 @@
   OwningExprResult ParseAssignmentExprWithObjCMessageExprStart(
       SourceLocation LBracloc, SourceLocation SuperLoc,
       TypeTy *ReceiverType, ExprArg ReceiverExpr);
+  bool ParseObjCXXMessageReceiver(bool &IsExpr, void *&TypeOrExpr);
 
   //===--------------------------------------------------------------------===//
   // C99 6.8: Statements and Blocks.

Modified: cfe/trunk/lib/Parse/ParseExpr.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Parse/ParseExpr.cpp?rev=102031&r1=102030&r2=102031&view=diff
==============================================================================
--- cfe/trunk/lib/Parse/ParseExpr.cpp (original)
+++ cfe/trunk/lib/Parse/ParseExpr.cpp Wed Apr 21 17:36:40 2010
@@ -29,30 +29,6 @@
 #include "llvm/ADT/SmallString.h"
 using namespace clang;
 
-/// PrecedenceLevels - These are precedences for the binary/ternary operators in
-/// the C99 grammar.  These have been named to relate with the C99 grammar
-/// productions.  Low precedences numbers bind more weakly than high numbers.
-namespace prec {
-  enum Level {
-    Unknown         = 0,    // Not binary operator.
-    Comma           = 1,    // ,
-    Assignment      = 2,    // =, *=, /=, %=, +=, -=, <<=, >>=, &=, ^=, |=
-    Conditional     = 3,    // ?
-    LogicalOr       = 4,    // ||
-    LogicalAnd      = 5,    // &&
-    InclusiveOr     = 6,    // |
-    ExclusiveOr     = 7,    // ^
-    And             = 8,    // &
-    Equality        = 9,    // ==, !=
-    Relational      = 10,   //  >=, <=, >, <
-    Shift           = 11,   // <<, >>
-    Additive        = 12,   // -, +
-    Multiplicative  = 13,   // *, /, %
-    PointerToMember = 14    // .*, ->*
-  };
-}
-
-
 /// getBinOpPrecedence - Return the precedence of the specified binary operator
 /// token.  This returns:
 ///
@@ -297,10 +273,10 @@
 /// ParseRHSOfBinaryExpression - Parse a binary expression that starts with
 /// LHS and has a precedence of at least MinPrec.
 Parser::OwningExprResult
-Parser::ParseRHSOfBinaryExpression(OwningExprResult LHS, unsigned MinPrec) {
-  unsigned NextTokPrec = getBinOpPrecedence(Tok.getKind(),
-                                            GreaterThanIsOperator,
-                                            getLang().CPlusPlus0x);
+Parser::ParseRHSOfBinaryExpression(OwningExprResult LHS, prec::Level MinPrec) {
+  prec::Level NextTokPrec = getBinOpPrecedence(Tok.getKind(),
+                                               GreaterThanIsOperator,
+                                               getLang().CPlusPlus0x);
   SourceLocation ColonLoc;
 
   while (1) {
@@ -363,7 +339,7 @@
 
     // Remember the precedence of this operator and get the precedence of the
     // operator immediately to the right of the RHS.
-    unsigned ThisPrec = NextTokPrec;
+    prec::Level ThisPrec = NextTokPrec;
     NextTokPrec = getBinOpPrecedence(Tok.getKind(), GreaterThanIsOperator,
                                      getLang().CPlusPlus0x);
 
@@ -380,7 +356,8 @@
       // is okay, to bind exactly as tightly.  For example, compile A=B=C=D as
       // A=(B=(C=D)), where each paren is a level of recursion here.
       // The function takes ownership of the RHS.
-      RHS = ParseRHSOfBinaryExpression(move(RHS), ThisPrec + !isRightAssoc);
+      RHS = ParseRHSOfBinaryExpression(move(RHS), 
+                            static_cast<prec::Level>(ThisPrec + !isRightAssoc));
       if (RHS.isInvalid())
         return move(RHS);
 

Modified: cfe/trunk/lib/Parse/ParseExprCXX.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Parse/ParseExprCXX.cpp?rev=102031&r1=102030&r2=102031&view=diff
==============================================================================
--- cfe/trunk/lib/Parse/ParseExprCXX.cpp (original)
+++ cfe/trunk/lib/Parse/ParseExprCXX.cpp Wed Apr 21 17:36:40 2010
@@ -749,6 +749,36 @@
   return false;
 }
 
+/// \brief Determine whether the current token starts a C++
+/// simple-type-specifier.
+bool Parser::isCXXSimpleTypeSpecifier() const {
+  switch (Tok.getKind()) {
+  case tok::annot_typename:
+  case tok::kw_short:
+  case tok::kw_long:
+  case tok::kw_signed:
+  case tok::kw_unsigned:
+  case tok::kw_void:
+  case tok::kw_char:
+  case tok::kw_int:
+  case tok::kw_float:
+  case tok::kw_double:
+  case tok::kw_wchar_t:
+  case tok::kw_char16_t:
+  case tok::kw_char32_t:
+  case tok::kw_bool:
+    // FIXME: C++0x decltype support.
+  // GNU typeof support.
+  case tok::kw_typeof:
+    return true;
+
+  default:
+    break;
+  }
+
+  return false;
+}
+
 /// ParseCXXSimpleTypeSpecifier - [C++ 7.1.5.2] Simple type specifiers.
 /// This should only be called when the current token is known to be part of
 /// simple-type-specifier.
@@ -837,6 +867,7 @@
     DS.SetTypeSpecType(DeclSpec::TST_bool, Loc, PrevSpec, DiagID);
     break;
 
+    // FIXME: C++0x decltype support.
   // GNU typeof support.
   case tok::kw_typeof:
     ParseTypeofSpecifier(DS);

Modified: cfe/trunk/lib/Parse/ParseInit.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Parse/ParseInit.cpp?rev=102031&r1=102030&r2=102031&view=diff
==============================================================================
--- cfe/trunk/lib/Parse/ParseInit.cpp (original)
+++ cfe/trunk/lib/Parse/ParseInit.cpp Wed Apr 21 17:36:40 2010
@@ -34,6 +34,19 @@
   }
 }
 
+static void CheckArrayDesignatorSyntax(Parser &P, SourceLocation Loc,
+                                       Designation &Desig) {
+  // If we have exactly one array designator, this used the GNU
+  // 'designation: array-designator' extension, otherwise there should be no
+  // designators at all!
+  if (Desig.getNumDesignators() == 1 &&
+      (Desig.getDesignator(0).isArrayDesignator() ||
+       Desig.getDesignator(0).isArrayRangeDesignator()))
+    P.Diag(Loc, diag::ext_gnu_missing_equal_designator);
+  else if (Desig.getNumDesignators() > 0)
+    P.Diag(Loc, diag::err_expected_equal_designator);
+}
+
 /// ParseInitializerWithPotentialDesignator - Parse the 'initializer' production
 /// checking to see if the token stream starts with a designator.
 ///
@@ -124,10 +137,46 @@
     //   [4][foo bar]      -> obsolete GNU designation with objc message send.
     //
     SourceLocation StartLoc = ConsumeBracket();
+    OwningExprResult Idx(Actions);
+
+    // If Objective-C is enabled and this is a typename (class message
+    // send) or send to 'super', parse this as a message send
+    // expression.  We handle C++ and C separately, since C++ requires
+    // much more complicated parsing.
+    if  (getLang().ObjC1 && getLang().CPlusPlus) {
+      // Send to 'super'.
+      if (Tok.is(tok::identifier) && Tok.getIdentifierInfo() == Ident_super &&
+          NextToken().isNot(tok::period) && CurScope->isInObjcMethodScope()) {
+        CheckArrayDesignatorSyntax(*this, StartLoc, Desig);
+        return ParseAssignmentExprWithObjCMessageExprStart(StartLoc,
+                                                           ConsumeToken(), 0, 
+                                                           ExprArg(Actions));
+      }
+
+      // Parse the receiver, which is either a type or an expression.
+      bool IsExpr;
+      void *TypeOrExpr;
+      if (ParseObjCXXMessageReceiver(IsExpr, TypeOrExpr)) {
+        SkipUntil(tok::r_square);
+        return ExprError();
+      }
+      
+      // If the receiver was a type, we have a class message; parse
+      // the rest of it.
+      if (!IsExpr) {
+        CheckArrayDesignatorSyntax(*this, StartLoc, Desig);
+        return ParseAssignmentExprWithObjCMessageExprStart(StartLoc, 
+                                                           SourceLocation(), 
+                                                           TypeOrExpr, 
+                                                           ExprArg(Actions));
+      }
 
-    // If Objective-C is enabled and this is a typename (class message send) or
-    // send to 'super', parse this as a message send expression.
-    if (getLang().ObjC1 && Tok.is(tok::identifier)) {
+      // If the receiver was an expression, we still don't know
+      // whether we have a message send or an array designator; just
+      // adopt the expression for further analysis below.
+      // FIXME: potentially-potentially evaluated expression above?
+      Idx = OwningExprResult(Actions, TypeOrExpr);
+    } else if (getLang().ObjC1 && Tok.is(tok::identifier)) {
       IdentifierInfo *II = Tok.getIdentifierInfo();
       SourceLocation IILoc = Tok.getLocation();
       TypeTy *ReceiverType;
@@ -141,16 +190,7 @@
                                              ReceiverType)) {
       case Action::ObjCSuperMessage:
       case Action::ObjCClassMessage:
-        // If we have exactly one array designator, this used the GNU
-        // 'designation: array-designator' extension, otherwise there should be no
-        // designators at all!
-        if (Desig.getNumDesignators() == 1 &&
-            (Desig.getDesignator(0).isArrayDesignator() ||
-             Desig.getDesignator(0).isArrayRangeDesignator()))
-          Diag(StartLoc, diag::ext_gnu_missing_equal_designator);
-        else if (Desig.getNumDesignators() > 0)
-          Diag(Tok, diag::err_expected_equal_designator);
-
+        CheckArrayDesignatorSyntax(*this, StartLoc, Desig);
         if (Kind == Action::ObjCSuperMessage)
           return ParseAssignmentExprWithObjCMessageExprStart(StartLoc,
                                                              ConsumeToken(),
@@ -175,13 +215,19 @@
       }
     }
 
+    // Parse the index expression, if we haven't already gotten one
+    // above (which can only happen in Objective-C++).
     // Note that we parse this as an assignment expression, not a constant
     // expression (allowing *=, =, etc) to handle the objc case.  Sema needs
     // to validate that the expression is a constant.
-    OwningExprResult Idx(ParseAssignmentExpression());
-    if (Idx.isInvalid()) {
-      SkipUntil(tok::r_square);
-      return move(Idx);
+    // FIXME: We also need to tell Sema that we're in a
+    // potentially-potentially evaluated context.
+    if (!Idx.get()) {
+      Idx = ParseAssignmentExpression();
+      if (Idx.isInvalid()) {
+        SkipUntil(tok::r_square);
+        return move(Idx);
+      }
     }
 
     // Given an expression, we could either have a designator (if the next
@@ -190,17 +236,7 @@
     // an assignment-expression production.
     if (getLang().ObjC1 && Tok.isNot(tok::ellipsis) &&
         Tok.isNot(tok::r_square)) {
-
-      // If we have exactly one array designator, this used the GNU
-      // 'designation: array-designator' extension, otherwise there should be no
-      // designators at all!
-      if (Desig.getNumDesignators() == 1 &&
-          (Desig.getDesignator(0).isArrayDesignator() ||
-           Desig.getDesignator(0).isArrayRangeDesignator()))
-        Diag(StartLoc, diag::ext_gnu_missing_equal_designator);
-      else if (Desig.getNumDesignators() > 0)
-        Diag(Tok, diag::err_expected_equal_designator);
-
+      CheckArrayDesignatorSyntax(*this, Tok.getLocation(), Desig);
       return ParseAssignmentExprWithObjCMessageExprStart(StartLoc,
                                                          SourceLocation(),
                                                          0, move(Idx));

Modified: cfe/trunk/lib/Parse/ParseObjc.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Parse/ParseObjc.cpp?rev=102031&r1=102030&r2=102031&view=diff
==============================================================================
--- cfe/trunk/lib/Parse/ParseObjc.cpp (original)
+++ cfe/trunk/lib/Parse/ParseObjc.cpp Wed Apr 21 17:36:40 2010
@@ -1711,6 +1711,92 @@
   }
 }
 
+/// \brirg Parse the receiver of an Objective-C++ message send.
+///
+/// This routine parses the receiver of a message send in
+/// Objective-C++ either as a type or as an expression. Note that this
+/// routine must not be called to parse a send to 'super', since it
+/// has no way to return such a result.
+/// 
+/// \param IsExpr Whether the receiver was parsed as an expression.
+///
+/// \param TypeOrExpr If the receiver was parsed as an expression (\c
+/// IsExpr is true), the parsed expression. If the receiver was parsed
+/// as a type (\c IsExpr is false), the parsed type.
+///
+/// \returns True if an error occurred during parsing or semantic
+/// analysis, in which case the arguments do not have valid
+/// values. Otherwise, returns false for a successful parse.
+///
+///   objc-receiver: [C++]
+///     'super' [not parsed here]
+///     expression
+///     simple-type-specifier
+///     typename-specifier
+
+bool Parser::ParseObjCXXMessageReceiver(bool &IsExpr, void *&TypeOrExpr) {
+  if (Tok.is(tok::identifier) || Tok.is(tok::coloncolon) || 
+      Tok.is(tok::kw_typename) || Tok.is(tok::annot_cxxscope))
+    TryAnnotateTypeOrScopeToken();
+
+  if (!isCXXSimpleTypeSpecifier()) {
+    //   objc-receiver:
+    //     expression
+    OwningExprResult Receiver = ParseExpression();
+    if (Receiver.isInvalid())
+      return true;
+
+    IsExpr = true;
+    TypeOrExpr = Receiver.take();
+    return false;
+  }
+
+  // objc-receiver:
+  //   typename-specifier
+  //   simple-type-specifier
+  //   expression (that starts with one of the above)
+  DeclSpec DS;
+  ParseCXXSimpleTypeSpecifier(DS);
+  
+  if (Tok.is(tok::l_paren)) {
+    // If we see an opening parentheses at this point, we are
+    // actually parsing an expression that starts with a
+    // function-style cast, e.g.,
+    //
+    //   postfix-expression:
+    //     simple-type-specifier ( expression-list [opt] )
+    //     typename-specifier ( expression-list [opt] )
+    //
+    // Parse the remainder of this case, then the (optional)
+    // postfix-expression suffix, followed by the (optional)
+    // right-hand side of the binary expression. We have an
+    // instance method.
+    OwningExprResult Receiver = ParseCXXTypeConstructExpression(DS);
+    if (!Receiver.isInvalid())
+      Receiver = ParsePostfixExpressionSuffix(move(Receiver));
+    if (!Receiver.isInvalid())
+      Receiver = ParseRHSOfBinaryExpression(move(Receiver), prec::Comma);
+    if (Receiver.isInvalid())
+      return true;
+
+    IsExpr = true;
+    TypeOrExpr = Receiver.take();
+    return false;
+  }
+  
+  // We have a class message. Turn the simple-type-specifier or
+  // typename-specifier we parsed into a type and parse the
+  // remainder of the class message.
+  Declarator DeclaratorInfo(DS, Declarator::TypeNameContext);
+  TypeResult Type = Actions.ActOnTypeName(CurScope, DeclaratorInfo);
+  if (Type.isInvalid())
+    return true;
+
+  IsExpr = false;
+  TypeOrExpr = Type.get();
+  return false;
+}
+
 ///   objc-message-expr:
 ///     '[' objc-receiver objc-message-args ']'
 ///
@@ -1719,11 +1805,38 @@
 ///     expression
 ///     class-name
 ///     type-name
+///
 Parser::OwningExprResult Parser::ParseObjCMessageExpression() {
   assert(Tok.is(tok::l_square) && "'[' expected");
   SourceLocation LBracLoc = ConsumeBracket(); // consume '['
 
-  if (Tok.is(tok::identifier)) {
+  if (getLang().CPlusPlus) {
+    // We completely separate the C and C++ cases because C++ requires
+    // more complicated (read: slower) parsing. 
+    
+    // Handle send to super.  
+    // FIXME: This doesn't benefit from the same typo-correction we
+    // get in Objective-C.
+    if (Tok.is(tok::identifier) && Tok.getIdentifierInfo() == Ident_super &&
+        NextToken().isNot(tok::period) && CurScope->isInObjcMethodScope())
+      return ParseObjCMessageExpressionBody(LBracLoc, ConsumeToken(), 0, 
+                                            ExprArg(Actions));
+
+    // Parse the receiver, which is either a type or an expression.
+    bool IsExpr;
+    void *TypeOrExpr;
+    if (ParseObjCXXMessageReceiver(IsExpr, TypeOrExpr)) {
+      SkipUntil(tok::r_square);
+      return ExprError();
+    }
+
+    if (IsExpr)
+      return ParseObjCMessageExpressionBody(LBracLoc, SourceLocation(), 0,
+                                         OwningExprResult(Actions, TypeOrExpr));
+
+    return ParseObjCMessageExpressionBody(LBracLoc, SourceLocation(), 
+                                          TypeOrExpr, ExprArg(Actions));
+  } else if (Tok.is(tok::identifier)) {
     IdentifierInfo *Name = Tok.getIdentifierInfo();
     SourceLocation NameLoc = Tok.getLocation();
     TypeTy *ReceiverType;

Modified: cfe/trunk/test/Parser/objc-init.m
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/Parser/objc-init.m?rev=102031&r1=102030&r2=102031&view=diff
==============================================================================
--- cfe/trunk/test/Parser/objc-init.m (original)
+++ cfe/trunk/test/Parser/objc-init.m Wed Apr 21 17:36:40 2010
@@ -1,4 +1,5 @@
 // RUN: %clang_cc1 -fsyntax-only -verify %s -pedantic
+// RUN: %clang_cc1 -fsyntax-only -verify -x objective-c++ %s 
 // rdar://5707001
 
 @interface NSNumber;

Modified: cfe/trunk/test/SemaObjCXX/message.mm
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/SemaObjCXX/message.mm?rev=102031&r1=102030&r2=102031&view=diff
==============================================================================
--- cfe/trunk/test/SemaObjCXX/message.mm (original)
+++ cfe/trunk/test/SemaObjCXX/message.mm Wed Apr 21 17:36:40 2010
@@ -1,12 +1,13 @@
 // RUN: %clang_cc1 -fsyntax-only -verify %s
 @interface I1
-- (void)method;
+- (int*)method;
 @end
 
 @implementation I1
-- (void)method {
+- (int*)method {
   struct x { };
   [x method]; // expected-error{{receiver type 'x' is not an Objective-C class}}
+  return 0;
 }
 @end
 
@@ -15,15 +16,62 @@
 @interface I2 {
   id ivar;
 }
-- (void)method;
+- (int*)method;
 + (void)method;
 @end
 
+struct I2_holder {
+  I2_holder();
+
+  I2 *get();
+};
+
+I2 *operator+(I2_holder, int);
+
 @implementation I2
-- (void)method {
+- (int*)method {
   [ivar method];
+
+  // Test instance messages that start with a simple-type-specifier.
+  [I2_holder().get() method];
+  [I2_holder().get() + 17 method];
+  return 0;
 }
 + (void)method {
   [ivar method]; // expected-error{{receiver type 'ivar' (aka 'ivar') is not an Objective-C class}}
 }
 @end
+
+// Class message sends
+ at interface I3
++ (int*)method;
+ at end
+
+ at interface I4 : I3
++ (int*)otherMethod;
+ at end
+
+template<typename T>
+struct identity {
+  typedef T type;
+};
+
+ at implementation I4
++ (int *)otherMethod {
+  // Test class messages that use non-trivial simple-type-specifiers
+  // or typename-specifiers.
+  if (false) {
+    if (true)
+      return [typename identity<I3>::type method];
+
+    return [::I3 method];
+  }
+
+  int* ip1 = {[super method]};
+  int* ip2 = {[::I3 method]};
+  int* ip3 = {[typename identity<I3>::type method]};
+  int* ip4 = {[typename identity<I2_holder>::type().get() method]};
+  int array[5] = {[3] = 2};
+  return [super method];
+}
+ at end





More information about the cfe-commits mailing list