diff mbox

[C++,PING] Re: [PATCH] make excessive template instantiation depth a fatal error

Message ID 542AB5FA.7000905@oracle.com
State New
Headers show

Commit Message

Paolo Carlini Sept. 30, 2014, 1:54 p.m. UTC
... forgot to attach the complete patch ;)

Paolo.

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

Comments

Jason Merrill Sept. 30, 2014, 2:38 p.m. UTC | #1
OK.

Jason
Manuel López-Ibáñez Sept. 30, 2014, 2:51 p.m. UTC | #2
I don't want to cause you more work Paolo, but perhaps this should be
documented in https://gcc.gnu.org/gcc-5/changes.html. ?

Something like:

* Excessive template instantiation depth is now a fatal error. This
prevents excessive diagnostics that usually do not help to identify
the problem.

Thanks for taking care of this!

Cheers,

Manuel.

On 30 September 2014 16:38, Jason Merrill <jason@redhat.com> wrote:
> OK.
>
> Jason
Paolo Carlini Sept. 30, 2014, 3:43 p.m. UTC | #3
Hi,

On 09/30/2014 04:51 PM, Manuel López-Ibáñez wrote:
> I don't want to cause you more work Paolo, but perhaps this should be
> documented in https://gcc.gnu.org/gcc-5/changes.html. ?
>
> Something like:
>
> * Excessive template instantiation depth is now a fatal error. This
> prevents excessive diagnostics that usually do not help to identify
> the problem.
>
> Thanks for taking care of this!
You are welcome. No problem about the changes.html bits, I'll take care 
of that too.

Paolo.
diff mbox

Patch

Index: cp/cp-tree.h
===================================================================
--- cp/cp-tree.h	(revision 215710)
+++ cp/cp-tree.h	(working copy)
@@ -5418,7 +5418,6 @@  extern const char *lang_decl_name		(tree, int, boo
 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);
@@ -5633,7 +5632,7 @@  extern tree tsubst_copy_and_build		(tree, tree, ts
 						 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);
@@ -5661,7 +5660,8 @@  extern tree fold_non_dependent_expr_sfinae	(tree,
 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);
