Index: flang/lib/Semantics/check-omp-structure.h =================================================================== --- flang/lib/Semantics/check-omp-structure.h +++ flang/lib/Semantics/check-omp-structure.h @@ -225,6 +225,7 @@ void CheckCycleConstraints(const parser::OpenMPLoopConstruct &x); void CheckDistLinear(const parser::OpenMPLoopConstruct &x); void CheckSIMDNest(const parser::OpenMPConstruct &x); + void CheckTARGETNest(const parser::OpenMPConstruct &x); std::int64_t GetOrdCollapseLevel(const parser::OpenMPLoopConstruct &x); void CheckIfDoOrderedClause(const parser::OmpBlockDirective &blkDirectiv); bool CheckReductionOperators(const parser::OmpClause::Reduction &); Index: flang/lib/Semantics/check-omp-structure.cpp =================================================================== --- flang/lib/Semantics/check-omp-structure.cpp +++ flang/lib/Semantics/check-omp-structure.cpp @@ -288,6 +288,9 @@ if (GetSIMDNest() > 0) { CheckSIMDNest(x); } + if (GetContext().directive == llvm::omp::Directive::OMPD_target) { + CheckTARGETNest(x); + } } } @@ -473,6 +476,51 @@ } } +void OmpStructureChecker::CheckTARGETNest(const parser::OpenMPConstruct &c) { + // 2.12.5 Target Construct Restriction + bool eligibleTARGET{false}; + llvm::omp::Directive directive; + std::visit( + common::visitors{ + [&](const parser::OpenMPBlockConstruct &c) { + const auto &beginBlockDir{ + std::get(c.t)}; + const auto &beginDir{ + std::get(beginBlockDir.t)}; + if (beginDir.v == llvm::omp::Directive::OMPD_target_data) { + eligibleTARGET = true; + directive = beginDir.v; + } + }, + [&](const parser::OpenMPStandaloneConstruct &c) { + std::visit( + common::visitors{ + [&](const parser::OpenMPSimpleStandaloneConstruct &c) { + const auto &dir{ + std::get(c.t)}; + if (dir.v == llvm::omp::Directive::OMPD_target_update || + dir.v == + llvm::omp::Directive::OMPD_target_enter_data || + dir.v == + llvm::omp::Directive::OMPD_target_exit_data) { + eligibleTARGET = true; + directive = dir.v; + } + }, + [&](const auto &c) {}, + }, + c.u); + }, + [&](const auto &c) {}, + }, + c.u); + if (eligibleTARGET) { + context_.Say(parser::FindSourceLocation(c), + "%s directive cannot be nested inside TARGET region"_err_en_US, + parser::ToUpperCaseLetters(getDirectiveName(directive).str())); + } +} + std::int64_t OmpStructureChecker::GetOrdCollapseLevel( const parser::OpenMPLoopConstruct &x) { const auto &beginLoopDir{std::get(x.t)}; Index: flang/test/Semantics/omp-target01.f90 =================================================================== --- /dev/null +++ flang/test/Semantics/omp-target01.f90 @@ -0,0 +1,42 @@ +! RUN: %S/test_errors.sh %s %t %flang -fopenmp +! REQUIRES: shell + +! OpenMP Version 5.0 +! Check OpenMP clause validity for the following directives: +! 2.12.5 Target Construct + +program main + integer :: i, j, N = 10 + real :: a, arrayA(512), arrayB(512), ai(10) + real, allocatable :: B(:) + + !$omp target + !ERROR: TARGET UPDATE directive cannot be nested inside TARGET region + !$omp target update from(arrayA) to(arrayB) + do i = 1, 512 + arrayA(i) = arrayB(i) + end do + !$omp end target + + !$omp target + !ERROR: TARGET DATA directive cannot be nested inside TARGET region + !$omp target data map(to: a) + do i = 1, N + a = 3.14 + end do + !$omp end target data + !$omp end target + + allocate(B(N)) + !$omp target + !ERROR: TARGET ENTER DATA directive cannot be nested inside TARGET region + !$omp target enter data map(alloc:B) + !$omp end target + + !$omp target + !ERROR: TARGET EXIT DATA directive cannot be nested inside TARGET region + !$omp target exit data map(delete:B) + !$omp end target + deallocate(B) + +end program main