Hi,

this issue points out that we aren't handling correctly alias template declarations of enums. The core problem in lookup_template_class_1 is easy to spot: we check for (and handle) TREE_CODE (template_type) == ENUMERAL_TYPE *before* DECL_ALIAS_TEMPLATE_P (gen_tmpl). Besides this more or less straightforward change, in the patchlet I also have to avoid calling tsubst_enum (otherwise we immediately have duplicate declarations for the enumerators of unscoped enums, and all sorts of troubles: I tried to cover in the extended testcase some of the weird things I was seeing earlier today ;) Tested x86_64-linux.

Thanks!
Paolo.

//////////////////////////
/cp
2013-11-12  Paolo Carlini  <paolo.carl...@oracle.com>

        PR c++/57734
        * pt.c (lookup_template_class_1): Handle alias template declarations
        of enumeration types.

/testsuite
2013-11-12  Paolo Carlini  <paolo.carl...@oracle.com>

        PR c++/57734
        * g++.dg/cpp0x/alias-decl-enum-1.C: New.
Index: cp/pt.c
===================================================================
--- cp/pt.c     (revision 204674)
+++ cp/pt.c     (working copy)
@@ -7458,31 +7458,8 @@ lookup_template_class_1 (tree d1, tree arglist, tr
        context = global_namespace;
 
       /* Create the type.  */
-      if (TREE_CODE (template_type) == ENUMERAL_TYPE)
+      if (DECL_ALIAS_TEMPLATE_P (gen_tmpl))
        {
-         if (!is_dependent_type)
-           {
-             set_current_access_from_decl (TYPE_NAME (template_type));
-             t = start_enum (TYPE_IDENTIFIER (template_type), NULL_TREE,
-                             tsubst (ENUM_UNDERLYING_TYPE (template_type),
-                                     arglist, complain, in_decl),
-                             SCOPED_ENUM_P (template_type), NULL);
-           }
-         else
-            {
-              /* We don't want to call start_enum for this type, since
-                 the values for the enumeration constants may involve
-                 template parameters.  And, no one should be interested
-                 in the enumeration constants for such a type.  */
-              t = cxx_make_type (ENUMERAL_TYPE);
-              SET_SCOPED_ENUM_P (t, SCOPED_ENUM_P (template_type));
-            }
-          SET_OPAQUE_ENUM_P (t, OPAQUE_ENUM_P (template_type));
-         ENUM_FIXED_UNDERLYING_TYPE_P (t)
-           = ENUM_FIXED_UNDERLYING_TYPE_P (template_type);
-       }
-      else if (DECL_ALIAS_TEMPLATE_P (gen_tmpl))
-       {
          /* The user referred to a specialization of an alias
            template represented by GEN_TMPL.
 
@@ -7505,6 +7482,29 @@ lookup_template_class_1 (tree d1, tree arglist, tr
          if (t == error_mark_node)
            return t;
        }
+      else if (TREE_CODE (template_type) == ENUMERAL_TYPE)
+       {
+         if (!is_dependent_type)
+           {
+             set_current_access_from_decl (TYPE_NAME (template_type));
+             t = start_enum (TYPE_IDENTIFIER (template_type), NULL_TREE,
+                             tsubst (ENUM_UNDERLYING_TYPE (template_type),
+                                     arglist, complain, in_decl),
+                             SCOPED_ENUM_P (template_type), NULL);
+           }
+         else
+            {
+              /* We don't want to call start_enum for this type, since
+                 the values for the enumeration constants may involve
+                 template parameters.  And, no one should be interested
+                 in the enumeration constants for such a type.  */
+              t = cxx_make_type (ENUMERAL_TYPE);
+              SET_SCOPED_ENUM_P (t, SCOPED_ENUM_P (template_type));
+            }
+          SET_OPAQUE_ENUM_P (t, OPAQUE_ENUM_P (template_type));
+         ENUM_FIXED_UNDERLYING_TYPE_P (t)
+           = ENUM_FIXED_UNDERLYING_TYPE_P (template_type);
+       }
       else if (CLASS_TYPE_P (template_type))
        {
          t = make_class_type (TREE_CODE (template_type));
@@ -7661,7 +7661,8 @@ lookup_template_class_1 (tree d1, tree arglist, tr
        = tree_cons (arglist, t,
                     DECL_TEMPLATE_INSTANTIATIONS (templ));
 
-      if (TREE_CODE (template_type) == ENUMERAL_TYPE && !is_dependent_type)
+      if (TREE_CODE (template_type) == ENUMERAL_TYPE && !is_dependent_type
+         && !DECL_ALIAS_TEMPLATE_P (gen_tmpl))
        /* Now that the type has been registered on the instantiations
           list, we set up the enumerators.  Because the enumeration
           constants may involve the enumeration type itself, we make
Index: testsuite/g++.dg/cpp0x/alias-decl-enum-1.C
===================================================================
--- testsuite/g++.dg/cpp0x/alias-decl-enum-1.C  (revision 0)
+++ testsuite/g++.dg/cpp0x/alias-decl-enum-1.C  (working copy)
@@ -0,0 +1,47 @@
+// PR c++/57734
+// { dg-do compile { target c++11 } }
+
+template<typename T, typename U>
+struct same_type { static const bool value = false; };
+
+template<typename T>
+struct same_type<T, T> { static const bool value = true; };
+
+enum e { zero };
+enum class eclass { one };
+
+template<typename T>
+using enum_alias = e;
+
+template<typename T>
+using eclass_alias = eclass;
+
+typedef enum_alias<void> etest0;
+typedef enum_alias<void> etest0;
+typedef enum_alias<int>  etest0;
+typedef enum_alias<int>  etest1;
+
+static_assert (same_type<etest0, etest1>::value, "");
+
+typedef eclass_alias<void> ectest0;
+typedef eclass_alias<void> ectest0;
+typedef eclass_alias<int>  ectest0;
+typedef eclass_alias<int>  ectest1;
+
+static_assert (same_type<ectest0, ectest1>::value, "");
+
+template<typename T>
+enum_alias<T> efoo(T f) { return enum_alias<T>::zero; }
+
+template<typename T>
+constexpr enum_alias<T> cefoo(T f) { return enum_alias<T>::zero; }
+
+static_assert ( cefoo(1) == e::zero, "");
+
+template<typename T>
+eclass_alias<T> ecfoo(T f) { return eclass_alias<T>::one; }
+
+template<typename T>
+constexpr eclass_alias<T> cecfoo(T f) { return eclass_alias<T>::one; }
+
+static_assert ( cecfoo(1) == eclass::one, "");

Reply via email to