diff --git gcc/c/ChangeLog gcc/c/ChangeLog
index 497c9b9..b12f41d 100644
--- gcc/c/ChangeLog
+++ gcc/c/ChangeLog
@@ -1,3 +1,11 @@
+2017-05-12  Thomas Schwinge  <thomas@codesourcery.com>
+
+	* c-parser.c (c_parser_omp_clause_num_gangs)
+	(c_parser_omp_clause_num_workers)
+	(c_parser_omp_clause_vector_length): Merge functions into...
+	(c_parser_oacc_single_int_clause): ... this new function.  Adjust
+	all users.
+
 2017-05-11  Nathan Sidwell  <nathan@acm.org>
 
 	* gimple-parser.c: Don't #include tree-dump.h.
diff --git gcc/c/c-parser.c gcc/c/c-parser.c
index 9398652..90d2d17 100644
--- gcc/c/c-parser.c
+++ gcc/c/c-parser.c
@@ -11339,51 +11339,6 @@ c_parser_omp_clause_nowait (c_parser *parser ATTRIBUTE_UNUSED, tree list)
   return c;
 }
 
-/* OpenACC:
-   num_gangs ( expression ) */
-
-static tree
-c_parser_omp_clause_num_gangs (c_parser *parser, tree list)
-{
-  location_t num_gangs_loc = c_parser_peek_token (parser)->location;
-  if (c_parser_require (parser, CPP_OPEN_PAREN, "expected %<(%>"))
-    {
-      location_t expr_loc = c_parser_peek_token (parser)->location;
-      c_expr expr = c_parser_expression (parser);
-      expr = convert_lvalue_to_rvalue (expr_loc, expr, false, true);
-      tree c, t = expr.value;
-      t = c_fully_fold (t, false, NULL);
-
-      c_parser_skip_until_found (parser, CPP_CLOSE_PAREN, "expected %<)%>");
-
-      if (!INTEGRAL_TYPE_P (TREE_TYPE (t)))
-	{
-	  c_parser_error (parser, "expected integer expression");
-	  return list;
-	}
-
-      /* Attempt to statically determine when the number isn't positive.  */
-      c = fold_build2_loc (expr_loc, LE_EXPR, boolean_type_node, t,
-		       build_int_cst (TREE_TYPE (t), 0));
-      protected_set_expr_location (c, expr_loc);
-      if (c == boolean_true_node)
-	{
-	  warning_at (expr_loc, 0,
-		      "%<num_gangs%> value must be positive");
-	  t = integer_one_node;
-	}
-
-      check_no_duplicate_clause (list, OMP_CLAUSE_NUM_GANGS, "num_gangs");
-
-      c = build_omp_clause (num_gangs_loc, OMP_CLAUSE_NUM_GANGS);
-      OMP_CLAUSE_NUM_GANGS_EXPR (c) = t;
-      OMP_CLAUSE_CHAIN (c) = list;
-      list = c;
-    }
-
-  return list;
-}
-
 /* OpenMP 2.5:
    num_threads ( expression ) */
 
@@ -11671,48 +11626,54 @@ c_parser_omp_clause_is_device_ptr (c_parser *parser, tree list)
 }
 
 /* OpenACC:
-   num_workers ( expression ) */
+   num_gangs ( expression )
+   num_workers ( expression )
+   vector_length ( expression )  */
 
 static tree
