OpenMP/Fortran: Permit end-clause on directive

Message ID 821786f3-ac7b-01e3-a386-f7c082494022@codesourcery.com
State New, archived
Headers
Series OpenMP/Fortran: Permit end-clause on directive |

Commit Message

Tobias Burnus Aug. 26, 2022, 6:21 p.m. UTC
  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
  

Comments

Harald Anlauf Aug. 29, 2022, 8:49 p.m. UTC | #1
Hi Tobias,

this is not really a review, but:

Am 26.08.22 um 20:21 schrieb Tobias Burnus:
> 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?

Regarding testcase nowait-4.f90: it has a part that tests for many
formally correct uses, and a part that tests for many invalid nowait.
Both parts seem to be giving reasonable coverage, so I wonder whether
it would be beneficial to split this one into two subsets.

It makes sense to have fewer but larger testcases in the testsuite,
to keep the time for regtesting at bay, but I'm split here on this
one - and yes, pun intended.

Harald

> 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
  
Jakub Jelinek Sept. 8, 2022, 3:21 p.m. UTC | #2
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
  
Jakub Jelinek Sept. 8, 2022, 3:25 p.m. UTC | #3
On Thu, Sep 08, 2022 at 05:21:08PM +0200, Jakub Jelinek via Gcc-patches wrote:
> Otherwise LGTM.

Oh, and what Harald wrote, it might be better to split the nowait-4.f90 test
into 2, one for all the valid nowait cases and one for the invalid ones,
such that the first one can be compile tested all the way through assembly.

	Jakub
  
Tobias Burnus Nov. 27, 2022, 5:38 p.m. UTC | #4
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
  

Patch

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'.
	(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-4.f90: New test.
	* gfortran.dg/gomp/nowait-5.f90: New test.
	* gfortran.dg/gomp/nowait-6.f90: New test.

 gcc/fortran/openmp.cc                            |  55 ++--
 gcc/fortran/parse.cc                             |  33 ++-
 gcc/testsuite/gfortran.dg/gomp/copyprivate-1.f90 |  21 ++
 gcc/testsuite/gfortran.dg/gomp/copyprivate-2.f90 |  69 +++++
 gcc/testsuite/gfortran.dg/gomp/nowait-4.f90      | 315 +++++++++++++++++++++++
 gcc/testsuite/gfortran.dg/gomp/nowait-5.f90      | 118 +++++++++
 gcc/testsuite/gfortran.dg/gomp/nowait-6.f90      |  92 +++++++
 libgomp/libgomp.texi                             |   2 +-
 8 files changed, 673 insertions(+), 32 deletions(-)

diff --git a/gcc/fortran/openmp.cc b/gcc/fortran/openmp.cc
index 594907714ff..b3b6fc17828 100644
--- a/gcc/fortran/openmp.cc
+++ b/gcc/fortran/openmp.cc
@@ -3795,17 +3795,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	\
@@ -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 \
@@ -4020,8 +4022,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));
 }
 
 
@@ -4031,7 +4033,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));
 }
 
 
@@ -5332,7 +5334,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)));
 }
 
 
@@ -5340,7 +5343,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)));
 }
 
 
@@ -5396,7 +5400,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)));
 }
 
 
@@ -5882,8 +5887,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));
 }
 
 
@@ -5893,7 +5898,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));
 }
 
 
@@ -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;
 }
 
@@ -6220,14 +6224,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;
@@ -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 "
+			 "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 80492c952aa..8a1bfda64d6 100644
--- a/gcc/fortran/parse.cc
+++ b/gcc/fortran/parse.cc
@@ -939,7 +939,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,
@@ -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 ();
@@ -5720,6 +5727,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:
@@ -5734,8 +5745,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..6615ed8688a
--- /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" }
+        !$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
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..8472df95f83
--- /dev/null
+++ b/gcc/testsuite/gfortran.dg/gomp/nowait-4.f90
@@ -0,0 +1,315 @@ 
+! 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
+
+! 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-5.f90 b/gcc/testsuite/gfortran.dg/gomp/nowait-5.f90
new file mode 100644
index 00000000000..41ead2f7eeb
--- /dev/null
+++ b/gcc/testsuite/gfortran.dg/gomp/nowait-5.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-6.f90 b/gcc/testsuite/gfortran.dg/gomp/nowait-6.f90
new file mode 100644
index 00000000000..5e666d123c5
--- /dev/null
+++ b/gcc/testsuite/gfortran.dg/gomp/nowait-6.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 0f2998cf8f1..6d580f70b2b 100644
--- a/libgomp/libgomp.texi
+++ b/libgomp/libgomp.texi
@@ -360,7 +360,7 @@  to address of matching mapped list item per 5.1, Sect. 2.21.7.2 @tab N @tab
       @tab N @tab
 @item @code{omp}/@code{ompx}/@code{omx} sentinels and @code{omp_}/@code{ompx_}
       namespaces @tab N/A @tab
-@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