From eba839f9719e66195f75207b377593c025c71b82 Mon Sep 17 00:00:00 2001
From: Mark Mitchell <mark@codesourcery.com>
Date: Mon, 18 Jul 2005 15:44:36 +0000
Subject: [PATCH] re PR c++/22263 (explicit instantiation fails to emit symbols
 defined later)

	PR c++/22263
	* cp-tree.h (instantiate_decl): Change prototype.
	* decl2.c (mark_used): Adjust accordingly.
	* pt.c (do_decl_instantiation): Likewise.
	(instantiate_class_member): Likewise.
	(instantiate_decl): Rename undefined_ok as expl_inst_class_mem_p.
	Clear DECL_INTERFACE_KNOWN for an explicitly instantiated template
	that has no definition available.
	(instantiate_pending_templates): Adjust call to instantiate_decl.

	PR c++/22263
	* g++.dg/template/explicit7.C: New test.

From-SVN: r102133
---
 gcc/cp/ChangeLog                          | 12 ++++++++
 gcc/cp/cp-tree.h                          |  2 +-
 gcc/cp/decl2.c                            |  3 +-
 gcc/cp/pt.c                               | 35 ++++++++++++++---------
 gcc/testsuite/ChangeLog                   |  5 ++++
 gcc/testsuite/g++.dg/template/explicit7.C | 13 +++++++++
 6 files changed, 54 insertions(+), 16 deletions(-)
 create mode 100644 gcc/testsuite/g++.dg/template/explicit7.C

diff --git a/gcc/cp/ChangeLog b/gcc/cp/ChangeLog
index 4c048cf4bd83..b30aabc1f9a7 100644
--- a/gcc/cp/ChangeLog
+++ b/gcc/cp/ChangeLog
@@ -1,3 +1,15 @@
+2005-07-18  Mark Mitchell  <mark@codesourcery.com>
+
+	PR c++/22263
+	* cp-tree.h (instantiate_decl): Change prototype.
+	* decl2.c (mark_used): Adjust accordingly.
+	* pt.c (do_decl_instantiation): Likewise.
+	(instantiate_class_member): Likewise.
+	(instantiate_decl): Rename undefined_ok as expl_inst_class_mem_p.
+	Clear DECL_INTERFACE_KNOWN for an explicitly instantiated template
+	that has no definition available.
+	(instantiate_pending_templates): Adjust call to instantiate_decl.
+
 2005-07-17  Mark Mitchell  <mark@codesourcery.com>
 
 	PR c++/22139
diff --git a/gcc/cp/cp-tree.h b/gcc/cp/cp-tree.h
index 2d5e5f1f41d5..d9d053d6dfb0 100644
--- a/gcc/cp/cp-tree.h
+++ b/gcc/cp/cp-tree.h
@@ -3997,7 +3997,7 @@ extern int more_specialized_fn			(tree, tree, int);
 extern void mark_class_instantiated		(tree, int);
 extern void do_decl_instantiation		(tree, tree);
 extern void do_type_instantiation		(tree, tree, tsubst_flags_t);
-extern tree instantiate_decl			(tree, int, int);
+extern tree instantiate_decl			(tree, int, bool);
 extern int push_tinst_level			(tree);
 extern void pop_tinst_level			(void);
 extern int more_specialized_class		(tree, tree, tree);
diff --git a/gcc/cp/decl2.c b/gcc/cp/decl2.c
index 22166e8b3982..5afcd896cc14 100644
--- a/gcc/cp/decl2.c
+++ b/gcc/cp/decl2.c
@@ -3278,7 +3278,8 @@ mark_used (tree decl)
        times.  Maintaining a stack of active functions is expensive,
        and the inliner knows to instantiate any functions it might
        need.  */
-    instantiate_decl (decl, /*defer_ok=*/true, /*undefined_ok=*/0);
+    instantiate_decl (decl, /*defer_ok=*/true, 
+		      /*expl_inst_class_mem_p=*/false);
 }
 
 #include "gt-cp-decl2.h"
diff --git a/gcc/cp/pt.c b/gcc/cp/pt.c
index bbf3bf9bb34e..619cdc117524 100644
--- a/gcc/cp/pt.c
+++ b/gcc/cp/pt.c
@@ -11010,7 +11010,8 @@ do_decl_instantiation (tree decl, tree storage)
 
   mark_decl_instantiated (result, extern_p);
   if (! extern_p)
-    instantiate_decl (result, /*defer_ok=*/1, /*undefined_ok=*/0);
+    instantiate_decl (result, /*defer_ok=*/1, 
+		      /*expl_inst_class_mem_p=*/false);
 }
 
 void
