Re: [C++ Patch] PR 84588 ("[8 Regression] internal compiler error: Segmentation fault (contains_struct_check())")​ (Take 2)

2018-05-21 Thread Jason Merrill
OK.

On Mon, May 21, 2018 at 8:41 AM, Paolo Carlini  wrote:
> Hi again,
>
> On 19/05/2018 15:30, Jason Merrill wrote:
>>
>> How about doing cp_parser_commit_to_tentative_parse if we see
>> something that must be a declaration?  cp_parser_simple_declaration
>> has
>>
>>/* If we have seen at least one decl-specifier, and the next token
>>   is not a parenthesis, then we must be looking at a declaration.
>>   (After "int (" we might be looking at a functional cast.)  */
>>if (decl_specifiers.any_specifiers_p
>>&& cp_lexer_next_token_is_not (parser->lexer, CPP_OPEN_PAREN)
>>&& cp_lexer_next_token_is_not (parser->lexer, CPP_OPEN_BRACE)
>>&& !cp_parser_error_occurred (parser))
>>  cp_parser_commit_to_tentative_parse (parser);
>>
>> That seems useful here, as well.  Maybe factored into a separate function.
>
> The below implements this new idea, which indeed appears to work well: I
> tested it and testsuite-wise seems essentially equivalent to what I posted
> yesterday, besides a slightly worse error-recovery for the first issue in
> cpp1z/decomp16.C: an additional 'no match for ‘operator=’' error.
>
> Thanks!
> Paolo.
>
> //
>


Re: [C++ Patch] PR 84588 ("[8 Regression] internal compiler error: Segmentation fault (contains_struct_check())")​ (Take 2)

2018-05-21 Thread Paolo Carlini

Hi again,

On 19/05/2018 15:30, Jason Merrill wrote:

How about doing cp_parser_commit_to_tentative_parse if we see
something that must be a declaration?  cp_parser_simple_declaration
has

   /* If we have seen at least one decl-specifier, and the next token
  is not a parenthesis, then we must be looking at a declaration.
  (After "int (" we might be looking at a functional cast.)  */
   if (decl_specifiers.any_specifiers_p
   && cp_lexer_next_token_is_not (parser->lexer, CPP_OPEN_PAREN)
   && cp_lexer_next_token_is_not (parser->lexer, CPP_OPEN_BRACE)
   && !cp_parser_error_occurred (parser))
 cp_parser_commit_to_tentative_parse (parser);

That seems useful here, as well.  Maybe factored into a separate function.
The below implements this new idea, which indeed appears to work well: I 
tested it and testsuite-wise seems essentially equivalent to what I 
posted yesterday, besides a slightly worse error-recovery for the first 
issue in cpp1z/decomp16.C: an additional 'no match for ‘operator=’' error.


Thanks!
Paolo.

//

Index: cp/parser.c
===
--- cp/parser.c (revision 260402)
+++ cp/parser.c (working copy)
@@ -11527,6 +11527,53 @@ cp_parser_selection_statement (cp_parser* parser,
 }
 }
 
+/* Helper function for cp_parser_condition and cp_parser_simple_declaration.
+   If we have seen at least one decl-specifier, and the next token
+   is not a parenthesis, then we must be looking at a declaration.
+   (After "int (" we might be looking at a functional cast.)  */
+
+static bool
+cp_parser_maybe_commit_to_declaration (cp_parser* parser,
+  bool any_specifiers_p)
+{
+  if (any_specifiers_p
+  && cp_lexer_next_token_is_not (parser->lexer, CPP_OPEN_PAREN)
+  && cp_lexer_next_token_is_not (parser->lexer, CPP_OPEN_BRACE)
+  && !cp_parser_error_occurred (parser))
+{
+  cp_parser_commit_to_tentative_parse (parser);
+  return true;
+}
+  return false;
+}
+
+/* Helper function for cp_parser_condition.  Enforces [stmt.stmt]/2:
+   The declarator shall not specify a function or an array.  Returns
+   TRUE if the declarator is valid, FALSE otherwise.  */
+
+static bool
+cp_parser_check_condition_declarator (cp_parser* parser,
+ cp_declarator *declarator,
+ location_t loc)
+{
+  if (function_declarator_p (declarator)
+  || declarator->kind == cdk_array)
+{
+  if (declarator->kind == cdk_array)
+   error_at (loc, "condition declares an array");
+  else
+   error_at (loc, "condition declares a function");
+  if (parser->fully_implicit_function_template_p)
+   abort_fully_implicit_template (parser);
+  cp_parser_skip_to_closing_parenthesis (parser, /*recovering=*/true,
+/*or_comma=*/false,
+/*consume_paren=*/false);
+  return false;
+}
+  else
+return true;
+}
+
 /* Parse a condition.
 
condition:
@@ -11563,6 +11610,10 @@ cp_parser_condition (cp_parser* parser)
&declares_class_or_enum);
   /* Restore the saved message.  */
   parser->type_definition_forbidden_message = saved_message;
