aboutsummaryrefslogtreecommitdiff
path: root/gcc/cp/parser.c
diff options
context:
space:
mode:
authorJakub Jelinek <jakub@redhat.com>2021-09-17 11:28:31 +0200
committerJakub Jelinek <jakub@redhat.com>2021-09-17 11:28:31 +0200
commit3a2bcffac602f5de56537a77db1062984bcefd45 (patch)
treeae688b9db0bfa75b79552f4d331ba4758e7a69cb /gcc/cp/parser.c
parent48b3caffcacc99adf72ba1be189a7d9ebc4190be (diff)
downloadgcc-3a2bcffac602f5de56537a77db1062984bcefd45.zip
gcc-3a2bcffac602f5de56537a77db1062984bcefd45.tar.gz
gcc-3a2bcffac602f5de56537a77db1062984bcefd45.tar.bz2
openmp: Add support for OpenMP 5.1 atomics for C++
Besides the C++ FE changes, I've noticed that the C FE didn't reject #pragma omp atomic capture compare { v = x; x = y; } and other forms of atomic swap, this patch fixes that too. And the c-family/ routine needed quite a few changes so that the new code in it works fine with both FEs. 2021-09-17 Jakub Jelinek <jakub@redhat.com> gcc/c-family/ * c-omp.c (c_finish_omp_atomic): Avoid creating TARGET_EXPR if test is true, use create_tmp_var_raw instead of create_tmp_var and add a zero initializer to TARGET_EXPRs that had NULL initializer. When omitting operands after v = x, use type of v rather than type of x. Fix type of vtmp TARGET_EXPR. gcc/c/ * c-parser.c (c_parser_omp_atomic): Reject atomic swap if capture is true. gcc/cp/ * cp-tree.h (finish_omp_atomic): Add r and weak arguments. * parser.c (cp_parser_omp_atomic): Update function comment for OpenMP 5.1 atomics, parse OpenMP 5.1 atomics and fail, compare and weak clauses. * semantics.c (finish_omp_atomic): Add r and weak arguments, handle them, handle COND_EXPRs. * pt.c (tsubst_expr): Adjust for COND_EXPR forms that finish_omp_atomic can now produce. gcc/testsuite/ * c-c++-common/gomp/atomic-18.c: Expect same diagnostics in C++ as in C. * c-c++-common/gomp/atomic-25.c: Drop c effective target. * c-c++-common/gomp/atomic-26.c: Likewise. * c-c++-common/gomp/atomic-27.c: Likewise. * c-c++-common/gomp/atomic-28.c: Likewise. * c-c++-common/gomp/atomic-29.c: Likewise. * c-c++-common/gomp/atomic-30.c: Likewise. Adjust expected diagnostics for C++ when it differs from C. (foo): Change return type from double to void. * g++.dg/gomp/atomic-5.C: Adjust expected diagnostics wording. * g++.dg/gomp/atomic-20.C: New test. libgomp/ * testsuite/libgomp.c-c++-common/atomic-19.c: Drop c effective target. Use /* */ comments instead of //. * testsuite/libgomp.c-c++-common/atomic-20.c: Likewise. * testsuite/libgomp.c-c++-common/atomic-21.c: Likewise. * testsuite/libgomp.c++/atomic-16.C: New test. * testsuite/libgomp.c++/atomic-17.C: New test.
Diffstat (limited to 'gcc/cp/parser.c')
-rw-r--r--gcc/cp/parser.c466
1 files changed, 453 insertions, 13 deletions
diff --git a/gcc/cp/parser.c b/gcc/cp/parser.c
index 8d60f40..20f949e 100644
--- a/gcc/cp/parser.c
+++ b/gcc/cp/parser.c
@@ -40082,19 +40082,56 @@ cp_parser_omp_allocate (cp_parser *parser, cp_token *pragma_tok)
capture-block:
{ v = x; update-stmt; } | { update-stmt; v = x; } | { v = x; x = expr; }
- where x and v are lvalue expressions with scalar type. */
+ OpenMP 5.1:
+ # pragma omp atomic compare new-line
+ conditional-update-atomic
+
+ # pragma omp atomic compare capture new-line
+ conditional-update-capture-atomic
+
+ conditional-update-atomic:
+ cond-expr-stmt | cond-update-stmt
+ cond-expr-stmt:
+ x = expr ordop x ? expr : x;
+ x = x ordop expr ? expr : x;
+ x = x == e ? d : x;
+ cond-update-stmt:
+ if (expr ordop x) { x = expr; }
+ if (x ordop expr) { x = expr; }
+ if (x == e) { x = d; }
+ ordop:
+ <, >
+ conditional-update-capture-atomic:
+ v = cond-expr-stmt
+ { v = x; cond-expr-stmt }
+ { cond-expr-stmt v = x; }
+ { v = x; cond-update-stmt }
+ { cond-update-stmt v = x; }
+ if (x == e) { x = d; } else { v = x; }
+ { r = x == e; if (r) { x = d; } }
+ { r = x == e; if (r) { x = d; } else { v = x; } }
+
+ where x, r and v are lvalue expressions with scalar type,
+ expr, e and d are expressions with scalar type and e might be
+ the same as v. */
static void
cp_parser_omp_atomic (cp_parser *parser, cp_token *pragma_tok, bool openacc)
{
tree lhs = NULL_TREE, rhs = NULL_TREE, v = NULL_TREE, lhs1 = NULL_TREE;
- tree rhs1 = NULL_TREE, orig_lhs;
+ tree rhs1 = NULL_TREE, orig_lhs, r = NULL_TREE;
location_t loc = pragma_tok->location;
enum tree_code code = ERROR_MARK, opcode = NOP_EXPR;
enum omp_memory_order memory_order = OMP_MEMORY_ORDER_UNSPECIFIED;
bool structured_block = false;
bool first = true;
tree clauses = NULL_TREE;
+ bool capture = false;
+ bool compare = false;
+ bool weak = false;
+ enum omp_memory_order fail = OMP_MEMORY_ORDER_UNSPECIFIED;
+ bool no_semicolon = false;
+ bool extra_scope = false;
while (cp_lexer_next_token_is_not (parser->lexer, CPP_PRAGMA_EOL))
{
@@ -40114,6 +40151,10 @@ cp_parser_omp_atomic (cp_parser *parser, cp_token *pragma_tok, bool openacc)
enum tree_code new_code = ERROR_MARK;
enum omp_memory_order new_memory_order
= OMP_MEMORY_ORDER_UNSPECIFIED;
+ bool new_capture = false;
+ bool new_compare = false;
+ bool new_weak = false;
+ enum omp_memory_order new_fail = OMP_MEMORY_ORDER_UNSPECIFIED;
if (!strcmp (p, "read"))
new_code = OMP_ATOMIC_READ;
@@ -40121,7 +40162,7 @@ cp_parser_omp_atomic (cp_parser *parser, cp_token *pragma_tok, bool openacc)
new_code = NOP_EXPR;
else if (!strcmp (p, "update"))
new_code = OMP_ATOMIC;
- else if (!strcmp (p, "capture"))
+ else if (openacc && !strcmp (p, "capture"))
new_code = OMP_ATOMIC_CAPTURE_NEW;
else if (openacc)
{
@@ -40129,6 +40170,52 @@ cp_parser_omp_atomic (cp_parser *parser, cp_token *pragma_tok, bool openacc)
error_at (cloc, "expected %<read%>, %<write%>, %<update%>, "
"or %<capture%> clause");
}
+ else if (!strcmp (p, "capture"))
+ new_capture = true;
+ else if (!strcmp (p, "compare"))
+ new_compare = true;
+ else if (!strcmp (p, "weak"))
+ new_weak = true;
+ else if (!strcmp (p, "fail"))
+ {
+ matching_parens parens;
+
+ cp_lexer_consume_token (parser->lexer);
+ if (!parens.require_open (parser))
+ continue;
+
+ if (cp_lexer_next_token_is (parser->lexer, CPP_NAME))
+ {
+ id = cp_lexer_peek_token (parser->lexer)->u.value;
+ const char *q = IDENTIFIER_POINTER (id);
+
+ if (!strcmp (q, "seq_cst"))
+ new_fail = OMP_MEMORY_ORDER_SEQ_CST;
+ else if (!strcmp (q, "acquire"))
+ new_fail = OMP_MEMORY_ORDER_ACQUIRE;
+ else if (!strcmp (q, "relaxed"))
+ new_fail = OMP_MEMORY_ORDER_RELAXED;
+ }
+
+ if (new_fail != OMP_MEMORY_ORDER_UNSPECIFIED)
+ {
+ cp_lexer_consume_token (parser->lexer);
+ if (fail != OMP_MEMORY_ORDER_UNSPECIFIED)
+ error_at (cloc, "too many %qs clauses", "fail");
+ else
+ fail = new_fail;
+ }
+ else
+ cp_parser_error (parser, "expected %<seq_cst%>, %<acquire%> "
+ "or %<relaxed%>");
+ if (new_fail == OMP_MEMORY_ORDER_UNSPECIFIED
+ || !parens.require_close (parser))
+ cp_parser_skip_to_closing_parenthesis (parser,
+ /*recovering=*/true,
+ /*or_comma=*/false,
+ /*consume_paren=*/true);
+ continue;
+ }
else if (!strcmp (p, "seq_cst"))
new_memory_order = OMP_MEMORY_ORDER_SEQ_CST;
else if (!strcmp (p, "acq_rel"))
@@ -40149,8 +40236,9 @@ cp_parser_omp_atomic (cp_parser *parser, cp_token *pragma_tok, bool openacc)
{
p = NULL;
error_at (cloc, "expected %<read%>, %<write%>, %<update%>, "
- "%<capture%>, %<seq_cst%>, %<acq_rel%>, "
- "%<release%>, %<relaxed%> or %<hint%> clause");
+ "%<capture%>, %<compare%>, %<weak%>, %<fail%>, "
+ "%<seq_cst%>, %<acq_rel%>, %<release%>, "
+ "%<relaxed%> or %<hint%> clause");
}
if (p)
{
@@ -40173,6 +40261,27 @@ cp_parser_omp_atomic (cp_parser *parser, cp_token *pragma_tok, bool openacc)
else
memory_order = new_memory_order;
}
+ else if (new_capture)
+ {
+ if (capture)
+ error_at (cloc, "too many %qs clauses", "capture");
+ else
+ capture = true;
+ }
+ else if (new_compare)
+ {
+ if (compare)
+ error_at (cloc, "too many %qs clauses", "compare");
+ else
+ compare = true;
+ }
+ else if (new_weak)
+ {
+ if (weak)
+ error_at (cloc, "too many %qs clauses", "weak");
+ else
+ weak = true;
+ }
cp_lexer_consume_token (parser->lexer);
continue;
}
@@ -40183,6 +40292,30 @@ cp_parser_omp_atomic (cp_parser *parser, cp_token *pragma_tok, bool openacc)
if (code == ERROR_MARK)
code = OMP_ATOMIC;
+ if (capture)
+ {
+ if (code != OMP_ATOMIC)
+ error_at (loc, "%qs clause is incompatible with %<read%> or %<write%> "
+ "clauses", "capture");
+ else
+ code = OMP_ATOMIC_CAPTURE_NEW;
+ }
+ if (compare && code != OMP_ATOMIC && code != OMP_ATOMIC_CAPTURE_NEW)
+ {
+ error_at (loc, "%qs clause is incompatible with %<read%> or %<write%> "
+ "clauses", "compare");
+ compare = false;
+ }
+ if (fail != OMP_MEMORY_ORDER_UNSPECIFIED && !compare)
+ {
+ error_at (loc, "%qs clause requires %qs clause", "fail", "compare");
+ fail = OMP_MEMORY_ORDER_UNSPECIFIED;
+ }
+ if (weak && !compare)
+ {
+ error_at (loc, "%qs clause requires %qs clause", "weak", "compare");
+ weak = false;
+ }
if (openacc)
memory_order = OMP_MEMORY_ORDER_RELAXED;
else if (memory_order == OMP_MEMORY_ORDER_UNSPECIFIED)
@@ -40244,6 +40377,10 @@ cp_parser_omp_atomic (cp_parser *parser, cp_token *pragma_tok, bool openacc)
default:
break;
}
+ if (fail != OMP_MEMORY_ORDER_UNSPECIFIED)
+ memory_order
+ = (enum omp_memory_order) (memory_order
+ | (fail << OMP_FAIL_MEMORY_ORDER_SHIFT));
switch (code)
{
@@ -40276,6 +40413,9 @@ cp_parser_omp_atomic (cp_parser *parser, cp_token *pragma_tok, bool openacc)
cp_lexer_consume_token (parser->lexer);
structured_block = true;
}
+ else if (compare
+ && cp_lexer_next_token_is_keyword (parser->lexer, RID_IF))
+ break;
else
{
v = cp_parser_unary_expression (parser);
@@ -40283,12 +40423,179 @@ cp_parser_omp_atomic (cp_parser *parser, cp_token *pragma_tok, bool openacc)
goto saw_error;
if (!cp_parser_require (parser, CPP_EQ, RT_EQ))
goto saw_error;
+ if (compare
+ && cp_lexer_next_token_is_keyword (parser->lexer, RID_IF))
+ {
+ location_t eloc = cp_lexer_peek_token (parser->lexer)->location;
+ error_at (eloc, "expected expression");
+ goto saw_error;
+ }
}
default:
break;
}
restart:
+ if (compare && cp_lexer_next_token_is_keyword (parser->lexer, RID_IF))
+ {
+ cp_lexer_consume_token (parser->lexer);
+
+ matching_parens parens;
+ if (!parens.require_open (parser))
+ goto saw_error;
+ location_t eloc = cp_lexer_peek_token (parser->lexer)->location;
+ tree cmp_expr;
+ if (r)
+ cmp_expr = cp_parser_unary_expression (parser);
+ else
+ cmp_expr = cp_parser_binary_expression (parser, false, true,
+ PREC_NOT_OPERATOR, NULL);
+ if (!parens.require_close (parser))
+ cp_parser_skip_to_closing_parenthesis (parser, true, false, true);
+ if (cmp_expr == error_mark_node)
+ goto saw_error;
+ if (r)
+ {
+ if (!cp_tree_equal (cmp_expr, r))
+ goto bad_if;
+ cmp_expr = rhs;
+ rhs = NULL_TREE;
+ gcc_assert (TREE_CODE (cmp_expr) == EQ_EXPR);
+ }
+ if (TREE_CODE (cmp_expr) == EQ_EXPR)
+ ;
+ else if (!structured_block && code == OMP_ATOMIC_CAPTURE_NEW)
+ {
+ error_at (EXPR_LOC_OR_LOC (cmp_expr, eloc),
+ "expected %<==%> comparison in %<if%> condition");
+ goto saw_error;
+ }
+ else if (TREE_CODE (cmp_expr) != GT_EXPR
+ && TREE_CODE (cmp_expr) != LT_EXPR)
+ {
+ error_at (EXPR_LOC_OR_LOC (cmp_expr, eloc),
+ "expected %<==%>, %<<%> or %<>%> comparison in %<if%> "
+ "condition");
+ goto saw_error;
+ }
+ if (!cp_parser_require (parser, CPP_OPEN_BRACE, RT_OPEN_BRACE))
+ goto saw_error;
+
+ extra_scope = true;
+ eloc = cp_lexer_peek_token (parser->lexer)->location;
+ lhs = cp_parser_unary_expression (parser);
+ orig_lhs = lhs;
+ if (lhs == error_mark_node)
+ goto saw_error;
+ if (!cp_lexer_next_token_is (parser->lexer, CPP_EQ))
+ {
+ cp_parser_error (parser, "expected %<=%>");
+ goto saw_error;
+ }
+ cp_lexer_consume_token (parser->lexer);
+ eloc = cp_lexer_peek_token (parser->lexer)->location;
+ if (TREE_CODE (cmp_expr) == EQ_EXPR)
+ rhs1 = cp_parser_expression (parser);
+ else
+ rhs1 = cp_parser_simple_cast_expression (parser);
+
+ if (!cp_parser_require (parser, CPP_SEMICOLON, RT_SEMICOLON))
+ goto saw_error;
+
+ if (!cp_parser_require (parser, CPP_CLOSE_BRACE, RT_CLOSE_BRACE))
+ goto saw_error;
+
+ extra_scope = false;
+ no_semicolon = true;
+
+ if (cp_tree_equal (TREE_OPERAND (cmp_expr, 0), lhs))
+ {
+ if (TREE_CODE (cmp_expr) == EQ_EXPR)
+ {
+ opcode = COND_EXPR;
+ rhs = TREE_OPERAND (cmp_expr, 1);
+ }
+ else if (cp_tree_equal (TREE_OPERAND (cmp_expr, 1), rhs1))
+ {
+ opcode = (TREE_CODE (cmp_expr) == GT_EXPR
+ ? MIN_EXPR : MAX_EXPR);
+ rhs = rhs1;
+ rhs1 = TREE_OPERAND (cmp_expr, 0);
+ }
+ else
+ goto bad_if;
+ }
+ else if (TREE_CODE (cmp_expr) == EQ_EXPR)
+ goto bad_if;
+ else if (cp_tree_equal (TREE_OPERAND (cmp_expr, 1), lhs)
+ && cp_tree_equal (TREE_OPERAND (cmp_expr, 0), rhs1))
+ {
+ opcode = (TREE_CODE (cmp_expr) == GT_EXPR
+ ? MAX_EXPR : MIN_EXPR);
+ rhs = rhs1;
+ rhs1 = TREE_OPERAND (cmp_expr, 1);
+ }
+ else
+ {
+ bad_if:
+ cp_parser_error (parser,
+ "invalid form of %<#pragma omp atomic compare%>");
+ goto saw_error;
+ }
+
+ if (cp_lexer_next_token_is_keyword (parser->lexer, RID_ELSE))
+ {
+ if (code != OMP_ATOMIC_CAPTURE_NEW
+ || (structured_block && r == NULL_TREE)
+ || TREE_CODE (cmp_expr) != EQ_EXPR)
+ {
+ eloc = cp_lexer_peek_token (parser->lexer)->location;
+ error_at (eloc, "unexpected %<else%>");
+ goto saw_error;
+ }
+
+ cp_lexer_consume_token (parser->lexer);
+
+ if (!cp_parser_require (parser, CPP_OPEN_BRACE, RT_OPEN_BRACE))
+ goto saw_error;
+
+ extra_scope = true;
+ v = cp_parser_unary_expression (parser);
+ if (v == error_mark_node)
+ goto saw_error;
+ if (!cp_parser_require (parser, CPP_EQ, RT_EQ))
+ goto saw_error;
+
+ tree expr = cp_parser_simple_cast_expression (parser);
+
+ if (!cp_tree_equal (expr, lhs))
+ goto bad_if;
+
+ if (!cp_parser_require (parser, CPP_SEMICOLON, RT_SEMICOLON))
+ goto saw_error;
+
+ if (!cp_parser_require (parser, CPP_CLOSE_BRACE, RT_CLOSE_BRACE))
+ goto saw_error;
+
+ extra_scope = false;
+ code = OMP_ATOMIC_CAPTURE_OLD;
+ if (r == NULL_TREE)
+ /* Signal to c_finish_omp_atomic that in
+ if (x == e) { x = d; } else { v = x; }
+ case the store to v should be conditional. */
+ r = void_list_node;
+ }
+ else if (code == OMP_ATOMIC_CAPTURE_NEW && !structured_block)
+ {
+ cp_parser_error (parser, "expected %<else%>");
+ goto saw_error;
+ }
+ else if (code == OMP_ATOMIC_CAPTURE_NEW
+ && r != NULL_TREE
+ && v == NULL_TREE)
+ code = OMP_ATOMIC;
+ goto stmt_done;
+ }
lhs = cp_parser_unary_expression (parser);
orig_lhs = lhs;
switch (TREE_CODE (lhs))
@@ -40304,6 +40611,8 @@ restart:
lhs = TREE_OPERAND (lhs, 0);
opcode = PLUS_EXPR;
rhs = integer_one_node;
+ if (compare)
+ goto invalid_compare;
break;
case POSTDECREMENT_EXPR:
@@ -40314,6 +40623,8 @@ restart:
lhs = TREE_OPERAND (lhs, 0);
opcode = MINUS_EXPR;
rhs = integer_one_node;
+ if (compare)
+ goto invalid_compare;
break;
case COMPOUND_EXPR:
@@ -40342,11 +40653,18 @@ restart:
&& !structured_block
&& TREE_CODE (orig_lhs) == COMPOUND_EXPR)
code = OMP_ATOMIC_CAPTURE_OLD;
+ if (compare)
+ goto invalid_compare;
break;
}
}
/* FALLTHRU */
default:
+ if (compare && !cp_lexer_next_token_is (parser->lexer, CPP_EQ))
+ {
+ cp_parser_error (parser, "expected %<=%>");
+ goto saw_error;
+ }
switch (cp_lexer_peek_token (parser->lexer)->type)
{
case CPP_MULT_EQ:
@@ -40414,6 +40732,8 @@ restart:
case BIT_AND_EXPR:
case BIT_IOR_EXPR:
case BIT_XOR_EXPR:
+ if (compare)
+ break;
if (cp_tree_equal (lhs, TREE_OPERAND (rhs, 1)))
{
if (cp_parser_parse_definitely (parser))
@@ -40427,11 +40747,91 @@ restart:
goto saw_error;
}
break;
+ case EQ_EXPR:
+ if (!compare
+ || code != OMP_ATOMIC_CAPTURE_NEW
+ || !structured_block
+ || v
+ || r)
+ break;
+ if (cp_lexer_next_token_is (parser->lexer, CPP_SEMICOLON)
+ && cp_lexer_nth_token_is_keyword (parser->lexer,
+ 2, RID_IF))
+ {
+ if (cp_parser_parse_definitely (parser))
+ {
+ r = lhs;
+ lhs = NULL_TREE;
+ rhs1 = NULL_TREE;
+ cp_lexer_consume_token (parser->lexer);
+ goto restart;
+ }
+ }
+ break;
+ case GT_EXPR:
+ case LT_EXPR:
+ if (compare
+ && cp_lexer_next_token_is (parser->lexer, CPP_QUERY)
+ && cp_tree_equal (lhs, TREE_OPERAND (rhs, 1))
+ && cp_parser_parse_definitely (parser))
+ {
+ opcode = TREE_CODE (rhs);
+ rhs1 = TREE_OPERAND (rhs, 0);
+ rhs = TREE_OPERAND (rhs, 1);
+ cond_expr:
+ cp_lexer_consume_token (parser->lexer);
+ bool saved_colon_corrects_to_scope_p
+ = parser->colon_corrects_to_scope_p;
+ parser->colon_corrects_to_scope_p = false;
+ tree e1 = cp_parser_expression (parser);
+ parser->colon_corrects_to_scope_p
+ = saved_colon_corrects_to_scope_p;
+ cp_parser_require (parser, CPP_COLON, RT_COLON);
+ tree e2 = cp_parser_simple_cast_expression (parser);
+ if (cp_tree_equal (lhs, e2))
+ {
+ if (cp_tree_equal (lhs, rhs1))
+ {
+ if (opcode == EQ_EXPR)
+ {
+ opcode = COND_EXPR;
+ rhs1 = e1;
+ goto stmt_done;
+ }
+ if (cp_tree_equal (rhs, e1))
+ {
+ opcode
+ = opcode == GT_EXPR ? MIN_EXPR : MAX_EXPR;
+ rhs = e1;
+ goto stmt_done;
+ }
+ }
+ else
+ {
+ gcc_assert (opcode != EQ_EXPR);
+ if (cp_tree_equal (rhs1, e1))
+ {
+ opcode
+ = opcode == GT_EXPR ? MAX_EXPR : MIN_EXPR;
+ rhs1 = rhs;
+ rhs = e1;
+ goto stmt_done;
+ }
+ }
+ }
+ cp_parser_error (parser,
+ "invalid form of "
+ "%<#pragma omp atomic compare%>");
+ goto saw_error;
+ }
+ break;
default:
break;
}
cp_parser_abort_tentative_parse (parser);
- if (structured_block && code == OMP_ATOMIC_CAPTURE_OLD)
+ if (structured_block
+ && code == OMP_ATOMIC_CAPTURE_OLD
+ && !compare)
{
rhs = cp_parser_expression (parser);
if (rhs == error_mark_node)
@@ -40459,7 +40859,7 @@ restart:
cp_lexer_consume_token (parser->lexer);
goto restart;
}
- else if (structured_block)
+ else if (structured_block && !compare)
{
opcode = NOP_EXPR;
rhs = rhs1;
@@ -40496,11 +40896,28 @@ restart:
case CPP_XOR:
opcode = BIT_XOR_EXPR;
break;
+ case CPP_EQ_EQ:
+ opcode = EQ_EXPR;
+ break;
+ case CPP_GREATER:
+ opcode = GT_EXPR;
+ break;
+ case CPP_LESS:
+ opcode = LT_EXPR;
+ break;
default:
cp_parser_error (parser,
"invalid operator for %<#pragma omp atomic%>");
goto saw_error;
}
+ if (compare
+ && TREE_CODE_CLASS (opcode) != tcc_comparison)
+ {
+ cp_parser_error (parser,
+ "invalid form of "
+ "%<#pragma omp atomic compare%>");
+ goto saw_error;
+ }
oprec = TOKEN_PRECEDENCE (token);
gcc_assert (oprec != PREC_NOT_OPERATOR);
if (commutative_tree_code (opcode))
@@ -40510,8 +40927,18 @@ restart:
oprec, NULL);
if (rhs == error_mark_node)
goto saw_error;
+ if (compare)
+ {
+ if (!cp_lexer_next_token_is (parser->lexer, CPP_QUERY))
+ {
+ cp_parser_error (parser,
+ "invalid form of "
+ "%<#pragma omp atomic compare%>");
+ goto saw_error;
+ }
+ goto cond_expr;
+ }
goto stmt_done;
- /* FALLTHROUGH */
default:
cp_parser_error (parser,
"invalid operator for %<#pragma omp atomic%>");
@@ -40525,10 +40952,12 @@ restart:
break;
}
stmt_done:
- if (structured_block && code == OMP_ATOMIC_CAPTURE_NEW)
+ if (structured_block && code == OMP_ATOMIC_CAPTURE_NEW && r == NULL_TREE)
{
- if (!cp_parser_require (parser, CPP_SEMICOLON, RT_SEMICOLON))
+ if (!no_semicolon
+ && !cp_parser_require (parser, CPP_SEMICOLON, RT_SEMICOLON))
goto saw_error;
+ no_semicolon = false;
v = cp_parser_unary_expression (parser);
if (v == error_mark_node)
goto saw_error;
@@ -40540,19 +40969,30 @@ stmt_done:
}
if (structured_block)
{
- cp_parser_consume_semicolon_at_end_of_statement (parser);
+ if (!no_semicolon)
+ cp_parser_consume_semicolon_at_end_of_statement (parser);
cp_parser_require (parser, CPP_CLOSE_BRACE, RT_CLOSE_BRACE);
}
done:
+ if (weak && opcode != COND_EXPR)
+ {
+ error_at (loc, "%<weak%> clause requires atomic equality comparison");
+ weak = false;
+ }
clauses = finish_omp_clauses (clauses, C_ORT_OMP);
finish_omp_atomic (pragma_tok->location, code, opcode, lhs, rhs, v, lhs1,
- rhs1, clauses, memory_order);
- if (!structured_block)
+ rhs1, r, clauses, memory_order, weak);
+ if (!structured_block && !no_semicolon)
cp_parser_consume_semicolon_at_end_of_statement (parser);
return;
+ invalid_compare:
+ error ("invalid form of %<pragma omp atomic compare%>");
+ /* FALLTHRU */
saw_error:
cp_parser_skip_to_end_of_block_or_statement (parser);
+ if (extra_scope && cp_lexer_next_token_is (parser->lexer, CPP_CLOSE_BRACE))
+ cp_lexer_consume_token (parser->lexer);
if (structured_block)
{
if (cp_lexer_next_token_is (parser->lexer, CPP_CLOSE_BRACE))