Following a suggestion in PR16564, this patch makes excessive template instantiation depth a fatal error. In fact, this allows simplifying the code a lot, just by printing first the context (like we do for every other diagnostic) instead of printing it after (which is not possible for a fatal error).
This changes the output of quite a few testcases, so before modifying those I would like to know whether the idea is OK. Examples of changed output are: [Before] g++.dg/cpp0x/decltype26.C:6:15: error: template instantiation depth exceeds maximum of 900 (use -ftemplate-depth= to increase the maximum) substituting 'template<class T> decltype (f(T())) f(T) [with T = <missing>]' g++.dg/cpp0x/decltype26.C:6:15: recursively required by substitution of 'template<class T> decltype (f(T())) f(T) [with T = A]' g++.dg/cpp0x/decltype26.C:6:15: required by substitution of 'template<class T> decltype (f(T())) f(T) [with T = A]' g++.dg/cpp0x/decltype26.C:13:8: required from here g++.dg/cpp0x/decltype26.C: In function 'int main()': g++.dg/cpp0x/decltype26.C:13:8: error: no matching function for call to 'f(A)' g++.dg/cpp0x/decltype26.C:6:18: note: candidate: template<class T> decltype (f(T())) f(T) g++.dg/cpp0x/decltype26.C:6:18: note: substitution of deduced template arguments resulted in errors seen above [After] g++.dg/cpp0x/decltype26.C: In substitution of 'template<class T> decltype (f(T())) f(T) [with T = A]': g++.dg/cpp0x/decltype26.C:6:15: recursively required by substitution of 'template<class T> decltype (f(T())) f(T) [with T = A]' g++.dg/cpp0x/decltype26.C:6:15: required by substitution of 'template<class T> decltype (f(T())) f(T) [with T = A]' g++.dg/cpp0x/decltype26.C:13:8: required from here g++.dg/cpp0x/decltype26.C:6:15: fatal error: template instantiation depth exceeds maximum of 900 (use -ftemplate-depth= to increase the maximum) One interesting case is for operator->(). Here we have to adjust the location of the template instantiations so we can point the user to the point of recursion: [Before] g++.dg/template/arrow1.C:12:11: error: template instantiation depth exceeds maximum of 900 (use -ftemplate-depth= to increase the maximum) instantiating 'a<(n + 1)> a<n>::operator->() [with int n = 900]' g++.dg/template/arrow1.C:12:11: recursively required from 'a<(n + 1)> a<n>::operator->() [with int n = 0]' g++.dg/template/arrow1.C:12:11: required from here g++.dg/template/arrow1.C:12:11: error: template instantiation depth exceeds maximum of 900 (use -ftemplate-depth= to increase the maximum) instantiating 'struct a<901>' g++.dg/template/arrow1.C:12:11: recursively required from 'a<(n + 1)> a<n>::operator->() [with int n = 0]' g++.dg/template/arrow1.C:12:11: required from here g++.dg/template/arrow1.C:12:11: error: invalid use of incomplete type 'struct a<901>' g++.dg/template/arrow1.C:5:8: note: declaration of 'struct a<901>' [After] g++.dg/template/arrow1.C: In instantiation of 'a<(n + 1)> a<n>::operator->() [with int n = 899]': g++.dg/template/arrow1.C:7:2: recursively required from 'a<(n + 1)> a<n>::operator->() [with int n = 1]' g++.dg/template/arrow1.C:7:2: required from 'a<(n + 1)> a<n>::operator->() [with int n = 0]' g++.dg/template/arrow1.C:12:11: required from here g++.dg/template/arrow1.C:12:11: fatal error: template instantiation depth exceeds maximum of 900 (use -ftemplate-depth= to increase the maximum) The rest of testcases follow the pattern: [Before] g++.dg/template/pr23510.C:9:1: error: expected ';' after struct definition g++.dg/template/pr23510.C:6:27: error: template instantiation depth exceeds maximum of 15 (use -ftemplate-depth= to increase the maximum) instantiating 'struct Factorial<5u>' g++.dg/template/pr23510.C:6:27: recursively required from 'struct Factorial<19u>' g++.dg/template/pr23510.C:6:27: required from 'struct Factorial<20u>' g++.dg/template/pr23510.C:21:20: required from here [After] g++.dg/template/pr23510.C:9:1: error: expected ';' after struct definition g++.dg/template/pr23510.C: In instantiation of 'struct Factorial<6u>': g++.dg/template/pr23510.C:6:27: recursively required from 'struct Factorial<19u>' g++.dg/template/pr23510.C:6:27: required from 'struct Factorial<20u>' g++.dg/template/pr23510.C:21:20: required from here g++.dg/template/pr23510.C:6:27: fatal error: template instantiation depth exceeds maximum of 15 (use -ftemplate-depth= to increase the maximum) Apart from these changes, the patch bootstraps and passes the regression suite on x86_64-linux. OK with the updated testcases? gcc/cp/ChangeLog: 2014-08-17 Manuel López-Ibáñez <m...@gcc.gnu.org> * error.c (print_instantiation_context): Delete. * typeck2.c (build_x_arrow): Record location when pushing template instantiation. * pt.c (push_tinst_level): Make it a wrapper around ... (push_tinst_level_loc): ... this. New function. Make excessive template instantiation depth a fatal error. Record location. Use bool as return type. (instantiate_pending_templates): Make excessive template instantiation depth a fatal error. (problematic_instantiation_changed): Use bool as return type. * cp-tree.h (print_instantiation_context): Delete. (push_tinst_level): Update declaration. (problematic_instantiation_changed): Likewise. (push_tinst_level_loc): New. gcc/testsuite/ChangeLog: 2014-08-17 Manuel López-Ibáñez <m...@gcc.gnu.org> * lib/gcc.exp: Accept "fatal error:" as error prefix. * lib/g++.exp: Likewise. * lib/obj-c++.exp: Likewise. * lib/objc.exp: Likewise. * g++.dg/template/pr16564.C: New test.
Index: gcc/testsuite/lib/gcc.exp =================================================================== --- gcc/testsuite/lib/gcc.exp (revision 214029) +++ gcc/testsuite/lib/gcc.exp (working copy) @@ -109,11 +109,11 @@ proc gcc_init { args } { if ![info exists tmpdir] then { set tmpdir /tmp } set gcc_warning_prefix "warning:" - set gcc_error_prefix "error:" + set gcc_error_prefix "(fatal )?error:" gcc_maybe_build_wrapper "${tmpdir}/gcc-testglue.o" } # Index: gcc/testsuite/lib/g++.exp =================================================================== --- gcc/testsuite/lib/g++.exp (revision 214029) +++ gcc/testsuite/lib/g++.exp (working copy) @@ -265,11 +265,11 @@ proc g++_init { args } { # Make sure that lines are not wrapped. That can confuse the # error-message parsing machinery. lappend ALWAYS_CXXFLAGS "additional_flags=-fmessage-length=0" set gcc_warning_prefix "warning:" - set gcc_error_prefix "error:" + set gcc_error_prefix "(fatal )?error:" if { [istarget *-*-darwin*] } { lappend ALWAYS_CXXFLAGS "ldflags=-multiply_defined suppress" } Index: gcc/testsuite/lib/obj-c++.exp =================================================================== --- gcc/testsuite/lib/obj-c++.exp (revision 214029) +++ gcc/testsuite/lib/obj-c++.exp (working copy) @@ -273,11 +273,11 @@ proc obj-c++_init { args } { # Make sure that lines are not wrapped. That can confuse the # error-message parsing machinery. lappend ALWAYS_OBJCXXFLAGS "additional_flags=-fmessage-length=0" set gcc_warning_prefix "warning:" - set gcc_error_prefix "error:" + set gcc_error_prefix "(fatal )?error:" if { [istarget *-*-darwin*] } { lappend ALWAYS_OBJCXXFLAGS "ldflags=-multiply_defined suppress" } Index: gcc/testsuite/lib/objc.exp =================================================================== --- gcc/testsuite/lib/objc.exp (revision 214029) +++ gcc/testsuite/lib/objc.exp (working copy) @@ -122,11 +122,11 @@ proc objc_init { args } { if ![info exists tmpdir] then { set tmpdir /tmp } set gcc_warning_prefix "warning:" - set gcc_error_prefix "error:" + set gcc_error_prefix "(fatal )?error:" objc_maybe_build_wrapper "${tmpdir}/objc-testglue.o" set objc_libgcc_s_path [gcc-set-multilib-library-path $OBJC_UNDER_TEST] } Index: gcc/testsuite/g++.dg/template/pr16564.C =================================================================== --- gcc/testsuite/g++.dg/template/pr16564.C (revision 0) +++ gcc/testsuite/g++.dg/template/pr16564.C (revision 0) @@ -0,0 +1,8 @@ +// { dg-do compile } +template<typename> struct A +{ + A<A> a; /* { dg-error "template instantiation depth" } */ + A() {} +}; + +A<int> a; Index: gcc/cp/error.c =================================================================== --- gcc/cp/error.c (revision 214029) +++ gcc/cp/error.c (working copy) @@ -3351,20 +3351,10 @@ maybe_print_instantiation_context (diagn return; record_last_problematic_instantiation (); print_instantiation_full_context (context); } - -/* Report the bare minimum context of a template instantiation. */ -void -print_instantiation_context (void) -{ - print_instantiation_partial_context - (global_dc, current_instantiation (), input_location); - pp_newline (global_dc->printer); - diagnostic_flush_buffer (global_dc); -} /* Report what constexpr call(s) we're trying to expand, if any. */ void maybe_print_constexpr_context (diagnostic_context *context) Index: gcc/cp/typeck2.c =================================================================== --- gcc/cp/typeck2.c (revision 214029) +++ gcc/cp/typeck2.c (working copy) @@ -1635,12 +1635,17 @@ build_x_arrow (location_t loc, tree expr &fn, complain))) { if (expr == error_mark_node) return error_mark_node; + /* This provides a better instantiation backtrace in case of + error. */ if (fn && DECL_USE_TEMPLATE (fn)) - push_tinst_level (fn); + push_tinst_level_loc (fn, + (current_instantiation () != actual_inst) + ? DECL_SOURCE_LOCATION (fn) + : input_location); fn = NULL; if (vec_member (TREE_TYPE (expr), types_memoized)) { if (complain & tf_error) Index: gcc/cp/pt.c =================================================================== --- gcc/cp/pt.c (revision 214029) +++ gcc/cp/pt.c (working copy) @@ -8334,51 +8334,51 @@ int depth_reached; static GTY(()) struct tinst_level *last_error_tinst_level; /* We're starting to instantiate D; record the template instantiation context for diagnostics and to restore it later. */ -int +bool push_tinst_level (tree d) { + return push_tinst_level_loc (d, input_location); +} + +/* We're starting to instantiate D; record the template instantiation context + at LOC for diagnostics and to restore it later. */ + +bool +push_tinst_level_loc (tree d, location_t loc) +{ struct tinst_level *new_level; if (tinst_depth >= max_tinst_depth) { - last_error_tinst_level = current_tinst_level; - if (TREE_CODE (d) == TREE_LIST) - error ("template instantiation depth exceeds maximum of %d (use " - "-ftemplate-depth= to increase the maximum) substituting %qS", - max_tinst_depth, d); - else - error ("template instantiation depth exceeds maximum of %d (use " - "-ftemplate-depth= to increase the maximum) instantiating %qD", - max_tinst_depth, d); - - print_instantiation_context (); - - return 0; + fatal_error ("template instantiation depth exceeds maximum of %d" + " (use -ftemplate-depth= to increase the maximum)", + max_tinst_depth); + return false; } /* 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_recursion (d)) - return 0; + return false; new_level = ggc_alloc<tinst_level> (); new_level->decl = d; - new_level->locus = input_location; + new_level->locus = loc; new_level->errors = errorcount+sorrycount; new_level->in_system_header_p = in_system_header_at (input_location); new_level->next = current_tinst_level; current_tinst_level = new_level; ++tinst_depth; if (GATHER_STATISTICS && (tinst_depth > depth_reached)) depth_reached = tinst_depth; - return 1; + return true; } /* We're done instantiating this template; return to the instantiation context. */ @@ -20230,14 +20230,14 @@ instantiate_pending_templates (int retri to avoid infinite loop. */ if (pending_templates && retries >= max_tinst_depth) { tree decl = pending_templates->tinst->decl; - error ("template instantiation depth exceeds maximum of %d" - " instantiating %q+D, possibly from virtual table generation" - " (use -ftemplate-depth= to increase the maximum)", - max_tinst_depth, decl); + fatal_error ("template instantiation depth exceeds maximum of %d" + " instantiating %q+D, possibly from virtual table generation" + " (use -ftemplate-depth= to increase the maximum)", + max_tinst_depth, decl); if (TREE_CODE (decl) == FUNCTION_DECL) /* Pretend that we defined it. */ DECL_INITIAL (decl) = error_mark_node; return; } @@ -20566,11 +20566,11 @@ get_mostly_instantiated_function_type (t return fn_type; } /* Return truthvalue if we're processing a template different from the last one involved in diagnostics. */ -int +bool problematic_instantiation_changed (void) { return current_tinst_level != last_error_tinst_level; } Index: gcc/cp/cp-tree.h =================================================================== --- gcc/cp/cp-tree.h (revision 214029) +++ gcc/cp/cp-tree.h (working copy) @@ -5410,11 +5410,10 @@ extern const char *decl_as_dwarf_string extern const char *expr_as_string (tree, int); extern const char *lang_decl_name (tree, int, bool); extern const char *lang_decl_dwarf_name (tree, int, bool); extern const char *language_to_string (enum languages); extern const char *class_key_or_enum_as_string (tree); -extern void print_instantiation_context (void); extern void maybe_warn_variadic_templates (void); extern void maybe_warn_cpp0x (cpp0x_warn_str str); extern bool pedwarn_cxx98 (location_t, int, const char *, ...) ATTRIBUTE_GCC_DIAG(3,4); extern location_t location_of (tree); extern void qualified_name_lookup_error (tree, tree, tree, @@ -5625,11 +5624,11 @@ extern tree tsubst_default_argument (tr extern tree tsubst (tree, tree, tsubst_flags_t, tree); extern tree tsubst_copy_and_build (tree, tree, tsubst_flags_t, tree, bool, bool); extern tree most_general_template (tree); extern tree get_mostly_instantiated_function_type (tree); -extern int problematic_instantiation_changed (void); +extern bool problematic_instantiation_changed (void); extern void record_last_problematic_instantiation (void); extern struct tinst_level *current_instantiation(void); extern tree maybe_get_template_decl_from_type_decl (tree); extern int processing_template_parmlist; extern bool dependent_type_p (tree); @@ -5653,11 +5652,12 @@ extern bool reregister_specialization ( extern tree fold_non_dependent_expr (tree); extern tree fold_non_dependent_expr_sfinae (tree, tsubst_flags_t); extern bool alias_type_or_template_p (tree); extern bool alias_template_specialization_p (const_tree); extern bool explicit_class_specialization_p (tree); -extern int push_tinst_level (tree); +extern bool push_tinst_level (tree); +extern bool push_tinst_level_loc (tree, location_t); extern void pop_tinst_level (void); extern struct tinst_level *outermost_tinst_level(void); extern void init_template_processing (void); extern void print_template_statistics (void); bool template_template_parameter_p (const_tree);