cp-tree.h (ENUM_TEMPLATE_INFO): New macro.
authorMark Mitchell <mark@markmitchell.com>
Thu, 6 Aug 1998 16:58:43 +0000 (16:58 +0000)
committerMark Mitchell <mmitchel@gcc.gnu.org>
Thu, 6 Aug 1998 16:58:43 +0000 (16:58 +0000)
* cp-tree.h (ENUM_TEMPLATE_INFO): New macro.
(TYPE_TEMPLATE_INFO): Likewise.
(SET_TYPE_TEMPLATE_INFO): Likewise.
(ENUM_TI_TEMPLATE): Likewise.
(ENUM_TI_ARGS): Likewise.
(lookup_nested_type_by_name): Remove.
* decl.c (maybe_process_template_type_declaration): Handle enums.
(start_enum): Don't check for primary-template enum declarations
here.
(finish_enum): Clean up, document.  Make sure template enum
constants get the correct type.
(build_enumerator): Copy initializers for template enumerations,
too.
(grok_enum_decls): Document.
* lex.c (do_identifier): Document use of LOOKUP_EXPR a bit
better.  Build LOOKUP_EXPRs for local variables, even if they are
TREE_PERMANENT.
* pt.c (tsubst_enum): Remove field_chain parameter.
(template_class_depth): Include the depth of surrounding function
contexts.
(push_template_decl): Check for primary-template enum declarations
here.  Deal with enumeration templates.
(lookup_template_class): Likewise.
(for_each_template_parm): Likewise.
(instantiate_class_template): Don't call tsubst_enum directly,
call tsubst instead, to instantiate enums.  Deal with all
field_chain issues here, not in tsubst_enum.
(lookup_nested_type_by_name): Remove.
(tsubst_aggr_type): Revise handling of enumeration types.
(tsubst): Likewise.
(tsubst_copy): Likewise.
(tsubst_expr): Call tsubst, not tsubst_enum for TAG_DEFNs.

From-SVN: r21622

gcc/cp/ChangeLog
gcc/cp/cp-tree.h
gcc/cp/decl.c
gcc/cp/lex.c
gcc/cp/pt.c
gcc/testsuite/g++.old-deja/g++.pt/crash19.C [new file with mode: 0644]
gcc/testsuite/g++.old-deja/g++.pt/enum6.C [new file with mode: 0644]
gcc/testsuite/g++.old-deja/g++.pt/enum7.C [new file with mode: 0644]

index 12218d8ae80da7a3300f35c8f2e96a143693ac56..f6bc1b67b1967a2d38ade409787ddbb7a3f97bff 100644 (file)
@@ -1,3 +1,38 @@
+1998-08-06  Mark Mitchell  <mark@markmitchell.com>
+
+       * cp-tree.h (ENUM_TEMPLATE_INFO): New macro.
+       (TYPE_TEMPLATE_INFO): Likewise.
+       (SET_TYPE_TEMPLATE_INFO): Likewise.
+       (ENUM_TI_TEMPLATE): Likewise.
+       (ENUM_TI_ARGS): Likewise.
+       (lookup_nested_type_by_name): Remove.
+       * decl.c (maybe_process_template_type_declaration): Handle enums.
+       (start_enum): Don't check for primary-template enum declarations
+       here. 
+       (finish_enum): Clean up, document.  Make sure template enum
+       constants get the correct type.
+       (build_enumerator): Copy initializers for template enumerations,
+       too. 
+       (grok_enum_decls): Document.
+       * lex.c (do_identifier): Document use of LOOKUP_EXPR a bit
+       better.  Build LOOKUP_EXPRs for local variables, even if they are
+       TREE_PERMANENT.
+       * pt.c (tsubst_enum): Remove field_chain parameter.
+       (template_class_depth): Include the depth of surrounding function
+       contexts.
+       (push_template_decl): Check for primary-template enum declarations
+       here.  Deal with enumeration templates.
+       (lookup_template_class): Likewise.
+       (for_each_template_parm): Likewise.
+       (instantiate_class_template): Don't call tsubst_enum directly,
+       call tsubst instead, to instantiate enums.  Deal with all
+       field_chain issues here, not in tsubst_enum.
+       (lookup_nested_type_by_name): Remove.
+       (tsubst_aggr_type): Revise handling of enumeration types.
+       (tsubst): Likewise.
+       (tsubst_copy): Likewise.
+       (tsubst_expr): Call tsubst, not tsubst_enum for TAG_DEFNs.
+       
 1998-08-04  Mark Mitchell  <mark@markmitchell.com>
 
        * decl.c (pushtag): Don't mangle the name of a TYPE_DECL if it
index aa84e0fa1d20666546a65ac7f589a431101ec29b..fdcd704803f640cf047e47fe3ed4c8b1ba988271 100644 (file)
@@ -1245,15 +1245,38 @@ struct lang_decl
 
 /* For a VAR_DECL or FUNCTION_DECL: template-specific information.  */
 #define DECL_TEMPLATE_INFO(NODE) (DECL_LANG_SPECIFIC(NODE)->decl_flags.template_info)
+
+/* Template information for a RECORD_TYPE or UNION_TYPE.  */
 #define CLASSTYPE_TEMPLATE_INFO(NODE) (TYPE_LANG_SPECIFIC(NODE)->template_info)
