Hi! The C FE apparently relies on c_parser_unary_expression never called if the expression to be parsed is actually a cast expression, otherwise it fails an assertion. c_parser_cast_expression of course guarantees that and during sizeof and __alignof__ parsing too, but c_parser_omp_atomic calls c_parser_unary_expression in many places when it is looking for unary expressions that are later on analyzed, and if invalid source code contains casts in those places (as the testcase shows), we ICE.
The following patch fixes it by calling c_parser_cast_expression instead and if the result is not an lvalue, wrapping the result after fully folding it into a NON_LVALUE_EXPR, so that we diagnose it later on. Bootstrapped/regtested on x86_64-linux and i686-linux, committed to trunk and 5 branch. 2015-09-09 Jakub Jelinek <ja...@redhat.com> PR c/67495 * c-parser.c (c_parser_omp_atomic): Use c_parser_cast_expression instead of c_parser_unary_expression. If the result is !lvalue_p, wrap the result of c_fully_fold into NON_LVALUE_EXPR. * gcc.dg/gomp/pr67495.c: New test. --- gcc/c/c-parser.c.jj 2015-09-03 17:18:31.000000000 +0200 +++ gcc/c/c-parser.c 2015-09-08 16:33:43.777568099 +0200 @@ -12422,6 +12422,7 @@ c_parser_omp_atomic (location_t loc, c_p bool structured_block = false; bool swapped = false; bool seq_cst = false; + bool non_lvalue_p; if (c_parser_next_token_is (parser, CPP_NAME)) { @@ -12475,20 +12476,33 @@ c_parser_omp_atomic (location_t loc, c_p { case OMP_ATOMIC_READ: case NOP_EXPR: /* atomic write */ - v = c_parser_unary_expression (parser).value; + v = c_parser_cast_expression (parser, NULL).value; + non_lvalue_p = !lvalue_p (v); v = c_fully_fold (v, false, NULL); if (v == error_mark_node) goto saw_error; + if (non_lvalue_p) + v = non_lvalue (v); loc = c_parser_peek_token (parser)->location; if (!c_parser_require (parser, CPP_EQ, "expected %<=%>")) goto saw_error; if (code == NOP_EXPR) - lhs = c_parser_expression (parser).value; + { + lhs = c_parser_expression (parser).value; + lhs = c_fully_fold (lhs, false, NULL); + if (lhs == error_mark_node) + goto saw_error; + } else - lhs = c_parser_unary_expression (parser).value; - lhs = c_fully_fold (lhs, false, NULL); - if (lhs == error_mark_node) - goto saw_error; + { + lhs = c_parser_cast_expression (parser, NULL).value; + non_lvalue_p = !lvalue_p (lhs); + lhs = c_fully_fold (lhs, false, NULL); + if (lhs == error_mark_node) + goto saw_error; + if (non_lvalue_p) + lhs = non_lvalue (lhs); + } if (code == NOP_EXPR) { /* atomic write is represented by OMP_ATOMIC with NOP_EXPR @@ -12507,10 +12521,13 @@ c_parser_omp_atomic (location_t loc, c_p } else { - v = c_parser_unary_expression (parser).value; + v = c_parser_cast_expression (parser, NULL).value; + non_lvalue_p = !lvalue_p (v); v = c_fully_fold (v, false, NULL); if (v == error_mark_node) goto saw_error; + if (non_lvalue_p) + v = non_lvalue (v); if (!c_parser_require (parser, CPP_EQ, "expected %<=%>")) goto saw_error; } @@ -12523,7 +12540,7 @@ c_parser_omp_atomic (location_t loc, c_p old or new x should be captured. */ restart: eloc = c_parser_peek_token (parser)->location; - expr = c_parser_unary_expression (parser); + expr = c_parser_cast_expression (parser, NULL); lhs = expr.value; expr = default_function_array_conversion (eloc, expr); unfolded_lhs = expr.value; @@ -12616,6 +12633,8 @@ restart: } /* FALLTHRU */ default: + if (!lvalue_p (unfolded_lhs)) + lhs = non_lvalue (lhs); switch (c_parser_peek_token (parser)->type) { case CPP_MULT_EQ: @@ -12730,20 +12749,25 @@ stmt_done: { if (!c_parser_require (parser, CPP_SEMICOLON, "expected %<;%>")) goto saw_error; - v = c_parser_unary_expression (parser).value; + v = c_parser_cast_expression (parser, NULL).value; + non_lvalue_p = !lvalue_p (v); v = c_fully_fold (v, false, NULL); if (v == error_mark_node) goto saw_error; + if (non_lvalue_p) + v = non_lvalue (v); if (!c_parser_require (parser, CPP_EQ, "expected %<=%>")) goto saw_error; eloc = c_parser_peek_token (parser)->location; - expr = c_parser_unary_expression (parser); + expr = c_parser_cast_expression (parser, NULL); lhs1 = expr.value; expr = default_function_array_read_conversion (eloc, expr); unfolded_lhs1 = expr.value; lhs1 = c_fully_fold (lhs1, false, NULL); if (lhs1 == error_mark_node) goto saw_error; + if (!lvalue_p (unfolded_lhs1)) + lhs1 = non_lvalue (lhs1); } if (structured_block) { --- gcc/testsuite/gcc.dg/gomp/pr67495.c.jj 2015-09-08 16:27:21.359239520 +0200 +++ gcc/testsuite/gcc.dg/gomp/pr67495.c 2015-09-08 16:27:52.119783329 +0200 @@ -0,0 +1,38 @@ +/* PR c/67495 */ +/* { dg-do compile } */ +/* { dg-options "-fopenmp" } */ + +int a, b, c; + +void +foo (void) +{ +#pragma omp atomic capture + a = (float)a + b; /* { dg-error "invalid operator" } */ +#pragma omp atomic read + (float) a = b; /* { dg-error "lvalue required" } */ +#pragma omp atomic write + (float) a = b; /* { dg-error "lvalue required" } */ +#pragma omp atomic read + a = (float) b; /* { dg-error "lvalue required" } */ +#pragma omp atomic capture + (float) a = b += c; /* { dg-error "lvalue required" } */ +#pragma omp atomic capture + { a += b; (float) c = a; } /* { dg-error "lvalue required" } */ +#pragma omp atomic capture + { a += b; c = (float) a; } /* { dg-error "uses two different expressions for memory" } */ +#pragma omp atomic capture + a = (int)a + b; /* { dg-error "invalid operator" } */ +#pragma omp atomic read + (int) a = b; /* { dg-error "lvalue required" } */ +#pragma omp atomic write + (int) a = b; /* { dg-error "lvalue required" } */ +#pragma omp atomic read + a = (int) b; /* { dg-error "lvalue required" } */ +#pragma omp atomic capture + (int) a = b += c; /* { dg-error "lvalue required" } */ +#pragma omp atomic capture + { a += b; (int) c = a; } /* { dg-error "lvalue required" } */ +#pragma omp atomic capture + { a += b; c = (int) a; } /* { dg-error "lvalue required" } */ +} Jakub