diff mbox

Fix ICEs with invalid C #pragma omp atomic (PR c/67495)

Message ID 20150909073732.GF1847@tucnak.redhat.com
State New
Headers show

Commit Message

Jakub Jelinek Sept. 9, 2015, 7:37 a.m. UTC
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  <jakub@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.


	Jakub
diff mbox

Patch

--- 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" } */
+}