cp-tree.h (lang_decl_flags): Add defined_in_class.
authorMark Mitchell <mark@markmitchell.com>
Fri, 6 Nov 1998 16:50:46 +0000 (16:50 +0000)
committerMark Mitchell <mmitchel@gcc.gnu.org>
Fri, 6 Nov 1998 16:50:46 +0000 (16:50 +0000)
* cp-tree.h (lang_decl_flags): Add defined_in_class.  Decrease
size of dummy.
(DECL_DEFINED_IN_CLASS_P): New macro.
(TEMPLATE_PARMS_FOR_INLINE): Document.
(check_static_variable_definition): New function.
* decl.c (cp_finish_decl): Set DECL_DEFINED_IN_CLASS_P, if
appropriate.
(check_static_variable_definition): Split out from ...
(grokdeclarator): Here.
* pt.c (check_default_tmpl_args): New function, split out from ...
(push_template_decl_real): Here.
(instantiate_template): Fix comment.

From-SVN: r23549

gcc/cp/ChangeLog
gcc/cp/cp-tree.h
gcc/cp/decl.c
gcc/cp/pt.c
gcc/testsuite/g++.old-deja/g++.pt/defarg6.C [new file with mode: 0644]
gcc/testsuite/g++.old-deja/g++.pt/defarg7.C [new file with mode: 0644]
gcc/testsuite/g++.old-deja/g++.pt/static5.C [new file with mode: 0644]

index 9bc821c04fc41c5f55cc36fcac3b32ecff2590fa..ef4908fd3e64996e2a1cfc3e0474ada60c28dd9e 100644 (file)
@@ -1,3 +1,18 @@
+1998-11-06  Mark Mitchell  <mark@markmitchell.com>
+
+       * cp-tree.h (lang_decl_flags): Add defined_in_class.  Decrease
+       size of dummy.
+       (DECL_DEFINED_IN_CLASS_P): New macro.
+       (TEMPLATE_PARMS_FOR_INLINE): Document.
+       (check_static_variable_definition): New function.
+       * decl.c (cp_finish_decl): Set DECL_DEFINED_IN_CLASS_P, if
+       appropriate. 
+       (check_static_variable_definition): Split out from ...
+       (grokdeclarator): Here.
+       * pt.c (check_default_tmpl_args): New function, split out from ...
+       (push_template_decl_real): Here.
+       (instantiate_template): Fix comment.
+       
 1998-11-04  Mark Mitchell  <mark@markmitchell.com>
 
        * cp-tree.h (CP_TYPE_CONST_P): Make {0,1}-valued.
index e55766f4652733ad8abe2c09e17f5599909d67c6..d502f93189d4dcd8b2b1e0a99ff4c583c8345f2f 100644 (file)
@@ -1095,7 +1095,8 @@ struct lang_decl_flags
   unsigned comdat : 1;
   unsigned needs_final_overrider : 1;
   unsigned bitfield : 1;
-  unsigned dummy : 2;
+  unsigned defined_in_class : 1;
+  unsigned dummy : 1;
 
   tree access;
   tree context;
@@ -1165,6 +1166,11 @@ struct lang_decl
    should be allocated.  */
 #define DECL_IN_AGGR_P(NODE) (DECL_LANG_FLAG_3(NODE))
 
+/* Nonzero if the DECL was defined in the class definition itself,
+   rather than outside the class.  */
+#define DECL_DEFINED_IN_CLASS_P(DECL) \
+ (DECL_LANG_SPECIFIC (DECL)->decl_flags.defined_in_class)
+
 /* Nonzero for FUNCTION_DECL means that this decl is just a
    friend declaration, and should not be added to the list of
    member functions for this class.  */
@@ -1357,6 +1363,9 @@ struct lang_decl
 
 #define INNERMOST_TEMPLATE_PARMS(NODE)  TREE_VALUE(NODE)
 
