This is the mail archive of the libstdc++@gcc.gnu.org mailing list for the libstdc++ 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: PR 13140


This patch tightens up error checking in G++.  In particular, we now
catch cases where a member is defined in a namespace that does not
enclose the class in whch it was declared, or cases where a template
is explicitly instantiated in a namespace that does not enclose the
namespace where it was declared, and we catch an explicit
specialization case that we didn't catch before. 

I'm planning to apply this to 4.1 (it's not a regression).  However,
this patch did catch a bug in the libstdc++ testsuite_character.h
file (see below), so I'm going to wait 24 hours before check-in, in
case the libstdc++ people object. 

Tested on x86_64-unknown-linux-gnu.

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

2005-09-15  Mark Mitchell  <mark@codesourcery.com>

	PR c++/13140
	* decl.c (check_class_member_definition_namespace): New function.
	(grokfndecl): Use it.
	(grokvardecl): Likewise.
	(grokdecl): Improve documentation.
	* pt.c (check_explicit_instantiation_namespace): New function.
	(register_specialization): Call check_specialization_namespace
	when replacing an implicitly instantiated function.
	(check_explicit_specialization): Ensure that DECL_CONTEXT is set
	correctly for namespace-scope specializations.
	(do_decl_instantiation): Use
	check_explicit_instantiation_namespace.
	(do_type_instantiation): Likewise.

2005-09-15  Mark Mitchell  <mark@codesourcery.com>

	PR c++/13140
	* g++.dg/parse/class2.C: New test.
	* g++.dg/template/explicit8.C: Likewise.
	* g++.dg/template/spec25.C: Likewise.

2005-09-15  Mark Mitchell  <mark@codesourcery.com>

	* testsuite/testsuite_character.h: Specialize character<>
	templates in __gnu_cxx, not in __gnu_test.

Index: gcc/cp/decl.c
===================================================================
RCS file: /cvs/gcc/gcc/gcc/cp/decl.c,v
retrieving revision 1.1426
diff -c -5 -p -r1.1426 decl.c
*** gcc/cp/decl.c	12 Sep 2005 19:53:59 -0000	1.1426
--- gcc/cp/decl.c	15 Sep 2005 09:45:02 -0000
*************** bad_specifiers (tree object,
*** 5582,5591 ****
--- 5582,5626 ----
  	      && !TYPE_REFFN_P (TREE_TYPE (object))
  	      && !TYPE_PTRMEMFUNC_P (TREE_TYPE (object)))))
      error ("%q+D declared with an exception specification", object);
  }
  
+ /* DECL is a member function or static data member and is presently
+    being defined.  Check that the definition is taking place in a
+    valid namespace.  */
+ 
+ static void
+ check_class_member_definition_namespace (tree decl)
+ {
+   /* These checks only apply to member functions and static data
+      members.  */
+   gcc_assert (TREE_CODE (decl) == FUNCTION_DECL
+ 	      || TREE_CODE (decl) == VAR_DECL);
+   /* We check for problems with specializations in pt.c in
+      check_specialization_namespace, where we can issue better
+      diagnostics.  */
+   if (processing_specialization)
+     return;
+   /* There are no restrictions on the placement of
+      explicit instantiations.  */
+   if (processing_explicit_instantiation)
+     return;
+   /* [class.mfct]
+ 
+      A member function definition that appears outside of the
+      class definition shall appear in a namespace scope enclosing
+      the class definition.
+ 
+      [class.static.data]
+ 
+      The definition for a static data member shall appear in a
+      namespace scope enclosing the member's class definition.  */
+   if (!is_ancestor (current_namespace, DECL_CONTEXT (decl)))
+     pedwarn ("definition of %qD is not in namespace enclosing %qT",
+ 	     decl, DECL_CONTEXT (decl));
+ }
+ 
  /* CTYPE is class type, or null if non-class.
     TYPE is type this FUNCTION_DECL should have, either FUNCTION_TYPE
     or METHOD_TYPE.
     DECLARATOR is the function's name.
     PARMS is a chain of PARM_DECLs for the function.
*************** grokfndecl (tree ctype,
*** 5660,5670 ****
        DECL_STATIC_FUNCTION_P (decl) = 1;
        DECL_CONTEXT (decl) = ctype;
      }
  
    if (ctype)
!     DECL_CONTEXT (decl) = ctype;
  
    if (ctype == NULL_TREE && DECL_MAIN_P (decl))
      {
        if (processing_template_decl)
  	error ("cannot declare %<::main%> to be a template");
--- 5695,5709 ----
        DECL_STATIC_FUNCTION_P (decl) = 1;
        DECL_CONTEXT (decl) = ctype;
      }
  
    if (ctype)
!     {
!       DECL_CONTEXT (decl) = ctype;
!       if (funcdef_flag)
! 	check_class_member_definition_namespace (decl);
!     }
  
    if (ctype == NULL_TREE && DECL_MAIN_P (decl))
      {
        if (processing_template_decl)
  	error ("cannot declare %<::main%> to be a template");
*************** grokvardecl (tree type,
*** 5992,6001 ****
--- 6031,6041 ----
    if (DECL_CLASS_SCOPE_P (decl))
      {
        set_linkage_for_static_data_member (decl);
        /* This function is only called with out-of-class definitions.  */
        DECL_EXTERNAL (decl) = 0;
