https://gcc.gnu.org/g:a6c2248cfd4bc922378f554578ee44e6b4690f5d

commit r15-9124-ga6c2248cfd4bc922378f554578ee44e6b4690f5d
Author: Jakub Jelinek <ja...@redhat.com>
Date:   Tue Apr 1 11:40:58 2025 +0200

    gimple-low: Diagnose assume attr expressions defining labels which are used 
as unary && operands outside of those [PR119537]
    
    The following testcases ICE on invalid code which defines
    labels inside of statement expressions and then uses &&label
    from code outside of the statement expressions.
    The C++ FE diagnoses that with a warning (not specifically for
    assume attribute, genericallly about taking address of a label
    outside of a statement expression so computed goto could violate
    the requirement that statement expression is not entered from
    outside of it through a jump into it), the C FE doesn't diagnose
    anything.
    Normal direct gotos to such labels are diagnosed by both C and C++.
    In the assume attribute case it is actually worse than for
    addresses of labels in normal statement expressions, in that case
    the labels are still in the current function, so invalid program
    can still jump to those (and in case of OpenMP/OpenACC where it
    is also invalid and stuff is moved to a separate function, such
    movement is done post cfg discovery of FORCED_LABELs and worst
    case one can run into cases which fail to assemble, but I haven't
    succeeded in creating ICE for that).
    For assume at -O0 we'd just throw away the assume expression if
    it is not a simple condition and so the label is then not defined
    anywhere and we ICE during cfg pass.
    The gimplify.cc hunks fix that, as we don't have FORCED_LABELs
    discovery done yet, it preserves all assume expressions which contain
    used user labels.
    With that we ICE during IRA, which is upset about an indirect jump
    to a label which doesn't exist.
    So, the gimple-low.cc hunks add diagnostics of the problem, it gathers
    uids of all the user used labels inside of the assume expressions (usually
    none) and if it finds any, walks the IL to find uses of those from outside
    of those expressions now outlined into separate magic functions.
    
    2025-04-01  Jakub Jelinek  <ja...@redhat.com>
    
            PR middle-end/119537
            * gimplify.cc (find_used_user_labels): New function.
            (gimplify_call_expr): Don't remove complex assume expression at -O0
            if it defines any user labels.
            * gimple-low.cc: Include diagnostic-core.h.
            (assume_labels): New variable.
            (diagnose_assume_labels): New function.
            (lower_function_body): Call it via walk_gimple_seq if assume_labels
            is non-NULL, then BITMAP_FREE assume_labels.
            (find_assumption_locals_r): Record in assume_labels uids of user
            labels defined in assume attribute expressions.
    
            * c-c++-common/pr119537-1.c: New test.
            * c-c++-common/pr119537-2.c: New test.

Diff:
---
 gcc/gimple-low.cc                       | 43 +++++++++++++++++++++++++++++++++
 gcc/gimplify.cc                         | 25 +++++++++++++++++--
 gcc/testsuite/c-c++-common/pr119537-1.c | 23 ++++++++++++++++++
 gcc/testsuite/c-c++-common/pr119537-2.c | 23 ++++++++++++++++++
 4 files changed, 112 insertions(+), 2 deletions(-)

diff --git a/gcc/gimple-low.cc b/gcc/gimple-low.cc
index b612970a55ac..79cdd7763dad 100644
--- a/gcc/gimple-low.cc
+++ b/gcc/gimple-low.cc
@@ -41,6 +41,7 @@ along with GCC; see the file COPYING3.  If not see
 #include "tree-inline.h"
 #include "gimple-walk.h"
 #include "attribs.h"
+#include "diagnostic-core.h"
 
 /* The differences between High GIMPLE and Low GIMPLE are the
    following:
@@ -78,6 +79,10 @@ struct lower_data
   bool cannot_fallthru;
 };
 
+/* Bitmap of LABEL_DECL uids for user labels moved into assume outlined
+   functions.  */
+static bitmap assume_labels;
+
 static void lower_stmt (gimple_stmt_iterator *, struct lower_data *);
 static void lower_gimple_bind (gimple_stmt_iterator *, struct lower_data *);
 static void lower_try_catch (gimple_stmt_iterator *, struct lower_data *);
