This is the mail archive of the
gcc-patches@gcc.gnu.org
mailing list for the GCC project.
C++ PATCH: Fix PR c++/16224
- From: Mark Mitchell <mark at codesourcery dot com>
- To: gcc-patches at gcc dot gnu dot org
- Date: Sun, 1 Aug 2004 23:28:31 -0700
- Subject: C++ PATCH: Fix PR c++/16224
- Reply-to: mark at codesourcery dot com
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 "" }
}