public inbox for fortran@gcc.gnu.org
 help / color / mirror / Atom feed
From: Tobias Burnus <tobias@codesourcery.com>
To: Jakub Jelinek <jakub@redhat.com>
Cc: gcc-patches <gcc-patches@gcc.gnu.org>, fortran <fortran@gcc.gnu.org>
Subject: Re: [Patch] OpenMP/Fortran: Permit end-clause on directive
Date: Sun, 27 Nov 2022 18:38:41 +0100	[thread overview]
Message-ID: <a2e2e68c-49ed-4fde-ab8d-e5a3cfd4aea9@codesourcery.com> (raw)
In-Reply-To: <YxoIZDg71k7w6gOl@tucnak>

[-- Attachment #1: Type: text/plain, Size: 7691 bytes --]

Updated patch – taking the comments below into account – and the remark
by Harald, second by Jakub. Namely:

I have now split the pre-existing nowait-2.f90 into nowait-2.f90 (with
only valid usage) and nowait-4.f90 (with the dg-error tests). In the
previous version of the patch, nowait-4.f90 was a variant of
nowait-2.f90 that used 'nowait' on the directive line. - And Harald
suggested to split the latter, which I now did – into nowait-{5,6}.f90.

Cf. Harald's email at
https://gcc.gnu.org/pipermail/gcc-patches/2022-August/600539.html and
two emails by Jakub ("Otherwise LGTM"), first at
https://gcc.gnu.org/pipermail/gcc-patches/2022-September/601304.html +
the next email in the thread.

I intent to commit the attached patch tomorrow, unless there are further
comments.

Thanks for the reviews (and I know that the follow up is very belated)!

Tobias


On 08.09.22 17:21, Jakub Jelinek via Fortran wrote:
> On Fri, Aug 26, 2022 at 08:21:26PM +0200, Tobias Burnus wrote:
>> I did run into some issues related to this; those turned out to be
>> unrelated, but I end ended up implementing this feature.
>>
>> Side remark: 'omp parallel workshare' seems to actually permit 'nowait'
>> now, but I guess that's an unintended change due to the
>> syntax-representation change. Hence, it is now tracked as Spec Issue
>> 3338 and I do not permit it.
>>
>> OK for mainline?
>>
>> Tobias
>> -----------------
>> Siemens Electronic Design Automation GmbH; Anschrift: Arnulfstraße 201, 80634 München; Gesellschaft mit beschränkter Haftung; Geschäftsführer: Thomas Heurung, Frank Thürauf; Sitz der Gesellschaft: München; Registergericht München, HRB 106955
>> OpenMP/Fortran: Permit end-clause on directive
>>
>> gcc/fortran/ChangeLog:
>>
>>      * openmp.cc (OMP_DO_CLAUSES, OMP_SCOPE_CLAUSES,
>>      OMP_SECTIONS_CLAUSES, OMP_SINGLE_CLAUSES): Add 'nowait'.
> This doesn't describe what the patch actually does, Add 'nowait'.
> is only true for the first 3, for OMP_SINGLE_CLAUSES IMHO you
> want a separate
>       (OMP_SINGLE_CLAUSES): Add 'nowait' and 'copyprivate'.
> entry.
>
>> @@ -3855,7 +3857,7 @@ cleanup:
>>      | OMP_CLAUSE_ORDER | OMP_CLAUSE_ALLOCATE)
>>   #define OMP_SINGLE_CLAUSES \
>>     (omp_mask (OMP_CLAUSE_PRIVATE) | OMP_CLAUSE_FIRSTPRIVATE         \
>> -   | OMP_CLAUSE_ALLOCATE)
>> +   | OMP_CLAUSE_ALLOCATE | OMP_CLAUSE_NOWAIT | OMP_CLAUSE_COPYPRIVATE)
>>   #define OMP_ORDERED_CLAUSES \
>>     (omp_mask (OMP_CLAUSE_THREADS) | OMP_CLAUSE_SIMD)
>>   #define OMP_DECLARE_TARGET_CLAUSES \
>> @@ -5909,13 +5915,11 @@ gfc_match_omp_teams_distribute_simd (void)
>>   match
>>   gfc_match_omp_workshare (void)
>>   {
>> -  if (gfc_match_omp_eos () != MATCH_YES)
>> -    {
>> -      gfc_error ("Unexpected junk after $OMP WORKSHARE statement at %C");
>> -      return MATCH_ERROR;
>> -    }
>> +  gfc_omp_clauses *c;
>> +  if (gfc_match_omp_clauses (&c, omp_mask (OMP_CLAUSE_NOWAIT)) != MATCH_YES)
>> +    return MATCH_ERROR;
>>     new_st.op = EXEC_OMP_WORKSHARE;
>> -  new_st.ext.omp_clauses = gfc_get_omp_clauses ();
>> +  new_st.ext.omp_clauses = c;
>>     return MATCH_YES;
>>   }
> I think it would be better to introduce OMP_WORKSHARE_CLAUSES and use
> it in both gfc_match_omp_workshare and just use
>    return match_omp (EXEC_OMP_WORKSHARE, OMP_WORKSHARE_CLAUSES);
> ?
>
>> @@ -6954,6 +6952,9 @@ resolve_omp_clauses (gfc_code *code, gfc_omp_clauses *omp_clauses,
>>            }
>>          break;
>>        case OMP_LIST_COPYPRIVATE:
>> +        if (omp_clauses->nowait)
>> +          gfc_error ("NOWAIT clause must not be be used with COPYPRIVATE "
> s/be be/be/
>> +                     "clause at %L", &n->where);
>>          for (; n != NULL; n = n->next)
>>            {
>>              if (n->sym->as && n->sym->as->type == AS_ASSUMED_SIZE)
>> @@ -5284,7 +5285,13 @@ parse_omp_do (gfc_statement omp_st)
>>     if (st == omp_end_st)
>>       {
>>         if (new_st.op == EXEC_OMP_END_NOWAIT)
>> -    cp->ext.omp_clauses->nowait |= new_st.ext.omp_bool;
>> +    {
>> +      if (cp->ext.omp_clauses->nowait && new_st.ext.omp_bool)
>> +        gfc_error_now ("Duplicated NOWAIT clause on %s and %s at %C",
>> +                       gfc_ascii_statement (omp_st),
>> +                       gfc_ascii_statement (omp_end_st));
>> +      cp->ext.omp_clauses->nowait |= new_st.ext.omp_bool;
>> +    }
>>         else
>>      gcc_assert (new_st.op == EXEC_NOP);
>>         gfc_clear_new_st ();
> Not sure if the standard is clear enough that unique clauses can't be
> repeated on both directive and corresponding end directive.  But let's
> assume that is the case.
>
>> --- /dev/null
>> +++ b/gcc/testsuite/gfortran.dg/gomp/copyprivate-2.f90
>> @@ -0,0 +1,69 @@
>> +  FUNCTION t()
>> +    INTEGER :: a, b, t
>> +    a = 0
>> +    t = b
>> +    b = 0
>> +    !$OMP PARALLEL REDUCTION(+:b)
>> +      !$OMP SINGLE COPYPRIVATE (b) NOWAIT  ! { dg-error "NOWAIT clause must not be be used with COPYPRIVATE clause" }
> Here too (several times).
>
>> +        !$OMP ATOMIC WRITE
>> +        b = 6
>> +      !$OMP END SINGLE
>> +    !$OMP END PARALLEL
>> +    t = t + b
>> +  END FUNCTION
>> +
>> +  FUNCTION t2()
>> +    INTEGER :: a, b, t2
>> +    a = 0
>> +    t2 = b
>> +    b = 0
>> +    !$OMP PARALLEL REDUCTION(+:b)
>> +      !$OMP SINGLE NOWAIT COPYPRIVATE (b)  ! { dg-error "NOWAIT clause must not be be used with COPYPRIVATE clause" }
>> +        !$OMP ATOMIC WRITE
>> +        b = 6
>> +      !$OMP END SINGLE
>> +    !$OMP END PARALLEL
>> +    t2 = t2 + b
>> +  END FUNCTION
>> +
>> +  FUNCTION t3()
>> +    INTEGER :: a, b, t3
>> +    a = 0
>> +    t3 = b
>> +    b = 0
>> +    !$OMP PARALLEL REDUCTION(+:b)
>> +      !$OMP SINGLE COPYPRIVATE (b)  ! { dg-error "NOWAIT clause must not be be used with COPYPRIVATE clause" }
>> +        !$OMP ATOMIC WRITE
>> +        b = 6
>> +      !$OMP END SINGLE NOWAIT
>> +    !$OMP END PARALLEL
>> +    t3 = t3 + b
>> +  END FUNCTION
>> +
>> +  FUNCTION t4()
>> +    INTEGER :: a, b, t4
>> +    a = 0
>> +    t4 = b
>> +    b = 0
>> +    !$OMP PARALLEL REDUCTION(+:b)
>> +      !$OMP SINGLE
>> +        !$OMP ATOMIC WRITE
>> +        b = 6
>> +      !$OMP END SINGLE NOWAIT COPYPRIVATE (b)  ! { dg-error "NOWAIT clause must not be be used with COPYPRIVATE clause" }
>> +    !$OMP END PARALLEL
>> +    t4 = t4 + b
>> +  END FUNCTION
>> +
>> +  FUNCTION t5()
>> +    INTEGER :: a, b, t5
>> +    a = 0
>> +    t5 = b
>> +    b = 0
>> +    !$OMP PARALLEL REDUCTION(+:b)
>> +      !$OMP SINGLE
>> +        !$OMP ATOMIC WRITE
>> +        b = 6
>> +      !$OMP END SINGLE COPYPRIVATE (b) NOWAIT  ! { dg-error "NOWAIT clause must not be be used with COPYPRIVATE clause" }
>> +    !$OMP END PARALLEL
>> +    t5 = t5 + b
>> +  END FUNCTION
> I think this lacks a test for !$OMP SINGLE NOWAIT and !$OMP END SINGLE COPYPRIVATE (b).
>
> Also, shouldn't we have test coverage for !$OMP SINGLE COPYPRIVATE (b) with !$OMP END SINGLE COPYPRIVATE (b)
> (that we detect multiple copyprivate clauses for the same variable even that
> way)?
>
> Otherwise LGTM.
>
> Note, for combined constructs with target seems we were already implementing
> this, because the 5.1 wording allows nowait only on !$omp target and not on
> !$omp end target, right?
>
>       Jakub
>
-----------------
Siemens Electronic Design Automation GmbH; Anschrift: Arnulfstraße 201, 80634 München; Gesellschaft mit beschränkter Haftung; Geschäftsführer: Thomas Heurung, Frank Thürauf; Sitz der Gesellschaft: München; Registergericht München, HRB 106955

[-- Attachment #2: end-decl-v3.diff --]
[-- Type: text/x-patch, Size: 38550 bytes --]

OpenMP/Fortran: Permit end-clause on directive

gcc/fortran/ChangeLog:

	* openmp.cc (OMP_DO_CLAUSES, OMP_SCOPE_CLAUSES,
	OMP_SECTIONS_CLAUSES): Add 'nowait'.
	(OMP_SINGLE_CLAUSES): Add 'nowait' and 'copyprivate'.
	(gfc_match_omp_distribute_parallel_do,
	gfc_match_omp_distribute_parallel_do_simd,
	gfc_match_omp_parallel_do,
	gfc_match_omp_parallel_do_simd,
	gfc_match_omp_parallel_sections,
	gfc_match_omp_teams_distribute_parallel_do,
	gfc_match_omp_teams_distribute_parallel_do_simd): Disallow 'nowait'.
	gfc_match_omp_workshare): Match 'nowait' clause.
	(gfc_match_omp_end_single): Use clause matcher for 'nowait'.
	(resolve_omp_clauses): Reject 'nowait' + 'copyprivate'.
	* parse.cc (decode_omp_directive): Break too long line.
	(parse_omp_do, parse_omp_structured_block): Diagnose duplicated
	'nowait' clause.

libgomp/ChangeLog:

	* libgomp.texi (OpenMP 5.2): Mark end-directive as Y.

gcc/testsuite/ChangeLog:

	* gfortran.dg/gomp/copyprivate-1.f90: New test.
	* gfortran.dg/gomp/copyprivate-2.f90: New test.
	* gfortran.dg/gomp/nowait-2.f90: Move dg-error tests ...
	* gfortran.dg/gomp/nowait-4.f90: ... to this new file.
	* gfortran.dg/gomp/nowait-5.f90: New test.
	* gfortran.dg/gomp/nowait-6.f90: New test.
	* gfortran.dg/gomp/nowait-7.f90: New test.
	* gfortran.dg/gomp/nowait-8.f90: New test.

 gcc/fortran/openmp.cc                            |  57 ++++----
 gcc/fortran/parse.cc                             |  33 ++++-
 gcc/testsuite/gfortran.dg/gomp/copyprivate-1.f90 |  21 +++
 gcc/testsuite/gfortran.dg/gomp/copyprivate-2.f90 |  97 ++++++++++++++
 gcc/testsuite/gfortran.dg/gomp/nowait-2.f90      | 159 -----------------------
 gcc/testsuite/gfortran.dg/gomp/nowait-4.f90      | 158 ++++++++++++++++++++++
 gcc/testsuite/gfortran.dg/gomp/nowait-5.f90      | 156 ++++++++++++++++++++++
 gcc/testsuite/gfortran.dg/gomp/nowait-6.f90      | 158 ++++++++++++++++++++++
 gcc/testsuite/gfortran.dg/gomp/nowait-7.f90      | 118 +++++++++++++++++
 gcc/testsuite/gfortran.dg/gomp/nowait-8.f90      |  92 +++++++++++++
 libgomp/libgomp.texi                             |   2 +-
 11 files changed, 857 insertions(+), 194 deletions(-)

diff --git a/gcc/fortran/openmp.cc b/gcc/fortran/openmp.cc
index e0e3b52ad57..862c649b0b6 100644
--- a/gcc/fortran/openmp.cc
+++ b/gcc/fortran/openmp.cc
@@ -4173,17 +4173,19 @@ cleanup:
   (omp_mask (OMP_CLAUSE_PRIVATE) | OMP_CLAUSE_FIRSTPRIVATE		\
    | OMP_CLAUSE_LASTPRIVATE | OMP_CLAUSE_REDUCTION			\
    | OMP_CLAUSE_SCHEDULE | OMP_CLAUSE_ORDERED | OMP_CLAUSE_COLLAPSE	\
-   | OMP_CLAUSE_LINEAR | OMP_CLAUSE_ORDER | OMP_CLAUSE_ALLOCATE)
+   | OMP_CLAUSE_LINEAR | OMP_CLAUSE_ORDER | OMP_CLAUSE_ALLOCATE		\
+   | OMP_CLAUSE_NOWAIT)
 #define OMP_LOOP_CLAUSES \
   (omp_mask (OMP_CLAUSE_BIND) | OMP_CLAUSE_COLLAPSE | OMP_CLAUSE_ORDER	\
    | OMP_CLAUSE_PRIVATE | OMP_CLAUSE_LASTPRIVATE | OMP_CLAUSE_REDUCTION)
 
 #define OMP_SCOPE_CLAUSES \
   (omp_mask (OMP_CLAUSE_PRIVATE) |OMP_CLAUSE_FIRSTPRIVATE		\
-   | OMP_CLAUSE_REDUCTION | OMP_CLAUSE_ALLOCATE)
+   | OMP_CLAUSE_REDUCTION | OMP_CLAUSE_ALLOCATE | OMP_CLAUSE_NOWAIT)
 #define OMP_SECTIONS_CLAUSES \
   (omp_mask (OMP_CLAUSE_PRIVATE) | OMP_CLAUSE_FIRSTPRIVATE		\
-   | OMP_CLAUSE_LASTPRIVATE | OMP_CLAUSE_REDUCTION | OMP_CLAUSE_ALLOCATE)
+   | OMP_CLAUSE_LASTPRIVATE | OMP_CLAUSE_REDUCTION			\
+   | OMP_CLAUSE_ALLOCATE | OMP_CLAUSE_NOWAIT)
 #define OMP_SIMD_CLAUSES \
   (omp_mask (OMP_CLAUSE_PRIVATE) | OMP_CLAUSE_LASTPRIVATE		\
    | OMP_CLAUSE_REDUCTION | OMP_CLAUSE_COLLAPSE | OMP_CLAUSE_SAFELEN	\
@@ -4233,7 +4235,7 @@ cleanup:
    | OMP_CLAUSE_ORDER | OMP_CLAUSE_ALLOCATE)
 #define OMP_SINGLE_CLAUSES \
   (omp_mask (OMP_CLAUSE_PRIVATE) | OMP_CLAUSE_FIRSTPRIVATE		\
-   | OMP_CLAUSE_ALLOCATE)
+   | OMP_CLAUSE_ALLOCATE | OMP_CLAUSE_NOWAIT | OMP_CLAUSE_COPYPRIVATE)
 #define OMP_ORDERED_CLAUSES \
   (omp_mask (OMP_CLAUSE_THREADS) | OMP_CLAUSE_SIMD)
 #define OMP_DECLARE_TARGET_CLAUSES \
