This is the mail archive of the gcc-patches@gcc.gnu.org mailing list for the GCC project.


Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]
Other format: [Raw text]

C++ PATCH: Fix PR c++/16224


This patches fixes PR c++/16224, a regression wherein we crashed on
invalid template specializations.  Tested on i686-pc-linux-gnu,
applied on the mainline and on the 3.4 branch.

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

2004-08-01  Mark Mitchell  <mark@codesourcery.com>

	PR c++/16224
	* name-lookup.c (decl_namespace): Remove.
	(current_decl_namespace): Use decl_namespace_context instead of
	decl_namespace.
	(push_decl_namespace): Likewise.
	(arg_assoc_class): Likewise.
	(arg_assoc_type): Likewise.
	* pt.c (check_specialization_namespace): New function.
	(maybe_process_partial_specialization): Use it.
	(register_specialization): Likewise.

2004-08-01  Mark Mitchell  <mark@codesourcery.com>

	PR c++/16224
	* g++.dg/template/spec17.C: New test.
	* g++.old-deja/g++.ns/template13.C: Remove XFAIL.
	* g++.old-deja/g++.pt/lookup10.C: Add dg-error marker.

Index: cp/name-lookup.c
===================================================================
RCS file: /cvs/gcc/gcc/gcc/cp/name-lookup.c,v
retrieving revision 1.79
diff -c -5 -p -r1.79 name-lookup.c
*** cp/name-lookup.c	25 Jul 2004 17:19:39 -0000	1.79
--- cp/name-lookup.c	2 Aug 2004 06:18:47 -0000
*************** set_namespace_binding (tree name, tree s
*** 2989,3019 ****
    else
      supplement_binding (b, val);
    timevar_pop (TV_NAME_LOOKUP);
  }
  
- /* Compute the namespace where a declaration is defined.  */
- 
- static tree
- decl_namespace (tree decl)
- {
-   timevar_push (TV_NAME_LOOKUP);
-   if (TYPE_P (decl))
-     decl = TYPE_STUB_DECL (decl);
-   while (DECL_CONTEXT (decl))
-     {
-       decl = DECL_CONTEXT (decl);
-       if (TREE_CODE (decl) == NAMESPACE_DECL)
- 	POP_TIMEVAR_AND_RETURN (TV_NAME_LOOKUP, decl);
-       if (TYPE_P (decl))
- 	decl = TYPE_STUB_DECL (decl);
-       my_friendly_assert (DECL_P (decl), 390);
-     }
- 
-   POP_TIMEVAR_AND_RETURN (TV_NAME_LOOKUP, global_namespace);
- }
- 
  /* Set the context of a declaration to scope. Complain if we are not
     outside scope.  */
  
  void
  set_decl_namespace (tree decl, tree scope, bool friendp)
--- 2989,2998 ----
*************** current_decl_namespace (void)
*** 3078,3090 ****
    /* If we have been pushed into a different namespace, use it.  */
    if (decl_namespace_list)
      return TREE_PURPOSE (decl_namespace_list);
  
    if (current_class_type)
!     result = decl_namespace (TYPE_STUB_DECL (current_class_type));
    else if (current_function_decl)
!     result = decl_namespace (current_function_decl);
    else 
      result = current_namespace;
    return result;
  }
  
--- 3057,3069 ----
    /* If we have been pushed into a different namespace, use it.  */
    if (decl_namespace_list)
      return TREE_PURPOSE (decl_namespace_list);
  
    if (current_class_type)
!     result = decl_namespace_context (current_class_type);
    else if (current_function_decl)
!     result = decl_namespace_context (current_function_decl);
    else 
      result = current_namespace;
    return result;
  }
  
*************** pop_nested_namespace (tree ns)
*** 3208,3218 ****
  
  void
  push_decl_namespace (tree decl)
  {
    if (TREE_CODE (decl) != NAMESPACE_DECL)
!     decl = decl_namespace (decl);
    decl_namespace_list = tree_cons (ORIGINAL_NAMESPACE (decl),
                                     NULL_TREE, decl_namespace_list);
  }
  
  /* [namespace.memdef]/2 */
--- 3187,3197 ----
  
  void
  push_decl_namespace (tree decl)
  {
    if (TREE_CODE (decl) != NAMESPACE_DECL)
!     decl = decl_namespace_context (decl);
    decl_namespace_list = tree_cons (ORIGINAL_NAMESPACE (decl),
                                     NULL_TREE, decl_namespace_list);
  }
  
  /* [namespace.memdef]/2 */