-c_parser_omp_clause_num_workers (c_parser *parser, tree list)
+c_parser_oacc_single_int_clause (c_parser *parser, omp_clause_code code,
+				 tree list)
 {
-  location_t num_workers_loc = c_parser_peek_token (parser)->location;
-  if (c_parser_require (parser, CPP_OPEN_PAREN, "expected %<(%>"))
+  location_t loc = c_parser_peek_token (parser)->location;
+
+  if (!c_parser_require (parser, CPP_OPEN_PAREN, "expected %<(%>"))
+    return list;
+
+  location_t expr_loc = c_parser_peek_token (parser)->location;
+  c_expr expr = c_parser_expression (parser);
+  expr = convert_lvalue_to_rvalue (expr_loc, expr, false, true);
+  tree c, t = expr.value;
+  t = c_fully_fold (t, false, NULL);
+
+  c_parser_skip_until_found (parser, CPP_CLOSE_PAREN, "expected %<)%>");
+
+  if (t == error_mark_node)
+    return list;
+  else if (!INTEGRAL_TYPE_P (TREE_TYPE (t)))
     {
-      location_t expr_loc = c_parser_peek_token (parser)->location;
-      c_expr expr = c_parser_expression (parser);
-      expr = convert_lvalue_to_rvalue (expr_loc, expr, false, true);
-      tree c, t = expr.value;
-      t = c_fully_fold (t, false, NULL);
+      error_at (expr_loc, "%qs expression must be integral",
+		omp_clause_code_name[code]);
+      return list;
+    }
 
-      c_parser_skip_until_found (parser, CPP_CLOSE_PAREN, "expected %<)%>");
-
-      if (!INTEGRAL_TYPE_P (TREE_TYPE (t)))
-	{
-	  c_parser_error (parser, "expected integer expression");
-	  return list;
-	}
-
-      /* Attempt to statically determine when the number isn't positive.  */
-      c = fold_build2_loc (expr_loc, LE_EXPR, boolean_type_node, t,
+  /* Attempt to statically determine when the number isn't positive.  */
+  c = fold_build2_loc (expr_loc, LE_EXPR, boolean_type_node, t,
 		       build_int_cst (TREE_TYPE (t), 0));
-      protected_set_expr_location (c, expr_loc);
-      if (c == boolean_true_node)
-	{
-	  warning_at (expr_loc, 0,
-		      "%<num_workers%> value must be positive");
-	  t = integer_one_node;
-	}
-
-      check_no_duplicate_clause (list, OMP_CLAUSE_NUM_WORKERS, "num_workers");
-
-      c = build_omp_clause (num_workers_loc, OMP_CLAUSE_NUM_WORKERS);
-      OMP_CLAUSE_NUM_WORKERS_EXPR (c) = t;
-      OMP_CLAUSE_CHAIN (c) = list;
-      list = c;
+  protected_set_expr_location (c, expr_loc);
+  if (c == boolean_true_node)
+    {
+      warning_at (expr_loc, 0,
+		  "%qs value must be positive",
+		  omp_clause_code_name[code]);
+      t = integer_one_node;
     }
 
-  return list;
+  check_no_duplicate_clause (list, code, omp_clause_code_name[code]);
+
+  c = build_omp_clause (loc, code);
+  OMP_CLAUSE_OPERAND (c, 0) = t;
+  OMP_CLAUSE_CHAIN (c) = list;
+  return c;
 }
 
 /* OpenACC:
@@ -12354,51 +12315,6 @@ c_parser_omp_clause_untied (c_parser *parser ATTRIBUTE_UNUSED, tree list)
   return c;
 }
 
-/* OpenACC:
-   vector_length ( expression ) */
-
-static tree
-c_parser_omp_clause_vector_length (c_parser *parser, tree list)
-{
-  location_t vector_length_loc = c_parser_peek_token (parser)->location;
-  if (c_parser_require (parser, CPP_OPEN_PAREN, "expected %<(%>"))
-    {
-      location_t expr_loc = c_parser_peek_token (parser)->location;
-      c_expr expr = c_parser_expression (parser);
-      expr = convert_lvalue_to_rvalue (expr_loc, expr, false, true);
-      tree c, t = expr.value;
-      t = c_fully_fold (t, false, NULL);
-
-      c_parser_skip_until_found (parser, CPP_CLOSE_PAREN, "expected %<)%>");
-
-      if (!INTEGRAL_TYPE_P (TREE_TYPE (t)))
-	{
-	  c_parser_error (parser, "expected integer expression");
-	  return list;
-	}
-
-      /* Attempt to statically determine when the number isn't positive.  */
-      c = fold_build2_loc (expr_loc, LE_EXPR, boolean_type_node, t,
-		       build_int_cst (TREE_TYPE (t), 0));
-      protected_set_expr_location (c, expr_loc);
-      if (c == boolean_true_node)
-	{
-	  warning_at (expr_loc, 0,
-		      "%<vector_length%> value must be positive");
-	  t = integer_one_node;
-	}
-
-      check_no_duplicate_clause (list, OMP_CLAUSE_VECTOR_LENGTH, "vector_length");
-
-      c = build_omp_clause (vector_length_loc, OMP_CLAUSE_VECTOR_LENGTH);
-      OMP_CLAUSE_VECTOR_LENGTH_EXPR (c) = t;
-      OMP_CLAUSE_CHAIN (c) = list;
-      list = c;
-    }
-
-  return list;
-}
-
 /* OpenMP 4.0:
    inbranch
    notinbranch */
@@ -13283,11 +13199,15 @@ c_parser_oacc_all_clauses (c_parser *parser, omp_clause_mask mask,
 	  c_name = "link";
 	  break;
 	case PRAGMA_OACC_CLAUSE_NUM_GANGS:
-	  clauses = c_parser_omp_clause_num_gangs (parser, clauses);
+	  clauses = c_parser_oacc_single_int_clause (parser,
+						     OMP_CLAUSE_NUM_GANGS,
+						     clauses);
 	  c_name = "num_gangs";
 	  break;
 	case PRAGMA_OACC_CLAUSE_NUM_WORKERS:
-	  clauses = c_parser_omp_clause_num_workers (parser, clauses);
+	  clauses = c_parser_oacc_single_int_clause (parser,
+						     OMP_CLAUSE_NUM_WORKERS,
+						     clauses);
 	  c_name = "num_workers";
 	  break;
 	case PRAGMA_OACC_CLAUSE_PRESENT:
@@ -13341,7 +13261,9 @@ c_parser_oacc_all_clauses (c_parser *parser, omp_clause_mask mask,
 						c_name,	clauses);
 	  break;
 	case PRAGMA_OACC_CLAUSE_VECTOR_LENGTH:
-	  clauses = c_parser_omp_clause_vector_length (parser, clauses);
+	  clauses = c_parser_oacc_single_int_clause (parser,
+						     OMP_CLAUSE_VECTOR_LENGTH,
+						     clauses);
 	  c_name = "vector_length";
 	  break;
 	case PRAGMA_OACC_CLAUSE_WAIT:
diff --git gcc/testsuite/ChangeLog gcc/testsuite/ChangeLog
index e1e2641..13241be 100644
--- gcc/testsuite/ChangeLog
+++ gcc/testsuite/ChangeLog
@@ -1,5 +1,8 @@
 2017-05-12  Thomas Schwinge  <thomas@codesourcery.com>
 
+	* c-c++-common/goacc/parallel-dims-1.c: New file.
+	* c-c++-common/goacc/parallel-dims-2.c: Likewise.
+
 	* c-c++-common/goacc/classify-kernels-unparallelized.c: Adjust.
 	* c-c++-common/goacc/classify-kernels.c: Likewise.
 	* c-c++-common/goacc/kernels-counter-vars-function-scope.c:
diff --git gcc/testsuite/c-c++-common/goacc/parallel-dims-1.c gcc/testsuite/c-c++-common/goacc/parallel-dims-1.c
new file mode 100644
index 0000000..a85d3d3
--- /dev/null
+++ gcc/testsuite/c-c++-common/goacc/parallel-dims-1.c
@@ -0,0 +1,8 @@
+/* Valid use of OpenACC parallelism dimensions clauses: num_gangs, num_workers,
+   vector_length.  */
+
+void f(int i)
+{
+#pragma acc parallel num_gangs(i) num_workers(i) vector_length(i)
+  ;
+}
diff --git gcc/testsuite/c-c++-common/goacc/parallel-dims-2.c gcc/testsuite/c-c++-common/goacc/parallel-dims-2.c
new file mode 100644
index 0000000..30a3d17
--- /dev/null
+++ gcc/testsuite/c-c++-common/goacc/parallel-dims-2.c
@@ -0,0 +1,134 @@
+/* Invalid use of OpenACC parallelism dimensions clauses: num_gangs,
+   num_workers, vector_length.  */
+
+void acc_kernels(int i)
+{
+#pragma acc kernels num_gangs(i) /* { dg-error "'num_gangs' is not valid for '#pragma acc kernels'" } */
+  ;
+#pragma acc kernels num_workers(i) /* { dg-error "'num_workers' is not valid for '#pragma acc kernels'" } */
+  ;
+#pragma acc kernels vector_length(i) /* { dg-error "'vector_length' is not valid for '#pragma acc kernels'" } */
+  ;
+}
+
+void acc_parallel(int i, float f)
+{
+#pragma acc parallel num_gangs /* { dg-error "expected '\\(' before end of line" } */
+  ;
+#pragma acc parallel num_workers /* { dg-error "expected '\\(' before end of line" } */
+  ;
+#pragma acc parallel vector_length /* { dg-error "expected '\\(' before end of line" } */
+  ;
+
+#pragma acc parallel num_gangs( /* { dg-error "expected (primary-|)expression before end of line" } */
+  ;
+#pragma acc parallel num_workers( /* { dg-error "expected (primary-|)expression before end of line" } */
+  ;
+#pragma acc parallel vector_length( /* { dg-error "expected (primary-|)expression before end of line" } */
+  ;
+
+#pragma acc parallel num_gangs() /* { dg-error "expected (primary-|)expression before '\\)' token" } */
+  ;
+#pragma acc parallel num_workers() /* { dg-error "expected (primary-|)expression before '\\)' token" } */
+  ;
+#pragma acc parallel vector_length() /* { dg-error "expected (primary-|)expression before '\\)' token" } */
+  ;
+
+#pragma acc parallel num_gangs(1 /* { dg-error "expected '\\)' before end of line" } */
+  ;
+#pragma acc parallel num_workers(1 /* { dg-error "expected '\\)' before end of line" } */
+  ;
+#pragma acc parallel vector_length(1 /* { dg-error "expected '\\)' before end of line" } */
+  ;
+
+#pragma acc parallel num_gangs(i /* { dg-error "expected '\\)' before end of line" } */
+  ;
+#pragma acc parallel num_workers(i /* { dg-error "expected '\\)' before end of line" } */
+  ;
+#pragma acc parallel vector_length(i /* { dg-error "expected '\\)' before end of line" } */
+  ;
+
+#pragma acc parallel num_gangs(1 i /* { dg-error "expected '\\)' before 'i'" } */
+  ;
+#pragma acc parallel num_workers(1 i /* { dg-error "expected '\\)' before 'i'" } */
+  ;
+#pragma acc parallel vector_length(1 i /* { dg-error "expected '\\)' before 'i'" } */
+  ;
+
+#pragma acc parallel num_gangs(1 i) /* { dg-error "expected '\\)' before 'i'" } */
+  ;
+#pragma acc parallel num_workers(1 i) /* { dg-error "expected '\\)' before 'i'" } */
+  ;
+#pragma acc parallel vector_length(1 i) /* { dg-error "expected '\\)' before 'i'" } */
+  ;
+
+#pragma acc parallel num_gangs(1, i /* { dg-error "expected '\\)' before ',' token" "TODO" { xfail c } } */
+  /* { dg-bogus "expected '\\)' before end of line" "TODO" { xfail c } .-1 } */
+  ;
+#pragma acc parallel num_workers(1, i /* { dg-error "expected '\\)' before ',' token" "TODO" { xfail c } } */
+  /* { dg-bogus "expected '\\)' before end of line" "TODO" { xfail c } .-1 } */
+  ;
+#pragma acc parallel vector_length(1, i /* { dg-error "expected '\\)' before ',' token" "TODO" { xfail c } } */
+  /* { dg-bogus "expected '\\)' before end of line" "TODO" { xfail c } .-1 } */
+  ;
+
+#pragma acc parallel num_gangs(1, i) /* { dg-error "expected '\\)' before ',' token" "TODO" { xfail c } } */
+  ;
+#pragma acc parallel num_workers(1, i) /* { dg-error "expected '\\)' before ',' token" "TODO" { xfail c } } */
+  ;
+#pragma acc parallel vector_length(1, i) /* { dg-error "expected '\\)' before ',' token" "TODO" { xfail c } } */
+  ;
+
+#pragma acc parallel num_gangs(num_gangs) /* { dg-error "'num_gangs' (un|was not )declared" } */
+  ;
+#pragma acc parallel num_workers(num_workers) /* { dg-error "'num_workers' (un|was not )declared" } */
+  ;
+#pragma acc parallel vector_length(vector_length) /* { dg-error "'vector_length' (un|was not )declared" } */
+  ;
+
+#pragma acc parallel num_gangs(f) /* { dg-error "'num_gangs' expression must be integral" } */
+  ;
+#pragma acc parallel num_workers(f) /* { dg-error "'num_workers' expression must be integral" } */
+  ;
+#pragma acc parallel vector_length(f) /* { dg-error "'vector_length' expression must be integral" } */
+  ;
+
+#pragma acc parallel num_gangs((float) 1) /* { dg-error "'num_gangs' expression must be integral" } */
+  ;
+#pragma acc parallel num_workers((float) 1) /* { dg-error "'num_workers' expression must be integral" } */
+  ;
+#pragma acc parallel vector_length((float) 1) /* { dg-error "'vector_length' expression must be integral" } */
+  ;
+
+#pragma acc parallel num_gangs(0) /* { dg-warning "'num_gangs' value must be positive" } */
+  ;
+#pragma acc parallel num_workers(0) /* { dg-warning "'num_workers' value must be positive" } */
+  ;
+#pragma acc parallel vector_length(0) /* { dg-warning "'vector_length' value must be positive" } */
+  ;
+
+#pragma acc parallel num_gangs((int) -1.2) /* { dg-warning "'num_gangs' value must be positive" } */
+  ;
+#pragma acc parallel num_workers((int) -1.2) /* { dg-warning "'num_workers' value must be positive" } */
+  ;
+#pragma acc parallel vector_length((int) -1.2) /* { dg-warning "'vector_length' value must be positive" } */
+  ;
+
+#pragma acc parallel \
+  num_gangs(1) /* { dg-error "too many 'num_gangs' clauses" "" { target c } } */ \
+  num_workers(1) /* { dg-error "too many 'num_workers' clauses" "" { target c } } */ \
+  vector_length(1) /* { dg-error "too many 'vector_length' clauses" "" { target c } } */ \
+  num_workers(1) /* { dg-error "too many 'num_workers' clauses" "" { target c++ } } */ \
+  vector_length(1) /* { dg-error "too many 'vector_length' clauses" "" { target c++ } } */ \
+  num_gangs(1) /* { dg-error "too many 'num_gangs' clauses" "" { target c++ } } */
+  ;
+
+#pragma acc parallel \
+  num_gangs(-1) /* { dg-warning "'num_gangs' value must be positive" } */ \
+  num_workers() /* { dg-error "expected (primary-|)expression before '\\)' token" } */ \
+  vector_length(abc) /* { dg-error "'abc' (un|was not )declared" } */ \
+  num_workers(0.5) /* { dg-error "'num_workers' expression must be integral" } */ \
+  vector_length(&acc_parallel) /* { dg-error "'vector_length' expression must be integral" } */ \
+  num_gangs( /* { dg-error "expected (primary-|)expression before end of line" "TODO" { xfail c } } */
+  ;
+}

Committed to gomp-4_0-branch in r247961:

commit 1c87e0644c7e9f84f62c4b1a4f5bca35fba80b36
Author: tschwinge <tschwinge@138bc75d-0d04-0410-961f-82ee72b054a4>
Date:   Fri May 12 09:34:37 2017 +0000

    OpenACC C front end maintenance: c_parser_oacc_single_int_clause
    
            gcc/c/
            * c-parser.c (c_parser_omp_clause_num_gangs)
            (c_parser_omp_clause_num_workers)
            (c_parser_omp_clause_vector_length): Merge functions into...
            (c_parser_oacc_single_int_clause): ... this new function.  Adjust
            all users.
            gcc/testsuite/
            * c-c++-common/goacc/parallel-dims-1.c: New file.
            * c-c++-common/goacc/parallel-dims-2.c: Likewise.
    
    trunk r247960
    
    git-svn-id: svn+ssh://gcc.gnu.org/svn/gcc/branches/gomp-4_0-branch@247961 138bc75d-0d04-0410-961f-82ee72b054a4
---
 gcc/c/ChangeLog.gomp                               |   8 +
 gcc/c/c-parser.c                                   | 172 ++++++---------------
 gcc/testsuite/ChangeLog.gomp                       |   3 +
 gcc/testsuite/c-c++-common/goacc/parallel-dims-1.c |   9 ++
 gcc/testsuite/c-c++-common/goacc/parallel-dims-2.c | 134 ++++++++++++++++
 5 files changed, 202 insertions(+), 124 deletions(-)

diff --git gcc/c/ChangeLog.gomp gcc/c/ChangeLog.gomp
index c3b6798..3efcc8b 100644
--- gcc/c/ChangeLog.gomp
+++ gcc/c/ChangeLog.gomp
@@ -1,3 +1,11 @@
+2017-05-12  Thomas Schwinge  <thomas@codesourcery.com>
+
+	* c-parser.c (c_parser_omp_clause_num_gangs)
+	(c_parser_omp_clause_num_workers)
+	(c_parser_omp_clause_vector_length): Merge functions into...
+	(c_parser_oacc_single_int_clause): ... this new function.  Adjust
+	all users.
+
 2017-05-04  Cesar Philippidis  <cesar@codesourcery.com>
 
 	* c-parser.c (c_parser_omp_clause_name): Add support for if_present.
diff --git gcc/c/c-parser.c gcc/c/c-parser.c
index 957007e..ef61c5f 100644
--- gcc/c/c-parser.c
+++ gcc/c/c-parser.c
@@ -11217,50 +11217,6 @@ c_parser_omp_clause_nowait (c_parser *parser ATTRIBUTE_UNUSED, tree list)
   return c;
 }
 
-/* OpenACC:
-   num_gangs ( expression ) */
-
-static tree
-c_parser_omp_clause_num_gangs (c_parser *parser, tree list)
-{
-  location_t num_gangs_loc = c_parser_peek_token (parser)->location;
-  if (c_parser_require (parser, CPP_OPEN_PAREN, "expected %<(%>"))
-    {
-      location_t expr_loc = c_parser_peek_token (parser)->location;
-      tree c, t = c_parser_expression (parser).value;
-      mark_exp_read (t);
-      t = c_fully_fold (t, false, NULL);
-
-      c_parser_skip_until_found (parser, CPP_CLOSE_PAREN, "expected %<)%>");
-
-      if (!INTEGRAL_TYPE_P (TREE_TYPE (t)))
-	{
-	  c_parser_error (parser, "expected integer expression");
-	  return list;
-	}
-
-      /* Attempt to statically determine when the number isn't positive.  */
-      c = fold_build2_loc (expr_loc, LE_EXPR, boolean_type_node, t,
-		       build_int_cst (TREE_TYPE (t), 0));
-      protected_set_expr_location (c, expr_loc);
-      if (c == boolean_true_node)
-	{
-	  warning_at (expr_loc, 0,
-		      "%<num_gangs%> value must be positive");
-	  t = integer_one_node;
-	}
-
-      check_no_duplicate_clause (list, OMP_CLAUSE_NUM_GANGS, "num_gangs");
-
-      c = build_omp_clause (num_gangs_loc, OMP_CLAUSE_NUM_GANGS);
-      OMP_CLAUSE_NUM_GANGS_EXPR (c) = t;
-      OMP_CLAUSE_CHAIN (c) = list;
-      list = c;
-    }
-
-  return list;
-}
-
 /* OpenMP 2.5:
    num_threads ( expression ) */
 
@@ -11542,47 +11498,53 @@ c_parser_omp_clause_is_device_ptr (c_parser *parser, tree list)
 }
 
 /* OpenACC:
-   num_workers ( expression ) */
+   num_gangs ( expression )
+   num_workers ( expression )
+   vector_length ( expression )  */
 
 static tree
-c_parser_omp_clause_num_workers (c_parser *parser, tree list)
+c_parser_oacc_single_int_clause (c_parser *parser, omp_clause_code code,
+				 tree list)
 {
-  location_t num_workers_loc = c_parser_peek_token (parser)->location;
-  if (c_parser_require (parser, CPP_OPEN_PAREN, "expected %<(%>"))
+  location_t loc = c_parser_peek_token (parser)->location;
+
+  if (!c_parser_require (parser, CPP_OPEN_PAREN, "expected %<(%>"))
+    return list;
+
+  location_t expr_loc = c_parser_peek_token (parser)->location;
+  tree c, t = c_parser_expression (parser).value;
+  mark_exp_read (t);
+  t = c_fully_fold (t, false, NULL);
+
+  c_parser_skip_until_found (parser, CPP_CLOSE_PAREN, "expected %<)%>");
+
+  if (t == error_mark_node)
+    return list;
+  else if (!INTEGRAL_TYPE_P (TREE_TYPE (t)))
     {
-      location_t expr_loc = c_parser_peek_token (parser)->location;
-      tree c, t = c_parser_expression (parser).value;
-      mark_exp_read (t);
-      t = c_fully_fold (t, false, NULL);
+      error_at (expr_loc, "%qs expression must be integral",
+		omp_clause_code_name[code]);
+      return list;
+    }
 
-      c_parser_skip_until_found (parser, CPP_CLOSE_PAREN, "expected %<)%>");
-
-      if (!INTEGRAL_TYPE_P (TREE_TYPE (t)))
-	{
-	  c_parser_error (parser, "expected integer expression");
-	  return list;
-	}
-
-      /* Attempt to statically determine when the number isn't positive.  */
-      c = fold_build2_loc (expr_loc, LE_EXPR, boolean_type_node, t,
+  /* Attempt to statically determine when the number isn't positive.  */
+  c = fold_build2_loc (expr_loc, LE_EXPR, boolean_type_node, t,
 		       build_int_cst (TREE_TYPE (t), 0));
-      protected_set_expr_location (c, expr_loc);
-      if (c == boolean_true_node)
-	{
-	  warning_at (expr_loc, 0,
-		      "%<num_workers%> value must be positive");
-	  t = integer_one_node;
-	}
-
-      check_no_duplicate_clause (list, OMP_CLAUSE_NUM_WORKERS, "num_workers");
-
-      c = build_omp_clause (num_workers_loc, OMP_CLAUSE_NUM_WORKERS);
-      OMP_CLAUSE_NUM_WORKERS_EXPR (c) = t;
-      OMP_CLAUSE_CHAIN (c) = list;
-      list = c;
+  protected_set_expr_location (c, expr_loc);
+  if (c == boolean_true_node)
+    {
+      warning_at (expr_loc, 0,
+		  "%qs value must be positive",
+		  omp_clause_code_name[code]);
+      t = integer_one_node;
     }
 
-  return list;
+  check_no_duplicate_clause (list, code, omp_clause_code_name[code]);
+
+  c = build_omp_clause (loc, code);
+  OMP_CLAUSE_OPERAND (c, 0) = t;
+  OMP_CLAUSE_CHAIN (c) = list;
+  return c;
 }
 
 /* OpenACC:
@@ -12342,50 +12304,6 @@ c_parser_omp_clause_untied (c_parser *parser ATTRIBUTE_UNUSED, tree list)
   return c;
 }
 
-/* OpenACC:
-   vector_length ( expression ) */
-
-static tree
-c_parser_omp_clause_vector_length (c_parser *parser, tree list)
-{
-  location_t vector_length_loc = c_parser_peek_token (parser)->location;
-  if (c_parser_require (parser, CPP_OPEN_PAREN, "expected %<(%>"))
-    {
-      location_t expr_loc = c_parser_peek_token (parser)->location;
-      tree c, t = c_parser_expression (parser).value;
-      mark_exp_read (t);
-      t = c_fully_fold (t, false, NULL);
-
-      c_parser_skip_until_found (parser, CPP_CLOSE_PAREN, "expected %<)%>");
-
-      if (!INTEGRAL_TYPE_P (TREE_TYPE (t)))
-	{
-	  c_parser_error (parser, "expected integer expression");
-	  return list;
-	}
-
-      /* Attempt to statically determine when the number isn't positive.  */
-      c = fold_build2_loc (expr_loc, LE_EXPR, boolean_type_node, t,
-		       build_int_cst (TREE_TYPE (t), 0));
-      protected_set_expr_location (c, expr_loc);
-      if (c == boolean_true_node)
-	{
-	  warning_at (expr_loc, 0,
-		      "%<vector_length%> value must be positive");
-	  t = integer_one_node;
-	}
-
-      check_no_duplicate_clause (list, OMP_CLAUSE_VECTOR_LENGTH, "vector_length");
-
-      c = build_omp_clause (vector_length_loc, OMP_CLAUSE_VECTOR_LENGTH);
-      OMP_CLAUSE_VECTOR_LENGTH_EXPR (c) = t;
-      OMP_CLAUSE_CHAIN (c) = list;
-      list = c;
-    }
-
-  return list;
-}
-
 /* OpenMP 4.0:
    inbranch
    notinbranch */
@@ -13292,11 +13210,15 @@ c_parser_oacc_all_clauses (c_parser *parser, omp_clause_mask mask,
 	  c_name = "nohost";
 	  break;
 	case PRAGMA_OACC_CLAUSE_NUM_GANGS:
-	  clauses = c_parser_omp_clause_num_gangs (parser, clauses);
+	  clauses = c_parser_oacc_single_int_clause (parser,
+						     OMP_CLAUSE_NUM_GANGS,
+						     clauses);
 	  c_name = "num_gangs";
 	  break;
 	case PRAGMA_OACC_CLAUSE_NUM_WORKERS:
-	  clauses = c_parser_omp_clause_num_workers (parser, clauses);
+	  clauses = c_parser_oacc_single_int_clause (parser,
+						     OMP_CLAUSE_NUM_WORKERS,
+						     clauses);
 	  c_name = "num_workers";
 	  break;
 	case PRAGMA_OACC_CLAUSE_PRESENT:
@@ -13330,7 +13252,9 @@ c_parser_oacc_all_clauses (c_parser *parser, omp_clause_mask mask,
 						c_name,	clauses);
 	  break;
 	case PRAGMA_OACC_CLAUSE_VECTOR_LENGTH:
-	  clauses = c_parser_omp_clause_vector_length (parser, clauses);
+	  clauses = c_parser_oacc_single_int_clause (parser,
+						     OMP_CLAUSE_VECTOR_LENGTH,
+						     clauses);
 	  c_name = "vector_length";
 	  break;
 	case PRAGMA_OACC_CLAUSE_WAIT:
diff --git gcc/testsuite/ChangeLog.gomp gcc/testsuite/ChangeLog.gomp
index dadff1a..c24820d 100644
--- gcc/testsuite/ChangeLog.gomp
+++ gcc/testsuite/ChangeLog.gomp
@@ -1,5 +1,8 @@
 2017-05-12  Thomas Schwinge  <thomas@codesourcery.com>
 
+	* c-c++-common/goacc/parallel-dims-1.c: New file.
+	* c-c++-common/goacc/parallel-dims-2.c: Likewise.
+
 	* c-c++-common/goacc/classify-kernels-unparallelized.c: Adjust.
 	* c-c++-common/goacc/classify-kernels.c: Likewise.
 	* c-c++-common/goacc/kernels-acc-loop-reduction.c: Likewise.
diff --git gcc/testsuite/c-c++-common/goacc/parallel-dims-1.c gcc/testsuite/c-c++-common/goacc/parallel-dims-1.c
new file mode 100644
index 0000000..9e4cfaa
--- /dev/null
+++ gcc/testsuite/c-c++-common/goacc/parallel-dims-1.c
@@ -0,0 +1,9 @@
+/* Valid use of OpenACC parallelism dimensions clauses: num_gangs, num_workers,
+   vector_length.  */
+
+void f(int i)
+{
+#pragma acc parallel /* { dg-bogus "region is (gang|worker|vector) partitioned" "" { xfail *-*-* } } */ \
+  num_gangs(i) num_workers(i) vector_length(i)
+  ;
+}
diff --git gcc/testsuite/c-c++-common/goacc/parallel-dims-2.c gcc/testsuite/c-c++-common/goacc/parallel-dims-2.c
new file mode 100644
index 0000000..30a3d17
--- /dev/null
+++ gcc/testsuite/c-c++-common/goacc/parallel-dims-2.c
@@ -0,0 +1,134 @@
+/* Invalid use of OpenACC parallelism dimensions clauses: num_gangs,
+   num_workers, vector_length.  */
+
+void acc_kernels(int i)
+{
+#pragma acc kernels num_gangs(i) /* { dg-error "'num_gangs' is not valid for '#pragma acc kernels'" } */
+  ;
+#pragma acc kernels num_workers(i) /* { dg-error "'num_workers' is not valid for '#pragma acc kernels'" } */
+  ;
+#pragma acc kernels vector_length(i) /* { dg-error "'vector_length' is not valid for '#pragma acc kernels'" } */
+  ;
+}
+
+void acc_parallel(int i, float f)
+{
+#pragma acc parallel num_gangs /* { dg-error "expected '\\(' before end of line" } */
+  ;
+#pragma acc parallel num_workers /* { dg-error "expected '\\(' before end of line" } */
+  ;
+#pragma acc parallel vector_length /* { dg-error "expected '\\(' before end of line" } */
+  ;
+
+#pragma acc parallel num_gangs( /* { dg-error "expected (primary-|)expression before end of line" } */
+  ;
+#pragma acc parallel num_workers( /* { dg-error "expected (primary-|)expression before end of line" } */
+  ;
+#pragma acc parallel vector_length( /* { dg-error "expected (primary-|)expression before end of line" } */
+  ;
+
+#pragma acc parallel num_gangs() /* { dg-error "expected (primary-|)expression before '\\)' token" } */
+  ;
+#pragma acc parallel num_workers() /* { dg-error "expected (primary-|)expression before '\\)' token" } */
+  ;
+#pragma acc parallel vector_length() /* { dg-error "expected (primary-|)expression before '\\)' token" } */
+  ;
+
+#pragma acc parallel num_gangs(1 /* { dg-error "expected '\\)' before end of line" } */
+  ;
+#pragma acc parallel num_workers(1 /* { dg-error "expected '\\)' before end of line" } */
+  ;
+#pragma acc parallel vector_length(1 /* { dg-error "expected '\\)' before end of line" } */
+  ;
+
+#pragma acc parallel num_gangs(i /* { dg-error "expected '\\)' before end of line" } */
+  ;
+#pragma acc parallel num_workers(i /* { dg-error "expected '\\)' before end of line" } */
+  ;
+#pragma acc parallel vector_length(i /* { dg-error "expected '\\)' before end of line" } */
+  ;
+
+#pragma acc parallel num_gangs(1 i /* { dg-error "expected '\\)' before 'i'" } */
+  ;
+#pragma acc parallel num_workers(1 i /* { dg-error "expected '\\)' before 'i'" } */
+  ;
+#pragma acc parallel vector_length(1 i /* { dg-error "expected '\\)' before 'i'" } */
+  ;
+
+#pragma acc parallel num_gangs(1 i) /* { dg-error "expected '\\)' before 'i'" } */
+  ;
+#pragma acc parallel num_workers(1 i) /* { dg-error "expected '\\)' before 'i'" } */
+  ;
+#pragma acc parallel vector_length(1 i) /* { dg-error "expected '\\)' before 'i'" } */
+  ;
+
+#pragma acc parallel num_gangs(1, i /* { dg-error "expected '\\)' before ',' token" "TODO" { xfail c } } */
+  /* { dg-bogus "expected '\\)' before end of line" "TODO" { xfail c } .-1 } */
+  ;
+#pragma acc parallel num_workers(1, i /* { dg-error "expected '\\)' before ',' token" "TODO" { xfail c } } */
+  /* { dg-bogus "expected '\\)' before end of line" "TODO" { xfail c } .-1 } */
+  ;
+#pragma acc parallel vector_length(1, i /* { dg-error "expected '\\)' before ',' token" "TODO" { xfail c } } */
+  /* { dg-bogus "expected '\\)' before end of line" "TODO" { xfail c } .-1 } */
+  ;
+
+#pragma acc parallel num_gangs(1, i) /* { dg-error "expected '\\)' before ',' token" "TODO" { xfail c } } */
+  ;
+#pragma acc parallel num_workers(1, i) /* { dg-error "expected '\\)' before ',' token" "TODO" { xfail c } } */
+  ;
+#pragma acc parallel vector_length(1, i) /* { dg-error "expected '\\)' before ',' token" "TODO" { xfail c } } */
+  ;
+
+#pragma acc parallel num_gangs(num_gangs) /* { dg-error "'num_gangs' (un|was not )declared" } */
+  ;
+#pragma acc parallel num_workers(num_workers) /* { dg-error "'num_workers' (un|was not )declared" } */
+  ;
+#pragma acc parallel vector_length(vector_length) /* { dg-error "'vector_length' (un|was not )declared" } */
+  ;
+
+#pragma acc parallel num_gangs(f) /* { dg-error "'num_gangs' expression must be integral" } */
+  ;
+#pragma acc parallel num_workers(f) /* { dg-error "'num_workers' expression must be integral" } */
+  ;
+#pragma acc parallel vector_length(f) /* { dg-error "'vector_length' expression must be integral" } */
+  ;
+
+#pragma acc parallel num_gangs((float) 1) /* { dg-error "'num_gangs' expression must be integral" } */
+  ;
+#pragma acc parallel num_workers((float) 1) /* { dg-error "'num_workers' expression must be integral" } */
+  ;
+#pragma acc parallel vector_length((float) 1) /* { dg-error "'vector_length' expression must be integral" } */
+  ;
+
+#pragma acc parallel num_gangs(0) /* { dg-warning "'num_gangs' value must be positive" } */
+  ;
+#pragma acc parallel num_workers(0) /* { dg-warning "'num_workers' value must be positive" } */
+  ;
+#pragma acc parallel vector_length(0) /* { dg-warning "'vector_length' value must be positive" } */
+  ;
+
+#pragma acc parallel num_gangs((int) -1.2) /* { dg-warning "'num_gangs' value must be positive" } */
+  ;
+#pragma acc parallel num_workers((int) -1.2) /* { dg-warning "'num_workers' value must be positive" } */
+  ;
+#pragma acc parallel vector_length((int) -1.2) /* { dg-warning "'vector_length' value must be positive" } */
+  ;
+
+#pragma acc parallel \
+  num_gangs(1) /* { dg-error "too many 'num_gangs' clauses" "" { target c } } */ \
+  num_workers(1) /* { dg-error "too many 'num_workers' clauses" "" { target c } } */ \
+  vector_length(1) /* { dg-error "too many 'vector_length' clauses" "" { target c } } */ \
+  num_workers(1) /* { dg-error "too many 'num_workers' clauses" "" { target c++ } } */ \
+  vector_length(1) /* { dg-error "too many 'vector_length' clauses" "" { target c++ } } */ \
+  num_gangs(1) /* { dg-error "too many 'num_gangs' clauses" "" { target c++ } } */
+  ;
+
+#pragma acc parallel \
+  num_gangs(-1) /* { dg-warning "'num_gangs' value must be positive" } */ \
+  num_workers() /* { dg-error "expected (primary-|)expression before '\\)' token" } */ \
+  vector_length(abc) /* { dg-error "'abc' (un|was not )declared" } */ \
+  num_workers(0.5) /* { dg-error "'num_workers' expression must be integral" } */ \
+  vector_length(&acc_parallel) /* { dg-error "'vector_length' expression must be integral" } */ \
+  num_gangs( /* { dg-error "expected (primary-|)expression before end of line" "TODO" { xfail c } } */
+  ;
+}
