aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorJason Merrill <jason@redhat.com>2011-07-11 14:52:12 -0400
committerJason Merrill <jason@gcc.gnu.org>2011-07-11 14:52:12 -0400
commit4904b64bf7dc5538b06d2ba01fc1c55231c09bb8 (patch)
tree3256896a64479248e6b7bfbaeb3af03b35d3636e
parent848ca96f30746fc6972105de156656ce8c5ee586 (diff)
downloadgcc-4904b64bf7dc5538b06d2ba01fc1c55231c09bb8.zip
gcc-4904b64bf7dc5538b06d2ba01fc1c55231c09bb8.tar.gz
gcc-4904b64bf7dc5538b06d2ba01fc1c55231c09bb8.tar.bz2
re PR c++/44609 (Invalid template code causes infinite loop of error messages)
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
-rw-r--r--gcc/cp/ChangeLog11
-rw-r--r--gcc/cp/cp-tree.h3
-rw-r--r--gcc/cp/decl2.c8
-rw-r--r--gcc/cp/mangle.c4
-rw-r--r--gcc/cp/pt.c39
-rw-r--r--gcc/testsuite/ChangeLog5
-rw-r--r--gcc/testsuite/g++.dg/template/recurse3.C14
7 files changed, 78 insertions, 6 deletions
diff --git a/gcc/cp/ChangeLog b/gcc/cp/ChangeLog
index 765c33b..d95650f 100644
--- a/gcc/cp/ChangeLog
+++ b/gcc/cp/ChangeLog
@@ -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
diff --git a/gcc/cp/cp-tree.h b/gcc/cp/cp-tree.h
index 357295c..cc08640 100644
--- a/gcc/cp/cp-tree.h
+++ b/gcc/cp/cp-tree.h
@@ -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;
};
diff --git a/gcc/cp/decl2.c b/gcc/cp/decl2.c
index 8cd51c2..d90d4b5 100644
--- a/gcc/cp/decl2.c
+++ b/gcc/cp/decl2.c
@@ -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. */
diff --git a/gcc/cp/mangle.c b/gcc/cp/mangle.c
index 81b772f..4a83c9a 100644
--- a/gcc/cp/mangle.c
+++ b/gcc/cp/mangle.c
@@ -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;
}
}
diff --git a/gcc/cp/pt.c b/gcc/cp/pt.c
index 2c64dd4..7c735ef 100644
--- a/gcc/cp/pt.c
+++ b/gcc/cp/pt.c
@@ -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;
}
diff --git a/gcc/testsuite/ChangeLog b/gcc/testsuite/ChangeLog
index 6c76e33..7d50bd1 100644
--- a/gcc/testsuite/ChangeLog
+++ b/gcc/testsuite/ChangeLog
@@ -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
index 0000000..f1db7c5
--- /dev/null
+++ b/gcc/testsuite/g++.dg/template/recurse3.C
@@ -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>();
+}