+/* Nonzero if the NODE corresponds to the template parameters for a
+   member template, whose inline definition is being processed after
+   the class definition is complete.  */
 #define TEMPLATE_PARMS_FOR_INLINE(NODE) TREE_LANG_FLAG_1 (NODE)
 
 #define DECL_SAVED_TREE(NODE)          DECL_MEMFUNC_POINTER_TO (NODE)
@@ -2682,6 +2691,7 @@ extern void print_other_binding_stack             PROTO((struct binding_level *));
 extern void revert_static_member_fn             PROTO((tree*, tree*, tree*));
 extern void cat_namespace_levels                PROTO((void));
 extern void fixup_anonymous_union               PROTO((tree));
+extern int check_static_variable_definition     PROTO((tree, tree));
 
 /* in decl2.c */
 extern int check_java_method                   PROTO((tree));
index 394984fa3a3bbb1242de21b77a77a1fe991256a1..6ed993e790ccd69c88ef30adc6c35fd7d521be80 100644 (file)
@@ -7071,6 +7071,12 @@ cp_finish_decl (decl, init, asmspec_tree, need_pop, flags)
       init = NULL_TREE;
     }
 
+  if (current_class_type
+      && DECL_REAL_CONTEXT (decl) == current_class_type
+      && TYPE_BEING_DEFINED (current_class_type)
+      && (DECL_INITIAL (decl) || init))
+    DECL_DEFINED_IN_CLASS_P (decl) = 1;
+
   if (TREE_CODE (decl) == VAR_DECL 
       && DECL_CONTEXT (decl)
       && TREE_CODE (DECL_CONTEXT (decl)) == NAMESPACE_DECL
@@ -8493,6 +8499,41 @@ build_ptrmemfunc_type (type)
 
 enum return_types { return_normal, return_ctor, return_dtor, return_conversion };
 
+/* DECL is a VAR_DECL defined in-class, whose TYPE is also given.
+   Check to see that the definition is valid.  Issue appropriate error
+   messages.  Return 1 if the definition is particularly bad, or 0
+   otherwise.  */
+
+int
+check_static_variable_definition (decl, type)
+     tree decl;
+     tree type;
+{
+  /* Motion 10 at San Diego: If a static const integral data member is
+     initialized with an integral constant expression, the initializer
+     may appear either in the declaration (within the class), or in
+     the definition, but not both.  If it appears in the class, the
+     member is a member constant.  The file-scope definition is always
+     required.  */
+  if (CLASS_TYPE_P (type) || TREE_CODE (type) == REFERENCE_TYPE)
+    {
+      cp_error ("in-class initialization of static data member of non-integral type `%T'", 
+               type);
+      /* If we just return the declaration, crashes will sometimes
+        occur.  We therefore return void_type_node, as if this was a
+        friend declaration, to cause callers to completely ignore
+        this declaration.  */
+      return 1;
+    }
+  else if (!CP_TYPE_CONST_P (type))
+    cp_error ("ANSI C++ forbids in-class initialization of non-const static member `%D'",
+             decl);
+  else if (pedantic && !INTEGRAL_TYPE_P (type))
+    cp_pedwarn ("ANSI C++ forbids initialization of member constant `%D' of non-integral type `%T'", decl, type);
+
+  return 0;
+}
+
 tree
 grokdeclarator (declarator, declspecs, decl_context, initialized, attrlist)
      tree declspecs;
@@ -10660,31 +10701,17 @@ grokdeclarator (declarator, declspecs, decl_context, initialized, attrlist)
                    staticp = 1;
                  }
 