+
+  cp_parser_maybe_commit_to_declaration (parser,
+type_specifiers.any_specifiers_p);
+
   /* If all is well, we might be looking at a declaration.  */
   if (!cp_parser_error_occurred (parser))
 {
@@ -11571,6 +11622,7 @@ cp_parser_condition (cp_parser* parser)
   tree attributes;
   cp_declarator *declarator;
   tree initializer = NULL_TREE;
+  location_t loc = cp_lexer_peek_token (parser->lexer)->location;
 
   /* Parse the declarator.  */
   declarator = cp_parser_declarator (parser, CP_PARSER_DECLARATOR_NAMED,
@@ -11601,6 +11653,9 @@ cp_parser_condition (cp_parser* parser)
  bool non_constant_p;
  int flags = LOOKUP_ONLYCONVERTING;
 
+ if (!cp_parser_check_condition_declarator (parser, declarator, loc))
+   return error_mark_node;
+
  /* Create the declaration.  */
  decl = start_decl (declarator, &type_specifiers,
 /*initialized_p=*/true,
@@ -11614,12 +11669,18 @@ cp_parser_condition (cp_parser* parser)
  CONSTRUCTOR_IS_DIRECT_INIT (initializer) = 1;
  flags = 0;
}
- else
+ else if (cp_lexer_next_token_is (parser->lexer, CPP_EQ))
{
  /* Consume the `='.  */
- cp_parser_require (parser, CPP_EQ, RT_EQ);
- initializer = cp_parser_initializer_clause (parser, 
&non_constant_p);
+ cp_lexer_consume_token (parser->lexer);
+ initializer = cp_parser_initializer_clause (parser,
+ &non_constant_p);
}
+

Re: [C++ Patch] PR 84588 ("[8 Regression] internal compiler error: Segmentation fault (contains_struct_check())")​ (Take 2)

2018-05-20 Thread Paolo Carlini

Hi,

On 19/05/2018 15:30, Jason Merrill wrote:

I would expect it to cause different diagnostic issues, from
complaining about something not being a proper declaration when it's
really an expression.  I also wonder about warning problems (either
missed or bogus) due to trying these in a different order.
Yes. It seems kind of science-fiction project ;) I'll give it more 
thought, anyway...

How about doing cp_parser_commit_to_tentative_parse if we see
something that must be a declaration?  cp_parser_simple_declaration
has

   /* If we have seen at least one decl-specifier, and the next token
  is not a parenthesis, then we must be looking at a declaration.
  (After "int (" we might be looking at a functional cast.)  */
   if (decl_specifiers.any_specifiers_p
   && cp_lexer_next_token_is_not (parser->lexer, CPP_OPEN_PAREN)
   && cp_lexer_next_token_is_not (parser->lexer, CPP_OPEN_BRACE)
   && !cp_parser_error_occurred (parser))
 cp_parser_commit_to_tentative_parse (parser);

That seems useful here, as well.  Maybe factored into a separate function.
Hmm, I see, thanks for the tip. To other day, eventually I figured out 
the below and fully tested it, which seems quite good to me, frankly: it 
simply adds a check of parenthesized_p (per your highly welcome previous 
clarification) to the existing checks: having spent quite a bit of time 
on [dcl.ambig.res] I think it's Ok - if the declarator isn't 
parenthesized can't be in fact an expression - and alone that allows us 
to make very good progress - well beyond the requirements of c++/84588 - 
on a number of diagnostic-quality fronts, see the attached additional 
testcases too. I can still construct a nasty condition of the form, say, 
'a (a(int auto)JUNK' which we don't handle well in terms of error 
recovery, but if you agree that the below is correct, it's probably 
enough for the *regression* part...


Thanks!
Paolo.

/
Index: cp/parser.c
===
--- cp/parser.c (revision 260402)
+++ cp/parser.c (working copy)
@@ -11527,6 +11527,33 @@ cp_parser_selection_statement (cp_parser* parser,
 }
 }
 
+/* Helper function for cp_parser_condition.  Enforces [stmt.stmt]/2:
+   The declarator shall not specify a function or an array.  Returns
+   TRUE if the declarator is valid, FALSE otherwise.  */
+
+static bool
+cp_parser_check_condition_declarator (cp_parser* parser,
+ cp_declarator *declarator,
+ location_t loc)
+{
+  if (function_declarator_p (declarator)
+  || declarator->kind == cdk_array)
+{
+  if (declarator->kind == cdk_array)
+   error_at (loc, "condition declares an array");
+  else
+   error_at (loc, "condition declares a function");
+  if (parser->fully_implicit_function_template_p)
+   abort_fully_implicit_template (parser);
+  cp_parser_skip_to_closing_parenthesis (parser, /*recovering=*/true,
+/*or_comma=*/false,
+/*consume_paren=*/false);
+  return false;
+}
+  else
+return true;
+}
+
 /* Parse a condition.
 
condition:
@@ -11571,11 +11598,13 @@ cp_parser_condition (cp_parser* parser)
   tree attributes;
   cp_declarator *declarator;
   tree initializer = NULL_TREE;
+  bool parenthesized_p = false;
+  location_t loc = cp_lexer_peek_token (parser->lexer)->location;
 
   /* Parse the declarator.  */
   declarator = cp_parser_declarator (parser, CP_PARSER_DECLARATOR_NAMED,
 /*ctor_dtor_or_conv_p=*/NULL,
-/*parenthesized_p=*/NULL,
+&parenthesized_p,
 /*member_p=*/false,
 /*friend_p=*/false);
   /* Parse the attributes.  */
@@ -11582,8 +11611,9 @@ cp_parser_condition (cp_parser* parser)
   attributes = cp_parser_attributes_opt (parser);
   /* Parse the asm-specification.  */
   asm_specification = cp_parser_asm_specification_opt (parser);
