On 06/08/15 13:47, Jason Merrill wrote:
How about using a DECL_LANG_FLAG instead of creating a garbage DEFAULT_ARG?

This patch uses DECL_LANG_FLAG_2 on the FIELD_DECL to mark that its NSDMI is being instantiated. I also discovered I'd flubbed the markup on the testcase, not sure why I didn't notice that in the test results. I've double checked this time, and all looks good.

built & tested on x86_64-linux-gnu

nathan
2015-06-09  Nathan Sidwell  <nat...@acm.org>

	cp/
	PR c++/58583
	* cp-tree.h (DECL_INSTANTIATING_NSDMI_P): New.
	* init.c (get_nsdmi): Check for DEFAULT_ARG in template case and
	protect it from recursive instantiation.

	testsuite/
	PR c++/58583
	* g++.dg/cpp0x/nsdmi-template14.C: New test.

Index: cp/cp-tree.h
===================================================================
--- cp/cp-tree.h	(revision 224198)
+++ cp/cp-tree.h	(working copy)
@@ -160,6 +160,7 @@ c-common.h, not after.
       LABEL_DECL_CONTINUE (in LABEL_DECL)
    2: DECL_THIS_EXTERN (in VAR_DECL or FUNCTION_DECL).
       DECL_IMPLICIT_TYPEDEF_P (in a TYPE_DECL)
+      DECL_INSTANTIATING_NSDMI_P (in a FIELD_DECL)
    3: DECL_IN_AGGR_P.
    4: DECL_C_BIT_FIELD (in a FIELD_DECL)
       DECL_ANON_UNION_VAR_P (in a VAR_DECL)
@@ -3785,6 +3786,11 @@ more_aggr_init_expr_args_p (const aggr_i
 #define DECL_ARRAY_PARAMETER_P(NODE) \
   DECL_LANG_FLAG_1 (PARM_DECL_CHECK (NODE))
 
+/* Nonzero for a FIELD_DECL who's NSMDI is currently being
+   instantiated.  */
+#define DECL_INSTANTIATING_NSDMI_P(NODE) \
+  DECL_LANG_FLAG_2 (FIELD_DECL_CHECK (NODE))
+
 /* Nonzero for FIELD_DECL node means that this field is a base class
    of the parent object, as opposed to a member field.  */
 #define DECL_FIELD_IS_BASE(NODE) \
Index: cp/init.c
===================================================================
--- cp/init.c	(revision 224198)
+++ cp/init.c	(working copy)
@@ -544,6 +544,7 @@ get_nsdmi (tree member, bool in_ctor)
   tree init;
   tree save_ccp = current_class_ptr;
   tree save_ccr = current_class_ref;
+  
   if (!in_ctor)
     {
       /* Use a PLACEHOLDER_EXPR when we don't have a 'this' parameter to
@@ -551,22 +552,40 @@ get_nsdmi (tree member, bool in_ctor)
       current_class_ref = build0 (PLACEHOLDER_EXPR, DECL_CONTEXT (member));
       current_class_ptr = build_address (current_class_ref);
     }
+
   if (DECL_LANG_SPECIFIC (member) && DECL_TEMPLATE_INFO (member))
     {
-      /* Do deferred instantiation of the NSDMI.  */
-      init = (tsubst_copy_and_build
-	      (DECL_INITIAL (DECL_TI_TEMPLATE (member)),
-	       DECL_TI_ARGS (member),
-	       tf_warning_or_error, member, /*function_p=*/false,
-	       /*integral_constant_expression_p=*/false));
+      init = DECL_INITIAL (DECL_TI_TEMPLATE (member));
+      if (TREE_CODE (init) == DEFAULT_ARG)
+	goto unparsed;
 
-      init = digest_nsdmi_init (member, init);
+      /* Check recursive instantiation.  */
+      if (DECL_INSTANTIATING_NSDMI_P (member))
+	{
+	  error ("recursive instantiation of non-static data member "
+		 "initializer for %qD", member);
+	  init = error_mark_node;
+	}
+      else
+	{
+	  DECL_INSTANTIATING_NSDMI_P (member) = 1;
+	  
+	  /* Do deferred instantiation of the NSDMI.  */
+	  init = (tsubst_copy_and_build
+		  (init, DECL_TI_ARGS (member),
+		   tf_warning_or_error, member, /*function_p=*/false,
+		   /*integral_constant_expression_p=*/false));
+	  init = digest_nsdmi_init (member, init);
+	  
+	  DECL_INSTANTIATING_NSDMI_P (member) = 0;
+	}
     }
   else
     {
       init = DECL_INITIAL (member);
       if (init && TREE_CODE (init) == DEFAULT_ARG)
 	{
+	unparsed:
 	  error ("constructor required before non-static data member "
 		 "for %qD has been parsed", member);
 	  DECL_INITIAL (member) = error_mark_node;
Index: testsuite/g++.dg/cpp0x/nsdmi-template14.C
===================================================================
--- testsuite/g++.dg/cpp0x/nsdmi-template14.C	(revision 0)
+++ testsuite/g++.dg/cpp0x/nsdmi-template14.C	(working copy)
@@ -0,0 +1,22 @@
+// PR c++/58583
+// { dg-do compile { target c++11 } }
+
+template<int> struct A // { dg-error "has been parsed" }
+{
+  int i = (A<0>(), 0); // { dg-error "has been parsed" }
+};
+
+template<int N> struct B
+{
+  B* p = new B<N>;
+};
+
+B<1> x; // { dg-error "recursive instantiation of non-static data" }
+
+struct C
+{
+  template<int N> struct D
+  {
+    D* p = new D<0>;
+  };
+};

Reply via email to