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 {
1484
1484
[](auto &&s) { return OmpEndDirective(std::move(s)); })};
1485
1485
} else if (auto &&body{
1486
1486
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;
1491
1498
}
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)); })};
1492
1506
}
1493
1507
}
1494
1508
return std::nullopt;
Original file line number Diff line number Diff line change @@ -843,6 +843,30 @@ void OmpStructureChecker::Enter(const parser::OpenMPBlockConstruct &x) {
843
843
const parser::Block &block{std::get<parser::Block>(x.t )};
844
844
845
845
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
+
846
870
if (llvm::omp::allTargetSet.test (GetContext ().directive )) {
847
871
EnterDirectiveNest (TargetNest);
848
872
}
Original file line number Diff line number Diff line change 1
1
! RUN: not %flang_fc1 -fsyntax-only -fopenmp %s 2>&1 | FileCheck %s
2
2
3
3
! $omp parallel
4
- ! CHECK: error: expected '!$OMP '
4
+ ! CHECK: error: Expected OpenMP end directive
5
5
end
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