diff mbox series

C++ PATCH for c++/67012, c++/86942, detect invalid cases with function return type deduction

Message ID 20180817021700.GZ4317@redhat.com
State New
Headers show
Series C++ PATCH for c++/67012, c++/86942, detect invalid cases with function return type deduction | expand

Commit Message

Marek Polacek Aug. 17, 2018, 2:17 a.m. UTC
As I promised in <https://gcc.gnu.org/ml/gcc-patches/2018-08/msg00908.html>,
this patch fixes a couple of invalid cases we weren't detecting.  It's got
testcases from two PRs and another case I found out; they're intertwined so
I think it makes sense to fix them in one go.

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

2018-08-16  Marek Polacek  <polacek@redhat.com>

	PR c++/86942
	PR c++/67012
	* decl.c (grokdeclarator): Disallow functions with trailing return
	type with decltype(auto) as its type.  Also check the function if
	it's inner declarator doesn't exist.

	* g++.dg/cpp0x/auto52.C: New test.
	* g++.dg/cpp1y/auto-fn52.C: New test.
	* g++.dg/cpp1y/auto-fn53.C: New test.
	* g++.dg/cpp1y/auto-fn54.C: New test.

Comments

Jason Merrill Aug. 21, 2018, 11:59 a.m. UTC | #1
On Fri, Aug 17, 2018 at 2:17 PM, Marek Polacek <polacek@redhat.com> wrote:
> As I promised in <https://gcc.gnu.org/ml/gcc-patches/2018-08/msg00908.html>,
> this patch fixes a couple of invalid cases we weren't detecting.  It's got
> testcases from two PRs and another case I found out; they're intertwined so
> I think it makes sense to fix them in one go.
>
> Bootstrapped/regtested on x86_64-linux, ok for trunk?
>
> 2018-08-16  Marek Polacek  <polacek@redhat.com>
>
>         PR c++/86942
>         PR c++/67012
>         * decl.c (grokdeclarator): Disallow functions with trailing return
>         type with decltype(auto) as its type.  Also check the function if
>         it's inner declarator doesn't exist.
>
>         * g++.dg/cpp0x/auto52.C: New test.
>         * g++.dg/cpp1y/auto-fn52.C: New test.
>         * g++.dg/cpp1y/auto-fn53.C: New test.
>         * g++.dg/cpp1y/auto-fn54.C: New test.
>
> diff --git gcc/cp/decl.c gcc/cp/decl.c
> index fa58bc4d2b3..8261f8e30e5 100644
> --- gcc/cp/decl.c
> +++ gcc/cp/decl.c
> @@ -11238,7 +11238,10 @@ grokdeclarator (const cp_declarator *declarator,
>
>             /* Handle a late-specified return type.  */
>             tree late_return_type = declarator->u.function.late_return_type;
> -           if (funcdecl_p)
> +           if (funcdecl_p
> +               /* This is the case e.g. for
> +                  using T = auto () -> int.  */
> +               || inner_declarator == NULL)

Hmm, checking funcdecl_p here seems just wrong; these errors should be
the same regardless of whether this is declaring a function.  What
breaks if we just remove this condition?  The deduction guide errors
will need to be adjusted to handle the abstract declarator case, but
that looks like the only spot that would need fixing.

>               {
>                 if (tree auto_node = type_uses_auto (type))
>                   {
> @@ -11270,6 +11273,18 @@ grokdeclarator (const cp_declarator *declarator,
>                                name, type);
>                         return error_mark_node;
>                       }
> +                   else if (is_auto (type)
> +                            && (TYPE_IDENTIFIER (type)
> +                                == decltype_auto_identifier))

I think you want AUTO_IS_DECLTYPE here.

> +                     {
> +                       if (funcdecl_p)
> +                         error ("%qs function with trailing return type has "
> +                                "%<decltype(auto)%> as its type rather than "
> +                                "plain %<auto%>", name);
> +                       else
> +                         error ("invalid use of %<decltype(auto)%>");
> +                       return error_mark_node;
> +                     }
>                     tree tmpl = CLASS_PLACEHOLDER_TEMPLATE (auto_node);
>                     if (!tmpl)
>                       if (tree late_auto = type_uses_auto (late_return_type))
> diff --git gcc/testsuite/g++.dg/cpp0x/auto52.C gcc/testsuite/g++.dg/cpp0x/auto52.C
> index e69de29bb2d..9bfe7c754b5 100644
> --- gcc/testsuite/g++.dg/cpp0x/auto52.C
> +++ gcc/testsuite/g++.dg/cpp0x/auto52.C
> @@ -0,0 +1,6 @@
> +// PR c++/86942
> +// { dg-do compile { target c++11 } }
> +
> +using T = auto() -> int;
> +using U = void() -> int; // { dg-error "function with trailing return type not declared with .auto." }
> +using W = auto(); // { dg-error "invalid use of .auto." }
> diff --git gcc/testsuite/g++.dg/cpp1y/auto-fn52.C gcc/testsuite/g++.dg/cpp1y/auto-fn52.C
> index e69de29bb2d..e239bc27dc2 100644
> --- gcc/testsuite/g++.dg/cpp1y/auto-fn52.C
> +++ gcc/testsuite/g++.dg/cpp1y/auto-fn52.C
> @@ -0,0 +1,4 @@
> +// PR c++/67012
> +// { dg-do compile { target c++14 } }
> +
> +decltype(auto) f() -> int; // { dg-error "function with trailing return type has" }
> diff --git gcc/testsuite/g++.dg/cpp1y/auto-fn53.C gcc/testsuite/g++.dg/cpp1y/auto-fn53.C
> index e69de29bb2d..720aeeb215d 100644
> --- gcc/testsuite/g++.dg/cpp1y/auto-fn53.C
> +++ gcc/testsuite/g++.dg/cpp1y/auto-fn53.C
> @@ -0,0 +1,4 @@
> +// PR c++/86942
> +// { dg-do compile { target c++14 } }
> +
> +using T = decltype(auto) () -> int; // { dg-error "invalid use of" }
> diff --git gcc/testsuite/g++.dg/cpp1y/auto-fn54.C gcc/testsuite/g++.dg/cpp1y/auto-fn54.C
> index e69de29bb2d..f3391ddfd75 100644
> --- gcc/testsuite/g++.dg/cpp1y/auto-fn54.C
> +++ gcc/testsuite/g++.dg/cpp1y/auto-fn54.C
> @@ -0,0 +1,3 @@
> +// { dg-do compile { target c++14 } }
> +
> +using T = int () -> decltype(auto); // { dg-error "function with trailing return type not declared with .auto." }
Marek Polacek Aug. 23, 2018, 5:01 p.m. UTC | #2
On Tue, Aug 21, 2018 at 11:59:06PM +1200, Jason Merrill wrote:
> On Fri, Aug 17, 2018 at 2:17 PM, Marek Polacek <polacek@redhat.com> wrote:
> > As I promised in <https://gcc.gnu.org/ml/gcc-patches/2018-08/msg00908.html>,
> > this patch fixes a couple of invalid cases we weren't detecting.  It's got
> > testcases from two PRs and another case I found out; they're intertwined so
> > I think it makes sense to fix them in one go.
> >
> > Bootstrapped/regtested on x86_64-linux, ok for trunk?
> >
> > 2018-08-16  Marek Polacek  <polacek@redhat.com>
> >
> >         PR c++/86942
> >         PR c++/67012
> >         * decl.c (grokdeclarator): Disallow functions with trailing return
> >         type with decltype(auto) as its type.  Also check the function if
> >         it's inner declarator doesn't exist.
> >
> >         * g++.dg/cpp0x/auto52.C: New test.
> >         * g++.dg/cpp1y/auto-fn52.C: New test.
> >         * g++.dg/cpp1y/auto-fn53.C: New test.
> >         * g++.dg/cpp1y/auto-fn54.C: New test.
> >
> > diff --git gcc/cp/decl.c gcc/cp/decl.c
> > index fa58bc4d2b3..8261f8e30e5 100644
> > --- gcc/cp/decl.c
> > +++ gcc/cp/decl.c
> > @@ -11238,7 +11238,10 @@ grokdeclarator (const cp_declarator *declarator,
> >
> >             /* Handle a late-specified return type.  */
> >             tree late_return_type = declarator->u.function.late_return_type;
> > -           if (funcdecl_p)
> > +           if (funcdecl_p
> > +               /* This is the case e.g. for
> > +                  using T = auto () -> int.  */
> > +               || inner_declarator == NULL)
> 
> Hmm, checking funcdecl_p here seems just wrong; these errors should be
> the same regardless of whether this is declaring a function.  What
> breaks if we just remove this condition?  The deduction guide errors
> will need to be adjusted to handle the abstract declarator case, but
> that looks like the only spot that would need fixing.
 
That was my first idea but it breaks with pointers to functions and pointers
to member functions as in auto2.C:

auto (*fp)() = f;
where the declarators are: cdk_function -> cdk_pointer -> cdk_id
auto (A::*pmf)() = &A::f;
where the declarators are: cdk_function -> cdk_ptrmem -> cdk_id

it complains that a function uses 'auto' type specifier without trailing return type

> >               {
> >                 if (tree auto_node = type_uses_auto (type))
> >                   {
> > @@ -11270,6 +11273,18 @@ grokdeclarator (const cp_declarator *declarator,
> >                                name, type);
> >                         return error_mark_node;
> >                       }
> > +                   else if (is_auto (type)
> > +                            && (TYPE_IDENTIFIER (type)
> > +                                == decltype_auto_identifier))
> 
> I think you want AUTO_IS_DECLTYPE here.

Ah, nice.

Marek
Jason Merrill Aug. 24, 2018, 12:36 p.m. UTC | #3
On Fri, Aug 24, 2018 at 3:01 AM, Marek Polacek <polacek@redhat.com> wrote:
> On Tue, Aug 21, 2018 at 11:59:06PM +1200, Jason Merrill wrote:
>> On Fri, Aug 17, 2018 at 2:17 PM, Marek Polacek <polacek@redhat.com> wrote:
>> > As I promised in <https://gcc.gnu.org/ml/gcc-patches/2018-08/msg00908.html>,
>> > this patch fixes a couple of invalid cases we weren't detecting.  It's got
>> > testcases from two PRs and another case I found out; they're intertwined so
>> > I think it makes sense to fix them in one go.
>> >
>> > Bootstrapped/regtested on x86_64-linux, ok for trunk?
>> >
>> > 2018-08-16  Marek Polacek  <polacek@redhat.com>
>> >
>> >         PR c++/86942
>> >         PR c++/67012
>> >         * decl.c (grokdeclarator): Disallow functions with trailing return
>> >         type with decltype(auto) as its type.  Also check the function if
>> >         it's inner declarator doesn't exist.
>> >
>> >         * g++.dg/cpp0x/auto52.C: New test.
>> >         * g++.dg/cpp1y/auto-fn52.C: New test.
>> >         * g++.dg/cpp1y/auto-fn53.C: New test.
>> >         * g++.dg/cpp1y/auto-fn54.C: New test.
>> >
>> > diff --git gcc/cp/decl.c gcc/cp/decl.c
>> > index fa58bc4d2b3..8261f8e30e5 100644
>> > --- gcc/cp/decl.c
>> > +++ gcc/cp/decl.c
>> > @@ -11238,7 +11238,10 @@ grokdeclarator (const cp_declarator *declarator,
>> >
>> >             /* Handle a late-specified return type.  */
>> >             tree late_return_type = declarator->u.function.late_return_type;
>> > -           if (funcdecl_p)
>> > +           if (funcdecl_p
>> > +               /* This is the case e.g. for
>> > +                  using T = auto () -> int.  */
>> > +               || inner_declarator == NULL)
>>
>> Hmm, checking funcdecl_p here seems just wrong; these errors should be
>> the same regardless of whether this is declaring a function.  What
>> breaks if we just remove this condition?  The deduction guide errors
>> will need to be adjusted to handle the abstract declarator case, but
>> that looks like the only spot that would need fixing.
>
> That was my first idea but it breaks with pointers to functions and pointers
> to member functions as in auto2.C:
>
> auto (*fp)() = f;
> where the declarators are: cdk_function -> cdk_pointer -> cdk_id
> auto (A::*pmf)() = &A::f;
> where the declarators are: cdk_function -> cdk_ptrmem -> cdk_id
>
> it complains that a function uses 'auto' type specifier without trailing return type

Ah, right.

>> >               {
>> >                 if (tree auto_node = type_uses_auto (type))
>> >                   {
>> > @@ -11270,6 +11273,18 @@ grokdeclarator (const cp_declarator *declarator,
>> >                                name, type);
>> >                         return error_mark_node;
>> >                       }
>> > +                   else if (is_auto (type)
>> > +                            && (TYPE_IDENTIFIER (type)
>> > +                                == decltype_auto_identifier))
>>
>> I think you want AUTO_IS_DECLTYPE here.
>
> Ah, nice.

OK with this change, then.

Jason
diff mbox series

Patch

diff --git gcc/cp/decl.c gcc/cp/decl.c
index fa58bc4d2b3..8261f8e30e5 100644
--- gcc/cp/decl.c
+++ gcc/cp/decl.c
@@ -11238,7 +11238,10 @@  grokdeclarator (const cp_declarator *declarator,
 
 	    /* Handle a late-specified return type.  */
 	    tree late_return_type = declarator->u.function.late_return_type;
-	    if (funcdecl_p)
+	    if (funcdecl_p
+		/* This is the case e.g. for
+		   using T = auto () -> int.  */
+		|| inner_declarator == NULL)
 	      {
 		if (tree auto_node = type_uses_auto (type))
 		  {
@@ -11270,6 +11273,18 @@  grokdeclarator (const cp_declarator *declarator,
 			       name, type);
 			return error_mark_node;
 		      }
+		    else if (is_auto (type)
+			     && (TYPE_IDENTIFIER (type)
+				 == decltype_auto_identifier))
+		      {
+			if (funcdecl_p)
+			  error ("%qs function with trailing return type has "
+				 "%<decltype(auto)%> as its type rather than "
+				 "plain %<auto%>", name);
+			else
+			  error ("invalid use of %<decltype(auto)%>");
+			return error_mark_node;
+		      }
 		    tree tmpl = CLASS_PLACEHOLDER_TEMPLATE (auto_node);
 		    if (!tmpl)
 		      if (tree late_auto = type_uses_auto (late_return_type))
diff --git gcc/testsuite/g++.dg/cpp0x/auto52.C gcc/testsuite/g++.dg/cpp0x/auto52.C
index e69de29bb2d..9bfe7c754b5 100644
--- gcc/testsuite/g++.dg/cpp0x/auto52.C
+++ gcc/testsuite/g++.dg/cpp0x/auto52.C
@@ -0,0 +1,6 @@ 
+// PR c++/86942
+// { dg-do compile { target c++11 } }
+
+using T = auto() -> int;
+using U = void() -> int; // { dg-error "function with trailing return type not declared with .auto." }
+using W = auto(); // { dg-error "invalid use of .auto." }
diff --git gcc/testsuite/g++.dg/cpp1y/auto-fn52.C gcc/testsuite/g++.dg/cpp1y/auto-fn52.C
index e69de29bb2d..e239bc27dc2 100644
--- gcc/testsuite/g++.dg/cpp1y/auto-fn52.C
+++ gcc/testsuite/g++.dg/cpp1y/auto-fn52.C
@@ -0,0 +1,4 @@ 
+// PR c++/67012
+// { dg-do compile { target c++14 } }
+
+decltype(auto) f() -> int; // { dg-error "function with trailing return type has" }
diff --git gcc/testsuite/g++.dg/cpp1y/auto-fn53.C gcc/testsuite/g++.dg/cpp1y/auto-fn53.C
index e69de29bb2d..720aeeb215d 100644
--- gcc/testsuite/g++.dg/cpp1y/auto-fn53.C
+++ gcc/testsuite/g++.dg/cpp1y/auto-fn53.C
@@ -0,0 +1,4 @@ 
+// PR c++/86942
+// { dg-do compile { target c++14 } }
+
+using T = decltype(auto) () -> int; // { dg-error "invalid use of" }
diff --git gcc/testsuite/g++.dg/cpp1y/auto-fn54.C gcc/testsuite/g++.dg/cpp1y/auto-fn54.C
index e69de29bb2d..f3391ddfd75 100644
--- gcc/testsuite/g++.dg/cpp1y/auto-fn54.C
+++ gcc/testsuite/g++.dg/cpp1y/auto-fn54.C
@@ -0,0 +1,3 @@ 
+// { dg-do compile { target c++14 } }
+
+using T = int () -> decltype(auto); // { dg-error "function with trailing return type not declared with .auto." }