re PR c++/16224 (internal compiler error: in write_unscoped_name (template/namespace))
authorMark Mitchell <mark@codesourcery.com>
Mon, 2 Aug 2004 06:25:36 +0000 (06:25 +0000)
committerMark Mitchell <mmitchel@gcc.gnu.org>
Mon, 2 Aug 2004 06:25:36 +0000 (06:25 +0000)
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.

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.

From-SVN: r85431

gcc/cp/ChangeLog
gcc/cp/name-lookup.c
gcc/cp/pt.c
gcc/testsuite/ChangeLog
gcc/testsuite/g++.dg/template/spec17.C [new file with mode: 0644]
gcc/testsuite/g++.old-deja/g++.ns/template13.C
gcc/testsuite/g++.old-deja/g++.pt/lookup10.C

index fffa892d494d323657820a25292debff654729d1..81a819a793167575e1b90f0894c7518ab69b00fa 100644 (file)
@@ -1,5 +1,16 @@
 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.
+
        PR c++/16489
        * cp-tree.h (DECL_INTEGRAL_CONSTANT_VAR_P): New macro.
        * call.c (null_ptr_cst_p): Handle variables with constant
index 8c36fe8bd0ec37693a51b499bbb7582a356d5c43..c44541285fb73ef850f2419225ddf816f05b3098 100644 (file)
@@ -2991,27 +2991,6 @@ set_namespace_binding (tree name, tree scope, tree 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.  */
 
@@ -3080,9 +3059,9 @@ current_decl_namespace (void)
     return TREE_PURPOSE (decl_namespace_list);
 
   if (current_class_type)
-    result = decl_namespace (TYPE_STUB_DECL (current_class_type));
+    result = decl_namespace_context (current_class_type);
   else if (current_function_decl)
-    result = decl_namespace (current_function_decl);
+    result = decl_namespace_context (current_function_decl);
   else 
     result = current_namespace;
   return result;
@@ -3210,7 +3189,7 @@ void
 push_decl_namespace (tree decl)
 {
   if (TREE_CODE (decl) != NAMESPACE_DECL)
-    decl = decl_namespace (decl);
+    decl = decl_namespace_context (decl);
   decl_namespace_list = tree_cons (ORIGINAL_NAMESPACE (decl),
                                    NULL_TREE, decl_namespace_list);
 }
@@ -4394,7 +4373,7 @@ arg_assoc_class (struct arg_lookup *k, tree type)
     return false;
   k->classes = tree_cons (type, NULL_TREE, k->classes);
   
-  context = decl_namespace (TYPE_MAIN_DECL (type));
+  context = decl_namespace_context (type);
   if (arg_assoc_namespace (k, context))
     return true;
 
@@ -4483,7 +4462,7 @@ arg_assoc_type (struct arg_lookup *k, tree 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)));
+      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.  */
index ad4891049748a7910304f805c0eba403130eec28..1e9bbb131227989f6fa93ca5c9c0d69c301e40a2 100644 (file)
@@ -708,6 +708,36 @@ end_explicit_instantiation (void)
   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.  */
 
@@ -733,15 +763,7 @@ maybe_process_partial_specialization (tree type)
       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));
-           }
+         check_specialization_namespace (CLASSTYPE_TI_TEMPLATE (type));
          SET_CLASSTYPE_TEMPLATE_SPECIALIZATION (type);
          if (processing_template_decl)
            push_template_decl (TYPE_MAIN_DECL (type));
@@ -1057,64 +1079,68 @@ register_specialization (tree spec, tree tmpl, tree args)
         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))
+      else if (comp_template_args (TREE_PURPOSE (s), args)
+              && DECL_TEMPLATE_SPECIALIZATION (spec))
        {
-         if (DECL_TEMPLATE_SPECIALIZATION (spec))
+         if (DECL_TEMPLATE_INSTANTIATION (fn))
            {
-             if (DECL_TEMPLATE_INSTANTIATION (fn))
+             if (TREE_USED (fn) 
+                 || DECL_EXPLICIT_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;
-                   }
+                 error ("specialization of %D after instantiation",
+                        fn);
+                 return spec;
                }
-             else if (DECL_TEMPLATE_SPECIALIZATION (fn))
+             else
                {
-                 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);
+                 /* 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));
index e394b1fe28c300d069a70d2c29db7c3b7b73470e..eb04ff1fd019d06602cf5b4f6183ccb64aac373a 100644 (file)
@@ -1,3 +1,10 @@
+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.
+
 2004-08-02  David Billinghurst
 
        PR fortran/16292
diff --git a/gcc/testsuite/g++.dg/template/spec17.C b/gcc/testsuite/g++.dg/template/spec17.C
new file mode 100644 (file)
index 0000000..2375576
--- /dev/null
@@ -0,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 d7e4b7970941cce61796c9a6f42084ac95c7aac8..058d7b9ec88e07492c9c5005cd8234e05b7e645f 100644 (file)
@@ -2,8 +2,9 @@
 // Templates defined outside must be declared inside
 namespace bar
 {
+  // trick it to provide some prior declaration
   template<class T>
-  void foo(); // trick it to provide some prior declaration
+  void foo(); // { dg-error "definition" }
   template<class T>class X; // { dg-error "" } previous declaration
 }
 
@@ -15,7 +16,7 @@ bar::foo(T const &a)
 }
 
 template<> void bar::foo<int>()
-{                        // { dg-error "" "" { xfail *-*-* } } not declared in bar - 
+{                        // { dg-error "" }
 }
 
 template<class T,class U>
index c0b4389162c8399c21c862b1606c7545fadfb1a2..1c04250fc3c0c59ece91d363d87e524c2f9874ef 100644 (file)
@@ -13,8 +13,8 @@ namespace Outer {
   namespace Core = Core_Real;
 
   namespace Core_Real {
-    template<class T> void Foo (T *) {}
+    template<class T> void Foo (T *) {} // { dg-error "definition" }
   }
 
-  template<> void Core::Foo<> (Render_Real::Type *) {}
+  template<> void Core::Foo<> (Render_Real::Type *) {} // { dg-error "" }
 }