PR c++/23099
authormmitchel <mmitchel@138bc75d-0d04-0410-961f-82ee72b054a4>
Mon, 29 Aug 2005 14:08:50 +0000 (14:08 +0000)
committermmitchel <mmitchel@138bc75d-0d04-0410-961f-82ee72b054a4>
Mon, 29 Aug 2005 14:08:50 +0000 (14:08 +0000)
* cp-tree.h (saved_scope): Add skip_evaluation.
* decl.c (start_decl): Use DECL_INITIALIZED_IN_CLASS_P, not
DECL_INITIAL, to determine whether or not a static data member was
initialized in the class-specifier.
(cp_finish_decl): Add comment.
* init.c (integral_constant_value): Subtitute into the
initializers for static data members in templates.
* name-lookup.c (push_to_top_level): Save skip_evaluation.
(pop_from_top_level): Restore it.
* pt.c (instantiate_class_template): Do not substitute into the
intializers of static data members when instantiating a class.
(regenerate_decl_from_template): Simplify.
(instantiate_decl): Tidy.  Substitute into the initializer for a
static data member even when the definition of the data member is
not available.

PR c++/23099
* g++.dg/init/member1.C: Make sure erroneous static data member
definitions are required.
* g++.dg/template/static13.C: New test.
* g++.dg/template/static14.C: Likewise.

git-svn-id: svn+ssh://gcc.gnu.org/svn/gcc/trunk@103604 138bc75d-0d04-0410-961f-82ee72b054a4

gcc/cp/ChangeLog
gcc/cp/cp-tree.h
gcc/cp/decl.c
gcc/cp/init.c
gcc/cp/name-lookup.c
gcc/cp/pt.c
gcc/testsuite/ChangeLog
gcc/testsuite/g++.dg/init/member1.C
gcc/testsuite/g++.dg/template/static13.C [new file with mode: 0644]
gcc/testsuite/g++.dg/template/static14.C [new file with mode: 0644]

index 4c2c72e..4051336 100644 (file)
@@ -1,3 +1,22 @@
+2005-08-28  Mark Mitchell  <mark@codesourcery.com>
+
+       PR c++/23099
+       * cp-tree.h (saved_scope): Add skip_evaluation.
+       * decl.c (start_decl): Use DECL_INITIALIZED_IN_CLASS_P, not
+       DECL_INITIAL, to determine whether or not a static data member was
+       initialized in the class-specifier.
+       (cp_finish_decl): Add comment.
+       * init.c (integral_constant_value): Subtitute into the
+       initializers for static data members in templates.
+       * name-lookup.c (push_to_top_level): Save skip_evaluation.
+       (pop_from_top_level): Restore it.
+       * pt.c (instantiate_class_template): Do not substitute into the
+       intializers of static data members when instantiating a class.
+       (regenerate_decl_from_template): Simplify.
+       (instantiate_decl): Tidy.  Substitute into the initializer for a
+       static data member even when the definition of the data member is
+       not available.
+
 2005-08-26  Mark Mitchell  <mark@codesourcery.com>
 
        PR c++/19004
index 17e074d..e8d5fe7 100644 (file)
@@ -655,6 +655,7 @@ struct saved_scope GTY(())
   int x_processing_specialization;
   bool x_processing_explicit_instantiation;
   int need_pop_function_context;
+  bool skip_evaluation;
 
   struct stmt_tree_s x_stmt_tree;
 
index 4199b24..a32be09 100644 (file)
@@ -3716,7 +3716,8 @@ start_decl (const cp_declarator *declarator,
                 declaration will have DECL_EXTERNAL set, but will have an
                 initialization.  Thus, duplicate_decls won't warn
                 about this situation, and so we check here.  */
-             if (DECL_INITIAL (decl) && DECL_INITIAL (field))
+             if (DECL_INITIAL (decl) 
+                 && DECL_INITIALIZED_IN_CLASS_P (field))
                error ("duplicate initialization of %qD", decl);
              if (duplicate_decls (decl, field))
                decl = field;
@@ -4921,10 +4922,20 @@ cp_finish_decl (tree decl, tree init, tree asmspec_tree, int flags)
                     "initialized", decl);
              init = NULL_TREE;
            }