+       check_class_member_definition_namespace (decl);
      }
    /* At top level, either `static' or no s.c. makes a definition
       (perhaps tentative), and absence of `static' makes it public.  */
    else if (toplevel_bindings_p ())
      {
*************** grokdeclarator (const cp_declarator *dec
*** 7481,7492 ****
        error ("template-id %qD used as a declarator",
  	     unqualified_id);
        unqualified_id = dname;
      }
  
!   /* If DECLARATOR is non-NULL, we know it is a cdk_id declarator;
!      otherwise, we would not have exited the loop above.  */
    if (declarator
        && declarator->u.id.qualifying_scope
        && TYPE_P (declarator->u.id.qualifying_scope))
      {
        tree t;
--- 7521,7537 ----
        error ("template-id %qD used as a declarator",
  	     unqualified_id);
        unqualified_id = dname;
      }
  
!   /* If TYPE is a FUNCTION_TYPE, but the function name was explicitly
!      qualified with a class-name, turn it into a METHOD_TYPE, unless
!      we know that the function is static.  We take advantage of this
!      opportunity to do other processing that pertains to entities
!      explicitly declared to be class members.  Note that if DECLARATOR
!      is non-NULL, we know it is a cdk_id declarator; otherwise, we
!      would not have exited the loop above.  */
    if (declarator
        && declarator->u.id.qualifying_scope
        && TYPE_P (declarator->u.id.qualifying_scope))
      {
        tree t;
*************** grokdeclarator (const cp_declarator *dec
*** 7569,7588 ****
  	  cxx_incomplete_type_error (NULL_TREE, ctype);
  	  return error_mark_node;
  	}
      }
  
    if (returned_attrs)
      {
        if (attrlist)
  	*attrlist = chainon (returned_attrs, *attrlist);
        else
  	attrlist = &returned_attrs;
      }
  
-   /* Now TYPE has the actual type.  */
- 
    /* Did array size calculations overflow?  */
  
    if (TREE_CODE (type) == ARRAY_TYPE
        && COMPLETE_TYPE_P (type)
        && TREE_CODE (TYPE_SIZE_UNIT (type)) == INTEGER_CST
--- 7614,7633 ----
  	  cxx_incomplete_type_error (NULL_TREE, ctype);
  	  return error_mark_node;
  	}
      }
  
+   /* Now TYPE has the actual type.  */
+ 
    if (returned_attrs)
      {
        if (attrlist)
  	*attrlist = chainon (returned_attrs, *attrlist);
        else
  	attrlist = &returned_attrs;
      }
  
    /* Did array size calculations overflow?  */
  
    if (TREE_CODE (type) == ARRAY_TYPE
        && COMPLETE_TYPE_P (type)
        && TREE_CODE (TYPE_SIZE_UNIT (type)) == INTEGER_CST
Index: gcc/cp/pt.c
===================================================================
RCS file: /cvs/gcc/gcc/gcc/cp/pt.c,v
retrieving revision 1.1034
diff -c -5 -p -r1.1034 pt.c
*** gcc/cp/pt.c	13 Sep 2005 14:44:07 -0000	1.1034
--- gcc/cp/pt.c	15 Sep 2005 09:45:02 -0000
*************** check_specialization_namespace (tree tmp
*** 670,679 ****
--- 670,696 ----
        pedwarn ("  from definition of %q+#D", tmpl);
        return false;
      }
  }
  
+ /* SPEC is an explicit instantiation.  Check that it is valid to
+    perform this explicit instantiation in the current namespace.  */
+ 
+ static void
+ check_explicit_instantiation_namespace (tree spec)
+ {
+   tree ns;
+ 
+   /* DR 275: An explicit instantiation shall appear in an enclosing
+      namespace of its template.  */ 
+   ns = decl_namespace_context (spec);
+   if (!is_ancestor (current_namespace, ns))
+     pedwarn ("explicit instantiation of %qD in namespace %qD "
+ 	     "(which does not enclose namespace %qD)"
+ 	     spec, current_namespace, ns);
+ }
+ 
  /* 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)
*************** register_specialization (tree spec, tree
*** 1185,1194 ****
--- 1202,1212 ----
  		 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, is_friend);
+ 	      check_specialization_namespace (fn);
  
  	      return fn;
  	    }
  	}
        else if (DECL_TEMPLATE_SPECIALIZATION (fn))
*************** check_explicit_specialization (tree decl
*** 2085,2102 ****
  
  	  /* This specialization has the same protection as the
  	     template it specializes.  */
  	  TREE_PRIVATE (decl) = TREE_PRIVATE (gen_tmpl);
  	  TREE_PROTECTED (decl) = TREE_PROTECTED (gen_tmpl);
