diff mbox

[c++/objc++] Make Objective-c++ recognise lambdas.

Message ID 29BB8A79-F3DA-4FC8-9CDE-9B3151F04B7A@mentor.com
State New
Headers show

Commit Message

Iain Sandoe Dec. 22, 2014, 12:50 p.m. UTC
Hi,

The principle of Objective-c/c++ is that they should be supersets of the parent language.  Thus, it is intended that valid c++ (or c) should be parsed by the relevant objective-c/c++ FE.

While trying to build some external code, I found that lambdas confuse things at present for objcp.

When we find "[" and we're in objcp mode, and the "[" introduces a lambda, we try to parse a message expression and if that fails we punt (thus we are unable to recognise lambdas).

The attached patch tries "[" as a message expression introducer, if that fails it drops through to try for a lambda (no change intended for the non-objective-c++ path).

I guess it's a bit of a nuisance that the diagnostics from a failed message expression are likely to end up as mentioning a lambda.  Perhaps we might decide to punt early if we are both ObjC and < c++11.

This allows me to parse some necessary lldb headers with gcc objcp.

Thoughts / OK for trunk?
(I can raise a formal PR if you like).

Iain

gcc/cp:
	* parser.c (cp_parser_primary_expression): If parsing an objective-c++ message
	expression fails, see if a lambda is present.
	(cp_parser_objc_message_reciever): Don't assume that if a message reciever expression
	fails it is a hard error.

gcc/testsuite:
	* obj-c++.dg/lambda-0.mm New file.
	* obj-c++.dg/lambda-1.mm New file.
From e8038ba3cb16095e53d09e23ff15f4682cb5bd0c Mon Sep 17 00:00:00 2001
From: Iain Sandoe <iain@codesourcery.com>
Date: Mon, 22 Dec 2014 10:50:45 +0000
Subject: [PATCH] Modify objective-c++ parse to check for lambdas when a
 message construct isn't matched after a [

---
 gcc/cp/parser.c                            | 21 +++++++++++++++++----
 gcc/testsuite/obj-c++.dg/lambda-0.mm       | 22 ++++++++++++++++++++++
 gcc/testsuite/obj-c++.dg/lambda-1.mm       | 13 +++++++++++++
 gcc/testsuite/obj-c++.dg/syntax-error-6.mm |  5 ++++-
 4 files changed, 56 insertions(+), 5 deletions(-)
 create mode 100644 gcc/testsuite/obj-c++.dg/lambda-0.mm
 create mode 100644 gcc/testsuite/obj-c++.dg/lambda-1.mm

Comments

Jason Merrill Dec. 22, 2014, 3 p.m. UTC | #1
OK.
Mike Stump Dec. 22, 2014, 4:54 p.m. UTC | #2
On Dec 22, 2014, at 4:50 AM, Iain Sandoe <iain_sandoe@mentor.com> wrote:
> When we find "[" and we're in objcp mode, and the "[" introduces a lambda, we try to parse a message expression and if that fails we punt (thus we are unable to recognise lambdas).

Even though Jason reviewed it, I also took a look.  Looks good.  This has to be the usual and customary fallout of language derivation.  One has to review the intersection and resolve any ambiguities.  Don’t think we get nice easy tools for this.  Thanks.
diff mbox

Patch

diff --git a/gcc/cp/parser.c b/gcc/cp/parser.c
index 8ff16ed..1409bef 100644
--- a/gcc/cp/parser.c
+++ b/gcc/cp/parser.c
@@ -4441,10 +4441,17 @@  cp_parser_primary_expression (cp_parser *parser,
       }
 
     case CPP_OPEN_SQUARE:
