C++ PATCH for c++/53599 (ICE with local class in template)

Message ID 4FD78C08.2070908@redhat.com
State New
Headers show

Commit Message

Jason Merrill June 12, 2012, 6:35 p.m.
On 06/07/2012 04:29 PM, Jason Merrill wrote:
> The problem here was that when we instantiate G::bar, we want to
> instantiate F, and end up improperly pushing the declaration inside G,
> which leads to the ICE. Adjusting the call to pushclass is enough to fix
> this, which is what I propose doing for the 4.7 branch. For 4.8 I'm
> going to do more.

What we really want is to get local classes declared at the same place 
in a template that they are in a non-template.  This patch achieves that 
by adding a DECL_EXPR to make the class declaration explicit.  This 
confused finish_cond, which expected a DECL_EXPR to be for a condition 
variable, so I needed to adjust it and tsubst_expr accordingly.

The second patch unconditionally instantiates local classes when we 
encounter their definition, so that we don't need to deal with trying to 
push back to the right scope later on--and because this seems to be what 
the language requires.

Tested x86_64-pc-linux-gnu, applied to trunk.


commit 978586407742e3f208d6f76ee0789b83c760e468
Author: jason <jason@138bc75d-0d04-0410-961f-82ee72b054a4>
Date:   Tue Jun 12 18:32:13 2012 +0000

    	* pt.c (tsubst_expr) [TAG_DEFN]: Instantiate local class.
    	* class.c (finish_struct): Don't add a TAG_DEFN for a lambda.
    	* decl2.c (finish_static_data_member_decl): Avoid redundant error.
    git-svn-id: svn+ssh://gcc.gnu.org/svn/gcc/trunk@188474 138bc75d-0d04-0410-961f-82ee72b054a4

diff --git a/gcc/cp/class.c b/gcc/cp/class.c
index 4bb9dd2..021344b 100644
--- a/gcc/cp/class.c
+++ b/gcc/cp/class.c
@@ -6337,7 +6337,9 @@  finish_struct (tree t, tree attributes)
     error ("trying to finish struct, but kicked out due to previous parse errors");
-  if (processing_template_decl && at_function_scope_p ())
+  if (processing_template_decl && at_function_scope_p ()
+      /* Lambdas are defined by the LAMBDA_EXPR.  */
+      && !LAMBDA_TYPE_P (t))
     add_stmt (build_min (TAG_DEFN, t));
   return t;
diff --git a/gcc/cp/decl2.c b/gcc/cp/decl2.c
index 78e17af..2e3c9a6 100644
--- a/gcc/cp/decl2.c
+++ b/gcc/cp/decl2.c
@@ -770,7 +770,9 @@  finish_static_data_member_decl (tree decl,
   if (! processing_template_decl)
     VEC_safe_push (tree, gc, pending_statics, decl);
-  if (LOCAL_CLASS_P (current_class_type))
+  if (LOCAL_CLASS_P (current_class_type)
+      /* We already complained about the template definition.  */
     permerror (input_location, "local class %q#T shall not have static data member %q#D",
 	       current_class_type, decl);
diff --git a/gcc/cp/pt.c b/gcc/cp/pt.c
index 04f7be8..5e02c8c 100644
--- a/gcc/cp/pt.c
+++ b/gcc/cp/pt.c
@@ -13123,7 +13123,21 @@  tsubst_expr (tree t, tree args, tsubst_flags_t complain, tree in_decl,
     case TAG_DEFN:
-      tsubst (TREE_TYPE (t), args, complain, NULL_TREE);
+      tmp = tsubst (TREE_TYPE (t), args, complain, NULL_TREE);
+      if (CLASS_TYPE_P (tmp))
+	{
+	  /* Local classes are not independent templates; they are
+	     instantiated along with their containing function.  And this
+	     way we don't have to deal with pushing out of one local class
+	     to instantiate a member of another local class.  */
+	  tree fn;
+	  /* Closures are handled by the LAMBDA_EXPR.  */
+	  gcc_assert (!LAMBDA_TYPE_P (TREE_TYPE (t)));
+	  complete_type (tmp);
+	  for (fn = TYPE_METHODS (tmp); fn; fn = DECL_CHAIN (fn))
+	    if (!DECL_ARTIFICIAL (fn))
+	      instantiate_decl (fn, /*defer_ok*/0, /*expl_inst_class*/false);
+	}
     case STATIC_ASSERT: