diff mbox

[C++] PR 57543

Message ID 5385B756.8070707@oracle.com
State New
Headers show

Commit Message

Paolo Carlini May 28, 2014, 10:15 a.m. UTC
... 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.

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

Comments

Jason Merrill May 28, 2014, 3:14 p.m. UTC | #1
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
Paolo Carlini May 28, 2014, 3:38 p.m. UTC | #2
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>>
Jason Merrill May 28, 2014, 3:49 p.m. UTC | #3
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
Paolo Carlini May 28, 2014, 3:59 p.m. UTC | #4
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.
Jason Merrill May 28, 2014, 4:33 p.m. UTC | #5
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
diff mbox

Patch

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>>();
+}