@@ -4247,7 +4249,8 @@ cleanup:
   (omp_mask (OMP_CLAUSE_FILTER))
 #define OMP_ERROR_CLAUSES \
   (omp_mask (OMP_CLAUSE_AT) | OMP_CLAUSE_MESSAGE | OMP_CLAUSE_SEVERITY)
-
+#define OMP_WORKSHARE_CLAUSES \
+  omp_mask (OMP_CLAUSE_NOWAIT)
 
 
 static match
@@ -4458,8 +4461,8 @@ gfc_match_omp_distribute_parallel_do (void)
   return match_omp (EXEC_OMP_DISTRIBUTE_PARALLEL_DO,
 		    (OMP_DISTRIBUTE_CLAUSES | OMP_PARALLEL_CLAUSES
 		     | OMP_DO_CLAUSES)
-		    & ~(omp_mask (OMP_CLAUSE_ORDERED))
-		    & ~(omp_mask (OMP_CLAUSE_LINEAR)));
+		    & ~(omp_mask (OMP_CLAUSE_ORDERED)
+			| OMP_CLAUSE_LINEAR | OMP_CLAUSE_NOWAIT));
 }
 
 
@@ -4469,7 +4472,7 @@ gfc_match_omp_distribute_parallel_do_simd (void)
   return match_omp (EXEC_OMP_DISTRIBUTE_PARALLEL_DO_SIMD,
 		    (OMP_DISTRIBUTE_CLAUSES | OMP_PARALLEL_CLAUSES
 		     | OMP_DO_CLAUSES | OMP_SIMD_CLAUSES)
-		    & ~(omp_mask (OMP_CLAUSE_ORDERED)));
+		    & ~(omp_mask (OMP_CLAUSE_ORDERED) | OMP_CLAUSE_NOWAIT));
 }
 
 
