> On Feb 11, 2022, at 3:54 PM, Jason Merrill <ja...@redhat.com> wrote:
> 
> On 2/11/22 15:29, Qing Zhao wrote:
>>> On Feb 11, 2022, at 1:39 PM, Jason Merrill <ja...@redhat.com> wrote:
>>> 
>>> On 2/11/22 13:11, Qing Zhao wrote:
>>>> Hi, Jason,
>>>>> On Feb 11, 2022, at 11:27 AM, Jason Merrill <ja...@redhat.com> wrote:
>>>>>>>> 
>>>>>>>> Sure, we might as well make this code more robust.  But we can do 
>>>>>>>> better than <unnamed type> if we check TYPE_PTRMEMFUNC_P.
>>>>>>> Okay, so what should we print to the user if it's “TYPE_PTRMEMFUNC_P”? 
>>>>>>> Print nothing or some special string?
>>>>>>>> 
>>>>>>>>> 2. The second level issue is what you suggested in the above, shall 
>>>>>>>>> we print the “compiler generated internal type”  to the user? And I 
>>>>>>>>> agree with you that it might not be a good idea to print such 
>>>>>>>>> compiler internal names to the user.  Are we do this right now in 
>>>>>>>>> general? (i.e, check whether the current TYPE is a source level TYPE 
>>>>>>>>> or a compiler internal TYPE, and then only print out the name of TYPE 
>>>>>>>>> for the source level TYPE?) and is there a bit in the TYPE to 
>>>>>>>>> distinguish whether a TYPE is user -level type or a compiler 
>>>>>>>>> generated internal type?
>>>>>>>> 
>>>>>>>>>> I think the real problem comes sooner, when 
>>>>>>>>>> c_fold_indirect_ref_for_warn turns a MEM_REF with RECORD_TYPE into a 
>>>>>>>>>> COMPONENT_REF with POINTER_TYPE.
>>>>>>>> 
>>>>>>>>> What’s the major issue for this transformation? (I will study this in 
>>>>>>>>> more details).
>>>>>>>> 
>>>>>>>> We told c_fold_indirect_ref that we want a RECORD_TYPE (the PMF as a 
>>>>>>>> whole) and it gave us back a POINTER_TYPE instead (the __pmf member). 
>>>>>>>> Folding shouldn't change the type of an expression like that.
>>>>>>> 
>>>>>>> Yes, this is not correct transformation, will study in more detail and 
>>>>>>> try to fix it.
>>>>>> After a deeper study of commit  r11-6729-gadb520606ce3e1e1 (which 
>>>>>> triggered the ICE and introduced the new routine 
>>>>>> “c_fold_indirect_ref_for_warn”), from my understanding,  the above 
>>>>>> transformation from a RECORD_TYPE (the PMF as a whole) to POINTER_TYPE 
>>>>>> (the __pmf member) is what the function intended to do as following:
>>>>>> 1823 static tree
>>>>>> 1824 c_fold_indirect_ref_for_warn (location_t loc, tree type, tree op,
>>>>>> 1825                               offset_int &off)
>>>>>> 1826 {
>>>>>> …
>>>>>> 1870 */* ((foo *)&struct_with_foo_field)[x] => COMPONENT_REF */*
>>>>>> 1871   else if (TREE_CODE (optype) == RECORD_TYPE)
>>>>>> 1872     {
>>>>>> 1873       for (tree field = TYPE_FIELDS (optype);
>>>>>> 1874            field; field = DECL_CHAIN (field))
>>>>>> 1875         if (TREE_CODE (field) == FIELD_DECL
>>>>>> …
>>>>>> 1886 if(upos <= off && off < upos + el_sz)
>>>>>> 1887               {
>>>>>> 1888                 tree cop = build3_loc (loc, COMPONENT_REF, 
>>>>>> TREE_TYPE (field),
>>>>>> 1889                                       op, field, NULL_TREE);
>>>>>> 1890                 off = off - upos;
>>>>>> The above code was used to transform a MEM_REF to a RECORD_TYPE to a 
>>>>>> COMPONENT_REF to the corresponding FIELD.
>>>>> 
>>>>> Yes, that's what the above code would correctly do if TYPE were the 
>>>>> pointer-to-method type.  It's wrong for this case because TYPE is 
>>>>> unrelated to TREE_TYPE (field).
>>>>> 
>>>>> I think the problem is just this line:
>>>>> 
>>>>>>                if (tree ret = c_fold_indirect_ref_for_warn (loc, type, 
>>>>>> cop,
>>>>>>                                                             off))
>>>>>>                  return ret;
>>>>>>                return cop;
>>>>>                  ^^^^^^^^^^
>>>>> 
>>>>> The recursive call does the proper type checking, but then the "return 
>>>>> cop" line returns the COMPONENT_REF even though the type check failed. 
>>>>> The parallel code in cxx_fold_indirect_ref_1 doesn't have this line,
>>>> Just compared the routine “cxx_fold_indirect_ref_1” and 
>>>> “c_fold_indirect_ref_for_warn”, looks like there are more places that have 
>>>> such difference, for example,
>>>> In “cxx_fold_indirect_ref_1”:
>>>>   /* ((foo *)&fooarray)[x] => fooarray[x] */
>>>>   else if (TREE_CODE (optype) == ARRAY_TYPE
>>>>            && tree_fits_uhwi_p (TYPE_SIZE_UNIT (TREE_TYPE (optype)))
>>>>            && !integer_zerop (TYPE_SIZE_UNIT (TREE_TYPE (optype))))
>>>> …
>>>>       if (tree_fits_uhwi_p (min_val))
>>>>         {
>>>>           tree index = size_int (idx + tree_to_uhwi (min_val));
>>>>           op = build4_loc (loc, ARRAY_REF, TREE_TYPE (optype), op, index,
>>>>                            NULL_TREE, NULL_TREE);
>>>>      return cxx_fold_indirect_ref_1 (ctx, loc, type, op, rem,
>>>>                                           empty_base);
>>>>    }
>>>> However, in “c_fold_indirect_ref_for_warn”, the corresponding part is:
>>>>   /* ((foo *)&fooarray)[x] => fooarray[x] */
>>>>   if (TREE_CODE (optype) == ARRAY_TYPE
>>>>       && TYPE_SIZE_UNIT (TREE_TYPE (optype))
>>>>       && TREE_CODE (TYPE_SIZE_UNIT (TREE_TYPE (optype))) == INTEGER_CST
>>>>       && !integer_zerop (TYPE_SIZE_UNIT (TREE_TYPE (optype))))
>>>> …
>>>>       if (TREE_CODE (min_val) == INTEGER_CST)
>>>>         {
>>>>           tree index
>>>>             = wide_int_to_tree (sizetype, idx + wi::to_offset (min_val));
>>>>           op = build4_loc (loc, ARRAY_REF, TREE_TYPE (optype), op, index,
>>>>                            NULL_TREE, NULL_TREE);
>>>>           off = rem;
>>>>           if (tree ret = c_fold_indirect_ref_for_warn (loc, type, op, off))
>>>>             return ret;
>>>>           return op;
>>>>         }
>>>> The exactly same difference as for “RECORD_TYPE”. So, I suspect that it’s 
>>>> a typo for “RECORD_TYPE” in “c_fold_indirect_ref_for_warn”.
>>>>> and removing it fixes the testcase, so I see
>>>>> 
>>>>> warning: ‘*(ptrmemfunc*)&x.ptrmemfunc::ptr’ is used uninitialized
>>>> The question is:
>>>> For the following IR:
>>>>   struct sp x;
>>>>   void (*<T389>) (void) _1;
>>>>  ...
>>>>   <bb 2> [local count: 1073741824]:
>>>>   _1 = MEM[(struct ptrmemfunc_U *)&x].ptr;
>>>>   _7 = _1 != 8B;
>>>> Which message is better:
>>>> 1. warning: ‘*(ptrmemfunc*)&x.ptrmemfunc::ptr’ is used uninitialized
>>>> Or
>>>> 2. warning: ‘*(ptrmemfunc*)((char*)&x + offsetof(void 
>>>> (S::*)(),__PTRMEMFUNC)).ptrmemfunc::ptr’ is used uninitialized
>>>> From the source code:
>>>> ====
>>>> struct S
>>>> {
>>>>   int j;
>>>> };
>>>> struct T : public S
>>>> {
>>>>   virtual void h () {}
>>>> };
>>>> struct ptrmemfunc
>>>> {
>>>>   void (*ptr) ();
>>>> };
>>>> typedef void (S::*sp)();
>>>> int main ()
>>>> {
>>>>   T t;
>>>>   sp x;
>>>>   ptrmemfunc *xp = (ptrmemfunc *) &x;
>>>>   if (xp->ptr != ((void (*)())(sizeof(void *))))
>>>>     return 1;
>>>> }
>>>> ====
>>>> The reference “xp->ptr” went through from “x” to “xp”, and there is a 
>>>> clear type casting from S::__PTRMEMFUNC to ptrmemfunc::ptr.
>>>> Shall we emit such type casting to the user?
>>> 
>>> But there is no such cast in the source; the cast is (ptrmemfunc*)&x, which 
>>> appears in the fixed message.
>> still a little confused here:  the original type for “x” is “sp”
> 
> Yes.
> 
>> (is “sp” equal to “S::__PTRMEMFUNC”?)
> 
> No.
> 
>> then it was casted to “ptrmemfunc *”.
> 
> Yes.
> 
>> So, should this type conversion from “S::__PTRMEMFUNC” to “ptrmemfunc *” be 
>> exposed to the user in the message?
> 
> The conversion from sp* to ptrmemfunc* is exposed as (ptrmemfunc*), which is 
> normal C++ syntax; a cast only names the target type, not the source type.
Okay, I see now.

thanks.

Qing
> 
>>> Though *(ptrmemfunc*)&x.ptrmemfunc::ptr is wrong syntax, it should be 
>>> ((ptrmemfunc*)&x)->ptr
>>> 
>>> Jakub, this is your code from r11-6729; from the comment on that commit it 
>>> sounds like you were deliberately ignoring type incompatibility here, and 
>>> my suggested fix changes two lines in uninit-40.c.  What do you think 
>>> should happen for this testcase?

Reply via email to