diff mbox

PR c++/69139

Message ID alpine.DEB.2.20.9.1602081411100.1231@idea
State New
Headers show

Commit Message

Patrick Palka Feb. 8, 2016, 7:14 p.m. UTC
On Mon, 8 Feb 2016, Jason Merrill wrote:

> On 02/08/2016 11:43 AM, Patrick Palka wrote:
>> BTW, last month I posted a patch for this PR that handles all kinds of
>> specifiers as well __attribute__ specifiers.
>> 
>> Patch is at: https://gcc.gnu.org/ml/gcc-patches/2016-01/msg02004.html
>> -- it makes the parser arbitrarily look ahead (while skipping over
>> pairs of parens) until it finds a DEREF, a COMMA, a CLOSE_PAREN or an
>> EQ.  If it first finds a DEREF then have_trailing_return_fn_decl is
>> set.  Dunno if it's better to have this kind of "dumb" lookahead, or
>> to be more explicit about one expects to consume like your followup
>> patch does.
>
> Hmm, I think I prefer your approach, but please add the testcase with stuff 
> between ) and ->.

Done.  Does this look OK?

-- >8 --

gcc/cp/ChangeLog:

 	PR c++/69139
 	* parser.c (cp_parser_simple_type_specifier): Make the check
 	for disambiguating between an 'auto' placeholder and an implicit
 	template parameter more robust.

gcc/testsuite/ChangeLog:

 	PR c++/69139
 	* g++.dg/cpp0x/trailing12.C: New test.
 	* g++.dg/cpp0x/trailing13.C: New test.
---
  gcc/cp/parser.c                         | 33 +++++++++++++++++++++++----------
  gcc/testsuite/g++.dg/cpp0x/trailing12.C | 22 ++++++++++++++++++++++
  gcc/testsuite/g++.dg/cpp0x/trailing13.C | 12 ++++++++++++
  3 files changed, 57 insertions(+), 10 deletions(-)
  create mode 100644 gcc/testsuite/g++.dg/cpp0x/trailing12.C
  create mode 100644 gcc/testsuite/g++.dg/cpp0x/trailing13.C

Comments

Adam Butcher Feb. 8, 2016, 8:30 p.m. UTC | #1
On 2016-02-08 19:14, Patrick Palka wrote:
> On Mon, 8 Feb 2016, Jason Merrill wrote:
>> On 02/08/2016 11:43 AM, Patrick Palka wrote:
>>> BTW, last month I posted a patch for this PR that handles all kinds 
>>> of
>>> specifiers as well __attribute__ specifiers.
>>> Patch is at: 
>>> https://gcc.gnu.org/ml/gcc-patches/2016-01/msg02004.html
>>> -- it makes the parser arbitrarily look ahead (while skipping over
>>> pairs of parens) until it finds a DEREF, a COMMA, a CLOSE_PAREN or 
>>> an
>>> EQ.  If it first finds a DEREF then have_trailing_return_fn_decl is
>>> set.  Dunno if it's better to have this kind of "dumb" lookahead, 
>>> or
>>> to be more explicit about one expects to consume like your followup
>>> patch does.
>>
>> Hmm, I think I prefer your approach [snip]
>
Me too.  I was worried that the cases handled in the explicit solution 
might get longer, more complex and repeat large amounts of other parser 
code.  Providing this approach gives us no false positives I would say 
it's superior.
Jason Merrill Feb. 8, 2016, 10:09 p.m. UTC | #2
OK.

Jason
diff mbox

Patch

diff --git a/gcc/cp/parser.c b/gcc/cp/parser.c
index d03b0c9..56c834f 100644
--- a/gcc/cp/parser.c
+++ b/gcc/cp/parser.c
@@ -16032,20 +16032,33 @@  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;
-	  if (cp_lexer_peek_nth_token (parser->lexer, 2)->type
-	      == CPP_OPEN_PAREN)
+
+	  cp_parser_parse_tentatively (parser);
+	  cp_lexer_consume_token (parser->lexer);
+	  while (cp_lexer_next_token_is_not (parser->lexer, CPP_EQ)
+		 && cp_lexer_next_token_is_not (parser->lexer, CPP_COMMA)
+		 && cp_lexer_next_token_is_not (parser->lexer, CPP_CLOSE_PAREN)
+		 && cp_lexer_next_token_is_not (parser->lexer, CPP_EOF))
  	    {
-	      cp_parser_parse_tentatively (parser);
-	      cp_lexer_consume_token (parser->lexer);
-	      cp_lexer_consume_token (parser->lexer);
-	      if (cp_parser_skip_to_closing_parenthesis (parser,
+	      if (cp_lexer_next_token_is (parser->lexer, CPP_OPEN_PAREN))
+		{
+		  cp_lexer_consume_token (parser->lexer);
+		  cp_parser_skip_to_closing_parenthesis (parser,
  							 /*recovering*/false,
  							 /*or_comma*/false,
-							 /*consume_paren*/true))
-		have_trailing_return_fn_decl
-		  = cp_lexer_next_token_is (parser->lexer, CPP_DEREF);
-	      cp_parser_abort_tentative_parse (parser);
+							 /*consume_paren*/true);
+		  continue;
+		}
+
+	      if (cp_lexer_next_token_is (parser->lexer, CPP_DEREF))
+		{
+		  have_trailing_return_fn_decl = true;
+		  break;
+		}
+
+	      cp_lexer_consume_token (parser->lexer);
  	    }
+	  cp_parser_abort_tentative_parse (parser);

  	  if (have_trailing_return_fn_decl)
  	    {
diff --git a/gcc/testsuite/g++.dg/cpp0x/trailing12.C b/gcc/testsuite/g++.dg/cpp0x/trailing12.C
new file mode 100644
index 0000000..a27d988
--- /dev/null
+++ b/gcc/testsuite/g++.dg/cpp0x/trailing12.C
@@ -0,0 +1,22 @@ 
+// PR c++/69139
+// { dg-do compile { target c++11 } }
+
+auto get(int) -> int { return {}; }
+template <class R> int f(auto (*)(int) -> R) { return {}; }
+int i = f(get);
+
+int foo1 (auto (int) -> char);
+
+int foo2 (auto f(int) -> char);
+
+int foo2 (auto (f)(int) -> char);
+
+int foo3 (auto (*f)(int) -> char);
+
+int foo4 (auto (*const **&f)(int) -> char);
+
+int foo5 (auto (*const **&f)(int, int *) -> char);
+
+int foo6 (auto (int) const -> char); // { dg-error "const" }
+
+void foo7 (auto __attribute__ ((unused)) f (int) -> int) { }
diff --git a/gcc/testsuite/g++.dg/cpp0x/trailing13.C b/gcc/testsuite/g++.dg/cpp0x/trailing13.C
new file mode 100644
index 0000000..2681bcd
--- /dev/null
+++ b/gcc/testsuite/g++.dg/cpp0x/trailing13.C
@@ -0,0 +1,12 @@ 
+// PR c++/69139
+// { dg-do compile { target c++11 } }
+
+struct X {
+  auto get(int) const & noexcept -> int { return {}; }
+  auto get(int) && throw () -> long { return {}; }
+};
+
+template <class R> auto f(auto (X::*)(int) const & -> R) -> R {}
+
+using I = decltype(f(&X::get));
+using I = int;