Hi,

we are getting bug reports about this issue with NSDMIs in template classes, like:

struct B
{
template<int N>
struct A
{
int X = N;
};
};

57887.C:6:13: error: ā€˜N’ was not declared in this scope

Looking at cp_parser_class_specifier_1, the comments about the late parsing of default arguments (which we are already handling correctly):

/* Make sure that any template parameters are in scope. */
maybe_begin_member_template_processing (decl);

it seems clear to me that something very similar must be done for NSDMIs too. Thus I prepared the below, which uses CLASSTYPE_TEMPLATE_INFO to adapt the existing code in maybe_begin_member_template_processing. It tests fine. How does it look?

Thanks!
Paolo.

///////////////////////

Index: cp/cp-tree.h
===================================================================
--- cp/cp-tree.h        (revision 204780)
+++ cp/cp-tree.h        (working copy)
@@ -5450,8 +5450,8 @@ extern bool maybe_clone_body                      (tree);
 /* in pt.c */
 extern bool check_template_shadow              (tree);
 extern tree get_innermost_template_args                (tree, int);
-extern void maybe_begin_member_template_processing (tree);
-extern void maybe_end_member_template_processing (void);
+extern void maybe_begin_member_template_or_nsdmi_processing (tree, bool);
+extern void maybe_end_member_template_or_nsdmi_processing (void);
 extern tree finish_member_template_decl                (tree);
 extern void begin_template_parm_list           (void);
 extern bool begin_specialization               (void);
Index: cp/decl.c
===================================================================
--- cp/decl.c   (revision 204780)
+++ cp/decl.c   (working copy)
@@ -13127,7 +13127,7 @@ start_preparsed_function (tree decl1, tree attrs,
      the class.)  It is not until after this point that
      PROCESSING_TEMPLATE_DECL is guaranteed to be set up correctly.  */
   if (flags & SF_INCLASS_INLINE)
-    maybe_begin_member_template_processing (decl1);
+    maybe_begin_member_template_or_nsdmi_processing (decl1, /*nsdmi=*/false);
 
   /* Effective C++ rule 15.  */
   if (warn_ecpp
@@ -14049,7 +14049,7 @@ finish_function (int flags)
      maybe_begin_member_template_processing when start_function was
      called.  */
   if (inclass_inline)
-    maybe_end_member_template_processing ();
+    maybe_end_member_template_or_nsdmi_processing ();
 
   /* Leave the scope of the class.  */
   if (ctype)
Index: cp/parser.c
===================================================================
--- cp/parser.c (revision 204780)
+++ cp/parser.c (working copy)
@@ -19254,11 +19254,12 @@ cp_parser_class_specifier_1 (cp_parser* parser)
              pushed_scope = push_scope (class_type);
            }
          /* Make sure that any template parameters are in scope.  */
-         maybe_begin_member_template_processing (decl);
+         maybe_begin_member_template_or_nsdmi_processing (decl,
+                                                          /*nsdmi=*/false);
          /* Parse the default argument expressions.  */
          cp_parser_late_parsing_default_args (parser, decl);
          /* Remove any template parameters from the symbol table.  */
-         maybe_end_member_template_processing ();
+         maybe_end_member_template_or_nsdmi_processing ();
        }
       vec_safe_truncate (unparsed_funs_with_default_args, 0);
       /* Now parse any NSDMIs.  */
@@ -19274,7 +19275,10 @@ cp_parser_class_specifier_1 (cp_parser* parser)
              pushed_scope = push_scope (class_type);
            }
          inject_this_parameter (class_type, TYPE_UNQUALIFIED);
+         maybe_begin_member_template_or_nsdmi_processing (class_type,
+                                                          /*nsdmi=*/true);
          cp_parser_late_parsing_nsdmi (parser, decl);
+         maybe_end_member_template_or_nsdmi_processing ();
        }
       vec_safe_truncate (unparsed_nsdmis, 0);
       current_class_ptr = save_ccp;
