On 5/9/25 11:37 AM, Simon Martin wrote:
Several gcc_assert through the C++ front-end involve seen_error (), that
does not take into account errors that were turned into warnings due to
-fpermissive or -Wtemplate-body.
Running the full C++ testsuite when forcing the use of -fpermissive
leads to ICEs for 6 tests (see list in ticket); one could consider those
as reject-valid cases.
This patch keeps track of whether we tried to emit an error (whether it
was eventually output as such or not) and uses this in seen_error.
Why isn't the current erroneous_templates code sufficient? At a glance,
it seems like the problem might be get_current_template returning the
lambda, which never gets passed to maybe_diagnose_erroneous_template.
The merge_exception_specifiers change is OK.
Successfully tested on x86_64-pc-linux-gnu.
PR c++/118388
gcc/cp/ChangeLog:
* error.cc (seen_error_raw): New counter to keep track of errors
including those downgraded to warnings.
(cp_seen_error): Take downgraded errors into account.
* typeck2.cc (merge_exception_specifiers): Use seen_error
instead of errorcount.
gcc/testsuite/ChangeLog:
* g++.dg/cpp0x/lambda/lambda-ice5-fpermissive.C: New test.
* g++.dg/cpp0x/noexcept128-fpermissive.C: New test.
---
gcc/cp/error.cc | 54 +++++++++----------
gcc/cp/typeck2.cc | 2 +-
.../cpp0x/lambda/lambda-ice5-fpermissive.C | 14 +++++
.../g++.dg/cpp0x/noexcept128-fpermissive.C | 21 ++++++++
4 files changed, 63 insertions(+), 28 deletions(-)
create mode 100644 gcc/testsuite/g++.dg/cpp0x/lambda/lambda-ice5-fpermissive.C
create mode 100644 gcc/testsuite/g++.dg/cpp0x/noexcept128-fpermissive.C
diff --git a/gcc/cp/error.cc b/gcc/cp/error.cc
index 75bf7dcef62..78ecafb0e02 100644
--- a/gcc/cp/error.cc
+++ b/gcc/cp/error.cc
@@ -215,6 +215,11 @@ get_current_template ()
erroneous_templates_t *erroneous_templates;
+/* SEEN_ERROR_RAW will be true if we tried to emit an error message, regardless
+ of whether it was actually output or downgraded to a warning. */
+
+bool seen_error_raw = false;
+
/* Callback function diagnostic_context::m_adjust_diagnostic_info.
Errors issued when parsing a template are automatically treated like
@@ -227,40 +232,35 @@ cp_adjust_diagnostic_info (diagnostic_context *context,
diagnostic_info *diagnostic)
{
if (diagnostic->kind == DK_ERROR)
- if (tree tmpl = get_current_template ())
- {
- diagnostic->option_id = OPT_Wtemplate_body;
-
- if (context->m_permissive)
- diagnostic->kind = DK_WARNING;
-
- bool existed;
- location_t &error_loc
- = hash_map_safe_get_or_insert<true> (erroneous_templates,
- tmpl, &existed);
- if (!existed)
- /* Remember that this template had a parse-time error so
- that we'll ensure a hard error has been issued upon
- its instantiation. */
- error_loc = diagnostic->richloc->get_loc ();
- }
+ {
+ seen_error_raw = true;
+ if (tree tmpl = get_current_template ())
+ {
+ diagnostic->option_id = OPT_Wtemplate_body;
+
+ if (context->m_permissive)
+ diagnostic->kind = DK_WARNING;
+
+ bool existed;
+ location_t &error_loc
+ = hash_map_safe_get_or_insert<true> (erroneous_templates,
+ tmpl, &existed);
+ if (!existed)
+ /* Remember that this template had a parse-time error so
+ that we'll ensure a hard error has been issued upon
+ its instantiation. */
+ error_loc = diagnostic->richloc->get_loc ();
+ }
+ }
}
/* A generalization of seen_error which also returns true if we've
- permissively downgraded an error to a warning inside a template. */
+ permissively downgraded an error to a warning. */
bool
cp_seen_error ()
{
- if ((seen_error) ())
- return true;
-
- if (erroneous_templates)
- if (tree tmpl = get_current_template ())
- if (erroneous_templates->get (tmpl))
- return true;
-
- return false;
+ return (seen_error) () || seen_error_raw;
}
/* CONTEXT->printer is a basic pretty printer that was constructed
diff --git a/gcc/cp/typeck2.cc b/gcc/cp/typeck2.cc
index 45edd180173..a2d230461c4 100644
--- a/gcc/cp/typeck2.cc
+++ b/gcc/cp/typeck2.cc
@@ -2726,7 +2726,7 @@ merge_exception_specifiers (tree list, tree add)
return add;
noex = TREE_PURPOSE (list);
gcc_checking_assert (!TREE_PURPOSE (add)
- || errorcount || !flag_exceptions
+ || seen_error () || !flag_exceptions
|| cp_tree_equal (noex, TREE_PURPOSE (add)));
/* Combine the dynamic-exception-specifiers, if any. */
diff --git a/gcc/testsuite/g++.dg/cpp0x/lambda/lambda-ice5-fpermissive.C
b/gcc/testsuite/g++.dg/cpp0x/lambda/lambda-ice5-fpermissive.C
new file mode 100644
index 00000000000..11300ad23e0
--- /dev/null
+++ b/gcc/testsuite/g++.dg/cpp0x/lambda/lambda-ice5-fpermissive.C
@@ -0,0 +1,14 @@
+// PR c++/118388
+// { dg-do compile { target c++11 } }
+// { dg-additional-options "-fpermissive" }
+
+template<int> int foo()
+{
+ [] (void i) { return 0; } (0); // { dg-warning "incomplete|invalid|no match"
}
+ return 0;
+}
+
+void bar()
+{
+ foo<0>();
+}
diff --git a/gcc/testsuite/g++.dg/cpp0x/noexcept128-fpermissive.C
b/gcc/testsuite/g++.dg/cpp0x/noexcept128-fpermissive.C
new file mode 100644
index 00000000000..dfc9629cb06
--- /dev/null
+++ b/gcc/testsuite/g++.dg/cpp0x/noexcept128-fpermissive.C
@@ -0,0 +1,21 @@
+// PR c++/118388
+// { dg-do compile { target c++11 } }
+// { dg-additional-options "-fpermissive" }
+
+template<typename T>
+struct traits
+{
+ static constexpr bool foo() { return sizeof(T) > 1; }
+ static constexpr bool bar() { return sizeof(T) > 1; }
+};
+
+template<typename T>
+struct X
+{
+ X& operator=(X&&) noexcept(traits<T>::foo());
+};
+
+template<typename T>
+ X<T>&
+ X<T>::operator=(X&&) noexcept(traits<T>::foo() && traits<T>::bar()) // { dg-warning
"different exception" }
+ { return *this; }