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.



git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@102031 91177308-0d34-0410-b5e6-96231b3b80d8
diff --git a/lib/Parse/ParseExpr.cpp b/lib/Parse/ParseExpr.cpp
index ef35dcb..588825b 100644
--- a/lib/Parse/ParseExpr.cpp
+++ b/lib/Parse/ParseExpr.cpp
@@ -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);
 
diff --git a/lib/Parse/ParseExprCXX.cpp b/lib/Parse/ParseExprCXX.cpp
index 8528f8f..74f4ebd 100644
--- a/lib/Parse/ParseExprCXX.cpp
+++ b/lib/Parse/ParseExprCXX.cpp
@@ -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);
diff --git a/lib/Parse/ParseInit.cpp b/lib/Parse/ParseInit.cpp
index 1a2a226..a382a9a 100644
--- a/lib/Parse/ParseInit.cpp
+++ b/lib/Parse/ParseInit.cpp
@@ -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.
-    if (getLang().ObjC1 && Tok.is(tok::identifier)) {
+    // 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 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));
diff --git a/lib/Parse/ParseObjc.cpp b/lib/Parse/ParseObjc.cpp
index 2a71bf0..7337445 100644
--- a/lib/Parse/ParseObjc.cpp
+++ b/lib/Parse/ParseObjc.cpp
@@ -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;