re PR c++/44609 (Invalid template code causes infinite loop of error messages)
authorJason Merrill <jason@redhat.com>
Mon, 11 Jul 2011 18:52:12 +0000 (14:52 -0400)
committerJason Merrill <jason@gcc.gnu.org>
Mon, 11 Jul 2011 18:52:12 +0000 (14:52 -0400)
PR c++/44609
* cp-tree.h (struct tinst_level): Add errors field.
* pt.c (neglectable_inst_p, limit_bad_template_recurson): New.
(push_tinst_level): Don't start another decl in that case.
(reopen_tinst_level): Adjust errors field.
* decl2.c (cp_write_global_declarations): Don't complain about
undefined inline if its template was defined.
* mangle.c (mangle_decl_string): Handle failure from push_tinst_level.

From-SVN: r176176

gcc/cp/ChangeLog
gcc/cp/cp-tree.h
gcc/cp/decl2.c
gcc/cp/mangle.c
gcc/cp/pt.c
gcc/testsuite/ChangeLog
gcc/testsuite/g++.dg/template/recurse3.C [new file with mode: 0644]

index 765c33bcaec30887415a62b3c0b05e95c5830b38..d95650f3db43adcc4b314efdbabef42d0ab79c74 100644 (file)
@@ -1,3 +1,14 @@
+2011-07-11  Jason Merrill  <jason@redhat.com>
+
+       PR c++/44609
+       * cp-tree.h (struct tinst_level): Add errors field.
+       * pt.c (neglectable_inst_p, limit_bad_template_recurson): New.
+       (push_tinst_level): Don't start another decl in that case.
+       (reopen_tinst_level): Adjust errors field.
+       * decl2.c (cp_write_global_declarations): Don't complain about
+       undefined inline if its template was defined.
+       * mangle.c (mangle_decl_string): Handle failure from push_tinst_level.
+
 2011-07-10  Jason Merrill  <jason@redhat.com>
 
        PR c++/49691
index 357295c84019bc2e2d51f7e762a8f6bbcbfe487f..cc086404cc95fb2a1c9502f1251f465c4816a855 100644 (file)
@@ -4679,6 +4679,9 @@ struct GTY((chain_next ("%h.next"))) tinst_level {
   /* The location where the template is instantiated.  */
   location_t locus;
 
+  /* errorcount+sorrycount when we pushed this level.  */
+  int errors;
+
   /* True if the location is in a system header.  */
   bool in_system_header_p;
 };
index 8cd51c28a2c652cd9a7c87ac84569bd4246cbb16..d90d4b5d8640138f684a06faaffd1d0d5e5076cb 100644 (file)
@@ -3950,10 +3950,10 @@ cp_write_global_declarations (void)
             #pragma interface, etc.) we decided not to emit the
             definition here.  */
          && !DECL_INITIAL (decl)
-         /* An explicit instantiation can be used to specify
-            that the body is in another unit. It will have
-            already verified there was a definition.  */
-         && !DECL_EXPLICIT_INSTANTIATION (decl))
+         /* Don't complain if the template was defined.  */
+         && !(DECL_TEMPLATE_INSTANTIATION (decl)
+              && DECL_INITIAL (DECL_TEMPLATE_RESULT
+                               (template_for_substitution (decl)))))
        {
          warning (0, "inline function %q+D used but never defined", decl);
          /* Avoid a duplicate warning from check_global_declaration_1.  */
index 81b772f6316ce11820bee172b6824592924b919b..4a83c9adb2e091758df43e25496ad757b1b3e745 100644 (file)
@@ -3106,11 +3106,11 @@ mangle_decl_string (const tree decl)
   if (DECL_LANG_SPECIFIC (decl) && DECL_USE_TEMPLATE (decl))
     {
       struct tinst_level *tl = current_instantiation ();
-      if (!tl || tl->decl != decl)
+      if ((!tl || tl->decl != decl)
+         && push_tinst_level (decl))
        {
          template_p = true;
          saved_fn = current_function_decl;
-         push_tinst_level (decl);
          current_function_decl = NULL_TREE;
        }
     }
index 2c64dd4a4c6aaeba1975d977f2cf9e0052288a2b..7c735ef75b7771004ea670ab133c413dc9e7c70d 100644 (file)
@@ -7499,6 +7499,36 @@ uses_template_parms_level (tree t, int level)
                                 /*include_nondeduced_p=*/true);
 }
 
+/* Returns TRUE iff INST is an instantiation we don't need to do in an
+   ill-formed translation unit, i.e. a variable or function that isn't
+   usable in a constant expression.  */
+
+static inline bool
+neglectable_inst_p (tree d)
+{
+  return (DECL_P (d)
+         && !(TREE_CODE (d) == FUNCTION_DECL ? DECL_DECLARED_CONSTEXPR_P (d)
+              : decl_maybe_constant_var_p (d)));
+}
+
+/* Returns TRUE iff we should refuse to instantiate DECL because it's
+   neglectable and instantiated from within an erroneous instantiation.  */
+
+static bool
+limit_bad_template_recurson (tree decl)
+{
+  struct tinst_level *lev = current_tinst_level;
+  int errs = errorcount + sorrycount;
+  if (lev == NULL || errs == 0 || !neglectable_inst_p (decl))
+    return false;
+
+  for (; lev; lev = lev->next)
+    if (neglectable_inst_p (lev->decl))
+      break;
+
+  return (lev && errs > lev->errors);
+}
+
 static int tinst_depth;
 extern int max_tinst_depth;
 #ifdef GATHER_STATISTICS
@@ -7532,9 +7562,16 @@ push_tinst_level (tree d)
       return 0;
     }
 
+  /* If the current instantiation caused problems, don't let it instantiate
+     anything else.  Do allow deduction substitution and decls usable in
+     constant expressions.  */
+  if (limit_bad_template_recurson (d))
+    return 0;
+
   new_level = ggc_alloc_tinst_level ();
   new_level->decl = d;
   new_level->locus = input_location;
+  new_level->errors = errorcount+sorrycount;
   new_level->in_system_header_p = in_system_header;
   new_level->next = current_tinst_level;
   current_tinst_level = new_level;
@@ -7578,6 +7615,8 @@ reopen_tinst_level (struct tinst_level *level)
 
   current_tinst_level = level;
   pop_tinst_level ();
+  if (current_tinst_level)
+    current_tinst_level->errors = errorcount+sorrycount;
   return level->decl;
 }
 
index 6c76e33b934f5f2305b5e63eeacae35c782a33ff..7d50bd12f6a8cbfe6076d6131973ee3b5740d98b 100644 (file)
@@ -1,3 +1,8 @@
+2011-07-11  Jason Merrill  <jason@redhat.com>
+
+       PR c++/44609
+       * g++.dg/template/recurse3.C: New.
+
 2011-07-11  Jakub Jelinek  <jakub@redhat.com>
 
        PR debug/49676
diff --git a/gcc/testsuite/g++.dg/template/recurse3.C b/gcc/testsuite/g++.dg/template/recurse3.C
new file mode 100644 (file)
index 0000000..f1db7c5
--- /dev/null
@@ -0,0 +1,14 @@
+// PR c++/44609
+// { dg-options -ftemplate-depth=10 }
+
+template<int N>
+void f()
+{
+  0 = 0;                       // { dg-error "lvalue required" }
+  f<N+1>();                    // { dg-bogus "instantiation depth" }
+}
+
+int main()
+{
+  f<0>();
+}