diff mbox

[C++,/,RFC] PR 50870

Message ID 4EA8879F.40906@oracle.com
State New
Headers show

Commit Message

Paolo Carlini Oct. 26, 2011, 10:20 p.m. UTC
On 10/26/2011 06:27 PM, Jason Merrill wrote:
> OK.
I re-opened this one because: 1- We may want to fix it in 4_6-branch 
too, it's a regression there too; 2- We are still handling incorrectly 
the template impl case. For the latter a variant of my old idea still 
works, fwiw.

Thanks,
Paolo.

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

Comments

Paolo Carlini Oct. 26, 2011, 10:25 p.m. UTC | #1
... forgot the testcase, sorry.

Paolo.

//////////////////////
Jason Merrill Oct. 26, 2011, 10:48 p.m. UTC | #2
On 10/26/2011 06:20 PM, Paolo Carlini wrote:
> I re-opened this one because: 1- We may want to fix it in 4_6-branch
> too, it's a regression there too; 2- We are still handling incorrectly
> the template impl case. For the latter a variant of my old idea still
> works, fwiw.

> -	object_type = TREE_TYPE (object);
> +	object_type = (TREE_CODE (object) == ARROW_EXPR
> +		       ? TREE_OPERAND (object, 0) : TREE_TYPE (object));

This is still wrong.  Why not use the same patch for 4.6 as for trunk?

Jason
Paolo Carlini Oct. 26, 2011, 10:53 p.m. UTC | #3
On 10/27/2011 12:48 AM, Jason Merrill wrote:
> On 10/26/2011 06:20 PM, Paolo Carlini wrote:
>> I re-opened this one because: 1- We may want to fix it in 4_6-branch
>> too, it's a regression there too; 2- We are still handling incorrectly
>> the template impl case. For the latter a variant of my old idea still
>> works, fwiw.
>
>> -    object_type = TREE_TYPE (object);
>> +    object_type = (TREE_CODE (object) == ARROW_EXPR
>> +               ? TREE_OPERAND (object, 0) : TREE_TYPE (object));
> This is still wrong.  Why not use the same patch for 4.6 as for trunk?
I don't understand, sorry: both mainline and 4_6-branch do not handle 
correctly both testcases, template impl and not. If you want to look 
into it personally, I can unassign myself, no problem, really.

Paolo.
Paolo Carlini Oct. 26, 2011, 11 p.m. UTC | #4
.. maybe my message wasn't clear, sorry, I'm a bit tired (here it's 
late): I meant to say that the non_reference tweak fixes the 
non-template impl class case, but something more is needed for a 
template impl (thus the new testcase). And, additionally, this issue is 
a [4.6/4.7 Regression], thus, post 4.6.2, we may be interested in back 
porting something.

Let me know if you need additional details, or whatelse. Or we want me 
to look into a different way to attack the template case.

Paolo.
Jason Merrill Oct. 27, 2011, 4:11 a.m. UTC | #5
On 10/26/2011 07:00 PM, Paolo Carlini wrote:
> .. maybe my message wasn't clear, sorry, I'm a bit tired (here it's
> late): I meant to say that the non_reference tweak fixes the
> non-template impl class case, but something more is needed for a
> template impl (thus the new testcase). And, additionally, this issue is
> a [4.6/4.7 Regression], thus, post 4.6.2, we may be interested in back
> porting something.

Ah.

> Let me know if you need additional details, or what else.

How is the template case failing?

> Or we want me to look into a different way to attack the template case.

Please.

Jason
Paolo Carlini Oct. 27, 2011, 11:29 a.m. UTC | #6
Hi,
> > Let me know if you need additional details, or what else.
>
> How is the template case failing?
Some preliminary notes, maybe you can already make some sense out of 
this, more later, if you like:

Thus we have this testcase:

template <class V>
   struct impl
   {
     template <class T> static T create();
   };

template <class T, class U, class V, class
       = decltype(impl<V>::template create<T>()
              -> impl<V>::template create<U>())>
struct tester { };

tester<impl<float>*, int, float> ti;

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

We are in tsubst_copy_and_build, COMPONENT_REF case. Argument t is:

<component_ref 0x7ffff57810e0
     arg 0 <arrow_expr 0x7ffff5769f00
         arg 0 <call_expr 0x7ffff57810a8
             fn <scope_ref 0x7ffff563db40 tree_0 tree_1 arg 0 
