public inbox for gcc-patches@gcc.gnu.org
 help / color / mirror / Atom feed
* C++ PATCH: PR 24389
@ 2005-10-16 23:30 Mark Mitchell
  2005-10-17 16:21 ` Gabriel Dos Reis
  0 siblings, 1 reply; 2+ messages in thread
From: Mark Mitchell @ 2005-10-16 23:30 UTC (permalink / raw)
  To: gcc-patches


This patch fixes PR c++/24389, which was (yet more) fallout from the
static data member patch.  The problem here was not, as stated in the
PR, that we were giving X<0>::n_primes non-weak linkage, but rather
that we are emitting a definition for X<I>::n_primes, where I was a
non-type template parameter!  

The cause was that the C++ standard, in its infinite wisdom, makes a
non-static data member in a class template non-dependent within the
scope of that template, so that, for example:

   template <typename T>
   struct S {  
     static const int I = 7; // I is not value-dependent within S<T>
     void f() { 
       A<I>::type t; // No "typename" keyword required; this is A<7>. 
     }
   };

As a result, we must play funny games with non-static data members,
even though we generally never evaluate expressions within
uninstantiated templates.  In particular, within integral constant
expressions, we must fold non-dependent expressions.

Tested on x86_64-unknown-linux-gnu, applied on the mainline and on the
4.0 branch.

--
Mark Mitchell
CodeSourcery, LLC
mark@codesourcery.com

2005-10-16  Mark Mitchell  <mark@codesourcery.com>

	PR c++/24389
	* decl2.c (mark_used): Use uses_template_parms instead of
	dependent_type_p.
	* init.c (constant_value_1): Handle uninstantiated templates
	specially.
	* pt.c (instantiate_decl): Add sanity check.

2005-10-16  Mark Mitchell  <mark@codesourcery.com>

	PR c++/24389
	* g++.dg/template/static21.C: New test.
	* g++.dg/template/static21-a.cc: Likewise.

Index: gcc/testsuite/g++.dg/template/static21.C
===================================================================
RCS file: gcc/testsuite/g++.dg/template/static21.C
diff -N gcc/testsuite/g++.dg/template/static21.C
*** /dev/null	1 Jan 1970 00:00:00 -0000
--- gcc/testsuite/g++.dg/template/static21.C	16 Oct 2005 21:36:44 -0000
***************
*** 0 ****
--- 1,20 ----
+ // PR c++/24389
+ // { dg-additional-sources "static21-a.cc" }
+ // { dg-do link }
+ 
+ template<int dummy>
+ struct X
+ {
+   static const int n_primes = 256;
+   static const unsigned long primes[n_primes + 1];
+ };
+ 
+ template<int dummy>
+ const int X<dummy>::n_primes;
+ 
+ template<int dummy>
+ const unsigned long X<dummy>::primes[n_primes + 1] =
+   { 0 };
+ 
+ const unsigned long  *f(void){return &X<0>::primes[0];}
+ 
Index: gcc/testsuite/g++.dg/template/static21-a.cc
===================================================================
RCS file: gcc/testsuite/g++.dg/template/static21-a.cc
diff -N gcc/testsuite/g++.dg/template/static21-a.cc
*** /dev/null	1 Jan 1970 00:00:00 -0000
--- gcc/testsuite/g++.dg/template/static21-a.cc	16 Oct 2005 21:36:44 -0000
***************
*** 0 ****
--- 1,17 ----
+ template<int dummy>
+     struct X
+     {
+       static const int n_primes = 256;
+       static const unsigned long primes[n_primes + 1];
+     };
+ 
+   template<int dummy>
+   const int X<dummy>::n_primes;
+ 
+   template<int dummy>
+   const unsigned long X<dummy>::primes[n_primes + 1] =
+     { 0 };
+ 
+ 
+ const unsigned long  *f1(void){return &X<0>::primes[0];}
+ int main(){}
Index: gcc/cp/decl2.c
===================================================================
RCS file: /cvs/gcc/gcc/gcc/cp/decl2.c,v
retrieving revision 1.770.2.10
diff -c -5 -p -r1.770.2.10 decl2.c
*** gcc/cp/decl2.c	7 Oct 2005 10:54:09 -0000	1.770.2.10
--- gcc/cp/decl2.c	16 Oct 2005 21:36:44 -0000
*************** mark_used (tree decl)
*** 3208,3233 ****
      return;
    /* Normally, we can wait until instantiation-time to synthesize
       DECL.  However, if DECL is a static data member initialized with
       a constant, we need the value right now because a reference to
       such a data member is not value-dependent.  */
!   if (processing_template_decl)
      {
!       if (TREE_CODE (decl) == VAR_DECL
! 	  && DECL_INITIALIZED_BY_CONSTANT_EXPRESSION_P (decl)
! 	  && DECL_CLASS_SCOPE_P (decl)
! 	  && !dependent_type_p (DECL_CONTEXT (decl)))
! 	{
! 	  /* Pretend that we are not in a template so that the
! 	     initializer for the static data member will be full
! 	     simplified.  */
! 	  saved_processing_template_decl = processing_template_decl;
! 	  processing_template_decl = 0;
! 	}
!       else
! 	return;  
      }
  
    if (TREE_CODE (decl) == FUNCTION_DECL && DECL_DECLARED_INLINE_P (decl)
        && !TREE_ASM_WRITTEN (decl))
      /* Remember it, so we can check it was defined.  */
      {
--- 3208,3237 ----
      return;
    /* Normally, we can wait until instantiation-time to synthesize
       DECL.  However, if DECL is a static data member initialized with
       a constant, we need the value right now because a reference to
       such a data member is not value-dependent.  */
!   if (TREE_CODE (decl) == VAR_DECL
!       && DECL_INITIALIZED_BY_CONSTANT_EXPRESSION_P (decl)
!       && DECL_CLASS_SCOPE_P (decl))
      {
!       /* Don't try to instantiate members of dependent types.  We
! 	 cannot just use dependent_type_p here because this function
! 	 may be called from fold_non_dependent_expr, and then we may
! 	 see dependent types, even though processing_template_decl
! 	 will not be set.  */
!       if (CLASSTYPE_TEMPLATE_INFO ((DECL_CONTEXT (decl)))
! 	  && uses_template_parms (CLASSTYPE_TI_ARGS (DECL_CONTEXT (decl))))
! 	return;
!       /* Pretend that we are not in a template, even if we are, so
! 	 that the static data member initializer will be processed.  */
!       saved_processing_template_decl = processing_template_decl;
!       processing_template_decl = 0;
      }
+   
+   if (processing_template_decl)
+     return;  
  
    if (TREE_CODE (decl) == FUNCTION_DECL && DECL_DECLARED_INLINE_P (decl)
        && !TREE_ASM_WRITTEN (decl))
      /* Remember it, so we can check it was defined.  */
      {
Index: gcc/cp/init.c
===================================================================
RCS file: /cvs/gcc/gcc/gcc/cp/init.c,v
retrieving revision 1.412.2.11
diff -c -5 -p -r1.412.2.11 init.c
*** gcc/cp/init.c	11 Oct 2005 20:59:50 -0000	1.412.2.11
--- gcc/cp/init.c	16 Oct 2005 21:36:45 -0000
*************** constant_value_1 (tree decl, bool integr
*** 1572,1591 ****
  	     ? DECL_INTEGRAL_CONSTANT_VAR_P (decl)
  	     : (TREE_CODE (decl) == VAR_DECL
  		&& CP_TYPE_CONST_NON_VOLATILE_P (TREE_TYPE (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_p
  	      ? !INTEGRAL_OR_ENUMERATION_TYPE_P (TREE_TYPE (init))
  	      : (!TREE_CONSTANT (init)
--- 1572,1602 ----
  	     ? DECL_INTEGRAL_CONSTANT_VAR_P (decl)
  	     : (TREE_CODE (decl) == VAR_DECL
  		&& CP_TYPE_CONST_NON_VOLATILE_P (TREE_TYPE (decl)))))
      {
        tree init;
!       /* Static data members in template classes may have
! 	 non-dependent initializers.  References to such non-static
! 	 data members are no value-dependent, so we must retrieve the
! 	 initializer here.  The DECL_INITIAL will have the right type,
! 	 but will not have been folded because that would prevent us
! 	 from performing all appropriate semantic checks at
! 	 instantiation time.  */
!       if (DECL_CLASS_SCOPE_P (decl)
! 	  && CLASSTYPE_TEMPLATE_INFO (DECL_CONTEXT (decl))
! 	  && uses_template_parms (CLASSTYPE_TI_ARGS 
! 				  (DECL_CONTEXT (decl))))
! 	init = fold_non_dependent_expr (DECL_INITIAL (decl));
!       else
! 	{
! 	  /* If DECL is a static data member in a template
! 	     specialization, 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 (!(init || init == error_mark_node)
  	  || !TREE_TYPE (init)
  	  || (integral_p
  	      ? !INTEGRAL_OR_ENUMERATION_TYPE_P (TREE_TYPE (init))
  	      : (!TREE_CONSTANT (init)
Index: gcc/cp/pt.c
===================================================================
RCS file: /cvs/gcc/gcc/gcc/cp/pt.c,v
retrieving revision 1.978.2.32
diff -c -5 -p -r1.978.2.32 pt.c
*** gcc/cp/pt.c	13 Oct 2005 08:36:37 -0000	1.978.2.32
--- gcc/cp/pt.c	16 Oct 2005 21:36:47 -0000
*************** instantiate_decl (tree d, int defer_ok, 
*** 11449,11458 ****
--- 11449,11462 ----
    /* Set TD to the template whose DECL_TEMPLATE_RESULT is the pattern
       for the instantiation.  */
    td = template_for_substitution (d);
    code_pattern = DECL_TEMPLATE_RESULT (td);
  
+   /* We should never be trying to instantiate a member of a class
+      template or partial specialization.  */ 
+   gcc_assert (d != code_pattern);
+  
    if ((DECL_NAMESPACE_SCOPE_P (d) && !DECL_INITIALIZED_IN_CLASS_P (d))
        || DECL_TEMPLATE_SPECIALIZATION (td))
      /* In the case of a friend template whose definition is provided
         outside the class, we may have too many arguments.  Drop the
         ones we don't need.  The same is true for specializations.  */

 



^ permalink raw reply	[flat|nested] 2+ messages in thread

* Re: C++ PATCH: PR 24389
  2005-10-16 23:30 C++ PATCH: PR 24389 Mark Mitchell
@ 2005-10-17 16:21 ` Gabriel Dos Reis
  0 siblings, 0 replies; 2+ messages in thread