@@ -5770,7 +5773,8 @@ match
 gfc_match_omp_parallel_do (void)
 {
   return match_omp (EXEC_OMP_PARALLEL_DO,
-		    OMP_PARALLEL_CLAUSES | OMP_DO_CLAUSES);
+		    (OMP_PARALLEL_CLAUSES | OMP_DO_CLAUSES)
+		    & ~(omp_mask (OMP_CLAUSE_NOWAIT)));
 }
 
 
@@ -5778,7 +5782,8 @@ match
 gfc_match_omp_parallel_do_simd (void)
 {
   return match_omp (EXEC_OMP_PARALLEL_DO_SIMD,
-		    OMP_PARALLEL_CLAUSES | OMP_DO_CLAUSES | OMP_SIMD_CLAUSES);
+		    (OMP_PARALLEL_CLAUSES | OMP_DO_CLAUSES | OMP_SIMD_CLAUSES)
+		    & ~(omp_mask (OMP_CLAUSE_NOWAIT)));
 }
 
 
@@ -5834,7 +5839,8 @@ match
 gfc_match_omp_parallel_sections (void)
 {
   return match_omp (EXEC_OMP_PARALLEL_SECTIONS,
-		    OMP_PARALLEL_CLAUSES | OMP_SECTIONS_CLAUSES);
+		    (OMP_PARALLEL_CLAUSES | OMP_SECTIONS_CLAUSES)
+		    & ~(omp_mask (OMP_CLAUSE_NOWAIT)));
 }
 
 
@@ -6320,8 +6326,8 @@ gfc_match_omp_teams_distribute_parallel_do (void)
   return match_omp (EXEC_OMP_TEAMS_DISTRIBUTE_PARALLEL_DO,
 		    (OMP_TEAMS_CLAUSES | OMP_DISTRIBUTE_CLAUSES
 		     | OMP_PARALLEL_CLAUSES | OMP_DO_CLAUSES)
-		    & ~(omp_mask (OMP_CLAUSE_ORDERED))
-		    & ~(omp_mask (OMP_CLAUSE_LINEAR)));
+		    & ~(omp_mask (OMP_CLAUSE_ORDERED)
+			| OMP_CLAUSE_LINEAR | OMP_CLAUSE_NOWAIT));
 }
 
 
@@ -6331,7 +6337,8 @@ gfc_match_omp_teams_distribute_parallel_do_simd (void)
   return match_omp (EXEC_OMP_TEAMS_DISTRIBUTE_PARALLEL_DO_SIMD,
 		    (OMP_TEAMS_CLAUSES | OMP_DISTRIBUTE_CLAUSES
 		     | OMP_PARALLEL_CLAUSES | OMP_DO_CLAUSES
-		     | OMP_SIMD_CLAUSES) & ~(omp_mask (OMP_CLAUSE_ORDERED)));
+		     | OMP_SIMD_CLAUSES)
+		    & ~(omp_mask (OMP_CLAUSE_ORDERED) | OMP_CLAUSE_NOWAIT));
 }
 
 
@@ -6347,14 +6354,7 @@ gfc_match_omp_teams_distribute_simd (void)
 match
 gfc_match_omp_workshare (void)
 {
-  if (gfc_match_omp_eos () != MATCH_YES)
-    {
-      gfc_error ("Unexpected junk after $OMP WORKSHARE statement at %C");
-      return MATCH_ERROR;
-    }
-  new_st.op = EXEC_OMP_WORKSHARE;
-  new_st.ext.omp_clauses = gfc_get_omp_clauses ();
-  return MATCH_YES;
+  return match_omp (EXEC_OMP_WORKSHARE, OMP_WORKSHARE_CLAUSES);
 }
 
 