-      if (c_dialect_objc ())
-        /* We have an Objective-C++ message. */
-        return cp_parser_objc_expression (parser);
       {
+	if (c_dialect_objc ())
+	  {
+	    /* We might have an Objective-C++ message. */
+	    cp_parser_parse_tentatively (parser);
+	    tree msg = cp_parser_objc_message_expression (parser);
+	    /* If that works out, we're done ... */
+	    if (cp_parser_parse_definitely (parser))
+	      return msg;
+	    /* ... else, fall though to see if it's a lambda.  */
+	  }
 	tree lam = cp_parser_lambda_expression (parser);
 	/* Don't warn about a failed tentative parse.  */
 	if (cp_parser_error_occurred (parser))
@@ -25630,14 +25637,20 @@  cp_parser_objc_message_receiver (cp_parser* parser)
   cp_parser_parse_tentatively (parser);
   rcv = cp_parser_expression (parser);
 
+  /* If that worked out, fine.  */
   if (cp_parser_parse_definitely (parser))
     return rcv;
 
+  cp_parser_parse_tentatively (parser);
   rcv = cp_parser_simple_type_specifier (parser,
 					 /*decl_specs=*/NULL,
 					 CP_PARSER_FLAGS_NONE);
 
-  return objc_get_class_reference (rcv);
+  if (cp_parser_parse_definitely (parser))
+    return objc_get_class_reference (rcv);
+  
+  cp_parser_error (parser, "objective-c++ message receiver expected");
+  return error_mark_node;
 }
 
 /* Parse the arguments and selectors comprising an Objective-C message.
diff --git a/gcc/testsuite/obj-c++.dg/lambda-0.mm b/gcc/testsuite/obj-c++.dg/lambda-0.mm
new file mode 100644
index 0000000..41482fd
--- /dev/null
+++ b/gcc/testsuite/obj-c++.dg/lambda-0.mm
@@ -0,0 +1,22 @@ 
+// Contributed by Iain Sandoe <iain@codesourcery.com>, December 2014.  */
+// { dg-do compile }
+// { dg-options "-std=c++11" }
+
+
+template<class Function>
+Function thing(Function fn, int a)
+{
+  fn(a);
+  return fn;
+}
+
+int
+test (int *arr, unsigned n)
+{
+  int total = 0;
+  for (unsigned i=0; i<n; i++) {
+    int a = arr[i];
+    thing ([&total] (int a) { total += a; }, a);
+  }
+  return total;
+}
diff --git a/gcc/testsuite/obj-c++.dg/lambda-1.mm b/gcc/testsuite/obj-c++.dg/lambda-1.mm
new file mode 100644
index 0000000..050d68d
--- /dev/null
+++ b/gcc/testsuite/obj-c++.dg/lambda-1.mm
@@ -0,0 +1,13 @@ 
+// Contributed by Iain Sandoe <iain@codesourcery.com>, December 2014.  */
+// { dg-do compile }
+// { dg-options "-std=c++11" }
+
+extern "C" {
+  int printf (const char *,...);
+}
+
+int main () 
+{
+  auto f = [] (const char *msg) -> int { printf("%s", msg); return 0; };
+  return f("Some test\n");
+}
diff --git a/gcc/testsuite/obj-c++.dg/syntax-error-6.mm b/gcc/testsuite/obj-c++.dg/syntax-error-6.mm
index 21423ec..36a444f 100644
--- a/gcc/testsuite/obj-c++.dg/syntax-error-6.mm
+++ b/gcc/testsuite/obj-c++.dg/syntax-error-6.mm
@@ -8,5 +8,8 @@  void FOO()
 {
   NSButton * mCopyAcrobatCB; 
 	
-  [ [ mCopyAcrobatCB state ] == 0 ] != 1;  /* { dg-error "objective\\-c\\+\\+" } */
+  [ [ mCopyAcrobatCB state ] == 0 ] != 1;  /* { dg-error "expected identifier before ... token" } */
+/* { dg-error "expected \\\'\\\{\\\' before \\\'!=\\\' token" "" { target *-*-* } 11 } */
+/* { dg-error "lambda expressions only available with" "" { target *-*-* } 11 } */
+/* { dg-error "no match for \\\'operator!=\\\' in" "" { target *-*-* } 11 } */
 }