<record_type 0x7ffff577f540 impl>
                 arg 1 <template_id_expr 0x7ffff563da80
                     arg 0 <identifier_node 0x7ffff577e790 create
                         bindings <(nil)>
                         local bindings <(nil)>>
                     arg 1 <tree_vec 0x7ffff5769e38 elt 0 
<template_type_parm 0x7ffff577f348 T>>>>>>
     arg 1 <scope_ref 0x7ffff563db70 tree_0 tree_1
         arg 0 <record_type 0x7ffff577f540 impl type_0 type_5 type_6 VOID
             align 8 symtab 0 alias set -1 canonical type 0x7ffff577f540 
context <translation_unit_decl 0x7ffff5646170 D.1>
             full-name "struct impl<V>"
             no-binfo use_template=1 interface-unknown
             chain <type_decl 0x7ffff5780170 impl>>
         arg 1 <template_id_expr 0x7ffff563dae0 arg 0 <identifier_node 
0x7ffff577e790 create>
             arg 1 <tree_vec 0x7ffff5769ed8 elt 0 <template_type_parm 
0x7ffff577f3f0 U>>>>>

Everything begins like the non-template case: member is computed, we get to:

else if (TREE_CODE (member) == SCOPE_REF
&& TREE_CODE (TREE_OPERAND (member, 1)) == TEMPLATE_ID_EXPR)