-  /* If the next token is not an `=' or '{', then we might still be
-looking at an expression.  For example:
+  /* If the next token is not an `=' or '{' and the declarator is
+parenthesized, then we might still be looking at an expression.
+For example:
 
   if (A(a).x)
 
@@ -11590,11 +11620,12 @@ cp_parser_condition (cp_parser* parser)
 looks like a decl-specifier-seq and a declarator -- but then
 there is no `=', so this is an expression.  */
   if (cp_lexer_next_token_is_not (parser->lexer, CPP_EQ)
- && cp_lexer_next_token_is_not (parser->lexer, CPP_OPEN_BRACE))
+ && cp_lexer_next_token_is_not (parser->lexer, CPP_OPEN_BRACE)
+ && parenthesized_p)
cp_parser_simulate_error (p

Re: [C++ Patch] PR 84588 ("[8 Regression] internal compiler error: Segmentation fault (contains_struct_check())")​ (Take 2)

2018-05-19 Thread Jason Merrill
On Fri, May 18, 2018 at 8:27 PM, Paolo Carlini  wrote:
> On 19/05/2018 01:40, Jason Merrill wrote:
>> On Fri, May 18, 2018 at 1:40 PM, Paolo Carlini 
>> wrote:
>>>
>>> Hi again,
>>>
>>> I'm playing with a wild, wild idea: would it make sense to try *first* an
>>> expression? Because, a quickly hacked draft appears to handle very
>>> elegantly
>>> all the possible cases of "junk" after the declarator, eg:
>>>
>>>  void foo()
>>>  {
>>>  if (void bar()JUNK);
>>>   }
>>>
>>> and the parenthesized case, etc, etc. Before trying to seriously work on
>>> that I wanted to ask...
>>
>> We'd need to try parsing as a declaration whether or not parsing as an
>> expression works, since any ambiguous cases are treated as
>> declarations [stmt.ambig].
>
> Yeah, that complicates the implementation of my idea. However, I'm thinking
> that at least *in the specific case of cp_parse_condition* from the
> computational complexity point of view probably we wouldn't regress much,
> because declarations are rare anyway, thus in most of the cases we end up
> doing both anyway. If we do expressions first and we save the result, then I
> believe when we can handle the declarator as something which cannot be a
> function or an array even if we don't see the initializer much more easily,
> we easily have a better diagnostic for things like
>
> if (int x);
>
> (another case we currently handle pretty badly, we don't talk about the
> missing initializer at all!), we cope elegantly with any junk following the
> wrong function/array declaration, etc. See that attached, if you are
> curious, which essentially passes the testsuite modulo a nit (*) which
> doesn't have anything to do with [stmt.ambig] per se (which of course is
> *not* correctly implemented in the wip).
>
> Can you give me your opinion about the more detailed idea, in particular
> whether we already have good infrastructure to implement [stmt.ambig] in
> this context, thus to keep the first parsing as an expression around,
> possibly returning to it if the parsing as a declaration fails??

I would expect it to cause different diagnostic issues, from
complaining about something not being a proper declaration when it's
really an expression.  I also wonder about warning problems (either
missed or bogus) due to trying these in a different order.

How about doing cp_parser_commit_to_tentative_parse if we see
something that must be a declaration?  cp_parser_simple_declaration
has

  /* If we have seen at least one decl-specifier, and the next token
 is not a parenthesis, then we must be looking at a declaration.
 (After "int (" we might be looking at a functional cast.)  */
  if (decl_specifiers.any_specifiers_p
  && cp_lexer_next_token_is_not (parser->lexer, CPP_OPEN_PAREN)
  && cp_lexer_next_token_is_not (parser->lexer, CPP_OPEN_BRACE)
  && !cp_parser_error_occurred (parser))
cp_parser_commit_to_tentative_parse (parser);

That seems useful here, as well.  Maybe factored into a separate function.

Jason


Re: [C++ Patch] PR 84588 ("[8 Regression] internal compiler error: Segmentation fault (contains_struct_check())")​ (Take 2)

2018-05-18 Thread Paolo Carlini

Hi,

On 19/05/2018 01:40, Jason Merrill wrote:

On Fri, May 18, 2018 at 1:40 PM, Paolo Carlini  wrote:

Hi again,

I'm playing with a wild, wild idea: would it make sense to try *first* an
expression? Because, a quickly hacked draft appears to handle very elegantly
all the possible cases of "junk" after the declarator, eg:

 void foo()
 {
 if (void bar()JUNK);
  }

and the parenthesized case, etc, etc. Before trying to seriously work on
that I wanted to ask...

We'd need to try parsing as a declaration whether or not parsing as an
expression works, since any ambiguous cases are treated as
declarations [stmt.ambig].
Yeah, that complicates the implementation of my idea. However, I'm 
thinking that at least *in the specific case of cp_parse_condition* from 
the computational complexity point of view probably we wouldn't regress 
much, because declarations are rare anyway, thus in most of the cases we 
end up doing both anyway. If we do expressions first and we save the 
result, then I believe when we can handle the declarator as something 
which cannot be a function or an array even if we don't see the 
initializer much more easily, we easily have a better diagnostic for 
things like


    if (int x);

(another case we currently handle pretty badly, we don't talk about the 
missing initializer at all!), we cope elegantly with any junk following 
the wrong function/array declaration, etc. See that attached, if you are 
curious, which essentially passes the testsuite modulo a nit (*) which 
doesn't have anything to do with [stmt.ambig] per se (which of course is 
*not* correctly implemented in the wip).


Can you give me your opinion about the more detailed idea, in particular 
whether we already have good infrastructure to implement [stmt.ambig] in 
this context, thus to keep the first parsing as an expression around, 
possibly returning to it if the parsing as a declaration fails??


I hope I'm making sense, it's again late here... in any case the wip 
patch I did much earlier today ;)


Paolo.

(*) Has to do with David's access failure hint not handling deferred 
access checks (accessor-fixits-6.C).
Index: parser.c
===
--- parser.c(revision 260347)
+++ parser.c(working copy)
@@ -11527,6 +11527,33 @@ cp_parser_selection_statement (cp_parser* parser,
 }
 }
 
+/* Helper function for cp_parser_condition.  Enforces [stmt.stmt]/2:
+   The declarator shall not specify a function or an array.  Returns
+   TRUE if the declarator is valid, FALSE otherwise.  */
+
+static bool
+cp_parser_check_condition_declarator (cp_parser* parser,
+ cp_declarator *declarator,
+ location_t loc)
+{
+  if (function_declarator_p (declarator)
+  || declarator->kind == cdk_array)
+{
+  if (declarator->kind == cdk_array)
+   error_at (loc, "condition declares an array");
+  else
+   error_at (loc, "condition declares a function");
+  if (parser->fully_implicit_function_template_p)
+   abort_fully_implicit_template (parser);
+  cp_parser_skip_to_closing_parenthesis (parser, /*recovering=*/true,
+/*or_comma=*/false,
+/*consume_paren=*/false);
+  return false;
+}
+  else
+return true;
+}
+
 /* Parse a condition.
 
condition:
@@ -11545,12 +11572,20 @@ cp_parser_selection_statement (cp_parser* parser,
 static tree
 cp_parser_condition (cp_parser* parser)
 {
+  cp_parser_parse_tentatively (parser);
+
+  /* Try the expression first.  */
+  tree expr = cp_parser_expression (parser);
+
+  if (cp_parser_parse_definitely (parser))
+return expr;
+
+  cp_parser_parse_tentatively (parser);
+
   cp_decl_specifier_seq type_specifiers;
   const char *saved_message;
   int declares_class_or_enum;
 
