public inbox for gcc-patches@gcc.gnu.org
 help / color / mirror / Atom feed
* [C++ Patch] PR 57543
@ 2014-05-27 13:32 Paolo Carlini
  2014-05-27 17:15 ` Jason Merrill
  0 siblings, 1 reply; 21+ messages in thread
From: Paolo Carlini @ 2014-05-27 13:32 UTC (permalink / raw)
  To: gcc-patches; +Cc: Jason Merrill

[-- Attachment #1: Type: text/plain, Size: 206 bytes --]

Hi,

here, in order to accept the code without an explicit this-> 
qualification, I propose to simply notice that instance == 
current_class_type. Tested x86_64-linux.

Thanks!
Paolo.

////////////////////

[-- Attachment #2: CL_57543 --]
[-- Type: text/plain, Size: 304 bytes --]

/cp
2014-05-27  Paolo Carlini  <paolo.carlini@oracle.com>

	PR c++/57543
	* call.c (build_new_method_call_1): In an unevaluated context
	allow calling a member function of the same class.

/testsuite
2014-05-27  Paolo Carlini  <paolo.carlini@oracle.com>

	PR c++/57543
	* g++.dg/cpp0x/decltype59.C: New.

[-- Attachment #3: patch_57543 --]
[-- Type: text/plain, Size: 1171 bytes --]

Index: cp/call.c
===================================================================
--- cp/call.c	(revision 210956)
+++ cp/call.c	(working copy)
@@ -8000,6 +8000,20 @@ build_new_method_call_1 (tree instance, tree fns,
 		     we know we really need it.  */
 		  cand->first_arg = instance;
 		}
+	      else if (cp_unevaluated_operand != 0
+		       && current_class_type
+		       && same_type_p (TYPE_MAIN_VARIANT (TREE_TYPE (instance)),
+				       current_class_type))
+		{
+		  /* For example (c++/57543):
+
+		     template< typename > struct X
+		     {
+		       void foo();
+		       auto bar() -> decltype( X::foo() );
+		     };  */
+		  gcc_assert (cand->first_arg == instance);
+		}
 	      else
 		{
 		  if (complain & tf_error)
Index: testsuite/g++.dg/cpp0x/decltype59.C
===================================================================
--- testsuite/g++.dg/cpp0x/decltype59.C	(revision 0)
+++ testsuite/g++.dg/cpp0x/decltype59.C	(working copy)
@@ -0,0 +1,13 @@
+// PR c++/57543
+// { dg-do compile { target c++11 } }
+
+template< typename T> struct X
+{
+  void foo();
+  auto bar() -> decltype( X::foo() );
+};
+
+int main()
+{
+  X<int>().bar();
+}

^ permalink raw reply	[flat|nested] 21+ messages in thread

* Re: [C++ Patch] PR 57543
  2014-05-27 13:32 [C++ Patch] PR 57543 Paolo Carlini
@ 2014-05-27 17:15 ` Jason Merrill
  2014-05-27 21:43   ` Paolo Carlini
  0 siblings, 1 reply; 21+ messages in thread
From: Jason Merrill @ 2014-05-27 17:15 UTC (permalink / raw)
  To: Paolo Carlini, gcc-patches

I don't think this is the right place for the fix; why do we have a 
dummy object at all?  Doesn't maybe_dummy_object return 
current_class_ref in this situation?

Jason

^ permalink raw reply	[flat|nested] 21+ messages in thread

* Re: [C++ Patch] PR 57543
  2014-05-27 17:15 ` Jason Merrill
@ 2014-05-27 21:43   ` Paolo Carlini
  2014-05-27 22:08     ` Paolo Carlini
  0 siblings, 1 reply; 21+ messages in thread
From: Paolo Carlini @ 2014-05-27 21:43 UTC (permalink / raw)
  To: Jason Merrill, gcc-patches