+
+         /* Check that the initializer for a static data member was a
+            constant.  Althouh we check in the parser that the
+            initializer is an integral constant expression, we do not
+            simplify division-by-zero at the point at which it
+            occurs.  Therefore, in:
+
+              struct S { static const int i = 7 / 0; };
+              
+            we issue an error at this point.  It would
+            probably be better to forbid division by zero in
+            integral constant expressions.  */
          if (DECL_EXTERNAL (decl) && init)
            {
-             /* The static data member cannot be initialized by a
-                non-constant when being declared.  */
              error ("%qD cannot be initialized by a non-constant expression"
                     " when being declared", decl);
              DECL_INITIALIZED_IN_CLASS_P (decl) = 0;
index 690e35f..8a8dc78 100644 (file)
@@ -1572,12 +1572,25 @@ integral_constant_value (tree decl)
              /* And so are variables with a 'const' type -- unless they
                 are also 'volatile'.  */
              && CP_TYPE_CONST_NON_VOLATILE_P (TREE_TYPE (decl))
-             && DECL_INITIALIZED_BY_CONSTANT_EXPRESSION_P (decl)))
-        && DECL_INITIAL (decl)
-        && DECL_INITIAL (decl) != error_mark_node
-        && TREE_TYPE (DECL_INITIAL (decl))
-        && INTEGRAL_OR_ENUMERATION_TYPE_P (TREE_TYPE (DECL_INITIAL (decl))))
-    decl = DECL_INITIAL (decl);
+             && DECL_INITIALIZED_BY_CONSTANT_EXPRESSION_P (decl))))
+    {
+      tree init;
+      /* If DECL is a static data member in a template class, we must
+        instantiate it here.  The initializer for the static data
+        member is not processed until needed; we need it now.  */ 
+      mark_used (decl);
+      init = DECL_INITIAL (decl);
+      /* If we are currently processing a template, the
+        initializer for a static data member may not be dependent,
+        but it is not folded until instantiation time.  */
+      if (init)
+       init = fold_non_dependent_expr (init);
+      if (!(init || init == error_mark_node)
+         || !TREE_TYPE (init)
+         || !INTEGRAL_OR_ENUMERATION_TYPE_P (TREE_TYPE (init)))
+       break;
+      decl = init;
+    }
   return decl;
 }
 
index 2beb3e7..7270a9d 100644 (file)
@@ -4872,12 +4872,14 @@ push_to_top_level (void)
   s->bindings = b;
   s->need_pop_function_context = need_pop;
   s->function_decl = current_function_decl;
+  s->skip_evaluation = skip_evaluation;
 
   scope_chain = s;
   current_function_decl = NULL_TREE;
   current_lang_base = VEC_alloc (tree, gc, 10);
   current_lang_name = lang_name_cplusplus;
   current_namespace = global_namespace;
+  skip_evaluation = 0;
   timevar_pop (TV_NAME_LOOKUP);
 }
 
@@ -4909,6 +4911,7 @@ pop_from_top_level (void)
   if (s->need_pop_function_context)
     pop_function_context_from (NULL_TREE);
   current_function_decl = s->function_decl;
+  skip_evaluation = s->skip_evaluation;
   timevar_pop (TV_NAME_LOOKUP);
 }
 
index 386dc2f..773d865 100644 (file)
@@ -5699,17 +5699,22 @@ instantiate_class_template (tree type)
                    --processing_template_decl;
                  if (TREE_CODE (r) == VAR_DECL)
                    {
-                     tree init;
-
-                     if (DECL_INITIALIZED_IN_CLASS_P (r))
-                       init = tsubst_expr (DECL_INITIAL (t), args,
-                                           tf_error | tf_warning, NULL_TREE);
-                     else
-                       init = NULL_TREE;
-
-                     finish_static_data_member_decl
-                       (r, init, /*asmspec_tree=*/NULL_TREE, /*flags=*/0);
-
+                     /* In [temp.inst]:
+
+                          [t]he initialization (and any associated
+                          side-effects) of a static data member does
+                          not occur unless the static data member is
+                          itself used in a way that requires the
+                          definition of the static data member to
+                          exist.  
+
+                        Therefore, we do not substitute into the
+                        initialized for the static data member here.  */
+                     finish_static_data_member_decl 
+                       (r, 
+                        /*init=*/NULL_TREE, 
+                        /*asmspec_tree=*/NULL_TREE, 
+                        /*flags=*/0);
                      if (DECL_INITIALIZED_IN_CLASS_P (r))
                        check_static_variable_definition (r, TREE_TYPE (r));
                    }
@@ -11278,13 +11283,9 @@ regenerate_decl_from_template (tree decl, tree tmpl)
        DECL_INLINE (decl) = 1;
     }
   else if (TREE_CODE (decl) == VAR_DECL)
-    {
-      if (!DECL_INITIALIZED_IN_CLASS_P (decl)
-         && DECL_INITIAL (code_pattern))
-       DECL_INITIAL (decl) =
-         tsubst_expr (DECL_INITIAL (code_pattern), args,
-                      tf_error, DECL_TI_TEMPLATE (decl));
-    }
+    DECL_INITIAL (decl) =
+      tsubst_expr (DECL_INITIAL (code_pattern), args,
+                  tf_error, DECL_TI_TEMPLATE (decl));
   else
     gcc_unreachable ();
 