@@ -11047,7 +11048,8 @@ instantiate_class_member (tree decl, int extern_p)
 {
   mark_decl_instantiated (decl, extern_p);
   if (! extern_p)
-    instantiate_decl (decl, /*defer_ok=*/1, /* undefined_ok=*/1);
+    instantiate_decl (decl, /*defer_ok=*/1, 
+		      /*expl_inst_class_mem_p=*/true);
 }
 
 /* Perform an explicit instantiation of template class T.  STORAGE, if
@@ -11343,14 +11345,12 @@ template_for_substitution (tree decl)
    DEFER_OK is nonzero, then we don't have to actually do the
    instantiation now; we just have to do it sometime.  Normally it is
    an error if this is an explicit instantiation but D is undefined.
-   If UNDEFINED_OK is nonzero, then instead we treat it as an implicit
-   instantiation.  UNDEFINED_OK is nonzero only if we are being used
-   to instantiate the members of an explicitly instantiated class
-   template.  */
-
+   EXPL_INST_CLASS_MEM_P is true iff D is a member of an
+   explicitly instantiated class template.  */
 
 tree
-instantiate_decl (tree d, int defer_ok, int undefined_ok)
+instantiate_decl (tree d, int defer_ok, 
+		  bool expl_inst_class_mem_p)
 {
   tree tmpl = DECL_TI_TEMPLATE (d);
   tree gen_args;
@@ -11439,9 +11439,14 @@ instantiate_decl (tree d, int defer_ok, int undefined_ok)
 
   input_location = DECL_SOURCE_LOCATION (d);
 
-  if (! pattern_defined && DECL_EXPLICIT_INSTANTIATION (d) && undefined_ok)
+  /* If D is a member of an explicitly instantiated class template,
+     and no definition is available, treat it like an implicit
+     instantiation.  */ 
+  if (!pattern_defined && expl_inst_class_mem_p 
+      && DECL_EXPLICIT_INSTANTIATION (d)) 
     {
       DECL_NOT_REALLY_EXTERN (d) = 0;
+      DECL_INTERFACE_KNOWN (d) = 0;
       SET_DECL_IMPLICIT_INSTANTIATION (d);
     }
 
@@ -11678,8 +11683,9 @@ instantiate_pending_templates (int retries)
 			 fn;
 			 fn = TREE_CHAIN (fn))
 		      if (! DECL_ARTIFICIAL (fn))
-			instantiate_decl (fn, /*defer_ok=*/0,
-					  /*undefined_ok=*/0);
+			instantiate_decl (fn, 
+					  /*defer_ok=*/0,
+					  /*expl_inst_class_mem_p=*/false);
 		  if (COMPLETE_TYPE_P (instantiation))
 		    reconsider = 1;
 		}
@@ -11699,9 +11705,10 @@ instantiate_pending_templates (int retries)
 	      if (!DECL_TEMPLATE_SPECIALIZATION (instantiation)
 		  && !DECL_TEMPLATE_INSTANTIATED (instantiation))
 		{
-		  instantiation = instantiate_decl (instantiation,
-						    /*defer_ok=*/0,
-						    /*undefined_ok=*/0);
+		  instantiation 
+		    = instantiate_decl (instantiation,
+					/*defer_ok=*/0,
+					/*expl_inst_class_mem_p=*/false);
 		  if (DECL_TEMPLATE_INSTANTIATED (instantiation))
 		    reconsider = 1;
 		}
diff --git a/gcc/testsuite/ChangeLog b/gcc/testsuite/ChangeLog
index 80b9604ecbf3..88228523684e 100644
--- a/gcc/testsuite/ChangeLog
+++ b/gcc/testsuite/ChangeLog
@@ -1,3 +1,8 @@
+2005-07-18  Mark Mitchell  <mark@codesourcery.com>
+
+	PR c++/22263
+	* g++.dg/template/explicit7.C: New test.
+
 2005-07-17  Jerry DeLisle  <jvdelisle@verizon.net>
     * gfortran.fortran-torture/execute/nan_inf_fmt.f90: Change case of field
     width of 8 to +Inf and -Inf.
diff --git a/gcc/testsuite/g++.dg/template/explicit7.C b/gcc/testsuite/g++.dg/template/explicit7.C
new file mode 100644
index 000000000000..7424677181a7
--- /dev/null
+++ b/gcc/testsuite/g++.dg/template/explicit7.C
@@ -0,0 +1,13 @@
+// PR c++/22263
+// { dg-do link }
+
+template <class T> struct S { T foo (); T bar (); };
+template <class T> T S<T>::foo () { return bar (); }
+template struct S<int>;
+template <class T> T S<T>::bar () { return T (); }
+
+#if !__GXX_WEAK__
+template int S<int>::bar ();
+#endif
+
+int main () { return S<int>().foo (); }