diff --git a/gcc/cp/ChangeLog b/gcc/cp/ChangeLog index 765c33bcaec..d95650f3db4 100644 --- a/gcc/cp/ChangeLog +++ b/gcc/cp/ChangeLog @@ -1,3 +1,14 @@ +2011-07-11 Jason Merrill + + 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 PR c++/49691 diff --git a/gcc/cp/cp-tree.h b/gcc/cp/cp-tree.h index 357295c8401..cc086404cc9 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 8cd51c28a2c..d90d4b5d864 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 81b772f6316..4a83c9adb2e 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 2c64dd4a4c6..7c735ef75b7 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 6c76e33b934..7d50bd12f6a 100644 --- a/gcc/testsuite/ChangeLog +++ b/gcc/testsuite/ChangeLog @@ -1,3 +1,8 @@ +2011-07-11 Jason Merrill + + PR c++/44609 + * g++.dg/template/recurse3.C: New. + 2011-07-11 Jakub Jelinek 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 00000000000..f1db7c5cbca --- /dev/null +++ b/gcc/testsuite/g++.dg/template/recurse3.C @@ -0,0 +1,14 @@ +// PR c++/44609 +// { dg-options -ftemplate-depth=10 } + +template +void f() +{ + 0 = 0; // { dg-error "lvalue required" } + f(); // { dg-bogus "instantiation depth" } +} + +int main() +{ + f<0>(); +}