+
+/* Template information for an ENUMERAL_TYPE.  Although an enumeration may
+   not be a primary template, it may be declared within the scope of a
+   primary template and the enumeration constants may depend on
+   non-type template parameters.  */
+#define ENUM_TEMPLATE_INFO(NODE) (TYPE_BINFO (NODE))
+
+/* Template information for an ENUMERAL_, RECORD_, or UNION_TYPE.  */
+#define TYPE_TEMPLATE_INFO(NODE)                                       \
+  (TREE_CODE (NODE) == ENUMERAL_TYPE                                   \
+   ? ENUM_TEMPLATE_INFO (NODE) : CLASSTYPE_TEMPLATE_INFO (NODE))
+
+/* Set the template information for an ENUMERAL_, RECORD_, or
+   UNION_TYPE to VAL.  */
+#define SET_TYPE_TEMPLATE_INFO(NODE, VAL)      \
+  (TREE_CODE (NODE) == ENUMERAL_TYPE           \
+   ? (ENUM_TEMPLATE_INFO (NODE) = VAL)                 \
+   : (CLASSTYPE_TEMPLATE_INFO (NODE) = VAL))
+
 #define TI_TEMPLATE(NODE) (TREE_PURPOSE (NODE))
 #define TI_ARGS(NODE) (TREE_VALUE (NODE))
 #define TI_SPEC_INFO(NODE) (TREE_CHAIN (NODE))
 #define TI_PENDING_TEMPLATE_FLAG(NODE) TREE_LANG_FLAG_1 (NODE)
+
 /* TI_PENDING_SPECIALIZATION_FLAG on a template-info node indicates
    that the template is a specialization of a member template, but
    that we don't yet know which one.  */
 #define TI_PENDING_SPECIALIZATION_FLAG(NODE) TREE_LANG_FLAG_1 (NODE)
+
 /* The TEMPLATE_DECL instantiated or specialized by NODE.  This
    TEMPLATE_DECL will be the immediate parent, not the most general
    template.  For example, in:
@@ -1273,6 +1296,7 @@ struct lang_decl
    the DECL_TI_TEMPLATE will be a LOOKUP_EXPR for `f' and the
    DECL_TI_ARGS will be {int}.  */ 
 #define DECL_TI_TEMPLATE(NODE)      TI_TEMPLATE (DECL_TEMPLATE_INFO (NODE))
+
 /* The template arguments used to obtain this decl from the most
    general form of DECL_TI_TEMPLATE.  For the example given for
    DECL_TI_TEMPLATE, the DECL_TI_ARGS will be {int, double}.  These
@@ -1282,6 +1306,19 @@ struct lang_decl
 #define CLASSTYPE_TI_TEMPLATE(NODE) TI_TEMPLATE (CLASSTYPE_TEMPLATE_INFO (NODE))
 #define CLASSTYPE_TI_ARGS(NODE)     TI_ARGS (CLASSTYPE_TEMPLATE_INFO (NODE))
 #define CLASSTYPE_TI_SPEC_INFO(NODE) TI_SPEC_INFO (CLASSTYPE_TEMPLATE_INFO (NODE))
+#define ENUM_TI_TEMPLATE(NODE)                         \
+  TI_TEMPLATE (ENUM_TEMPLATE_INFO (NODE))
+#define ENUM_TI_ARGS(NODE)                     \
+  TI_ARGS (ENUM_TEMPLATE_INFO (NODE))
+
+/* Like DECL_TI_TEMPLATE, but for an ENUMERAL_, RECORD_, or UNION_TYPE.  */
+#define TYPE_TI_TEMPLATE(NODE)                 \
+  (TI_TEMPLATE (TYPE_TEMPLATE_INFO (NODE)))
+
+/* Like DECL_TI_ARGS, , but for an ENUMERAL_, RECORD_, or UNION_TYPE.  */
+#define TYPE_TI_ARGS(NODE)                     \
+  (TI_ARGS (TYPE_TEMPLATE_INFO (NODE)))
+
 #define INNERMOST_TEMPLATE_PARMS(NODE)  TREE_VALUE(NODE)
 
 #define TEMPLATE_PARMS_FOR_INLINE(NODE) TREE_LANG_FLAG_1 (NODE)
@@ -2783,7 +2820,6 @@ extern void mark_class_instantiated               PROTO((tree, int));
 extern void do_decl_instantiation              PROTO((tree, tree, tree));
 extern void do_type_instantiation              PROTO((tree, tree));
 extern tree instantiate_decl                   PROTO((tree));
-extern tree lookup_nested_type_by_name         PROTO((tree, tree));
 extern tree do_poplevel                                PROTO((void));
 extern tree get_bindings                       PROTO((tree, tree, tree));
 /* CONT ... */
