> 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” (is “sp” equal to “S::__PTRMEMFUNC”?), then it was casted to “ptrmemfunc *”. So, should this type conversion from “S::__PTRMEMFUNC” to “ptrmemfunc *” be exposed to the user in the message? 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? > > Jason