- 
  	  /* The specialization has the same visibility as the
  	     template it specializes.  */
  	  if (DECL_VISIBILITY_SPECIFIED (gen_tmpl))
  	    {
  	      DECL_VISIBILITY_SPECIFIED (decl) = 1;
  	      DECL_VISIBILITY (decl) = DECL_VISIBILITY (gen_tmpl);
  	    }
  
  	  if (is_friend && !have_def)
  	    /* This is not really a declaration of a specialization.
  	       It's just the name of an instantiation.  But, it's not
  	       a request for an instantiation, either.  */
--- 2103,2132 ----
  
  	  /* This specialization has the same protection as the
  	     template it specializes.  */
  	  TREE_PRIVATE (decl) = TREE_PRIVATE (gen_tmpl);
  	  TREE_PROTECTED (decl) = TREE_PROTECTED (gen_tmpl);
  	  /* The specialization has the same visibility as the
  	     template it specializes.  */
  	  if (DECL_VISIBILITY_SPECIFIED (gen_tmpl))
  	    {
  	      DECL_VISIBILITY_SPECIFIED (decl) = 1;
  	      DECL_VISIBILITY (decl) = DECL_VISIBILITY (gen_tmpl);
  	    }
+ 	  /* If DECL is a friend declaration, declared using an
+ 	     unqualified name, the namespace associated with DECL may
+ 	     have been set incorrectly.  For example, in:
+ 	     
+ 	       template <typename T> void f(T); 
+                namespace N {
+   	         struct S { friend void f<int>(int); }
+                }
+ 
+              we will have set the DECL_CONTEXT for the friend
+              declaration to N, rather than to the global namespace.  */
+ 	  if (DECL_NAMESPACE_SCOPE_P (decl))
+ 	    DECL_CONTEXT (decl) = DECL_CONTEXT (tmpl);
  
  	  if (is_friend && !have_def)
  	    /* This is not really a declaration of a specialization.
  	       It's just the name of an instantiation.  But, it's not
  	       a request for an instantiation, either.  */
*************** do_decl_instantiation (tree decl, tree s
*** 10996,11006 ****
  		 "instantiations");
        extern_p = 1;
      }
    else
      error ("storage class %qD applied to template instantiation", storage);
! 
    mark_decl_instantiated (result, extern_p);
    if (! extern_p)
      instantiate_decl (result, /*defer_ok=*/1, 
  		      /*expl_inst_class_mem_p=*/false);
  }
--- 11026,11037 ----
  		 "instantiations");
        extern_p = 1;
      }
    else
      error ("storage class %qD applied to template instantiation", storage);
!   
!   check_explicit_instantiation_namespace (result);
    mark_decl_instantiated (result, extern_p);
    if (! extern_p)
      instantiate_decl (result, /*defer_ok=*/1, 
  		      /*expl_inst_class_mem_p=*/false);
  }
*************** do_type_instantiation (tree t, tree stor
*** 11128,11137 ****
--- 11159,11169 ----
        /* If we've already instantiated the template, just return now.  */
        if (!CLASSTYPE_INTERFACE_ONLY (t))
  	return;
      }
  
+   check_explicit_instantiation_namespace (TYPE_NAME (t));
    mark_class_instantiated (t, extern_p);
  
    if (nomem_p)
      return;
  
