Skip to content

Conversation

@bhandarkar-pranav
Copy link
Contributor

This patch enhances the semantics test for checking that teams directives are strictly nested inside target directives.

Fixes #153173

This patch enhances the semantics test for checking that teams directives
are strictly nested inside target directives.
@llvmbot llvmbot added flang Flang issues not falling into any other category flang:openmp flang:semantics labels Nov 17, 2025
@llvmbot
Copy link
Member

llvmbot commented Nov 17, 2025

@llvm/pr-subscribers-flang-openmp

@llvm/pr-subscribers-flang-semantics

Author: Pranav Bhandarkar (bhandarkar-pranav)

Changes

This patch enhances the semantics test for checking that teams directives are strictly nested inside target directives.

Fixes #153173


Full diff: https://github.com/llvm/llvm-project/pull/168437.diff

3 Files Affected:

  • (modified) flang/lib/Semantics/check-omp-loop.cpp (+9)
  • (modified) flang/lib/Semantics/check-omp-structure.cpp (+7)
  • (added) flang/test/Semantics/OpenMP/target-teams-nesting.f90 (+22)
diff --git a/flang/lib/Semantics/check-omp-loop.cpp b/flang/lib/Semantics/check-omp-loop.cpp
index aaaa2d6e78280..09005e3076d03 100644
--- a/flang/lib/Semantics/check-omp-loop.cpp
+++ b/flang/lib/Semantics/check-omp-loop.cpp
@@ -262,6 +262,15 @@ void OmpStructureChecker::Enter(const parser::OpenMPLoopConstruct &x) {
     EnterDirectiveNest(SIMDNest);
   }
 
+  if (CurrentDirectiveIsNested() &&
+      llvm::omp::allTeamsSet.test(GetContext().directive) &&
+      GetContextParent().directive == llvm::omp::Directive::OMPD_target &&
+      !GetDirectiveNest(TargetBlockOnlyTeams)) {
+    context_.Say(GetContextParent().directiveSource,
+        "TARGET construct with nested TEAMS region contains statements or "
+        "directives outside of the TEAMS construct"_err_en_US);
+  }
+
   // Combined target loop constructs are target device constructs. Keep track of
   // whether any such construct has been visited to later check that REQUIRES
   // directives for target-related options don't appear after them.
diff --git a/flang/lib/Semantics/check-omp-structure.cpp b/flang/lib/Semantics/check-omp-structure.cpp
index 37b4404cc598f..472208949abad 100644
--- a/flang/lib/Semantics/check-omp-structure.cpp
+++ b/flang/lib/Semantics/check-omp-structure.cpp
@@ -5215,6 +5215,13 @@ bool OmpStructureChecker::CheckTargetBlockOnlyTeams(
         if (dirId == llvm::omp::Directive::OMPD_teams) {
           nestedTeams = true;
         }
+      } else if (const auto *ompLoopConstruct{
+                     std::get_if<parser::OpenMPLoopConstruct>(
+                         &ompConstruct->u)}) {
+        llvm::omp::Directive dirId{ompLoopConstruct->BeginDir().DirId()};
+        if (llvm::omp::allTeamsSet.test(dirId)) {
+          nestedTeams = true;
+        }
       }
     }
 
diff --git a/flang/test/Semantics/OpenMP/target-teams-nesting.f90 b/flang/test/Semantics/OpenMP/target-teams-nesting.f90
new file mode 100644
index 0000000000000..59786d4f9e397
--- /dev/null
+++ b/flang/test/Semantics/OpenMP/target-teams-nesting.f90
@@ -0,0 +1,22 @@
+! RUN: %python %S/../test_errors.py %s %flang_fc1 -fopenmp
+
+program main
+  implicit none
+  integer, parameter :: n = 100
+  integer, parameter :: expected = n+2
+  integer :: i
+  integer :: counter
+
+  counter = 0
+  !ERROR: TARGET construct with nested TEAMS region contains statements or directives outside of the TEAMS construct
+  !$omp target map(tofrom:counter)
+  counter = counter+1
+  !$omp teams distribute reduction(+:counter)
+  do i=1, n
+     counter = counter+1
+  end do
+  counter = counter+1
+  !$omp end target
+
+  print '("Result: "I0)', counter
+ end program

@github-actions
Copy link

github-actions bot commented Nov 17, 2025

🐧 Linux x64 Test Results

  • 4064 tests passed
  • 202 tests skipped

counter = counter+1
!$omp end target

print '("Result: "I0)', counter
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

nit: no need for the print statement here.

Comment on lines +265 to +268
if (CurrentDirectiveIsNested() &&
llvm::omp::topTeamsSet.test(GetContext().directive) &&
GetContextParent().directive == llvm::omp::Directive::OMPD_target &&
!GetDirectiveNest(TargetBlockOnlyTeams)) {
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Not exactly relevant to this PR since a similar check is used somewhere else. But for the following example:

!$omp target ....
  !$omp teams ....
    !$omp target ....
      .... some statement ....
      !$omp teams ....
        ....
....

Would the semantic check trigger in this case? I think it won't since GetDirectiveNest(TargetBlockOnlyTeams) will return a non-zero result.

Copy link
Contributor Author

@bhandarkar-pranav bhandarkar-pranav Nov 20, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I coudn't nest a target directive inside the teams directive because that is not allowed, but I did the following

 !$omp target map(tofrom:counter)
   !$omp teams
    !$omp parallel
      !$omp target
        ... some stmt...
       !$omp teams
        .... a structured block...
       !$omp end teams    
      !$omp end target
    !$omp end parallel
   !$omp end teams
  !$omp end target

This compiled fine but it shouldn't have for the reason you mentioned. Strangely enough, gfortran also accepts the code above, only warning about reverse-offloading. I am torn between spending time fixing it on the one hand while on the other hand letting what seems to be an obscure case slide.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

flang:openmp flang:semantics flang Flang issues not falling into any other category

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Missing Flang semantics check causes ICE

3 participants