[PATCH] v6: C++: more location wrapper nodes (PR c++/43064, PR c++/43486)
Jason Merrill
jason@redhat.com
Tue Dec 18 20:40:00 GMT 2018
On 12/18/18 4:22 PM, David Malcolm wrote:
> On Mon, 2018-12-17 at 18:30 -0500, David Malcolm wrote:
>> On Mon, 2018-12-17 at 14:33 -0500, Jason Merrill wrote:
>>> On 12/14/18 7:17 PM, David Malcolm wrote:
>>>> + /* Since default args are effectively part of the function
>>>> type,
>>>> + strip location wrappers here, since otherwise the
>>>> location of
>>>> + one function's default arguments is arbitrarily chosen
>>>> for
>>>> + all functions with similar signature (due to
>>>> canonicalization
>>>> + of function types). */
>>>
>>> Hmm, looking at this again, why would this happen? I see that
>>> type_list_equal uses == to compare default arguments, so two
>>> function
>>> types with the same default argument but different location
>>> wrappers
>>> shouldn't be combined.
>>>
>>> Jason
>>
>> Thanks.
>>
>> I did some digging into this. I added this strip to fix
>> g++.dg/template/defarg6.C
>> but it looks like I was overzealous (the comment is correct, but it's
>> papering over a problem).
>>
>> It turns out that type_list_equal is doing more than just pointer
>> equality; it's hitting the simple_cst_equal part of the && at line
>> 7071:
>>
>> 7063 bool
>> 7064 type_list_equal (const_tree l1, const_tree l2)
>> 7065 {
>> 7066 const_tree t1, t2;
>> 7067
>> 7068 for (t1 = l1, t2 = l2; t1 && t2; t1 = TREE_CHAIN (t1),
>> t2 = TREE_CHAIN (t2))
>> 7069 if (TREE_VALUE (t1) != TREE_VALUE (t2)
>> 7070 || (TREE_PURPOSE (t1) != TREE_PURPOSE (t2)
>> 7071 && ! (1 == simple_cst_equal (TREE_PURPOSE
>> (t1), TREE_PURPOSE (t2))
>> 7072 && (TREE_TYPE (TREE_PURPOSE (t1))
>> 7073 == TREE_TYPE (TREE_PURPOSE
>> (t2))))))
>> 7074 return false;
>> 7075
>> 7076 return t1 == t2;
>> 7077 }
>>
>> What's happening is that there are two different functions with
>> identical types apart from the locations of their (equal) default
>> arguments: both of the TREE_PURPOSEs are NON_LVALUE_EXPR wrappers
>> around a CONST_DECL enum value (at different source locations).
>>
>> simple_cst_equal is stripping the location wrappers here:
>>
>> 7311 if (CONVERT_EXPR_CODE_P (code1) || code1 ==
>> NON_LVALUE_EXPR)
>> 7312 {
>> 7313 if (CONVERT_EXPR_CODE_P (code2)
>> 7314 || code2 == NON_LVALUE_EXPR)
>> 7315 return simple_cst_equal (TREE_OPERAND (t1, 0),
>> TREE_OPERAND (t2, 0));
>> 7316 else
>> 7317 return simple_cst_equal (TREE_OPERAND (t1, 0),
>> t2);
>> 7318 }
>>
>> and thus finds them to be equal; the iteration in type_list_equal
>> continues, and runs out of parameters with t1 == t2 == NULL, and thus
>> returns true, and thus the two function types hash to the same slot,
>> and the two function types get treated as being the same.
>>
>> It's not clear to me yet what the best solution to this is:
>> - should simple_cst_equal regard different source locations as being
>> different?
>> - should function-type hashing use a custom version of
>> type_list_equal
>> when comparing params, and make different source locations of default
>> args be different?
>> - something else?
>>
>> Dave
>
> I tried both of the above approaches, and both work.
>
> Here's v6 of the patch:
>
> I removed the strip of wrappers in cp_parser_late_parsing_default_args
> from earlier versions of the patch, in favor of fixing simple_cst_equal
> so that it treats location wrappers with unequal source locations as
> being unequal. This ensures that function-types with default arguments
> don't get merged when the default argument constants have different
> spelling locations. [I have an alternative patch which instead
> introduces a different comparator for FUNCTION_TYPE's TYPE_ARG_TYPES
> within type_cache_hasher::equal, almost identical to type_list_equal,
> but adding the requirement that location wrappers around default
> arguments have equal source location for the params to be considered
> equal; both patches pass bootstrap®ression testing]
>
> Doing so leads to the reported location for the bad default argument
> within a template in g++.dg/template/defarg6.C moving to the argument
> location. Previously, the callsite of the instantiation was identified
> due to the use of input_location in convert_like_real here:
>
> 6816 location_t loc = cp_expr_loc_or_loc (expr, input_location);
>
> With a location wrapper, it uses the spelling location of the
> default argument, but doesn't identify the location of the callsite
> that's instantiating the template.
>
> So I moved the note in tsubst_default_argument about which callsite
> led to a diagnostic to after the check_default_argument call, so that
> diagnostics within that receive notes, too.
>
> As before, this was successfully bootstrapped & regrtested on
> x86_64-pc-linux-gnu, in conjunction with the followup patch.
>
> OK for trunk?
Ah, I hadn't seen this before my last email. Let's go with this version.
Jason
More information about the Gcc-patches
mailing list