@@ -23219,7 +23223,8 @@ cp_parser_late_parsing_for_member (cp_parser* pars
   push_unparsed_function_queues (parser);
 
   /* Make sure that any template parameters are in scope.  */
-  maybe_begin_member_template_processing (member_function);
+  maybe_begin_member_template_or_nsdmi_processing (member_function,
+                                                  /*nsdmi=*/false);
 
   /* If the body of the function has not yet been parsed, parse it
      now.  */
@@ -23274,7 +23279,7 @@ cp_parser_late_parsing_for_member (cp_parser* pars
     }
 
   /* Remove any template parameters from the symbol table.  */
-  maybe_end_member_template_processing ();
+  maybe_end_member_template_or_nsdmi_processing ();
 
   /* Restore the queue.  */
   pop_unparsed_function_queues (parser);
Index: cp/pt.c
===================================================================
--- cp/pt.c     (revision 204780)
+++ cp/pt.c     (working copy)
@@ -151,7 +151,7 @@ static int for_each_template_parm (tree, tree_fn_t
                                   struct pointer_set_t*, bool);
 static tree expand_template_argument_pack (tree);
 static tree build_template_parm_index (int, int, int, tree, tree);
-static bool inline_needs_template_parms (tree);
+static bool inline_needs_template_parms (tree, bool);
 static void push_inline_template_parms_recursive (tree, int);
 static tree retrieve_local_specialization (tree);
 static void register_local_specialization (tree, tree);
@@ -377,9 +377,9 @@ template_class_depth (tree type)
    Returns true if processing DECL needs us to push template parms.  */
 
 static bool
-inline_needs_template_parms (tree decl)
+inline_needs_template_parms (tree decl, bool nsdmi)
 {
-  if (! DECL_TEMPLATE_INFO (decl))
+  if (!decl || (!nsdmi && ! DECL_TEMPLATE_INFO (decl)))
     return false;
 
   return (TMPL_PARMS_DEPTH (DECL_TEMPLATE_PARMS (most_general_template (decl)))
@@ -452,12 +452,16 @@ push_inline_template_parms_recursive (tree parmlis
    a friend template defined in a class definition.  */
 
 void
-maybe_begin_member_template_processing (tree decl)
+maybe_begin_member_template_or_nsdmi_processing (tree decl, bool nsdmi)
 {
   tree parms;
   int levels = 0;
 
-  if (inline_needs_template_parms (decl))
+  if (nsdmi)
+    decl = (CLASSTYPE_TEMPLATE_INFO (decl)
+           ? TREE_TYPE (CLASSTYPE_TEMPLATE_INFO (decl)) : NULL_TREE);
+
+  if (inline_needs_template_parms (decl, nsdmi))
     {
       parms = DECL_TEMPLATE_PARMS (most_general_template (decl));
       levels = TMPL_PARMS_DEPTH (parms) - processing_template_decl;
@@ -479,7 +483,7 @@ void
 /* Undo the effects of maybe_begin_member_template_processing.  */
 
 void
-maybe_end_member_template_processing (void)
+maybe_end_member_template_or_nsdmi_processing (void)
 {
   int i;
   int last;
Index: testsuite/g++.dg/cpp0x/nsdmi-template3.C
===================================================================
--- testsuite/g++.dg/cpp0x/nsdmi-template3.C    (revision 0)
+++ testsuite/g++.dg/cpp0x/nsdmi-template3.C    (working copy)
@@ -0,0 +1,16 @@
+// PR c++/58760
+// { dg-do compile { target c++11 } }
+
+enum en
+{
+  a,b,c
+};
+ 
+struct B
+{
+  template<en N>
+  struct A
+  {
+    const int X = N;
+  };
+};
Index: testsuite/g++.dg/cpp0x/nsdmi-template4.C
===================================================================
--- testsuite/g++.dg/cpp0x/nsdmi-template4.C    (revision 0)
+++ testsuite/g++.dg/cpp0x/nsdmi-template4.C    (working copy)
@@ -0,0 +1,24 @@
+// PR c++/57887
+// { dg-do compile { target c++11 } }
+
+struct B
+{
+  template<int N>
+  struct A
+  {
+    int X = N;
+  };
+};
+
+template<int M>
+struct C
+{
+  int Y = M;
+
+  template<int N>
+  struct A
+  {
+    int X = N;
+    int Y = M;
+  };
+};

Reply via email to