diff mbox series

c++: goto entering scope of obj w/ non-trivial dtor [PR103091]

Message ID 20230505173648.1593931-1-ppalka@redhat.com
State New
Headers show
Series c++: goto entering scope of obj w/ non-trivial dtor [PR103091] | expand

Commit Message

Patrick Palka May 5, 2023, 5:36 p.m. UTC
It seems DR 2256 permitted goto to cross the initialization of a
trivially initialized object with a non-trivial destructor.  We
already supported this as an -fpermissive extension, so this patch
just makes us unconditionally support this.

Bootstrapped and regtested on x86_64-pc-linux-gnu, does this look OK
for trunk?

	DR 2256
	PR c++/103091

gcc/cp/ChangeLog:

	* decl.cc (decl_jump_unsafe): Return bool instead of int.
	Don't consider TYPE_HAS_NONTRIVIAL_DESTRUCTOR.
	(check_previous_goto_1): Simplify now that decl_jump_unsafe
	returns bool instead of int.
	(check_goto): Likewise.

gcc/testsuite/ChangeLog:

	* g++.old-deja/g++.other/init9.C: Don't expect diagnostics for
	goto made valid by DR 2256.
	* g++.dg/init/goto4.C: New test.
---
 gcc/cp/decl.cc                               | 56 ++++++--------------
 gcc/testsuite/g++.dg/init/goto4.C            | 22 ++++++++
 gcc/testsuite/g++.old-deja/g++.other/init9.C |  7 +--
 3 files changed, 42 insertions(+), 43 deletions(-)
 create mode 100644 gcc/testsuite/g++.dg/init/goto4.C

Comments

Jason Merrill May 5, 2023, 6:18 p.m. UTC | #1
On 5/5/23 13:36, Patrick Palka wrote:
> It seems DR 2256 permitted goto to cross the initialization of a
> trivially initialized object with a non-trivial destructor.  We
> already supported this as an -fpermissive extension, so this patch
> just makes us unconditionally support this.
> 
> Bootstrapped and regtested on x86_64-pc-linux-gnu, does this look OK
> for trunk?

OK.

