diff mbox

[C++] PR 53158

Message ID 4FA7F554.90003@oracle.com
State New
Headers show

Commit Message

Paolo Carlini May 7, 2012, 4:16 p.m. UTC
Hi,

for this testcase:

int main()
{
auto a = []() { return true; };
auto b = []() { return a(); }; // { dg-error "'a' is not captured" }
int c, d;
while (b() && c < d)
{
}
}

we produce meaningless diagnostics for the while loop (stemming from b() 
but the caret is also in the wrong place, a separate issue):

error: invalid operands of types ‘void’ and ‘int’ to binary ‘operator!=’

because nothing notices in cp_parser_lambda_body that 
cp_parser_expression went wrong, thus finish_return_stmt (expr) is 
called on expr == error_mark_node. The way I'm handling the problem is 
by returning false to the caller, cp_parser_lambda_expression, which is 
already equipped to smoothly handle errors and return back error_mark_node.

Tested x86_64-linux.

Thanks,
Paolo.

///////////////////////
/cp
2012-05-07  Paolo Carlini  <paolo.carlini@oracle.com>

	PR c++/53158
	* parser.c (cp_parser_lambda_body): Return a boolean, false if
	cp_parser_expression returns error_mark_node;
	(cp_parser_lambda_expression): Check the latter.

/testsuite
2012-05-07  Paolo Carlini  <paolo.carlini@oracle.com>

	PR c++/53158
	* g++.dg/cpp0x/lambda/lambda-err2.C: New.

Comments

Jason Merrill May 7, 2012, 5:16 p.m. UTC | #1
I don't think the diagnostic is meaningless; since a() is ill-formed, 
b() has type void.  But we ought to give a more helpful message when an 
expression used as a truth value has an unsuitable type.

Jason
Paolo Carlini May 7, 2012, 5:18 p.m. UTC | #2
On 05/07/2012 07:16 PM, Jason Merrill wrote:
> I don't think the diagnostic is meaningless; since a() is ill-formed, 
> b() has type void.
Sure we do understand it ;)
>   But we ought to give a more helpful message when an expression used 
> as a truth value has an unsuitable type.
Thus something much more general than the lambda context of the PR. Ok, 
I can see what I can do.

Thanks!
Paolo.
Paolo Carlini May 7, 2012, 5:40 p.m. UTC | #3
On 05/07/2012 07:18 PM, Paolo Carlini wrote:
> On 05/07/2012 07:16 PM, Jason Merrill wrote:
>> I don't think the diagnostic is meaningless; since a() is ill-formed, 
>> b() has type void.
> Sure we do understand it ;)
>>   But we ought to give a more helpful message when an expression used 
>> as a truth value has an unsuitable type.
> Thus something much more general than the lambda context of the PR. 
> Ok, I can see what I can do.
I think this is the minimal testcase we are looking for:

void foo();

void bar(int a, int b)
{
   if (foo() && a < b)
     ;
}

the error message is the same we see in PR 53158, thus:

a.cc:5:20: error: invalid operands of types ‘void’ and ‘int’ to binary 
‘operator!=’
    if (foo() && a < b)

If I take out the 'a < b' subexpression, we get:

a.cc:5:12: error: could not convert ‘foo()’ from ‘void’ to ‘bool’
    if (foo())

Is this the error message we want to see for the former testcase, or we 
want something slightly different?

Thanks!
Paolo.
Manuel López-Ibáñez May 7, 2012, 6:07 p.m. UTC | #4
On 7 May 2012 19:40, Paolo Carlini <paolo.carlini@oracle.com> wrote:
> On 05/07/2012 07:18 PM, Paolo Carlini wrote:
>
> a.cc:5:12: error: could not convert ‘foo()’ from ‘void’ to ‘bool’
>   if (foo())
>
> Is this the error message we want to see for the former testcase, or we want
> something slightly different?

If "foo()" is printed with %qE, and now that we have caret
diagnostics, I would expect the message to be:

error: could not convert expression from 'void' to 'bool'

For comparison, this is what Clang gives:

/tmp/webcompile/_8320_0.cc:7:6: error: value of type 'void' is not
contextually convertible to 'bool'
 if (foo() && a < b)
     ^~~~~
/tmp/webcompile/_8320_0.cc:7:12: error: invalid operands to binary
expression ('void' and 'bool')
 if (foo() && a < b)
     ~~~~~ ^  ~~~~~
2 errors generated.


G++ could do better in this case, foo() is likely to be some kind of
FUNCTION_DECL, so g++ could be smarter and say something like:

error: could not convert return type of 'foo' from 'void' to 'bool'
note: 'foo' declared here

Just a suggestion.

Cheers,

Manuel.
diff mbox

Patch

Index: testsuite/g++.dg/cpp0x/lambda/lambda-err2.C
===================================================================
--- testsuite/g++.dg/cpp0x/lambda/lambda-err2.C	(revision 0)
+++ testsuite/g++.dg/cpp0x/lambda/lambda-err2.C	(revision 0)
@@ -0,0 +1,12 @@ 
+// PR c++/53158
+// { dg-do compile { target c++11 } }
+
+int main()
+{
+  auto a = []() { return true; };
+  auto b = []() { return a(); };  // { dg-error "'a' is not captured" }
+  int c, d;
+  while (b() && c < d)
+    {
+    }
+}
Index: cp/parser.c
===================================================================
--- cp/parser.c	(revision 187249)
+++ cp/parser.c	(working copy)
@@ -1848,7 +1848,7 @@  static void cp_parser_lambda_introducer
   (cp_parser *, tree);
 static bool cp_parser_lambda_declarator_opt
   (cp_parser *, tree);
-static void cp_parser_lambda_body
+static bool cp_parser_lambda_body
   (cp_parser *, tree);
 
 /* Statements [gram.stmt.stmt]  */
@@ -8101,7 +8101,7 @@  cp_parser_lambda_expression (cp_parser* parser)
     ok = cp_parser_lambda_declarator_opt (parser, lambda_expr);
 
     if (ok)
-      cp_parser_lambda_body (parser, lambda_expr);
+      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);
 
@@ -8466,11 +8466,13 @@  cp_parser_lambda_declarator_opt (cp_parser* parser
    but which requires special handling.
    LAMBDA_EXPR is the current representation of the lambda expression.  */
 
-static void
+static bool
 cp_parser_lambda_body (cp_parser* parser, tree lambda_expr)
 {
   bool nested = (current_function_decl != NULL_TREE);
   bool local_variables_forbidden_p = parser->local_variables_forbidden_p;
+  bool ok = true;
+
   if (nested)
     push_function_context ();
   else
@@ -8540,6 +8542,8 @@  cp_parser_lambda_body (cp_parser* parser, tree lam
 	cp_parser_require_keyword (parser, RID_RETURN, RT_RETURN);
 
 	expr = cp_parser_expression (parser, /*cast_p=*/false, &idk);
+	if (expr == error_mark_node)
+	  ok = false;
 
 	cp_parser_require (parser, CPP_SEMICOLON, RT_SEMICOLON);
 	cp_parser_require (parser, CPP_CLOSE_BRACE, RT_CLOSE_BRACE);
@@ -8579,6 +8583,8 @@  cp_parser_lambda_body (cp_parser* parser, tree lam
     pop_function_context();
   else
     --function_depth;
+
+  return ok;
 }
 
 /* Statements [gram.stmt.stmt]  */