On 3/19/20 7:55 PM, Martin Sebor wrote:
On 3/18/20 9:07 PM, Jason Merrill wrote:
On 3/12/20 6:38 PM, Martin Sebor wrote:
...
+     declarations of a class from its uses doesn't work for type aliases
+     (as in using T = class C;).  */

Good point.  Perhaps we could pass flags to cp_parser_declares_only_class_p and have it return false if CP_PARSER_FLAGS_TYPENAME_OPTIONAL, since that is set for an alias but not for a normal type-specifier.

I wondered if there was a way to identify that we're dealing with
an alias.  CP_PARSER_FLAGS_TYPENAME_OPTIONAL is set not just for
those but also for template declarations (in
cp_parser_single_declaration) but I was able to make it work by
tweaking cp_parser_type_specifier.  It doesn't feel very clean
(it seems like either the bit or all of cp_parser_flags could be
a member of the parser class or some subobject of it) but it does
the job.  Thanks for pointing me in the right direction!

Hmm, true, relying on that flag is probably too fragile. And now that I look closer, I see that we already have is_declaration in cp_parser_elaborated_type_specifier, we just need to check that before cp_parser_declares_only_class_p like we do earlier in the function.

+  if (!decl_p && !def_p && TREE_CODE (decl) == TEMPLATE_DECL)
     {
+      /* When TYPE is the use of an implicit specialization of a previously +     declared template set TYPE_DECL to the type of the primary template +     for the specialization and look it up in CLASS2LOC below.  For uses
+     of explicit or partial specializations TYPE_DECL already points to
+     the declaration of the specialization.  */
+      type_decl = specialization_of (type_decl);

Here shouldn't is_use be true?

If it were set to true here we would find the partial specialization
corresponding to its specialization in the use when what we want is
the latter.  As a result, for the following:

   template <class>   struct S;
   template <class T> struct S<T*>;

   extern class  S<int*> s1;   // expect -Wmismatched-tags
   extern struct S<int*> s2;

we'd end up with a warning for s2 pointing to the instantiation of
s1 as the "guiding declaration:"

z.C:5:15: warning: ‘template<class T> struct S<T*>’ declared with a mismatched class-key ‘struct’ [-Wmismatched-tags]
     5 | extern struct S<int*> s2;
       |               ^~~~~~~
z.C:5:15: note: remove the class-key or replace it with ‘class’
z.C:4:15: note: ‘template<class T> struct S<T*>’ first declared as ‘class’ here
     4 | extern class  S<int*> s1;   // expect -Wmismatched-tags
       |               ^~~~~~~

I found this puzzling and wanted to see why that would be, but I can't reproduce it; compiling with -Wmismatched-tags produces only

wa2.C:4:17: warning: ‘S<T*>’ declared with a mismatched class-key ‘class’ [-Wmismatched-tags]
    4 |   extern class  S<int*> s1;   // expect -Wmismatched-tags
      |                 ^~~~~~~
wa2.C:4:17: note: remove the class-key or replace it with ‘struct’
wa2.C:2:29: note: ‘S<T*>’ first declared as ‘struct’ here
    2 |   template <class T> struct S<T*>;

So the only difference is whether we talk about S<T*> or S<int*>. I agree that the latter is probably better, which is what you get without my suggested change. But since specialization_of does nothing if is_use is false, how about removing the call here and removing the is_use parameter?

+  if (tree spec = most_specialized_partial_spec (ret, tf_none))
+    if (spec != error_mark_node)
+      ret = TREE_VALUE (spec);

I think you want to take the TREE_TYPE of the template here, so you don't need to do it here:

+      tree pt = specialization_of (TYPE_MAIN_DECL (type), true);
+      if (TREE_CODE (pt) == TEMPLATE_DECL)
+          pt = TREE_TYPE (pt);
+      pt = TYPE_MAIN_DECL (pt);

And also, since it takes a TYPE_DECL, it would be better to return another TYPE_DECL rather than a _TYPE, especially since the only caller immediately extracts a TYPE_DECL.

Jason

Reply via email to