diff mbox

[gomp4] Update error messages for c and c++ reductions

Message ID 202abf8e-a34c-46ab-0536-b500410e658e@codesourcery.com
State New
Headers show

Commit Message

Cesar Philippidis April 26, 2017, 8:08 p.m. UTC
This patches updates the c and c++ FEs to report consistent error
messages for invalid reductions involving array elements, struct
members, and class members. Most of those variables were already
rejected by the generic OpenMP code, but this patch makes the error
messages more precise for OpenACC. It also fixes an ICE involving
invalid struct member reductions in c.

I've committed this patch to gomp-4_0-branch.

Cesar

Comments

Thomas Schwinge Oct. 24, 2019, 2:07 p.m. UTC | #1
Hi!

On 2017-04-26T13:08:11-0700, Cesar Philippidis <cesar@codesourcery.com> wrote:
> This patches updates the c and c++ FEs to report consistent error
> messages for invalid reductions involving array elements, struct
> members, and class members. Most of those variables were already
> rejected by the generic OpenMP code, but this patch makes the error
> messages more precise for OpenACC. It also fixes an ICE involving
> invalid struct member reductions in c.
>
> I've committed this patch to gomp-4_0-branch.

It then got into openacc-gcc-8-branch in commit
16ead336bc86fade855e0ec2edfc257286f429b6 "[OpenACC] Update error messages
for c and c++ reductions", was proposed for GCC trunk in
<http://mid.mail-archive.com/ae587152-072d-52b0-0129-99de0ed40d03@codesourcery.com>
"various OpenACC reduction enhancements" (together with other, unrelated
changes...), and got into openacc-gcc-9-branch in commit
533beb2ec19f8486e4b1b645a153746f96b41f04 "Various OpenACC reduction
enhancements - FE changes" (together with other, unrelated changes...).


At least in their og8 incarnation (have not yet verified other
branches/patches), I find these changes cause quite a serious regression
in the C front end.  Given the buggy:

    #pragma acc routine vector
    int f(int n)
    {
      int plus = 0;
      int minus = 0;
    #pragma acc loop reduction(+:plus, -:minus)
      for (int i = 0; i < n; ++i)
        ++plus, --minus;
    
      return plus * minus;
    }

..., where we used to (and still do for C++) diagnose:

    [...]: In function 'f':
    [...]:6:35: error: expected ')' before '-' token
     #pragma acc loop reduction(+:plus, -:minus)
                               ~       ^~
                                       )

..., with the patch applied, this doesn't get any diagnostic anymore, so
wrong-code gets generated.


Grüße
 Thomas


> 	gcc/c/
> 	* c-parser.c (c_parser_omp_variable_list): New c_omp_region_type
> 	argument.  Use it to specialize handling of OMP_CLAUSE_REDUCTION for
> 	OpenACC.
> 	(c_parser_omp_clause_reduction): Update call to
> 	c_parser_omp_variable_list.  Propage OpenACC errors as necessary.
> 	(c_parser_oacc_all_clauses): Update call to
> 	p_parser_omp_clause_reduction.
> 	(c_parser_omp_all_clauses): Likewise.
> 	(c_parser_cilk_all_clauses): Likewise.
>
> 	gcc/cp/
> 	* parser.c (cp_parser_omp_var_list_no_open): New c_omp_region_type
> 	argument.  Use it to specialize handling of OMP_CLAUSE_REDUCTION for
> 	OpenACC.
> 	(cp_parser_omp_clause_reduction): Update call to
> 	cp_parser_omp_variable_list.  Propage OpenACC errors as necessary.
> 	(cp_parser_oacc_all_clauses): Update call to
> 	cp_parser_omp_clause_reduction..
> 	(cp_parser_omp_all_clauses): Liekwise.
> 	(cp_parser_cilk_simd_all_clauses): Likewise.
>
> 	gcc/testsuite/
> 	* c-c++-common/goacc/reduction-7.c: New test.
> 	* g++.dg/goacc/reductions-1.C: New test.