@@ -87,6 +92,29 @@ static void lower_builtin_posix_memalign 
(gimple_stmt_iterator *);
 static void lower_builtin_assume_aligned (gimple_stmt_iterator *);
 
 
+/* Helper function for lower_function_body, called via walk_gimple_seq.
+   Diagnose uses of user labels defined inside of assume attribute
+   expressions.  */
+
+static tree
+diagnose_assume_labels (tree *tp, int *, void *data)
+{
+  if (TREE_CODE (*tp) == LABEL_DECL
+      && !DECL_ARTIFICIAL (*tp)
+      && DECL_NAME (*tp)
+      && bitmap_bit_p (assume_labels, DECL_UID (*tp)))
+    {
+      struct walk_stmt_info *wi = (struct walk_stmt_info *) data;
+      auto_diagnostic_group d;
+      error_at (gimple_location (gsi_stmt (wi->gsi)),
+               "reference to label %qD defined inside of %<assume%> "
+               "attribute expression from outside of the attribute", *tp);
+      inform (DECL_SOURCE_LOCATION (*tp), "%qD defined here", *tp);
+    }
+  return NULL_TREE;
+}
+
+
 /* Lower the body of current_function_decl from High GIMPLE into Low
    GIMPLE.  */
 
@@ -169,6 +197,15 @@ lower_function_body (void)
      lowered sequence.  */
   gimple_set_body (current_function_decl, lowered_body);
 
+  if (assume_labels)
+    {
+      struct walk_stmt_info wi;
+
+      memset (&wi, 0, sizeof (wi));
+      walk_gimple_seq (lowered_body, NULL, diagnose_assume_labels, &wi);
+      BITMAP_FREE (assume_labels);
+    }
+
   gcc_assert (data.block == DECL_INITIAL (current_function_decl));
   BLOCK_SUBBLOCKS (data.block)
     = blocks_nreverse (BLOCK_SUBBLOCKS (data.block));
@@ -335,6 +372,12 @@ find_assumption_locals_r (gimple_stmt_iterator *gsi_p, 
bool *,
       {
        tree label = gimple_label_label (as_a <glabel *> (stmt));
        data->id.decl_map->put (label, label);
+       if (DECL_NAME (label) && !DECL_ARTIFICIAL (label))
+         {
+           if (assume_labels == NULL)
+             assume_labels = BITMAP_ALLOC (NULL);
+           bitmap_set_bit (assume_labels, DECL_UID (label));
+         }
        break;
       }
     case GIMPLE_RETURN:
diff --git a/gcc/gimplify.cc b/gcc/gimplify.cc
index 02ad3981adf0..e90220cc2a05 100644
--- a/gcc/gimplify.cc
+++ b/gcc/gimplify.cc
@@ -4504,6 +4504,21 @@ gimplify_variant_call_expr (tree expr, fallback_t 
fallback,
 }
 
 
+/* Helper function for gimplify_call_expr, called via walk_tree.
+   Find used user labels.  */
+
+static tree
+find_used_user_labels (tree *tp, int *, void *)
+{
+  if (TREE_CODE (*tp) == LABEL_EXPR
+      && !DECL_ARTIFICIAL (LABEL_EXPR_LABEL (*tp))
+      && DECL_NAME (LABEL_EXPR_LABEL (*tp))
+      && TREE_USED (LABEL_EXPR_LABEL (*tp)))
+    return *tp;
+  return NULL_TREE;
+}
+
+
 /* Gimplify the CALL_EXPR node *EXPR_P into the GIMPLE sequence PRE_P.
    WANT_VALUE is true if the result of the call is desired.  */
 
@@ -4564,8 +4579,14 @@ gimplify_call_expr (tree *expr_p, gimple_seq *pre_p, 
fallback_t fallback)
                                                   fndecl, 0));
                  return GS_OK;
                }
