[pushed] c++: computed goto from catch block [PR81438]

Message ID 20231222031754.3556161-1-jason@redhat.com
State Unresolved
Headers
Series [pushed] c++: computed goto from catch block [PR81438] |

Checks

Context Check Description
snail/gcc-patch-check warning Git am fail log

Commit Message

Jason Merrill Dec. 22, 2023, 3:17 a.m. UTC
  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


base-commit: d26f589e61a178e898d8b247042b487287ffe121
  

Patch

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