#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:
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 *);
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. */
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));
{
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:
}
+/* 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. */
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;
--- /dev/null
+/* 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 } */
+}
--- /dev/null
+/* 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 } */
+}