> 	DR 2256
> 	PR c++/103091
> 
> gcc/cp/ChangeLog:
> 
> 	* decl.cc (decl_jump_unsafe): Return bool instead of int.
> 	Don't consider TYPE_HAS_NONTRIVIAL_DESTRUCTOR.
> 	(check_previous_goto_1): Simplify now that decl_jump_unsafe
> 	returns bool instead of int.
> 	(check_goto): Likewise.
> 
> gcc/testsuite/ChangeLog:
> 
> 	* g++.old-deja/g++.other/init9.C: Don't expect diagnostics for
> 	goto made valid by DR 2256.
> 	* g++.dg/init/goto4.C: New test.
> ---
>   gcc/cp/decl.cc                               | 56 ++++++--------------
>   gcc/testsuite/g++.dg/init/goto4.C            | 22 ++++++++
>   gcc/testsuite/g++.old-deja/g++.other/init9.C |  7 +--
>   3 files changed, 42 insertions(+), 43 deletions(-)
>   create mode 100644 gcc/testsuite/g++.dg/init/goto4.C
> 
> diff --git a/gcc/cp/decl.cc b/gcc/cp/decl.cc
> index 71d33d2b7a4..23a2b2fef0b 100644
> --- a/gcc/cp/decl.cc
> +++ b/gcc/cp/decl.cc
> @@ -69,7 +69,7 @@ enum bad_spec_place {
>   
>   static const char *redeclaration_error_message (tree, tree);
>   
> -static int decl_jump_unsafe (tree);
> +static bool decl_jump_unsafe (tree);
>   static void require_complete_types_for_parms (tree);
>   static tree grok_reference_init (tree, tree, tree, int);
>   static tree grokvardecl (tree, tree, tree, const cp_decl_specifier_seq *,
> @@ -3548,10 +3548,9 @@ declare_local_label (tree id)
>     return ent ? ent->label_decl : NULL_TREE;
>   }
>   
> -/* Returns nonzero if it is ill-formed to jump past the declaration of
> -   DECL.  Returns 2 if it's also a real problem.  */
> +/* Returns true if it is ill-formed to jump past the declaration of DECL.  */
>   
> -static int
> +static bool
>   decl_jump_unsafe (tree decl)
>   {
>     /* [stmt.dcl]/3: A program that jumps from a point where a local variable
> @@ -3562,18 +3561,11 @@ decl_jump_unsafe (tree decl)
>        preceding types and is declared without an initializer (8.5).  */
>     tree type = TREE_TYPE (decl);
>   
> -  if (!VAR_P (decl) || TREE_STATIC (decl)
> -      || type == error_mark_node)
> -    return 0;
> -
> -  if (DECL_NONTRIVIALLY_INITIALIZED_P (decl)
> -      || variably_modified_type_p (type, NULL_TREE))
> -    return 2;
> -
> -  if (TYPE_HAS_NONTRIVIAL_DESTRUCTOR (type))
> -    return 1;
> -
> -  return 0;
> +  return (type != error_mark_node
> +	  && VAR_P (decl)
> +	  && !TREE_STATIC (decl)
> +	  && (DECL_NONTRIVIALLY_INITIALIZED_P (decl)
> +	      || variably_modified_type_p (type, NULL_TREE)));
>   }
>   
>   /* A subroutine of check_previous_goto_1 and check_goto to identify a branch
> @@ -3625,27 +3617,18 @@ check_previous_goto_1 (tree decl, cp_binding_level* level, tree names,
>   	   new_decls = (DECL_P (new_decls) ? DECL_CHAIN (new_decls)
>   			: TREE_CHAIN (new_decls)))
>   	{
> -	  int problem = decl_jump_unsafe (new_decls);
> +	  bool problem = decl_jump_unsafe (new_decls);
>   	  if (! problem)
>   	    continue;
>   
>   	  if (!identified)
>   	    {
> -	      complained = identify_goto (decl, input_location, locus,
> -					  problem > 1
> -					  ? DK_ERROR : DK_PERMERROR);
> +	      complained = identify_goto (decl, input_location, locus, DK_ERROR);
>   	      identified = 1;
>   	    }
>   	  if (complained)
> -	    {
> -	      if (problem > 1)
> -		inform (DECL_SOURCE_LOCATION (new_decls),
> -			"  crosses initialization of %q#D", new_decls);
> -	      else
> -		inform (DECL_SOURCE_LOCATION (new_decls),
> -			"  enters scope of %q#D, which has "
> -			"non-trivial destructor", new_decls);
> -	    }
> +	    inform (DECL_SOURCE_LOCATION (new_decls),
> +		    "  crosses initialization of %q#D", new_decls);
>   	}
>   
>         if (b == level)
> @@ -3790,9 +3773,9 @@ check_goto (tree decl)
>   
>     FOR_EACH_VEC_SAFE_ELT (ent->bad_decls, ix, bad)
>       {
> -      int u = decl_jump_unsafe (bad);
> +      bool problem = decl_jump_unsafe (bad);
>   
> -      if (u > 1 && DECL_ARTIFICIAL (bad))
> +      if (problem && DECL_ARTIFICIAL (bad))
>   	{
>   	  /* Can't skip init of __exception_info.  */
>   	  if (identified == 1)
> @@ -3806,15 +3789,8 @@ check_goto (tree decl)
>   	  saw_catch = true;
>   	}
>         else if (complained)
> -	{
> -	  if (u > 1)
> -	    inform (DECL_SOURCE_LOCATION (bad),
> -		    "  skips initialization of %q#D", bad);
> -	  else
> -	    inform (DECL_SOURCE_LOCATION (bad),
> -		    "  enters scope of %q#D which has "
> -		    "non-trivial destructor", bad);
> -	}
> +	inform (DECL_SOURCE_LOCATION (bad),
> +		"  skips initialization of %q#D", bad);
>       }
>   
>     if (complained)
> diff --git a/gcc/testsuite/g++.dg/init/goto4.C b/gcc/testsuite/g++.dg/init/goto4.C
> new file mode 100644
> index 00000000000..90ae52e6455
> --- /dev/null
> +++ b/gcc/testsuite/g++.dg/init/goto4.C
> @@ -0,0 +1,22 @@
> +// DR 2256
> +// PR c++/103091
> +// { dg-do run }
> +
> +static int i;
> +
> +struct A {
> +  ~A() { ++i;}
> +};
> +
> +void f() {
> +  goto L;
> +  A a;
> +L:
> +  return;
> +}
> +
> +int main() {
> +  f();
> +  if (i != 1)
> +    __builtin_abort();
> +}
> diff --git a/gcc/testsuite/g++.old-deja/g++.other/init9.C b/gcc/testsuite/g++.old-deja/g++.other/init9.C
> index 46d99028bdd..0194cd1b49a 100644
> --- a/gcc/testsuite/g++.old-deja/g++.other/init9.C
> +++ b/gcc/testsuite/g++.old-deja/g++.other/init9.C
> @@ -24,9 +24,10 @@ struct X {
>   };
>   
>   void b() {
> -  goto bar; // { dg-message "" } jump from here
> -  X x; // { dg-message "" } jump crosses initialization
> - bar: // { dg-error "" } jump to here
> +  // This was ill-formed until DR 2256.
> +  goto bar;
> +  X x;
> + bar:
>     ;
>   }
>
diff mbox series

Patch