-               /* Motion 10 at San Diego: If a static const integral data
-                  member is initialized with an integral constant
-                  expression, the initializer may appear either in the
-                  declaration (within the class), or in the definition,
-                  but not both.  If it appears in the class, the member is
-                  a member constant.  The file-scope definition is always
-                  required.  */
-               if (CLASS_TYPE_P (type)
-                   || TREE_CODE (type) == REFERENCE_TYPE)
-                 {
-                   cp_error ("in-class initialization of static data member of non-integral type `%T'", 
-                             type);
-                   /* If we just return the declaration, crashes will
-                      sometimes occur.  We therefore return
-                      void_type_node, as if this was a friend
-                      declaration, to cause callers to completely
-                      ignore this declaration.  */
-                   return void_type_node;
-                 }
-               else if (!(type_quals & TYPE_QUAL_CONST))
-                 cp_error ("ANSI C++ forbids in-class initialization of non-const static member `%D'",
-                           declarator);
-               else if (pedantic && ! INTEGRAL_TYPE_P (type) 
-                        && !uses_template_parms (type))
-                 cp_pedwarn ("ANSI C++ forbids initialization of member constant `%D' of non-integral type `%T'", declarator, type);
+               if (uses_template_parms (type))
+                 /* We'll check at instantiation time.  */
+                 ;
+               else if (check_static_variable_definition (declarator,
+                                                          type))
+                 /* If we just return the declaration, crashes
+                    will sometimes occur.  We therefore return
+                        void_type_node, as if this was a friend
+                        declaration, to cause callers to completely
+                        ignore this declaration.  */
+                 return void_type_node;
              }
 
            if (staticp)
index 27882f7c9e7ac4b19d1fe85237398eb35889cc8f..aa814566129cd698714ff5573d7b7d2c2a019b0c 100644 (file)
@@ -135,6 +135,7 @@ static tree tsubst_arg_types PROTO((tree, tree, tree));
 static void check_specialization_scope PROTO((void));
 static tree process_partial_specialization PROTO((tree));
 static void set_current_access_from_decl PROTO((tree));
