Patchwork C++ PATCH for c++/60375 (unevaluated lambda)

login
register
mail settings
Submitter Jason Merrill
Date March 25, 2014, 5:59 p.m.
Message ID <5331C414.3000508@redhat.com>
Download mbox | patch
Permalink /patch/333641/
State New
Headers show

Comments

Jason Merrill - March 25, 2014, 5:59 p.m.
The parser was getting confused by trying to process the body of the 
lambda in an unevaluated context, so let's just skip the body.  The 
second patch avoids repeated errors about the issue, but isn't necessary 
to fix the ICE, so I'm saving it for after 4.9.

Tested x86_64-pc-linux-gnu, applying to trunk.

Patch

commit 276e736980d133f032633eeb69d9edb1be6070eb
Author: Jason Merrill <jason@redhat.com>
Date:   Mon Mar 24 16:11:02 2014 -0400

    	PR c++/60375
    	* parser.c (cp_parser_lambda_expression): Don't parse the body of
    	a lambda in unevaluated context.

diff --git a/gcc/cp/parser.c b/gcc/cp/parser.c
index 4ca08a1..2e117a5 100644
--- a/gcc/cp/parser.c
+++ b/gcc/cp/parser.c
@@ -8718,14 +8718,17 @@  cp_parser_lambda_expression (cp_parser* parser)
 {
   tree lambda_expr = build_lambda_expr ();
   tree type;
-  bool ok;
+  bool ok = true;
 
   LAMBDA_EXPR_LOCATION (lambda_expr)
     = cp_lexer_peek_token (parser->lexer)->location;
 
   if (cp_unevaluated_operand)
-    error_at (LAMBDA_EXPR_LOCATION (lambda_expr),
-	      "lambda-expression in unevaluated context");
+    {
+      error_at (LAMBDA_EXPR_LOCATION (lambda_expr),
+		"lambda-expression in unevaluated context");
+      ok = false;
+    }
 
   /* We may be in the middle of deferred access check.  Disable
      it now.  */
@@ -8770,12 +8773,15 @@  cp_parser_lambda_expression (cp_parser* parser)
     /* By virtue of defining a local class, a lambda expression has access to
        the private variables of enclosing classes.  */
 
-    ok = cp_parser_lambda_declarator_opt (parser, lambda_expr);
+    ok &= cp_parser_lambda_declarator_opt (parser, lambda_expr);
 
     if (ok)
       cp_parser_lambda_body (parser, lambda_expr);
     else if (cp_parser_require (parser, CPP_OPEN_BRACE, RT_OPEN_BRACE))
-      cp_parser_skip_to_end_of_block_or_statement (parser);
+      {
+	if (cp_parser_skip_to_closing_brace (parser))
+	  cp_lexer_consume_token (parser->lexer);
+      }
 
     /* The capture list was built up in reverse order; fix that now.  */
     LAMBDA_EXPR_CAPTURE_LIST (lambda_expr)
diff --git a/gcc/testsuite/g++.dg/cpp0x/lambda/lambda-uneval.C b/gcc/testsuite/g++.dg/cpp0x/lambda/lambda-uneval.C
index 898f685..dcea169 100644
--- a/gcc/testsuite/g++.dg/cpp0x/lambda/lambda-uneval.C
+++ b/gcc/testsuite/g++.dg/cpp0x/lambda/lambda-uneval.C
@@ -5,3 +5,5 @@  template <class T>
 struct A { };
 A<decltype([]{ return 1; }())> a; // { dg-error "lambda.*unevaluated context" }
 
+// { dg-prune-output "template argument" }
+// { dg-prune-output "invalid type" }
diff --git a/gcc/testsuite/g++.dg/cpp0x/lambda/lambda-uneval2.C b/gcc/testsuite/g++.dg/cpp0x/lambda/lambda-uneval2.C
new file mode 100644
index 0000000..14cb298
--- /dev/null
+++ b/gcc/testsuite/g++.dg/cpp0x/lambda/lambda-uneval2.C
@@ -0,0 +1,7 @@ 
+// PR c++/60375
+// { dg-do compile { target c++11 } }
+
+struct A
+{
+  decltype( [](){ return this; }() ) x; // { dg-error "unevaluated" }
+};

commit d0dd16c1e91b1d394c659e608d86a93e82f24fb4
Author: Jason Merrill <jason@redhat.com>
Date:   Mon Mar 24 16:11:02 2014 -0400

    	* parser.h (struct cp_token): Rename ambiguous_p to error_reported.
    	* parser.c: Adjust.
    	(cp_lexer_get_preprocessor_token): Always clear it.
    	(cp_parser_lambda_expression): Use it to avoid duplicate diagnostics.

diff --git a/gcc/cp/parser.c b/gcc/cp/parser.c
index 2e117a5..fa3e111 100644
--- a/gcc/cp/parser.c
+++ b/gcc/cp/parser.c
@@ -762,6 +762,7 @@  cp_lexer_get_preprocessor_token (cp_lexer *lexer, cp_token *token)
   token->keyword = RID_MAX;
   token->pragma_kind = PRAGMA_NONE;
   token->purged_p = false;
+  token->error_reported = false;
 
   /* On some systems, some header files are surrounded by an
      implicit extern "C" block.  Set a flag in the token if it
@@ -797,7 +798,6 @@  cp_lexer_get_preprocessor_token (cp_lexer *lexer, cp_token *token)
               C_SET_RID_CODE (token->u.value, RID_MAX);
             }
 
-	  token->ambiguous_p = false;
 	  token->keyword = RID_MAX;
 	}
     }
@@ -3011,7 +3011,7 @@  cp_parser_parse_and_diagnose_invalid_type_name (cp_parser *parser)
   if (token->type == CPP_NESTED_NAME_SPECIFIER)
     {
       cp_token *next = cp_lexer_peek_nth_token (parser->lexer, 2);
-      if (next->type == CPP_NAME && next->ambiguous_p)
+      if (next->type == CPP_NAME && next->error_reported)
 	goto out;
     }
 
@@ -4535,7 +4535,7 @@  cp_parser_primary_expression (cp_parser *parser,
 	       we've already issued an error message; there's no reason
 	       to check again.  */
 	    if (id_expr_token->type == CPP_NAME
-		&& id_expr_token->ambiguous_p)
+		&& id_expr_token->error_reported)
 	      {
 		cp_parser_simulate_error (parser);
 		return error_mark_node;
@@ -5313,7 +5313,7 @@  cp_parser_nested_name_specifier_opt (cp_parser *parser,
 	      token = cp_lexer_consume_token (parser->lexer);
 	      if (!error_p)
 		{
-		  if (!token->ambiguous_p)
+		  if (!token->error_reported)
 		    {
 		      tree decl;
 		      tree ambiguous_decls;
@@ -8719,14 +8719,18 @@  cp_parser_lambda_expression (cp_parser* parser)
   tree lambda_expr = build_lambda_expr ();
   tree type;
   bool ok = true;
+  cp_token *token = cp_lexer_peek_token (parser->lexer);
 
-  LAMBDA_EXPR_LOCATION (lambda_expr)
-    = cp_lexer_peek_token (parser->lexer)->location;
+  LAMBDA_EXPR_LOCATION (lambda_expr) = token->location;
 
   if (cp_unevaluated_operand)
     {
-      error_at (LAMBDA_EXPR_LOCATION (lambda_expr),
-		"lambda-expression in unevaluated context");
+      if (!token->error_reported)
+	{
+	  error_at (LAMBDA_EXPR_LOCATION (lambda_expr),
+		    "lambda-expression in unevaluated context");
+	  token->error_reported = true;
+	}
       ok = false;
     }
 
@@ -19122,7 +19126,7 @@  cp_parser_class_name (cp_parser *parser,
 
       /* Look for the identifier.  */
       identifier_token = cp_lexer_peek_token (parser->lexer);
-      ambiguous_p = identifier_token->ambiguous_p;
+      ambiguous_p = identifier_token->error_reported;
       identifier = cp_parser_identifier (parser);
       /* If the next token isn't an identifier, we are certainly not
 	 looking at a class-name.  */
diff --git a/gcc/cp/parser.h b/gcc/cp/parser.h
index d558c60..758c6df 100644
--- a/gcc/cp/parser.h
+++ b/gcc/cp/parser.h
@@ -51,10 +51,10 @@  typedef struct GTY (()) cp_token {
   ENUM_BITFIELD (pragma_kind) pragma_kind : 6;
   /* True if this token is from a context where it is implicitly extern "C" */
   BOOL_BITFIELD implicit_extern_c : 1;
-  /* True for a CPP_NAME token that is not a keyword (i.e., for which
-     KEYWORD is RID_MAX) iff this name was looked up and found to be
-     ambiguous.  An error has already been reported.  */
-  BOOL_BITFIELD ambiguous_p : 1;
+  /* True if an error has already been reported for this token, such as a
+     CPP_NAME token that is not a keyword (i.e., for which KEYWORD is
+     RID_MAX) iff this name was looked up and found to be ambiguous.  */
+  BOOL_BITFIELD error_reported : 1;
   /* True for a token that has been purged.  If a token is purged,
      it is no longer a valid token and it should be considered
      deleted.  */