C++ PATCH to Implement P0846R0, ADL and function templates [v2]
Jason Merrill
jason@redhat.com
Thu Nov 1 16:16:00 GMT 2018
On 10/31/18 6:45 PM, Marek Polacek wrote:
> On Mon, Oct 29, 2018 at 05:59:13PM -0400, Jason Merrill wrote:
>> On 10/28/18 3:56 PM, Marek Polacek wrote:
>>> This patch implements P0846R0: ADL and Function Templates that are not Visible
>>> <http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2017/p0846r0.html>
>>> whereby a name for which a normal lookup produces either no result or finds one
>>> or more functions and that is followed by a "<" would be treated as if a function
>>> template name had been found and would cause ADL to be performed. Thus e.g.
>>>
>>> namespace N {
>>> struct S { };
>>> template<int X> void f(S);
>>> }
>>>
>>> void
>>> bar (N::S s)
>>> {
>>> f<3>(s);
>>> }
>>>
>>> will now compile; ADL will find N::f. The gist of the approach I took is in
>>> cp_parser_template_name and setting TEMPLATE_ID_TRY_ADL_P.
>>
>> Why do you need that flag? Can't you tell from the first operand of the
>> TEMPLATE_ID_EXPR whether it's suitable?
>
> I needed to distinguish between the two kinds of identifiers
> cp_parser_template_name can return. But I found out I can (ab)use
> IDENTIFIER_BINDING for that. If it's empty then name lookup didn't find
> anything (push_binding wasn't called for such an id), so we should try ADL.
> Otherwise it's a dependent name and we need to wait for instantiation.
>
>>> There's something I'm not clear on; the proposal talks about an
>>> unqualified-id followed by a <, which is also the case for
>>>
>>> a.foo < 1;
>>>
>>> which is "postfix-expression . unqualified-id <", but treating "foo" as a
>>> template name would break valid programs. I don't think this proposal should
>>> be in effect for class member accesses, so I've disabled it by using scoped_p
>>> below. See fn-template8.C for a complete testcase for this scenario.
>>
>> Agreed; ADL doesn't apply to class member access, so it shouldn't apply
>> here. Sent mail to the core reflector.
>
> Great, thanks for that.
>
>>> @@ -7165,7 +7165,9 @@ cp_parser_postfix_expression (cp_parser *parser, bool address_p, bool cast_p,
>>> if (idk == CP_ID_KIND_UNQUALIFIED
>>> || idk == CP_ID_KIND_TEMPLATE_ID)
>>> {
>>> - if (identifier_p (postfix_expression))
>>> + if (identifier_p (postfix_expression)
>>> + || (TREE_CODE (postfix_expression) == TEMPLATE_ID_EXPR
>>> + && TEMPLATE_ID_TRY_ADL_P (postfix_expression)))
>>
>> Here I think you can check whether the first operand is an identifier.
>
> Changed, along with checking for IDENTIFIER_BINDING. E.g. this is a test that
> would fail if we tried ADL for a template-id with any identifier:
>
> template <int> struct X {
> X() { fn<>(0); }
> template <int> void fn();
> };
>
> here we need to perform two-stage lookup.
I don't see why; when we look up fn we find the member template, and we
should remember that. I think this code:
> /* If DECL is dependent, and refers to a function, then just return
> its name; we will look it up again during template instantiation. */
> if (DECL_FUNCTION_TEMPLATE_P (decl) || !DECL_P (decl))
> {
> tree scope = ovl_scope (decl);
> if (TYPE_P (scope) && dependent_type_p (scope))
> return identifier;
> }
should go so that returning an identifier can consistently mean nothing
found.
Jason
More information about the Gcc-patches
mailing list