*************** arg_assoc_class (struct arg_lookup *k, t
*** 4392,4402 ****
  
    if (purpose_member (type, k->classes))
      return false;
    k->classes = tree_cons (type, NULL_TREE, k->classes);
    
!   context = decl_namespace (TYPE_MAIN_DECL (type));
    if (arg_assoc_namespace (k, context))
      return true;
  
    if (TYPE_BINFO (type))
      {
--- 4371,4381 ----
  
    if (purpose_member (type, k->classes))
      return false;
    k->classes = tree_cons (type, NULL_TREE, k->classes);
    
!   context = decl_namespace_context (type);
    if (arg_assoc_namespace (k, context))
      return true;
  
    if (TYPE_BINFO (type))
      {
*************** arg_assoc_type (struct arg_lookup *k, tr
*** 4481,4491 ****
      case REFERENCE_TYPE:
      case ARRAY_TYPE:
        return arg_assoc_type (k, TREE_TYPE (type));
      case UNION_TYPE:
      case ENUMERAL_TYPE:
!       return arg_assoc_namespace (k, decl_namespace (TYPE_MAIN_DECL (type)));
      case METHOD_TYPE:
        /* The basetype is referenced in the first arg type, so just
  	 fall through.  */
      case FUNCTION_TYPE:
        /* Associate the parameter types.  */
--- 4460,4470 ----
      case REFERENCE_TYPE:
      case ARRAY_TYPE:
        return arg_assoc_type (k, TREE_TYPE (type));
      case UNION_TYPE:
      case ENUMERAL_TYPE:
!       return arg_assoc_namespace (k, decl_namespace_context (type));
      case METHOD_TYPE:
        /* The basetype is referenced in the first arg type, so just
  	 fall through.  */
      case FUNCTION_TYPE:
        /* Associate the parameter types.  */
Index: cp/pt.c
===================================================================
RCS file: /cvs/gcc/gcc/gcc/cp/pt.c,v
retrieving revision 1.899
diff -c -5 -p -r1.899 pt.c
*** cp/pt.c	2 Aug 2004 01:58:50 -0000	1.899
--- cp/pt.c	2 Aug 2004 06:18:48 -0000
*************** end_explicit_instantiation (void)
*** 706,715 ****
--- 706,745 ----
  {
    my_friendly_assert(processing_explicit_instantiation, 20020913);
    processing_explicit_instantiation = false;
  }
  
+ /* A explicit specialization or partial specialization TMPL is being
+    declared.  Check that the namespace in which the specialization is
+    occurring is permissible.  Returns false iff it is invalid to
+    specialize TMPL in the current namespace.  */
+    
+ static bool
+ check_specialization_namespace (tree tmpl)
+ {
+   tree tpl_ns = decl_namespace_context (tmpl);
+ 
+   /* [tmpl.expl.spec]
+      
+      An explicit specialization shall be declared in the namespace of
+      which the template is a member, or, for member templates, in the
+      namespace of which the enclosing class or enclosing class
+      template is a member.  An explicit specialization of a member
+      function, member class or static data member of a class template
+      shall be declared in the namespace of which the class template is
+      a member.  */
+   if (is_associated_namespace (current_namespace, tpl_ns))
+     /* Same or super-using namespace.  */
+     return true;
+   else
+     {
+       pedwarn ("specialization of `%D' in different namespace", tmpl);
+       cp_pedwarn_at ("  from definition of `%#D'", tmpl);
+       return false;
+     }
+ }
+ 
  /* The TYPE is being declared.  If it is a template type, that means it
     is a partial specialization.  Do appropriate error-checking.  */
  
  void 
  maybe_process_partial_specialization (tree type)
*************** maybe_process_partial_specialization (tr
*** 731,749 ****
  	 Make sure that `C<int>' and `C<T*>' are implicit instantiations.  */
  
        if (CLASSTYPE_IMPLICIT_INSTANTIATION (type)
  	  && !COMPLETE_TYPE_P (type))
  	{
! 	  tree tpl_ns = decl_namespace_context (CLASSTYPE_TI_TEMPLATE (type));
! 	  if (is_associated_namespace (current_namespace, tpl_ns))
! 	    /* Same or super-using namespace.  */;
! 	  else
! 	    {
! 	      pedwarn ("specializing `%#T' in different namespace", type);
! 	      cp_pedwarn_at ("  from definition of `%#D'",
! 			     CLASSTYPE_TI_TEMPLATE (type));
! 	    }
  	  SET_CLASSTYPE_TEMPLATE_SPECIALIZATION (type);
  	  if (processing_template_decl)
  	    push_template_decl (TYPE_MAIN_DECL (type));
  	}
        else if (CLASSTYPE_TEMPLATE_INSTANTIATION (type))
--- 761,771 ----
  	 Make sure that `C<int>' and `C<T*>' are implicit instantiations.  */
  
        if (CLASSTYPE_IMPLICIT_INSTANTIATION (type)
  	  && !COMPLETE_TYPE_P (type))
  	{
! 	  check_specialization_namespace (CLASSTYPE_TI_TEMPLATE (type));
  	  SET_CLASSTYPE_TEMPLATE_SPECIALIZATION (type);
  	  if (processing_template_decl)
  	    push_template_decl (TYPE_MAIN_DECL (type));
  	}
        else if (CLASSTYPE_TEMPLATE_INSTANTIATION (type))
*************** register_specialization (tree spec, tree
*** 1055,1122 ****
  	 calls duplicate_decls which will update the specialization
  	 list.  But, we'll still get called again here anyhow.  It's
  	 more convenient to simply allow this than to try to prevent it.  */
        if (fn == spec)
  	return spec;
!       else if (comp_template_args (TREE_PURPOSE (s), args))
  	{
! 	  if (DECL_TEMPLATE_SPECIALIZATION (spec))
  	    {
! 	      if (DECL_TEMPLATE_INSTANTIATION (fn))
  		{
! 		  if (TREE_USED (fn) 
! 		      || DECL_EXPLICIT_INSTANTIATION (fn))
! 		    {
! 		      error ("specialization of %D after instantiation",
! 				fn);
! 		      return spec;
! 		    }
! 		  else
! 		    {
! 		      /* This situation should occur only if the first
! 			 specialization is an implicit instantiation,
! 			 the second is an explicit specialization, and
! 			 the implicit instantiation has not yet been
! 			 used.  That situation can occur if we have
! 			 implicitly instantiated a member function and
! 			 then specialized it later.
! 
! 			 We can also wind up here if a friend
! 			 declaration that looked like an instantiation
! 			 turns out to be a specialization:
! 
! 			   template <class T> void foo(T);
! 			   class S { friend void foo<>(int) };
! 			   template <> void foo(int);  
! 
! 			 We transform the existing DECL in place so that
! 			 any pointers to it become pointers to the
! 			 updated declaration.  
! 
! 			 If there was a definition for the template, but
! 			 not for the specialization, we want this to
! 			 look as if there were no definition, and vice
! 			 versa.  */
! 		      DECL_INITIAL (fn) = NULL_TREE;
! 		      duplicate_decls (spec, fn);
! 
! 		      return fn;
! 		    }
  		}
! 	      else if (DECL_TEMPLATE_SPECIALIZATION (fn))
  		{
! 		  if (!duplicate_decls (spec, fn) && DECL_INITIAL (spec))
! 		    /* Dup decl failed, but this is a new
! 		       definition. Set the line number so any errors
! 		       match this new definition.  */
! 		    DECL_SOURCE_LOCATION (fn) = DECL_SOURCE_LOCATION (spec);
  		  
  		  return fn;
  		}
  	    }
  	}
!       }
  
    DECL_TEMPLATE_SPECIALIZATIONS (tmpl)
       = tree_cons (args, spec, DECL_TEMPLATE_SPECIALIZATIONS (tmpl));
  
    return spec;
--- 1077,1148 ----
  	 calls duplicate_decls which will update the specialization
  	 list.  But, we'll still get called again here anyhow.  It's
  	 more convenient to simply allow this than to try to prevent it.  */
        if (fn == spec)
  	return spec;
!       else if (comp_template_args (TREE_PURPOSE (s), args)
! 	       && DECL_TEMPLATE_SPECIALIZATION (spec))
  	{
! 	  if (DECL_TEMPLATE_INSTANTIATION (fn))
  	    {
! 	      if (TREE_USED (fn) 
! 		  || DECL_EXPLICIT_INSTANTIATION (fn))
  		{
! 		  error ("specialization of %D after instantiation",
! 			 fn);
! 		  return spec;
  		}
! 	      else
  		{
! 		  /* This situation should occur only if the first
! 		     specialization is an implicit instantiation, the
! 		     second is an explicit specialization, and the
! 		     implicit instantiation has not yet been used.
! 		     That situation can occur if we have implicitly
! 		     instantiated a member function and then
! 		     specialized it later.
! 
! 		     We can also wind up here if a friend declaration
! 		     that looked like an instantiation turns out to be
! 		     a specialization:
! 
! 		       template <class T> void foo(T);
! 		       class S { friend void foo<>(int) };
! 		       template <> void foo(int);  
! 
! 		     We transform the existing DECL in place so that
! 		     any pointers to it become pointers to the updated
! 		     declaration.
! 
! 		     If there was a definition for the template, but
! 		     not for the specialization, we want this to look
! 		     as if there were no definition, and vice
! 		     versa.  */
! 		  DECL_INITIAL (fn) = NULL_TREE;
! 		  duplicate_decls (spec, fn);
  		  
  		  return fn;
  		}
  	    }
+ 	  else if (DECL_TEMPLATE_SPECIALIZATION (fn))
+ 	    {
+ 	      if (!duplicate_decls (spec, fn) && DECL_INITIAL (spec))
+ 		/* Dup decl failed, but this is a new definition. Set
+ 		   the line number so any errors match this new
+ 		   definition.  */
+ 		DECL_SOURCE_LOCATION (fn) = DECL_SOURCE_LOCATION (spec);
+ 	      
+ 	      return fn;
+ 	    }
  	}
!     }
! 
!   /* A specialization must be declared in the same namespace as the
!      template it is specializing.  */
!   if (DECL_TEMPLATE_SPECIALIZATION (spec)
!       && !check_specialization_namespace (tmpl))
!     DECL_CONTEXT (spec) = decl_namespace_context (tmpl);
  
    DECL_TEMPLATE_SPECIALIZATIONS (tmpl)
       = tree_cons (args, spec, DECL_TEMPLATE_SPECIALIZATIONS (tmpl));
  
    return spec;
Index: testsuite/g++.dg/template/spec17.C
===================================================================
RCS file: testsuite/g++.dg/template/spec17.C
diff -N testsuite/g++.dg/template/spec17.C
*** /dev/null	1 Jan 1970 00:00:00 -0000
--- testsuite/g++.dg/template/spec17.C	2 Aug 2004 05:55:37 -0000
***************
*** 0 ****
--- 1,11 ----
+ // PR c++/16224
+ 
+ namespace io { 
+   template <typename> int foo(); // { dg-error "" }
+ } 
+  
+ using namespace io; 
+  
+ template<> int foo<int>(); // { dg-error "" }
+  
+ int a = foo<int>(); 
Index: testsuite/g++.old-deja/g++.ns/template13.C
===================================================================
RCS file: /cvs/gcc/gcc/gcc/testsuite/g++.old-deja/g++.ns/template13.C,v
retrieving revision 1.6
diff -c -5 -p -r1.6 template13.C
*** testsuite/g++.old-deja/g++.ns/template13.C	1 May 2003 02:02:47 -0000	1.6
--- testsuite/g++.old-deja/g++.ns/template13.C	2 Aug 2004 05:55:37 -0000
***************
*** 1,11 ****
  // { dg-do assemble { xfail *-*-* } }
  // Templates defined outside must be declared inside
  namespace bar
  {
    template<class T>
!   void foo(); // trick it to provide some prior declaration
    template<class T>class X; // { dg-error "" } previous declaration
  }
  
  template <typename T>
  T const
--- 1,12 ----
  // { dg-do assemble { xfail *-*-* } }
  // Templates defined outside must be declared inside
  namespace bar
  {
+   // trick it to provide some prior declaration
    template<class T>
!   void foo(); // { dg-error "definition" }
    template<class T>class X; // { dg-error "" } previous declaration
  }
  
  template <typename T>
  T const
*************** bar::foo(T const &a)    
*** 13,22 ****
  {                        // { dg-error "" "" { xfail *-*-* } } not declared in bar - 
    return a;
  }
  
  template<> void bar::foo<int>()
! {                        // { dg-error "" "" { xfail *-*-* } } not declared in bar - 
  }
  
  template<class T,class U>
  class bar::X{};         // { dg-error "" } does not match declaration
--- 14,23 ----
  {                        // { dg-error "" "" { xfail *-*-* } } not declared in bar - 
    return a;
  }
  
  template<> void bar::foo<int>()
! {                        // { dg-error "" }
  }
  
  template<class T,class U>
  class bar::X{};         // { dg-error "" } does not match declaration
Index: testsuite/g++.old-deja/g++.pt/lookup10.C
===================================================================
RCS file: /cvs/gcc/gcc/gcc/testsuite/g++.old-deja/g++.pt/lookup10.C,v
retrieving revision 1.2
diff -c -5 -p -r1.2 lookup10.C
*** testsuite/g++.old-deja/g++.pt/lookup10.C	1 May 2003 02:02:54 -0000	1.2
--- testsuite/g++.old-deja/g++.pt/lookup10.C	2 Aug 2004 05:55:37 -0000
*************** namespace Outer {
*** 11,20 ****
  
    namespace Core_Real {}  
    namespace Core = Core_Real;
  
    namespace Core_Real {
!     template<class T> void Foo (T *) {}
    }
  
!   template<> void Core::Foo<> (Render_Real::Type *) {}
  }  
--- 11,20 ----
  
    namespace Core_Real {}  
    namespace Core = Core_Real;
  
    namespace Core_Real {
!     template<class T> void Foo (T *) {} // { dg-error "definition" }
    }
  
!   template<> void Core::Foo<> (Render_Real::Type *) {} // { dg-error "" }
  }  


Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]