+static void check_default_tmpl_args PROTO((tree, tree, int, int));
 
 /* We use TREE_VECs to hold template arguments.  If there is only one
    level of template arguments, then the TREE_VEC contains the
@@ -1853,28 +1854,9 @@ process_partial_specialization (decl)
   int ntparms = TREE_VEC_LENGTH (inner_parms);
   int  i;
   int did_error_intro = 0;
-  int issued_default_arg_message = 0;
   struct template_parm_data tpd;
   struct template_parm_data tpd2;
 
-  /* [temp.class.spec]
-     
-     The template parameter list of a specialization shall not
-     contain default template argument values.  */
-  for (i = 0; i < ntparms; ++i) 
-    {
-      if (TREE_PURPOSE (TREE_VEC_ELT (inner_parms, i)))
-       {
-         if (!issued_default_arg_message)
-           {
-             cp_error ("default argument in partial specialization `%T'", 
-                       type);
-             issued_default_arg_message = 1;
-           }
-         TREE_PURPOSE (TREE_VEC_ELT (inner_parms, i)) = NULL_TREE;
-       }
-    }
-
   /* We check that each of the template parameters given in the
      partial specialization is used in the argument list to the
      specialization.  For example:
@@ -2029,6 +2011,107 @@ process_partial_specialization (decl)
   return decl;
 }
 
+/* Check that a template declaration's use of default arguments is not
+   invalid.  Here, PARMS are the template parameters.  IS_PRIMARY is
+   non-zero if DECL is the thing declared by a primary template.
+   IS_PARTIAL is non-zero if DECL is a partial specialization.  */
+
+static void
+check_default_tmpl_args (decl, parms, is_primary, is_partial)
+     tree decl;
+     tree parms;
+     int is_primary;
+     int is_partial;
+{
+  char* msg;
+  int   last_level_to_check;
+
+  /* [temp.param] 
+
+     A default template-argument shall not be specified in a
+     function template declaration or a function template definition, nor
+     in the template-parameter-list of the definition of a member of a
+     class template.  */
+
+  if (current_class_type
+      && !TYPE_BEING_DEFINED (current_class_type)
+      && DECL_REAL_CONTEXT (decl) == current_class_type
+      && DECL_DEFINED_IN_CLASS_P (decl)) 
+    /* We already checked these parameters when the template was
+       declared, so there's no need to do it again now.  This is an
+       inline member function definition.  */
+    return;
+
+  if (TREE_CODE (decl) != TYPE_DECL || is_partial || !is_primary)
+    /* For an ordinary class template, default template arguments are
+       allowed at the innermost level, e.g.:
+         template <class T = int>
+        struct S {};
+       but, in a partial specialization, they're not allowed even
+       there, as we have in [temp.class.spec]:
+     
+        The template parameter list of a specialization shall not
+        contain default template argument values.  
+
+       So, for a partial specialization, or for a function template,
+       we look at all of them.  */
+    ;
+  else
+    /* But, for a primary class template that is not a partial
+       specialization we look at all template parameters except the
+       innermost ones.  */
+    parms = TREE_CHAIN (parms);
+
+  /* Figure out what error message to issue.  */
+  if (TREE_CODE (decl) == FUNCTION_DECL)
+    msg = "default argument for template parameter in function template `%D'";
+  else if (is_partial)
+    msg = "default argument in partial specialization `%D'";
+  else
+    msg = "default argument for template parameter for class enclosing `%D'";
+
+  if (current_class_type && TYPE_BEING_DEFINED (current_class_type))
+    /* If we're inside a class definition, there's no need to
+       examine the paramters to the class itself.  On the one
+       hand, they will be checked when the class is defined, and,
+       on the other, default arguments are legal in things like:
+         template <class T = double>
+         struct S { template <class U> void f(U); };
+       Here the default argument for `S' has no bearing on the
+       declaration of `f'.  */
+    last_level_to_check = template_class_depth (current_class_type) + 1;
+  else
+    /* Check everything.  */
+    last_level_to_check = 0;
+
+  for (; parms && TMPL_PARMS_DEPTH (parms) >= last_level_to_check; 
+       parms = TREE_CHAIN (parms))
+    {
+      tree inner_parms = TREE_VALUE (parms);
+      int i, ntparms;
+
+      ntparms = TREE_VEC_LENGTH (inner_parms);
+      for (i = 0; i < ntparms; ++i) 
+       if (TREE_PURPOSE (TREE_VEC_ELT (inner_parms, i)))
+         {
+           if (msg)
+             {
+               cp_error (msg, decl);
+               msg = 0;
+             }
+
+           /* Clear out the default argument so that we are not
+              confused later.  */
+           TREE_PURPOSE (TREE_VEC_ELT (inner_parms, i)) = NULL_TREE;
+         }
+
+      /* At this point, if we're still interested in issuing messages,
+        they must apply to classes surrounding the object declared.  */
+      if (msg)
+       msg = "default argument for template parameter for class enclosing `%D'"; 
+    }
+}
+
 /* Creates a TEMPLATE_DECL for the indicated DECL using the template
    parameters given by current_template_args, or reuses a
    previously existing one, if appropriate.  Returns the DECL, or an
@@ -2046,6 +2129,12 @@ push_template_decl_real (decl, is_friend)
   tree info;
   tree ctx;
   int primary;
+  int is_partial;
+
+  /* See if this is a partial specialization.  */
+  is_partial = (TREE_CODE (decl) == TYPE_DECL && DECL_ARTIFICIAL (decl)
+               && TREE_CODE (TREE_TYPE (decl)) != ENUMERAL_TYPE
+               && CLASSTYPE_TEMPLATE_SPECIALIZATION (TREE_TYPE (decl)));
 
   is_friend |= (TREE_CODE (decl) == FUNCTION_DECL && DECL_FRIEND_P (decl));
 
@@ -2076,6 +2165,7 @@ push_template_decl_real (decl, is_friend)
   else
     info = ctx;
 
+  /* See if this is a primary template.  */
   if (info && TREE_CODE (info) == FUNCTION_DECL)
     primary = 0;
   /* Note that template_class_depth returns 0 if given NULL_TREE, so
@@ -2096,47 +2186,13 @@ push_template_decl_real (decl, is_friend)
        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)))
-    return process_partial_specialization (decl);
+  /* Check to see that the rules regarding the use of default
+     arguments are not being violated.  */
+  check_default_tmpl_args (decl, current_template_parms, 
+                          primary, is_partial);
 
