[OpenMP] Prevent nesting of target constructs within target code execution regions.

Summary:
This patch enhances Sema to check for the following restriction:

OpenMP 4.5 [2.17 Nesting of Regions]
If a target, target update, target data, target enter data, or
target exit data construct is encountered during execution of a
target region, the behavior is unspecified.

Reviewers: ABataev

Differential Revision: http://reviews.llvm.org/D16758

llvm-svn: 259464
diff --git a/clang/lib/Sema/SemaOpenMP.cpp b/clang/lib/Sema/SemaOpenMP.cpp
index 5777723..1300de1 100644
--- a/clang/lib/Sema/SemaOpenMP.cpp
+++ b/clang/lib/Sema/SemaOpenMP.cpp
@@ -809,7 +809,7 @@
   auto DKind = DSAStack->getDirectiveForScope(RSI->TheScope);
   auto Ty = D->getType();
 
-  if (isOpenMPTargetDirective(DKind)) {
+  if (isOpenMPTargetExecutionDirective(DKind)) {
     // This table summarizes how a given variable should be passed to the device
     // given its type and the clauses where it appears. This table is based on
     // the description in OpenMP 4.5 [2.10.4, target Construct] and
@@ -907,7 +907,7 @@
         DSAStack->hasDirective(
             [](OpenMPDirectiveKind K, const DeclarationNameInfo &DNI,
                SourceLocation Loc) -> bool {
-              return isOpenMPTargetDirective(K);
+              return isOpenMPTargetExecutionDirective(K);
             },
             false)) {
       return true;
@@ -944,7 +944,8 @@
 
   auto *VD = dyn_cast<VarDecl>(D);
   return VD && !VD->hasLocalStorage() &&
-         DSAStack->hasExplicitDirective(isOpenMPTargetDirective, Level);
+         DSAStack->hasExplicitDirective(isOpenMPTargetExecutionDirective,
+                                        Level);
 }
 
 void Sema::DestroyDataSharingAttributesStack() { delete DSAStack; }
@@ -2313,11 +2314,11 @@
   // | target           | flush           | *                                  |
   // | target           | ordered         | *                                  |
   // | target           | atomic          | *                                  |
-  // | target           | target          | *                                  |
-  // | target           | target parallel | *                                  |
-  // | target           | target enter    | *                                  |
+  // | target           | target          |                                    |
+  // | target           | target parallel |                                    |
+  // | target           | target enter    |                                    |
   // |                  | data            |                                    |
-  // | target           | target exit     | *                                  |
+  // | target           | target exit     |                                    |
   // |                  | data            |                                    |
   // | target           | teams           | *                                  |
   // | target           | cancellation    |                                    |
@@ -2347,11 +2348,11 @@
   // | target parallel  | flush           | *                                  |
   // | target parallel  | ordered         | *                                  |
   // | target parallel  | atomic          | *                                  |
-  // | target parallel  | target          | *                                  |
-  // | target parallel  | target parallel | *                                  |
-  // | target parallel  | target enter    | *                                  |
+  // | target parallel  | target          |                                    |
+  // | target parallel  | target parallel |                                    |
+  // | target parallel  | target enter    |                                    |
   // |                  | data            |                                    |
-  // | target parallel  | target exit     | *                                  |
+  // | target parallel  | target exit     |                                    |
   // |                  | data            |                                    |
   // | target parallel  | teams           |                                    |
   // | target parallel  | cancellation    |                                    |
@@ -2498,6 +2499,7 @@
   // +------------------+-----------------+------------------------------------+
   if (Stack->getCurScope()) {
     auto ParentRegion = Stack->getParentDirective();
+    auto OffendingRegion = ParentRegion;
     bool NestingProhibited = false;
     bool CloseNesting = true;
     enum {
@@ -2658,10 +2660,30 @@
       NestingProhibited = !isOpenMPTeamsDirective(ParentRegion);
       Recommend = ShouldBeInTeamsRegion;
     }
+    if (!NestingProhibited &&
+        (isOpenMPTargetExecutionDirective(CurrentRegion) ||
+         isOpenMPTargetDataManagementDirective(CurrentRegion))) {
+      // OpenMP 4.5 [2.17 Nesting of Regions]
+      // If a target, target update, target data, target enter data, or
+      // target exit data construct is encountered during execution of a
+      // target region, the behavior is unspecified.
+      NestingProhibited = Stack->hasDirective(
+          [&OffendingRegion](OpenMPDirectiveKind K,
+                             const DeclarationNameInfo &DNI,
+                             SourceLocation Loc) -> bool {
+            if (isOpenMPTargetExecutionDirective(K)) {
+              OffendingRegion = K;
+              return true;
+            } else
+              return false;
+          },
+          false /* don't skip top directive */);
+      CloseNesting = false;
+    }
     if (NestingProhibited) {
       SemaRef.Diag(StartLoc, diag::err_omp_prohibited_region)
-          << CloseNesting << getOpenMPDirectiveName(ParentRegion) << Recommend
-          << getOpenMPDirectiveName(CurrentRegion);
+          << CloseNesting << getOpenMPDirectiveName(OffendingRegion)
+          << Recommend << getOpenMPDirectiveName(CurrentRegion);
       return true;
     }
   }