@@ -6658,14 +6658,8 @@ match
 gfc_match_omp_end_single (void)
 {
   gfc_omp_clauses *c;
-  if (gfc_match ("% nowait") == MATCH_YES)
-    {
-      new_st.op = EXEC_OMP_END_NOWAIT;
-      new_st.ext.omp_bool = true;
-      return MATCH_YES;
-    }
-  if (gfc_match_omp_clauses (&c, omp_mask (OMP_CLAUSE_COPYPRIVATE))
-      != MATCH_YES)
+  if (gfc_match_omp_clauses (&c, omp_mask (OMP_CLAUSE_COPYPRIVATE)
+					   | OMP_CLAUSE_NOWAIT) != MATCH_YES)
     return MATCH_ERROR;
   new_st.op = EXEC_OMP_END_SINGLE;
   new_st.ext.omp_clauses = c;
@@ -7406,6 +7400,9 @@ resolve_omp_clauses (gfc_code *code, gfc_omp_clauses *omp_clauses,
 	      }
 	    break;
 	  case OMP_LIST_COPYPRIVATE:
+	    if (omp_clauses->nowait)
+	      gfc_error ("NOWAIT clause must not be used with COPYPRIVATE "
+			 "clause at %L", &n->where);
 	    for (; n != NULL; n = n->next)
 	      {
 		if (n->sym->as && n->sym->as->type == AS_ASSUMED_SIZE)
diff --git a/gcc/fortran/parse.cc b/gcc/fortran/parse.cc
index f04fd13cc69..51ff0fc6ace 100644
--- a/gcc/fortran/parse.cc
+++ b/gcc/fortran/parse.cc
@@ -942,7 +942,8 @@ decode_omp_directive (void)
       matchs ("end ordered", gfc_match_omp_eos_error, ST_OMP_END_ORDERED);
       matchs ("end parallel do simd", gfc_match_omp_eos_error,
 	      ST_OMP_END_PARALLEL_DO_SIMD);
-      matcho ("end parallel do", gfc_match_omp_eos_error, ST_OMP_END_PARALLEL_DO);
+      matcho ("end parallel do", gfc_match_omp_eos_error,
+	      ST_OMP_END_PARALLEL_DO);
       matcho ("end parallel loop", gfc_match_omp_eos_error,
 	      ST_OMP_END_PARALLEL_LOOP);
       matcho ("end parallel masked taskloop simd", gfc_match_omp_eos_error,
@@ -5305,7 +5306,13 @@ parse_omp_do (gfc_statement omp_st)
   if (st == omp_end_st)
     {
       if (new_st.op == EXEC_OMP_END_NOWAIT)
-	cp->ext.omp_clauses->nowait |= new_st.ext.omp_bool;
+	{
+	  if (cp->ext.omp_clauses->nowait && new_st.ext.omp_bool)
+	    gfc_error_now ("Duplicated NOWAIT clause on %s and %s at %C",
+			   gfc_ascii_statement (omp_st),
+			   gfc_ascii_statement (omp_end_st));
+	  cp->ext.omp_clauses->nowait |= new_st.ext.omp_bool;
+	}
       else
 	gcc_assert (new_st.op == EXEC_NOP);
       gfc_clear_new_st ();
@@ -5745,6 +5752,10 @@ parse_omp_structured_block (gfc_statement omp_st, bool workshare_stmts_only)
   switch (new_st.op)
     {
     case EXEC_OMP_END_NOWAIT:
+      if (cp->ext.omp_clauses->nowait && new_st.ext.omp_bool)
+	gfc_error_now ("Duplicated NOWAIT clause on %s and %s at %C",
+		       gfc_ascii_statement (omp_st),
+		       gfc_ascii_statement (omp_end_st));
       cp->ext.omp_clauses->nowait |= new_st.ext.omp_bool;
       break;
     case EXEC_OMP_END_CRITICAL:
@@ -5759,8 +5770,22 @@ parse_omp_structured_block (gfc_statement omp_st, bool workshare_stmts_only)
       new_st.ext.omp_name = NULL;
       break;
     case EXEC_OMP_END_SINGLE:
-      cp->ext.omp_clauses->lists[OMP_LIST_COPYPRIVATE]
-	= new_st.ext.omp_clauses->lists[OMP_LIST_COPYPRIVATE];
+      if (cp->ext.omp_clauses->nowait && new_st.ext.omp_clauses->nowait)
+	gfc_error_now ("Duplicated NOWAIT clause on %s and %s at %C",
+		       gfc_ascii_statement (omp_st),
+		       gfc_ascii_statement (omp_end_st));
+      cp->ext.omp_clauses->nowait |= new_st.ext.omp_clauses->nowait;
+      if (cp->ext.omp_clauses->lists[OMP_LIST_COPYPRIVATE])
+	{
+	  gfc_omp_namelist *nl;
+	  for (nl = cp->ext.omp_clauses->lists[OMP_LIST_COPYPRIVATE];
+	      nl->next; nl = nl->next);
+	    ;
+	  nl->next = new_st.ext.omp_clauses->lists[OMP_LIST_COPYPRIVATE];
+	}
+      else
+	cp->ext.omp_clauses->lists[OMP_LIST_COPYPRIVATE]
+	  = new_st.ext.omp_clauses->lists[OMP_LIST_COPYPRIVATE];
       new_st.ext.omp_clauses->lists[OMP_LIST_COPYPRIVATE] = NULL;
       gfc_free_omp_clauses (new_st.ext.omp_clauses);
       break;
diff --git a/gcc/testsuite/gfortran.dg/gomp/copyprivate-1.f90 b/gcc/testsuite/gfortran.dg/gomp/copyprivate-1.f90
new file mode 100644
index 00000000000..eb2c865818e
--- /dev/null
+++ b/gcc/testsuite/gfortran.dg/gomp/copyprivate-1.f90
@@ -0,0 +1,21 @@
+! based on pr59467.f90 but COPYPRIVATE on the directive
+! { dg-additional-options "-fdump-tree-original" }
+
+  FUNCTION t()
+    INTEGER :: a, b, t
+    a = 0
+    b = 0
+    t = b
+    b = 0
+    !$OMP PARALLEL REDUCTION(+:b)
+      !$OMP SINGLE COPYPRIVATE (b)
+        !$OMP ATOMIC WRITE
+        b = 6
+      !$OMP END SINGLE
+    !$OMP END PARALLEL
+    t = t + b
+  END FUNCTION
+
+! { dg-final { scan-tree-dump-times "#pragma omp parallel reduction\\(\\+:b\\)" 1 "original" } }
+! { dg-final { scan-tree-dump-times "#pragma omp single copyprivate\\(b\\)" 1 "original" } }
+! { dg-final { scan-tree-dump-times "#pragma omp atomic relaxed" 1 "original" } }
diff --git a/gcc/testsuite/gfortran.dg/gomp/copyprivate-2.f90 b/gcc/testsuite/gfortran.dg/gomp/copyprivate-2.f90
new file mode 100644
index 00000000000..130f3716e1e
--- /dev/null
+++ b/gcc/testsuite/gfortran.dg/gomp/copyprivate-2.f90
@@ -0,0 +1,97 @@
+  FUNCTION t()
+    INTEGER :: a, b, t
+    a = 0
+    t = b
+    b = 0
+    !$OMP PARALLEL REDUCTION(+:b)
+      !$OMP SINGLE COPYPRIVATE (b) NOWAIT  ! { dg-error "NOWAIT clause must not be used with COPYPRIVATE clause" }
+        !$OMP ATOMIC WRITE
+        b = 6
+      !$OMP END SINGLE
+    !$OMP END PARALLEL
+    t = t + b
+  END FUNCTION
+
+  FUNCTION t2()
+    INTEGER :: a, b, t2
+    a = 0
+    t2 = b
+    b = 0
+    !$OMP PARALLEL REDUCTION(+:b)
+      !$OMP SINGLE NOWAIT COPYPRIVATE (b)  ! { dg-error "NOWAIT clause must not be used with COPYPRIVATE clause" }
+        !$OMP ATOMIC WRITE
+        b = 6
+      !$OMP END SINGLE
+    !$OMP END PARALLEL
+    t2 = t2 + b
+  END FUNCTION
+
+  FUNCTION t3()
+    INTEGER :: a, b, t3
+    a = 0
+    t3 = b
+    b = 0
+    !$OMP PARALLEL REDUCTION(+:b)
+      !$OMP SINGLE COPYPRIVATE (b)  ! { dg-error "NOWAIT clause must not be used with COPYPRIVATE clause" }
+        !$OMP ATOMIC WRITE
+        b = 6
+      !$OMP END SINGLE NOWAIT
+    !$OMP END PARALLEL
+    t3 = t3 + b
+  END FUNCTION
+
+  FUNCTION t4()
+    INTEGER :: a, b, t4
+    a = 0
+    t4 = b
+    b = 0
+    !$OMP PARALLEL REDUCTION(+:b)
+      !$OMP SINGLE
+        !$OMP ATOMIC WRITE
+        b = 6
+      !$OMP END SINGLE NOWAIT COPYPRIVATE (b)  ! { dg-error "NOWAIT clause must not be used with COPYPRIVATE clause" }
+    !$OMP END PARALLEL
+    t4 = t4 + b
+  END FUNCTION
+
+  FUNCTION t5()
+    INTEGER :: a, b, t5
+    a = 0
+    t5 = b
+    b = 0
+    !$OMP PARALLEL REDUCTION(+:b)
+      !$OMP SINGLE
+        !$OMP ATOMIC WRITE
+        b = 6
+      !$OMP END SINGLE COPYPRIVATE (b) NOWAIT  ! { dg-error "NOWAIT clause must not be used with COPYPRIVATE clause" }
+    !$OMP END PARALLEL
+    t5 = t5 + b
+  END FUNCTION
+
+  FUNCTION t6()
+    INTEGER :: a, b, t6
+    a = 0
+    t6 = b
+    b = 0
+    !$OMP PARALLEL REDUCTION(+:b)
+      !$OMP SINGLE NOWAIT
+        !$OMP ATOMIC WRITE
+        b = 6
+      !$OMP END SINGLE COPYPRIVATE (b) ! { dg-error "NOWAIT clause must not be used with COPYPRIVATE clause" }
+    !$OMP END PARALLEL
+    t6 = t6 + b
+  END FUNCTION
+
+  FUNCTION t7()
+    INTEGER :: a, b, t7
+    a = 0
+    t7 = b
+    b = 0
+    !$OMP PARALLEL REDUCTION(+:b)
+      !$OMP SINGLE COPYPRIVATE (b)
+        !$OMP ATOMIC WRITE
+        b = 7
+      !$OMP END SINGLE COPYPRIVATE (b) ! { dg-error "Symbol 'b' present on multiple clauses" }
+    !$OMP END PARALLEL
+    t7 = t7 + b
+  END FUNCTION
diff --git a/gcc/testsuite/gfortran.dg/gomp/nowait-2.f90 b/gcc/testsuite/gfortran.dg/gomp/nowait-2.f90
index d18459bd315..c6881171e5d 100644
--- a/gcc/testsuite/gfortran.dg/gomp/nowait-2.f90
+++ b/gcc/testsuite/gfortran.dg/gomp/nowait-2.f90
@@ -154,162 +154,3 @@ end do
 !$omp end target data
 
 end
-
-! invalid nowait
-
-subroutine foo
-implicit none
-integer :: i, a(5)
-!$omp atomic write
-i = 5
-!$omp end atomic nowait  ! { dg-error "Unexpected junk" }
-
-!$omp critical
-!$omp end critical nowait  ! { dg-error "Unexpected junk" }
-
-!$omp distribute
-do i = 1, 5
-end do
-!$omp end distribute nowait  ! { dg-error "Unexpected junk" }
-
-!$omp distribute parallel do
-do i = 1, 5
-end do
-!$omp end distribute parallel do nowait  ! { dg-error "Unexpected junk" }
-
-!$omp distribute parallel do simd
-do i = 1, 5
-end do
-!$omp end distribute parallel do simd nowait  ! { dg-error "Unexpected junk" }
-
-!$omp parallel sections
-  !$omp section
-  block; end block
-!$omp end parallel sections nowait  ! { dg-error "Unexpected junk" }
-
-!$omp distribute simd
-do i = 1, 5
-end do
-!$omp end distribute simd nowait  ! { dg-error "Unexpected junk" }
-
-!$omp masked
-!$omp end masked nowait  ! { dg-error "Unexpected junk" }
-
-!$omp masked taskloop
-do i = 1, 5
-end do
-!$omp end masked taskloop nowait  ! { dg-error "Unexpected junk" }
-
-!$omp masked taskloop simd
-do i = 1, 5
-end do
-!$omp end masked taskloop simd nowait  ! { dg-error "Unexpected junk" }
-
-!$omp master
-!$omp end master nowait  ! { dg-error "Unexpected junk" }
-
-!$omp master taskloop
-do i = 1, 5
-end do
-!$omp end master taskloop nowait  ! { dg-error "Unexpected junk" }
-
-!$omp master taskloop simd
-do i = 1, 5
-end do
-!$omp end master taskloop simd nowait  ! { dg-error "Unexpected junk" }
-
-!$omp ordered
-!$omp end ordered nowait  ! { dg-error "Unexpected junk" }
-
-!$omp parallel
-!$omp end parallel nowait  ! { dg-error "Unexpected junk" }
-
-!$omp parallel workshare
-a(:) = 5
-!$omp end parallel workshare nowait  ! { dg-error "Unexpected junk" }
-
-!$omp parallel do
-do i = 1, 5
-end do
-!$omp end parallel do nowait  ! { dg-error "Unexpected junk" }
-
-!$omp parallel do simd
-do i = 1, 5
-end do
-!$omp end parallel do simd nowait  ! { dg-error "Unexpected junk" }
-
-!$omp parallel masked
-!$omp end parallel masked nowait  ! { dg-error "Unexpected junk" }
-
-!$omp parallel masked taskloop
-do i = 1, 5
-end do
-!$omp end parallel masked taskloop nowait  ! { dg-error "Unexpected junk" }
-
-!$omp parallel masked taskloop simd
-do i = 1, 5
-end do
-!$omp end parallel masked taskloop simd nowait  ! { dg-error "Unexpected junk" }
-
-!$omp parallel master
-!$omp end parallel master nowait  ! { dg-error "Unexpected junk" }
-
-!$omp parallel master taskloop
-do i = 1, 5
-end do
-!$omp end parallel master taskloop nowait  ! { dg-error "Unexpected junk" }
-
-!$omp parallel master taskloop simd
-do i = 1, 5
-end do
-!$omp end parallel master taskloop simd nowait  ! { dg-error "Unexpected junk" }
-
-!$omp simd
-do i = 1, 5
-end do
-!$omp end simd nowait  ! { dg-error "Unexpected junk" }
-
-!$omp task
-!$omp end task nowait  ! { dg-error "Unexpected junk" }
-
-!$omp taskgroup
-!$omp end taskgroup nowait  ! { dg-error "Unexpected junk" }
-
-!$omp taskloop
-do i = 1, 5
-end do
-!$omp end taskloop nowait  ! { dg-error "Unexpected junk" }
-
-!$omp taskloop simd
-do i = 1, 5
-end do
-!$omp end taskloop simd nowait  ! { dg-error "Unexpected junk" }
-
-!$omp teams
-!$omp end teams nowait  ! { dg-error "Unexpected junk" }
-
-!$omp teams distribute
-do i = 1, 5
-end do
-!$omp end teams distribute nowait  ! { dg-error "Unexpected junk" }
-
-!$omp teams distribute parallel do
-do i = 1, 5
-end do
-!$omp end teams distribute parallel do nowait  ! { dg-error "Unexpected junk" }
-
-!$omp teams distribute parallel do simd
-do i = 1, 5
-end do
-!$omp end teams distribute parallel do simd nowait  ! { dg-error "Unexpected junk" }
-
-!$omp teams distribute simd
-do i = 1, 5
-end do
-!$omp end teams distribute simd nowait  ! { dg-error "Unexpected junk" }
-
-!$omp target data map(tofrom:i)
-!$omp end target data nowait  ! { dg-error "Unexpected junk" }
-
-end  ! { dg-error "Unexpected END statement" }
-! { dg-prune-output "Unexpected end of file" }
diff --git a/gcc/testsuite/gfortran.dg/gomp/nowait-4.f90 b/gcc/testsuite/gfortran.dg/gomp/nowait-4.f90
new file mode 100644
index 00000000000..bebb9d7fb8f
--- /dev/null
+++ b/gcc/testsuite/gfortran.dg/gomp/nowait-4.f90
@@ -0,0 +1,158 @@
+! invalid nowait
+
+subroutine foo
+implicit none
+integer :: i, a(5)
+!$omp atomic write
+i = 5
+!$omp end atomic nowait  ! { dg-error "Unexpected junk" }
+
+!$omp critical
+!$omp end critical nowait  ! { dg-error "Unexpected junk" }
+
+!$omp distribute
+do i = 1, 5
+end do
+!$omp end distribute nowait  ! { dg-error "Unexpected junk" }
+
+!$omp distribute parallel do
+do i = 1, 5
+end do
+!$omp end distribute parallel do nowait  ! { dg-error "Unexpected junk" }
+
+!$omp distribute parallel do simd
+do i = 1, 5
+end do
+!$omp end distribute parallel do simd nowait  ! { dg-error "Unexpected junk" }
+
+!$omp parallel sections
+  !$omp section
+  block; end block
+!$omp end parallel sections nowait  ! { dg-error "Unexpected junk" }
+
+!$omp distribute simd
+do i = 1, 5
+end do
+!$omp end distribute simd nowait  ! { dg-error "Unexpected junk" }
+
+!$omp masked
+!$omp end masked nowait  ! { dg-error "Unexpected junk" }
+
+!$omp masked taskloop
+do i = 1, 5
+end do
+!$omp end masked taskloop nowait  ! { dg-error "Unexpected junk" }
+
+!$omp masked taskloop simd
+do i = 1, 5
+end do
+!$omp end masked taskloop simd nowait  ! { dg-error "Unexpected junk" }
+
+!$omp master
+!$omp end master nowait  ! { dg-error "Unexpected junk" }
+
+!$omp master taskloop
+do i = 1, 5
+end do
+!$omp end master taskloop nowait  ! { dg-error "Unexpected junk" }
+
+!$omp master taskloop simd
+do i = 1, 5
+end do
+!$omp end master taskloop simd nowait  ! { dg-error "Unexpected junk" }
+
+!$omp ordered
+!$omp end ordered nowait  ! { dg-error "Unexpected junk" }
+
+!$omp parallel
+!$omp end parallel nowait  ! { dg-error "Unexpected junk" }
+
+!$omp parallel workshare
+a(:) = 5
+!$omp end parallel workshare nowait  ! { dg-error "Unexpected junk" }
+
+!$omp parallel do
+do i = 1, 5
+end do
+!$omp end parallel do nowait  ! { dg-error "Unexpected junk" }
+
+!$omp parallel do simd
+do i = 1, 5
+end do
+!$omp end parallel do simd nowait  ! { dg-error "Unexpected junk" }
+
+!$omp parallel masked
+!$omp end parallel masked nowait  ! { dg-error "Unexpected junk" }
+
+!$omp parallel masked taskloop
+do i = 1, 5
+end do
+!$omp end parallel masked taskloop nowait  ! { dg-error "Unexpected junk" }
+
+!$omp parallel masked taskloop simd
+do i = 1, 5
+end do
+!$omp end parallel masked taskloop simd nowait  ! { dg-error "Unexpected junk" }
+
+!$omp parallel master
+!$omp end parallel master nowait  ! { dg-error "Unexpected junk" }
+
+!$omp parallel master taskloop
+do i = 1, 5
+end do
+!$omp end parallel master taskloop nowait  ! { dg-error "Unexpected junk" }
+
+!$omp parallel master taskloop simd
+do i = 1, 5
+end do
+!$omp end parallel master taskloop simd nowait  ! { dg-error "Unexpected junk" }
+
+!$omp simd
+do i = 1, 5
+end do
+!$omp end simd nowait  ! { dg-error "Unexpected junk" }
+
+!$omp task
+!$omp end task nowait  ! { dg-error "Unexpected junk" }
+
+!$omp taskgroup
+!$omp end taskgroup nowait  ! { dg-error "Unexpected junk" }
+
+!$omp taskloop
+do i = 1, 5
+end do
+!$omp end taskloop nowait  ! { dg-error "Unexpected junk" }
+
+!$omp taskloop simd
+do i = 1, 5
+end do
+!$omp end taskloop simd nowait  ! { dg-error "Unexpected junk" }
+
+!$omp teams
+!$omp end teams nowait  ! { dg-error "Unexpected junk" }
+
+!$omp teams distribute
+do i = 1, 5
+end do
+!$omp end teams distribute nowait  ! { dg-error "Unexpected junk" }
+
+!$omp teams distribute parallel do
+do i = 1, 5
+end do
+!$omp end teams distribute parallel do nowait  ! { dg-error "Unexpected junk" }
+
+!$omp teams distribute parallel do simd
+do i = 1, 5
+end do
+!$omp end teams distribute parallel do simd nowait  ! { dg-error "Unexpected junk" }
+
+!$omp teams distribute simd
+do i = 1, 5
+end do
+!$omp end teams distribute simd nowait  ! { dg-error "Unexpected junk" }
+
+!$omp target data map(tofrom:i)
+!$omp end target data nowait  ! { dg-error "Unexpected junk" }
+
+end  ! { dg-error "Unexpected END statement" }
+! { dg-prune-output "Unexpected end of file" }
diff --git a/gcc/testsuite/gfortran.dg/gomp/nowait-5.f90 b/gcc/testsuite/gfortran.dg/gomp/nowait-5.f90
new file mode 100644
index 00000000000..c6881171e5d
--- /dev/null
+++ b/gcc/testsuite/gfortran.dg/gomp/nowait-5.f90
@@ -0,0 +1,156 @@
+! Cross check that it is accepted without nowait
+subroutine bar()
+implicit none
+integer :: i, a(5)
+!$omp atomic write
+i = 5
+!$omp end atomic
+
+!$omp critical
+!$omp end critical
+
+!$omp distribute
+do i = 1, 5
+end do
+!$omp end distribute
+
+!$omp distribute parallel do
+do i = 1, 5
+end do
+!$omp end distribute parallel do
+
+!$omp distribute parallel do simd
+do i = 1, 5
+end do
+!$omp end distribute parallel do simd
+
+!$omp distribute simd
+do i = 1, 5
+end do
+!$omp end distribute simd
+
+!$omp masked
+!$omp end masked
+
+!$omp masked taskloop
+do i = 1, 5
+end do
+!$omp end masked taskloop
+
+!$omp masked taskloop simd
+do i = 1, 5
+end do
+!$omp end masked taskloop simd
+
+!$omp master
+!$omp end master
+
+!$omp master taskloop
+do i = 1, 5
+end do
+!$omp end master taskloop
+
+!$omp master taskloop simd
+do i = 1, 5
+end do
+!$omp end master taskloop simd
+
+!$omp ordered
+!$omp end ordered
+
+!$omp parallel
+!$omp end parallel
+
+!$omp parallel workshare
+a(:) = 5
+!$omp end parallel workshare
+
+!$omp parallel do
+do i = 1, 5
+end do
+!$omp end parallel do
+
+!$omp parallel do simd
+do i = 1, 5
+end do
+!$omp end parallel do simd
+
+!$omp parallel sections
+  !$omp section
+  block; end block
+!$omp end parallel sections
+
+!$omp parallel masked
+!$omp end parallel masked
+
+!$omp parallel masked taskloop
+do i = 1, 5
+end do
+!$omp end parallel masked taskloop
+
+!$omp parallel masked taskloop simd
+do i = 1, 5
+end do
+!$omp end parallel masked taskloop simd
+
+!$omp parallel master
+!$omp end parallel master
+
+!$omp parallel master taskloop
+do i = 1, 5
+end do
+!$omp end parallel master taskloop
+
+!$omp parallel master taskloop simd
+do i = 1, 5
+end do
+!$omp end parallel master taskloop simd
+
+!$omp simd
+do i = 1, 5
+end do
+!$omp end simd
+
+!$omp task
+!$omp end task
+
+!$omp taskgroup
+!$omp end taskgroup
+
+!$omp taskloop
+do i = 1, 5
+end do
+!$omp end taskloop
+
+!$omp taskloop simd
+do i = 1, 5
+end do
+!$omp end taskloop simd
+
+!$omp teams
+!$omp end teams
+
+!$omp teams distribute
+do i = 1, 5
+end do
+!$omp end teams distribute
+
+!$omp teams distribute parallel do
+do i = 1, 5
+end do
+!$omp end teams distribute parallel do
+
+!$omp teams distribute parallel do simd
+do i = 1, 5
+end do
+!$omp end teams distribute parallel do simd
+
+!$omp teams distribute simd
+do i = 1, 5
+end do
+!$omp end teams distribute simd
+
+!$omp target data map(tofrom:i)
+!$omp end target data
+
+end
diff --git a/gcc/testsuite/gfortran.dg/gomp/nowait-6.f90 b/gcc/testsuite/gfortran.dg/gomp/nowait-6.f90
new file mode 100644
index 00000000000..5fe7d38fcb7
--- /dev/null
+++ b/gcc/testsuite/gfortran.dg/gomp/nowait-6.f90
@@ -0,0 +1,158 @@
+! invalid nowait
+
+subroutine foo
+implicit none
+integer :: i, a(5)
+!$omp atomic write nowait  ! { dg-error "Failed to match clause" }
+i = 5
+!$omp end atomic  ! { dg-error "Unexpected ..OMP END " }
+
+!$omp critical nowait  ! { dg-error "Failed to match clause" }
+!$omp end critical  ! { dg-error "Unexpected ..OMP END " }
+
+!$omp distribute nowait  ! { dg-error "Failed to match clause" }
+do i = 1, 5
+end do
+!$omp end distribute  ! { dg-error "Unexpected ..OMP END " }
+
+!$omp distribute parallel do nowait  ! { dg-error "Failed to match clause" }
+do i = 1, 5
+end do
+!$omp end distribute parallel do  ! { dg-error "Unexpected ..OMP END " }
+
+!$omp distribute parallel do simd nowait  ! { dg-error "Failed to match clause" }
+do i = 1, 5
+end do
+!$omp end distribute parallel do simd  ! { dg-error "Unexpected ..OMP END " }
+
+!$omp parallel sections nowait  ! { dg-error "Failed to match clause" }
+  !$omp section  ! { dg-error "Unexpected ..OMP SECTION statement" }
+  block; end block
+!$omp end parallel sections  ! { dg-error "Unexpected ..OMP END " }
+
+!$omp distribute simd nowait  ! { dg-error "Failed to match clause" }
+do i = 1, 5
+end do
+!$omp end distribute simd  ! { dg-error "Unexpected ..OMP END " }
+
+!$omp masked nowait  ! { dg-error "Failed to match clause" }
+!$omp end masked  ! { dg-error "Unexpected ..OMP END " }
+
+!$omp masked taskloop nowait  ! { dg-error "Failed to match clause" }
+do i = 1, 5
+end do
+!$omp end masked taskloop  ! { dg-error "Unexpected ..OMP END " }
+
+!$omp masked taskloop simd nowait  ! { dg-error "Failed to match clause" }
+do i = 1, 5
+end do
+!$omp end masked taskloop simd  ! { dg-error "Unexpected ..OMP END " }
+
+!$omp master nowait  ! { dg-error "Unexpected junk" }
+!$omp end master  ! { dg-error "Unexpected ..OMP END " }
+
+!$omp master taskloop nowait  ! { dg-error "Failed to match clause" }
+do i = 1, 5
+end do
+!$omp end master taskloop  ! { dg-error "Unexpected ..OMP END " }
+
+!$omp master taskloop simd nowait  ! { dg-error "Failed to match clause" }
+do i = 1, 5
+end do
+!$omp end master taskloop simd  ! { dg-error "Unexpected ..OMP END " }
+
+!$omp ordered nowait  ! { dg-error "Failed to match clause" }
+!$omp end ordered  ! { dg-error "Unexpected ..OMP END " }
+
+!$omp parallel nowait  ! { dg-error "Failed to match clause" }
+!$omp end parallel  ! { dg-error "Unexpected ..OMP END " }
+
+!$omp parallel workshare nowait  ! { dg-error "Failed to match clause" }
+a(:) = 5
+!$omp end parallel workshare  ! { dg-error "Unexpected ..OMP END " }
+
+!$omp parallel do nowait  ! { dg-error "Failed to match clause" }
+do i = 1, 5
+end do
+!$omp end parallel do  ! { dg-error "Unexpected ..OMP END " }
+
+!$omp parallel do simd nowait  ! { dg-error "Failed to match clause" }
+do i = 1, 5
+end do
+!$omp end parallel do simd  ! { dg-error "Unexpected ..OMP END " }
+
+!$omp parallel masked nowait  ! { dg-error "Failed to match clause" }
+!$omp end parallel masked  ! { dg-error "Unexpected ..OMP END " }
+
+!$omp parallel masked taskloop nowait  ! { dg-error "Failed to match clause" }
+do i = 1, 5
+end do
+!$omp end parallel masked taskloop  ! { dg-error "Unexpected ..OMP END " }
+
+!$omp parallel masked taskloop simd nowait  ! { dg-error "Failed to match clause" }
+do i = 1, 5
+end do
+!$omp end parallel masked taskloop simd  ! { dg-error "Unexpected ..OMP END " }
+
+!$omp parallel master nowait  ! { dg-error "Failed to match clause" }
+!$omp end parallel master  ! { dg-error "Unexpected ..OMP END " }
+
+!$omp parallel master taskloop nowait  ! { dg-error "Failed to match clause" }
+do i = 1, 5
+end do
+!$omp end parallel master taskloop  ! { dg-error "Unexpected ..OMP END " }
+
+!$omp parallel master taskloop simd nowait  ! { dg-error "Failed to match clause" }
+do i = 1, 5
+end do
+!$omp end parallel master taskloop simd  ! { dg-error "Unexpected ..OMP END " }
+
+!$omp simd nowait  ! { dg-error "Failed to match clause" }
+do i = 1, 5
+end do
+!$omp end simd  ! { dg-error "Unexpected ..OMP END " }
+
+!$omp task nowait  ! { dg-error "Failed to match clause" }
+!$omp end task  ! { dg-error "Unexpected ..OMP END " }
+
+!$omp taskgroup nowait  ! { dg-error "Failed to match clause" }
+!$omp end taskgroup  ! { dg-error "Unexpected ..OMP END " }
+
+!$omp taskloop nowait  ! { dg-error "Failed to match clause" }
+do i = 1, 5
+end do
+!$omp end taskloop  ! { dg-error "Unexpected ..OMP END " }
+
+!$omp taskloop simd nowait  ! { dg-error "Failed to match clause" }
+do i = 1, 5
+end do
+!$omp end taskloop simd  ! { dg-error "Unexpected ..OMP END " }
+
+!$omp teams nowait  ! { dg-error "Failed to match clause" }
+!$omp end teams  ! { dg-error "Unexpected ..OMP END " }
+
+!$omp teams distribute nowait  ! { dg-error "Failed to match clause" }
+do i = 1, 5
+end do
+!$omp end teams distribute  ! { dg-error "Unexpected ..OMP END " }
+
+!$omp teams distribute parallel do nowait  ! { dg-error "Failed to match clause" }
+do i = 1, 5
+end do
+!$omp end teams distribute parallel do  ! { dg-error "Unexpected ..OMP END " }
+
+!$omp teams distribute parallel do simd nowait  ! { dg-error "Failed to match clause" }
+do i = 1, 5
+end do
+!$omp end teams distribute parallel do simd  ! { dg-error "Unexpected ..OMP END " }
+
+!$omp teams distribute simd nowait  ! { dg-error "Failed to match clause" }
+do i = 1, 5
+end do
+!$omp end teams distribute simd  ! { dg-error "Unexpected ..OMP END " }
+
+!$omp target data map(tofrom:i) nowait  ! { dg-error "Failed to match clause" }
+!$omp end target data  ! { dg-error "Unexpected ..OMP END " }
+
+end
+! { dg-prune-output "Unexpected end of file" }
diff --git a/gcc/testsuite/gfortran.dg/gomp/nowait-7.f90 b/gcc/testsuite/gfortran.dg/gomp/nowait-7.f90
new file mode 100644
index 00000000000..41ead2f7eeb
--- /dev/null
+++ b/gcc/testsuite/gfortran.dg/gomp/nowait-7.f90
@@ -0,0 +1,118 @@
+! { dg-additional-options "-fdump-tree-original" }
+
+subroutine foo
+implicit none
+integer :: i, a(5)
+
+!$omp do nowait
+do i = 1, 5
+end do
+!$omp end do
+
+!$omp do simd nowait
+do i = 1, 5
+end do
+!$omp end do simd
+
+!$omp scope nowait
+!$omp end scope
+
+!$omp sections nowait
+  !$omp section
+  block; end block
+!$omp end sections
+
+!$omp single nowait
+!$omp end single
+
+!$omp target nowait
+!$omp end target
+
+!$omp target parallel nowait
+!$omp end target parallel
+
+!$omp target parallel do nowait
+do i = 1, 5
+end do
+!$omp end target parallel do
+
+!$omp target parallel do simd nowait
+do i = 1, 5
+end do
+!$omp end target parallel do simd
+
+!$omp target parallel loop nowait
+do i = 1, 5
+end do
+!$omp end target parallel loop
+
+!$omp target teams distribute parallel do nowait
+do i = 1, 5
+end do
+!$omp end target teams distribute parallel do
+
+!$omp target teams distribute parallel do simd nowait
+do i = 1, 5
+end do
+!$omp end target teams distribute parallel do simd
+
+!$omp target simd nowait
+do i = 1, 5
+end do
+!$omp end target simd
+
+!$omp target teams nowait
+!$omp end target teams
+
+!$omp target teams distribute nowait
+do i = 1, 5
+end do
+!$omp end target teams distribute
+
+!$omp target teams distribute simd nowait
+do i = 1, 5
+end do
+!$omp end target teams distribute simd
+
+!$omp target teams loop nowait
+do i = 1, 5
+end do
+!$omp end target teams loop
+
+!$omp workshare nowait
+A(:) = 5
+!$omp end workshare
+end
+
+! Note: internally, for '... parallel do ...', 'nowait' is always added
+! such that for 'omp end target parallel do nowait', 'nowait' is on both
+! 'target' as specified in the OpenMP spec and and on 'do' due to internal usage.
+
+! Expected with 'nowait'
+
+! { dg-final { scan-tree-dump-times "#pragma omp for nowait" 6 "original" } }
+! { dg-final { scan-tree-dump-times "#pragma omp for schedule\\(static\\) nowait" 1 "original" } }
+! { dg-final { scan-tree-dump-times "#pragma omp sections nowait" 1 "original" } }
+! { dg-final { scan-tree-dump-times "#pragma omp single nowait" 1 "original" } }
+! { dg-final { scan-tree-dump-times "#pragma omp target nowait" 12 "original" } }
+
+! Never:
+
+! { dg-final { scan-tree-dump-not "#pragma omp distribute\[^\n\r]*nowait" "original" } }
+! { dg-final { scan-tree-dump-not "#pragma omp loop\[^\n\r]*nowait" "original" } }
+! { dg-final { scan-tree-dump-not "#pragma omp parallel\[^\n\r]*nowait" "original" } }
+! { dg-final { scan-tree-dump-not "#pragma omp section\[^s\]\[^\n\r]*nowait" "original" } }
+! { dg-final { scan-tree-dump-not "#pragma omp simd\[^\n\r]*nowait" "original" } }
+! { dg-final { scan-tree-dump-not "#pragma omp teams\[^\n\r]*nowait" "original" } }
+
+! Sometimes or never with nowait:
+
+! { dg-final { scan-tree-dump-times "#pragma omp distribute\[\n\r]" 4 "original" } }
+! { dg-final { scan-tree-dump-times "#pragma omp loop\[\n\r]" 2 "original" } }
+! { dg-final { scan-tree-dump-times "#pragma omp parallel\[\n\r]" 6 "original" } }
+! { dg-final { scan-tree-dump-times "#pragma omp section\[\n\r]" 1 "original" } }
+! { dg-final { scan-tree-dump-times "#pragma omp simd linear\\(i:1\\)\[\n\r]" 5 "original" } }
+! { dg-final { scan-tree-dump-times "#pragma omp teams\[\n\r]" 6 "original" } }
+
+! { dg-final { scan-tree-dump-times "#pragma omp target\[\n\r]" 0 "original" } }
+! { dg-final { scan-tree-dump-times "#pragma omp for\[\n\r]" 0 "original" } }
diff --git a/gcc/testsuite/gfortran.dg/gomp/nowait-8.f90 b/gcc/testsuite/gfortran.dg/gomp/nowait-8.f90
new file mode 100644
index 00000000000..5e666d123c5
--- /dev/null
+++ b/gcc/testsuite/gfortran.dg/gomp/nowait-8.f90
@@ -0,0 +1,92 @@
+subroutine foo
+implicit none
+integer :: i, a(5)
+
+!$omp do nowait nowait  ! { dg-error "Duplicated 'nowait' clause" }
+do i = 1, 5
+end do
+
+!$omp do
+do i = 1, 5
+end do
+!$omp do nowait nowait  ! { dg-error "Duplicated 'nowait' clause" }
+
+!$omp do nowait
+do i = 1, 5
+end do
+!$omp end do nowait  ! { dg-error "Duplicated NOWAIT clause" }
+
+!$omp do simd nowait
+do i = 1, 5
+end do
+!$omp end do simd nowait  ! { dg-error "Duplicated NOWAIT clause" }
+
+!$omp scope nowait
+!$omp end scope nowait  ! { dg-error "Duplicated NOWAIT clause" }
+
+!$omp sections nowait
+  !$omp section
+  block; end block
+!$omp end sections nowait  ! { dg-error "Duplicated NOWAIT clause" }
+
+!$omp single nowait
+!$omp end single nowait  ! { dg-error "Duplicated NOWAIT clause" }
+
+!$omp target nowait
+!$omp end target nowait  ! { dg-error "Duplicated NOWAIT clause" }
+
+!$omp target parallel nowait
+!$omp end target parallel nowait  ! { dg-error "Duplicated NOWAIT clause" }
+
+!$omp target parallel do nowait
+do i = 1, 5
+end do
+!$omp end target parallel do nowait  ! { dg-error "Duplicated NOWAIT clause" }
+
+!$omp target parallel do simd nowait
+do i = 1, 5
+end do
+!$omp end target parallel do simd nowait  ! { dg-error "Duplicated NOWAIT clause" }
+
+!$omp target parallel loop nowait
+do i = 1, 5
+end do
+!$omp end target parallel loop nowait  ! { dg-error "Duplicated NOWAIT clause" }
+
+!$omp target teams distribute parallel do nowait
+do i = 1, 5
+end do
+!$omp end target teams distribute parallel do nowait  ! { dg-error "Duplicated NOWAIT clause" }
+
+!$omp target teams distribute parallel do simd nowait
+do i = 1, 5
+end do
+!$omp end target teams distribute parallel do simd nowait  ! { dg-error "Duplicated NOWAIT clause" }
+
+!$omp target simd nowait
+do i = 1, 5
+end do
+!$omp end target simd nowait  ! { dg-error "Duplicated NOWAIT clause" }
+
+!$omp target teams nowait
+!$omp end target teams nowait  ! { dg-error "Duplicated NOWAIT clause" }
+
+!$omp target teams distribute nowait
+do i = 1, 5
+end do
+!$omp end target teams distribute nowait  ! { dg-error "Duplicated NOWAIT clause" }
+
+!$omp target teams distribute simd nowait
+do i = 1, 5
+end do
+!$omp end target teams distribute simd nowait  ! { dg-error "Duplicated NOWAIT clause" }
+
+!$omp target teams loop nowait
+do i = 1, 5
+end do
+!$omp end target teams loop nowait  ! { dg-error "Duplicated NOWAIT clause" }
+
+!$omp workshare nowait
+A(:) = 5
+!$omp end workshare nowait  ! { dg-error "Duplicated NOWAIT clause" }
+end
diff --git a/libgomp/libgomp.texi b/libgomp/libgomp.texi
index 584af45bd67..85cae742cd4 100644
--- a/libgomp/libgomp.texi
+++ b/libgomp/libgomp.texi
@@ -375,7 +375,7 @@ to address of matching mapped list item per 5.1, Sect. 2.21.7.2 @tab N @tab
       a warning enabled by default and, for fixed-source code, the @code{omx}
       sentinel is warned for with with @code{-Wsurprising} (enabled by
       @code{-Wall}).  Unknown clauses are always rejected with an error.}
-@item Clauses on @code{end} directive can be on directive @tab N @tab
+@item Clauses on @code{end} directive can be on directive @tab Y @tab
 @item Deprecation of no-argument @code{destroy} clause on @code{depobj}
       @tab N @tab
 @item @code{linear} clause syntax changes and @code{step} modifier @tab Y @tab

      parent reply	other threads:[~2022-11-27 17:38 UTC|newest]

Thread overview: 5+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2022-08-26 18:21 Tobias Burnus
2022-08-29 20:49 ` Harald Anlauf
2022-09-08 15:21 ` Jakub Jelinek
2022-09-08 15:25   ` Jakub Jelinek
2022-11-27 17:38   ` Tobias Burnus [this message]

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to=a2e2e68c-49ed-4fde-ab8d-e5a3cfd4aea9@codesourcery.com \
    --to=tobias@codesourcery.com \
    --cc=fortran@gcc.gnu.org \
    --cc=gcc-patches@gcc.gnu.org \
    --cc=jakub@redhat.com \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for read-only IMAP folder(s) and NNTP newsgroup(s).