in here we have a call of lookup_qualified_name (TREE_OPERAND (member, 
0), tmpl, ... which, in this case, fails, returns error_mark_node (Seg 
Fault immediately after).

When lookup_qualified_name is called, this is member:

<scope_ref 0x7ffff563dd20 tree_0 tree_1
     arg 0 <record_type 0x7ffff577f9d8 impl type_0 type_5 type_6 VOID
         align 8 symtab 0 alias set -1 canonical type 0x7ffff577f9d8 
context <translation_unit_decl 0x7ffff5646170 D.1>
         full-name "struct impl<V>"
         no-binfo use_template=1 interface-unknown
         chain <type_decl 0x7ffff57802e0 impl>>
     arg 1 <template_id_expr 0x7ffff563dcf0
         type <lang_type 0x7ffff5765888 unknown type type <lang_type 
0x7ffff5765888 unknown type>
             VOID
             align 1 symtab 0 alias set -1 canonical type 0x7ffff5765888
             pointer_to_this <lang_type 0x7ffff5765888 unknown type> 
reference_to_this <lang_type 0x7ffff5765888 unknown type>>

         arg 0 <identifier_node 0x7ffff577e790 create
             bindings <(nil)>
             local bindings <(nil)>>
         arg 1 <tree_vec 0x7ffff5783140 elt 0 <template_type_parm 
0x7ffff577f7e0 U>>>>

and this is tmpl:

<identifier_node 0x7ffff577e790 create bindings <(nil)> local bindings 
<(nil)>>

For comparison, in the non-template case, path inside COMPONENT_REF is 
rather different after member: none of the if branches is executed, we 
just get to return finish_class_member_access_expr at the end of case 
COMPONENT_REF.

Thanks!
Paolo.
Jason Merrill Oct. 27, 2011, 12:43 p.m. UTC | #7
Looks like

>                 qualified_name_lookup_error (object_type, tmpl, member,
>                                              input_location);

is passing the wrong first argument; the scope argument should be the 
same as we passed to lookup_qualified_name.

Jason
Paolo Carlini Oct. 27, 2011, 12:57 p.m. UTC | #8
Hi,

> Looks like
> 
>>                qualified_name_lookup_error (object_type, tmpl, member,
>>                                             input_location);
> 
> is passing the wrong first argument; the scope argument should be the same as we passed to lookup_qualified_name.

Ok, thanks, I'll work more on this later today. Then, if we fix that we don't error out at all, right? Because this is a reject valid, AFAIK.

Paolo
Jason Merrill Oct. 27, 2011, 1:04 p.m. UTC | #9
On 10/27/2011 08:57 AM, Paolo Carlini wrote:
> Ok, thanks, I'll work more on this later today. Then, if we fix that we don't error out at all, right? Because this is a reject valid, AFAIK.

In that case, lookup_qualified_name shouldn't be returning error_mark_node.

Jason
Paolo Carlini Oct. 27, 2011, 1:32 p.m. UTC | #10
Hi

> On 10/27/2011 08:57 AM, Paolo Carlini wrote:
>> Ok, thanks, I'll work more on this later today. Then, if we fix that we don't error out at all, right? Because this is a reject valid, AFAIK.
> 
> In that case, lookup_qualified_name shouldn't be returning error_mark_node.

Yes, I suspected that. I'll try to look a bit into it but I don't make promises, if you consider the issue urgent, definitely don't wait on me.

Thanks again,
Paolo
Paolo Carlini Oct. 27, 2011, 11:08 p.m. UTC | #11
Hi again,
>> On 10/27/2011 08:57 AM, Paolo Carlini wrote:
>>> Ok, thanks, I'll work more on this later today. Then, if we fix that we don't error out at all, right? Because this is a reject valid, AFAIK.
>> In that case, lookup_qualified_name shouldn't be returning error_mark_node.
A little more information, maybe more to come today: 
lookup_qualified_name calls lookup_member which actually gives up *very* 
early, because its first argument, xbasetype, aka TREE_OPERAND (member, 
0) in tsubst_copy_and_build, has no binfo:

<record_type 0x7ffff577f9d8 impl type_0 type_5 type_6 VOID
     align 8 symtab 0 alias set -1 canonical type 0x7ffff577f9d8 context 
<translation_unit_decl 0x7ffff5646170 D.1>
     full-name "struct impl<V>"
     no-binfo use_template=1 interface-unknown
     chain <type_decl 0x7ffff57802e0 impl>>

thus (type is xbasetype completed):

1192   if (!basetype_path)
1193     basetype_path = TYPE_BINFO (type);
1194
1195   if (!basetype_path)
1196     return NULL_TREE;

NULL_TREE becomes error_mark_node in lookup_qualified_name.

For comparison, in 4_5-branch we have, for xbasetype, a very different 
story:

<record_type 0x7ffff5a15690 impl type_5 type_6 QI
     size <integer_cst 0x7ffff7e6d730 type <integer_type 0x7ffff7e820a8 
bit_size_type> constant 8>
     unit size <integer_cst 0x7ffff7e6d758 type <integer_type 
0x7ffff7e82000 long unsigned int> constant 1>
     align 8 symtab 0 alias set -1 canonical type 0x7ffff5a15690
     fields <type_decl 0x7ffff5a17170 impl
         type <record_type 0x7ffff5a157e0 impl type_5 type_6 QI size 
<integer_cst 0x7ffff7e6d730 8> unit size <integer_cst 0x7ffff7e6d758 1>
             align 8 symtab 0 alias set -1 canonical type 0x7ffff5a15690 
fields <type_decl 0x7ffff5a17170 impl>
             full-name "struct impl<float>"
             X() X(constX&) this=(X&) n_parents=0 use_template=1 
interface-unknown
             chain <type_decl 0x7ffff5a170b8 impl>>
         external nonlocal suppress-debug decl_4 VOID file 50870.C line 
6 col 3
         align 8 context <record_type 0x7ffff5a15690 impl> result 
<record_type 0x7ffff5a15690 impl>
 >
     full-name "struct impl<float>"
     X() X(constX&) this=(X&) n_parents=0 use_template=1 interface-unknown
     pointer_to_this <pointer_type 0x7ffff5a15738> chain <type_decl 
0x7ffff5a170b8 impl>>

Paolo.
Paolo Carlini Oct. 28, 2011, 12:01 a.m. UTC | #12
.. thus now I'm investigating, comparing 4.5 to mainline, where the 
former gets the TYPE_BINFO of the TREE_OPERAND (member, 0). And the 
answer is "simple": at the beginning of tsubst_copy_and_build case 
COMPONENT_REF itself! Where:

     member = TREE_OPERAND (t, 1);
     if (BASELINK_P (member))
       member = tsubst_baselink (member,
                     non_reference (TREE_TYPE (object)),
                     args, complain, in_decl);
     else
       member = tsubst_copy (member, args, complain, in_decl);

the tsubst_copy call changes very little member in mainline. From this:

<scope_ref 0x7ffff563db70 tree_0 tree_1
     arg 0 <record_type 0x7ffff577f540 impl type_0 type_5 type_6 VOID
         align 8 symtab 0 alias set -1 canonical type 0x7ffff577f540 
context <translation_unit_decl 0x7ffff5646170 D.1>
         full-name "struct impl<V>"
         no-binfo use_template=1 interface-unknown
         chain <type_decl 0x7ffff5780170 impl>>
     arg 1 <template_id_expr 0x7ffff563dae0
         arg 0 <identifier_node 0x7ffff577e790 create
             bindings <(nil)>
             local bindings <(nil)>>
         arg 1 <tree_vec 0x7ffff5769ed8 elt 0 <template_type_parm 
0x7ffff577f3f0 U>>>>

to this:

<scope_ref 0x7ffff563dd20 tree_0 tree_1
     arg 0 <record_type 0x7ffff577f9d8 impl type_0 type_5 type_6 VOID
         align 8 symtab 0 alias set -1 canonical type 0x7ffff577f9d8 
context <translation_unit_decl 0x7ffff5646170 D.1>
         full-name "struct impl<V>"
         no-binfo use_template=1 interface-unknown
         chain <type_decl 0x7ffff57802e0 impl>>
     arg 1 <template_id_expr 0x7ffff563dcf0
         type <lang_type 0x7ffff5765888 unknown type type <lang_type 
0x7ffff5765888 unknown type>
             VOID
             align 1 symtab 0 alias set -1 canonical type 0x7ffff5765888
             pointer_to_this <lang_type 0x7ffff5765888 unknown type> 
reference_to_this <lang_type 0x7ffff5765888 unknown type>>

         arg 0 <identifier_node 0x7ffff577e790 create
             bindings <(nil)>
             local bindings <(nil)>>
         arg 1 <tree_vec 0x7ffff5783140 elt 0 <template_type_parm 
0x7ffff577f7e0 U>>>>

note: no changes for arg0, no-binfo.

Instead, in the 4.5 case, from:

<scope_ref 0x7ffff7f8d188 tree_0
     arg 0 <record_type 0x7ffff5a15348 impl type_0 type_5 type_6 VOID
         align 8 symtab 0 alias set -1 canonical type 0x7ffff5a15348
         full-name "struct impl<V>"
         no-binfo use_template=1 interface-unknown
         chain <type_decl 0x7ffff5a01c38 impl>>
     arg 1 <template_id_expr 0x7ffff7f8d0e0
         arg 0 <identifier_node 0x7ffff5a11840 create
         bindings <(nil)>
         local bindings <(nil)>>
         arg 1 <tree_vec 0x7ffff5a164d8
             elt 0 <template_type_parm 0x7ffff5a151f8 U>>>>

To:

<scope_ref 0x7ffff7f8d268 tree_0
     arg 0 <record_type 0x7ffff5a15690 impl type_5 type_6 QI
         size <integer_cst 0x7ffff7e6d730 constant 8>
         unit size <integer_cst 0x7ffff7e6d758 constant 1>
         align 8 symtab 0 alias set -1 canonical type 0x7ffff5a15690
         fields <type_decl 0x7ffff5a17170 impl type <record_type 
0x7ffff5a157e0 impl>
             external nonlocal suppress-debug decl_4 VOID file 50870.C 
line 6 col 3
             align 8 context <record_type 0x7ffff5a15690 impl> result 
<record_type 0x7ffff5a15690 impl>
 >
         full-name "struct impl<float>"
         X() X(constX&) this=(X&) n_parents=0 use_template=1 
interface-unknown
         pointer_to_this <pointer_type 0x7ffff5a15738> chain <type_decl 
0x7ffff5a170b8 impl>>
     arg 1 <template_id_expr 0x7ffff7f8d230
         type <lang_type 0x7ffff59f8bd0 unknown type type <lang_type 
0x7ffff59f8bd0 unknown type>
             VOID
             align 1 symtab 0 alias set -1 canonical type 0x7ffff59f8bd0
             pointer_to_this <lang_type 0x7ffff59f8bd0 unknown type> 
reference_to_this <lang_type 0x7ffff59f8bd0 unknown type>>

         arg 0 <identifier_node 0x7ffff5a11840 create
         bindings <(nil)>
         local bindings <(nil)>>
         arg 1 <tree_vec 0x7ffff5a16b18
             elt 0 <integer_type 0x7ffff7e82498 int>>>>

arg0 gets its fields. Now, a big difference between the two - 4.5 vs 
mainline - tsubst_copy calls, is the args argument.

In 4.5, a very simple and understandable:

<tree_vec 0x7ffff59f67c0
     elt 0 <pointer_type 0x7ffff5a15738>
     elt 1 <integer_type 0x7ffff7e82498 int>
     elt 2 <real_type 0x7ffff7e96150 float>>

in mainline:

<tree_vec 0x7ffff5758fc0
     elt 0 <template_type_parm 0x7ffff577f738 T VOID
         align 8 symtab 0 alias set -1 canonical type 0x7ffff577f738
        index 0 level 1 orig_level 1
         chain <type_decl 0x7ffff576df18 T>>
     elt 1 <template_type_parm 0x7ffff577f7e0 U VOID
         align 8 symtab 0 alias set -1 canonical type 0x7ffff577f7e0
        index 1 level 1 orig_level 1
         chain <type_decl 0x7ffff5780000 U>>
     elt 2 <template_type_parm 0x7ffff577f888 V type_0 type_6 VOID
         align 8 symtab 0 alias set -1 canonical type 0x7ffff577f888
        index 2 level 1 orig_level 1
         chain <type_decl 0x7ffff57800b8 V>>
     elt 3 <template_type_parm 0x7ffff577f930 VOID
         align 8 symtab 0 alias set -1 canonical type 0x7ffff577f930
        index 3 level 1 orig_level 1
         chain <type_decl 0x7ffff5780228 D.1853>>>

args comes directly from the tsubst_copy_and_build arguments, looks like 
we reach case COMPONENT_REF with the template arguments still 
unsubstituted, something is simply not done earlier in mainline.

I guess I had better stopping here in terms of details on the mailing 
list today. If you have some further hints...

Thanks!
Paolo.
Paolo Carlini Oct. 28, 2011, 12:22 a.m. UTC | #13
.. maybe one final piece of information for today.

I'm trying to figure out where the very different args argument is 
coming from.

Both in 4.5 and in mainline we have the same final chain of 
tusbst_copy_build, preceded by tsubst_copy_and_build, tusbst_expr, 
tsubt, tsubst_template_arg, the args argument remains the same all the way.

Earlier than that things are different: in mainline the same args, as 
arglist, comes from fixup_template_parm, and earlier we have 
fixup_template_parms which creates the arglist itself, even earlier the 
parser.

In 4.5 before tsubst_template_arg we have coerce_template_parms, which 
changes its args argument to the final value, and before that 
lookup_template_class, finish_template_type, the parser.

Paolo.
Jason Merrill Oct. 28, 2011, 4:07 p.m. UTC | #14
On 10/27/2011 08:22 PM, Paolo Carlini wrote:
> I'm trying to figure out where the very different args argument is
> coming from.

> Earlier than that things are different: in mainline the same args, as
> arglist, comes from fixup_template_parm, and earlier we have
> fixup_template_parms which creates the arglist itself

Right, this is new.  I guess the COMPONENT_REF code needs to be fixed to 
handle partial instantiation.

Jason
Paolo Carlini Oct. 28, 2011, 4:22 p.m. UTC | #15
On 10/28/2011 06:07 PM, Jason Merrill wrote:
> On 10/27/2011 08:22 PM, Paolo Carlini wrote:
>> I'm trying to figure out where the very different args argument is
>> coming from.
>
>> Earlier than that things are different: in mainline the same args, as
>> arglist, comes from fixup_template_parm, and earlier we have
>> fixup_template_parms which creates the arglist itself
>
> Right, this is new.  I guess the COMPONENT_REF code needs to be fixed 
> to handle partial instantiation.
I see. Something I didn't tell you yesterday, is that, in 4_5-branch, 
tsubst_template_arg is called like this, by coerce_template_parms:

       /* There must be a default arg in this case.  */
       arg = tsubst_template_arg (TREE_PURPOSE (parm), new_args,
                      complain, in_decl);

which, what can I say, looks right ;)

By the way, your hint that probably we are also passing a wrong first 
argument to qualified_name_lookup_error may be useful for the other 
issue, the ice-on-invalid, which I was trying to fix in the parser ;) 
Let me test something...

Paolo.
diff mbox

Patch

Index: pt.c
===================================================================
--- pt.c	(revision 180532)
+++ pt.c	(working copy)
@@ -13706,12 +13706,13 @@  tsubst_copy_and_build (tree t,
 	/* Remember that there was a reference to this entity.  */
 	if (DECL_P (object))
 	  mark_used (object);
-	object_type = TREE_TYPE (object);
+	object_type = (TREE_CODE (object) == ARROW_EXPR
+		       ? TREE_OPERAND (object, 0) : TREE_TYPE (object));
 
 	member = TREE_OPERAND (t, 1);
 	if (BASELINK_P (member))
 	  member = tsubst_baselink (member,
-				    non_reference (TREE_TYPE (object)),
+				    non_reference (object_type),
 				    args, complain, in_decl);
 	else
 	  member = tsubst_copy (member, args, complain, in_decl);