-  /* Try the declaration first.  */
-  cp_parser_parse_tentatively (parser);
   /* New types are not allowed in the type-specifier-seq for a
  condition.  */
   saved_message = parser->type_definition_forbidden_message;
@@ -11563,6 +11598,7 @@ cp_parser_condition (cp_parser* parser)
&declares_class_or_enum);
   /* Restore the saved message.  */
   parser->type_definition_forbidden_message = saved_message;
+
   /* If all is well, we might be looking at a declaration.  */
   if (!cp_parser_error_occurred (parser))
 {
@@ -11570,7 +11606,8 @@ cp_parser_condition (cp_parser* parser)
   tree asm_specification;
   tree attributes;
   cp_declarator *declarator;
-  tree initializer = NULL_TREE;
+  tree initializer;
+  location_t loc = cp_lexer_peek_token (parser->lexer)->location;
 
   /* Parse the declarator.  */
   declarator = cp_parser_declarator (parser, CP_PARSER_DECLARATOR_NAMED,
@@ -11582,19 +11619,7 @@ cp_parser_condition (cp_parser* parser)
   attributes = cp_parser_attributes_opt

Re: [C++ Patch] PR 84588 ("[8 Regression] internal compiler error: Segmentation fault (contains_struct_check())")​ (Take 2)

2018-05-18 Thread Jason Merrill
On Fri, May 18, 2018 at 1:40 PM, Paolo Carlini  wrote:
> Hi again,
>
> I'm playing with a wild, wild idea: would it make sense to try *first* an
> expression? Because, a quickly hacked draft appears to handle very elegantly
> all the possible cases of "junk" after the declarator, eg:
>
> void foo()
> {
> if (void bar()JUNK);
>  }
>
> and the parenthesized case, etc, etc. Before trying to seriously work on
> that I wanted to ask...

We'd need to try parsing as a declaration whether or not parsing as an
expression works, since any ambiguous cases are treated as
declarations [stmt.ambig].

Jason


Re: [C++ Patch] PR 84588 ("[8 Regression] internal compiler error: Segmentation fault (contains_struct_check())")​ (Take 2)

2018-05-18 Thread Paolo Carlini

Hi again,

I'm playing with a wild, wild idea: would it make sense to try *first* 
an expression? Because, a quickly hacked draft appears to handle very 
elegantly all the possible cases of "junk" after the declarator, eg:


    void foo()
    {
        if (void bar()JUNK);
 }

and the parenthesized case, etc, etc. Before trying to seriously work on 
that I wanted to ask...


Paolo.


Re: [C++ Patch] PR 84588 ("[8 Regression] internal compiler error: Segmentation fault (contains_struct_check())")​ (Take 2)

2018-05-18 Thread Paolo Carlini

Hi,

On 18/05/2018 16:45, Jason Merrill wrote:

I guess it's desirable to also give this error when the declarator is
followed by ) or ; rather than other tokens that could be more
expression (like in A(a).x in the comment).

I can certainly try to implement this, maybe just something minimal to begin
with, as you say ) or ; alone would be safe and would already take care of
all the tests I have around.

Certainly, unconditionally deferring at that point to cp_parser_expression
leads to *very* bad error-recovery. For fun, try with 8.1.0:

 void foo()
 {
   for (;void bar(););
 }

and it gets worse.

It would also need to be only for a non-parenthesized declarator,
which can't be an expression; a parenthesized declarator can be, as in
this well-formed testcase:

bool (bar()) { return 0; } // declaration

void foo()
{
   for (;bool (bar());); // expression
}

Thanks for clarifying that. I'll make sure we have such testcases.

Interestingly, if we aren't careful about that in the new code, 
libstdc++-v3 doesn't even build, eh!


Paolo.


Re: [C++ Patch] PR 84588 ("[8 Regression] internal compiler error: Segmentation fault (contains_struct_check())")​ (Take 2)

2018-05-18 Thread Jason Merrill
On Fri, May 18, 2018 at 10:30 AM, Paolo Carlini
 wrote:
> Hi,
>
> On 18/05/2018 16:19, Jason Merrill wrote:
>>
>> On Fri, May 18, 2018 at 10:05 AM, Paolo Carlini
>>  wrote:
>>>
>>> Hi,
>>>
>>> On 18/05/2018 15:56, Jason Merrill wrote:

 I had in mind moving the call to cp_parser_check_condition_declarator
 into the block controlled by cp_parser_parse_definitely; this is a
 semantic check that should follow the syntactic checks.  If there's no
 initializer, it doesn't parse as a condition declaration, so we don't
 want to complain about it being a semantically invalid condition
 declaration.
>>>
>>> If we do that we are back to something very, very, similar to what I
>>> posted
>>> at the beginning of the thread, right? Therefore, for all the testcases
>>> which don't have an initializer we end-up with *horrible*, literally
>>> *horrible* cascades of errors, plus we ICE on the c++/84588 variants
>>> without
>>> an initializer.
>>
>> Ah.  Why is that?
>>
>> I guess it's desirable to also give this error when the declarator is
>> followed by ) or ; rather than other tokens that could be more
>> expression (like in A(a).x in the comment).
>
> I can certainly try to implement this, maybe just something minimal to begin
> with, as you say ) or ; alone would be safe and would already take care of
> all the tests I have around.
>
> Certainly, unconditionally deferring at that point to cp_parser_expression
> leads to *very* bad error-recovery. For fun, try with 8.1.0:
>
> void foo()
> {
>   for (;void bar(););
> }
>
> and it gets worse.

It would also need to be only for a non-parenthesized declarator,
which can't be an expression; a parenthesized declarator can be, as in
this well-formed testcase:

