diff mbox

[C++1y,3/4] Ensure implicit template parameters have distinct canonical types.

Message ID 3c94265be0a93211393264ac16908baa@imap.force9.net
State New
Headers show

Commit Message

Adam Butcher Sept. 23, 2013, 7:15 a.m. UTC
On 22.09.2013 18:57, Adam Butcher wrote:
> The following solves the canonical type issue in the general case
> (pointers and refs) and makes it equivalent to the explicit template
> case -- in terms of canonical type at least.
>
>       for (tree t = TREE_TYPE (TREE_VALUE (p)); t; t = TREE_CHAIN 
> (t))
>         TYPE_CANONICAL (t) = t;
>
The above is insufficient; the traversal doesn't handle function 
pointers.  Currently, to get my local testcases passing, I have the 
following workaround that abuses find_type_usage.  I intend for this to 
be replaced with a better solution but it will at least mean that people 
can start experimenting with this feature now (as they appear to be 
doing http://gcc.gnu.org/bugzilla/show_bug.cgi?id=58500).  This supports 
that testcase also.

Cheers,
Adam



     Workaround implicit function template parameter canonical type 
issue.

         * parser.c (add_implicit_template_parms): Workaround to fix up 
canonical
         type references left over from before substation of 'auto'.  
Better
         solution needed but this makes test cases functional.

+      find_type_usage (TREE_VALUE (p), (bool (*)(const_tree))
+                      helper::fixup_canonical_types);
+
        ++synth_count;

        tree synth_id = make_generic_type_name ();

Comments

Adam Butcher Sept. 24, 2013, 7:05 a.m. UTC | #1
On 23.09.2013 08:15, Adam Butcher wrote:
> On 22.09.2013 18:57, Adam Butcher wrote:
>> The following solves the canonical type issue in the general case
>> (pointers and refs) and makes it equivalent to the explicit template
>> case -- in terms of canonical type at least.
>>
>>       for (tree t = TREE_TYPE (TREE_VALUE (p)); t; t = TREE_CHAIN 
>> (t))
>>         TYPE_CANONICAL (t) = t;
>>
> The above is insufficient; the traversal doesn't handle function
> pointers.  Currently, to get my local testcases passing, I have the
> following workaround that abuses find_type_usage.  I intend for this
> to be replaced with a better solution but it will at least mean that
> people can start experimenting with this feature now (as they appear
> to be doing http://gcc.gnu.org/bugzilla/show_bug.cgi?id=58500).  This
> supports that testcase also.
>

Shall I push the patch below to trunk as an intermediate workaround 
whilst I get to refactoring to support on-the-fly template parm 
synthesis?

On the subject of on-the-fly synthesis: I haven't started yet but I'm 
thinking to trigger in 'cp_parser_simple_type_specifier' when 
'current_binding_level->kind == sk_function_parms'.  I can foresee a 
potential issue with packs in that, upon reading the 'auto' (potentially 
nested in some other type), a plain template parm will be synthesized; 
but it may need to be a pack parm type if '...' is found later.

My initial testcase is:

   template <typename T> struct X { T m(int, float); };

   auto f(X<auto>, auto (X<auto>::*) (auto...))
   {
      char* s = "warn";
   }

   int main()
   {
      X<char> x;
      f(x, &X<void>::m);
   }

where f should be translated as similar to:

   template <typename A1, typename A2, typename A3,
             typename... A4>
   auto f(X<A1>, A2 (X<A3>::*) (A4...))
   {
      char* s = "warn";
   }


In the case of something like:

   auto f(X<auto>&&...)

the translation would need to be:

   template <typename... A>
   auto f(X<A>&&...)


I'm thinking that getting that to happen correctly might be tricky (but 
haven't tried yet).  The 'auto' would trigger plain template parameter 
synthesis.  Perhaps a 'could_be_parameter_pack_p' on the 
template_type_parm?  Though I don't know how the following could be 
handled as implicit

   template <typename T, typename A...>
   auto f(X<T, A>&&...)

It would not be possible to infer which of the template parms to make 
the pack.

   auto f(X<auto, auto>&&...)

Probably multiple generic-type pack expansions should be forbidden.

I'll see what happens when I get there but any guidance/thoughts you 
have on the subject will be valuable.

Cheers,
Adam



>     Workaround implicit function template parameter canonical type 
> issue.
>
>         * parser.c (add_implicit_template_parms): Workaround to fix
> up canonical
>         type references left over from before substation of 'auto'.  
> Better
>         solution needed but this makes test cases functional.
>
> diff --git a/gcc/cp/parser.c b/gcc/cp/parser.c
> index f3133f3..4171476 100644
> --- a/gcc/cp/parser.c
> +++ b/gcc/cp/parser.c
> @@ -28987,6 +28987,25 @@ add_implicit_template_parms (cp_parser
> *parser, size_t expect_count,
>        if (!generic_type_ptr)
>         continue;
>
> +      /* Make the canonical type of each part of the parameter 
> distinct.
> +        FIXME: A better solution is needed for this.  Not least the 
> abuse of
> +        find_type_usage.  Need foreach_type or similar for proper 
> mutable
> +        access.  If something like this does turn out to be
> necessary then the
> +        find_type_usage loop above can be replaced by a foreach_type
> that fixes
> +        up the canonical types on the way to finding the 'auto'.  */
> +
> +      struct helper { static bool fixup_canonical_types (tree t) {
> +         t = TREE_TYPE (t);
> +         if (!t)
> +           return false;
> +         if (is_auto_or_concept (t))
> +           return true;
> +         TYPE_CANONICAL (t) = t;
> +         return false;
> +      }};
> +      find_type_usage (TREE_VALUE (p), (bool (*)(const_tree))
> +                      helper::fixup_canonical_types);
> +
>        ++synth_count;
>
>        tree synth_id = make_generic_type_name ();
Jason Merrill Sept. 25, 2013, 4:01 p.m. UTC | #2
On 09/24/2013 02:05 AM, Adam Butcher wrote:
> Shall I push the patch below to trunk as an intermediate workaround
> whilst I get to refactoring to support on-the-fly template parm synthesis?

I think let's wait for a better fix.

> On the subject of on-the-fly synthesis: I haven't started yet but I'm
> thinking to trigger in 'cp_parser_simple_type_specifier' when
> 'current_binding_level->kind == sk_function_parms'.  I can foresee a
> potential issue with packs in that, upon reading the 'auto' (potentially
> nested in some other type), a plain template parm will be synthesized;
> but it may need to be a pack parm type if '...' is found later.

Hmm, good point.

I think there are two options:

1) Build up the type as normal and use tsubst to replace the non-pack 
template parameter with a pack if needed.

2) If we see 'auto', scan ahead (possibly via tentative parsing) to see 
if there's a ...

Jason
diff mbox

Patch

diff --git a/gcc/cp/parser.c b/gcc/cp/parser.c
index f3133f3..4171476 100644
--- a/gcc/cp/parser.c
+++ b/gcc/cp/parser.c
@@ -28987,6 +28987,25 @@  add_implicit_template_parms (cp_parser 
*parser, size_t expect_count,
        if (!generic_type_ptr)
         continue;

+      /* Make the canonical type of each part of the parameter 
distinct.
+        FIXME: A better solution is needed for this.  Not least the 
abuse of
+        find_type_usage.  Need foreach_type or similar for proper 
mutable
+        access.  If something like this does turn out to be necessary 
then the
+        find_type_usage loop above can be replaced by a foreach_type 
that fixes
+        up the canonical types on the way to finding the 'auto'.  */
+
+      struct helper { static bool fixup_canonical_types (tree t) {
+         t = TREE_TYPE (t);
+         if (!t)
+           return false;
+         if (is_auto_or_concept (t))
+           return true;
+         TYPE_CANONICAL (t) = t;
+         return false;
+      }};