Index: gcc/testsuite/g++.dg/parse/class2.C
===================================================================
RCS file: gcc/testsuite/g++.dg/parse/class2.C
diff -N gcc/testsuite/g++.dg/parse/class2.C
*** /dev/null	1 Jan 1970 00:00:00 -0000
--- gcc/testsuite/g++.dg/parse/class2.C	15 Sep 2005 09:45:02 -0000
***************
*** 0 ****
--- 1,14 ----
+ // PR c++/13140
+ 
+ struct foo {
+   foo();
+   void f();
+   static int i;
+ };
+ 
+ 
+ namespace bar {
+   foo::foo() {} // { dg-error "namespace" }
+   void foo::f() {} // { dg-error "namespace" }
+   int foo::i; // { dg-error "namespace" } 
+ }
Index: gcc/testsuite/g++.dg/template/explicit8.C
===================================================================
RCS file: gcc/testsuite/g++.dg/template/explicit8.C
diff -N gcc/testsuite/g++.dg/template/explicit8.C
*** /dev/null	1 Jan 1970 00:00:00 -0000
--- gcc/testsuite/g++.dg/template/explicit8.C	15 Sep 2005 09:45:02 -0000
***************
*** 0 ****
--- 1,13 ----
+ namespace N {
+   template <typename T>
+   struct S {
+     void f() {}
+   };
+   namespace I {
+     template void S<double>::f(); // { dg-error "namespace" }
+   }
+ }
+ 
+ namespace K {
+   template void N::S<int>::f(); // { dg-error "namespace" }
+ }
Index: gcc/testsuite/g++.dg/template/spec25.C
===================================================================
RCS file: gcc/testsuite/g++.dg/template/spec25.C
diff -N gcc/testsuite/g++.dg/template/spec25.C
*** /dev/null	1 Jan 1970 00:00:00 -0000
--- gcc/testsuite/g++.dg/template/spec25.C	15 Sep 2005 09:45:02 -0000
***************
*** 0 ****
--- 1,10 ----
+ namespace N {
+   template <typename T>
+   struct S {
+     void f() {}
+   };
+ }
+ 
+ namespace K {
+   template <> void N::S<char>::f() {} // { dg-error "namespace|definition" }
+ }
Index: libstdc++-v3/testsuite/testsuite_character.h
===================================================================
RCS file: /cvs/gcc/gcc/libstdc++-v3/testsuite/testsuite_character.h,v
retrieving revision 1.6
diff -c -5 -p -r1.6 testsuite_character.h
*** libstdc++-v3/testsuite/testsuite_character.h	17 Aug 2005 02:14:29 -0000	1.6
--- libstdc++-v3/testsuite/testsuite_character.h	15 Sep 2005 09:45:02 -0000
*************** namespace __gnu_test
*** 70,115 ****
    using __gnu_cxx::character;
    typedef character<unsigned char, pod_int, pod_state>  	pod_char;
    typedef character<unsigned char, unsigned int, pod_state>  	pod_uchar;
    typedef character<unsigned short, unsigned int>	   	pod_ushort;
    typedef character<unsigned int, unsigned long>	   	pod_uint;  
  
    // Specializations.
    // pod_char
    template<>
      template<typename V2>
!       inline pod_char::char_type
!       pod_char::char_type::from(const V2& v)
        {
  	char_type ret = { static_cast<value_type>(v.value) };
  	return ret;
        }
  
    template<>
      template<typename V2>
        inline V2
!       pod_char::char_type::to(const char_type& c)
        {
  	V2 ret = { c.value };
  	return ret;
        }
    
-   // pod_uchar
    template<>
      template<typename V2>
!       inline pod_uchar::char_type
!       pod_uchar::char_type::from(const V2& v)
        {
  	char_type ret;
  	ret.value = (v >> 5);
  	return ret;
        }
  
    template<>
      template<typename V2>
        inline V2
!       pod_uchar::char_type::to(const char_type& c)
        { return static_cast<V2>(c.value << 5); }
  }; // namespace __gnu_test
  
  namespace std
  {
--- 70,116 ----
    using __gnu_cxx::character;
    typedef character<unsigned char, pod_int, pod_state>  	pod_char;
    typedef character<unsigned char, unsigned int, pod_state>  	pod_uchar;
    typedef character<unsigned short, unsigned int>	   	pod_ushort;
    typedef character<unsigned int, unsigned long>	   	pod_uint;  
+ }
  
+ namespace __gnu_cxx {
    // Specializations.
    // pod_char
    template<>
      template<typename V2>
!       inline __gnu_test::pod_char::char_type
!       __gnu_test::pod_char::char_type::from(const V2& v)
        {
  	char_type ret = { static_cast<value_type>(v.value) };
  	return ret;
        }
  
    template<>
      template<typename V2>
        inline V2
!       __gnu_test::pod_char::char_type::to(const char_type& c)
        {
  	V2 ret = { c.value };
  	return ret;
        }
    
    template<>
      template<typename V2>
!       inline __gnu_test::pod_uchar::char_type
!       __gnu_test::pod_uchar::char_type::from(const V2& v)
        {
  	char_type ret;
  	ret.value = (v >> 5);
  	return ret;
        }
  
    template<>
      template<typename V2>
        inline V2
!       __gnu_test::pod_uchar::char_type::to(const char_type& c)
        { return static_cast<V2>(c.value << 5); }
  }; // namespace __gnu_test
  
  namespace std
  {


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