store_parm_decls ();
}
+/* Called by walk_tree to look for and update context-less labels. */
+
+static tree
+set_labels_context_r (tree *tp, int *walk_subtrees, void *data)
+{
+ if (TREE_CODE (*tp) == LABEL_EXPR
+ && DECL_CONTEXT (LABEL_EXPR_LABEL (*tp)) == NULL_TREE)
+ {
+ DECL_CONTEXT (LABEL_EXPR_LABEL (*tp)) = static_cast<tree>(data);
+ *walk_subtrees = 0;
+ }
+
+ return NULL_TREE;
+}
+
/* Store the parameter declarations into the current function declaration.
This is called after parsing the parameter declarations, before
digesting the body of the function.
thus won't naturally see the SAVE_EXPR containing the increment. All
other pending sizes would be handled by gimplify_parameters. */
if (arg_info->pending_sizes)
- add_stmt (arg_info->pending_sizes);
+ {
+ /* In very special circumstances, e.g. for code like
+ _Atomic int i = 5;
+ void f (int a[i += 2]) {}
+ we need to execute the atomic assignment on function entry.
+ But in this case, it is not just a straight store, it has the
+ op= form, which means that build_atomic_assign has generated
+ gotos, labels, etc. Because at that time the function decl
+ for F has not been created yet, those labels do not have any
+ function context. But we have the fndecl now, so update the
+ labels accordingly. gimplify_expr would crash otherwise. */
+ walk_tree_without_duplicates (&arg_info->pending_sizes,
+ set_labels_context_r, fndecl);
+ add_stmt (arg_info->pending_sizes);
+ }
}
/* Store PARM_DECLs in PARMS into scope temporarily. Used for
/* Remove the qualifiers for the rest of the expressions and
create the VAL temp variable to hold the RHS. */
nonatomic_type = build_qualified_type (expr_type, TYPE_UNQUALIFIED);
- tmp = create_tmp_var (nonatomic_type);
+ tmp = create_tmp_var_raw (nonatomic_type);
tmp_addr = build_unary_op (loc, ADDR_EXPR, tmp, 0);
TREE_ADDRESSABLE (tmp) = 1;
TREE_NO_WARNING (tmp) = 1;
mark_exp_read (exp.value);
/* Return tmp which contains the value loaded. */
- exp.value = build2 (COMPOUND_EXPR, nonatomic_type, func_call, tmp);
+ exp.value = build4 (TARGET_EXPR, nonatomic_type, tmp, func_call,
+ NULL_TREE, NULL_TREE);
}
return exp;
}
the VAL temp variable to hold the RHS. */
nonatomic_lhs_type = build_qualified_type (lhs_type, TYPE_UNQUALIFIED);
nonatomic_rhs_type = build_qualified_type (rhs_type, TYPE_UNQUALIFIED);
- val = create_tmp_var (nonatomic_rhs_type);
+ val = create_tmp_var_raw (nonatomic_rhs_type);
TREE_ADDRESSABLE (val) = 1;
TREE_NO_WARNING (val) = 1;
- rhs = build2 (MODIFY_EXPR, nonatomic_rhs_type, val, rhs);
+ rhs = build4 (TARGET_EXPR, nonatomic_rhs_type, val, rhs, NULL_TREE,
+ NULL_TREE);
SET_EXPR_LOCATION (rhs, loc);
add_stmt (rhs);
}
/* Create the variables and labels required for the op= form. */
- old = create_tmp_var (nonatomic_lhs_type);
+ old = create_tmp_var_raw (nonatomic_lhs_type);
old_addr = build_unary_op (loc, ADDR_EXPR, old, 0);
TREE_ADDRESSABLE (old) = 1;
TREE_NO_WARNING (old) = 1;
- newval = create_tmp_var (nonatomic_lhs_type);
+ newval = create_tmp_var_raw (nonatomic_lhs_type);
newval_addr = build_unary_op (loc, ADDR_EXPR, newval, 0);
TREE_ADDRESSABLE (newval) = 1;
params->quick_push (old_addr);
params->quick_push (seq_cst);
func_call = c_build_function_call_vec (loc, vNULL, fndecl, params, NULL);
- add_stmt (func_call);
+ old = build4 (TARGET_EXPR, nonatomic_lhs_type, old, func_call, NULL_TREE,
+ NULL_TREE);
+ add_stmt (old);
params->truncate (0);
/* Create the expressions for floating-point environment
/* newval = old + val; */
rhs = build_binary_op (loc, modifycode, old, val, 1);
+ rhs = c_fully_fold (rhs, false, NULL);
rhs = convert_for_assignment (loc, UNKNOWN_LOCATION, nonatomic_lhs_type,
rhs, NULL_TREE, ic_assign, false, NULL_TREE,
NULL_TREE, 0);
if (rhs != error_mark_node)
{
- rhs = build2 (MODIFY_EXPR, nonatomic_lhs_type, newval, rhs);
+ rhs = build4 (TARGET_EXPR, nonatomic_lhs_type, newval, rhs, NULL_TREE,
+ NULL_TREE);
SET_EXPR_LOCATION (rhs, loc);
add_stmt (rhs);
}
stmt = build3 (COND_EXPR, void_type_node, func_call, goto_stmt, NULL_TREE);
SET_EXPR_LOCATION (stmt, loc);
add_stmt (stmt);
-
+
if (clear_call)
add_stmt (clear_call);
goto_stmt = build1 (GOTO_EXPR, void_type_node, loop_decl);
SET_EXPR_LOCATION (goto_stmt, loc);
add_stmt (goto_stmt);
-
+
/* done: */
add_stmt (done_label);
--- /dev/null
+/* PR c/65345 */
+/* { dg-do compile } */
+/* { dg-options "" } */
+
+_Atomic int i = 3;
+
+int a1 = sizeof (i + 1);
+int a2 = sizeof (i = 0);
+int a3 = sizeof (i++);
+int a4 = sizeof (i--);
+int a5 = sizeof (-i);
+
+int b1 = _Alignof (i + 1);
+int b2 = _Alignof (i = 0);
+int b3 = _Alignof (i++);
+int b4 = _Alignof (i--);
+int b5 = _Alignof (-i);
+
+int c1 = i; /* { dg-error "initializer element is not constant" } */
+int c2 = (i ? 1 : 2); /* { dg-error "initializer element is not constant" } */
+int c3[i]; /* { dg-error "variably modified" } */
+int c4 = 0 || i; /* { dg-error "initializer element is not constant" } */
+int c5 = (i += 10); /* { dg-error "initializer element is not constant" } */
+
+_Static_assert (_Generic (i, int: 1, default: 0) == 1, "1");
+_Static_assert (_Generic (i + 1, int: 1, default: 0) == 1, "2");
+_Static_assert (_Generic (i = 0, int: 1, default: 0) == 1, "3");
+_Static_assert (_Generic (i++, int: 1, default: 0) == 1, "4");
+_Static_assert (_Generic (i--, int: 1, default: 0) == 1, "5");
+
+void fn1 (int a[i + 1]);
+void fn2 (int a[i = 0]);
+void fn3 (int a[i++]);
+void fn4 (int a[i--]);
+void fn5 (int a[-i]);