diff options
author | Jakub Jelinek <jakub@redhat.com> | 2021-09-17 11:28:31 +0200 |
---|---|---|
committer | Jakub Jelinek <jakub@redhat.com> | 2021-09-17 11:28:31 +0200 |
commit | 3a2bcffac602f5de56537a77db1062984bcefd45 (patch) | |
tree | ae688b9db0bfa75b79552f4d331ba4758e7a69cb /gcc/cp/parser.c | |
parent | 48b3caffcacc99adf72ba1be189a7d9ebc4190be (diff) | |
download | gcc-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.c | 466 |
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)) |