> diff --git a/gcc/c/c-parser.c b/gcc/c/c-parser.c
> index 05b9774..b1af31f 100644
> --- a/gcc/c/c-parser.c
> +++ b/gcc/c/c-parser.c
> @@ -10618,7 +10618,8 @@ c_parser_oacc_wait_list (c_parser *parser, location_t clause_loc, tree list)
>  static tree
>  c_parser_omp_variable_list (c_parser *parser,
>  			    location_t clause_loc,
> -			    enum omp_clause_code kind, tree list)
> +			    enum omp_clause_code kind, tree list,
> +			    enum c_omp_region_type ort = C_ORT_OMP)
>  {
>    if (c_parser_next_token_is_not (parser, CPP_NAME)
>        || c_parser_peek_token (parser)->id_kind != C_ID_ID)
> @@ -10674,6 +10675,22 @@ c_parser_omp_variable_list (c_parser *parser,
>  	      /* FALLTHROUGH  */
>  	    case OMP_CLAUSE_DEPEND:
>  	    case OMP_CLAUSE_REDUCTION:
> +	      if (kind == OMP_CLAUSE_REDUCTION && ort == C_ORT_ACC)
> +		{
> +		  switch (c_parser_peek_token (parser)->type)
> +		    {
> +		    case CPP_OPEN_PAREN:
> +		    case CPP_OPEN_SQUARE:
> +		    case CPP_DOT:
> +		    case CPP_DEREF:
> +		      error ("invalid reduction variable");
> +		      t = error_mark_node;
> +		    default:;
> +		      break;
> +		    }
> +		  if (t == error_mark_node)
> +		    break;
> +		}
>  	      while (c_parser_next_token_is (parser, CPP_OPEN_SQUARE))
>  		{
>  		  tree low_bound = NULL_TREE, length = NULL_TREE;
> @@ -12039,9 +12056,12 @@ c_parser_omp_clause_private (c_parser *parser, tree list)
>       identifier  */
>  
>  static tree
> -c_parser_omp_clause_reduction (c_parser *parser, tree list)
> +c_parser_omp_clause_reduction (c_parser *parser, tree list,
> +			       enum c_omp_region_type ort)
>  {
>    location_t clause_loc = c_parser_peek_token (parser)->location;
> +  bool seen_error = false;
> +
>    if (c_parser_require (parser, CPP_OPEN_PAREN, "expected %<(%>"))
>      {
>        enum tree_code code = ERROR_MARK;
> @@ -12104,7 +12124,13 @@ c_parser_omp_clause_reduction (c_parser *parser, tree list)
>  	  tree nl, c;
>  
>  	  nl = c_parser_omp_variable_list (parser, clause_loc,
> -					   OMP_CLAUSE_REDUCTION, list);
> +					   OMP_CLAUSE_REDUCTION, list, ort);
> +	  if (c_parser_peek_token (parser)->type != CPP_CLOSE_PAREN)
> +	    {
> +	      seen_error = true;
> +	      goto cleanup;
> +	    }
> +
>  	  for (c = nl; c != list; c = OMP_CLAUSE_CHAIN (c))
>  	    {
>  	      tree d = OMP_CLAUSE_DECL (c), type;
> @@ -12133,14 +12159,16 @@ c_parser_omp_clause_reduction (c_parser *parser, tree list)
>  		  || !(INTEGRAL_TYPE_P (type)
>  		       || TREE_CODE (type) == REAL_TYPE
>  		       || TREE_CODE (type) == COMPLEX_TYPE))
> -		OMP_CLAUSE_REDUCTION_PLACEHOLDER (c)
> +		  OMP_CLAUSE_REDUCTION_PLACEHOLDER (c)
>  		  = c_omp_reduction_lookup (reduc_id,
>  					    TYPE_MAIN_VARIANT (type));
>  	    }
>  
>  	  list = nl;
>  	}
> -      c_parser_skip_until_found (parser, CPP_CLOSE_PAREN, "expected %<)%>");
> +    cleanup:
> +      c_parser_skip_until_found (parser, CPP_CLOSE_PAREN,
> +				 seen_error ? NULL : "expected %<)%>");
>      }
>    return list;
>  }
> @@ -13272,7 +13300,7 @@ c_parser_oacc_all_clauses (c_parser *parser, omp_clause_mask mask,
>  	  c_name = "private";
>  	  break;
>  	case PRAGMA_OACC_CLAUSE_REDUCTION:
> -	  clauses = c_parser_omp_clause_reduction (parser, clauses);
> +	  clauses = c_parser_omp_clause_reduction (parser, clauses, C_ORT_ACC);
>  	  c_name = "reduction";
>  	  break;
>  	case PRAGMA_OACC_CLAUSE_SEQ:
> @@ -13432,7 +13460,7 @@ c_parser_omp_all_clauses (c_parser *parser, omp_clause_mask mask,
>  	  c_name = "private";
>  	  break;
>  	case PRAGMA_OMP_CLAUSE_REDUCTION:
> -	  clauses = c_parser_omp_clause_reduction (parser, clauses);
> +	  clauses = c_parser_omp_clause_reduction (parser, clauses, C_ORT_OMP);
>  	  c_name = "reduction";
>  	  break;
>  	case PRAGMA_OMP_CLAUSE_SCHEDULE:
> @@ -17764,7 +17792,7 @@ c_parser_cilk_all_clauses (c_parser *parser)
>  	  break;
>  	case PRAGMA_CILK_CLAUSE_REDUCTION:
>  	  /* Use the OpenMP counterpart.  */
> -	  clauses = c_parser_omp_clause_reduction (parser, clauses);
> +	  clauses = c_parser_omp_clause_reduction (parser, clauses, C_ORT_CILK);
>  	  break;
>  	default:
>  	  c_parser_error (parser, "expected %<#pragma simd%> clause");
> diff --git a/gcc/cp/parser.c b/gcc/cp/parser.c
> index 4080b8a..b082feb 100644
> --- a/gcc/cp/parser.c
> +++ b/gcc/cp/parser.c
> @@ -30009,7 +30009,8 @@ check_no_duplicate_clause (tree clauses, enum omp_clause_code code,
>  
>  static tree
>  cp_parser_omp_var_list_no_open (cp_parser *parser, enum omp_clause_code kind,
> -				tree list, bool *colon)
> +				tree list, bool *colon,
> +				enum c_omp_region_type ort = C_ORT_OMP)
>  {
>    cp_token *token;
>    bool saved_colon_corrects_to_scope_p = parser->colon_corrects_to_scope_p;
> @@ -30082,6 +30083,21 @@ cp_parser_omp_var_list_no_open (cp_parser *parser, enum omp_clause_code kind,
>  	      /* FALLTHROUGH.  */
>  	    case OMP_CLAUSE_DEPEND:
>  	    case OMP_CLAUSE_REDUCTION:
> +	      if (kind == OMP_CLAUSE_REDUCTION && ort == C_ORT_ACC)
> +		{
> +		  switch (cp_lexer_peek_token (parser->lexer)->type)
> +		    {
> +		    case CPP_OPEN_PAREN:
> +		    case CPP_OPEN_SQUARE:
> +		    case CPP_DOT:
> +		    case CPP_DEREF:
> +		      error ("invalid reduction variable");
> +		      decl = error_mark_node;
> +		      goto skip_comma;
> +		    default:;
> +		      break;
> +		    }
> +		}
>  	      while (cp_lexer_next_token_is (parser->lexer, CPP_OPEN_SQUARE))
>  		{
>  		  tree low_bound = NULL_TREE, length = NULL_TREE;
> @@ -31215,7 +31231,8 @@ cp_parser_omp_clause_ordered (cp_parser *parser,
>       id-expression  */
>  
>  static tree
> -cp_parser_omp_clause_reduction (cp_parser *parser, tree list)
> +cp_parser_omp_clause_reduction (cp_parser *parser, tree list,
> +				enum c_omp_region_type ort)
>  {
>    enum tree_code code = ERROR_MARK;
>    tree nlist, c, id = NULL_TREE;
> @@ -31296,7 +31313,7 @@ cp_parser_omp_clause_reduction (cp_parser *parser, tree list)
>      goto resync_fail;
>  
>    nlist = cp_parser_omp_var_list_no_open (parser, OMP_CLAUSE_REDUCTION, list,
> -					  NULL);
> +					  NULL, ort);
>    for (c = nlist; c != list; c = OMP_CLAUSE_CHAIN (c))
>      {
>        OMP_CLAUSE_REDUCTION_CODE (c) = code;
> @@ -32426,7 +32443,7 @@ cp_parser_oacc_all_clauses (cp_parser *parser, omp_clause_mask mask,
>  	  c_name = "private";
>  	  break;
>  	case PRAGMA_OACC_CLAUSE_REDUCTION:
> -	  clauses = cp_parser_omp_clause_reduction (parser, clauses);
> +	  clauses = cp_parser_omp_clause_reduction (parser, clauses, C_ORT_ACC);
>  	  c_name = "reduction";
>  	  break;
>  	case PRAGMA_OACC_CLAUSE_SEQ:
> @@ -32618,7 +32635,7 @@ cp_parser_omp_all_clauses (cp_parser *parser, omp_clause_mask mask,
>  	  c_name = "private";
>  	  break;
>  	case PRAGMA_OMP_CLAUSE_REDUCTION:
> -	  clauses = cp_parser_omp_clause_reduction (parser, clauses);
> +	  clauses = cp_parser_omp_clause_reduction (parser, clauses, C_ORT_OMP);
>  	  c_name = "reduction";
>  	  break;
>  	case PRAGMA_OMP_CLAUSE_SCHEDULE:
> @@ -38038,7 +38055,7 @@ cp_parser_cilk_simd_all_clauses (cp_parser *parser, cp_token *pragma_token)
>  					  clauses);
>        else if (c_kind == PRAGMA_CILK_CLAUSE_REDUCTION)
>  	/* Use the OMP 4.0 equivalent function.  */
> -	clauses = cp_parser_omp_clause_reduction (parser, clauses);
> +	clauses = cp_parser_omp_clause_reduction (parser, clauses, C_ORT_CILK);
>        else
>  	{
>  	  clauses = error_mark_node;
> diff --git a/gcc/testsuite/c-c++-common/goacc/reduction-7.c b/gcc/testsuite/c-c++-common/goacc/reduction-7.c
> new file mode 100644
> index 0000000..5d48dda
> --- /dev/null
> +++ b/gcc/testsuite/c-c++-common/goacc/reduction-7.c
> @@ -0,0 +1,113 @@
> +/* Exercise invalid reductions on array and struct members.  */
> +
> +/* { dg-compile } */
> +
> +void
> +test_parallel ()
> +{
> +  struct {
> +    int a;
> +    float b[5];
> +  } s1, s2[10];
> +
> +  int i;
> +  double z[100];
> +
> +#pragma acc parallel reduction(+:s1.a) /* { dg-error "invalid reduction variable" } */
> +  for (i = 0; i < 10; i++)
> +    s1.a += 1;
> +
> +#pragma acc parallel reduction(+:s1.b[3]) /* { dg-error "invalid reduction variable" } */
> +  for (i = 0; i < 10; i++)
> +    s1.b[3] += 1;
> +
> +#pragma acc parallel reduction(+:s2[2].a) /* { dg-error "invalid reduction variable" } */
> +  for (i = 0; i < 10; i++)
> +    s2[2].a += 1;
> +
> +#pragma acc parallel reduction(+:s2[3].b[4]) /* { dg-error "invalid reduction variable" } */
> +  for (i = 0; i < 10; i++)
> +    s2[3].b[4] += 1;
> +
> +#pragma acc parallel reduction(+:z[5]) /* { dg-error "invalid reduction variable" } */
> +  for (i = 0; i < 10; i++)
> +    z[5] += 1;
> +}
> +
> +void
> +test_combined ()
> +{
> +  struct {
> +    int a;
> +    float b[5];
> +  } s1, s2[10];
> +
> +  int i;
> +  double z[100];
> +
> +#pragma acc parallel loop reduction(+:s1.a) /* { dg-error "invalid reduction variable" } */
> +  for (i = 0; i < 10; i++)
> +    s1.a += 1;
> +
> +#pragma acc parallel loop reduction(+:s1.b[3]) /* { dg-error "invalid reduction variable" } */
> +  for (i = 0; i < 10; i++)
> +    s1.b[3] += 1;
> +
> +#pragma acc parallel loop reduction(+:s2[2].a) /* { dg-error "invalid reduction variable" } */
> +  for (i = 0; i < 10; i++)
> +    s2[2].a += 1;
> +
> +#pragma acc parallel loop reduction(+:s2[3].b[4]) /* { dg-error "invalid reduction variable" } */
> +  for (i = 0; i < 10; i++)
> +    s2[3].b[4] += 1;
> +
> +#pragma acc parallel loop reduction(+:z[5]) /* { dg-error "invalid reduction variable" } */
> +  for (i = 0; i < 10; i++)
> +    z[5] += 1;
> +
> +}
> +
> +void
> +test_loops ()
> +{
> +  struct {
> +    int a;
> +    float b[5];
> +  } s1, s2[10];
> +
> +  int i;
> +  double z[100];
> +
> +#pragma acc parallel
> +  {
> +#pragma acc loop reduction(+:s1.a) /* { dg-error "invalid reduction variable" } */
> +  for (i = 0; i < 10; i++)
> +    s1.a += 1;
> +
> +#pragma acc loop reduction(+:s1.b[3]) /* { dg-error "invalid reduction variable" } */
> +  for (i = 0; i < 10; i++)
> +    s1.b[3] += 1;
> +
> +#pragma acc loop reduction(+:s2[2].a) /* { dg-error "invalid reduction variable" } */
> +  for (i = 0; i < 10; i++)
> +    s2[2].a += 1;
> +
> +#pragma acc loop reduction(+:s2[3].b[4]) /* { dg-error "invalid reduction variable" } */
> +  for (i = 0; i < 10; i++)
> +    s2[3].b[4] += 1;
> +
> +#pragma acc loop reduction(+:z[5]) /* { dg-error "invalid reduction variable" } */
> +  for (i = 0; i < 10; i++)
> +    z[5] += 1;
> +  }
> +}
> +
> +int
> +main ()
> +{
> +  test_parallel ();
> +  test_combined ();
> +  test_loops ();
> +
> +  return 0;
> +}
> diff --git a/gcc/testsuite/g++.dg/goacc/reductions-1.C b/gcc/testsuite/g++.dg/goacc/reductions-1.C
> new file mode 100644
> index 0000000..50a6e5e
> --- /dev/null
> +++ b/gcc/testsuite/g++.dg/goacc/reductions-1.C
> @@ -0,0 +1,550 @@
> +// Test for invalid reduction variables.
> +
> +// { dg-do compile }
> +
> +class C1
> +{
> +  int b, d[10];
> +
> +public:
> +  int a, c[10];
> +
> +  C1 () { a = 0; b = 0; }
> +  int& get_b () { return b; }
> +  int* get_d () { return d; }
> +};
> +
> +template <typename T>
> +class C2
> +{
> +  T b, d[10];
> +
> +public:
> +  T a, c[10];
> +
> +  C2 () { a = 0; b = 0; }
> +  T& get_b () { return b; }
> +  T* get_d () { return d; }
> +};
> +
> +struct S1
> +{
> +  int a, b, c[10], d[10];
> +
> +  S1 () { a = 0; b = 0; }
> +  int& get_b () { return b; }
> +  int* get_d () { return d; }
> +};
> +
> +template <typename T>
> +struct S2
> +{
> +  T a, b, c[10], d[10];
> +
> +  S2 () { a = 0; b = 0; }
> +  T& get_b () { return b; }
> +  T* get_d () { return d; }
> +};
> +
> +template <typename T>
> +void
> +test_parallel ()
> +{
> +  int i, a[10];
> +  T b[10];
> +  C1 c1, c1a[10];
> +  C2<T> c2, c2a[10];
> +  S1 s1, s1a[10];
> +  S2<float> s2, s2a[10];
> +
> +  // Reductions on class members.
> +
> +#pragma acc parallel reduction(+:c1.a) // { dg-error "invalid reduction variable" }
> +  for (i = 0; i < 100; i++)
> +    c1.a += 1;
> +
> +#pragma acc parallel reduction(+:c1.get_b ()) // { dg-error "invalid reduction variable" }
> +  for (i = 0; i < 100; i++)
> +    c1.get_b () += 1;
> +
> +#pragma acc parallel reduction(+:c1.c[1]) // { dg-error "invalid reduction variable" }
> +  for (i = 0; i < 100; i++)
> +    c1.c[1] += 1;
> +
> +#pragma acc parallel reduction(+:c1.get_d ()[1]) // { dg-error "invalid reduction variable" }
> +  for (i = 0; i < 100; i++)
> +    c1.get_d ()[1] += 1;
> +
> +#pragma acc parallel reduction(+:c1a[1].a) // { dg-error "invalid reduction variable" }
> +  for (i = 0; i < 100; i++)
> +    c1a[1].a += 1;
> +
> +#pragma acc parallel reduction(+:c1a[1].get_b ()) // { dg-error "invalid reduction variable" }
> +  for (i = 0; i < 100; i++)
> +    c1a[1].get_b () += 1;
> +
> +#pragma acc parallel reduction(+:c1a[1].c[1]) // { dg-error "invalid reduction variable" }
> +  for (i = 0; i < 100; i++)
> +    c1a[1].c[1] += 1;
> +
> +#pragma acc parallel reduction(+:c1a[1].get_d ()[1]) // { dg-error "invalid reduction variable" }
> +  for (i = 0; i < 100; i++)
> +    c1a[1].get_d ()[1] += 1;
> +
> +
> +  // Reductions on a template class member.
> +
> +#pragma acc parallel reduction(+:c2.a) // { dg-error "invalid reduction variable" }
> +  for (i = 0; i < 100; i++)
> +    c2.a += 1;
> +
> +#pragma acc parallel reduction(+:c2.get_b ()) // { dg-error "invalid reduction variable" }
> +  for (i = 0; i < 100; i++)
> +    c2.get_b () += 1;
> +
> +#pragma acc parallel reduction(+:c2.c[1]) // { dg-error "invalid reduction variable" }
> +  for (i = 0; i < 100; i++)
> +    c2.c[1] += 1;
> +
> +#pragma acc parallel reduction(+:c2.get_d ()[1]) // { dg-error "invalid reduction variable" }
> +  for (i = 0; i < 100; i++)
> +    c2.get_d ()[1] += 1;
> +
> +
> +#pragma acc parallel reduction(+:c2a[1].a) // { dg-error "invalid reduction variable" }
> +  for (i = 0; i < 100; i++)
> +    c2a[1].a += 1;
> +
> +#pragma acc parallel reduction(+:c2a[1].get_b ()[1]) // { dg-error "invalid reduction variable" }
> +  for (i = 0; i < 100; i++)
> +    c2a[1].get_b () += 1;
> +
> +#pragma acc parallel reduction(+:c2a[1].c[1]) // { dg-error "invalid reduction variable" }
> +  for (i = 0; i < 100; i++)
> +    c2a[1].c[1] += 1;
> +
> +#pragma acc parallel reduction(+:c2a[1].get_d ()[1]) // { dg-error "invalid reduction variable" }
> +  for (i = 0; i < 100; i++)
> +    c2a[1].get_d ()[1] += 1;
> +
> +
> +  // Reductions on struct element.
> +
> +#pragma acc parallel reduction(+:s1.a) // { dg-error "invalid reduction variable" }
> +  for (i = 0; i < 100; i++)
> +    s1.a += 1;
> +
> +#pragma acc parallel reduction(+:s1.get_b ()) // { dg-error "invalid reduction variable" }
> +  for (i = 0; i < 100; i++)
> +    s1.get_b () += 1;
> +
> +#pragma acc parallel reduction(+:s1.c[1]) // { dg-error "invalid reduction variable" }
> +  for (i = 0; i < 100; i++)
> +    s1.c[1] += 1;
> +
> +#pragma acc parallel reduction(+:s1.get_d ()[1]) // { dg-error "invalid reduction variable" }
> +  for (i = 0; i < 100; i++)
> +    s1.get_d ()[1] += 1;
> +
> +#pragma acc parallel reduction(+:s1a[1].a) // { dg-error "invalid reduction variable" }
> +  for (i = 0; i < 100; i++)
> +    s1a[1].a += 1;
> +
> +#pragma acc parallel reduction(+:s1a[1].get_b ()) // { dg-error "invalid reduction variable" }
> +  for (i = 0; i < 100; i++)
> +    s1a[1].get_b () += 1;
> +
> +#pragma acc parallel reduction(+:s1a[1].c[1]) // { dg-error "invalid reduction variable" }
> +  for (i = 0; i < 100; i++)
> +    s1a[1].c[1] += 1;
> +
> +#pragma acc parallel reduction(+:s1a[1].get_d ()[1]) // { dg-error "invalid reduction variable" }
> +  for (i = 0; i < 100; i++)
> +    s1a[1].get_d ()[1] += 1;
> +
> +
> +  // Reductions on a template struct element.
> +
> +#pragma acc parallel reduction(+:s2.a) // { dg-error "invalid reduction variable" }
> +  for (i = 0; i < 100; i++)
> +    s2.a += 1;
> +
> +#pragma acc parallel reduction(+:s2.get_b ()) // { dg-error "invalid reduction variable" }
> +  for (i = 0; i < 100; i++)
> +    s2.get_b () += 1;
> +
> +#pragma acc parallel reduction(+:s2.c[1]) // { dg-error "invalid reduction variable" }
> +  for (i = 0; i < 100; i++)
> +    s2.c[1] += 1;
> +
> +#pragma acc parallel reduction(+:s2.get_d ()[1]) // { dg-error "invalid reduction variable" }
> +  for (i = 0; i < 100; i++)
> +    s2.get_d ()[1] += 1;
> +
> +#pragma acc parallel reduction(+:s2a[1].a) // { dg-error "invalid reduction variable" }
> +  for (i = 0; i < 100; i++)
> +    s2a[1].a += 1;
> +
> +#pragma acc parallel reduction(+:s2a[1].get_b ()) // { dg-error "invalid reduction variable" }
> +  for (i = 0; i < 100; i++)
> +    s2a[1].get_b () += 1;
> +
> +#pragma acc parallel reduction(+:s2a[1].c[1]) // { dg-error "invalid reduction variable" }
> +  for (i = 0; i < 100; i++)
> +    s2a[1].c[1] += 1;
> +
> +#pragma acc parallel reduction(+:s2a[1].get_d ()[1]) // { dg-error "invalid reduction variable" }
> +  for (i = 0; i < 100; i++)
> +    s2a[1].get_d ()[1] += 1;
> +
> +
> +  // Reductions on arrays.
> +
> +#pragma acc parallel reduction(+:a[10]) // { dg-error "invalid reduction variable" }
> +  for (i = 0; i < 100; i++)
> +    a[10] += 1;
> +
> +#pragma acc parallel reduction(+:b[10]) // { dg-error "invalid reduction variable" }
> +  for (i = 0; i < 100; i++)
> +    b[10] += 1;
> +}
> +
> +template <typename T>
> +void
> +test_combined ()
> +{
> +  int i, a[10];
> +  T b[10];
> +  C1 c1, c1a[10];
> +  C2<T> c2, c2a[10];
> +  S1 s1, s1a[10];
> +  S2<float> s2, s2a[10];
> +
> +  // Reductions on class members.
> +
> +#pragma acc parallel loop reduction(+:c1.a) // { dg-error "invalid reduction variable" }
> +  for (i = 0; i < 100; i++)
> +    c1.a += 1;
> +
> +#pragma acc parallel loop reduction(+:c1.get_b ()) // { dg-error "invalid reduction variable" }
> +  for (i = 0; i < 100; i++)
> +    c1.get_b () += 1;
> +
> +#pragma acc parallel loop reduction(+:c1.c[1]) // { dg-error "invalid reduction variable" }
> +  for (i = 0; i < 100; i++)
> +    c1.c[1] += 1;
> +
> +#pragma acc parallel loop reduction(+:c1.get_d ()[1]) // { dg-error "invalid reduction variable" }
> +  for (i = 0; i < 100; i++)
> +    c1.get_d ()[1] += 1;
> +
> +#pragma acc parallel loop reduction(+:c1a[1].a) // { dg-error "invalid reduction variable" }
> +  for (i = 0; i < 100; i++)
> +    c1a[1].a += 1;
> +
> +#pragma acc parallel loop reduction(+:c1a[1].get_b ()) // { dg-error "invalid reduction variable" }
> +  for (i = 0; i < 100; i++)
> +    c1a[1].get_b () += 1;
> +
> +#pragma acc parallel loop reduction(+:c1a[1].c[1]) // { dg-error "invalid reduction variable" }
> +  for (i = 0; i < 100; i++)
> +    c1a[1].c[1] += 1;
> +
> +#pragma acc parallel loop reduction(+:c1a[1].get_d ()[1]) // { dg-error "invalid reduction variable" }
> +  for (i = 0; i < 100; i++)
> +    c1a[1].get_d ()[1] += 1;
> +
> +
> +  // Reductions on a template class member.
> +
> +#pragma acc parallel loop reduction(+:c2.a) // { dg-error "invalid reduction variable" }
> +  for (i = 0; i < 100; i++)
> +    c2.a += 1;
> +
> +#pragma acc parallel loop reduction(+:c2.get_b ()) // { dg-error "invalid reduction variable" }
> +  for (i = 0; i < 100; i++)
> +    c2.get_b () += 1;
> +
> +#pragma acc parallel loop reduction(+:c2.c[1]) // { dg-error "invalid reduction variable" }
> +  for (i = 0; i < 100; i++)
> +    c2.c[1] += 1;
> +
> +#pragma acc parallel loop reduction(+:c2.get_d ()[1]) // { dg-error "invalid reduction variable" }
> +  for (i = 0; i < 100; i++)
> +    c2.get_d ()[1] += 1;
> +
> +
> +#pragma acc parallel loop reduction(+:c2a[1].a) // { dg-error "invalid reduction variable" }
> +  for (i = 0; i < 100; i++)
> +    c2a[1].a += 1;
> +
> +#pragma acc parallel loop reduction(+:c2a[1].get_b ()[1]) // { dg-error "invalid reduction variable" }
> +  for (i = 0; i < 100; i++)
> +    c2a[1].get_b () += 1;
> +
> +#pragma acc parallel loop reduction(+:c2a[1].c[1]) // { dg-error "invalid reduction variable" }
> +  for (i = 0; i < 100; i++)
> +    c2a[1].c[1] += 1;
> +
> +#pragma acc parallel loop reduction(+:c2a[1].get_d ()[1]) // { dg-error "invalid reduction variable" }
> +  for (i = 0; i < 100; i++)
> +    c2a[1].get_d ()[1] += 1;
> +
> +
> +  // Reductions on struct element.
> +
> +#pragma acc parallel loop reduction(+:s1.a) // { dg-error "invalid reduction variable" }
> +  for (i = 0; i < 100; i++)
> +    s1.a += 1;
> +
> +#pragma acc parallel loop reduction(+:s1.get_b ()) // { dg-error "invalid reduction variable" }
> +  for (i = 0; i < 100; i++)
> +    s1.get_b () += 1;
> +
> +#pragma acc parallel loop reduction(+:s1.c[1]) // { dg-error "invalid reduction variable" }
> +  for (i = 0; i < 100; i++)
> +    s1.c[1] += 1;
> +
> +#pragma acc parallel loop reduction(+:s1.get_d ()[1]) // { dg-error "invalid reduction variable" }
> +  for (i = 0; i < 100; i++)
> +    s1.get_d ()[1] += 1;
> +
> +#pragma acc parallel loop reduction(+:s1a[1].a) // { dg-error "invalid reduction variable" }
> +  for (i = 0; i < 100; i++)
> +    s1a[1].a += 1;
> +
> +#pragma acc parallel loop reduction(+:s1a[1].get_b ()) // { dg-error "invalid reduction variable" }
> +  for (i = 0; i < 100; i++)
> +    s1a[1].get_b () += 1;
> +
> +#pragma acc parallel loop reduction(+:s1a[1].c[1]) // { dg-error "invalid reduction variable" }
> +  for (i = 0; i < 100; i++)
> +    s1a[1].c[1] += 1;
> +
> +#pragma acc parallel loop reduction(+:s1a[1].get_d ()[1]) // { dg-error "invalid reduction variable" }
> +  for (i = 0; i < 100; i++)
> +    s1a[1].get_d ()[1] += 1;
> +
> +
> +  // Reductions on a template struct element.
> +
> +#pragma acc parallel loop reduction(+:s2.a) // { dg-error "invalid reduction variable" }
> +  for (i = 0; i < 100; i++)
> +    s2.a += 1;
> +
> +#pragma acc parallel loop reduction(+:s2.get_b ()) // { dg-error "invalid reduction variable" }
> +  for (i = 0; i < 100; i++)
> +    s2.get_b () += 1;
> +
> +#pragma acc parallel loop reduction(+:s2.c[1]) // { dg-error "invalid reduction variable" }
> +  for (i = 0; i < 100; i++)
> +    s2.c[1] += 1;
> +
> +#pragma acc parallel loop reduction(+:s2.get_d ()[1]) // { dg-error "invalid reduction variable" }
> +  for (i = 0; i < 100; i++)
> +    s2.get_d ()[1] += 1;
> +
> +#pragma acc parallel loop reduction(+:s2a[1].a) // { dg-error "invalid reduction variable" }
> +  for (i = 0; i < 100; i++)
> +    s2a[1].a += 1;
> +
> +#pragma acc parallel loop reduction(+:s2a[1].get_b ()) // { dg-error "invalid reduction variable" }
> +  for (i = 0; i < 100; i++)
> +    s2a[1].get_b () += 1;
> +
> +#pragma acc parallel loop reduction(+:s2a[1].c[1]) // { dg-error "invalid reduction variable" }
> +  for (i = 0; i < 100; i++)
> +    s2a[1].c[1] += 1;
> +
> +#pragma acc parallel loop reduction(+:s2a[1].get_d ()[1]) // { dg-error "invalid reduction variable" }
> +  for (i = 0; i < 100; i++)
> +    s2a[1].get_d ()[1] += 1;
> +
> +
> +  // Reductions on arrays.
> +
> +#pragma acc parallel loop reduction(+:a[10]) // { dg-error "invalid reduction variable" }
> +  for (i = 0; i < 100; i++)
> +    a[10] += 1;
> +
> +#pragma acc parallel loop reduction(+:b[10]) // { dg-error "invalid reduction variable" }
> +  for (i = 0; i < 100; i++)
> +    b[10] += 1;
> +}
> +
> +template <typename T>
> +void
> +test_loop ()
> +{
> +  int i, a[10];
> +  T b[10];
> +  C1 c1, c1a[10];
> +  C2<T> c2, c2a[10];
> +  S1 s1, s1a[10];
> +  S2<float> s2, s2a[10];
> +
> +  // Reductions on class members.
> +
> +  #pragma acc parallel
> +  {
> +
> +#pragma acc loop reduction(+:c1.a) // { dg-error "invalid reduction variable" }
> +    for (i = 0; i < 100; i++)
> +      c1.a += 1;
> +
> +#pragma acc loop reduction(+:c1.get_b ()) // { dg-error "invalid reduction variable" }
> +    for (i = 0; i < 100; i++)
> +      c1.get_b () += 1;
> +
> +#pragma acc loop reduction(+:c1.c[1]) // { dg-error "invalid reduction variable" }
> +    for (i = 0; i < 100; i++)
> +      c1.c[1] += 1;
> +
> +#pragma acc loop reduction(+:c1.get_d ()[1]) // { dg-error "invalid reduction variable" }
> +    for (i = 0; i < 100; i++)
> +      c1.get_d ()[1] += 1;
> +
> +#pragma acc loop reduction(+:c1a[1].a) // { dg-error "invalid reduction variable" }
> +    for (i = 0; i < 100; i++)
> +      c1a[1].a += 1;
> +
> +#pragma acc loop reduction(+:c1a[1].get_b ()) // { dg-error "invalid reduction variable" }
> +    for (i = 0; i < 100; i++)
> +      c1a[1].get_b () += 1;
> +
> +#pragma acc loop reduction(+:c1a[1].c[1]) // { dg-error "invalid reduction variable" }
> +    for (i = 0; i < 100; i++)
> +      c1a[1].c[1] += 1;
> +
> +#pragma acc loop reduction(+:c1a[1].get_d ()[1]) // { dg-error "invalid reduction variable" }
> +    for (i = 0; i < 100; i++)
> +      c1a[1].get_d ()[1] += 1;
> +
> +
> +    // Reductions on a template class member.
> +
> +#pragma acc loop reduction(+:c2.a) // { dg-error "invalid reduction variable" }
> +    for (i = 0; i < 100; i++)
> +      c2.a += 1;
> +
> +#pragma acc loop reduction(+:c2.get_b ()) // { dg-error "invalid reduction variable" }
> +    for (i = 0; i < 100; i++)
> +      c2.get_b () += 1;
> +
> +#pragma acc loop reduction(+:c2.c[1]) // { dg-error "invalid reduction variable" }
> +    for (i = 0; i < 100; i++)
> +      c2.c[1] += 1;
> +
> +#pragma acc loop reduction(+:c2.get_d ()[1]) // { dg-error "invalid reduction variable" }
> +    for (i = 0; i < 100; i++)
> +      c2.get_d ()[1] += 1;
> +
> +
> +#pragma acc loop reduction(+:c2a[1].a) // { dg-error "invalid reduction variable" }
> +    for (i = 0; i < 100; i++)
> +      c2a[1].a += 1;
> +
> +#pragma acc loop reduction(+:c2a[1].get_b ()[1]) // { dg-error "invalid reduction variable" }
> +    for (i = 0; i < 100; i++)
> +      c2a[1].get_b () += 1;
> +
> +#pragma acc loop reduction(+:c2a[1].c[1]) // { dg-error "invalid reduction variable" }
> +    for (i = 0; i < 100; i++)
> +      c2a[1].c[1] += 1;
> +
> +#pragma acc loop reduction(+:c2a[1].get_d ()[1]) // { dg-error "invalid reduction variable" }
> +    for (i = 0; i < 100; i++)
> +      c2a[1].get_d ()[1] += 1;
> +
> +
> +    // Reductions on struct element.
> +
> +#pragma acc loop reduction(+:s1.a) // { dg-error "invalid reduction variable" }
> +    for (i = 0; i < 100; i++)
> +      s1.a += 1;
> +
> +#pragma acc loop reduction(+:s1.get_b ()) // { dg-error "invalid reduction variable" }
> +    for (i = 0; i < 100; i++)
> +      s1.get_b () += 1;
> +
> +#pragma acc loop reduction(+:s1.c[1]) // { dg-error "invalid reduction variable" }
> +    for (i = 0; i < 100; i++)
> +      s1.c[1] += 1;
> +
> +#pragma acc loop reduction(+:s1.get_d ()[1]) // { dg-error "invalid reduction variable" }
> +    for (i = 0; i < 100; i++)
> +      s1.get_d ()[1] += 1;
> +
> +#pragma acc loop reduction(+:s1a[1].a) // { dg-error "invalid reduction variable" }
> +    for (i = 0; i < 100; i++)
> +      s1a[1].a += 1;
> +
> +#pragma acc loop reduction(+:s1a[1].get_b ()) // { dg-error "invalid reduction variable" }
> +    for (i = 0; i < 100; i++)
> +      s1a[1].get_b () += 1;
> +
> +#pragma acc loop reduction(+:s1a[1].c[1]) // { dg-error "invalid reduction variable" }
> +    for (i = 0; i < 100; i++)
> +      s1a[1].c[1] += 1;
> +
> +#pragma acc loop reduction(+:s1a[1].get_d ()[1]) // { dg-error "invalid reduction variable" }
> +    for (i = 0; i < 100; i++)
> +      s1a[1].get_d ()[1] += 1;
> +
> +
> +    // Reductions on a template struct element.
> +
> +#pragma acc loop reduction(+:s2.a) // { dg-error "invalid reduction variable" }
> +    for (i = 0; i < 100; i++)
> +      s2.a += 1;
> +
> +#pragma acc loop reduction(+:s2.get_b ()) // { dg-error "invalid reduction variable" }
> +    for (i = 0; i < 100; i++)
> +      s2.get_b () += 1;
> +
> +#pragma acc loop reduction(+:s2.c[1]) // { dg-error "invalid reduction variable" }
> +    for (i = 0; i < 100; i++)
> +      s2.c[1] += 1;
> +
> +#pragma acc loop reduction(+:s2.get_d ()[1]) // { dg-error "invalid reduction variable" }
> +    for (i = 0; i < 100; i++)
> +      s2.get_d ()[1] += 1;
> +
> +#pragma acc loop reduction(+:s2a[1].a) // { dg-error "invalid reduction variable" }
> +    for (i = 0; i < 100; i++)
> +      s2a[1].a += 1;
> +
> +#pragma acc loop reduction(+:s2a[1].get_b ()) // { dg-error "invalid reduction variable" }
> +    for (i = 0; i < 100; i++)
> +      s2a[1].get_b () += 1;
> +
> +#pragma acc loop reduction(+:s2a[1].c[1]) // { dg-error "invalid reduction variable" }
> +    for (i = 0; i < 100; i++)
> +      s2a[1].c[1] += 1;
> +
> +#pragma acc loop reduction(+:s2a[1].get_d ()[1]) // { dg-error "invalid reduction variable" }
> +    for (i = 0; i < 100; i++)
> +      s2a[1].get_d ()[1] += 1;
> +
> +
> +    // Reductions on arrays.
> +
> +#pragma acc loop reduction(+:a[10]) // { dg-error "invalid reduction variable" }
> +    for (i = 0; i < 100; i++)
> +      a[10] += 1;
> +
> +#pragma acc loop reduction(+:b[10]) // { dg-error "invalid reduction variable" }
> +    for (i = 0; i < 100; i++)
> +      b[10] += 1;
> +  }
> +}
> +
> +int
> +main ()
> +{
> +  test_parallel<double> ();
> +  test_combined<long> ();
> +  test_loop<short> ();
> +
> +  return 0;
> +}
diff mbox

Patch

2017-04-26  Cesar Philippidis  <cesar@codesourcery.com>

	gcc/c/
	* c-parser.c (c_parser_omp_variable_list): New c_omp_region_type
	argument.  Use it to specialize handling of OMP_CLAUSE_REDUCTION for
	OpenACC.
	(c_parser_omp_clause_reduction): Update call to
	c_parser_omp_variable_list.  Propage OpenACC errors as necessary.
	(c_parser_oacc_all_clauses): Update call to
	p_parser_omp_clause_reduction.
	(c_parser_omp_all_clauses): Likewise.
	(c_parser_cilk_all_clauses): Likewise.

	gcc/cp/
	* parser.c (cp_parser_omp_var_list_no_open): New c_omp_region_type
	argument.  Use it to specialize handling of OMP_CLAUSE_REDUCTION for
	OpenACC.
	(cp_parser_omp_clause_reduction): Update call to
	cp_parser_omp_variable_list.  Propage OpenACC errors as necessary.
	(cp_parser_oacc_all_clauses): Update call to
	cp_parser_omp_clause_reduction..
	(cp_parser_omp_all_clauses): Liekwise.
	(cp_parser_cilk_simd_all_clauses): Likewise.

	gcc/testsuite/
	* c-c++-common/goacc/reduction-7.c: New test.
	* g++.dg/goacc/reductions-1.C: New test.


diff --git a/gcc/c/c-parser.c b/gcc/c/c-parser.c
index 05b9774..b1af31f 100644
--- a/gcc/c/c-parser.c
+++ b/gcc/c/c-parser.c
@@ -10618,7 +10618,8 @@  c_parser_oacc_wait_list (c_parser *parser, location_t clause_loc, tree list)
 static tree
 c_parser_omp_variable_list (c_parser *parser,
 			    location_t clause_loc,
-			    enum omp_clause_code kind, tree list)
+			    enum omp_clause_code kind, tree list,
+			    enum c_omp_region_type ort = C_ORT_OMP)
 {
   if (c_parser_next_token_is_not (parser, CPP_NAME)
       || c_parser_peek_token (parser)->id_kind != C_ID_ID)
@@ -10674,6 +10675,22 @@  c_parser_omp_variable_list (c_parser *parser,
 	      /* FALLTHROUGH  */
 	    case OMP_CLAUSE_DEPEND:
 	    case OMP_CLAUSE_REDUCTION:
+	      if (kind == OMP_CLAUSE_REDUCTION && ort == C_ORT_ACC)
+		{
+		  switch (c_parser_peek_token (parser)->type)
+		    {
+		    case CPP_OPEN_PAREN:
+		    case CPP_OPEN_SQUARE:
+		    case CPP_DOT:
+		    case CPP_DEREF:
+		      error ("invalid reduction variable");
+		      t = error_mark_node;
+		    default:;
+		      break;
+		    }
+		  if (t == error_mark_node)
+		    break;
+		}
 	      while (c_parser_next_token_is (parser, CPP_OPEN_SQUARE))
 		{
 		  tree low_bound = NULL_TREE, length = NULL_TREE;
@@ -12039,9 +12056,12 @@  c_parser_omp_clause_private (c_parser *parser, tree list)
      identifier  */
 
 static tree
-c_parser_omp_clause_reduction (c_parser *parser, tree list)
+c_parser_omp_clause_reduction (c_parser *parser, tree list,
+			       enum c_omp_region_type ort)
 {
   location_t clause_loc = c_parser_peek_token (parser)->location;
+  bool seen_error = false;
+
   if (c_parser_require (parser, CPP_OPEN_PAREN, "expected %<(%>"))
     {
       enum tree_code code = ERROR_MARK;
@@ -12104,7 +12124,13 @@  c_parser_omp_clause_reduction (c_parser *parser, tree list)
 	  tree nl, c;
 
 	  nl = c_parser_omp_variable_list (parser, clause_loc,
-					   OMP_CLAUSE_REDUCTION, list);
+					   OMP_CLAUSE_REDUCTION, list, ort);
+	  if (c_parser_peek_token (parser)->type != CPP_CLOSE_PAREN)
+	    {
+	      seen_error = true;
+	      goto cleanup;
+	    }
+
 	  for (c = nl; c != list; c = OMP_CLAUSE_CHAIN (c))
 	    {
 	      tree d = OMP_CLAUSE_DECL (c), type;
@@ -12133,14 +12159,16 @@  c_parser_omp_clause_reduction (c_parser *parser, tree list)
 		  || !(INTEGRAL_TYPE_P (type)
 		       || TREE_CODE (type) == REAL_TYPE
 		       || TREE_CODE (type) == COMPLEX_TYPE))
-		OMP_CLAUSE_REDUCTION_PLACEHOLDER (c)
+		  OMP_CLAUSE_REDUCTION_PLACEHOLDER (c)
 		  = c_omp_reduction_lookup (reduc_id,
 					    TYPE_MAIN_VARIANT (type));
 	    }
 
 	  list = nl;
 	}
-      c_parser_skip_until_found (parser, CPP_CLOSE_PAREN, "expected %<)%>");
+    cleanup:
+      c_parser_skip_until_found (parser, CPP_CLOSE_PAREN,
+				 seen_error ? NULL : "expected %<)%>");
     }
   return list;
 }
@@ -13272,7 +13300,7 @@  c_parser_oacc_all_clauses (c_parser *parser, omp_clause_mask mask,
 	  c_name = "private";
 	  break;
 	case PRAGMA_OACC_CLAUSE_REDUCTION:
-	  clauses = c_parser_omp_clause_reduction (parser, clauses);
+	  clauses = c_parser_omp_clause_reduction (parser, clauses, C_ORT_ACC);
 	  c_name = "reduction";
 	  break;
 	case PRAGMA_OACC_CLAUSE_SEQ:
@@ -13432,7 +13460,7 @@  c_parser_omp_all_clauses (c_parser *parser, omp_clause_mask mask,
 	  c_name = "private";
 	  break;
 	case PRAGMA_OMP_CLAUSE_REDUCTION:
-	  clauses = c_parser_omp_clause_reduction (parser, clauses);
+	  clauses = c_parser_omp_clause_reduction (parser, clauses, C_ORT_OMP);
 	  c_name = "reduction";
 	  break;
 	case PRAGMA_OMP_CLAUSE_SCHEDULE:
@@ -17764,7 +17792,7 @@  c_parser_cilk_all_clauses (c_parser *parser)
 	  break;
 	case PRAGMA_CILK_CLAUSE_REDUCTION:
 	  /* Use the OpenMP counterpart.  */
-	  clauses = c_parser_omp_clause_reduction (parser, clauses);
+	  clauses = c_parser_omp_clause_reduction (parser, clauses, C_ORT_CILK);
 	  break;
 	default:
 	  c_parser_error (parser, "expected %<#pragma simd%> clause");
diff --git a/gcc/cp/parser.c b/gcc/cp/parser.c
index 4080b8a..b082feb 100644
--- a/gcc/cp/parser.c
+++ b/gcc/cp/parser.c
@@ -30009,7 +30009,8 @@  check_no_duplicate_clause (tree clauses, enum omp_clause_code code,
 
 static tree
 cp_parser_omp_var_list_no_open (cp_parser *parser, enum omp_clause_code kind,
-				tree list, bool *colon)
+				tree list, bool *colon,
+				enum c_omp_region_type ort = C_ORT_OMP)
 {
   cp_token *token;
   bool saved_colon_corrects_to_scope_p = parser->colon_corrects_to_scope_p;
@@ -30082,6 +30083,21 @@  cp_parser_omp_var_list_no_open (cp_parser *parser, enum omp_clause_code kind,
 	      /* FALLTHROUGH.  */
 	    case OMP_CLAUSE_DEPEND:
 	    case OMP_CLAUSE_REDUCTION:
+	      if (kind == OMP_CLAUSE_REDUCTION && ort == C_ORT_ACC)
+		{
+		  switch (cp_lexer_peek_token (parser->lexer)->type)
+		    {
+		    case CPP_OPEN_PAREN:
+		    case CPP_OPEN_SQUARE:
+		    case CPP_DOT:
+		    case CPP_DEREF:
+		      error ("invalid reduction variable");
+		      decl = error_mark_node;
+		      goto skip_comma;
+		    default:;
+		      break;
+		    }
+		}
 	      while (cp_lexer_next_token_is (parser->lexer, CPP_OPEN_SQUARE))
 		{
 		  tree low_bound = NULL_TREE, length = NULL_TREE;
@@ -31215,7 +31231,8 @@  cp_parser_omp_clause_ordered (cp_parser *parser,
      id-expression  */
 
 static tree
-cp_parser_omp_clause_reduction (cp_parser *parser, tree list)
+cp_parser_omp_clause_reduction (cp_parser *parser, tree list,
+				enum c_omp_region_type ort)
 {
   enum tree_code code = ERROR_MARK;
   tree nlist, c, id = NULL_TREE;
@@ -31296,7 +31313,7 @@  cp_parser_omp_clause_reduction (cp_parser *parser, tree list)
     goto resync_fail;
 
   nlist = cp_parser_omp_var_list_no_open (parser, OMP_CLAUSE_REDUCTION, list,
-					  NULL);
+					  NULL, ort);
   for (c = nlist; c != list; c = OMP_CLAUSE_CHAIN (c))
     {
       OMP_CLAUSE_REDUCTION_CODE (c) = code;
@@ -32426,7 +32443,7 @@  cp_parser_oacc_all_clauses (cp_parser *parser, omp_clause_mask mask,
 	  c_name = "private";
 	  break;
 	case PRAGMA_OACC_CLAUSE_REDUCTION:
-	  clauses = cp_parser_omp_clause_reduction (parser, clauses);
+	  clauses = cp_parser_omp_clause_reduction (parser, clauses, C_ORT_ACC);
 	  c_name = "reduction";
 	  break;
 	case PRAGMA_OACC_CLAUSE_SEQ:
@@ -32618,7 +32635,7 @@  cp_parser_omp_all_clauses (cp_parser *parser, omp_clause_mask mask,
 	  c_name = "private";
 	  break;
 	case PRAGMA_OMP_CLAUSE_REDUCTION:
-	  clauses = cp_parser_omp_clause_reduction (parser, clauses);
+	  clauses = cp_parser_omp_clause_reduction (parser, clauses, C_ORT_OMP);
 	  c_name = "reduction";
 	  break;
 	case PRAGMA_OMP_CLAUSE_SCHEDULE:
@@ -38038,7 +38055,7 @@  cp_parser_cilk_simd_all_clauses (cp_parser *parser, cp_token *pragma_token)
 					  clauses);
       else if (c_kind == PRAGMA_CILK_CLAUSE_REDUCTION)
 	/* Use the OMP 4.0 equivalent function.  */
-	clauses = cp_parser_omp_clause_reduction (parser, clauses);
+	clauses = cp_parser_omp_clause_reduction (parser, clauses, C_ORT_CILK);
       else
 	{
 	  clauses = error_mark_node;
diff --git a/gcc/testsuite/c-c++-common/goacc/reduction-7.c b/gcc/testsuite/c-c++-common/goacc/reduction-7.c
new file mode 100644
index 0000000..5d48dda
--- /dev/null
+++ b/gcc/testsuite/c-c++-common/goacc/reduction-7.c
@@ -0,0 +1,113 @@ 
+/* Exercise invalid reductions on array and struct members.  */
+
+/* { dg-compile } */
+
+void
+test_parallel ()
+{
+  struct {
+    int a;
+    float b[5];
+  } s1, s2[10];
+
+  int i;
+  double z[100];
+
+#pragma acc parallel reduction(+:s1.a) /* { dg-error "invalid reduction variable" } */
+  for (i = 0; i < 10; i++)
+    s1.a += 1;
+
+#pragma acc parallel reduction(+:s1.b[3]) /* { dg-error "invalid reduction variable" } */
+  for (i = 0; i < 10; i++)
+    s1.b[3] += 1;
+
+#pragma acc parallel reduction(+:s2[2].a) /* { dg-error "invalid reduction variable" } */
+  for (i = 0; i < 10; i++)
+    s2[2].a += 1;
+
+#pragma acc parallel reduction(+:s2[3].b[4]) /* { dg-error "invalid reduction variable" } */
+  for (i = 0; i < 10; i++)
+    s2[3].b[4] += 1;
+
+#pragma acc parallel reduction(+:z[5]) /* { dg-error "invalid reduction variable" } */
+  for (i = 0; i < 10; i++)
+    z[5] += 1;
+}
+
+void
+test_combined ()
+{
+  struct {
+    int a;
+    float b[5];
+  } s1, s2[10];
+
+  int i;
+  double z[100];
+
+#pragma acc parallel loop reduction(+:s1.a) /* { dg-error "invalid reduction variable" } */
+  for (i = 0; i < 10; i++)
+    s1.a += 1;
+
+#pragma acc parallel loop reduction(+:s1.b[3]) /* { dg-error "invalid reduction variable" } */
+  for (i = 0; i < 10; i++)
+    s1.b[3] += 1;
+
+#pragma acc parallel loop reduction(+:s2[2].a) /* { dg-error "invalid reduction variable" } */
+  for (i = 0; i < 10; i++)
+    s2[2].a += 1;
+
+#pragma acc parallel loop reduction(+:s2[3].b[4]) /* { dg-error "invalid reduction variable" } */
+  for (i = 0; i < 10; i++)
+    s2[3].b[4] += 1;
+
+#pragma acc parallel loop reduction(+:z[5]) /* { dg-error "invalid reduction variable" } */
+  for (i = 0; i < 10; i++)
+    z[5] += 1;
+
+}
+
+void
+test_loops ()
+{
+  struct {
+    int a;
+    float b[5];
+  } s1, s2[10];
+
+  int i;
+  double z[100];
+
+#pragma acc parallel
+  {
+#pragma acc loop reduction(+:s1.a) /* { dg-error "invalid reduction variable" } */
+  for (i = 0; i < 10; i++)
+    s1.a += 1;
+
+#pragma acc loop reduction(+:s1.b[3]) /* { dg-error "invalid reduction variable" } */
+  for (i = 0; i < 10; i++)
+    s1.b[3] += 1;
+
+#pragma acc loop reduction(+:s2[2].a) /* { dg-error "invalid reduction variable" } */
+  for (i = 0; i < 10; i++)
+    s2[2].a += 1;
+
+#pragma acc loop reduction(+:s2[3].b[4]) /* { dg-error "invalid reduction variable" } */
+  for (i = 0; i < 10; i++)
+    s2[3].b[4] += 1;
+
+#pragma acc loop reduction(+:z[5]) /* { dg-error "invalid reduction variable" } */
+  for (i = 0; i < 10; i++)
+    z[5] += 1;
+  }
+}
+
+int
+main ()
+{
+  test_parallel ();
+  test_combined ();
+  test_loops ();
+
+  return 0;
+}
diff --git a/gcc/testsuite/g++.dg/goacc/reductions-1.C b/gcc/testsuite/g++.dg/goacc/reductions-1.C
new file mode 100644
index 0000000..50a6e5e
--- /dev/null
+++ b/gcc/testsuite/g++.dg/goacc/reductions-1.C
@@ -0,0 +1,550 @@ 
+// Test for invalid reduction variables.
+
+// { dg-do compile }
+
+class C1
+{
+  int b, d[10];
+
+public:
+  int a, c[10];
+
+  C1 () { a = 0; b = 0; }
+  int& get_b () { return b; }
+  int* get_d () { return d; }
+};
+
+template <typename T>
+class C2
+{
+  T b, d[10];
+
+public:
+  T a, c[10];
+
+  C2 () { a = 0; b = 0; }
+  T& get_b () { return b; }
+  T* get_d () { return d; }
+};
+
+struct S1
+{
+  int a, b, c[10], d[10];
+
+  S1 () { a = 0; b = 0; }
+  int& get_b () { return b; }
+  int* get_d () { return d; }
+};
+
+template <typename T>
+struct S2
+{
+  T a, b, c[10], d[10];
+
+  S2 () { a = 0; b = 0; }
+  T& get_b () { return b; }
+  T* get_d () { return d; }
+};
+
+template <typename T>
+void
+test_parallel ()
+{
+  int i, a[10];
+  T b[10];
+  C1 c1, c1a[10];
+  C2<T> c2, c2a[10];
+  S1 s1, s1a[10];
+  S2<float> s2, s2a[10];
+
+  // Reductions on class members.
+
+#pragma acc parallel reduction(+:c1.a) // { dg-error "invalid reduction variable" }
+  for (i = 0; i < 100; i++)
+    c1.a += 1;
+
+#pragma acc parallel reduction(+:c1.get_b ()) // { dg-error "invalid reduction variable" }
+  for (i = 0; i < 100; i++)
+    c1.get_b () += 1;
+
+#pragma acc parallel reduction(+:c1.c[1]) // { dg-error "invalid reduction variable" }
+  for (i = 0; i < 100; i++)
+    c1.c[1] += 1;
+
+#pragma acc parallel reduction(+:c1.get_d ()[1]) // { dg-error "invalid reduction variable" }
+  for (i = 0; i < 100; i++)
+    c1.get_d ()[1] += 1;
+
+#pragma acc parallel reduction(+:c1a[1].a) // { dg-error "invalid reduction variable" }
+  for (i = 0; i < 100; i++)
+    c1a[1].a += 1;
+
+#pragma acc parallel reduction(+:c1a[1].get_b ()) // { dg-error "invalid reduction variable" }
+  for (i = 0; i < 100; i++)
+    c1a[1].get_b () += 1;
+
+#pragma acc parallel reduction(+:c1a[1].c[1]) // { dg-error "invalid reduction variable" }
+  for (i = 0; i < 100; i++)
+    c1a[1].c[1] += 1;
+
+#pragma acc parallel reduction(+:c1a[1].get_d ()[1]) // { dg-error "invalid reduction variable" }
+  for (i = 0; i < 100; i++)
+    c1a[1].get_d ()[1] += 1;
+
+
+  // Reductions on a template class member.
+
+#pragma acc parallel reduction(+:c2.a) // { dg-error "invalid reduction variable" }
+  for (i = 0; i < 100; i++)
+    c2.a += 1;
+
+#pragma acc parallel reduction(+:c2.get_b ()) // { dg-error "invalid reduction variable" }
+  for (i = 0; i < 100; i++)
+    c2.get_b () += 1;
+
+#pragma acc parallel reduction(+:c2.c[1]) // { dg-error "invalid reduction variable" }
+  for (i = 0; i < 100; i++)
+    c2.c[1] += 1;
+
+#pragma acc parallel reduction(+:c2.get_d ()[1]) // { dg-error "invalid reduction variable" }
+  for (i = 0; i < 100; i++)
+    c2.get_d ()[1] += 1;
+
+
+#pragma acc parallel reduction(+:c2a[1].a) // { dg-error "invalid reduction variable" }
+  for (i = 0; i < 100; i++)
+    c2a[1].a += 1;
+
+#pragma acc parallel reduction(+:c2a[1].get_b ()[1]) // { dg-error "invalid reduction variable" }
+  for (i = 0; i < 100; i++)
+    c2a[1].get_b () += 1;
+
+#pragma acc parallel reduction(+:c2a[1].c[1]) // { dg-error "invalid reduction variable" }
+  for (i = 0; i < 100; i++)
+    c2a[1].c[1] += 1;
+
+#pragma acc parallel reduction(+:c2a[1].get_d ()[1]) // { dg-error "invalid reduction variable" }
+  for (i = 0; i < 100; i++)
+    c2a[1].get_d ()[1] += 1;
+
+
+  // Reductions on struct element.
+
+#pragma acc parallel reduction(+:s1.a) // { dg-error "invalid reduction variable" }
+  for (i = 0; i < 100; i++)
+    s1.a += 1;
+
+#pragma acc parallel reduction(+:s1.get_b ()) // { dg-error "invalid reduction variable" }
+  for (i = 0; i < 100; i++)
+    s1.get_b () += 1;
+
+#pragma acc parallel reduction(+:s1.c[1]) // { dg-error "invalid reduction variable" }
+  for (i = 0; i < 100; i++)
+    s1.c[1] += 1;
+
+#pragma acc parallel reduction(+:s1.get_d ()[1]) // { dg-error "invalid reduction variable" }
+  for (i = 0; i < 100; i++)
+    s1.get_d ()[1] += 1;
+
+#pragma acc parallel reduction(+:s1a[1].a) // { dg-error "invalid reduction variable" }
+  for (i = 0; i < 100; i++)
+    s1a[1].a += 1;
+
+#pragma acc parallel reduction(+:s1a[1].get_b ()) // { dg-error "invalid reduction variable" }
+  for (i = 0; i < 100; i++)
+    s1a[1].get_b () += 1;
+
+#pragma acc parallel reduction(+:s1a[1].c[1]) // { dg-error "invalid reduction variable" }
+  for (i = 0; i < 100; i++)
+    s1a[1].c[1] += 1;
+
+#pragma acc parallel reduction(+:s1a[1].get_d ()[1]) // { dg-error "invalid reduction variable" }
+  for (i = 0; i < 100; i++)
+    s1a[1].get_d ()[1] += 1;
+
+
+  // Reductions on a template struct element.
+
+#pragma acc parallel reduction(+:s2.a) // { dg-error "invalid reduction variable" }
+  for (i = 0; i < 100; i++)
+    s2.a += 1;
+
+#pragma acc parallel reduction(+:s2.get_b ()) // { dg-error "invalid reduction variable" }
+  for (i = 0; i < 100; i++)
+    s2.get_b () += 1;
+
+#pragma acc parallel reduction(+:s2.c[1]) // { dg-error "invalid reduction variable" }
+  for (i = 0; i < 100; i++)
+    s2.c[1] += 1;
+
+#pragma acc parallel reduction(+:s2.get_d ()[1]) // { dg-error "invalid reduction variable" }
+  for (i = 0; i < 100; i++)
+    s2.get_d ()[1] += 1;
+
+#pragma acc parallel reduction(+:s2a[1].a) // { dg-error "invalid reduction variable" }
+  for (i = 0; i < 100; i++)
+    s2a[1].a += 1;
+
+#pragma acc parallel reduction(+:s2a[1].get_b ()) // { dg-error "invalid reduction variable" }
+  for (i = 0; i < 100; i++)
+    s2a[1].get_b () += 1;
+
+#pragma acc parallel reduction(+:s2a[1].c[1]) // { dg-error "invalid reduction variable" }
+  for (i = 0; i < 100; i++)
+    s2a[1].c[1] += 1;
+
+#pragma acc parallel reduction(+:s2a[1].get_d ()[1]) // { dg-error "invalid reduction variable" }
+  for (i = 0; i < 100; i++)
+    s2a[1].get_d ()[1] += 1;
+
+
+  // Reductions on arrays.
+
+#pragma acc parallel reduction(+:a[10]) // { dg-error "invalid reduction variable" }
+  for (i = 0; i < 100; i++)
+    a[10] += 1;
+
+#pragma acc parallel reduction(+:b[10]) // { dg-error "invalid reduction variable" }
+  for (i = 0; i < 100; i++)
+    b[10] += 1;
+}
+
+template <typename T>
+void
+test_combined ()
+{
+  int i, a[10];
+  T b[10];
+  C1 c1, c1a[10];
+  C2<T> c2, c2a[10];
+  S1 s1, s1a[10];
+  S2<float> s2, s2a[10];
+
+  // Reductions on class members.
+
+#pragma acc parallel loop reduction(+:c1.a) // { dg-error "invalid reduction variable" }
+  for (i = 0; i < 100; i++)
+    c1.a += 1;
+
+#pragma acc parallel loop reduction(+:c1.get_b ()) // { dg-error "invalid reduction variable" }
+  for (i = 0; i < 100; i++)
+    c1.get_b () += 1;
+
+#pragma acc parallel loop reduction(+:c1.c[1]) // { dg-error "invalid reduction variable" }
+  for (i = 0; i < 100; i++)
+    c1.c[1] += 1;
+
+#pragma acc parallel loop reduction(+:c1.get_d ()[1]) // { dg-error "invalid reduction variable" }
+  for (i = 0; i < 100; i++)
+    c1.get_d ()[1] += 1;
+
+#pragma acc parallel loop reduction(+:c1a[1].a) // { dg-error "invalid reduction variable" }
+  for (i = 0; i < 100; i++)
+    c1a[1].a += 1;
+
+#pragma acc parallel loop reduction(+:c1a[1].get_b ()) // { dg-error "invalid reduction variable" }
+  for (i = 0; i < 100; i++)
+    c1a[1].get_b () += 1;
+
+#pragma acc parallel loop reduction(+:c1a[1].c[1]) // { dg-error "invalid reduction variable" }
+  for (i = 0; i < 100; i++)
+    c1a[1].c[1] += 1;
+
+#pragma acc parallel loop reduction(+:c1a[1].get_d ()[1]) // { dg-error "invalid reduction variable" }
+  for (i = 0; i < 100; i++)
+    c1a[1].get_d ()[1] += 1;
+
+
+  // Reductions on a template class member.
+
+#pragma acc parallel loop reduction(+:c2.a) // { dg-error "invalid reduction variable" }
+  for (i = 0; i < 100; i++)
+    c2.a += 1;
+
+#pragma acc parallel loop reduction(+:c2.get_b ()) // { dg-error "invalid reduction variable" }
+  for (i = 0; i < 100; i++)
+    c2.get_b () += 1;
+
+#pragma acc parallel loop reduction(+:c2.c[1]) // { dg-error "invalid reduction variable" }
+  for (i = 0; i < 100; i++)
+    c2.c[1] += 1;
+
+#pragma acc parallel loop reduction(+:c2.get_d ()[1]) // { dg-error "invalid reduction variable" }
+  for (i = 0; i < 100; i++)
+    c2.get_d ()[1] += 1;
+
+
+#pragma acc parallel loop reduction(+:c2a[1].a) // { dg-error "invalid reduction variable" }
+  for (i = 0; i < 100; i++)
+    c2a[1].a += 1;
+
+#pragma acc parallel loop reduction(+:c2a[1].get_b ()[1]) // { dg-error "invalid reduction variable" }
+  for (i = 0; i < 100; i++)
+    c2a[1].get_b () += 1;
+
+#pragma acc parallel loop reduction(+:c2a[1].c[1]) // { dg-error "invalid reduction variable" }
+  for (i = 0; i < 100; i++)
+    c2a[1].c[1] += 1;
+
+#pragma acc parallel loop reduction(+:c2a[1].get_d ()[1]) // { dg-error "invalid reduction variable" }
+  for (i = 0; i < 100; i++)
+    c2a[1].get_d ()[1] += 1;
+
+
+  // Reductions on struct element.
+
+#pragma acc parallel loop reduction(+:s1.a) // { dg-error "invalid reduction variable" }
+  for (i = 0; i < 100; i++)
+    s1.a += 1;
+
+#pragma acc parallel loop reduction(+:s1.get_b ()) // { dg-error "invalid reduction variable" }
+  for (i = 0; i < 100; i++)
+    s1.get_b () += 1;
+
+#pragma acc parallel loop reduction(+:s1.c[1]) // { dg-error "invalid reduction variable" }
+  for (i = 0; i < 100; i++)
+    s1.c[1] += 1;
+
+#pragma acc parallel loop reduction(+:s1.get_d ()[1]) // { dg-error "invalid reduction variable" }
+  for (i = 0; i < 100; i++)
+    s1.get_d ()[1] += 1;
+
+#pragma acc parallel loop reduction(+:s1a[1].a) // { dg-error "invalid reduction variable" }
+  for (i = 0; i < 100; i++)
+    s1a[1].a += 1;
+
+#pragma acc parallel loop reduction(+:s1a[1].get_b ()) // { dg-error "invalid reduction variable" }
+  for (i = 0; i < 100; i++)
+    s1a[1].get_b () += 1;
+
+#pragma acc parallel loop reduction(+:s1a[1].c[1]) // { dg-error "invalid reduction variable" }
+  for (i = 0; i < 100; i++)
+    s1a[1].c[1] += 1;
+
+#pragma acc parallel loop reduction(+:s1a[1].get_d ()[1]) // { dg-error "invalid reduction variable" }
+  for (i = 0; i < 100; i++)
+    s1a[1].get_d ()[1] += 1;
+
+
+  // Reductions on a template struct element.
+
+#pragma acc parallel loop reduction(+:s2.a) // { dg-error "invalid reduction variable" }
+  for (i = 0; i < 100; i++)
+    s2.a += 1;
+
+#pragma acc parallel loop reduction(+:s2.get_b ()) // { dg-error "invalid reduction variable" }
+  for (i = 0; i < 100; i++)
+    s2.get_b () += 1;
+
+#pragma acc parallel loop reduction(+:s2.c[1]) // { dg-error "invalid reduction variable" }
+  for (i = 0; i < 100; i++)
+    s2.c[1] += 1;
+
+#pragma acc parallel loop reduction(+:s2.get_d ()[1]) // { dg-error "invalid reduction variable" }
+  for (i = 0; i < 100; i++)
+    s2.get_d ()[1] += 1;
+
+#pragma acc parallel loop reduction(+:s2a[1].a) // { dg-error "invalid reduction variable" }
+  for (i = 0; i < 100; i++)
+    s2a[1].a += 1;
+
+#pragma acc parallel loop reduction(+:s2a[1].get_b ()) // { dg-error "invalid reduction variable" }
+  for (i = 0; i < 100; i++)
+    s2a[1].get_b () += 1;
+
+#pragma acc parallel loop reduction(+:s2a[1].c[1]) // { dg-error "invalid reduction variable" }
+  for (i = 0; i < 100; i++)
+    s2a[1].c[1] += 1;
+
+#pragma acc parallel loop reduction(+:s2a[1].get_d ()[1]) // { dg-error "invalid reduction variable" }
+  for (i = 0; i < 100; i++)
+    s2a[1].get_d ()[1] += 1;
+
+
+  // Reductions on arrays.
+
+#pragma acc parallel loop reduction(+:a[10]) // { dg-error "invalid reduction variable" }
+  for (i = 0; i < 100; i++)
+    a[10] += 1;
+
+#pragma acc parallel loop reduction(+:b[10]) // { dg-error "invalid reduction variable" }
+  for (i = 0; i < 100; i++)
+    b[10] += 1;
+}
+
+template <typename T>
+void
+test_loop ()
+{
+  int i, a[10];
+  T b[10];
+  C1 c1, c1a[10];
+  C2<T> c2, c2a[10];
+  S1 s1, s1a[10];
+  S2<float> s2, s2a[10];
+
+  // Reductions on class members.
+
+  #pragma acc parallel
+  {
+
+#pragma acc loop reduction(+:c1.a) // { dg-error "invalid reduction variable" }
+    for (i = 0; i < 100; i++)
+      c1.a += 1;
+
+#pragma acc loop reduction(+:c1.get_b ()) // { dg-error "invalid reduction variable" }
+    for (i = 0; i < 100; i++)
+      c1.get_b () += 1;
+
+#pragma acc loop reduction(+:c1.c[1]) // { dg-error "invalid reduction variable" }
+    for (i = 0; i < 100; i++)
+      c1.c[1] += 1;
+
+#pragma acc loop reduction(+:c1.get_d ()[1]) // { dg-error "invalid reduction variable" }
+    for (i = 0; i < 100; i++)
+      c1.get_d ()[1] += 1;
+
+#pragma acc loop reduction(+:c1a[1].a) // { dg-error "invalid reduction variable" }
+    for (i = 0; i < 100; i++)
+      c1a[1].a += 1;
+
+#pragma acc loop reduction(+:c1a[1].get_b ()) // { dg-error "invalid reduction variable" }
+    for (i = 0; i < 100; i++)
+      c1a[1].get_b () += 1;
+
+#pragma acc loop reduction(+:c1a[1].c[1]) // { dg-error "invalid reduction variable" }
+    for (i = 0; i < 100; i++)
+      c1a[1].c[1] += 1;
+
+#pragma acc loop reduction(+:c1a[1].get_d ()[1]) // { dg-error "invalid reduction variable" }
+    for (i = 0; i < 100; i++)
+      c1a[1].get_d ()[1] += 1;
+
+
+    // Reductions on a template class member.
+
+#pragma acc loop reduction(+:c2.a) // { dg-error "invalid reduction variable" }
+    for (i = 0; i < 100; i++)
+      c2.a += 1;
+
+#pragma acc loop reduction(+:c2.get_b ()) // { dg-error "invalid reduction variable" }
+    for (i = 0; i < 100; i++)
+      c2.get_b () += 1;
+
+#pragma acc loop reduction(+:c2.c[1]) // { dg-error "invalid reduction variable" }
+    for (i = 0; i < 100; i++)
+      c2.c[1] += 1;
+
+#pragma acc loop reduction(+:c2.get_d ()[1]) // { dg-error "invalid reduction variable" }
+    for (i = 0; i < 100; i++)
+      c2.get_d ()[1] += 1;
+
+
+#pragma acc loop reduction(+:c2a[1].a) // { dg-error "invalid reduction variable" }
+    for (i = 0; i < 100; i++)
+      c2a[1].a += 1;
+
+#pragma acc loop reduction(+:c2a[1].get_b ()[1]) // { dg-error "invalid reduction variable" }
+    for (i = 0; i < 100; i++)
+      c2a[1].get_b () += 1;
+
+#pragma acc loop reduction(+:c2a[1].c[1]) // { dg-error "invalid reduction variable" }
+    for (i = 0; i < 100; i++)
+      c2a[1].c[1] += 1;
+
+#pragma acc loop reduction(+:c2a[1].get_d ()[1]) // { dg-error "invalid reduction variable" }
+    for (i = 0; i < 100; i++)
+      c2a[1].get_d ()[1] += 1;
+
+
+    // Reductions on struct element.
+
+#pragma acc loop reduction(+:s1.a) // { dg-error "invalid reduction variable" }
+    for (i = 0; i < 100; i++)
+      s1.a += 1;
+
+#pragma acc loop reduction(+:s1.get_b ()) // { dg-error "invalid reduction variable" }
+    for (i = 0; i < 100; i++)
+      s1.get_b () += 1;
+
+#pragma acc loop reduction(+:s1.c[1]) // { dg-error "invalid reduction variable" }
+    for (i = 0; i < 100; i++)
+      s1.c[1] += 1;
+
+#pragma acc loop reduction(+:s1.get_d ()[1]) // { dg-error "invalid reduction variable" }
+    for (i = 0; i < 100; i++)
+      s1.get_d ()[1] += 1;
+
+#pragma acc loop reduction(+:s1a[1].a) // { dg-error "invalid reduction variable" }
+    for (i = 0; i < 100; i++)
+      s1a[1].a += 1;
+
+#pragma acc loop reduction(+:s1a[1].get_b ()) // { dg-error "invalid reduction variable" }
+    for (i = 0; i < 100; i++)
+      s1a[1].get_b () += 1;
+
+#pragma acc loop reduction(+:s1a[1].c[1]) // { dg-error "invalid reduction variable" }
+    for (i = 0; i < 100; i++)
+      s1a[1].c[1] += 1;
+
+#pragma acc loop reduction(+:s1a[1].get_d ()[1]) // { dg-error "invalid reduction variable" }
+    for (i = 0; i < 100; i++)
+      s1a[1].get_d ()[1] += 1;
+
+
+    // Reductions on a template struct element.
+
+#pragma acc loop reduction(+:s2.a) // { dg-error "invalid reduction variable" }
+    for (i = 0; i < 100; i++)
+      s2.a += 1;
+
+#pragma acc loop reduction(+:s2.get_b ()) // { dg-error "invalid reduction variable" }
+    for (i = 0; i < 100; i++)
+      s2.get_b () += 1;
+
+#pragma acc loop reduction(+:s2.c[1]) // { dg-error "invalid reduction variable" }
+    for (i = 0; i < 100; i++)
+      s2.c[1] += 1;
+
+#pragma acc loop reduction(+:s2.get_d ()[1]) // { dg-error "invalid reduction variable" }
+    for (i = 0; i < 100; i++)
+      s2.get_d ()[1] += 1;
+
+#pragma acc loop reduction(+:s2a[1].a) // { dg-error "invalid reduction variable" }
+    for (i = 0; i < 100; i++)
+      s2a[1].a += 1;
+
+#pragma acc loop reduction(+:s2a[1].get_b ()) // { dg-error "invalid reduction variable" }
+    for (i = 0; i < 100; i++)
+      s2a[1].get_b () += 1;
+
+#pragma acc loop reduction(+:s2a[1].c[1]) // { dg-error "invalid reduction variable" }
+    for (i = 0; i < 100; i++)
+      s2a[1].c[1] += 1;
+
+#pragma acc loop reduction(+:s2a[1].get_d ()[1]) // { dg-error "invalid reduction variable" }
+    for (i = 0; i < 100; i++)
+      s2a[1].get_d ()[1] += 1;
+
+
+    // Reductions on arrays.
+
+#pragma acc loop reduction(+:a[10]) // { dg-error "invalid reduction variable" }
+    for (i = 0; i < 100; i++)
+      a[10] += 1;
+
+#pragma acc loop reduction(+:b[10]) // { dg-error "invalid reduction variable" }
+    for (i = 0; i < 100; i++)
+      b[10] += 1;
+  }
+}
+
+int
+main ()
+{
+  test_parallel<double> ();
+  test_combined<long> ();
+  test_loop<short> ();
+
+  return 0;
+}