File tree Expand file tree Collapse file tree 5 files changed +116
-5
lines changed Expand file tree Collapse file tree 5 files changed +116
-5
lines changed Original file line number Diff line number Diff line change @@ -1484,11 +1484,25 @@ struct OmpBlockConstructParser {
14841484 [](auto &&s) { return OmpEndDirective(std::move(s)); })};
14851485 } else if (auto &&body{
14861486 attempt(LooselyStructuredBlockParser{}).Parse(state)}) {
1487- // Try loosely-structured block with a mandatory end-directive
1488- if (auto end{OmpEndDirectiveParser{dir_}.Parse(state)}) {
1489- return OmpBlockConstruct{OmpBeginDirective(std::move(*begin)),
1490- std::move(*body), OmpEndDirective{std::move(*end)}};
1487+ // Try loosely-structured block with a mandatory end-directive.
1488+ auto end{maybe(OmpEndDirectiveParser{dir_}).Parse(state)};
1489+ // Dereference outer optional (maybe() always succeeds) and look at the
1490+ // inner optional.
1491+ bool endPresent{end->has_value()};
1492+
1493+ // ORDERED is special. We do need to return failure here so that the
1494+ // standalone ORDERED construct can be distinguished from the block
1495+ // associated construct.
1496+ if (!endPresent && dir_ == llvm::omp::Directive::OMPD_ordered) {
1497+ return std::nullopt;
14911498 }
1499+
1500+ // Delay the error for a missing end-directive until semantics so that
1501+ // we have better control over the output.
1502+ return OmpBlockConstruct{OmpBeginDirective(std::move(*begin)),
1503+ std::move(*body),
1504+ llvm::transformOptional(std::move(*end),
1505+ [](auto &&s) { return OmpEndDirective(std::move(s)); })};
14921506 }
14931507 }
14941508 return std::nullopt;
Original file line number Diff line number Diff line change @@ -843,6 +843,30 @@ void OmpStructureChecker::Enter(const parser::OpenMPBlockConstruct &x) {
843843 const parser::Block &block{std::get<parser::Block>(x.t )};
844844
845845 PushContextAndClauseSets (beginSpec.DirName ().source , beginSpec.DirId ());
846+
847+ // Missing mandatory end block: this is checked in semantics because that
848+ // makes it easier to control the error messages.
849+ // The end block is mandatory when the construct is not applied to a strictly
850+ // structured block (aka it is applied to a loosely structured block). In
851+ // other words, the body doesn't contain exactly one parser::BlockConstruct.
852+ auto isStrictlyStructuredBlock{[](const parser::Block &block) -> bool {
853+ if (block.size () != 1 ) {
854+ return false ;
855+ }
856+ const parser::ExecutionPartConstruct &contents{block.front ()};
857+ auto *executableConstruct{
858+ std::get_if<parser::ExecutableConstruct>(&contents.u )};
859+ if (!executableConstruct) {
860+ return false ;
861+ }
862+ return std::holds_alternative<common::Indirection<parser::BlockConstruct>>(
863+ executableConstruct->u );
864+ }};
865+ if (!endSpec && !isStrictlyStructuredBlock (block)) {
866+ context_.Say (
867+ x.BeginDir ().source , " Expected OpenMP end directive" _err_en_US);
868+ }
869+
846870 if (llvm::omp::allTargetSet.test (GetContext ().directive )) {
847871 EnterDirectiveNest (TargetNest);
848872 }
Original file line number Diff line number Diff line change 11! RUN: not %flang_fc1 -fsyntax-only -fopenmp %s 2>&1 | FileCheck %s
22
33! $omp parallel
4- ! CHECK: error: expected '!$OMP '
4+ ! CHECK: error: Expected OpenMP end directive
55end
Original file line number Diff line number Diff line change 1+ ! RUN: %flang_fc1 -fdebug-dump-parse-tree -fopenmp -fopenmp-version=45 %s | FileCheck %s
2+
3+ ! Check that standalone ORDERED is successfully distinguished form block associated ORDERED
4+
5+ ! CHECK: | SubroutineStmt
6+ ! CHECK-NEXT: | | Name = 'standalone'
7+ subroutine standalone
8+ integer :: x(10 , 10 )
9+ do i = 1 , 10
10+ do j = 1 ,10
11+ ! CHECK: OpenMPConstruct -> OpenMPStandaloneConstruct
12+ ! CHECK-NEXT: | OmpDirectiveName -> llvm::omp::Directive = ordered
13+ ! CHECK-NEXT: | OmpClauseList ->
14+ ! CHECK-NEXT: | Flags = None
15+ ! $omp ordered
16+ x(i, j) = i + j
17+ end do
18+ end do
19+ end subroutine
20+
21+ ! CHECK: | SubroutineStmt
22+ ! CHECK-NEXT: | | Name = 'strict_block'
23+ subroutine strict_block
24+ integer :: x(10 , 10 )
25+ integer :: tmp
26+ do i = 1 , 10
27+ do j = 1 ,10
28+ ! CHECK: OpenMPConstruct -> OpenMPBlockConstruct
29+ ! CHECK-NEXT: | OmpBeginDirective
30+ ! CHECK-NEXT: | | OmpDirectiveName -> llvm::omp::Directive = ordered
31+ ! CHECK-NEXT: | | OmpClauseList ->
32+ ! CHECK-NEXT: | | Flags = None
33+ ! $omp ordered
34+ block
35+ tmp = i + j
36+ x(i, j) = tmp
37+ end block
38+ end do
39+ end do
40+ end subroutine
41+
42+ ! CHECK: | SubroutineStmt
43+ ! CHECK-NEXT: | | Name = 'loose_block'
44+ subroutine loose_block
45+ integer :: x(10 , 10 )
46+ integer :: tmp
47+ do i = 1 , 10
48+ do j = 1 ,10
49+ ! CHECK: OpenMPConstruct -> OpenMPBlockConstruct
50+ ! CHECK-NEXT: | OmpBeginDirective
51+ ! CHECK-NEXT: | | OmpDirectiveName -> llvm::omp::Directive = ordered
52+ ! CHECK-NEXT: | | OmpClauseList ->
53+ ! CHECK-NEXT: | | Flags = None
54+ ! $omp ordered
55+ tmp = i + j
56+ x(i, j) = tmp
57+ ! $omp end ordered
58+ end do
59+ end do
60+ end subroutine
Original file line number Diff line number Diff line change 1+ ! RUN: %python %S/../test_errors.py %s %flang -fopenmp
2+
3+ ! Test that we can diagnose missing end directives without an explosion of errors
4+
5+ ! ERROR: Expected OpenMP end directive
6+ ! $omp parallel
7+ ! ERROR: Expected OpenMP end directive
8+ ! $omp task
9+ ! ERROR: Expected OpenMP end directive
10+ ! $omp parallel
11+ ! ERROR: Expected OpenMP end directive
12+ ! $omp task
13+ end
You can’t perform that action at this time.
0 commit comments