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.

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; }
-- 
2.44.0

Reply via email to