bool (bar()) { return 0; } // declaration

void foo()
{
  for (;bool (bar());); // expression
}

Jason


Re: [C++ Patch] PR 84588 ("[8 Regression] internal compiler error: Segmentation fault (contains_struct_check())")​ (Take 2)

2018-05-18 Thread Paolo Carlini

Hi,

On 18/05/2018 16:19, Jason Merrill wrote:

On Fri, May 18, 2018 at 10:05 AM, Paolo Carlini
 wrote:

Hi,

On 18/05/2018 15:56, Jason Merrill wrote:

I had in mind moving the call to cp_parser_check_condition_declarator
into the block controlled by cp_parser_parse_definitely; this is a
semantic check that should follow the syntactic checks.  If there's no
initializer, it doesn't parse as a condition declaration, so we don't
want to complain about it being a semantically invalid condition
declaration.

If we do that we are back to something very, very, similar to what I posted
at the beginning of the thread, right? Therefore, for all the testcases
which don't have an initializer we end-up with *horrible*, literally
*horrible* cascades of errors, plus we ICE on the c++/84588 variants without
an initializer.

Ah.  Why is that?

I guess it's desirable to also give this error when the declarator is
followed by ) or ; rather than other tokens that could be more
expression (like in A(a).x in the comment).
I can certainly try to implement this, maybe just something minimal to 
begin with, as you say ) or ; alone would be safe and would already take 
care of all the tests I have around.


Certainly, unconditionally deferring at that point to 
cp_parser_expression leads to *very* bad error-recovery. For fun, try 
with 8.1.0:


    void foo()
    {
      for (;void bar(););
    }

and it gets worse.

Paolo.


Re: [C++ Patch] PR 84588 ("[8 Regression] internal compiler error: Segmentation fault (contains_struct_check())")​ (Take 2)

2018-05-18 Thread Jason Merrill
On Fri, May 18, 2018 at 10:05 AM, Paolo Carlini
 wrote:
> Hi,
>
> On 18/05/2018 15:56, Jason Merrill wrote:
>>
>> I had in mind moving the call to cp_parser_check_condition_declarator
>> into the block controlled by cp_parser_parse_definitely; this is a
>> semantic check that should follow the syntactic checks.  If there's no
>> initializer, it doesn't parse as a condition declaration, so we don't
>> want to complain about it being a semantically invalid condition
>> declaration.
>
> If we do that we are back to something very, very, similar to what I posted
> at the beginning of the thread, right? Therefore, for all the testcases
> which don't have an initializer we end-up with *horrible*, literally
> *horrible* cascades of errors, plus we ICE on the c++/84588 variants without
> an initializer.

Ah.  Why is that?

I guess it's desirable to also give this error when the declarator is
followed by ) or ; rather than other tokens that could be more
expression (like in A(a).x in the comment).

Jason


Re: [C++ Patch] PR 84588 ("[8 Regression] internal compiler error: Segmentation fault (contains_struct_check())")​ (Take 2)

2018-05-18 Thread Paolo Carlini

Hi,

On 18/05/2018 15:56, Jason Merrill wrote:

I had in mind moving the call to cp_parser_check_condition_declarator
into the block controlled by cp_parser_parse_definitely; this is a
semantic check that should follow the syntactic checks.  If there's no
initializer, it doesn't parse as a condition declaration, so we don't
want to complain about it being a semantically invalid condition
declaration.
If we do that we are back to something very, very, similar to what I 
posted at the beginning of the thread, right? Therefore, for all the 
testcases which don't have an initializer we end-up with *horrible*, 
literally *horrible* cascades of errors, plus we ICE on the c++/84588 
variants without an initializer. If you like we can do that and defer 
the other related issues - strictly speaking c++/84588 would be fixed - 
to another new bug.


Paolo.


Re: [C++ Patch] PR 84588 ("[8 Regression] internal compiler error: Segmentation fault (contains_struct_check())")​ (Take 2)

2018-05-18 Thread Jason Merrill
On Fri, May 18, 2018 at 4:41 AM, Paolo Carlini  wrote:
> Hi,
>
>>> On 18/05/2018 01:21, Jason Merrill wrote:

 On Thu, May 17, 2018 at 5:54 PM, Paolo Carlini
  wrote:
>
> On 17/05/2018 16:58, Jason Merrill wrote:
>>
>> On Thu, May 17, 2018 at 10:27 AM, Paolo Carlini
>>  wrote:
>>>
>>> PS: maybe better using function_declarator_p?
>>
>> I think so, yes.  The relevant rule seems to be "The declarator shall
>> not specify a function or an array.", so let's check for arrays, too.
>
> Agreed. I had the amended patch ready when I noticed (again) that it
> wasn't
> addressing another related class of issues which involves declarators
> not
> followed by initializers. Thus I tried to fix those too, and the below
> which
> moves the check up appears to work fine, passes testing, etc. Are there
> any
> risks that an erroneous function / array as declarator is in fact a
> well
> formed expression?!?

 That doesn't matter; if it parses as a declarator, it's a declarator,
 even if it's an ill-formed declarator.  But...

 +  bool decl_p = cp_parser_parse_definitely (parser);
 +  if (!cp_parser_check_condition_declarator (parser, declarator,
 loc))
 +return error_mark_node;

 ...if cp_parser_parse_definitely returns false, parsing as a
 declarator failed, so we shouldn't look at "declarator".
>
> What I'm attaching below isn't affected by this problem: I moved the check
> further up - *before* maybe calling cp_parser_simulated_error because an
> initializer isn't in sight - and is carried out only when
> !cp_parser_error_occurred, thus cp_parser_declarator succeeded .
> cp_parser_commit_to_tentative_parse is called when the check fails.
> Bootstrapped and tested on x86_64-linux.

I had in mind moving the call to cp_parser_check_condition_declarator
into the block controlled by cp_parser_parse_definitely; this is a
semantic check that should follow the syntactic checks.  If there's no
initializer, it doesn't parse as a condition declaration, so we don't
want to complain about it being a semantically invalid condition
declaration.

