Re: [PATCH] c++: Fix parsing of abstract-declarator starting with ... followed by [ or ( [PR115012]

2024-05-24 Thread Jason Merrill

On 5/9/24 14:12, Jakub Jelinek wrote:


The C++26 P2662R3 Pack indexing paper mentions that both GCC
and MSVC don't handle T...[10] parameter declaration when T
is a pack.  While that will change meaning in C++26, in C++11 .. C++23
this ought to be valid.


Sure, but I don't think it does anyone any favors to start accepting a 
pattern that we know is going to break before long.  Us not accepting it 
was part of the rationale for the paper.



Also, T...(args) as well.


This part of the patch is OK.


The following patch handles those in cp_parser_direct_declarator.

Bootstrapped/regtested on x86_64-linux and i686-linux, ok for trunk?

2024-05-09  Jakub Jelinek  

PR c++/115012
* parser.cc (cp_parser_direct_declarator): Handle
abstract declarator starting with ... followed by [
or (.

* g++.dg/cpp0x/variadic185.C: New test.
* g++.dg/cpp0x/variadic186.C: New test.

--- gcc/cp/parser.cc.jj 2024-05-09 10:30:58.0 +0200
+++ gcc/cp/parser.cc2024-05-09 16:44:01.250777325 +0200
@@ -23916,7 +23916,12 @@ cp_parser_direct_declarator (cp_parser*
  {
/* Peek at the next token.  */
token = cp_lexer_peek_token (parser->lexer);
-  if (token->type == CPP_OPEN_PAREN)
+  if (token->type == CPP_OPEN_PAREN
+ || (first
+ && dcl_kind != CP_PARSER_DECLARATOR_NAMED
+ && token->type == CPP_ELLIPSIS
+ && cxx_dialect > cxx98
+ && cp_lexer_nth_token_is (parser->lexer, 2, CPP_OPEN_PAREN)))
{
  /* This is either a parameter-declaration-clause, or a
 parenthesized declarator. When we know we are parsing a
@@ -23955,6 +23960,11 @@ cp_parser_direct_declarator (cp_parser*
  
  	 Thus again, we try a parameter-declaration-clause, and if

 that fails, we back out and return.  */
+ bool pack_expansion_p = token->type == CPP_ELLIPSIS;
+
+ if (pack_expansion_p)
+   /* Consume the `...' */
+   cp_lexer_consume_token (parser->lexer);
  
  	  if (!first || dcl_kind != CP_PARSER_DECLARATOR_NAMED)

{
@@ -24098,6 +24108,7 @@ cp_parser_direct_declarator (cp_parser*
 attrs,
 parens_loc);
  declarator->attributes = gnu_attrs;
+ declarator->parameter_pack_p |= pack_expansion_p;
  /* Any subsequent parameter lists are to do with
 return type, so are not those of the declared
 function.  */
@@ -24121,7 +24132,7 @@ cp_parser_direct_declarator (cp_parser*
  
  	  /* If this is the first, we can try a parenthesized

 declarator.  */
- if (first)
+ if (first && !pack_expansion_p)
{
  bool saved_in_type_id_in_expr_p;
  
@@ -24156,16 +24167,27 @@ cp_parser_direct_declarator (cp_parser*

  else
break;
}
-  else if ((!first || dcl_kind != CP_PARSER_DECLARATOR_NAMED)
-  && token->type == CPP_OPEN_SQUARE
-  && !cp_next_tokens_can_be_attribute_p (parser))
+  else if (((!first || dcl_kind != CP_PARSER_DECLARATOR_NAMED)
+   && token->type == CPP_OPEN_SQUARE
+   && !cp_next_tokens_can_be_attribute_p (parser))
+  || (first
+  && dcl_kind != CP_PARSER_DECLARATOR_NAMED
+  && token->type == CPP_ELLIPSIS
+  && cp_lexer_nth_token_is (parser->lexer, 2, CPP_OPEN_SQUARE)
+  && cxx_dialect > cxx98
+  && !cp_nth_tokens_can_be_std_attribute_p (parser, 2)))
{
  /* Parse an array-declarator.  */
  tree bounds, attrs;
+ bool pack_expansion_p = token->type == CPP_ELLIPSIS;
  
  	  if (ctor_dtor_or_conv_p)

*ctor_dtor_or_conv_p = 0;
  
+	  if (pack_expansion_p)

+   /* Consume the `...' */
+   cp_lexer_consume_token (parser->lexer);
+
  open_paren = NULL;
  first = false;
  parser->default_arg_ok_p = false;
@@ -24220,6 +24242,7 @@ cp_parser_direct_declarator (cp_parser*
  attrs = cp_parser_std_attribute_spec_seq (parser);
  declarator = make_array_declarator (declarator, bounds);
  declarator->std_attributes = attrs;
+ declarator->parameter_pack_p |= pack_expansion_p;
}
else if (first && dcl_kind != CP_PARSER_DECLARATOR_ABSTRACT)
{
--- gcc/testsuite/g++.dg/cpp0x/variadic185.C.jj 2024-05-09 15:08:49.070651189 
+0200
+++ gcc/testsuite/g++.dg/cpp0x/variadic185.C2024-05-09 15:07:40.045583153 
+0200
@@ -0,0 +1,39 @@
+// PR c++/115012
+// { dg-do compile { target { c++11 && c++23_down } } }
+// { dg-final { scan-assembler "_Z3fooILi10EJidEEvDpAT__T0_" } }
+// { dg-final { scan-assembler "_Z3barILi10EiEvPT0_" } }
+// { dg-final { scan-assembler "_Z3bazILi10EJidEEvDpAT__T0_" } }
+// { dg-final { scan-assembler "_

C++ Patch ping - Re: [PATCH] c++: Fix parsing of abstract-declarator starting with ... followed by [ or ( [PR115012]

2024-05-16 Thread Jakub Jelinek
Hi!

I'd like to ping the 
https://gcc.gnu.org/pipermail/gcc-patches/2024-May/651199.html
patch.

Thanks.

On Thu, May 09, 2024 at 08:12:30PM +0200, Jakub Jelinek wrote:
> The C++26 P2662R3 Pack indexing paper mentions that both GCC
> and MSVC don't handle T...[10] parameter declaration when T
> is a pack.  While that will change meaning in C++26, in C++11 .. C++23
> this ought to be valid.  Also, T...(args) as well.
> 
> The following patch handles those in cp_parser_direct_declarator.
> 
> Bootstrapped/regtested on x86_64-linux and i686-linux, ok for trunk?
> 
> 2024-05-09  Jakub Jelinek  
> 
>   PR c++/115012
>   * parser.cc (cp_parser_direct_declarator): Handle
>   abstract declarator starting with ... followed by [
>   or (.
> 
>   * g++.dg/cpp0x/variadic185.C: New test.
>   * g++.dg/cpp0x/variadic186.C: New test.

Jakub



[PATCH] c++: Fix parsing of abstract-declarator starting with ... followed by [ or ( [PR115012]

2024-05-09 Thread Jakub Jelinek
Hi!

The C++26 P2662R3 Pack indexing paper mentions that both GCC
and MSVC don't handle T...[10] parameter declaration when T
is a pack.  While that will change meaning in C++26, in C++11 .. C++23
this ought to be valid.  Also, T...(args) as well.

The following patch handles those in cp_parser_direct_declarator.

Bootstrapped/regtested on x86_64-linux and i686-linux, ok for trunk?

2024-05-09  Jakub Jelinek  

PR c++/115012
* parser.cc (cp_parser_direct_declarator): Handle
abstract declarator starting with ... followed by [
or (.

* g++.dg/cpp0x/variadic185.C: New test.
* g++.dg/cpp0x/variadic186.C: New test.

--- gcc/cp/parser.cc.jj 2024-05-09 10:30:58.0 +0200
+++ gcc/cp/parser.cc2024-05-09 16:44:01.250777325 +0200
@@ -23916,7 +23916,12 @@ cp_parser_direct_declarator (cp_parser*
 {
   /* Peek at the next token.  */
   token = cp_lexer_peek_token (parser->lexer);
-  if (token->type == CPP_OPEN_PAREN)
+  if (token->type == CPP_OPEN_PAREN
+ || (first
+ && dcl_kind != CP_PARSER_DECLARATOR_NAMED
+ && token->type == CPP_ELLIPSIS
+ && cxx_dialect > cxx98
+ && cp_lexer_nth_token_is (parser->lexer, 2, CPP_OPEN_PAREN)))
{
  /* This is either a parameter-declaration-clause, or a
 parenthesized declarator. When we know we are parsing a
@@ -23955,6 +23960,11 @@ cp_parser_direct_declarator (cp_parser*
 
 Thus again, we try a parameter-declaration-clause, and if
 that fails, we back out and return.  */
+ bool pack_expansion_p = token->type == CPP_ELLIPSIS;
+
+ if (pack_expansion_p)
+   /* Consume the `...' */
+   cp_lexer_consume_token (parser->lexer);
 
  if (!first || dcl_kind != CP_PARSER_DECLARATOR_NAMED)
{
@@ -24098,6 +24108,7 @@ cp_parser_direct_declarator (cp_parser*
 attrs,
 parens_loc);
  declarator->attributes = gnu_attrs;
+ declarator->parameter_pack_p |= pack_expansion_p;
  /* Any subsequent parameter lists are to do with
 return type, so are not those of the declared
 function.  */
@@ -24121,7 +24132,7 @@ cp_parser_direct_declarator (cp_parser*
 
  /* If this is the first, we can try a parenthesized
 declarator.  */
- if (first)
+ if (first && !pack_expansion_p)
{
  bool saved_in_type_id_in_expr_p;
 
@@ -24156,16 +24167,27 @@ cp_parser_direct_declarator (cp_parser*
  else
break;
}
-  else if ((!first || dcl_kind != CP_PARSER_DECLARATOR_NAMED)
-  && token->type == CPP_OPEN_SQUARE
-  && !cp_next_tokens_can_be_attribute_p (parser))
+  else if (((!first || dcl_kind != CP_PARSER_DECLARATOR_NAMED)
+   && token->type == CPP_OPEN_SQUARE
+   && !cp_next_tokens_can_be_attribute_p (parser))
+  || (first
+  && dcl_kind != CP_PARSER_DECLARATOR_NAMED
+  && token->type == CPP_ELLIPSIS
+  && cp_lexer_nth_token_is (parser->lexer, 2, CPP_OPEN_SQUARE)
+  && cxx_dialect > cxx98
+  && !cp_nth_tokens_can_be_std_attribute_p (parser, 2)))
{
  /* Parse an array-declarator.  */
  tree bounds, attrs;
+ bool pack_expansion_p = token->type == CPP_ELLIPSIS;
 
  if (ctor_dtor_or_conv_p)
*ctor_dtor_or_conv_p = 0;
 
+ if (pack_expansion_p)
+   /* Consume the `...' */
+   cp_lexer_consume_token (parser->lexer);
+
  open_paren = NULL;
  first = false;
  parser->default_arg_ok_p = false;
@@ -24220,6 +24242,7 @@ cp_parser_direct_declarator (cp_parser*
  attrs = cp_parser_std_attribute_spec_seq (parser);
  declarator = make_array_declarator (declarator, bounds);
  declarator->std_attributes = attrs;
+ declarator->parameter_pack_p |= pack_expansion_p;
}
   else if (first && dcl_kind != CP_PARSER_DECLARATOR_ABSTRACT)
{
--- gcc/testsuite/g++.dg/cpp0x/variadic185.C.jj 2024-05-09 15:08:49.070651189 
+0200
+++ gcc/testsuite/g++.dg/cpp0x/variadic185.C2024-05-09 15:07:40.045583153 
+0200
@@ -0,0 +1,39 @@
+// PR c++/115012
+// { dg-do compile { target { c++11 && c++23_down } } }
+// { dg-final { scan-assembler "_Z3fooILi10EJidEEvDpAT__T0_" } }
+// { dg-final { scan-assembler "_Z3barILi10EiEvPT0_" } }
+// { dg-final { scan-assembler "_Z3bazILi10EJidEEvDpAT__T0_" } }
+// { dg-final { scan-assembler "_Z3quxILi5EJifEEvDpAT__AT__T0_" } }
+
+template 
+void
+foo (T... x[N])
+{
+}
+
+template 
+void
+bar (T [N])
+{
+}
+
+template 
+void
+baz (T... [N])
+{
+}
+
+template 
+void
+qux (T... [N][N])
+{
+}
+
+void
+corge (int a[10], double b[10], int c[5][

Re: [PATCH] c++: fix parsing with auto(x) at block scope [PR112482]

2023-12-14 Thread Jason Merrill

On 12/14/23 16:02, Marek Polacek wrote:

Bootstrapped/regtested on x86_64-pc-linux-gnu, ok for trunk?


OK.


-- >8 --
This is sort of like r14-5514, but at block scope.  Consider

   struct A { A(int, int); };
   void
   g (int a)
   {
 A bar(auto(a), 42); // not a fn decl
   }

where we emit error: 'auto' parameter not permitted in this context
which is bogus -- bar doesn't declare a function, so the auto is OK,
but we don't know it till we've seen the second argument.  The error
comes from grokdeclarator invoked just after we've parsed the auto(a).

A possible approach seems to be to delay the auto parameter checking
and only check once we know we are indeed dealing with a function
declaration.  For tparms, we should still emit the error right away.

PR c++/112482

gcc/cp/ChangeLog:

* decl.cc (grokdeclarator): Do not issue the auto parameter error while
tentatively parsing a function parameter.
* parser.cc (cp_parser_parameter_declaration_clause): Check it here.

gcc/testsuite/ChangeLog:

* g++.dg/cpp23/auto-fncast15.C: New test.
---
  gcc/cp/decl.cc | 13 +++--
  gcc/cp/parser.cc   | 17 +++--
  gcc/testsuite/g++.dg/cpp23/auto-fncast15.C | 21 +
  3 files changed, 47 insertions(+), 4 deletions(-)
  create mode 100644 gcc/testsuite/g++.dg/cpp23/auto-fncast15.C

diff --git a/gcc/cp/decl.cc b/gcc/cp/decl.cc
index 4d17ead123a..1ffe4c82748 100644
--- a/gcc/cp/decl.cc
+++ b/gcc/cp/decl.cc
@@ -14203,6 +14203,7 @@ grokdeclarator (const cp_declarator *declarator,
tree auto_node = type_uses_auto (type);
if (auto_node && !(cxx_dialect >= cxx17 && template_parm_flag))
{
+ bool err_p = true;
  if (cxx_dialect >= cxx14)
{
  if (decl_context == PARM && AUTO_IS_DECLTYPE (auto_node))
@@ -14221,13 +14222,21 @@ grokdeclarator (const cp_declarator *declarator,
"abbreviated function template");
  inform (DECL_SOURCE_LOCATION (c), "%qD declared here", c);
}
- else
+ else if (decl_context == CATCHPARM || template_parm_flag)
error_at (typespec_loc,
  "% parameter not permitted in this context");
+ else
+   /* Do not issue an error while tentatively parsing a function
+  parameter: for T t(auto(a), 42);, when we just saw the 1st
+  parameter, we don't know yet that this construct won't be
+  a function declaration.  Defer the checking to
+  cp_parser_parameter_declaration_clause.  */
+   err_p = false;
}
  else
error_at (typespec_loc, "parameter declared %");
- type = error_mark_node;
+ if (err_p)
+   type = error_mark_node;
}
  
/* A parameter declared as an array of T is really a pointer to T.

diff --git a/gcc/cp/parser.cc b/gcc/cp/parser.cc
index 58e910d64af..e4fbab1bab5 100644
--- a/gcc/cp/parser.cc
+++ b/gcc/cp/parser.cc
@@ -25102,8 +25102,21 @@ cp_parser_parameter_declaration_clause (cp_parser* 
parser,
   committed yet, nor should we.  Pushing here will detect the error
   of redefining a parameter.  */
if (cp_lexer_next_token_is (parser->lexer, CPP_CLOSE_PAREN))
-for (tree p : pending_decls)
-  pushdecl (p);
+{
+  for (tree p : pending_decls)
+   pushdecl (p);
+
+  /* Delayed checking of auto parameters.  */
+  if (!parser->auto_is_implicit_function_template_parm_p
+ && cxx_dialect >= cxx14)
+   for (tree p = parameters; p; p = TREE_CHAIN (p))
+ if (type_uses_auto (TREE_TYPE (TREE_VALUE (p
+   {
+ error_at (location_of (TREE_VALUE (p)),
+   "% parameter not permitted in this context");
+ TREE_TYPE (TREE_VALUE (p)) = error_mark_node;
+   }
+}
  
/* Finish the parameter list.  */

if (!ellipsis_p)
diff --git a/gcc/testsuite/g++.dg/cpp23/auto-fncast15.C 
b/gcc/testsuite/g++.dg/cpp23/auto-fncast15.C
new file mode 100644
index 000..deb1efcc46c
--- /dev/null
+++ b/gcc/testsuite/g++.dg/cpp23/auto-fncast15.C
@@ -0,0 +1,21 @@
+// PR c++/112482
+// { dg-do compile { target c++23 } }
+// { dg-options "-Wno-vexing-parse" }
+
+void foo (auto i, auto j);
+
+struct A {
+   A(int,int);
+};
+
+void
+g (int a)
+{
+  A b1(auto(42), auto(42));
+  A b2(auto(a), auto(42));
+  A b3(auto(42), auto(a));
+  A b4(auto(a), // { dg-error "13:'auto' parameter" }
+   auto(a2)); // { dg-error "13:'auto' parameter" }
+  int v1(auto(42));
+  int fn1(auto(a)); // { dg-error "16:'auto' parameter" }
+}

base-commit: 767e2674875139ac8f354ceee655c1a9561b9779




[PATCH] c++: fix parsing with auto(x) at block scope [PR112482]

2023-12-14 Thread Marek Polacek
Bootstrapped/regtested on x86_64-pc-linux-gnu, ok for trunk?

-- >8 --
This is sort of like r14-5514, but at block scope.  Consider

  struct A { A(int, int); };
  void
  g (int a)
  {
A bar(auto(a), 42); // not a fn decl
  }

where we emit error: 'auto' parameter not permitted in this context
which is bogus -- bar doesn't declare a function, so the auto is OK,
but we don't know it till we've seen the second argument.  The error
comes from grokdeclarator invoked just after we've parsed the auto(a).

A possible approach seems to be to delay the auto parameter checking
and only check once we know we are indeed dealing with a function
declaration.  For tparms, we should still emit the error right away.

PR c++/112482

gcc/cp/ChangeLog:

* decl.cc (grokdeclarator): Do not issue the auto parameter error while
tentatively parsing a function parameter.
* parser.cc (cp_parser_parameter_declaration_clause): Check it here.

gcc/testsuite/ChangeLog:

* g++.dg/cpp23/auto-fncast15.C: New test.
---
 gcc/cp/decl.cc | 13 +++--
 gcc/cp/parser.cc   | 17 +++--
 gcc/testsuite/g++.dg/cpp23/auto-fncast15.C | 21 +
 3 files changed, 47 insertions(+), 4 deletions(-)
 create mode 100644 gcc/testsuite/g++.dg/cpp23/auto-fncast15.C

diff --git a/gcc/cp/decl.cc b/gcc/cp/decl.cc
index 4d17ead123a..1ffe4c82748 100644
--- a/gcc/cp/decl.cc
+++ b/gcc/cp/decl.cc
@@ -14203,6 +14203,7 @@ grokdeclarator (const cp_declarator *declarator,
   tree auto_node = type_uses_auto (type);
   if (auto_node && !(cxx_dialect >= cxx17 && template_parm_flag))
{
+ bool err_p = true;
  if (cxx_dialect >= cxx14)
{
  if (decl_context == PARM && AUTO_IS_DECLTYPE (auto_node))
@@ -14221,13 +14222,21 @@ grokdeclarator (const cp_declarator *declarator,
"abbreviated function template");
  inform (DECL_SOURCE_LOCATION (c), "%qD declared here", c);
}
- else
+ else if (decl_context == CATCHPARM || template_parm_flag)
error_at (typespec_loc,
  "% parameter not permitted in this context");
+ else
+   /* Do not issue an error while tentatively parsing a function
+  parameter: for T t(auto(a), 42);, when we just saw the 1st
+  parameter, we don't know yet that this construct won't be
+  a function declaration.  Defer the checking to
+  cp_parser_parameter_declaration_clause.  */
+   err_p = false;
}
  else
error_at (typespec_loc, "parameter declared %");
- type = error_mark_node;
+ if (err_p)
+   type = error_mark_node;
}
 
   /* A parameter declared as an array of T is really a pointer to T.
diff --git a/gcc/cp/parser.cc b/gcc/cp/parser.cc
index 58e910d64af..e4fbab1bab5 100644
--- a/gcc/cp/parser.cc
+++ b/gcc/cp/parser.cc
@@ -25102,8 +25102,21 @@ cp_parser_parameter_declaration_clause (cp_parser* 
parser,
  committed yet, nor should we.  Pushing here will detect the error
  of redefining a parameter.  */
   if (cp_lexer_next_token_is (parser->lexer, CPP_CLOSE_PAREN))
-for (tree p : pending_decls)
-  pushdecl (p);
+{
+  for (tree p : pending_decls)
+   pushdecl (p);
+
+  /* Delayed checking of auto parameters.  */
+  if (!parser->auto_is_implicit_function_template_parm_p
+ && cxx_dialect >= cxx14)
+   for (tree p = parameters; p; p = TREE_CHAIN (p))
+ if (type_uses_auto (TREE_TYPE (TREE_VALUE (p
+   {
+ error_at (location_of (TREE_VALUE (p)),
+   "% parameter not permitted in this context");
+ TREE_TYPE (TREE_VALUE (p)) = error_mark_node;
+   }
+}
 
   /* Finish the parameter list.  */
   if (!ellipsis_p)
diff --git a/gcc/testsuite/g++.dg/cpp23/auto-fncast15.C 
b/gcc/testsuite/g++.dg/cpp23/auto-fncast15.C
new file mode 100644
index 000..deb1efcc46c
--- /dev/null
+++ b/gcc/testsuite/g++.dg/cpp23/auto-fncast15.C
@@ -0,0 +1,21 @@
+// PR c++/112482
+// { dg-do compile { target c++23 } }
+// { dg-options "-Wno-vexing-parse" }
+
+void foo (auto i, auto j);
+
+struct A {
+   A(int,int);
+};
+
+void
+g (int a)
+{
+  A b1(auto(42), auto(42));
+  A b2(auto(a), auto(42));
+  A b3(auto(42), auto(a));
+  A b4(auto(a), // { dg-error "13:'auto' parameter" }
+   auto(a2)); // { dg-error "13:'auto' parameter" }
+  int v1(auto(42));
+  int fn1(auto(a)); // { dg-error "16:'auto' parameter" }
+}

base-commit: 767e2674875139ac8f354ceee655c1a9561b9779
-- 
2.43.0



Re: [PATCH] c++: Fix parsing [[]][[]];

2023-12-05 Thread Marek Polacek
On Tue, Dec 05, 2023 at 08:51:51AM +0100, Jakub Jelinek wrote:
> Hi!
> 
> When working on the previous patch I put [[]] [[]] asm (""); into a
> testcase, but was surprised it wasn't parsed.

By wasn't parsed you mean we gave an error, right?  I only see an error
with block-scope [[]] [[]];.

> The problem is that when cp_parser_std_attribute_spec returns NULL, it
> can mean 2 different things, one is that the next token(s) are neither
> [[ nor alignas (in that case the caller should break from the loop),
> or when we parsed something like [[]] - it was valid attribute specifier,
> but didn't specify any attributes in it.
> 
> The following patch fixes that by adding another parameter to differentiate
> between the cases, guess another option would be to use some magic
> tree value for the break case instead of NULL_TREE (but error_mark_node is
> already taken and means something else).
> 
> Bootstrapped/regtested on x86_64-linux and i686-linux, ok for trunk?
> 
> Or shall I go with some magic return which will never happen otherwise?
> void_node?

It seems marginally better to me to use void_list_node so that we don't
need a new parm, like what we do when parsing parameters: ()/(void)/(...),
but I should let others decide.

If we stay with any_p, please add a comment saying that it means "found any",
not "accepts any" or something else.  Thanks,

> 2023-12-05  Jakub Jelinek  
> 
>   * parser.cc (cp_parser_std_attribute_spec): Add ANY_P argument, set
>   what it points to initially to true and only if token is neither
>   CPP_OPEN_SQUARE nor RID_ALIGNAS CPP_KEYWORD set it to false.
>   (cp_parser_std_attribute_spec_seq): Adjust
>   cp_parser_std_attribute_spec caller.  If it returns NULL_TREE and
>   any_p is true, continue rather than break.
> 
>   * g++.dg/cpp0x/gen-attrs-79.C: New test.
> 
> --- gcc/cp/parser.cc.jj   2023-12-04 20:23:53.225009856 +0100
> +++ gcc/cp/parser.cc  2023-12-04 20:49:21.160426104 +0100
> @@ -2703,7 +2703,7 @@ static tree cp_parser_gnu_attribute_list
>  static tree cp_parser_std_attribute
>(cp_parser *, tree);
>  static tree cp_parser_std_attribute_spec
> -  (cp_parser *);
> +  (cp_parser *, bool *);
>  static tree cp_parser_std_attribute_spec_seq
>(cp_parser *);
>  static size_t cp_parser_skip_std_attribute_spec_seq
> @@ -30265,11 +30265,12 @@ void cp_parser_late_contract_condition (
>conditional-expression ] ]  */
>  
>  static tree
> -cp_parser_std_attribute_spec (cp_parser *parser)
> +cp_parser_std_attribute_spec (cp_parser *parser, bool *any_p)
>  {
>tree attributes = NULL_TREE;
>cp_token *token = cp_lexer_peek_token (parser->lexer);
>  
> +  *any_p = true;
>if (token->type == CPP_OPEN_SQUARE
>&& cp_lexer_peek_nth_token (parser->lexer, 2)->type == CPP_OPEN_SQUARE)
>  {
> @@ -30342,7 +30343,10 @@ cp_parser_std_attribute_spec (cp_parser
>  
>if (token->type != CPP_KEYWORD
> || token->keyword != RID_ALIGNAS)
> - return NULL_TREE;
> + {
> +   *any_p = false;
> +   return NULL_TREE;
> + }
>  
>cp_lexer_consume_token (parser->lexer);
>maybe_warn_cpp0x (CPP0X_ATTRIBUTES);
> @@ -30414,9 +30418,16 @@ cp_parser_std_attribute_spec_seq (cp_par
>  
>while (true)
>  {
> -  tree attr_spec = cp_parser_std_attribute_spec (parser);
> +  bool any_p;
> +  tree attr_spec = cp_parser_std_attribute_spec (parser, &any_p);
>if (attr_spec == NULL_TREE)
> - break;
> + {
> +   /* Accept [[]][[]]; for which cp_parser_std_attribute_spec
> +  also returns NULL_TREE as there are no attributes.  */
> +   if (any_p)
> + continue;
> +   break;
> + }
>if (attr_spec == error_mark_node)
>   return error_mark_node;
>  
> --- gcc/testsuite/g++.dg/cpp0x/gen-attrs-79.C.jj  2023-12-04 
> 20:38:35.122574430 +0100
> +++ gcc/testsuite/g++.dg/cpp0x/gen-attrs-79.C 2023-12-04 20:38:29.468654143 
> +0100
> @@ -0,0 +1,9 @@
> +// { dg-do compile { target c++11 } }
> +
> +[[]] [[]];
> +
> +[[]] [[]] void
> +foo ()
> +{
> +  [[]] [[]];
> +}
> 
>   Jakub
> 

Marek



[PATCH] c++: Fix parsing [[]][[]];

2023-12-04 Thread Jakub Jelinek
Hi!

When working on the previous patch I put [[]] [[]] asm (""); into a
testcase, but was surprised it wasn't parsed.
The problem is that when cp_parser_std_attribute_spec returns NULL, it
can mean 2 different things, one is that the next token(s) are neither
[[ nor alignas (in that case the caller should break from the loop),
or when we parsed something like [[]] - it was valid attribute specifier,
but didn't specify any attributes in it.

The following patch fixes that by adding another parameter to differentiate
between the cases, guess another option would be to use some magic
tree value for the break case instead of NULL_TREE (but error_mark_node is
already taken and means something else).

Bootstrapped/regtested on x86_64-linux and i686-linux, ok for trunk?

Or shall I go with some magic return which will never happen otherwise?
void_node?

2023-12-05  Jakub Jelinek  

* parser.cc (cp_parser_std_attribute_spec): Add ANY_P argument, set
what it points to initially to true and only if token is neither
CPP_OPEN_SQUARE nor RID_ALIGNAS CPP_KEYWORD set it to false.
(cp_parser_std_attribute_spec_seq): Adjust
cp_parser_std_attribute_spec caller.  If it returns NULL_TREE and
any_p is true, continue rather than break.

* g++.dg/cpp0x/gen-attrs-79.C: New test.

--- gcc/cp/parser.cc.jj 2023-12-04 20:23:53.225009856 +0100
+++ gcc/cp/parser.cc2023-12-04 20:49:21.160426104 +0100
@@ -2703,7 +2703,7 @@ static tree cp_parser_gnu_attribute_list
 static tree cp_parser_std_attribute
   (cp_parser *, tree);
 static tree cp_parser_std_attribute_spec
-  (cp_parser *);
+  (cp_parser *, bool *);
 static tree cp_parser_std_attribute_spec_seq
   (cp_parser *);
 static size_t cp_parser_skip_std_attribute_spec_seq
@@ -30265,11 +30265,12 @@ void cp_parser_late_contract_condition (
 conditional-expression ] ]  */
 
 static tree
-cp_parser_std_attribute_spec (cp_parser *parser)
+cp_parser_std_attribute_spec (cp_parser *parser, bool *any_p)
 {
   tree attributes = NULL_TREE;
   cp_token *token = cp_lexer_peek_token (parser->lexer);
 
+  *any_p = true;
   if (token->type == CPP_OPEN_SQUARE
   && cp_lexer_peek_nth_token (parser->lexer, 2)->type == CPP_OPEN_SQUARE)
 {
@@ -30342,7 +30343,10 @@ cp_parser_std_attribute_spec (cp_parser
 
   if (token->type != CPP_KEYWORD
  || token->keyword != RID_ALIGNAS)
-   return NULL_TREE;
+   {
+ *any_p = false;
+ return NULL_TREE;
+   }
 
   cp_lexer_consume_token (parser->lexer);
   maybe_warn_cpp0x (CPP0X_ATTRIBUTES);
@@ -30414,9 +30418,16 @@ cp_parser_std_attribute_spec_seq (cp_par
 
   while (true)
 {
-  tree attr_spec = cp_parser_std_attribute_spec (parser);
+  bool any_p;
+  tree attr_spec = cp_parser_std_attribute_spec (parser, &any_p);
   if (attr_spec == NULL_TREE)
-   break;
+   {
+ /* Accept [[]][[]]; for which cp_parser_std_attribute_spec
+also returns NULL_TREE as there are no attributes.  */
+ if (any_p)
+   continue;
+ break;
+   }
   if (attr_spec == error_mark_node)
return error_mark_node;
 
--- gcc/testsuite/g++.dg/cpp0x/gen-attrs-79.C.jj2023-12-04 
20:38:35.122574430 +0100
+++ gcc/testsuite/g++.dg/cpp0x/gen-attrs-79.C   2023-12-04 20:38:29.468654143 
+0100
@@ -0,0 +1,9 @@
+// { dg-do compile { target c++11 } }
+
+[[]] [[]];
+
+[[]] [[]] void
+foo ()
+{
+  [[]] [[]];
+}

Jakub



Re: [PATCH] c++: fix parsing with auto(x) [PR112410]

2023-11-09 Thread Jason Merrill

On 11/9/23 14:58, Marek Polacek wrote:

Bootstrapped/regtested on x86_64-pc-linux-gnu, ok for trunk?

-- >8 --
Here we are wrongly parsing

   int y(auto(42));

which uses the C++23 cast-to-prvalue feature, and initializes y to 42.
However, we were treating the auto as an implicit template parameter.

Fixing the auto{42} case is easy, but when auto is followed by a (,
I found the fix to be much more involved.  For instance, we cannot
use cp_parser_expression, because that can give hard errors.  It's
also necessary to disambiguate 'auto(i)' as 'auto i', not a cast.
auto(), auto(int), auto(f)(int), auto(*), auto(i[]), auto(...), etc.
are all function declarations.  We have to look at more than one
token to decide.


Yeah, this is a most vexing parse problem.  The code is synthesizing 
template parameters before we've resolved whether the auto is a 
decl-specifier or not.



In this fix, I'm (ab)using cp_parser_declarator, with member_p=false
so that it doesn't commit.  But it handles even more complicated
cases as

   int fn (auto (*const **&f)(int) -> char);


But it doesn't seem to handle the extremely vexing

struct A {
  A(int,int);
};

int main()
{
  int a;
  A b(auto(a), 42);
}

I think we need to stop synthesizing immediately when we see RID_AUTO, 
and instead go back after we successfully parse a declaration and 
synthesize for any autos we saw along the way.  :/


Jason



[PATCH] c++: fix parsing with auto(x) [PR112410]

2023-11-09 Thread Marek Polacek
Bootstrapped/regtested on x86_64-pc-linux-gnu, ok for trunk?

-- >8 --
Here we are wrongly parsing

  int y(auto(42));

which uses the C++23 cast-to-prvalue feature, and initializes y to 42.
However, we were treating the auto as an implicit template parameter.

Fixing the auto{42} case is easy, but when auto is followed by a (,
I found the fix to be much more involved.  For instance, we cannot
use cp_parser_expression, because that can give hard errors.  It's
also necessary to disambiguate 'auto(i)' as 'auto i', not a cast.
auto(), auto(int), auto(f)(int), auto(*), auto(i[]), auto(...), etc.
are all function declarations.  We have to look at more than one
token to decide.

In this fix, I'm (ab)using cp_parser_declarator, with member_p=false
so that it doesn't commit.  But it handles even more complicated
cases as

  int fn (auto (*const **&f)(int) -> char);

PR c++/112410

gcc/cp/ChangeLog:

* parser.cc (cp_parser_simple_type_specifier): Disambiguate
between a variable and function declaration with auto.
(cp_parser_constructor_declarator_p): Use cp_parser_starts_param_decl_p.
(cp_parser_starts_param_decl_p): New, factored out of
cp_parser_constructor_declarator_p.

gcc/testsuite/ChangeLog:

* g++.dg/cpp23/auto-fncast13.C: New test.
---
 gcc/cp/parser.cc   | 79 ++
 gcc/testsuite/g++.dg/cpp23/auto-fncast13.C | 61 +
 2 files changed, 125 insertions(+), 15 deletions(-)
 create mode 100644 gcc/testsuite/g++.dg/cpp23/auto-fncast13.C

diff --git a/gcc/cp/parser.cc b/gcc/cp/parser.cc
index 5116bcb78f6..3edee092e56 100644
--- a/gcc/cp/parser.cc
+++ b/gcc/cp/parser.cc
@@ -2887,6 +2887,8 @@ static bool cp_parser_next_token_ends_template_argument_p
   (cp_parser *);
 static bool cp_parser_nth_token_starts_template_argument_list_p
   (cp_parser *, size_t);
+static bool cp_parser_starts_param_decl_p
+  (cp_parser *);
 static enum tag_types cp_parser_token_is_class_key
   (cp_token *);
 static enum tag_types cp_parser_token_is_type_parameter_key
@@ -19991,6 +19993,8 @@ cp_parser_simple_type_specifier (cp_parser* parser,
  /* The 'auto' might be the placeholder return type for a function decl
 with trailing return type.  */
  bool have_trailing_return_fn_decl = false;
+ /* Or it might be auto(x) or auto {x}.  */
+ bool decay_copy = false;
 
  cp_parser_parse_tentatively (parser);
  cp_lexer_consume_token (parser->lexer);
@@ -20002,12 +20006,43 @@ cp_parser_simple_type_specifier (cp_parser* parser,
  if (cp_lexer_next_token_is (parser->lexer, CPP_OPEN_PAREN))
{
  cp_lexer_consume_token (parser->lexer);
+ /* An auto specifier that appears in a parameter declaration
+might be the placeholder for a late return type, or it
+can be an implicit template parameter.  But it can also
+be a prvalue cast, rendering the current construct not
+a function declaration at all.  Check if it decidedly
+cannot be a valid function-style cast first...  */
+ if (!cp_parser_starts_param_decl_p (parser))
+   {
+ /* Ug, we couldn't tell.  Try to parse whatever follows
+as a declarator; this should detect cases like
+auto(i), auto(*), auto(f[]), auto(f)(int).  */
+ cp_parser_declarator (parser, CP_PARSER_DECLARATOR_EITHER,
+   CP_PARSER_FLAGS_NONE,
+   /*ctor_dtor_or_conv_p=*/nullptr,
+   /*parenthesized_p=*/NULL,
+   /*member_p=*/true,
+   /*friend_p=*/false,
+   /*static_p=*/true);
+ /* OK, if we now see a ')', it looks like a valid
+function declaration.  Otherwise, let's go with
+auto(x).  */
+ decay_copy
+   = cp_lexer_next_token_is_not (parser->lexer,
+ CPP_CLOSE_PAREN);
+   }
  cp_parser_skip_to_closing_parenthesis (parser,
 /*recovering*/false,
 /*or_comma*/false,
 /*consume_paren*/true);
  continue;
}
+ /* The easy case: it has got to be C++23 auto(x).  */
+ else if (cp_lexer_next_token_is (parser->lexer, CPP_OPEN_BRACE))
+   {
+ decay_copy = true;
+ break;
+   }
 
  if (cp_lexer_ne

Re: [PATCH] c++: Fix parsing of invalid enum specifiers [PR90995]

2020-03-15 Thread Jason Merrill via Gcc-patches

On 3/14/20 4:06 AM, Jakub Jelinek wrote:

Hi!

The testcase shows some accepts-invalid (the ones without alignas) and
ice-on-invalid-code (the ones with alignas) cases.
If the enum doesn't have an underlying type and is not a definition,
the caller retries to parse it as elaborated type specifier.
E.g. for enum struct S s it will then pedwarn that elaborated type specifier
shouldn't have the struct/class keywords.
The problem is if the enum specifier is not followed by { when it has
underlying type.  In that case we have already called
cp_parser_parse_definitely to end the tentative parsing started at the
beginning of cp_parser_enum_specifier.  But the
cp_parser_error (parser, "expected %<;%> or %<{%>");
doesn't emit any error because the whole function is called from yet another
tentative parse and the caller starts parsing the elaborated type
specifier where the cp_parser_enum_specifier stopped (i.e. after the
underlying type token(s)).  The ultimate caller than commits the tentative
parsing (and even if it wouldn't, it wouldn't know what kind of error
to report).  I think after seeing enum {,struct,class} : type not being
followed by { or ;, there is no reason not to report it right away, as it
can't be valid C++, which is what the patch does.  Not sure if we shouldn't
also return error_mark_node instead of NULL_TREE, so that the caller doesn't
try to parse it as elaborated type specifier (the patch doesn't do that
right now).

Furthermore, while reading the code, I've noticed that
parser->colon_corrects_to_scope_p is saved and set to false at the start
of the function, but not restored back in some cases.  Don't have a testcase
where this would be a problem, but it just seems wrong.  Either we can in
the two spots replace return NULL_TREE; with { type = NULL_TREE; goto out; }
or we could perhaps abuse warning_sentinel or create a special class with
dtor to clean the flag up.


Let's use temp_override.



And lastly, I've fixed some formatting issues in the function while reading
it.

Bootstrapped/regtested on x86_64-linux and i686-linux, ok for trunk?

2020-03-14  Jakub Jelinek  

PR c++/90995
* parser.c (cp_parser_enum_specifier): Make sure to restore
parser->colon_corrects_to_scope_p in all cases.  If scoped
enum or enum with underlying type is not followed by { or ;,
call error_at rather than cp_parser_error.  Formatting fixes.

* g++.dg/cpp0x/enum40.C: New test.

--- gcc/cp/parser.c.jj  2020-03-12 18:17:58.039230033 +0100
+++ gcc/cp/parser.c 2020-03-13 21:44:20.117085594 +0100
@@ -19043,24 +19043,24 @@ cp_parser_enum_specifier (cp_parser* par
  
push_deferring_access_checks (dk_no_check);

nested_name_specifier
-  = cp_parser_nested_name_specifier_opt (parser,
-/*typename_keyword_p=*/true,
-/*check_dependency_p=*/false,
-/*type_p=*/false,
-/*is_declaration=*/false);
+= cp_parser_nested_name_specifier_opt (parser,
+  /*typename_keyword_p=*/true,
+  /*check_dependency_p=*/false,
+  /*type_p=*/false,
+  /*is_declaration=*/false);
  
if (nested_name_specifier)

  {
tree name;
  
identifier = cp_parser_identifier (parser);

-  name =  cp_parser_lookup_name (parser, identifier,
-enum_type,
-/*is_template=*/false,
-/*is_namespace=*/false,
-/*check_dependency=*/true,
-/*ambiguous_decls=*/NULL,
-input_location);
+  name = cp_parser_lookup_name (parser, identifier,
+   enum_type,
+   /*is_template=*/false,
+   /*is_namespace=*/false,
+   /*check_dependency=*/true,
+   /*ambiguous_decls=*/NULL,
+   input_location);
if (name && name != error_mark_node)
{
  type = TREE_TYPE (name);
@@ -19117,7 +19117,10 @@ cp_parser_enum_specifier (cp_parser* par
  
/* At this point this is surely not elaborated type specifier.  */

if (!cp_parser_parse_definitely (parser))
-   return NULL_TREE;
+   {
+ type = NULL_TREE;
+ goto out;
+   }
  
if (cxx_dialect < cxx11)

  maybe_warn_cpp0x (CPP0X_SCOPED_ENUMS);
@@ -19151,17 +19154,23 @@ cp_parser_enum_specifier (cp_parser* par
if ((scoped_enum_p || underlying_type)
  && cp_lexer_next_token_is_not (parser->lexer, CPP_SEMICOLON))
{
- cp_pars

[PATCH] c++: Fix parsing of invalid enum specifiers [PR90995]

2020-03-14 Thread Jakub Jelinek via Gcc-patches
Hi!

The testcase shows some accepts-invalid (the ones without alignas) and
ice-on-invalid-code (the ones with alignas) cases.
If the enum doesn't have an underlying type and is not a definition,
the caller retries to parse it as elaborated type specifier.
E.g. for enum struct S s it will then pedwarn that elaborated type specifier
shouldn't have the struct/class keywords.
The problem is if the enum specifier is not followed by { when it has
underlying type.  In that case we have already called
cp_parser_parse_definitely to end the tentative parsing started at the
beginning of cp_parser_enum_specifier.  But the
cp_parser_error (parser, "expected %<;%> or %<{%>");
doesn't emit any error because the whole function is called from yet another
tentative parse and the caller starts parsing the elaborated type
specifier where the cp_parser_enum_specifier stopped (i.e. after the
underlying type token(s)).  The ultimate caller than commits the tentative
parsing (and even if it wouldn't, it wouldn't know what kind of error
to report).  I think after seeing enum {,struct,class} : type not being
followed by { or ;, there is no reason not to report it right away, as it
can't be valid C++, which is what the patch does.  Not sure if we shouldn't
also return error_mark_node instead of NULL_TREE, so that the caller doesn't
try to parse it as elaborated type specifier (the patch doesn't do that
right now).

Furthermore, while reading the code, I've noticed that
parser->colon_corrects_to_scope_p is saved and set to false at the start
of the function, but not restored back in some cases.  Don't have a testcase
where this would be a problem, but it just seems wrong.  Either we can in
the two spots replace return NULL_TREE; with { type = NULL_TREE; goto out; }
or we could perhaps abuse warning_sentinel or create a special class with
dtor to clean the flag up.

And lastly, I've fixed some formatting issues in the function while reading
it.

Bootstrapped/regtested on x86_64-linux and i686-linux, ok for trunk?

2020-03-14  Jakub Jelinek  

PR c++/90995
* parser.c (cp_parser_enum_specifier): Make sure to restore
parser->colon_corrects_to_scope_p in all cases.  If scoped
enum or enum with underlying type is not followed by { or ;,
call error_at rather than cp_parser_error.  Formatting fixes.

* g++.dg/cpp0x/enum40.C: New test.

--- gcc/cp/parser.c.jj  2020-03-12 18:17:58.039230033 +0100
+++ gcc/cp/parser.c 2020-03-13 21:44:20.117085594 +0100
@@ -19043,24 +19043,24 @@ cp_parser_enum_specifier (cp_parser* par
 
   push_deferring_access_checks (dk_no_check);
   nested_name_specifier
-  = cp_parser_nested_name_specifier_opt (parser,
-/*typename_keyword_p=*/true,
-/*check_dependency_p=*/false,
-/*type_p=*/false,
-/*is_declaration=*/false);
+= cp_parser_nested_name_specifier_opt (parser,
+  /*typename_keyword_p=*/true,
+  /*check_dependency_p=*/false,
+  /*type_p=*/false,
+  /*is_declaration=*/false);
 
   if (nested_name_specifier)
 {
   tree name;
 
   identifier = cp_parser_identifier (parser);
-  name =  cp_parser_lookup_name (parser, identifier,
-enum_type,
-/*is_template=*/false,
-/*is_namespace=*/false,
-/*check_dependency=*/true,
-/*ambiguous_decls=*/NULL,
-input_location);
+  name = cp_parser_lookup_name (parser, identifier,
+   enum_type,
+   /*is_template=*/false,
+   /*is_namespace=*/false,
+   /*check_dependency=*/true,
+   /*ambiguous_decls=*/NULL,
+   input_location);
   if (name && name != error_mark_node)
{
  type = TREE_TYPE (name);
@@ -19117,7 +19117,10 @@ cp_parser_enum_specifier (cp_parser* par
 
   /* At this point this is surely not elaborated type specifier.  */
   if (!cp_parser_parse_definitely (parser))
-   return NULL_TREE;
+   {
+ type = NULL_TREE;
+ goto out;
+   }
 
   if (cxx_dialect < cxx11)
 maybe_warn_cpp0x (CPP0X_SCOPED_ENUMS);
@@ -19151,17 +19154,23 @@ cp_parser_enum_specifier (cp_parser* par
   if ((scoped_enum_p || underlying_type)
  && cp_lexer_next_token_is_not (parser->lexer, CPP_SEMICOLON))
{
- cp_parser_error (parser, "expected %<;%> or %<{%>");
  if (has_underlying_type)
{