@@ -11367,7 +11368,7 @@ instantiate_decl (tree d, int defer_ok,
   tree code_pattern;
   tree spec;
   tree gen_tmpl;
-  int pattern_defined;
+  bool pattern_defined;
   int need_push;
   location_t saved_loc = input_location;
 
@@ -11415,9 +11416,6 @@ instantiate_decl (tree d, int defer_ok,
 
   timevar_push (TV_PARSE);
 
-  /* We may be in the middle of deferred access check.  Disable it now.  */
-  push_deferring_access_checks (dk_no_deferred);
-
   /* Set TD to the template whose DECL_TEMPLATE_RESULT is the pattern
      for the instantiation.  */
   td = template_for_substitution (d);
@@ -11437,6 +11435,10 @@ instantiate_decl (tree d, int defer_ok,
     pattern_defined = (DECL_SAVED_TREE (code_pattern) != NULL_TREE);
   else
     pattern_defined = ! DECL_IN_AGGR_P (code_pattern);
+
+  /* We may be in the middle of deferred access check.  Disable it now.  */
+  push_deferring_access_checks (dk_no_deferred);
+
   /* Unless an explicit instantiation directive has already determined
      the linkage of D, remember that a definition is available for
      this entity.  */
@@ -11486,12 +11488,6 @@ instantiate_decl (tree d, int defer_ok,
       pop_access_scope (d);
     }
 
-  /* We should have set up DECL_INITIAL in instantiate_class_template
-     for in-class definitions of static data members.  */
-  gcc_assert (!(TREE_CODE (d) == VAR_DECL
-               && DECL_INITIALIZED_IN_CLASS_P (d)
-               && DECL_INITIAL (d) == NULL_TREE));
-
   /* Do not instantiate templates that we know will be defined
      elsewhere.  */
   if (DECL_INTERFACE_KNOWN (d)
@@ -11504,6 +11500,20 @@ instantiate_decl (tree d, int defer_ok,
      because it's used by add_pending_template.  */
   else if (! pattern_defined || defer_ok)
     {
+      /* The definition of the static data member is now required so
+        we must substitute the initializer.  */
+      if (TREE_CODE (d) == VAR_DECL
+         && !DECL_INITIAL (d) 
+         && DECL_INITIAL (code_pattern))
+       {
+         push_nested_class (DECL_CONTEXT (d));
+         DECL_INITIAL (d)
+           = tsubst_expr (DECL_INITIAL (code_pattern), 
+                          args,
+                          tf_error | tf_warning, NULL_TREE);
+         pop_nested_class ();
+       }
+
       input_location = saved_loc;
 
       if (at_eof && !pattern_defined
@@ -11570,10 +11580,7 @@ instantiate_decl (tree d, int defer_ok,
 
       /* Enter the scope of D so that access-checking works correctly.  */
       push_nested_class (DECL_CONTEXT (d));
-      cp_finish_decl (d,
-                     (!DECL_INITIALIZED_IN_CLASS_P (d)
-                      ? DECL_INITIAL (d) : NULL_TREE),
-                     NULL_TREE, 0);
+      cp_finish_decl (d, DECL_INITIAL (d), NULL_TREE, 0);
       pop_nested_class ();
     }
   else if (TREE_CODE (d) == FUNCTION_DECL)
index 229e55b..c896f32 100644 (file)
@@ -1,3 +1,11 @@
+2005-08-28  Mark Mitchell  <mark@codesourcery.com>
+
+       PR c++/23099
+       * g++.dg/init/member1.C: Make sure erroneous static data member
+       definitions are required.
+       * g++.dg/template/static13.C: New test.
+       * g++.dg/template/static14.C: Likewise.
+
 2005-08-29  Jakub Jelinek  <jakub@redhat.com>
 
        * gcc.target/i386/pr23575.c: Use -msse2 instead of
index 1c89d5a..aededf2 100644 (file)
@@ -11,8 +11,11 @@ template<int> struct B {};
 template<typename T> struct C
 {
   static const int i = A<T>::i;  // { dg-error "incomplete" }
-  static const int j = i;      // { dg-error "initialized by a non-const" }
+  static const int j = i;
   B<j> b;  // { dg-error "not a valid template arg" }
 };
 
 C<int> c;
+
+int i = C<int>::i;
+int j = C<int>::j;
diff --git a/gcc/testsuite/g++.dg/template/static13.C b/gcc/testsuite/g++.dg/template/static13.C
new file mode 100644 (file)
index 0000000..c43f555
--- /dev/null
@@ -0,0 +1,14 @@
+// PR c++/23099
+
+struct Base {
+  int x;
+};
+
+template <typename T>
+struct A {
+  static const int N = sizeof(static_cast<Base*>(T()));
+};
+
+struct Derived : Base {
+  A<Derived*> a;
+};
diff --git a/gcc/testsuite/g++.dg/template/static14.C b/gcc/testsuite/g++.dg/template/static14.C
new file mode 100644 (file)
index 0000000..5bc0e73
--- /dev/null
@@ -0,0 +1,13 @@
+struct Base {
+  int x;
+};
+
+template <typename T>
+struct A {
+  static const int N = sizeof(static_cast<Base*>(T()));
+  int a[N];
+};
+
+struct Derived : Base {
+  A<Derived*> a;
+};