Jason


Re: [C++ Patch] PR 84588 ("[8 Regression] internal compiler error: Segmentation fault (contains_struct_check())")​ (Take 2)

2018-05-18 Thread Paolo Carlini

Hi,


On 18/05/2018 01:21, Jason Merrill wrote:
On Thu, May 17, 2018 at 5:54 PM, Paolo Carlini 
 wrote:

On 17/05/2018 16:58, Jason Merrill wrote:

On Thu, May 17, 2018 at 10:27 AM, Paolo Carlini
 wrote:

PS: maybe better using function_declarator_p?

I think so, yes.  The relevant rule seems to be "The declarator shall
not specify a function or an array.", so let's check for arrays, too.
Agreed. I had the amended patch ready when I noticed (again) that 
it wasn't
addressing another related class of issues which involves 
declarators not
followed by initializers. Thus I tried to fix those too, and the 
below which
moves the check up appears to work fine, passes testing, etc. Are 
there any
risks that an erroneous function / array as declarator is in fact a 
well

formed expression?!?

That doesn't matter; if it parses as a declarator, it's a declarator,
even if it's an ill-formed declarator.  But...

+  bool decl_p = cp_parser_parse_definitely (parser);
+  if (!cp_parser_check_condition_declarator (parser, 
declarator, loc))

+    return error_mark_node;

...if cp_parser_parse_definitely returns false, parsing as a
declarator failed, so we shouldn't look at "declarator".
What I'm attaching below isn't affected by this problem: I moved the 
check further up - *before* maybe calling cp_parser_simulated_error 
because an initializer isn't in sight - and is carried out only when 
!cp_parser_error_occurred, thus cp_parser_declarator succeeded . 
cp_parser_commit_to_tentative_parse is called when the check fails. 
Bootstrapped and tested on x86_64-linux.


Thanks!
Paolo.

//
Index: cp/parser.c
===
--- cp/parser.c (revision 260347)
+++ cp/parser.c (working copy)
@@ -11527,6 +11527,34 @@ cp_parser_selection_statement (cp_parser* parser,
 }
 }
 
