Tested x86_64-pc-linux-gnu, applying to trunk.

-- 8< --

As with 37722, we don't clean up the exception object if a computed goto
leaves a catch block, but we can warn about that.

        PR c++/81438

gcc/cp/ChangeLog:

        * decl.cc (poplevel_named_label_1): Handle leaving catch.
        (check_previous_goto_1): Likewise.
        (check_goto_1): Likewise.

gcc/testsuite/ChangeLog:

        * g++.dg/ext/label15.C: Require indirect_jumps.
        * g++.dg/ext/label16.C: New test.
---
 gcc/cp/decl.cc                     | 42 ++++++++++++++++++++++++------
 gcc/testsuite/g++.dg/ext/label15.C |  1 +
 gcc/testsuite/g++.dg/ext/label16.C | 34 ++++++++++++++++++++++++
 3 files changed, 69 insertions(+), 8 deletions(-)
 create mode 100644 gcc/testsuite/g++.dg/ext/label16.C

diff --git a/gcc/cp/decl.cc b/gcc/cp/decl.cc
index e044bfa6701..6b4d89e7115 100644
--- a/gcc/cp/decl.cc
+++ b/gcc/cp/decl.cc
@@ -571,10 +571,14 @@ poplevel_named_label_1 (named_label_entry **slot, 
cp_binding_level *bl)
        if (use->binding_level == bl)
          {
            if (auto &cg = use->computed_goto)
-             for (tree d = use->names_in_scope; d; d = DECL_CHAIN (d))
-               if (TREE_CODE (d) == VAR_DECL && !TREE_STATIC (d)
-                   && TYPE_HAS_NONTRIVIAL_DESTRUCTOR (TREE_TYPE (d)))
-                 vec_safe_push (cg, d);
+             {
+               if (bl->kind == sk_catch)
+                 vec_safe_push (cg, get_identifier ("catch"));
+               for (tree d = use->names_in_scope; d; d = DECL_CHAIN (d))
+                 if (TREE_CODE (d) == VAR_DECL && !TREE_STATIC (d)
+                     && TYPE_HAS_NONTRIVIAL_DESTRUCTOR (TREE_TYPE (d)))
+                   vec_safe_push (cg, d);
+             }
 
            use->binding_level = obl;
            use->names_in_scope = obl->names;
@@ -3820,7 +3824,12 @@ check_previous_goto_1 (tree decl, cp_binding_level* 
level, tree names,
       identified = 2;
       if (complained)
        for (tree d : computed)
-         inform (DECL_SOURCE_LOCATION (d), "  does not destroy %qD", d);
+         {
+           if (DECL_P (d))
+             inform (DECL_SOURCE_LOCATION (d), "  does not destroy %qD", d);
+           else if (d == get_identifier ("catch"))
+             inform (*locus, "  does not clean up handled exception");
+         }
     }
 
   return !identified;
@@ -3963,15 +3972,32 @@ check_goto_1 (named_label_entry *ent, bool computed)
       auto names = ent->names_in_scope;
       for (auto b = current_binding_level; ; b = b->level_chain)
        {
+         if (b->kind == sk_catch)
+           {
+             if (!identified)
+               {
+                 complained
+                   = identify_goto (decl, DECL_SOURCE_LOCATION (decl),
+                                    &input_location, DK_ERROR, computed);
+                 identified = 2;
+               }
+             if (complained)
+               inform (input_location,
+                       "  does not clean up handled exception");
+           }
          tree end = b == level ? names : NULL_TREE;
          for (tree d = b->names; d != end; d = DECL_CHAIN (d))
            {
              if (TREE_CODE (d) == VAR_DECL && !TREE_STATIC (d)
                  && TYPE_HAS_NONTRIVIAL_DESTRUCTOR (TREE_TYPE (d)))
                {
-                 complained = identify_goto (decl, DECL_SOURCE_LOCATION (decl),
-                                             &input_location, DK_ERROR,
-                                             computed);
+                 if (!identified)
+                   {
+                     complained
+                       = identify_goto (decl, DECL_SOURCE_LOCATION (decl),
+                                        &input_location, DK_ERROR, computed);
+                     identified = 2;
+                   }
                  if (complained)
                    inform (DECL_SOURCE_LOCATION (d),
                            "  does not destroy %qD", d);
diff --git a/gcc/testsuite/g++.dg/ext/label15.C 
b/gcc/testsuite/g++.dg/ext/label15.C
index f9d6a0dd626..5a23895d52d 100644
--- a/gcc/testsuite/g++.dg/ext/label15.C
+++ b/gcc/testsuite/g++.dg/ext/label15.C
@@ -1,4 +1,5 @@
 // PR c++/37722
+// { dg-do compile { target indirect_jumps } }
 // { dg-options "" }
 
 extern "C" int printf (const char *, ...);
diff --git a/gcc/testsuite/g++.dg/ext/label16.C 
b/gcc/testsuite/g++.dg/ext/label16.C
new file mode 100644
index 00000000000..ea79b6ef1fc
--- /dev/null
+++ b/gcc/testsuite/g++.dg/ext/label16.C
@@ -0,0 +1,34 @@
+// PR c++/81438
+// { dg-do compile { target indirect_jumps } }
+// { dg-options "" }
+
+bool b;
+int main()
+{
+  try
+    {
+      try { throw 3; }
+      catch(...) {
+      h:;                      // { dg-warning "jump to label" }
+       try { throw 7; }
+       catch(...) {
+         if (b)
+           goto *&&h;          // { dg-message "computed goto" }
+                               // { dg-message "handled exception" "" { target 
*-*-* } .-1 }
+         else
+           goto *&&g;          // { dg-message "computed goto" }
+                               // { dg-message "handled exception" "" { target 
*-*-* } .-1 }
+       }
+      g:;                      // { dg-warning "jump to label" }
+       throw;
+      }
+    }
+  catch(int v)
+    {
+      __builtin_printf("%d\n", v);
+      if(v != 3)              // 7 because we don't clean up the catch on
+       __builtin_abort();     // computed goto
+    }
+
+  return 0;
+}

base-commit: d26f589e61a178e898d8b247042b487287ffe121
-- 
2.39.3

Reply via email to