index 699170a0c9235ecf47245ee93e03e259d4ed6509..1b70a1ba9151820378737ee192e8fbc2cd31c8cb 100644 (file)
@@ -2253,26 +2253,29 @@ maybe_process_template_type_declaration (type, globalize, b)
     {
       maybe_check_template_type (type);
 
-      if (IS_AGGR_TYPE (type)
-         && (/* If !GLOBALIZE then we are looking at a definition.
-                It may not be a primary template.  (For example, in:
+      my_friendly_assert (IS_AGGR_TYPE (type) 
+                         || TREE_CODE (type) == ENUMERAL_TYPE, 0);
+                         
+                         
+      if (/* If !GLOBALIZE then we are looking at a definition.
+            It may not be a primary template.  (For example, in:
                  
-                template <class T>
-                struct S1 { class S2 {}; }
+              template <class T>
+              struct S1 { class S2 {}; }
                  
-                we have to push_template_decl for S2.)  */
-             (processing_template_decl && !globalize)
-             /* If we are declaring a friend template class, we will
-                have GLOBALIZE set, since something like:
+            we have to push_template_decl for S2.)  */
+         (processing_template_decl && !globalize)
+         /* If we are declaring a friend template class, we will
+            have GLOBALIZE set, since something like:
 
-                template <class T>
-                struct S1 {
-                  template <class U>
-                  friend class S2; 
-                };
+              template <class T>
+              struct S1 {
+                template <class U>
+                friend class S2; 
+              };
 
-                declares S2 to be at global scope.  */
-             || PROCESSING_REAL_TEMPLATE_DECL_P ()))
+            declares S2 to be at global scope.  */
+         || PROCESSING_REAL_TEMPLATE_DECL_P ())
        {
          /* This may change after the call to
             push_template_decl_real, but we want the original value.  */
@@ -2286,7 +2289,8 @@ maybe_process_template_type_declaration (type, globalize, b)
             declaration of the member class into the class scope.  In the
             friend case, push_template_decl will already have put the
             friend into global scope, if appropriate.  */
-         if (!globalize && b->pseudo_global
+         if (TREE_CODE (type) != ENUMERAL_TYPE
+             && !globalize && b->pseudo_global
              && b->level_chain->parm_flag == 2)
            {
              pushdecl_with_scope (CLASSTYPE_TI_TEMPLATE (type),
@@ -11753,9 +11757,6 @@ start_enum (name)
       pushtag (name, enumtype, 0);
     }
 
-  if (b->pseudo_global)
-    cp_error ("template declaration of `%#T'", enumtype);
-
   if (current_class_type)
     TREE_ADDRESSABLE (b->tags) = 1;
 
@@ -11783,30 +11784,46 @@ finish_enum (enumtype, values)
 
   if (values)
     {
-      register tree pair;
-      register tree value = DECL_INITIAL (TREE_VALUE (values));
+      tree pair;
 
-      if (! processing_template_decl)
-       {
-         /* Speed up the main loop by performing some precalculations */
-         TREE_TYPE (TREE_VALUE (values)) = enumtype;
-         TREE_TYPE (value) = enumtype;
-         minnode = maxnode = value;
-       }
-      TREE_VALUE (values) = value;
-      
-      for (pair = TREE_CHAIN (values); pair; pair = TREE_CHAIN (pair))
+      for (pair = values; pair; pair = TREE_CHAIN (pair))
        {
-         value = DECL_INITIAL (TREE_VALUE (pair));
-         if (! processing_template_decl)
-           {
-             TREE_TYPE (TREE_VALUE (pair)) = enumtype;
+         tree decl;
+         tree value;
+
+         /* The TREE_VALUE is a CONST_DECL for this enumeration
+            constant.  */
+         decl = TREE_VALUE (pair);
+
+         /* The type of the CONST_DECL is the type of the enumeration,
+            not an INTEGER_TYPE.  */
+         TREE_TYPE (decl) = enumtype;
+
+         /* The DECL_INITIAL will be NULL if we are processing a
+            template declaration and this enumeration constant had no
+            explicit initializer.  */
+         value = DECL_INITIAL (decl);
+         if (value)
+           {
+             /* Set the TREE_TYPE for the VALUE as well.  When
+                processing a template, however, we might have a
+                TEMPLATE_PARM_INDEX, and we should not change the
+                type of such a thing.  */
+             if (TREE_CODE (value) == TEMPLATE_PARM_INDEX)
+               DECL_INITIAL (decl) = value 
+                 = build1 (NOP_EXPR, enumtype, value);
              TREE_TYPE (value) = enumtype;
-             if (tree_int_cst_lt (maxnode, value))
+
+             if (!minnode)
+               minnode = maxnode = value;
+             else if (tree_int_cst_lt (maxnode, value))
                maxnode = value;
              else if (tree_int_cst_lt (value, minnode))
                minnode = value;
            }
+
+         /* In the list we're building up, we want the enumeration
+            values, not the CONST_DECLs.  */
          TREE_VALUE (pair) = value;
        }
     }
@@ -11922,16 +11939,17 @@ build_enumerator (name, value)
      /* Remove no-op casts from the value.  */
      if (value)
        STRIP_TYPE_NOPS (value);
-
-     /* We have to always copy here; not all INTEGER_CSTs are unshared,
-       and there's no wedding ring. Look at size_int()...*/
-     value = copy_node (value);
 #if 0
      /* To fix MAX_VAL enum consts. (bkoz)  */
      TREE_TYPE (value) = integer_type_node;
 #endif
    }
 
+ /* We have to always copy here; not all INTEGER_CSTs are unshared,
+    and there's no wedding ring. Look at size_int()...*/
+ if (value != NULL_TREE)
+   value = copy_node (value);
+
   /* C++ associates enums with global, function, or class declarations.  */
 
   decl = current_scope ();
@@ -11970,6 +11988,23 @@ build_enumerator (name, value)
   return result;
 }
 
+/* Called after we have finished the declaration of an enumeration
+   type, and, perhaps, some objects whose type involves the
+   enumeration type.  DECL, if non-NULL, is the declaration of the
+   first such object.  
+
+   If CURRENT_LOCAL_ENUM is NULL, the DECL is returned. 
+
+   If CURRENT_LOCAL_ENUM is non-NULL, it should be the CONST_DECL for
+   the last enumeration constant of an enumeration type that is a
+   member of a class.  The enumeration constants are already chained
+   together through their TREE_CHAIN fields.  This function sets the
+   TREE_CHAIN of the last enumeration constant to DECL.  The
+   CONST_DECL for the last enumeration constant is returned.  
+
+   CURRENT_LOCAL_ENUM will always be NULL when this function 
+   returns.  */
+
 tree
 grok_enum_decls (decl)
      tree decl;
index a9166d1fd448826b54d3dd434cef8f38bf6c562c..3271965939027045c1134adbfe4dba56bce0edc8 100644 (file)
@@ -2988,9 +2988,26 @@ do_identifier (token, parsing, args)
   else
     id = hack_identifier (id, token);
 
+  /* We must look up dependent names when the template is
+     instantiated, not while parsing it.  For now, we don't
+     distinguish between dependent and independent names.  So, for
+     example, we look up all overloaded functions at
+     instantiation-time, even though in some cases we should just use
+     the DECL we have here.  We also use LOOKUP_EXPRs to find things
+     like local variables, rather than created TEMPLATE_DECLs for the
+     local variables and then finding matching instantiations.  */
   if (current_template_parms
       && (is_overloaded_fn (id) 
+         /* If it's not going to be around at instantiation time, we
+            look it up then.  This is a hack, and should go when we
+            really get dependent/independent name lookup right.  */
          || !TREE_PERMANENT (id)
+         /* Some local VAR_DECLs (such as those for local variables
+            in member functions of local classes) are built on the
+            permanent obstack.  */
+         || (TREE_CODE (id) == VAR_DECL 
+             && CP_DECL_CONTEXT (id)
+             && TREE_CODE (CP_DECL_CONTEXT (id)) == FUNCTION_DECL)
          || TREE_CODE (id) == PARM_DECL
          || TREE_CODE (id) == USING_DECL))
     id = build_min_nt (LOOKUP_EXPR, token);
index 6775575cb596fcd2918db31d71ac118b907bd9c0..3071f1e37153b2973311f7e9f7590a337cc2b063 100644 (file)
@@ -85,7 +85,7 @@ static tree tsubst_expr_values PROTO((tree, tree));
 static int list_eq PROTO((tree, tree));
 static tree get_class_bindings PROTO((tree, tree, tree));
 static tree coerce_template_parms PROTO((tree, tree, tree, int, int));
-static tree tsubst_enum        PROTO((tree, tree, tree *));
+static tree tsubst_enum        PROTO((tree, tree));
 static tree add_to_template_args PROTO((tree, tree));
 static tree add_outermost_template_args PROTO((tree, tree));
 static void maybe_adjust_types_for_deduction PROTO((unification_kind_t, tree*,
@@ -254,15 +254,29 @@ template_class_depth_real (type, count_specializations)
   int depth;
 
   for (depth = 0; 
-       type && TREE_CODE (type) != FUNCTION_DECL 
-        && TREE_CODE (type) != NAMESPACE_DECL;
-       type = TYPE_CONTEXT (type))
-    if (CLASSTYPE_TEMPLATE_INFO (type)
-       && PRIMARY_TEMPLATE_P (CLASSTYPE_TI_TEMPLATE (type))
-       && ((count_specializations
-            && CLASSTYPE_TEMPLATE_SPECIALIZATION (type))
-           || uses_template_parms (CLASSTYPE_TI_ARGS (type))))
-      ++depth;
+       type && TREE_CODE (type) != NAMESPACE_DECL;
+       type = (TREE_CODE (type) == FUNCTION_DECL) 
+        ? DECL_REAL_CONTEXT (type) : TYPE_CONTEXT (type))
+    {
+      if (TREE_CODE (type) != FUNCTION_DECL)
+       {
+         if (CLASSTYPE_TEMPLATE_INFO (type)
+             && PRIMARY_TEMPLATE_P (CLASSTYPE_TI_TEMPLATE (type))
+             && ((count_specializations
+                  && CLASSTYPE_TEMPLATE_SPECIALIZATION (type))
+                 || uses_template_parms (CLASSTYPE_TI_ARGS (type))))
+           ++depth;
+       }
+      else 
+       {
+         if (DECL_TEMPLATE_INFO (type)
+             && PRIMARY_TEMPLATE_P (DECL_TI_TEMPLATE (type))
+             && ((count_specializations
+                  && DECL_TEMPLATE_SPECIALIZATION (type))
+                 || uses_template_parms (DECL_TI_ARGS (type))))
+           ++depth;
+       }
+    }
 
   return depth;
 }
@@ -1802,10 +1816,14 @@ push_template_decl_real (decl, is_friend)
        cp_error ("template with C linkage");
       if (TREE_CODE (decl) == TYPE_DECL && ANON_AGGRNAME_P (DECL_NAME (decl)))
        cp_error ("template class without a name");
+      if (TREE_CODE (decl) == TYPE_DECL 
+         && TREE_CODE (TREE_TYPE (decl)) == ENUMERAL_TYPE)
+       cp_error ("template declaration of `%#T'", TREE_TYPE (decl));
     }
 
   /* Partial specialization.  */
   if (TREE_CODE (decl) == TYPE_DECL && DECL_ARTIFICIAL (decl)
+      && TREE_CODE (TREE_TYPE (decl)) != ENUMERAL_TYPE
       && CLASSTYPE_TEMPLATE_SPECIALIZATION (TREE_TYPE (decl)))
     {
       tree type = TREE_TYPE (decl);
@@ -1930,10 +1948,11 @@ push_template_decl_real (decl, is_friend)
                  ctx, decl);
       if (TREE_CODE (decl) == TYPE_DECL)
        {
-         if (IS_AGGR_TYPE_CODE (TREE_CODE (TREE_TYPE (decl)))
-             && CLASSTYPE_TEMPLATE_INFO (TREE_TYPE (decl))
-             && CLASSTYPE_TI_TEMPLATE (TREE_TYPE (decl)))
-           tmpl = CLASSTYPE_TI_TEMPLATE (TREE_TYPE (decl));
+         if ((IS_AGGR_TYPE_CODE (TREE_CODE (TREE_TYPE (decl)))
+              || TREE_CODE (TREE_TYPE (decl)) == ENUMERAL_TYPE)
+             && TYPE_TEMPLATE_INFO (TREE_TYPE (decl))
+             && TYPE_TI_TEMPLATE (TREE_TYPE (decl)))
+           tmpl = TYPE_TI_TEMPLATE (TREE_TYPE (decl));
          else
            {
              cp_error ("`%D' does not declare a template type", decl);
@@ -2037,8 +2056,9 @@ push_template_decl_real (decl, is_friend)
 
   if (TREE_CODE (decl) == TYPE_DECL && DECL_ARTIFICIAL (decl))
     {
-      CLASSTYPE_TEMPLATE_INFO (TREE_TYPE (tmpl)) = info;
-      if (!ctx || TREE_CODE (ctx) != FUNCTION_DECL)
+      SET_TYPE_TEMPLATE_INFO (TREE_TYPE (tmpl), info);
+      if ((!ctx || TREE_CODE (ctx) != FUNCTION_DECL)
+         && TREE_CODE (TREE_TYPE (decl)) != ENUMERAL_TYPE)
        DECL_NAME (decl) = classtype_mangled_name (TREE_TYPE (decl));
     }
   else if (! DECL_LANG_SPECIFIC (decl))
@@ -3124,9 +3144,11 @@ lookup_template_class (d1, arglist, in_decl, context, entering_scope)
       template = CLASSTYPE_TI_TEMPLATE (TREE_TYPE (d1));
       d1 = DECL_NAME (template);
     }
-  else if (TREE_CODE_CLASS (TREE_CODE (d1)) == 't' && IS_AGGR_TYPE (d1))
+  else if (TREE_CODE (d1) == ENUMERAL_TYPE 
+          || (TREE_CODE_CLASS (TREE_CODE (d1)) == 't' 
+              && IS_AGGR_TYPE (d1)))
     {
-      template = CLASSTYPE_TI_TEMPLATE (d1);
+      template = TYPE_TI_TEMPLATE (d1);
       d1 = DECL_NAME (template);
     }
   else if (TREE_CODE (d1) == TEMPLATE_DECL
@@ -3229,7 +3251,7 @@ lookup_template_class (d1, arglist, in_decl, context, entering_scope)
              return error_mark_node;
            }
 
-         arglist = add_to_template_args (CLASSTYPE_TI_ARGS (context),
+         arglist = add_to_template_args (TYPE_TI_ARGS (context),
                                          arglist);
          arg_depth = TMPL_ARGS_DEPTH (arglist);
        }
@@ -3286,7 +3308,7 @@ lookup_template_class (d1, arglist, in_decl, context, entering_scope)
 
         the `C<T>' is just the same as `C'.  Outside of the
         class, however, such a reference is an instantiation.  */
-      if (comp_template_args (CLASSTYPE_TI_ARGS (template_type),
+      if (comp_template_args (TYPE_TI_ARGS (template_type),
                              arglist))
        {
          found = template_type;
@@ -3338,45 +3360,67 @@ lookup_template_class (d1, arglist, in_decl, context, entering_scope)
       push_obstacks (&permanent_obstack, &permanent_obstack);
       
       /* Create the type.  */
-      t = make_lang_type (TREE_CODE (template_type));
-      CLASSTYPE_DECLARED_CLASS (t) 
-       = CLASSTYPE_DECLARED_CLASS (template_type);
-      TYPE_CONTEXT (t) = FROB_CONTEXT (context);
+      if (TREE_CODE (template_type) == ENUMERAL_TYPE)
+       {
+         if (!uses_template_parms (arglist))
+           t = tsubst_enum (template_type, arglist);
+         else
+           /* We don't want to call tsubst_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 = make_node (ENUMERAL_TYPE);
+       }
+      else
+       {
+         t = make_lang_type (TREE_CODE (template_type));
+         CLASSTYPE_DECLARED_CLASS (t) 
+           = CLASSTYPE_DECLARED_CLASS (template_type);
+         CLASSTYPE_GOT_SEMICOLON (t) = 1;
+         SET_CLASSTYPE_IMPLICIT_INSTANTIATION (t);
+       }
+
+      /* If we called tsubst_enum above, this information will already
+        be set up.  */
+      if (!TYPE_NAME (t))
+       {
+         TYPE_CONTEXT (t) = FROB_CONTEXT (context);
          
-      /* Create a stub TYPE_DECL for it.  */
-      type_decl = build_decl (TYPE_DECL, DECL_NAME (template), t);
-      SET_DECL_ARTIFICIAL (type_decl);
-      DECL_CONTEXT (type_decl) = TYPE_CONTEXT (t);
-      DECL_SOURCE_FILE (type_decl) 
-       = DECL_SOURCE_FILE (TYPE_STUB_DECL (template_type));
-      DECL_SOURCE_LINE (type_decl) 
-       = DECL_SOURCE_LINE (TYPE_STUB_DECL (template_type));
-      TYPE_STUB_DECL (t) = TYPE_NAME (t) = type_decl;
+         /* Create a stub TYPE_DECL for it.  */
+         type_decl = build_decl (TYPE_DECL, DECL_NAME (template), t);
+         SET_DECL_ARTIFICIAL (type_decl);
+         DECL_CONTEXT (type_decl) = TYPE_CONTEXT (t);
+         DECL_SOURCE_FILE (type_decl) 
+           = DECL_SOURCE_FILE (TYPE_STUB_DECL (template_type));
+         DECL_SOURCE_LINE (type_decl) 
+           = DECL_SOURCE_LINE (TYPE_STUB_DECL (template_type));
+         TYPE_STUB_DECL (t) = TYPE_NAME (t) = type_decl;
+       }
+      else
+       type_decl = TYPE_NAME (t);
 
       /* We're done with the permanent obstack, now.  */
       pop_obstacks ();
 
-      /* Seems to be wanted.  */
-      CLASSTYPE_GOT_SEMICOLON (t) = 1;
-
       /* Set up the template information.  */
       arglist = copy_to_permanent (arglist);
-      CLASSTYPE_TEMPLATE_INFO (t)
-       = perm_tree_cons (template, arglist, NULL_TREE);
+      SET_TYPE_TEMPLATE_INFO (t,
+                             perm_tree_cons (template, arglist, NULL_TREE));
       DECL_TEMPLATE_INSTANTIATIONS (template) = perm_tree_cons
        (arglist, t, DECL_TEMPLATE_INSTANTIATIONS (template));
-      SET_CLASSTYPE_IMPLICIT_INSTANTIATION (t);
 
       /* Reset the name of the type, now that CLASSTYPE_TEMPLATE_INFO
         is set up.  */
-      DECL_NAME (type_decl) = classtype_mangled_name (t);
+      if (TREE_CODE (t) != ENUMERAL_TYPE)
+       DECL_NAME (type_decl) = classtype_mangled_name (t);
       DECL_ASSEMBLER_NAME (type_decl) = DECL_NAME (type_decl);
       if (! uses_template_parms (arglist))
        {
          DECL_ASSEMBLER_NAME (type_decl)
            = get_identifier (build_overload_name (t, 1, 1));
          
-         if (flag_external_templates
+         if (TREE_CODE (t) != ENUMERAL_TYPE
+             && flag_external_templates
              && CLASSTYPE_INTERFACE_KNOWN (TREE_TYPE (template))
              && ! CLASSTYPE_INTERFACE_ONLY (TREE_TYPE (template)))
            add_pending_template (t);
@@ -3449,15 +3493,19 @@ for_each_template_parm (t, fn, data)
     case POINTER_TYPE:
     case REFERENCE_TYPE:
       return for_each_template_parm (TREE_TYPE (t), fn, data);
+
     case RECORD_TYPE:
       if (TYPE_PTRMEMFUNC_FLAG (t))
        return for_each_template_parm (TYPE_PTRMEMFUNC_FN_TYPE (t),
                                       fn, data);
+      /* Fall through.  */
+
     case UNION_TYPE:
-      if (! CLASSTYPE_TEMPLATE_INFO (t))
+    case ENUMERAL_TYPE:
+      if (! TYPE_TEMPLATE_INFO (t))
        return 0;
       return for_each_template_parm (TREE_VALUE
-                                    (CLASSTYPE_TEMPLATE_INFO (t)),
+                                    (TYPE_TEMPLATE_INFO (t)),
                                     fn, data);
     case FUNCTION_TYPE:
       if (for_each_template_parm (TYPE_ARG_TYPES (t), fn, data))
@@ -3541,16 +3589,6 @@ for_each_template_parm (t, fn, data)
     case NAMESPACE_DECL:
       return 0;
 
-    case ENUMERAL_TYPE:
-      {
-       tree v;
-
-       for (v = TYPE_VALUES (t); v != NULL_TREE; v = TREE_CHAIN (v))
-         if (for_each_template_parm (TREE_VALUE (v), fn, data))
-           return 1;
-      }
-      return 0;
-
       /* constants */
     case INTEGER_CST:
     case REAL_CST:
@@ -4207,24 +4245,46 @@ instantiate_class_template (type)
       tree name = TYPE_IDENTIFIER (tag);
       tree newtag;
 
-      if (TREE_CODE (tag) == ENUMERAL_TYPE)
+      newtag = tsubst (tag, args, NULL_TREE);
+      if (TREE_CODE (newtag) == ENUMERAL_TYPE)
        {
-         newtag = tsubst_enum (tag, args, field_chain);
-         while (*field_chain)
+         extern tree current_local_enum;
+         tree prev_local_enum = current_local_enum;
+
+         if (TYPE_VALUES (newtag))
            {
-             DECL_FIELD_CONTEXT (*field_chain) = type;
-             field_chain = &TREE_CHAIN (*field_chain);
+             tree v;
+
+             /* We must set things up so that CURRENT_LOCAL_ENUM is the
+                CONST_DECL for the last enumeration constant, since the
+                CONST_DECLs are chained backwards.  */
+             for (v = TYPE_VALUES (newtag); TREE_CHAIN (v); 
+                  v = TREE_CHAIN (v))
+               ;
+
+             current_local_enum 
+               = IDENTIFIER_CLASS_VALUE (TREE_PURPOSE (v));
+             *field_chain = grok_enum_decls (NULL_TREE);
+             current_local_enum = prev_local_enum;
+
+             while (*field_chain)
+               {
+                 DECL_FIELD_CONTEXT (*field_chain) = type;
+                 field_chain = &TREE_CHAIN (*field_chain);
+               }
            }
        }
       else
-       newtag = tsubst (tag, args, NULL_TREE);
-
-      /* Now, we call pushtag to put this NEWTAG into the scope of
-        TYPE.  We first set up the IDENTIFIER_TYPE_VALUE to avoid
-        pushtag calling push_template_decl.  */
-      if (name)
-       SET_IDENTIFIER_TYPE_VALUE (name, newtag);
-      pushtag (name, newtag, /*globalize=*/0);
+       {
+         /* Now, we call pushtag to put this NEWTAG into the scope of
+            TYPE.  We first set up the IDENTIFIER_TYPE_VALUE to avoid
+            pushtag calling push_template_decl.  We don't have to do
+            this for enums because it will already have been done in
+            tsubst_enum.  */
+         if (name)
+           SET_IDENTIFIER_TYPE_VALUE (name, newtag);
+         pushtag (name, newtag, /*globalize=*/0);
+       }
     }
 
   /* Don't replace enum constants here.  */
@@ -4371,24 +4431,6 @@ list_eq (t1, t2)
   return list_eq (TREE_CHAIN (t1), TREE_CHAIN (t2));
 }
 
-tree 
-lookup_nested_type_by_name (ctype, name)
-        tree ctype, name;
-{
-  tree t;
-
-  complete_type (ctype);
-
-  for (t = CLASSTYPE_TAGS (ctype); t; t = TREE_CHAIN (t))
-    {
-      if (name == TREE_PURPOSE (t)
-         /* this catches typedef enum { foo } bar; */
-         || name == TYPE_IDENTIFIER (TREE_VALUE (t)))
-       return TREE_VALUE (t);
-    }
-  return NULL_TREE;
-}
-
 /* If arg is a non-type template parameter that does not depend on template
    arguments, fold it like we weren't in the body of a template.  */
 
@@ -4507,11 +4549,11 @@ tsubst_template_parms (parms, args)
   return r;
 }
 
-/* Substitute the ARGS into the indicated aggregate type T.  If T is
-   not an aggregate type, it is handled as if by tsubst.  IN_DECL is
-   as for tsubst.  If ENTERING_SCOPE is non-zero, T is the context for
-   a template which we are presently tsubst'ing.  Return the
-   subsituted value.  */
+/* Substitute the ARGS into the indicated aggregate (or enumeration)
+   type T.  If T is not an aggregate or enumeration type, it is
+   handled as if by tsubst.  IN_DECL is as for tsubst.  If
+   ENTERING_SCOPE is non-zero, T is the context for a template which
+   we are presently tsubst'ing.  Return the subsituted value.  */
 
 tree
 tsubst_aggr_type (t, args, in_decl, entering_scope)
@@ -4535,6 +4577,7 @@ tsubst_aggr_type (t, args, in_decl, entering_scope)
        }
 
       /* else fall through */
+    case ENUMERAL_TYPE:
     case UNION_TYPE:
       if (uses_template_parms (t))
        {
@@ -4559,7 +4602,7 @@ tsubst_aggr_type (t, args, in_decl, entering_scope)
             and supposing that we are instantiating f<int, double>,
             then our ARGS will be {int, double}, but, when looking up
             S we only want {double}.  */
-         argvec = tsubst (CLASSTYPE_TI_ARGS (t), args, in_decl);
+         argvec = tsubst (TYPE_TI_ARGS (t), args, in_decl);
 
          r = lookup_template_class (t, argvec, in_decl, context,
                                     entering_scope);
@@ -4614,6 +4657,7 @@ tsubst (t, args, in_decl)
     {
     case RECORD_TYPE:
     case UNION_TYPE:
+    case ENUMERAL_TYPE:
       return tsubst_aggr_type (t, args, in_decl, /*entering_scope=*/0);
 
     case ERROR_MARK:
@@ -4629,18 +4673,6 @@ tsubst (t, args, in_decl)
     case NAMESPACE_DECL:
       return t;
 
-    case ENUMERAL_TYPE:
-      {
-       tree ctx = tsubst_aggr_type (TYPE_CONTEXT (t), args, in_decl,
-                                    /*entering_scope=*/1);
-       if (ctx == NULL_TREE || TREE_CODE (ctx) == NAMESPACE_DECL)
-         return t;
-       else if (ctx == current_function_decl)
-         return lookup_name (TYPE_IDENTIFIER (t), 1);
-       else
-         return lookup_nested_type_by_name (ctx, TYPE_IDENTIFIER (t));
-      }
-
     case INTEGER_TYPE:
       if (t == integer_type_node)
        return t;
@@ -5496,12 +5528,45 @@ tsubst_copy (t, args, in_decl)
       return do_identifier (DECL_NAME (t), 0, NULL_TREE);
 
     case CONST_DECL:
+      {
+       tree enum_type;
+       tree v;
+
+       if (!DECL_CONTEXT (t))
+         /* This is a global enumeration constant.  */
+         return t;
+
+       /* Unfortunately, we cannot just call lookup_name here.
+        Consider:
+
+        template <int I> int f() {
+          enum E { a = I };
+          struct S { void g() { E e = a; } };
+        };
+
+        When we instantiate f<7>::S::g(), say, lookup_name is not
+        clever enough to find f<7>::a.  */
+       enum_type 
+         = tsubst_aggr_type (TREE_TYPE (t), args, in_decl, 
+                             /*entering_scope=*/0);
+
+       for (v = TYPE_VALUES (enum_type); 
+            v != NULL_TREE; 
+            v = TREE_CHAIN (v))
+         if (TREE_PURPOSE (v) == DECL_NAME (t))
+           return TREE_VALUE (v);
+
+         /* We didn't find the name.  That should never happen; if
+            name-lookup found it during preliminary parsing, we
+            should find it again here during instantiation.  */
+       my_friendly_abort (0);
+      }
+      break;
+
     case FIELD_DECL:
       if (DECL_CONTEXT (t))
        {
          tree ctx;
-         if (TREE_CODE (DECL_CONTEXT (t)) == FUNCTION_DECL)
-           return lookup_name (DECL_NAME (t), 0);
 
          ctx = tsubst_aggr_type (DECL_CONTEXT (t), args, in_decl,
                                  /*entering_scope=*/1);
@@ -5984,7 +6049,7 @@ tsubst_expr (t, args, in_decl)
       lineno = TREE_COMPLEXITY (t);
       t = TREE_TYPE (t);
       if (TREE_CODE (t) == ENUMERAL_TYPE)
-       tsubst_enum (t, args, NULL);
+       tsubst (t, args, NULL_TREE);
       break;
 
     default:
@@ -7823,13 +7888,11 @@ add_maybe_template (d, fns)
   DECL_MAYBE_TEMPLATE (d) = 1;
 }
 
-/* Instantiate an enumerated type.  Used by instantiate_class_template and
-   tsubst_expr.  */
+/* Instantiate an enumerated type.  */
 
 static tree
-tsubst_enum (tag, args, field_chain)
+tsubst_enum (tag, args)
      tree tag, args;
-     tree * field_chain;
 {
   extern tree current_local_enum;
   tree prev_local_enum = current_local_enum;
@@ -7839,18 +7902,26 @@ tsubst_enum (tag, args, field_chain)
 
   for (e = TYPE_VALUES (tag); e; e = TREE_CHAIN (e))
     {
-      tree elt = build_enumerator (TREE_PURPOSE (e),
-                                  tsubst_expr (TREE_VALUE (e), args,
-                                               NULL_TREE));
+      tree value;
+      tree elt;
+
+      value = TREE_VALUE (e);
+      if (value)
+       {
+         if (TREE_CODE (value) == NOP_EXPR)
+           /* This is the special case where the value is really a
+          TEMPLATE_PARM_INDEX.  See finish_enum.  */
+           value = TREE_OPERAND (value, 0);
+         value = tsubst_expr (value, args, NULL_TREE);
+       }
+
+      elt = build_enumerator (TREE_PURPOSE (e), value);
       TREE_CHAIN (elt) = values;
       values = elt;
     }
 
   finish_enum (newtag, values);
 
-  if (NULL != field_chain)
-    *field_chain = grok_enum_decls (NULL_TREE);
-
   current_local_enum = prev_local_enum;
 
   return newtag;
diff --git a/gcc/testsuite/g++.old-deja/g++.pt/crash19.C b/gcc/testsuite/g++.old-deja/g++.pt/crash19.C
new file mode 100644 (file)
index 0000000..2da6dd9
--- /dev/null
@@ -0,0 +1,19 @@
+// Build don't link:
+
+template <int I>
+void f()
+{
+  class C { public: int c; };
+
+  struct S {
+    void g() {
+      C e;
+      e.c = 3;
+    };
+  };
+
+  S s;
+  s.g();
+}
+
+template void f<7>();
diff --git a/gcc/testsuite/g++.old-deja/g++.pt/enum6.C b/gcc/testsuite/g++.old-deja/g++.pt/enum6.C
new file mode 100644 (file)
index 0000000..acfd681
--- /dev/null
@@ -0,0 +1,14 @@
+// Build don't link:
+
+template <class T>
+struct vector {};
+
+template<class T>
+void fn(T)
+{
+  enum tern { H, L, X, U };
+
+  vector<tern> ternvec; // ERROR - composed from a local type
+}
+
+template void fn(int);
diff --git a/gcc/testsuite/g++.old-deja/g++.pt/enum7.C b/gcc/testsuite/g++.old-deja/g++.pt/enum7.C
new file mode 100644 (file)
index 0000000..47dcbfa
--- /dev/null
@@ -0,0 +1,27 @@
+template <int I>
+int f()
+{
+  enum E { a = I };
+
+  struct S {
+    int g() {
+      E e;
+      e = a;
+      return (int) e;
+    };
+  };
+
+  S s;
+
+  return s.g();
+}
+
+
+int main()
+{
+  if (f<7>() != 7)
+    return 1;
+  if (f<-3>() != -3)
+    return 1;
+  return 0;
+}