+/* Helper function for cp_parser_condition.  Enforces [stmt.stmt]/2:
+   The declarator shall not specify a function or an array.  Returns
+   TRUE if the declarator is valid, FALSE otherwise.  */
+
+static bool
+cp_parser_check_condition_declarator (cp_parser* parser,
+ cp_declarator *declarator,
+ location_t loc)
+{
+  if (function_declarator_p (declarator)
+  || declarator->kind == cdk_array)
+{
+  cp_parser_commit_to_tentative_parse (parser);
+  if (declarator->kind == cdk_array)
+   error_at (loc, "condition declares an array");
+  else
+   error_at (loc, "condition declares a function");
+  if (parser->fully_implicit_function_template_p)
+   abort_fully_implicit_template (parser);
+  cp_parser_skip_to_closing_parenthesis (parser, /*recovering=*/true,
+/*or_comma=*/false,
+/*consume_paren=*/false);
+  return false;
+}
+  else
+return true;
+}
+
 /* Parse a condition.
 
condition:
@@ -11571,6 +11599,7 @@ cp_parser_condition (cp_parser* parser)
   tree attributes;
   cp_declarator *declarator;
   tree initializer = NULL_TREE;
+  location_t loc = cp_lexer_peek_token (parser->lexer)->location;
 
   /* Parse the declarator.  */
   declarator = cp_parser_declarator (parser, CP_PARSER_DECLARATOR_NAMED,
@@ -11582,6 +11611,11 @@ cp_parser_condition (cp_parser* parser)
   attributes = cp_parser_attributes_opt (parser);
   /* Parse the asm-specification.  */
   asm_specification = cp_parser_asm_specification_opt (parser);
+
+  if (!cp_parser_error_occurred (parser)
+ && !cp_parser_check_condition_declarator (parser, declarator, loc))
+   return error_mark_node;
+
   /* If the next token is not an `=' or '{', then we might still be
 looking at an expression.  For example:
 
Index: testsuite/g++.dg/cpp0x/cond1.C
===
--- testsuite/g++.dg/cpp0x/cond1.C  (nonexistent)
+++ testsuite/g++.dg/cpp0x/cond1.C  (working copy)
@@ -0,0 +1,23 @@
+// PR c++/84588
+// { dg-do compile { target c++11 } }
+
+void foo()
+{
+  if (int bar() {})  // { dg-error "condition declares a function" }
+;
+
+  for (;int bar() {};)  // { dg-error "condition declares a function" }
+;
+
+  while (int bar() {})  // { dg-error "condition declares a function" }
+;
+
+  if (int a[] {})  // { dg-error "condition declares an array" }
+;
+
+  for (;int a[] {};)  // { dg-error "condition declares an array" }
+;
+
+  while (int a[] {})  // { dg-error "condition declares an array" }
+;
+}
Index: testsuite/g++.dg/cpp1y/pr84588-1.C
===
--- testsuite/g++.dg/cpp1y/pr84588-1.C  (nonexistent)
+++ testsuite/g++.dg/cpp1y/pr84588-1.C  (working copy)
@@ -0,0 +1,25 @@
+// { dg-do compile { target c++14 } }
+
+struct a {
+  void b() {}
+  void c(void (*) () = [] {
+  if (a a(int auto) {})  // { dg-err

Re: [C++ Patch] PR 84588 ("[8 Regression] internal compiler error: Segmentation fault (contains_struct_check())")​ (Take 2)

2018-05-17 Thread Paolo Carlini

Hi again,

On 18/05/2018 02:31, Paolo Carlini wrote:

Hi,

On 18/05/2018 01:21, Jason Merrill wrote:
On Thu, May 17, 2018 at 5:54 PM, Paolo Carlini 
 wrote:

On 17/05/2018 16:58, Jason Merrill wrote:

On Thu, May 17, 2018 at 10:27 AM, Paolo Carlini
 wrote:

PS: maybe better using function_declarator_p?

I think so, yes.  The relevant rule seems to be "The declarator shall
not specify a function or an array.", so let's check for arrays, too.
Agreed. I had the amended patch ready when I noticed (again) that it 
wasn't
addressing another related class of issues which involves 
declarators not
followed by initializers. Thus I tried to fix those too, and the 
below which
moves the check up appears to work fine, passes testing, etc. Are 
there any
risks that an erroneous function / array as declarator is in fact a 
well

formed expression?!?

That doesn't matter; if it parses as a declarator, it's a declarator,
even if it's an ill-formed declarator.  But...

+  bool decl_p = cp_parser_parse_definitely (parser);
+  if (!cp_parser_check_condition_declarator (parser, declarator, 
loc))

+    return error_mark_node;

...if cp_parser_parse_definitely returns false, parsing as a
declarator failed, so we shouldn't look at "declarator".
Uhm, then you are saying that we should fix cp_parser_declarator 
itself, right? Because we don't want cp_parser_parse_definitely 
returning false after cp_parser_declarator parses, say, 'if (int 
foo())' and therefore cp_parser_condition proceed with 
cp_parser_expression, we want to emit our error and bail out. 
Therefore the problem in the new patch seems that it tries to paper 
over that cp_parser_declarator issue in the caller?!? Like, Ok, 
cp_parser_declarator failed, but it was anyway trying to declare a 
function / array and that can't possibly be an expression, see what I 
mean? *Somehow*, the question you answered above.
Ok, now I finally see what's the exact issue you pointed out (I'm a bit 
tired). Seems fixable.


If I understand correctly, the reason why the 3 lines you cited above 
are wrong as they are is that my patch *assumes* that 
cp_parser_declarator didn't really fail and cp_parser_condition has 
forced the tentative parse to fail by calling cp_parser_simulate_error 
immediately before when it didn't see an initializer immediately 
following. That's actually true for 'if (int foo())', thus it makes 
sense to check the declarator anyway for such cases *even* if 
cp_parser_parse_definitely returns false. See what I mean?


Therefore, it seems to me that an amended patch would rearrange 
cp_parser_condition to *not* call cp_parser_simulate_error for the cases 
we care about ('if (int foo())') and instead check the declarator.


I'll work on that tomorrow...

Thanks,
Paolo.



Re: [C++ Patch] PR 84588 ("[8 Regression] internal compiler error: Segmentation fault (contains_struct_check())")​ (Take 2)

2018-05-17 Thread Paolo Carlini

Hi,

On 18/05/2018 01:21, Jason Merrill wrote:

On Thu, May 17, 2018 at 5:54 PM, Paolo Carlini  wrote:

On 17/05/2018 16:58, Jason Merrill wrote:

On Thu, May 17, 2018 at 10:27 AM, Paolo Carlini
 wrote:

PS: maybe better using function_declarator_p?

I think so, yes.  The relevant rule seems to be "The declarator shall
not specify a function or an array.", so let's check for arrays, too.

Agreed. I had the amended patch ready when I noticed (again) that it wasn't
addressing another related class of issues which involves declarators not
followed by initializers. Thus I tried to fix those too, and the below which
moves the check up appears to work fine, passes testing, etc. Are there any
risks that an erroneous function / array as declarator is in fact a well
formed expression?!?

That doesn't matter; if it parses as a declarator, it's a declarator,
even if it's an ill-formed declarator.  But...

+  bool decl_p = cp_parser_parse_definitely (parser);
+  if (!cp_parser_check_condition_declarator (parser, declarator, loc))
+return error_mark_node;

...if cp_parser_parse_definitely returns false, parsing as a
declarator failed, so we shouldn't look at "declarator".
Uhm, then you are saying that we should fix cp_parser_declarator itself, 
right? Because we don't want cp_parser_parse_definitely returning false 
after cp_parser_declarator parses, say, 'if (int foo())' and therefore 
cp_parser_condition proceed with cp_parser_expression, we want to emit 
our error and bail out. Therefore the problem in the new patch seems 
that it tries to paper over that cp_parser_declarator issue in the 
caller?!? Like, Ok, cp_parser_declarator failed, but it was anyway 
trying to declare a function / array and that can't possibly be an 
expression, see what I mean? *Somehow*, the question you answered above.


Paolo.


Re: [C++ Patch] PR 84588 ("[8 Regression] internal compiler error: Segmentation fault (contains_struct_check())")​ (Take 2)

2018-05-17 Thread Jason Merrill
On Thu, May 17, 2018 at 5:54 PM, Paolo Carlini  wrote:
> On 17/05/2018 16:58, Jason Merrill wrote:
>>
>> On Thu, May 17, 2018 at 10:27 AM, Paolo Carlini
>>  wrote:
>>>
>>> PS: maybe better using function_declarator_p?
>>
>> I think so, yes.  The relevant rule seems to be "The declarator shall
>> not specify a function or an array.", so let's check for arrays, too.
>
> Agreed. I had the amended patch ready when I noticed (again) that it wasn't
> addressing another related class of issues which involves declarators not
> followed by initializers. Thus I tried to fix those too, and the below which
> moves the check up appears to work fine, passes testing, etc. Are there any
> risks that an erroneous function / array as declarator is in fact a well
> formed expression?!?

That doesn't matter; if it parses as a declarator, it's a declarator,
even if it's an ill-formed declarator.  But...

+  bool decl_p = cp_parser_parse_definitely (parser);
+  if (!cp_parser_check_condition_declarator (parser, declarator, loc))
+return error_mark_node;

...if cp_parser_parse_definitely returns false, parsing as a
declarator failed, so we shouldn't look at "declarator".

Also, "here" in the diagnostic seems unnecessarily vague; we could be
more specific.  Maybe "condition declares a function/array"?

Jason


Re: [C++ Patch] PR 84588 ("[8 Regression] internal compiler error: Segmentation fault (contains_struct_check())")​ (Take 2)

2018-05-17 Thread Paolo Carlini

Hi,

On 17/05/2018 16:58, Jason Merrill wrote:

On Thu, May 17, 2018 at 10:27 AM, Paolo Carlini
 wrote:

PS: maybe better using function_declarator_p?

I think so, yes.  The relevant rule seems to be "The declarator shall
not specify a function or an array.", so let's check for arrays, too.
Agreed. I had the amended patch ready when I noticed (again) that it 
wasn't addressing another related class of issues which involves 
declarators not followed by initializers. Thus I tried to fix those too, 
and the below which moves the check up appears to work fine, passes 
testing, etc. Are there any risks that an erroneous function / array as 
declarator is in fact a well formed expression?!? I haven't been able so 
far to construct examples...


Thanks!
Paolo.


Index: cp/parser.c
===
--- cp/parser.c (revision 260331)
+++ cp/parser.c (working copy)
@@ -11527,6 +11527,33 @@ cp_parser_selection_statement (cp_parser* parser,
 }
 }
 
+/* Helper function for cp_parser_condition.  Enforces [stmt.stmt]:
+   The declarator shall not specify a function or an array.  Returns
+   TRUE is the declator is valid, FALSE otherwise.  */
+
+static bool
+cp_parser_check_condition_declarator (cp_parser* parser,
+ cp_declarator *declarator,
+ location_t loc)
+{
+  if (function_declarator_p (declarator)
+  || declarator->kind == cdk_array)
+{
+  if (declarator->kind == cdk_array)
+   error_at (loc, "an array type is not allowed here");
+  else
+   error_at (loc, "a function type is not allowed here");
+  if (parser->fully_implicit_function_template_p)
+   abort_fully_implicit_template (parser);
+  cp_parser_skip_to_closing_parenthesis (parser, /*recovering=*/true,
+/*or_comma=*/false,
+/*consume_paren=*/false);
+  return false;
+}
+  else
+return true;
+}
+
 /* Parse a condition.
 
condition:
@@ -11571,6 +11598,7 @@ cp_parser_condition (cp_parser* parser)
   tree attributes;
   cp_declarator *declarator;
   tree initializer = NULL_TREE;
+  location_t loc = cp_lexer_peek_token (parser->lexer)->location;
 
   /* Parse the declarator.  */
   declarator = cp_parser_declarator (parser, CP_PARSER_DECLARATOR_NAMED,
@@ -11592,10 +11620,15 @@ cp_parser_condition (cp_parser* parser)
   if (cp_lexer_next_token_is_not (parser->lexer, CPP_EQ)
  && cp_lexer_next_token_is_not (parser->lexer, CPP_OPEN_BRACE))
cp_parser_simulate_error (parser);
-   
+
   /* If we did see an `=' or '{', then we are looking at a declaration
 for sure.  */
-  if (cp_parser_parse_definitely (parser))
+  bool decl_p = cp_parser_parse_definitely (parser);
+
+  if (!cp_parser_check_condition_declarator (parser, declarator, loc))
+   return error_mark_node;
+
+  if (decl_p)
{
  tree pushed_scope;
  bool non_constant_p;
Index: testsuite/g++.dg/cpp0x/cond1.C
===
--- testsuite/g++.dg/cpp0x/cond1.C  (nonexistent)
+++ testsuite/g++.dg/cpp0x/cond1.C  (working copy)
@@ -0,0 +1,23 @@
+// PR c++/84588
+// { dg-do compile { target c++11 } }
+
+void foo()
+{
+  if (int bar() {})  // { dg-error "function type is not allowed" }
+;
+
+  for (;int bar() {};)  // { dg-error "function type is not allowed" }
+;
+
+  while (int bar() {})  // { dg-error "function type is not allowed" }
+;
+
+  if (int a[] {})  // { dg-error "array type is not allowed" }
+;
+
+  for (;int a[] {};)  // { dg-error "array type is not allowed" }
+;
+
+  while (int a[] {})  // { dg-error "array type is not allowed" }
+;
+}
Index: testsuite/g++.dg/cpp1y/pr84588-1.C
===
--- testsuite/g++.dg/cpp1y/pr84588-1.C  (nonexistent)
+++ testsuite/g++.dg/cpp1y/pr84588-1.C  (working copy)
@@ -0,0 +1,25 @@
+// { dg-do compile { target c++14 } }
+
+struct a {
+  void b() {}
+  void c(void (*) () = [] {
+  if (a a(int auto) {})  // { dg-error "two or more data types|function 
type" }
+  ;
+  }) {}
+};
+
+struct d {
+  void e() {}
+  void f(void (*) () = [] {
+  for (;d d(int auto) {};)  // { dg-error "two or more data types|function 
type" }
+  ;
+  }) {}
+};
+
+struct g {
+  void h() {}
+  void i(void (*) () = [] {
+  while (g g(int auto) {})  // { dg-error "two or more data types|function 
type" }
+  ;
+  }) {}
+};
Index: testsuite/g++.dg/cpp1y/pr84588-2.C
===
--- testsuite/g++.dg/cpp1y/pr84588-2.C  (nonexistent)
+++ testsuite/g++.dg/cpp1y/pr84588-2.C  (working copy)
@@ -0,0 +1,25 @@
+// { dg-do compile { target c++14 } }
+
+struct a {
+  void b() {}
+  void c(void (*) () = [] {
+  if

Re: [C++ Patch] PR 84588 ("[8 Regression] internal compiler error: Segmentation fault (contains_struct_check())")​ (Take 2)

2018-05-17 Thread Jason Merrill
On Thu, May 17, 2018 at 10:27 AM, Paolo Carlini
 wrote:
> PS: maybe better using function_declarator_p?

I think so, yes.  The relevant rule seems to be "The declarator shall
not specify a function or an array.", so let's check for arrays, too.

Jason


Re: [C++ Patch] PR 84588 ("[8 Regression] internal compiler error: Segmentation fault (contains_struct_check())")​ (Take 2)

2018-05-17 Thread Paolo Carlini
PS: maybe better using function_declarator_p??? I think I regression 
tested that variant too, at some point.


Paolo.