diff --git a/gcc/cp/decl.cc b/gcc/cp/decl.cc
index 71d33d2b7a4..23a2b2fef0b 100644
--- a/gcc/cp/decl.cc
+++ b/gcc/cp/decl.cc
@@ -69,7 +69,7 @@  enum bad_spec_place {
 
 static const char *redeclaration_error_message (tree, tree);
 
-static int decl_jump_unsafe (tree);
+static bool decl_jump_unsafe (tree);
 static void require_complete_types_for_parms (tree);
 static tree grok_reference_init (tree, tree, tree, int);
 static tree grokvardecl (tree, tree, tree, const cp_decl_specifier_seq *,
@@ -3548,10 +3548,9 @@  declare_local_label (tree id)
   return ent ? ent->label_decl : NULL_TREE;
 }
 
-/* Returns nonzero if it is ill-formed to jump past the declaration of
-   DECL.  Returns 2 if it's also a real problem.  */
+/* Returns true if it is ill-formed to jump past the declaration of DECL.  */
 
-static int
+static bool
 decl_jump_unsafe (tree decl)
 {
   /* [stmt.dcl]/3: A program that jumps from a point where a local variable
@@ -3562,18 +3561,11 @@  decl_jump_unsafe (tree decl)
      preceding types and is declared without an initializer (8.5).  */
   tree type = TREE_TYPE (decl);
 
-  if (!VAR_P (decl) || TREE_STATIC (decl)
-      || type == error_mark_node)
-    return 0;
-
-  if (DECL_NONTRIVIALLY_INITIALIZED_P (decl)
-      || variably_modified_type_p (type, NULL_TREE))
-    return 2;
-
-  if (TYPE_HAS_NONTRIVIAL_DESTRUCTOR (type))
-    return 1;
-
-  return 0;
+  return (type != error_mark_node
+	  && VAR_P (decl)
+	  && !TREE_STATIC (decl)
+	  && (DECL_NONTRIVIALLY_INITIALIZED_P (decl)
+	      || variably_modified_type_p (type, NULL_TREE)));
 }
 
 /* A subroutine of check_previous_goto_1 and check_goto to identify a branch
@@ -3625,27 +3617,18 @@  check_previous_goto_1 (tree decl, cp_binding_level* level, tree names,
 	   new_decls = (DECL_P (new_decls) ? DECL_CHAIN (new_decls)
 			: TREE_CHAIN (new_decls)))
 	{
-	  int problem = decl_jump_unsafe (new_decls);
+	  bool problem = decl_jump_unsafe (new_decls);
 	  if (! problem)
 	    continue;
 
 	  if (!identified)
 	    {
-	      complained = identify_goto (decl, input_location, locus,
-					  problem > 1
-					  ? DK_ERROR : DK_PERMERROR);
+	      complained = identify_goto (decl, input_location, locus, DK_ERROR);
 	      identified = 1;
 	    }
 	  if (complained)
-	    {
-	      if (problem > 1)
-		inform (DECL_SOURCE_LOCATION (new_decls),
-			"  crosses initialization of %q#D", new_decls);
-	      else
-		inform (DECL_SOURCE_LOCATION (new_decls),
-			"  enters scope of %q#D, which has "
-			"non-trivial destructor", new_decls);
-	    }
+	    inform (DECL_SOURCE_LOCATION (new_decls),
+		    "  crosses initialization of %q#D", new_decls);
 	}
 
       if (b == level)
@@ -3790,9 +3773,9 @@  check_goto (tree decl)
 
   FOR_EACH_VEC_SAFE_ELT (ent->bad_decls, ix, bad)
     {
-      int u = decl_jump_unsafe (bad);
+      bool problem = decl_jump_unsafe (bad);
 
-      if (u > 1 && DECL_ARTIFICIAL (bad))
+      if (problem && DECL_ARTIFICIAL (bad))
 	{
 	  /* Can't skip init of __exception_info.  */
 	  if (identified == 1)
@@ -3806,15 +3789,8 @@  check_goto (tree decl)
 	  saw_catch = true;
 	}
       else if (complained)
-	{
-	  if (u > 1)
-	    inform (DECL_SOURCE_LOCATION (bad),
-		    "  skips initialization of %q#D", bad);
-	  else
-	    inform (DECL_SOURCE_LOCATION (bad),
-		    "  enters scope of %q#D which has "
-		    "non-trivial destructor", bad);
-	}
+	inform (DECL_SOURCE_LOCATION (bad),
+		"  skips initialization of %q#D", bad);
     }
 
   if (complained)
diff --git a/gcc/testsuite/g++.dg/init/goto4.C b/gcc/testsuite/g++.dg/init/goto4.C
new file mode 100644
index 00000000000..90ae52e6455
--- /dev/null
+++ b/gcc/testsuite/g++.dg/init/goto4.C
@@ -0,0 +1,22 @@ 
+// DR 2256
+// PR c++/103091
+// { dg-do run }
+
+static int i;
+
+struct A {
+  ~A() { ++i;}
+};
+
+void f() {
+  goto L;
+  A a;
+L:
+  return;
+}
+
+int main() {
+  f();
+  if (i != 1)
+    __builtin_abort();
+}
diff --git a/gcc/testsuite/g++.old-deja/g++.other/init9.C b/gcc/testsuite/g++.old-deja/g++.other/init9.C
index 46d99028bdd..0194cd1b49a 100644
--- a/gcc/testsuite/g++.old-deja/g++.other/init9.C
+++ b/gcc/testsuite/g++.old-deja/g++.other/init9.C
@@ -24,9 +24,10 @@  struct X {
 };
 
 void b() {
-  goto bar; // { dg-message "" } jump from here
-  X x; // { dg-message "" } jump crosses initialization
- bar: // { dg-error "" } jump to here
+  // This was ill-formed until DR 2256.
+  goto bar;
+  X x;
+ bar:
   ;
 }