-             /* If not optimizing, ignore the assumptions.  */
-             if (!optimize || seen_error ())
+             /* If not optimizing, ignore the assumptions unless there
+                are used user labels in it.  */
+             if ((!optimize
+                  && !walk_tree_without_duplicates (&CALL_EXPR_ARG (*expr_p,
+                                                                    0),
+                                                    find_used_user_labels,
+                                                    NULL))
+                 || seen_error ())
                {
                  *expr_p = NULL_TREE;
                  return GS_ALL_DONE;
diff --git a/gcc/testsuite/c-c++-common/pr119537-1.c 
b/gcc/testsuite/c-c++-common/pr119537-1.c
new file mode 100644
index 000000000000..7959826d9f76
--- /dev/null
+++ b/gcc/testsuite/c-c++-common/pr119537-1.c
@@ -0,0 +1,23 @@
+/* PR middle-end/119537 */
+/* { dg-do compile } */
+/* { dg-options "-O0" } */
+
+volatile int v;
+void *bar (void *, void *);
+
+void
+foo (bool z)
+{
+  if (z)
+    goto *&&x;                         /* { dg-error "reference to label 'x' 
defined inside of 'assume' attribute expression from outside of the attribute" 
} */
+                                       /* { dg-message "as a possible target 
of computed goto" "" { target c++ } .-1 } */
+  [[gnu::assume (({ x: v += 1; true; }))]];/* { dg-message "'x' defined here" 
} */
+                                       /* { dg-warning "jump to label 'x'" "" 
{ target c++ } .-1 } */
+                                       /* { dg-message "enters statement 
expression" "" { target c++ } .-2 } */
+  [[gnu::assume (({ y: v += 1; true; }))]];/* { dg-message "'y' defined here" 
} */
+                                       /* { dg-warning "jump to label 'y'" "" 
{ target c++ } .-1 } */
+  goto *bar (&&x, &&y);                        /* { dg-error "reference to 
label 'x' defined inside of 'assume' attribute expression from outside of the 
attribute" } */
+                                       /* { dg-error "reference to label 'y' 
defined inside of 'assume' attribute expression from outside of the attribute" 
"" { target *-*-* } .-1 } */
+                                       /* { dg-message "as a possible target 
of computed goto" "" { target c++ } .-2 } */
+                                       /* { dg-message "enters statement 
expression" "" { target c++ } .-3 } */
+}
diff --git a/gcc/testsuite/c-c++-common/pr119537-2.c 
b/gcc/testsuite/c-c++-common/pr119537-2.c
new file mode 100644
index 000000000000..7d65672448ac
--- /dev/null
+++ b/gcc/testsuite/c-c++-common/pr119537-2.c
@@ -0,0 +1,23 @@
+/* PR middle-end/119537 */
+/* { dg-do compile } */
+/* { dg-options "-O2" } */
+
+volatile int v;
+void *bar (void *, void *);
+
+void
+foo (bool z)
+{
+  if (z)
+    goto *&&x;                         /* { dg-error "reference to label 'x' 
defined inside of 'assume' attribute expression from outside of the attribute" 
} */
+                                       /* { dg-message "as a possible target 
of computed goto" "" { target c++ } .-1 } */
+  [[gnu::assume (({ x: v += 1; true; }))]];/* { dg-message "'x' defined here" 
} */
+                                       /* { dg-warning "jump to label 'x'" "" 
{ target c++ } .-1 } */
+                                       /* { dg-message "enters statement 
expression" "" { target c++ } .-2 } */
+  [[gnu::assume (({ y: v += 1; true; }))]];/* { dg-message "'y' defined here" 
} */
+                                       /* { dg-warning "jump to label 'y'" "" 
{ target c++ } .-1 } */
+  goto *bar (&&x, &&y);                        /* { dg-error "reference to 
label 'x' defined inside of 'assume' attribute expression from outside of the 
attribute" } */
+                                       /* { dg-error "reference to label 'y' 
defined inside of 'assume' attribute expression from outside of the attribute" 
"" { target *-*-* } .-1 } */
+                                       /* { dg-message "as a possible target 
of computed goto" "" { target c++ } .-2 } */
+                                       /* { dg-message "enters statement 
expression" "" { target c++ } .-3 } */
+}

Reply via email to