On 3/28/25 12:46 PM, Marek Polacek wrote:
On Fri, Mar 28, 2025 at 11:49:48AM -0400, Jason Merrill wrote:
On 3/27/25 5:00 PM, Marek Polacek wrote:
On Wed, Mar 19, 2025 at 12:00:00PM -0400, Jason Merrill wrote:
On 3/17/25 6:55 PM, Marek Polacek wrote:
Bootstrapped/regtested on x86_64-pc-linux-gnu, ok for trunk?

-- >8 --
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.

It seems that we try to prevent this in cp_convert_and_check with

            warning_sentinel c (warn_int_in_bool_context);

which is why we don't get a warning when we first instantiate the template.

But that doesn't help when we rebuild the expression for
dump_template_bindings because the recursion check in report_diagnostic
comes before the check whether the diagnostic is actually enabled.

I think rather than adding another mechanism for suppressing warnings, I'd
like to make the existing ones work better by moving the recursion check
after the checks for disabled diagnostics.

Fair enough.  That happens to fix c++/116960 et al too.  Note that my
adding a complain parameter into c-family isn't entirely novel:
c_sizeof_or_alignof_type also has one.


Bootstrapped/regtested on x86_64-pc-linux-gnu, ok for trunk?

-- >8 --
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 only after diagnostic_enabled.

gcc/testsuite/ChangeLog:

        * g++.dg/cpp2a/lambda-uneval26.C: New test.
        * g++.dg/warn/undefined2.C: New test.
---
   gcc/diagnostic.cc                            | 24 ++++++++++----------
   gcc/testsuite/g++.dg/cpp2a/lambda-uneval26.C | 10 ++++++++
   gcc/testsuite/g++.dg/warn/undefined2.C       | 14 ++++++++++++
   3 files changed, 36 insertions(+), 12 deletions(-)
   create mode 100644 gcc/testsuite/g++.dg/cpp2a/lambda-uneval26.C
   create mode 100644 gcc/testsuite/g++.dg/warn/undefined2.C

diff --git a/gcc/diagnostic.cc b/gcc/diagnostic.cc
index 82d7f946818..425477ea5b2 100644
--- a/gcc/diagnostic.cc
+++ b/gcc/diagnostic.cc
@@ -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
@@ -1426,6 +1414,18 @@ diagnostic_context::report_diagnostic (diagnostic_info 
*diagnostic)
     if (!diagnostic_enabled (diagnostic))
       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 ();
+    }

Let's move this a little farther down, past...

     if ((was_warning || diagnostic->kind == DK_WARNING)
         && ((!m_warn_system_headers
           && diagnostic->m_iinfo.m_allsyslocs)

...this early exit, as well.

The m_lock check used to be right before the increment, until DJ's r109907
that added #pragma GCC diagnostic; it would make sense to me for them to be
together again.  I don't suppose it matters whether the check_max_errors is
before or after the m_lock handling.

Sure, thanks.

Bootstrapped/regtested on x86_64-pc-linux-gnu, ok for trunk?

OK, thanks.

-- >8 --
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.
---
  gcc/diagnostic.cc                            | 24 ++++++++++----------
  gcc/testsuite/g++.dg/cpp2a/lambda-uneval26.C | 10 ++++++++
  gcc/testsuite/g++.dg/warn/undefined2.C       | 14 ++++++++++++
  3 files changed, 36 insertions(+), 12 deletions(-)
  create mode 100644 gcc/testsuite/g++.dg/cpp2a/lambda-uneval26.C
  create mode 100644 gcc/testsuite/g++.dg/warn/undefined2.C

diff --git a/gcc/diagnostic.cc b/gcc/diagnostic.cc
index 82d7f946818..07c76b6c652 100644
--- a/gcc/diagnostic.cc
+++ b/gcc/diagnostic.cc
@@ -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
index 00000000000..3e3097bedcb
--- /dev/null
+++ b/gcc/testsuite/g++.dg/cpp2a/lambda-uneval26.C
@@ -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
index 00000000000..1b2ec353adb
--- /dev/null
+++ b/gcc/testsuite/g++.dg/warn/undefined2.C
@@ -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); }

base-commit: 58b59251ea22913ce0d5871db64f5d24f2b15493

Reply via email to