Index: cp/error.c
===================================================================
--- cp/error.c	(revision 215710)
+++ cp/error.c	(working copy)
@@ -3360,16 +3360,6 @@  maybe_print_instantiation_context (diagnostic_cont
   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.  */
 
Index: cp/pt.c
===================================================================
--- cp/pt.c	(revision 215710)
+++ cp/pt.c	(working copy)
@@ -8347,26 +8347,26 @@  static GTY(()) struct tinst_level *last_error_tins
 /* 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
@@ -8373,11 +8373,11 @@  push_tinst_level (tree d)
      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;
@@ -8387,7 +8387,7 @@  push_tinst_level (tree d)
   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
@@ -20291,10 +20291,10 @@  instantiate_pending_templates (int retries)
     {
       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;
@@ -20627,7 +20627,7 @@  get_mostly_instantiated_function_type (tree decl)
 
 /* 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: cp/typeck2.c
===================================================================
--- cp/typeck2.c	(revision 215710)
+++ cp/typeck2.c	(working copy)
@@ -1639,8 +1639,13 @@  build_x_arrow (location_t loc, tree expr, tsubst_f
 	  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))
Index: testsuite/g++.dg/cpp0x/decltype26.C
===================================================================
--- testsuite/g++.dg/cpp0x/decltype26.C	(revision 215708)
+++ testsuite/g++.dg/cpp0x/decltype26.C	(working copy)
@@ -10,7 +10,7 @@  decltype(f(T())) f(T t)		// { dg-error "depth" }
 
 int main()
 {
-  f(A());			// { dg-error "no match" }
+  f(A());			// { dg-message "from here" }
 }
 
-// { dg-prune-output "note" }
+// { dg-prune-output "compilation terminated" }
Index: testsuite/g++.dg/cpp0x/decltype28.C
===================================================================
--- testsuite/g++.dg/cpp0x/decltype28.C	(revision 215708)
+++ testsuite/g++.dg/cpp0x/decltype28.C	(working copy)
@@ -14,3 +14,5 @@  ft (F f, typename enable_if<N==0, int>::type) {}
 int main() {
   ft<struct a*, 2> (0, 0);	// { dg-message "from here" }
 }
+
+// { dg-prune-output "compilation terminated" }
Index: testsuite/g++.dg/cpp0x/decltype29.C
===================================================================
--- testsuite/g++.dg/cpp0x/decltype29.C	(revision 215708)
+++ testsuite/g++.dg/cpp0x/decltype29.C	(working copy)
@@ -13,7 +13,7 @@  decltype (ft<F> (F()))		// { dg-error "depth" }
 ft() {}
 
 int main() {
-    ft<struct a*, 0>();		// { dg-error "no match|wrong number" }
+    ft<struct a*, 0>();		// { dg-message "from here" }
 }
 
-// { dg-prune-output "note" }
+// { dg-prune-output "compilation terminated" }
Index: testsuite/g++.dg/cpp0x/decltype32.C
===================================================================
--- testsuite/g++.dg/cpp0x/decltype32.C	(revision 215708)
+++ testsuite/g++.dg/cpp0x/decltype32.C	(working copy)
@@ -4,7 +4,7 @@ 
 
 template <typename T>
 auto make_array(const T& il) ->
-decltype(make_array(il))    // { dg-error "not declared|no matching|exceeds" }
+decltype(make_array(il))    // { dg-error "not declared|no matching|depth" }
 { }
 
 int main()
@@ -11,3 +11,5 @@  int main()
 {
   int z = make_array(1);    // { dg-error "no matching" }
 }
+
+// { dg-prune-output "compilation terminated" }
Index: testsuite/g++.dg/cpp0x/enum11.C
===================================================================
--- testsuite/g++.dg/cpp0x/enum11.C	(revision 215708)
+++ testsuite/g++.dg/cpp0x/enum11.C	(working copy)
@@ -4,12 +4,10 @@ 
 
 template<unsigned int N> struct Pair { };
 struct Foo { enum { Mask = 1 }; } foo;
-template<typename A, typename B> class Pair<A::Mask | B::Mask>
-operator|(const A &, const B &)	// { dg-message "substitution" }
+template<typename A, typename B> class Pair<A::Mask | B::Mask> // { dg-error "depth" }
+operator|(const A &, const B &)
 { }
 
-Pair<Foo::Mask> f = foo|foo;	// { dg-message "no match" }
+Pair<Foo::Mask> f = foo|foo;	// { dg-message "from here" }
 
-// { dg-prune-output "note" }
-// { dg-prune-output "here" }
-// { dg-prune-output "instantiation depth" }
+// { dg-prune-output "compilation terminated" }
Index: testsuite/g++.dg/template/arrow1.C
===================================================================
--- testsuite/g++.dg/template/arrow1.C	(revision 215708)
+++ testsuite/g++.dg/template/arrow1.C	(working copy)
@@ -9,9 +9,7 @@  struct a {
 };
 
 int main() {
-    a<0>()->x; // { dg-error "instantiation depth exceeds maximum" }
+    a<0>()->x; // { dg-error "depth" }
 }
 
-// { dg-prune-output "incomplete type" }
-// { dg-prune-output "declaration of" }
-// { dg-prune-output "used but never defined" }
+// { dg-prune-output "compilation terminated" }
Index: testsuite/g++.dg/template/pr23510.C
===================================================================
--- testsuite/g++.dg/template/pr23510.C	(revision 215708)
+++ testsuite/g++.dg/template/pr23510.C	(working copy)
@@ -3,21 +3,21 @@ 
 template<unsigned int nFactor>
 struct Factorial
 {
-  enum { nValue = nFactor * Factorial<nFactor - 1>::nValue }; // { dg-error "depth exceeds maximum" "exceeds" } 
-  // { dg-message "recursively required" "recurse" { target *-*-* } 6 }
-  // { dg-error "incomplete type" "incomplete" { target *-*-* } 6 } 
-} // { dg-error "expected ';' after" }
+  enum { nValue = nFactor * Factorial<nFactor - 1>::nValue }; // { dg-error "depth" } 
+};
 
-  template<>
-  struct Factorial<0>
-  {
-    enum { nValue = 1 };
-  };
+template<>
+struct Factorial<0>
+{
+  enum { nValue = 1 };
+};
 
-    static const unsigned int FACTOR = 20;
+static const unsigned int FACTOR = 20;
 
 int main()
 {
-  Factorial<FACTOR>::nValue;
+  Factorial<FACTOR>::nValue;  // { dg-message "from here" }
   return 0;
 }
+
+// { dg-prune-output "compilation terminated" }
Index: testsuite/g++.dg/template/recurse.C
===================================================================
--- testsuite/g++.dg/template/recurse.C	(revision 215708)
+++ testsuite/g++.dg/template/recurse.C	(working copy)
@@ -5,10 +5,8 @@  template <int I> struct F
 {
   int operator()()
     {
-      F<I+1> f;			// { dg-error "incomplete type" "incomplete" }
-				// { dg-bogus "exceeds maximum.*exceeds maximum" "exceeds" { xfail *-*-* } 8 }
-                                // { dg-error "exceeds maximum" "exceeds" { xfail *-*-* } 8 }
-      return f()*I;             // { dg-message "recursively" "recurse" }
+      F<I+1> f;			// { dg-error "depth" }
+      return f()*I;
     }
 };
 
@@ -20,8 +18,7 @@  template <> struct F<52>
 int main ()
 {
   F<1> f;
-  return f();		// { dg-message "from here" "excessive recursion" }
+  return f();		// { dg-message "from here" }
 }
 
-// Ignore excess messages from recursion.
-// { dg-prune-output "from 'int" }
+// { dg-prune-output "compilation terminated" }
Index: testsuite/g++.dg/template/recurse2.C
===================================================================
--- testsuite/g++.dg/template/recurse2.C	(revision 215708)
+++ testsuite/g++.dg/template/recurse2.C	(working copy)
@@ -2,7 +2,8 @@ 
 // We should not see an error about non-constant initialization.
 
 template <int N> struct X {
-    static const int value = X<N-1>::value; // { dg-error "instantiation|incomplete" }
-  // { dg-message "recursively required" "" { target *-*-* } 5 }
+    static const int value = X<N-1>::value; // { dg-error "depth" }
 };
 template struct X<1000>;
+
+// { dg-prune-output "compilation terminated" }
Index: testsuite/g++.dg/template/vtable2.C
===================================================================
--- testsuite/g++.dg/template/vtable2.C	(revision 215708)
+++ testsuite/g++.dg/template/vtable2.C	(working copy)
@@ -11,8 +11,10 @@ 
 template <class T> struct inner {};
 
 template <class T> struct parent {
-  virtual void f()			// { dg-error "instantiation depth" }
+  virtual void f()			// { dg-error "depth" }
     { parent<inner<T> > p; };
 };
 
 template struct parent<int>;
+
+// { dg-prune-output "compilation terminated" }
Index: testsuite/g++.old-deja/g++.pt/infinite1.C
===================================================================
--- testsuite/g++.old-deja/g++.pt/infinite1.C	(revision 215708)
+++ testsuite/g++.old-deja/g++.pt/infinite1.C	(working copy)
@@ -20,4 +20,4 @@  int main()
   f<0>();
 }
 
-// { dg-prune-output "note" }
+// { dg-prune-output "compilation terminated" }
Index: testsuite/lib/g++.exp
===================================================================
--- testsuite/lib/g++.exp	(revision 215708)
+++ testsuite/lib/g++.exp	(working copy)
@@ -267,7 +267,7 @@  proc g++_init { args } {
     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: testsuite/lib/gcc.exp
===================================================================
--- testsuite/lib/gcc.exp	(revision 215708)
+++ testsuite/lib/gcc.exp	(working copy)
@@ -111,7 +111,7 @@  proc gcc_init { args } {
     }
 
     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: testsuite/lib/obj-c++.exp
===================================================================
--- testsuite/lib/obj-c++.exp	(revision 215708)
+++ testsuite/lib/obj-c++.exp	(working copy)
@@ -275,7 +275,7 @@  proc obj-c++_init { args } {
     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: testsuite/lib/objc.exp
===================================================================
--- testsuite/lib/objc.exp	(revision 215708)
+++ testsuite/lib/objc.exp	(working copy)
@@ -124,7 +124,7 @@  proc objc_init { args } {
     }
 
     set gcc_warning_prefix "warning:"
-    set gcc_error_prefix "error:"
+    set gcc_error_prefix "(fatal )?error:"
 
     objc_maybe_build_wrapper "${tmpdir}/objc-testglue.o"