From: Gabriel Dos Reis @ 2005-10-17 16:21 UTC (permalink / raw)
  To: mark; +Cc: gcc-patches

Mark Mitchell <mark@codesourcery.com> writes:

| This patch fixes PR c++/24389, which was (yet more) fallout from the
| static data member patch.  The problem here was not, as stated in the
| PR, that we were giving X<0>::n_primes non-weak linkage, but rather
| that we are emitting a definition for X<I>::n_primes, where I was a
| non-type template parameter!  
| 
| The cause was that the C++ standard, in its infinite wisdom, makes a
| non-static data member in a class template non-dependent within the
| scope of that template, so that, for example:
| 
|    template <typename T>
|    struct S {  
|      static const int I = 7; // I is not value-dependent within S<T>
|      void f() { 
|        A<I>::type t; // No "typename" keyword required; this is A<7>. 
|      }
|    };
| 
| As a result, we must play funny games with non-static data members,
| even though we generally never evaluate expressions within
| uninstantiated templates.  In particular, within integral constant
| expressions, we must fold non-dependent expressions.

That was new in C++03, compared to C++98, in search of rule optimizations
in small.  I'm glad we share similar appreciationsof list of special rules
and optimization in small ;-)

-- Gaby

^ permalink raw reply	[flat|nested] 2+ messages in thread

end of thread, other threads:[~2005-10-17 16:21 UTC | newest]

Thread overview: 2+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2005-10-16 23:30 C++ PATCH: PR 24389 Mark Mitchell
2005-10-17 16:21 ` Gabriel Dos Reis

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for read-only IMAP folder(s) and NNTP newsgroup(s).