]> git.ipfire.org Git - thirdparty/gcc.git/commitdiff
c++: fix reporting routines re-entered [PR119303]
authorMarek Polacek <polacek@redhat.com>
Thu, 27 Mar 2025 19:03:18 +0000 (15:03 -0400)
committerMarek Polacek <polacek@redhat.com>
Mon, 31 Mar 2025 14:35:12 +0000 (10:35 -0400)
We crash while we call warning_at ("inline function used but never defined")
since it invokes dump_template_bindings -> tsubst -> ... -> convert_like ->
... -> c_common_truthvalue_conversion -> warning_at ("enum constant in boolean
     context")

cp_truthvalue_conversion correctly gets complain=0 but it calls
c_common_truthvalue_conversion from c-family which doesn't have
a similar parameter.

We can fix this by tweaking diagnostic_context::report_diagnostic to
check for recursion after checking if the diagnostic was enabled.

PR c++/116960
PR c++/119303

gcc/ChangeLog:

* diagnostic.cc (diagnostic_context::report_diagnostic): Check for
non-zero m_lock later, after checking diagnostic_enabled.

gcc/testsuite/ChangeLog:

* g++.dg/cpp2a/lambda-uneval26.C: New test.
* g++.dg/warn/undefined2.C: New test.

Reviewed-by: Jason Merrill <jason@redhat.com>
gcc/diagnostic.cc
gcc/testsuite/g++.dg/cpp2a/lambda-uneval26.C [new file with mode: 0644]
gcc/testsuite/g++.dg/warn/undefined2.C [new file with mode: 0644]

index 82d7f946818b2982cf9c11d4a3e6920034290676..07c76b6c6526d4e6886c1f9cc5fd68817898e02a 100644 (file)
@@ -1398,18 +1398,6 @@ diagnostic_context::report_diagnostic (diagnostic_info *diagnostic)
   if (diagnostic->kind == DK_NOTE && m_inhibit_notes_p)
     return false;
 
-  if (m_lock > 0)
-    {
-      /* If we're reporting an ICE in the middle of some other error,
-        try to flush out the previous error, then let this one
-        through.  Don't do this more than once.  */
-      if ((diagnostic->kind == DK_ICE || diagnostic->kind == DK_ICE_NOBT)
-         && m_lock == 1)
-       pp_newline_and_flush (m_reference_printer);
-      else
-       error_recursion ();
-    }
-
   /* If the user requested that warnings be treated as errors, so be
      it.  Note that we do this before the next block so that
      individual warnings can be overridden back to warnings with
@@ -1437,6 +1425,18 @@ diagnostic_context::report_diagnostic (diagnostic_info *diagnostic)
   if (diagnostic->kind != DK_NOTE && diagnostic->kind != DK_ICE)
     check_max_errors (false);
 
+  if (m_lock > 0)
+    {
+      /* If we're reporting an ICE in the middle of some other error,
+        try to flush out the previous error, then let this one
+        through.  Don't do this more than once.  */
+      if ((diagnostic->kind == DK_ICE || diagnostic->kind == DK_ICE_NOBT)
+         && m_lock == 1)
+       pp_newline_and_flush (m_reference_printer);
+      else
+       error_recursion ();
+    }
+
   m_lock++;
 
   if (diagnostic->kind == DK_ICE || diagnostic->kind == DK_ICE_NOBT)
diff --git a/gcc/testsuite/g++.dg/cpp2a/lambda-uneval26.C b/gcc/testsuite/g++.dg/cpp2a/lambda-uneval26.C
new file mode 100644 (file)
index 0000000..3e3097b
--- /dev/null
@@ -0,0 +1,10 @@
+// PR c++/116960
+// { dg-do compile { target c++20 } }
+
+template<auto>
+using Foo = decltype([](auto) { return 0; }(0));
+
+template<typename...>
+Foo<[] {}> foo() {}   // { dg-warning "no return statement" }
+
+auto t = foo();
diff --git a/gcc/testsuite/g++.dg/warn/undefined2.C b/gcc/testsuite/g++.dg/warn/undefined2.C
new file mode 100644 (file)
index 0000000..1b2ec35
--- /dev/null
@@ -0,0 +1,14 @@
+// PR c++/119303
+
+template <class> struct c {
+  enum { d = 4 };
+};
+template <bool> struct e {
+  typedef void g;
+};
+template <class _Tp>
+inline typename e<!c<_Tp>::d>::g bar(_Tp); // { dg-warning "used but never defined" }
+
+int x;
+
+void foo() { bar(x); }