-  /* [temp.param] A default template-argument shall not be specified in a
-     function template declaration or a function template definition, nor
-     in the template-parameter-list of the definition of a member of a
-     class template.  */
-  {
-    tree parms;
-    int issued_default_arg_message = 0;
-
-    parms = current_template_parms;
-    if (primary)
-      parms = TREE_CHAIN (parms);
-    for (; parms; parms = TREE_CHAIN (parms))
-      {
-       tree inner_parms = TREE_VALUE (parms);
-       int i, ntparms;
-
-       if (TREE_TYPE (inner_parms))
-         continue;
-
-       ntparms = TREE_VEC_LENGTH (inner_parms);
-       for (i = 0; i < ntparms; ++i) 
-         {
-           if (TREE_PURPOSE (TREE_VEC_ELT (inner_parms, i)))
-             {
-               if (!issued_default_arg_message)
-                 {
-                   cp_error ("default argument for template parameter of class enclosing `%D'", 
-                             decl);
-                   issued_default_arg_message = 1;
-                 }
-               TREE_PURPOSE (TREE_VEC_ELT (inner_parms, i)) = NULL_TREE;
-             }
-         }
-      }
-  }
+  if (is_partial)
+    return process_partial_specialization (decl);
 
   args = current_template_args ();
 
@@ -4604,6 +4660,8 @@ instantiate_class_template (type)
            DECL_IN_AGGR_P (r) = 1;
            DECL_EXTERNAL (r) = 1;
            cp_finish_decl (r, DECL_INITIAL (r), NULL_TREE, 0, 0);
+           if (DECL_DEFINED_IN_CLASS_P (r))
+             check_static_variable_definition (r, TREE_TYPE (r));
          }
        
        /* R will have a TREE_CHAIN if and only if it has already been
@@ -6468,7 +6526,7 @@ tsubst_expr (t, args, in_decl)
   return NULL_TREE;
 }
 
-/* Instantiate the indicated variable of function template TMPL with
+/* Instantiate the indicated variable or function template TMPL with
    the template arguments in TARG_PTR.  */
 
 tree
diff --git a/gcc/testsuite/g++.old-deja/g++.pt/defarg6.C b/gcc/testsuite/g++.old-deja/g++.pt/defarg6.C
new file mode 100644 (file)
index 0000000..0094c5c
--- /dev/null
@@ -0,0 +1,27 @@
+// Build don't link:
+
+template <class T>
+struct C {
+  template <class U>
+  void f(U); // OK
+
+  template <class V = int>
+  struct I {}; // OK
+
+  template <class W = int>
+  void h(W); // ERROR - default argument
+  
+  template <class Y>
+  void k(Y);
+};
+
+template <class T>
+template <class U = double>
+void C<T>::f(U) {} // ERROR - default argument
+
+template <class X = void*>
+void g(X); // ERROR - default argument
+
+template <class T = double>
+template <class Y>
+void C<T>::k(Y) {} // ERROR - default argument
diff --git a/gcc/testsuite/g++.old-deja/g++.pt/defarg7.C b/gcc/testsuite/g++.old-deja/g++.pt/defarg7.C
new file mode 100644 (file)
index 0000000..0db043f
--- /dev/null
@@ -0,0 +1,11 @@
+// Build don't link:
+
+template <int Dim, class T, class EngineTag>
+class Engine {};
+
+struct Brick;
+template<int Dim, class T = double , class EngineTag = Brick >
+struct ConstArray {
+  static const int dimensions = Engine<Dim, T, EngineTag>::dimensions;
+};
diff --git a/gcc/testsuite/g++.old-deja/g++.pt/static5.C b/gcc/testsuite/g++.old-deja/g++.pt/static5.C
new file mode 100644 (file)
index 0000000..f6e125d
--- /dev/null
@@ -0,0 +1,9 @@
+// Build don't link:
+
+template <class T>
+struct S
+{
+  static const T t = 3; // ERROR - initializing non-integral type
+};
+
+double d = S<double>::t;