[-- Attachment #1: Type: text/plain, Size: 964 bytes --]

Hi,

On 05/27/2014 07:15 PM, Jason Merrill wrote:
> I don't think this is the right place for the fix; why do we have a 
> dummy object at all?  Doesn't maybe_dummy_object return 
> current_class_ref in this situation?
I see, thanks for the dummy object clarification.

Therefore, it seems to me that the real issue is that current_class_ref 
is null when maybe_dummy_object is called in the template case, vs the 
non-template case where cp_parser_late_return_type_opt calls 
inject_this_parameter. Thus the below, which at least passes testing.

The most tricky case is tested with struct Z: in that case 
tsubst_function_type is called , via 3/4 hops, from fn_type_unification, 
thus the former cannot simply use current_class_type, which is null. I 
tried to cope with that by using DECL_CONTEXT (in_decl) but then 
fn_type_unification has to pass the actual TEMPLATE_DECL as in_decl, not 
NULL_TREE. Is that reasonable??

Thanks!
Paolo.

////////////////////

[-- Attachment #2: patch_57543_2 --]
[-- Type: text/plain, Size: 2160 bytes --]

Index: cp/pt.c
===================================================================
--- cp/pt.c	(revision 210956)
+++ cp/pt.c	(working copy)
@@ -11323,7 +11323,28 @@ tsubst_function_type (tree t,
   gcc_assert (TYPE_CONTEXT (t) == NULL_TREE);
 
   /* Substitute the return type.  */
+  tree save_ccp = current_class_ptr;
+  tree save_ccr = current_class_ref;
+  bool do_inject = (!current_class_ref
+		    && TREE_CODE (t) == METHOD_TYPE
+		    && TREE_CODE (TREE_TYPE (t)) == DECLTYPE_TYPE);
+  if (do_inject)
+    {
+      /* DR 1207: 'this' is in scope in the trailing return type.  */
+      inject_this_parameter (current_class_type
+			     ? current_class_type
+			     : DECL_CONTEXT (in_decl),
+			     type_memfn_quals (t));
+    }
+
   return_type = tsubst (TREE_TYPE (t), args, complain, in_decl);
+
+  if (do_inject)
+    {
+      current_class_ptr = save_ccp;
+      current_class_ref = save_ccr;
+    }
+
   if (return_type == error_mark_node)
     return error_mark_node;
   /* DR 486 clarifies that creation of a function type with an
@@ -15872,7 +15893,7 @@ fn_type_unification (tree fn,
 	 access path at this point.  */
       push_deferring_access_checks (dk_deferred);
       fntype = tsubst (TREE_TYPE (fn), explicit_targs,
-		       complain | tf_partial, NULL_TREE);
+		       complain | tf_partial, fn);
       pop_deferring_access_checks ();
       input_location = loc;
       processing_template_decl -= incomplete;
Index: testsuite/g++.dg/cpp0x/decltype59.C
===================================================================
--- testsuite/g++.dg/cpp0x/decltype59.C	(revision 0)
+++ testsuite/g++.dg/cpp0x/decltype59.C	(working copy)
@@ -0,0 +1,29 @@
+// PR c++/57543
+// { dg-do compile { target c++11 } }
+
+template< typename > struct X
+{
+  void foo();
+  auto bar() -> decltype( X::foo() );
+};
+
+template< typename > struct Y
+{
+  void foo();
+  template< typename >
+  auto bar() -> decltype( Y::foo() );
+};
+
+template< typename > struct Z
+{
+  void foo();
+  template< typename T>
+  auto bar() -> decltype( T::foo() );
+};
+
+int main()
+{
+  X<int>().bar();
+  Y<int>().bar<double>();
+  Z<int>().bar<Z<int>>();
+}

^ permalink raw reply	[flat|nested] 21+ messages in thread

* Re: [C++ Patch] PR 57543
  2014-05-27 21:43   ` Paolo Carlini
@ 2014-05-27 22:08     ` Paolo Carlini
  2014-05-28 10:18       ` Paolo Carlini
  0 siblings, 1 reply; 21+ messages in thread
From: Paolo Carlini @ 2014-05-27 22:08 UTC (permalink / raw)
  To: Jason Merrill, gcc-patches

[-- Attachment #1: Type: text/plain, Size: 226 bytes --]

... if the approach makes sense, we want to pass a proper in_decl in one 
more place, otherwise specializations are not handled (eg, K in the 
testcase). Like the below, lightly tested so far.

Paolo.

///////////////////////

[-- Attachment #2: patch_57543_3 --]
[-- Type: text/plain, Size: 2736 bytes --]

Index: cp/pt.c
===================================================================
--- cp/pt.c	(revision 210956)
+++ cp/pt.c	(working copy)
@@ -1987,7 +1987,7 @@ determine_specialization (tree template_id,
 	    continue;
 
 	  /* Make sure that the deduced arguments actually work.  */
-	  insttype = tsubst (TREE_TYPE (fn), targs, tf_none, NULL_TREE);
+	  insttype = tsubst (TREE_TYPE (fn), targs, tf_none, fn);
 	  if (insttype == error_mark_node)
 	    continue;
 	  fn_arg_types
@@ -11323,7 +11323,28 @@ tsubst_function_type (tree t,
   gcc_assert (TYPE_CONTEXT (t) == NULL_TREE);
 
   /* Substitute the return type.  */
+  tree save_ccp = current_class_ptr;
+  tree save_ccr = current_class_ref;
+  bool do_inject = (!current_class_ref
+		    && TREE_CODE (t) == METHOD_TYPE
+		    && TREE_CODE (TREE_TYPE (t)) == DECLTYPE_TYPE);
+  if (do_inject)
+    {
+      /* DR 1207: 'this' is in scope in the trailing return type.  */
+      inject_this_parameter (current_class_type
+			     ? current_class_type
+			     : DECL_CONTEXT (in_decl),
+			     type_memfn_quals (t));
+    }
+
   return_type = tsubst (TREE_TYPE (t), args, complain, in_decl);
+
+  if (do_inject)
+    {
+      current_class_ptr = save_ccp;
+      current_class_ref = save_ccr;
+    }
+
   if (return_type == error_mark_node)
     return error_mark_node;
   /* DR 486 clarifies that creation of a function type with an
@@ -15872,7 +15893,7 @@ fn_type_unification (tree fn,
 	 access path at this point.  */
       push_deferring_access_checks (dk_deferred);
       fntype = tsubst (TREE_TYPE (fn), explicit_targs,
-		       complain | tf_partial, NULL_TREE);
+		       complain | tf_partial, fn);
       pop_deferring_access_checks ();
       input_location = loc;
       processing_template_decl -= incomplete;
Index: testsuite/g++.dg/cpp0x/decltype59.C
===================================================================
--- testsuite/g++.dg/cpp0x/decltype59.C	(revision 0)
+++ testsuite/g++.dg/cpp0x/decltype59.C	(working copy)
@@ -0,0 +1,41 @@
+// PR c++/57543
+// { dg-do compile { target c++11 } }
+
+template< typename > struct X
+{
+  void foo();
+  auto bar() -> decltype( X::foo() );
+};
+
+template< typename > struct Y
+{
+  void foo();
+  template< typename >
+  auto bar() -> decltype( Y::foo() );
+};
+
+template< typename > struct Z
+{
+  void foo();
+  template< typename T >
+  auto bar() -> decltype( T::foo() );
+};
+
+template< typename > struct K
+{
+  void foo();
+  template< typename T >
+  auto bar() -> decltype( T::foo() );
+};
+
+template<>
+template<>
+auto K<int>::bar<K<int>>() -> decltype( K<int>::foo() );
+
+int main()
+{
+  X<int>().bar();
+  Y<int>().bar<double>();
+  Z<int>().bar<Z<int>>();
+  K<int>().bar<K<int>>();
+}

^ permalink raw reply	[flat|nested] 21+ messages in thread

* Re: [C++ Patch] PR 57543
  2014-05-27 22:08     ` Paolo Carlini
@ 2014-05-28 10:18       ` Paolo Carlini
  2014-05-28 15:14         ` Jason Merrill
  0 siblings, 1 reply; 21+ messages in thread
From: Paolo Carlini @ 2014-05-28 10:18 UTC (permalink / raw)
  To: Jason Merrill, gcc-patches

[-- Attachment #1: Type: text/plain, Size: 186 bytes --]

... turns out, I can avoid fiddling with in_decl (which, I realized, is 
meant to be used for diagnostics). The below version also passes testing.

Thanks,
Paolo.

/////////////////////

[-- Attachment #2: patch_57543_4 --]
[-- Type: text/plain, Size: 2038 bytes --]

Index: cp/pt.c
===================================================================
--- cp/pt.c	(revision 211003)
+++ cp/pt.c	(working copy)
@@ -11323,7 +11323,28 @@ tsubst_function_type (tree t,
   gcc_assert (TYPE_CONTEXT (t) == NULL_TREE);
 
   /* Substitute the return type.  */
+  tree save_ccp = current_class_ptr;
+  tree save_ccr = current_class_ref;
+  bool do_inject = (!current_class_ref
+		    && TREE_CODE (t) == METHOD_TYPE
+		    && TREE_CODE (TREE_TYPE (t)) == DECLTYPE_TYPE);
+  if (do_inject)
+    {
+      /* DR 1207: 'this' is in scope in the trailing return type.  */
+      tree this_type = (current_class_type
+			? current_class_type
+			: TREE_TYPE (TREE_VALUE (TYPE_ARG_TYPES (t))));
+      inject_this_parameter (this_type, type_memfn_quals (t));
+    }
+
   return_type = tsubst (TREE_TYPE (t), args, complain, in_decl);
+
+  if (do_inject)
+    {
+      current_class_ptr = save_ccp;
+      current_class_ref = save_ccr;
+    }
+
   if (return_type == error_mark_node)
     return error_mark_node;
   /* DR 486 clarifies that creation of a function type with an
Index: testsuite/g++.dg/cpp0x/decltype59.C
===================================================================
--- testsuite/g++.dg/cpp0x/decltype59.C	(revision 0)
+++ testsuite/g++.dg/cpp0x/decltype59.C	(working copy)
@@ -0,0 +1,41 @@
+// PR c++/57543
+// { dg-do compile { target c++11 } }
+
+template< typename > struct X
+{
+  void foo();
+  auto bar() -> decltype( X::foo() );
+};
+
+template< typename > struct Y
+{
+  void foo();
+  template< typename >
+  auto bar() -> decltype( Y::foo() );
+};
+
+template< typename > struct Z
+{
+  void foo();
+  template< typename T >
+  auto bar() -> decltype( T::foo() );
+};
+
+template< typename > struct K
+{
+  void foo();
+  template< typename T >
+  auto bar() -> decltype( T::foo() );
+};
+
+template<>
+template<>
+auto K<int>::bar<K<int>>() -> decltype( K<int>::foo() );
+
+int main()
+{
+  X<int>().bar();
+  Y<int>().bar<double>();
+  Z<int>().bar<Z<int>>();
+  K<int>().bar<K<int>>();
+}

^ permalink raw reply	[flat|nested] 21+ messages in thread

* Re: [C++ Patch] PR 57543
  2014-05-28 10:18       ` Paolo Carlini
@ 2014-05-28 15:14         ` Jason Merrill
  2014-05-28 15:41           ` Paolo Carlini
  0 siblings, 1 reply; 21+ messages in thread
From: Jason Merrill @ 2014-05-28 15:14 UTC (permalink / raw)
  To: Paolo Carlini, gcc-patches

On 05/28/2014 06:15 AM, Paolo Carlini wrote:
> +  bool do_inject = (!current_class_ref
> +		    && TREE_CODE (t) == METHOD_TYPE
> +		    && TREE_CODE (TREE_TYPE (t)) == DECLTYPE_TYPE);

Let's do this for any METHOD_TYPE; the decltype could be nested as a 
template argument.  And current_class_ref might be for the wrong class.

> +      /* DR 1207: 'this' is in scope in the trailing return type.  */
> +      tree this_type = (current_class_type
> +			? current_class_type
> +			: TREE_TYPE (TREE_VALUE (TYPE_ARG_TYPES (t))));

And here let's use class_of_this_parm unconditionally.

Jason

^ permalink raw reply	[flat|nested] 21+ messages in thread

* Re: [C++ Patch] PR 57543
  2014-05-28 15:14         ` Jason Merrill
@ 2014-05-28 15:41           ` Paolo Carlini
  2014-05-28 15:49             ` Jason Merrill
  0 siblings, 1 reply; 21+ messages in thread
From: Paolo Carlini @ 2014-05-28 15:41 UTC (permalink / raw)
  To: Jason Merrill, gcc-patches

Hi,

On 05/28/2014 05:14 PM, Jason Merrill wrote:
> On 05/28/2014 06:15 AM, Paolo Carlini wrote:
>> +  bool do_inject = (!current_class_ref
>> +            && TREE_CODE (t) == METHOD_TYPE
>> +            && TREE_CODE (TREE_TYPE (t)) == DECLTYPE_TYPE);
>
> Let's do this for any METHOD_TYPE; the decltype could be nested as a 
> template argument.  And current_class_ref might be for the wrong class.
Ok.
>
>> +      /* DR 1207: 'this' is in scope in the trailing return type.  */
>> +      tree this_type = (current_class_type
>> +            ? current_class_type
>> +            : TREE_TYPE (TREE_VALUE (TYPE_ARG_TYPES (t))));
>
> And here let's use class_of_this_parm unconditionally.
But unconditionally doesn't work, without doing something more. For 
example for the first test, as reported: when current_class_type is set 
and equal to "struct X<int>", class_of_this_parm is "struct X< 
<template-parameter-1-1> >". I'm trying to paste below the trees:

(gdb) p debug_tree(class_of_this_parm(t))
  <record_type 0x7ffff6819a80 X type_0 type_5 type_6 VOID
     size <integer_cst 0x7ffff66d58a0 type <integer_type 0x7ffff66d7150 
bitsizetype> constant 0>
     unit size <integer_cst 0x7ffff66d5858 type <integer_type 
0x7ffff66d70a8 sizetype> constant 0>
     align 8 symtab 0 alias set -1 canonical type 0x7ffff6819a80
     fields <type_decl 0x7ffff6813b80 X
         type <record_type 0x7ffff6819b28 X type_0 type_5 type_6 VOID 
size <integer_cst 0x7ffff66d58a0 0> unit size <integer_cst 0x7ffff66d5858 0>
             align 8 symtab 0 alias set -1 canonical type 0x7ffff6819a80 
fields <type_decl 0x7ffff6813b80 X> context <translation_unit_decl 
0x7ffff66e0170 D.1>
             full-name "struct X< <template-parameter-1-1> >"
             n_parents=0 use_template=0 interface-unknown
             chain <type_decl 0x7ffff6813a10 X>>
         used nonlocal decl_4 VOID file 57543_1.C line 5 col 1
         align 1 context <record_type 0x7ffff6819a80 X> result 
<record_type 0x7ffff6819a80 X>
        > context <translation_unit_decl 0x7ffff66e0170 D.1>
     full-name "struct X< <template-parameter-1-1> >"
     n_parents=0 use_template=0 interface-unknown
     pointer_to_this <pointer_type 0x7ffff6819d20> chain <type_decl 
0x7ffff6813a10 X>>
$3 = void
(gdb) p current_class_type
$4 = (tree) 0x7ffff682a2a0
(gdb) p debug_tree(current_class_type)
  <record_type 0x7ffff682a2a0 X type_5 type_6 VOID
     align 8 symtab 0 alias set -1 canonical type 0x7ffff682a2a0
     fields <type_decl 0x7ffff682c0b8 X
         type <record_type 0x7ffff682a348 X used type_5 type_6 VOID
             align 8 symtab 0 alias set -1 canonical type 0x7ffff682a2a0 
context <translation_unit_decl 0x7ffff66e0170 D.1>
             full-name "struct X<int>"
             n_parents=0 use_template=1 interface-unknown
             chain <type_decl 0x7ffff6813f18 X>>
         used external nonlocal suppress-debug decl_4 VOID file 
57543_1.C line 5 col 1
         align 8 context <record_type 0x7ffff682a2a0 X> result 
<record_type 0x7ffff682a2a0 X>
        > context <translation_unit_decl 0x7ffff66e0170 D.1>
     full-name "struct X<int>"
     n_parents=0 use_template=1 interface-unknown
     pointer_to_this <pointer_type 0x7ffff682a3f0> chain <type_decl 
0x7ffff6813f18 X>>

^ permalink raw reply	[flat|nested] 21+ messages in thread

* Re: [C++ Patch] PR 57543
  2014-05-28 15:41           ` Paolo Carlini
@ 2014-05-28 15:49             ` Jason Merrill
  2014-05-28 16:02               ` Paolo Carlini
  0 siblings, 1 reply; 21+ messages in thread
From: Jason Merrill @ 2014-05-28 15:49 UTC (permalink / raw)
  To: Paolo Carlini, gcc-patches

On 05/28/2014 11:38 AM, Paolo Carlini wrote:
> But unconditionally doesn't work, without doing something more. For
> example for the first test, as reported: when current_class_type is set
> and equal to "struct X<int>", class_of_this_parm is "struct X<
> <template-parameter-1-1> >".

Right, it needs to be the substituted this parameter.

Let's remember when we had a trailing return type (probably by setting a 
flag in splice_late_return_type and then preserving it when we rebuild 
METHOD/FUNCTION_TYPEs) and if it's set, tsubst the return type after the 
argument types rather than before so that SFINAE consistently works in 
lexical order.

Jason

^ permalink raw reply	[flat|nested] 21+ messages in thread

* Re: [C++ Patch] PR 57543
  2014-05-28 15:49             ` Jason Merrill
@ 2014-05-28 16:02               ` Paolo Carlini
  2014-05-28 16:33                 ` Jason Merrill
  0 siblings, 1 reply; 21+ messages in thread
From: Paolo Carlini @ 2014-05-28 16:02 UTC (permalink / raw)
  To: Jason Merrill, gcc-patches

Hi,

On 05/28/2014 05:49 PM, Jason Merrill wrote:
> On 05/28/2014 11:38 AM, Paolo Carlini wrote:
>> But unconditionally doesn't work, without doing something more. For
>> example for the first test, as reported: when current_class_type is set
>> and equal to "struct X<int>", class_of_this_parm is "struct X<
>> <template-parameter-1-1> >".
>
> Right, it needs to be the substituted this parameter.
>
> Let's remember when we had a trailing return type (probably by setting 
> a flag in splice_late_return_type and then preserving it when we 
> rebuild METHOD/FUNCTION_TYPEs) and if it's set, tsubst the return type 
> after the argument types rather than before so that SFINAE 
> consistently works in lexical order.
I see. Even not considering this issue, there are many regression if I 
inject for all method types. I'm afraid the issue turns out to be much 
more tricky than I hoped, I guess I'm going to unassign myself, for now, 
and work on some other pending issues in my todo. You are of course more 
than welcome to take it and include my additional tests in your work!

Thanks,
Paolo.

^ permalink raw reply	[flat|nested] 21+ messages in thread

* Re: [C++ Patch] PR 57543
  2014-05-28 16:02               ` Paolo Carlini
@ 2014-05-28 16:33                 ` Jason Merrill
  2014-05-28 17:09                   ` Paolo Carlini
  0 siblings, 1 reply; 21+ messages in thread
From: Jason Merrill @ 2014-05-28 16:33 UTC (permalink / raw)
  To: Paolo Carlini, gcc-patches

On 05/28/2014 11:59 AM, Paolo Carlini wrote:
> I see. Even not considering this issue, there are many regression if I
> inject for all method types. I'm afraid the issue turns out to be much
> more tricky than I hoped, I guess I'm going to unassign myself, for now,
> and work on some other pending issues in my todo. You are of course more
> than welcome to take it and include my additional tests in your work!

OK.  Please add a link to this thread in the PR, if you haven't already.

Jason


^ permalink raw reply	[flat|nested] 21+ messages in thread

* Re: [C++ Patch] PR 57543
  2014-05-28 16:33                 ` Jason Merrill
@ 2014-05-28 17:09                   ` Paolo Carlini
  2014-05-28 20:03                     ` Paolo Carlini
  2014-05-29 13:34                     ` Jason Merrill
  0 siblings, 2 replies; 21+ messages in thread
From: Paolo Carlini @ 2014-05-28 17:09 UTC (permalink / raw)
  To: Jason Merrill, gcc-patches

[-- Attachment #1: Type: text/plain, Size: 1006 bytes --]

Hi,

On 05/28/2014 06:33 PM, Jason Merrill wrote:
> On 05/28/2014 11:59 AM, Paolo Carlini wrote:
>> I see. Even not considering this issue, there are many regression if I
>> inject for all method types. I'm afraid the issue turns out to be much
>> more tricky than I hoped, I guess I'm going to unassign myself, for now,
>> and work on some other pending issues in my todo. You are of course more
>> than welcome to take it and include my additional tests in your work!
>
> OK.  Please add a link to this thread in the PR, if you haven't already.
Now, I got this "insane" idea: would it make sense to simply invert the 
substitutions (args and return) unconditionally? I'm asking because the 
below appears to pass the testsuite modulo decltype28.C which we would 
end up accepting, but likewise do current clang, icc, and Solaris 
Studio!?! (In case I would have also to double check something weird I 
was seeing if the injection happens for all method types...)

Thanks!
Paolo.

///////////////////////

[-- Attachment #2: p --]
[-- Type: text/plain, Size: 2329 bytes --]

Index: cp/pt.c
===================================================================
--- cp/pt.c	(revision 211024)
+++ cp/pt.c	(working copy)
@@ -11322,8 +11322,32 @@ tsubst_function_type (tree t,
   /* The TYPE_CONTEXT is not used for function/method types.  */
   gcc_assert (TYPE_CONTEXT (t) == NULL_TREE);
 
+  /* Substitute the argument types.  */
+  arg_types = tsubst_arg_types (TYPE_ARG_TYPES (t), args, NULL_TREE,
+				complain, in_decl);
+  if (arg_types == error_mark_node)
+    return error_mark_node;
+
   /* Substitute the return type.  */
+  tree save_ccp = current_class_ptr;
+  tree save_ccr = current_class_ref;
+  bool do_inject = (TREE_CODE (t) == METHOD_TYPE
+		    && TREE_CODE (TREE_TYPE (t)) == DECLTYPE_TYPE);
+  if (do_inject)
+    {
+      /* DR 1207: 'this' is in scope in the trailing return type.  */
+      tree this_type = TREE_TYPE (TREE_VALUE (arg_types));
+      inject_this_parameter (this_type, cp_type_quals (this_type));
+    }
+
   return_type = tsubst (TREE_TYPE (t), args, complain, in_decl);
+
+  if (do_inject)
+    {
+      current_class_ptr = save_ccp;
+      current_class_ref = save_ccr;
+    }
+
   if (return_type == error_mark_node)
     return error_mark_node;
   /* DR 486 clarifies that creation of a function type with an
@@ -11344,12 +11368,6 @@ tsubst_function_type (tree t,
   if (abstract_virtuals_error_sfinae (ACU_RETURN, return_type, complain))
     return error_mark_node;
 
-  /* Substitute the argument types.  */
-  arg_types = tsubst_arg_types (TYPE_ARG_TYPES (t), args, NULL_TREE,
-				complain, in_decl);
-  if (arg_types == error_mark_node)
-    return error_mark_node;
-
   /* Construct a new type node and return it.  */
   if (TREE_CODE (t) == FUNCTION_TYPE)
     {
Index: testsuite/g++.dg/cpp0x/decltype28.C
===================================================================
--- testsuite/g++.dg/cpp0x/decltype28.C	(revision 211024)
+++ testsuite/g++.dg/cpp0x/decltype28.C	(working copy)
@@ -8,9 +8,9 @@ template <class F, int N>
 void ft (F f, typename enable_if<N!=0, int>::type) {}
 
 template< class F, int N >
-decltype(ft<F, N-1> (F(), 0))	// { dg-error "depth" }
+decltype(ft<F, N-1> (F(), 0))
 ft (F f, typename enable_if<N==0, int>::type) {}
 
 int main() {
-  ft<struct a*, 2> (0, 0);	// { dg-message "from here" }
+  ft<struct a*, 2> (0, 0);
 }

^ permalink raw reply	[flat|nested] 21+ messages in thread

* Re: [C++ Patch] PR 57543
  2014-05-28 17:09                   ` Paolo Carlini
@ 2014-05-28 20:03                     ` Paolo Carlini
  2014-05-29  0:07                       ` Paolo Carlini
  2014-05-29 13:34                     ` Jason Merrill
  1 sibling, 1 reply; 21+ messages in thread
From: Paolo Carlini @ 2014-05-28 20:03 UTC (permalink / raw)
  To: Jason Merrill, gcc-patches

[-- Attachment #1: Type: text/plain, Size: 872 bytes --]

Hi again,

On 05/28/2014 07:06 PM, Paolo Carlini wrote:
> (In case I would have also to double check something weird I was 
> seeing if the injection happens for all method types...)
In the meanwhile I investigated the reason of all those regressions I 
was seeing when injecting in all METHOD_TYPEs: while handling, eg, from 
cpp0x/access02.C:

template<class T>
struct foo_argument
{
   template<class Ret, class C, class Arg>
   static Arg test(Ret (C::*)(Arg));
   ...
};

we may still have, *after* substituting the argument types, that the the 
TREE_TYPE of the 0-th argument is still dependent, eg, a 
TEMPLATE_TYPE_PARM. In such cases it seems to me clear that it doesn't 
make sense to inject it, we don't really know the type. Indeed, if we 
try, we ICE in type_of_this_parm.

Thus the below, which passes testing.

Thanks!
Paolo.

////////////////////////////


[-- Attachment #2: patch_57543_5 --]
[-- Type: text/plain, Size: 3284 bytes --]

Index: cp/pt.c
===================================================================
--- cp/pt.c	(revision 211024)
+++ cp/pt.c	(working copy)
@@ -11322,8 +11322,32 @@ tsubst_function_type (tree t,
   /* The TYPE_CONTEXT is not used for function/method types.  */
   gcc_assert (TYPE_CONTEXT (t) == NULL_TREE);
 
+  /* Substitute the argument types.  */
+  arg_types = tsubst_arg_types (TYPE_ARG_TYPES (t), args, NULL_TREE,
+				complain, in_decl);
+  if (arg_types == error_mark_node)
+    return error_mark_node;
+
   /* Substitute the return type.  */
+  tree save_ccp = current_class_ptr;
+  tree save_ccr = current_class_ref;
+  tree this_type = (TREE_CODE (t) == METHOD_TYPE
+		    ? TREE_TYPE (TREE_VALUE (arg_types)) : NULL_TREE);
+  bool do_inject = this_type && !dependent_type_p (this_type);
+  if (do_inject)
+    {
+      /* DR 1207: 'this' is in scope in the trailing return type.  */
+      inject_this_parameter (this_type, cp_type_quals (this_type));
+    }
+
   return_type = tsubst (TREE_TYPE (t), args, complain, in_decl);
+
+  if (do_inject)
+    {
+      current_class_ptr = save_ccp;
+      current_class_ref = save_ccr;
+    }
+
   if (return_type == error_mark_node)
     return error_mark_node;
   /* DR 486 clarifies that creation of a function type with an
@@ -11344,12 +11368,6 @@ tsubst_function_type (tree t,
   if (abstract_virtuals_error_sfinae (ACU_RETURN, return_type, complain))
     return error_mark_node;
 
-  /* Substitute the argument types.  */
-  arg_types = tsubst_arg_types (TYPE_ARG_TYPES (t), args, NULL_TREE,
-				complain, in_decl);
-  if (arg_types == error_mark_node)
-    return error_mark_node;
-
   /* Construct a new type node and return it.  */
   if (TREE_CODE (t) == FUNCTION_TYPE)
     {
Index: testsuite/g++.dg/cpp0x/decltype28.C
===================================================================
--- testsuite/g++.dg/cpp0x/decltype28.C	(revision 211024)
+++ testsuite/g++.dg/cpp0x/decltype28.C	(working copy)
@@ -8,9 +8,9 @@ template <class F, int N>
 void ft (F f, typename enable_if<N!=0, int>::type) {}
 
 template< class F, int N >
-decltype(ft<F, N-1> (F(), 0))	// { dg-error "depth" }
+decltype(ft<F, N-1> (F(), 0))
 ft (F f, typename enable_if<N==0, int>::type) {}
 
 int main() {
-  ft<struct a*, 2> (0, 0);	// { dg-message "from here" }
+  ft<struct a*, 2> (0, 0);
 }
Index: testsuite/g++.dg/cpp0x/decltype59.C
===================================================================
--- testsuite/g++.dg/cpp0x/decltype59.C	(revision 0)
+++ testsuite/g++.dg/cpp0x/decltype59.C	(working copy)
@@ -0,0 +1,41 @@
+// PR c++/57543
+// { dg-do compile { target c++11 } }
+
+template< typename > struct X
+{
+  void foo();
+  auto bar() -> decltype( X::foo() );
+};
+
+template< typename > struct Y
+{
+  void foo();
+  template< typename >
+  auto bar() -> decltype( Y::foo() );
+};
+
+template< typename > struct Z
+{
+  void foo();
+  template< typename T >
+  auto bar() -> decltype( T::foo() );
+};
+
+template< typename > struct K
+{
+  void foo();
+  template< typename T >
+  auto bar() -> decltype( T::foo() );
+};
+
+template<>
+template<>
+auto K<int>::bar<K<int>>() -> decltype( K<int>::foo() );
+
+int main()
+{
+  X<int>().bar();
+  Y<int>().bar<double>();
+  Z<int>().bar<Z<int>>();
+  K<int>().bar<K<int>>();
+}

^ permalink raw reply	[flat|nested] 21+ messages in thread

* Re: [C++ Patch] PR 57543
  2014-05-28 20:03                     ` Paolo Carlini
@ 2014-05-29  0:07                       ` Paolo Carlini
  0 siblings, 0 replies; 21+ messages in thread
From: Paolo Carlini @ 2014-05-29  0:07 UTC (permalink / raw)
  To: Jason Merrill, gcc-patches

On 05/28/2014 10:00 PM, Paolo Carlini wrote:
> Hi again,
>
> On 05/28/2014 07:06 PM, Paolo Carlini wrote:
>> (In case I would have also to double check something weird I was 
>> seeing if the injection happens for all method types...)
> In the meanwhile I investigated the reason of all those regressions I 
> was seeing when injecting in all METHOD_TYPEs: while handling, eg, 
> from cpp0x/access02.C:
>
> template<class T>
> struct foo_argument
> {
>   template<class Ret, class C, class Arg>
>   static Arg test(Ret (C::*)(Arg));
>   ...
> };
Just wanted to add that I spent some time analyzing what we do for the 
above and things seem in good shape: the first time we call 
tsubst_function_type on Ret (C::)(Arg) we don't know the type of C and 
we do not inject. Then we work again on it, when we actually know the 
types of Ret, C, and Arg, and then we inject, and tsubst_function_type 
returns a fully substituted fntype, an (int) (base::) (int).

Paolo.

^ permalink raw reply	[flat|nested] 21+ messages in thread

* Re: [C++ Patch] PR 57543
  2014-05-28 17:09                   ` Paolo Carlini
  2014-05-28 20:03                     ` Paolo Carlini
@ 2014-05-29 13:34                     ` Jason Merrill
  2014-05-29 13:52                       ` Paolo Carlini
  2014-05-29 19:20                       ` Paolo Carlini
  1 sibling, 2 replies; 21+ messages in thread
From: Jason Merrill @ 2014-05-29 13:34 UTC (permalink / raw)
  To: Paolo Carlini, gcc-patches

On 05/28/2014 01:06 PM, Paolo Carlini wrote:
> Now, I got this "insane" idea: would it make sense to simply invert the
> substitutions (args and return) unconditionally?

If we're going to change the order, I want to do it in a more correct, 
rather than differently wrong, way.  DR 1227 clarified that substitution 
should proceed in lexical order.

http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_defects.html#1227

Jason

^ permalink raw reply	[flat|nested] 21+ messages in thread

* Re: [C++ Patch] PR 57543
  2014-05-29 13:34                     ` Jason Merrill
@ 2014-05-29 13:52                       ` Paolo Carlini
  2014-05-29 19:20                       ` Paolo Carlini
  1 sibling, 0 replies; 21+ messages in thread
From: Paolo Carlini @ 2014-05-29 13:52 UTC (permalink / raw)
  To: Jason Merrill, gcc-patches

Hi,

On 05/29/2014 03:34 PM, Jason Merrill wrote:
> On 05/28/2014 01:06 PM, Paolo Carlini wrote:
>> Now, I got this "insane" idea: would it make sense to simply invert the
>> substitutions (args and return) unconditionally?
>
> If we're going to change the order, I want to do it in a more correct, 
> rather than differently wrong, way.  DR 1227 clarified that 
> substitution should proceed in lexical order.
>
> http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_defects.html#1227
Ok, I had no idea we had this kind of much more general issue. Then this 
is really something for you to handle ;)

Thanks!
Paolo.

^ permalink raw reply	[flat|nested] 21+ messages in thread

* Re: [C++ Patch] PR 57543
  2014-05-29 13:34                     ` Jason Merrill
  2014-05-29 13:52                       ` Paolo Carlini
@ 2014-05-29 19:20                       ` Paolo Carlini
  2014-05-30 14:13                         ` Jason Merrill
  1 sibling, 1 reply; 21+ messages in thread
From: Paolo Carlini @ 2014-05-29 19:20 UTC (permalink / raw)
  To: Jason Merrill, gcc-patches

[-- Attachment #1: Type: text/plain, Size: 682 bytes --]

Hi again,

On 05/29/2014 03:34 PM, Jason Merrill wrote:
> On 05/28/2014 01:06 PM, Paolo Carlini wrote:
>> Now, I got this "insane" idea: would it make sense to simply invert the
>> substitutions (args and return) unconditionally?
>
> If we're going to change the order, I want to do it in a more correct, 
> rather than differently wrong, way.  DR 1227 clarified that 
> substitution should proceed in lexical order.
>
> http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_defects.html#1227
So, here is another iteration, sorry about the ping-pong. I put together 
the below which already passes testing. How does it look?

Thanks again for your patience,
Paolo.

/////////////////////

[-- Attachment #2: patch_57543_6 --]
[-- Type: text/plain, Size: 6949 bytes --]

Index: cp/cp-tree.h
===================================================================
--- cp/cp-tree.h	(revision 211052)
+++ cp/cp-tree.h	(working copy)
@@ -125,7 +125,7 @@ c-common.h, not after.
    Usage of TYPE_LANG_FLAG_?:
    0: TYPE_DEPENDENT_P
    1: TYPE_HAS_USER_CONSTRUCTOR.
-   2: unused
+   2: TYPE_HAS_LATE_RETURN_TYPE (in FUNCTION_TYPE, METHOD_TYPE)
    3: TYPE_FOR_JAVA.
    4: TYPE_HAS_NONTRIVIAL_DESTRUCTOR
    5: CLASS_TYPE_P (in RECORD_TYPE and UNION_TYPE)
@@ -3404,6 +3404,11 @@ more_aggr_init_expr_args_p (const aggr_init_expr_a
    user-declared constructor.  */
 #define TYPE_HAS_USER_CONSTRUCTOR(NODE) (TYPE_LANG_FLAG_1 (NODE))
 
+/* Nonzero means that the FUNCTION_TYPE or METHOD_TYPE has a
+   late-specified return type.  */
+#define TYPE_HAS_LATE_RETURN_TYPE(NODE) \
+  (TYPE_LANG_FLAG_2 (FUNC_OR_METHOD_CHECK (NODE)))
+
 /* When appearing in an INDIRECT_REF, it means that the tree structure
    underneath is actually a call to a constructor.  This is needed
    when the constructor must initialize local storage (which can
Index: cp/decl.c
===================================================================
--- cp/decl.c	(revision 211052)
+++ cp/decl.c	(working copy)
@@ -8817,6 +8817,7 @@ grokdeclarator (const cp_declarator *declarator,
   bool template_parm_flag = false;
   bool typedef_p = decl_spec_seq_has_spec_p (declspecs, ds_typedef);
   bool constexpr_p = decl_spec_seq_has_spec_p (declspecs, ds_constexpr);
+  bool late_return_type_p = false;
   source_location saved_loc = input_location;
   const char *errmsg;
 
@@ -9660,6 +9661,9 @@ grokdeclarator (const cp_declarator *declarator,
 	    if (type == error_mark_node)
 	      return error_mark_node;
 
+	    if (declarator->u.function.late_return_type)
+	      late_return_type_p = true;
+
 	    if (ctype == NULL_TREE
 		&& decl_context == FIELD
 		&& funcdecl_p
@@ -10590,6 +10594,10 @@ grokdeclarator (const cp_declarator *declarator,
 	      decl_function_context (TYPE_MAIN_DECL (ctype)) : NULL_TREE;
 	    publicp = (! friendp || ! staticp)
 	      && function_context == NULL_TREE;
+
+	    if (late_return_type_p)
+	      TYPE_HAS_LATE_RETURN_TYPE (type) = 1;
+
 	    decl = grokfndecl (ctype, type,
 			       TREE_CODE (unqualified_id) != TEMPLATE_ID_EXPR
 			       ? unqualified_id : dname,
@@ -10814,6 +10822,9 @@ grokdeclarator (const cp_declarator *declarator,
 	publicp = (ctype != NULL_TREE
 		   || storage_class != sc_static);
 
+	if (late_return_type_p)
+	  TYPE_HAS_LATE_RETURN_TYPE (type) = 1;
+
 	decl = grokfndecl (ctype, type, original_name, parms, unqualified_id,
 			   virtualp, flags, memfn_quals, rqual, raises,
 			   1, friendp,
Index: cp/pt.c
===================================================================
--- cp/pt.c	(revision 211052)
+++ cp/pt.c	(working copy)
@@ -11322,8 +11322,42 @@ tsubst_function_type (tree t,
   /* The TYPE_CONTEXT is not used for function/method types.  */
   gcc_assert (TYPE_CONTEXT (t) == NULL_TREE);
 
-  /* Substitute the return type.  */
-  return_type = tsubst (TREE_TYPE (t), args, complain, in_decl);
+  /* DR 1227:  Mixing immediate and non-immediate contexts in deduction
+     failure.  */
+  bool late_return_type_p = TYPE_HAS_LATE_RETURN_TYPE (t);
+
+  if (late_return_type_p)
+    {
+      /* Substitute the argument types.  */
+      arg_types = tsubst_arg_types (TYPE_ARG_TYPES (t), args, NULL_TREE,
+				    complain, in_decl);
+      if (arg_types == error_mark_node)
+	return error_mark_node;
+
+      tree save_ccp = current_class_ptr;
+      tree save_ccr = current_class_ref;
+      tree this_type = (TREE_CODE (t) == METHOD_TYPE
+			? TREE_TYPE (TREE_VALUE (arg_types)) : NULL_TREE);
+      bool do_inject = this_type && !dependent_type_p (this_type);
+      if (do_inject)
+	{
+	  /* DR 1207: 'this' is in scope in the trailing return type.  */
+	  inject_this_parameter (this_type, cp_type_quals (this_type));
+	}
+
+      /* Substitute the return type.  */
+      return_type = tsubst (TREE_TYPE (t), args, complain, in_decl);
+
+      if (do_inject)
+	{
+	  current_class_ptr = save_ccp;
+	  current_class_ref = save_ccr;
+	}
+    }
+  else
+    /* Substitute the return type.  */
+    return_type = tsubst (TREE_TYPE (t), args, complain, in_decl);
+
   if (return_type == error_mark_node)
     return error_mark_node;
   /* DR 486 clarifies that creation of a function type with an
@@ -11344,11 +11378,14 @@ tsubst_function_type (tree t,
   if (abstract_virtuals_error_sfinae (ACU_RETURN, return_type, complain))
     return error_mark_node;
 
-  /* Substitute the argument types.  */
-  arg_types = tsubst_arg_types (TYPE_ARG_TYPES (t), args, NULL_TREE,
-				complain, in_decl);
-  if (arg_types == error_mark_node)
-    return error_mark_node;
+  if (!late_return_type_p)
+    {
+      /* Substitute the argument types.  */
+      arg_types = tsubst_arg_types (TYPE_ARG_TYPES (t), args, NULL_TREE,
+				    complain, in_decl);
+      if (arg_types == error_mark_node)
+	return error_mark_node;
+    }
 
   /* Construct a new type node and return it.  */
   if (TREE_CODE (t) == FUNCTION_TYPE)
@@ -11384,6 +11421,9 @@ tsubst_function_type (tree t,
     }
   fntype = cp_build_type_attribute_variant (fntype, TYPE_ATTRIBUTES (t));
 
+  if (late_return_type_p)
+    TYPE_HAS_LATE_RETURN_TYPE (fntype) = 1;
+
   return fntype;
 }
 
Index: testsuite/g++.dg/cpp0x/decltype59.C
===================================================================
--- testsuite/g++.dg/cpp0x/decltype59.C	(revision 0)
+++ testsuite/g++.dg/cpp0x/decltype59.C	(working copy)
@@ -0,0 +1,41 @@
+// PR c++/57543
+// { dg-do compile { target c++11 } }
+
+template< typename > struct X
+{
+  void foo();
+  auto bar() -> decltype( X::foo() );
+};
+
+template< typename > struct Y
+{
+  void foo();
+  template< typename >
+  auto bar() -> decltype( Y::foo() );
+};
+
+template< typename > struct Z
+{
+  void foo();
+  template< typename T >
+  auto bar() -> decltype( T::foo() );
+};
+
+template< typename > struct K
+{
+  void foo();
+  template< typename T >
+  auto bar() -> decltype( T::foo() );
+};
+
+template<>
+template<>
+auto K<int>::bar<K<int>>() -> decltype( K<int>::foo() );
+
+int main()
+{
+  X<int>().bar();
+  Y<int>().bar<double>();
+  Z<int>().bar<Z<int>>();
+  K<int>().bar<K<int>>();
+}
Index: testsuite/g++.dg/cpp0x/pr57543.C
===================================================================
--- testsuite/g++.dg/cpp0x/pr57543.C	(revision 0)
+++ testsuite/g++.dg/cpp0x/pr57543.C	(working copy)
@@ -0,0 +1,13 @@
+// PR c++/57543
+// { dg-do compile { target c++11 } } 
+
+template <class T> struct A { using X = typename T::X; };  // { dg-error "not a class" }
+template <class T> typename T::X f(typename A<T>::X);
+template <class T> void f(...) { }
+template <class T> auto g(typename A<T>::X) -> typename T::X;  // { dg-message "required" }
+template <class T> void g(...) { }
+
+void h() {
+  f<int>(0);  // OK
+  g<int>(0);  // { dg-message "required" }
+}

^ permalink raw reply	[flat|nested] 21+ messages in thread

* Re: [C++ Patch] PR 57543
  2014-05-29 19:20                       ` Paolo Carlini
@ 2014-05-30 14:13                         ` Jason Merrill
  2014-05-30 14:24                           ` Paolo Carlini
  0 siblings, 1 reply; 21+ messages in thread
From: Jason Merrill @ 2014-05-30 14:13 UTC (permalink / raw)
  To: Paolo Carlini, gcc-patches

On 05/29/2014 03:17 PM, Paolo Carlini wrote:
> I put together the below which already passes testing.

Thanks!

> +      bool do_inject = this_type && !dependent_type_p (this_type);

!dependent_type_p should be !dependent_scope_p, or perhaps even 
CLASS_TYPE_P.  It should be OK to inject a this pointer of a dependent 
class, and we might need it to get the right semantics.

You also need to propagate the flag in a bunch of other places: 
everywhere we call build_method_type_directly ought to cover it.

Jason

^ permalink raw reply	[flat|nested] 21+ messages in thread

* Re: [C++ Patch] PR 57543
  2014-05-30 14:13                         ` Jason Merrill
@ 2014-05-30 14:24                           ` Paolo Carlini
  2014-05-30 14:41                             ` Jason Merrill
  0 siblings, 1 reply; 21+ messages in thread
From: Paolo Carlini @ 2014-05-30 14:24 UTC (permalink / raw)
  To: Jason Merrill, gcc-patches

Hi,

On 05/30/2014 04:13 PM, Jason Merrill wrote:
> On 05/29/2014 03:17 PM, Paolo Carlini wrote:
>> I put together the below which already passes testing.
>
> Thanks!
You are welcome. Let's finish this, then ;)
>
>> +      bool do_inject = this_type && !dependent_type_p (this_type);
>
> !dependent_type_p should be !dependent_scope_p, or perhaps even 
> CLASS_TYPE_P.  It should be OK to inject a this pointer of a dependent 
> class, and we might need it to get the right semantics.
I suspected that. I'll experiment with the latter, or in case the former.
> You also need to propagate the flag in a bunch of other places: 
> everywhere we call build_method_type_directly ought to cover it.
Agreed, I spotted a few places. What about build_function_type? I think 
it's the same issue, right? Because in that case we don't have any 
problem with the injection of this but we want to propagate the flag in 
order to eventually have tsubst_function_type substituting in the right 
order.

Paolo.

^ permalink raw reply	[flat|nested] 21+ messages in thread

* Re: [C++ Patch] PR 57543
  2014-05-30 14:24                           ` Paolo Carlini
@ 2014-05-30 14:41                             ` Jason Merrill
  2014-05-30 17:39                               ` Paolo Carlini
  0 siblings, 1 reply; 21+ messages in thread
From: Jason Merrill @ 2014-05-30 14:41 UTC (permalink / raw)
  To: Paolo Carlini, gcc-patches

On 05/30/2014 10:21 AM, Paolo Carlini wrote:
>> You also need to propagate the flag in a bunch of other places:
>> everywhere we call build_method_type_directly ought to cover it.
> Agreed, I spotted a few places. What about build_function_type? I think
> it's the same issue, right?

Right, I was just thinking that the relevant uses of build_function_type 
will be near calls to build_method_type_directly.  :)

Jason

^ permalink raw reply	[flat|nested] 21+ messages in thread

* Re: [C++ Patch] PR 57543
  2014-05-30 14:41                             ` Jason Merrill
@ 2014-05-30 17:39                               ` Paolo Carlini
  2014-05-30 18:54                                 ` Jason Merrill
  0 siblings, 1 reply; 21+ messages in thread
From: Paolo Carlini @ 2014-05-30 17:39 UTC (permalink / raw)
  To: Jason Merrill, gcc-patches

[-- Attachment #1: Type: text/plain, Size: 1804 bytes --]

Hi,

On 05/30/2014 04:41 PM, Jason Merrill wrote:
> On 05/30/2014 10:21 AM, Paolo Carlini wrote:
>>> You also need to propagate the flag in a bunch of other places:
>>> everywhere we call build_method_type_directly ought to cover it.
>> Agreed, I spotted a few places. What about build_function_type? I think
>> it's the same issue, right?
>
> Right, I was just thinking that the relevant uses of 
> build_function_type will be near calls to build_method_type_directly.  :)
Indeed. Thus I have the below, which passes testing. Most of the changes 
are quite obvious, some maybe redundant but safe, I think. Exceptions:
1- I'm not sure cp_reconstruct_complex_type needs the changes, but 
probably cannot hurt.
2- Likewise change_return_type, for different reasons.
3- I understand Core/1227 as including the case of the late return type 
vs the parameters of generic lambdas, thus the rather heavy handed tweak 
to cp_parser_lambda_declarator_opt, which appears to work under the 
debugger (in the sense that for testcases like 
cpp1y/lambda-generic-cfun.C I checked that the on flag is still there in 
the eventual tsubst_function_type), but I need help about the conversion 
operator: should I do something in maybe_add_lambda_conv_op, thus 
propagate somehow from TREE_TYPE (callop)?!? In case, it would be easy, 
but I need help about the actual semantics we want (this isn't really 
about our impl, more about the specs of generic lambdas, sorry).

Finally, about !dependent_scope_p vs CLASS_TYPE_P, just wanted to 
mention, in case isn't obvious already, that build_this_parm has 
CLASS_TYPE_P which we badly want to be true if we want to avoid 
immediate ICEs in type_of_this_parm. Thus, it seems in fact the minimal 
check to use in tsusbt_function_type.

Thanks!
Paolo.

////////////////////////

[-- Attachment #2: patch_57543_7 --]
[-- Type: text/plain, Size: 14565 bytes --]

Index: cp/cp-tree.h
===================================================================
--- cp/cp-tree.h	(revision 211072)
+++ cp/cp-tree.h	(working copy)
@@ -125,7 +125,7 @@ c-common.h, not after.
    Usage of TYPE_LANG_FLAG_?:
    0: TYPE_DEPENDENT_P
    1: TYPE_HAS_USER_CONSTRUCTOR.
-   2: unused
+   2: TYPE_HAS_LATE_RETURN_TYPE (in FUNCTION_TYPE, METHOD_TYPE)
    3: TYPE_FOR_JAVA.
    4: TYPE_HAS_NONTRIVIAL_DESTRUCTOR
    5: CLASS_TYPE_P (in RECORD_TYPE and UNION_TYPE)
@@ -3404,6 +3404,11 @@ more_aggr_init_expr_args_p (const aggr_init_expr_a
    user-declared constructor.  */
 #define TYPE_HAS_USER_CONSTRUCTOR(NODE) (TYPE_LANG_FLAG_1 (NODE))
 
+/* Nonzero means that the FUNCTION_TYPE or METHOD_TYPE has a
+   late-specified return type.  */
+#define TYPE_HAS_LATE_RETURN_TYPE(NODE) \
+  (TYPE_LANG_FLAG_2 (FUNC_OR_METHOD_CHECK (NODE)))
+
 /* When appearing in an INDIRECT_REF, it means that the tree structure
    underneath is actually a call to a constructor.  This is needed
    when the constructor must initialize local storage (which can
Index: cp/decl.c
===================================================================
--- cp/decl.c	(revision 211072)
+++ cp/decl.c	(working copy)
@@ -8817,6 +8817,7 @@ grokdeclarator (const cp_declarator *declarator,
   bool template_parm_flag = false;
   bool typedef_p = decl_spec_seq_has_spec_p (declspecs, ds_typedef);
   bool constexpr_p = decl_spec_seq_has_spec_p (declspecs, ds_constexpr);
+  bool late_return_type_p = false;
   source_location saved_loc = input_location;
   const char *errmsg;
 
@@ -9660,6 +9661,9 @@ grokdeclarator (const cp_declarator *declarator,
 	    if (type == error_mark_node)
 	      return error_mark_node;
 
+	    if (declarator->u.function.late_return_type)
+	      late_return_type_p = true;
+
 	    if (ctype == NULL_TREE
 		&& decl_context == FIELD
 		&& funcdecl_p
@@ -10590,6 +10594,10 @@ grokdeclarator (const cp_declarator *declarator,
 	      decl_function_context (TYPE_MAIN_DECL (ctype)) : NULL_TREE;
 	    publicp = (! friendp || ! staticp)
 	      && function_context == NULL_TREE;
+
+	    if (late_return_type_p)
+	      TYPE_HAS_LATE_RETURN_TYPE (type) = 1;
+
 	    decl = grokfndecl (ctype, type,
 			       TREE_CODE (unqualified_id) != TEMPLATE_ID_EXPR
 			       ? unqualified_id : dname,
@@ -10814,6 +10822,9 @@ grokdeclarator (const cp_declarator *declarator,
 	publicp = (ctype != NULL_TREE
 		   || storage_class != sc_static);
 
+	if (late_return_type_p)
+	  TYPE_HAS_LATE_RETURN_TYPE (type) = 1;
+
 	decl = grokfndecl (ctype, type, original_name, parms, unqualified_id,
 			   virtualp, flags, memfn_quals, rqual, raises,
 			   1, friendp,
@@ -14421,6 +14432,8 @@ static_fn_type (tree memfntype)
 	    (fntype, TYPE_ATTRIBUTES (memfntype)));
   fntype = (build_exception_variant
 	    (fntype, TYPE_RAISES_EXCEPTIONS (memfntype)));
+  if (TYPE_HAS_LATE_RETURN_TYPE (memfntype))
+    TYPE_HAS_LATE_RETURN_TYPE (fntype) = 1;
   return fntype;
 }
 
Index: cp/decl2.c
===================================================================
--- cp/decl2.c	(revision 211072)
+++ cp/decl2.c	(working copy)
@@ -119,6 +119,7 @@ build_memfn_type (tree fntype, tree ctype, cp_cv_q
   tree raises;
   tree attrs;
   int type_quals;
+  bool late_return_type_p;
 
   if (fntype == error_mark_node || ctype == error_mark_node)
     return error_mark_node;
@@ -130,6 +131,7 @@ build_memfn_type (tree fntype, tree ctype, cp_cv_q
   ctype = cp_build_qualified_type (ctype, type_quals);
   raises = TYPE_RAISES_EXCEPTIONS (fntype);
   attrs = TYPE_ATTRIBUTES (fntype);
+  late_return_type_p = TYPE_HAS_LATE_RETURN_TYPE (fntype);
   fntype = build_method_type_directly (ctype, TREE_TYPE (fntype),
 				       (TREE_CODE (fntype) == METHOD_TYPE
 					? TREE_CHAIN (TYPE_ARG_TYPES (fntype))
@@ -140,6 +142,8 @@ build_memfn_type (tree fntype, tree ctype, cp_cv_q
     fntype = build_ref_qualified_type (fntype, rqual);
   if (raises)
     fntype = build_exception_variant (fntype, raises);
+  if (late_return_type_p)
+    TYPE_HAS_LATE_RETURN_TYPE (fntype) = 1;
 
   return fntype;
 }
@@ -154,6 +158,7 @@ change_return_type (tree new_ret, tree fntype)
   tree args = TYPE_ARG_TYPES (fntype);
   tree raises = TYPE_RAISES_EXCEPTIONS (fntype);
   tree attrs = TYPE_ATTRIBUTES (fntype);
+  bool late_return_type_p = TYPE_HAS_LATE_RETURN_TYPE (fntype);
 
   if (new_ret == error_mark_node)
     return fntype;
@@ -175,6 +180,8 @@ change_return_type (tree new_ret, tree fntype)
     newtype = build_exception_variant (newtype, raises);
   if (attrs)
     newtype = cp_build_type_attribute_variant (newtype, attrs);
+  if (late_return_type_p)
+    TYPE_HAS_LATE_RETURN_TYPE (newtype) = 1;
 
   return newtype;
 }
@@ -1276,6 +1283,7 @@ tree
 cp_reconstruct_complex_type (tree type, tree bottom)
 {
   tree inner, outer;
+  bool late_return_type_p = false;
 
   if (TYPE_PTR_P (type))
     {
@@ -1301,6 +1309,7 @@ cp_reconstruct_complex_type (tree type, tree botto
     }
   else if (TREE_CODE (type) == FUNCTION_TYPE)
     {
+      late_return_type_p = TYPE_HAS_LATE_RETURN_TYPE (type);
       inner = cp_reconstruct_complex_type (TREE_TYPE (type), bottom);
       outer = build_function_type (inner, TYPE_ARG_TYPES (type));
       outer = apply_memfn_quals (outer,
@@ -1309,6 +1318,7 @@ cp_reconstruct_complex_type (tree type, tree botto
     }
   else if (TREE_CODE (type) == METHOD_TYPE)
     {
+      late_return_type_p = TYPE_HAS_LATE_RETURN_TYPE (type);
       inner = cp_reconstruct_complex_type (TREE_TYPE (type), bottom);
       /* The build_method_type_directly() routine prepends 'this' to argument list,
 	 so we must compensate by getting rid of it.  */
@@ -1327,7 +1337,12 @@ cp_reconstruct_complex_type (tree type, tree botto
 
   if (TYPE_ATTRIBUTES (type))
     outer = cp_build_type_attribute_variant (outer, TYPE_ATTRIBUTES (type));
-  return cp_build_qualified_type (outer, cp_type_quals (type));
+  outer = cp_build_qualified_type (outer, cp_type_quals (type));
+
+  if (late_return_type_p)
+    TYPE_HAS_LATE_RETURN_TYPE (outer) = 1;
+
+  return outer;
 }
 
 /* Replaces any constexpr expression that may be into the attributes
Index: cp/parser.c
===================================================================
--- cp/parser.c	(revision 211072)
+++ cp/parser.c	(working copy)
@@ -9152,6 +9152,8 @@ cp_parser_lambda_declarator_opt (cp_parser* parser
 	DECL_ARTIFICIAL (fco) = 1;
 	/* Give the object parameter a different name.  */
 	DECL_NAME (DECL_ARGUMENTS (fco)) = get_identifier ("__closure");
+	if (LAMBDA_EXPR_RETURN_TYPE (lambda_expr))
+	  TYPE_HAS_LATE_RETURN_TYPE (TREE_TYPE (fco)) = 1;
       }
     if (template_param_list)
       {
Index: cp/pt.c
===================================================================
--- cp/pt.c	(revision 211072)
+++ cp/pt.c	(working copy)
@@ -2256,6 +2256,10 @@ copy_default_args_to_explicit_spec (tree decl)
 					      TYPE_ATTRIBUTES (old_type));
   new_type = build_exception_variant (new_type,
 				      TYPE_RAISES_EXCEPTIONS (old_type));
+
+  if (TYPE_HAS_LATE_RETURN_TYPE (old_type))
+    TYPE_HAS_LATE_RETURN_TYPE (new_type) = 1;
+
   TREE_TYPE (decl) = new_type;
 }
 
@@ -11322,8 +11326,42 @@ tsubst_function_type (tree t,
   /* The TYPE_CONTEXT is not used for function/method types.  */
   gcc_assert (TYPE_CONTEXT (t) == NULL_TREE);
 
-  /* Substitute the return type.  */
-  return_type = tsubst (TREE_TYPE (t), args, complain, in_decl);
+  /* DR 1227: Mixing immediate and non-immediate contexts in deduction
+     failure.  */
+  bool late_return_type_p = TYPE_HAS_LATE_RETURN_TYPE (t);
+
+  if (late_return_type_p)
+    {
+      /* Substitute the argument types.  */
+      arg_types = tsubst_arg_types (TYPE_ARG_TYPES (t), args, NULL_TREE,
+				    complain, in_decl);
+      if (arg_types == error_mark_node)
+	return error_mark_node;
+
+      tree save_ccp = current_class_ptr;
+      tree save_ccr = current_class_ref;
+      tree this_type = (TREE_CODE (t) == METHOD_TYPE
+			? TREE_TYPE (TREE_VALUE (arg_types)) : NULL_TREE);
+      bool do_inject = this_type && CLASS_TYPE_P (this_type);
+      if (do_inject)
+	{
+	  /* DR 1207: 'this' is in scope in the trailing return type.  */
+	  inject_this_parameter (this_type, cp_type_quals (this_type));
+	}
+
+      /* Substitute the return type.  */
+      return_type = tsubst (TREE_TYPE (t), args, complain, in_decl);
+
+      if (do_inject)
+	{
+	  current_class_ptr = save_ccp;
+	  current_class_ref = save_ccr;
+	}
+    }
+  else
+    /* Substitute the return type.  */
+    return_type = tsubst (TREE_TYPE (t), args, complain, in_decl);
+
   if (return_type == error_mark_node)
     return error_mark_node;
   /* DR 486 clarifies that creation of a function type with an
@@ -11344,11 +11382,14 @@ tsubst_function_type (tree t,
   if (abstract_virtuals_error_sfinae (ACU_RETURN, return_type, complain))
     return error_mark_node;
 
-  /* Substitute the argument types.  */
-  arg_types = tsubst_arg_types (TYPE_ARG_TYPES (t), args, NULL_TREE,
-				complain, in_decl);
-  if (arg_types == error_mark_node)
-    return error_mark_node;
+  if (!late_return_type_p)
+    {
+      /* Substitute the argument types.  */
+      arg_types = tsubst_arg_types (TYPE_ARG_TYPES (t), args, NULL_TREE,
+				    complain, in_decl);
+      if (arg_types == error_mark_node)
+	return error_mark_node;
+    }
 
   /* Construct a new type node and return it.  */
   if (TREE_CODE (t) == FUNCTION_TYPE)
@@ -11384,6 +11425,9 @@ tsubst_function_type (tree t,
     }
   fntype = cp_build_type_attribute_variant (fntype, TYPE_ATTRIBUTES (t));
 
+  if (late_return_type_p)
+    TYPE_HAS_LATE_RETURN_TYPE (fntype) = 1;
+
   return fntype;
 }
 
Index: cp/tree.c
===================================================================
--- cp/tree.c	(revision 211072)
+++ cp/tree.c	(working copy)
@@ -1257,6 +1257,8 @@ strip_typedefs (tree t)
 	if (TYPE_RAISES_EXCEPTIONS (t))
 	  result = build_exception_variant (result,
 					    TYPE_RAISES_EXCEPTIONS (t));
+	if (TYPE_HAS_LATE_RETURN_TYPE (t))
+	  TYPE_HAS_LATE_RETURN_TYPE (result) = 1;
       }
       break;
     case TYPENAME_TYPE:
Index: cp/typeck.c
===================================================================
--- cp/typeck.c	(revision 211072)
+++ cp/typeck.c	(working copy)
@@ -818,6 +818,7 @@ merge_types (tree t1, tree t2)
 	tree p2 = TYPE_ARG_TYPES (t2);
 	tree parms;
 	tree rval, raises;
+	bool late_return_type_p = TYPE_HAS_LATE_RETURN_TYPE (t1);
 
 	/* Save space: see if the result is identical to one of the args.  */
 	if (valtype == TREE_TYPE (t1) && ! p2)
@@ -842,6 +843,8 @@ merge_types (tree t1, tree t2)
 	raises = merge_exception_specifiers (TYPE_RAISES_EXCEPTIONS (t1),
 					     TYPE_RAISES_EXCEPTIONS (t2));
 	t1 = build_exception_variant (rval, raises);
+	if (late_return_type_p)
+	  TYPE_HAS_LATE_RETURN_TYPE (t1) = 1;
 	break;
       }
 
@@ -854,6 +857,7 @@ merge_types (tree t1, tree t2)
 						  TYPE_RAISES_EXCEPTIONS (t2));
 	cp_ref_qualifier rqual = type_memfn_rqual (t1);
 	tree t3;
+	bool late_return_type_p = TYPE_HAS_LATE_RETURN_TYPE (t1);
 
 	/* If this was a member function type, get back to the
 	   original type of type member function (i.e., without
@@ -867,6 +871,8 @@ merge_types (tree t1, tree t2)
 					 TYPE_ARG_TYPES (t3));
 	t1 = build_exception_variant (t3, raises);
 	t1 = build_ref_qualified_type (t1, rqual);
+	if (late_return_type_p)
+	  TYPE_HAS_LATE_RETURN_TYPE (t1) = 1;
 	break;
       }
 
Index: testsuite/g++.dg/cpp0x/decltype59.C
===================================================================
--- testsuite/g++.dg/cpp0x/decltype59.C	(revision 0)
+++ testsuite/g++.dg/cpp0x/decltype59.C	(working copy)
@@ -0,0 +1,41 @@
+// PR c++/57543
+// { dg-do compile { target c++11 } }
+
+template< typename > struct X
+{
+  void foo();
+  auto bar() -> decltype( X::foo() );
+};
+
+template< typename > struct Y
+{
+  void foo();
+  template< typename >
+  auto bar() -> decltype( Y::foo() );
+};
+
+template< typename > struct Z
+{
+  void foo();
+  template< typename T >
+  auto bar() -> decltype( T::foo() );
+};
+
+template< typename > struct K
+{
+  void foo();
+  template< typename T >
+  auto bar() -> decltype( T::foo() );
+};
+
+template<>
+template<>
+auto K<int>::bar<K<int>>() -> decltype( K<int>::foo() );
+
+int main()
+{
+  X<int>().bar();
+  Y<int>().bar<double>();
+  Z<int>().bar<Z<int>>();
+  K<int>().bar<K<int>>();
+}
Index: testsuite/g++.dg/cpp0x/pr57543-1.C
===================================================================
--- testsuite/g++.dg/cpp0x/pr57543-1.C	(revision 0)
+++ testsuite/g++.dg/cpp0x/pr57543-1.C	(working copy)
@@ -0,0 +1,13 @@
+// PR c++/57543
+// { dg-do compile { target c++11 } } 
+
+template <class T> struct A { using X = typename T::X; };  // { dg-error "not a class" }
+template <class T> typename T::X f(typename A<T>::X);
+template <class T> void f(...) { }
+template <class T> auto g(typename A<T>::X) -> typename T::X;  // { dg-message "required" }
+template <class T> void g(...) { }
+
+void h() {
+  f<int>(0);  // OK
+  g<int>(0);  // { dg-message "required" }
+}
Index: testsuite/g++.dg/cpp0x/pr57543-2.C
===================================================================
--- testsuite/g++.dg/cpp0x/pr57543-2.C	(revision 0)
+++ testsuite/g++.dg/cpp0x/pr57543-2.C	(working copy)
@@ -0,0 +1,17 @@
+// PR c++/57543
+// { dg-do compile { target c++11 } } 
+
+struct S
+{
+  template <class T> struct A { using X = typename T::X; };  // { dg-error "not a class" }
+  template <class T> typename T::X f(typename A<T>::X);
+  template <class T> void f(...) { }
+  template <class T> auto g(typename A<T>::X) -> typename T::X;  // { dg-message "required" }
+  template <class T> void g(...) { }
+
+  void h()
+  {
+    f<int>(0);  // OK
+    g<int>(0);  // { dg-message "required" }
+  }
+};
Index: testsuite/g++.dg/cpp0x/pr57543-3.C
===================================================================
--- testsuite/g++.dg/cpp0x/pr57543-3.C	(revision 0)
+++ testsuite/g++.dg/cpp0x/pr57543-3.C	(working copy)
@@ -0,0 +1,20 @@
+// PR c++/57543
+// { dg-do compile { target c++11 } } 
+
+template <class>
+class C
+{
+  template <class T> struct A { using X = typename T::X; };  // { dg-error "not a class" }
+  template <class T> typename T::X f(typename A<T>::X);
+  template <class T> void f(...) { }
+  template <class T> auto g(typename A<T>::X) -> typename T::X;  // { dg-message "required" }
+  template <class T> void g(...) { }
+
+  void h()
+  {
+    f<int>(0);  // OK
+    g<int>(0);  // { dg-message "required" }
+  }
+};
+
+template class C<int>;  // { dg-message "required" }

^ permalink raw reply	[flat|nested] 21+ messages in thread

* Re: [C++ Patch] PR 57543
  2014-05-30 17:39                               ` Paolo Carlini
@ 2014-05-30 18:54                                 ` Jason Merrill
  0 siblings, 0 replies; 21+ messages in thread
From: Jason Merrill @ 2014-05-30 18:54 UTC (permalink / raw)
  To: Paolo Carlini, gcc-patches

On 05/30/2014 01:36 PM, Paolo Carlini wrote:
> 3- I understand Core/1227 as including the case of the late return type
> vs the parameters of generic lambdas, thus the rather heavy handed tweak
> to cp_parser_lambda_declarator_opt, which appears to work under the
> debugger (in the sense that for testcases like
> cpp1y/lambda-generic-cfun.C I checked that the on flag is still there in
> the eventual tsubst_function_type), but I need help about the conversion
> operator: should I do something in maybe_add_lambda_conv_op, thus
> propagate somehow from TREE_TYPE (callop)?!? In case, it would be easy,
> but I need help about the actual semantics we want (this isn't really
> about our impl, more about the specs of generic lambdas, sorry).

I don't think we need to worry about the conversion op, as it doesn't 
have any parameters.

The patch is OK.

Jason

^ permalink raw reply	[flat|nested] 21+ messages in thread

end of thread, other threads:[~2014-05-30 18:54 UTC | newest]

Thread overview: 21+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2014-05-27 13:32 [C++ Patch] PR 57543 Paolo Carlini
2014-05-27 17:15 ` Jason Merrill
2014-05-27 21:43   ` Paolo Carlini
2014-05-27 22:08     ` Paolo Carlini
2014-05-28 10:18       ` Paolo Carlini
2014-05-28 15:14         ` Jason Merrill
2014-05-28 15:41           ` Paolo Carlini
2014-05-28 15:49             ` Jason Merrill
2014-05-28 16:02               ` Paolo Carlini
2014-05-28 16:33                 ` Jason Merrill
2014-05-28 17:09                   ` Paolo Carlini
2014-05-28 20:03                     ` Paolo Carlini
2014-05-29  0:07                       ` Paolo Carlini
2014-05-29 13:34                     ` Jason Merrill
2014-05-29 13:52                       ` Paolo Carlini
2014-05-29 19:20                       ` Paolo Carlini
2014-05-30 14:13                         ` Jason Merrill
2014-05-30 14:24                           ` Paolo Carlini
2014-05-30 14:41                             ` Jason Merrill
2014-05-30 17:39                               ` Paolo Carlini
2014-05-30 18:54                                 ` Jason Merrill

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for read-only IMAP folder(s) and NNTP newsgroup(s).