================
@@ -7938,46 +7985,107 @@ void SemaOpenMP::ActOnOpenMPDeclareVariantDirective(
     }
   }
 
-  // OpenMP 5.1 [2.3.5, declare variant directive, Restrictions]
-  // Each argument can only appear in a single adjust_args clause for each
-  // declare variant directive.
-  llvm::SmallPtrSet<const VarDecl *, 4> AdjustVars;
+  // OpenMP 6.0 [5.2.1]: each parameter list item may be specified only once
+  // per directive. The subject is the item, so a range is exempt and a name
+  // does not collide with a position that resolves to the same parameter.
+  llvm::SmallPtrSet<const VarDecl *, 4> AdjustVars; // named items
+  llvm::SmallSet<uint64_t, 4> AdjustPositions;      // literal positional items
 
-  for (Expr *E : AllAdjustArgs) {
-    E = E->IgnoreParenImpCasts();
-    if (const auto *DRE = dyn_cast<DeclRefExpr>(E)) {
-      if (const auto *PVD = dyn_cast<ParmVarDecl>(DRE->getDecl())) {
-        const VarDecl *CanonPVD = PVD->getCanonicalDecl();
-        if (FD->getNumParams() > PVD->getFunctionScopeIndex() &&
-            FD->getParamDecl(PVD->getFunctionScopeIndex())
-                    ->getCanonicalDecl() == CanonPVD) {
-          // It's a parameter of the function, check duplicates.
-          if (!AdjustVars.insert(CanonPVD).second) {
-            Diag(DRE->getLocation(), diag::err_omp_adjust_arg_multiple_clauses)
-                << PVD;
+  for (const OMPAdjustArgsClause *Clause : AdjustArgs) {
+    for (const OMPAdjustArgsItem &ItemInfo : Clause->items()) {
+      // OpenMP 6.0 [5.2.1]: a parameter range 'lb:ub'. A range is
+      // exempt from the duplicate restriction above — it is one item
+      // identifying one or more parameters — so nothing is recorded for
+      // dedup.
+      if (ItemInfo.Kind == OMPAdjustArgsItem::Range) {
+        if (!checkOMPAdjustArgsRange(*this, ItemInfo))
+          return;
+        continue;
+      }
+
+      assert(ItemInfo.E && "expected an adjust_args expression");
+      Expr *Item = ItemInfo.E->IgnoreParenImpCasts();
+
+      // A named parameter list item — unchanged from OpenMP 5.1.
+      if (const auto *DRE = dyn_cast<DeclRefExpr>(Item)) {
+        if (const auto *PVD = dyn_cast<ParmVarDecl>(DRE->getDecl())) {
+          const VarDecl *CanonPVD = PVD->getCanonicalDecl();
+          if (FD->getNumParams() > PVD->getFunctionScopeIndex() &&
+              FD->getParamDecl(PVD->getFunctionScopeIndex())
+                      ->getCanonicalDecl() == CanonPVD) {
+            if (!AdjustVars.insert(CanonPVD).second) {
+              Diag(DRE->getLocation(),
+                   diag::err_omp_adjust_arg_multiple_clauses)
+                  << PVD;
+              return;
+            }
+            continue;
+          }
+        }
+      }
+
+      if (getLangOpts().OpenMP < 60) {
+        // Anything that is not a function parameter is an error before 6.0.
+        Diag(Item->getExprLoc(), diag::err_omp_param_or_this_in_clause)
+            << FD << 0;
+        return;
+      }
+
+      // OpenMP 6.0 [5.2.1]: the position of a parameter, given as a
+      // positive constant integer expression. A dependent item is skipped
+      // here and rechecked when the template is instantiated.
+      if (Item->isTypeDependent() || Item->getType()->isIntegerType()) {
+        llvm::APSInt Pos;
+        switch (checkOMPAdjustArgsValue(*this, Item,
+                                        /*StrictlyPositive=*/true, Pos)) {
+        case OMPAdjustArgsVal::Invalid:
+          return;
+        case OMPAdjustArgsVal::Dependent:
+          continue;
+        case OMPAdjustArgsVal::Known:
+          if (!AdjustPositions.insert(Pos.getZExtValue()).second) {
+            Diag(Item->getExprLoc(), diag::err_omp_adjust_arg_multiple_clauses)
+                << Pos;
             return;
           }
           continue;
         }
       }
+
+      // Not a name or a position: neither form OpenMP 6.0 allows for a
+      // non-range item.
+      Diag(Item->getExprLoc(), diag::err_omp_adjust_args_invalid_item);
+      return;
     }
-    // Anything that is not a function parameter is an error.
-    Diag(E->getExprLoc(), diag::err_omp_param_or_this_in_clause) << FD << 0;
-    return;
   }
 
-  // OpenMP 6.0 [9.6.2 (page 332, line 31-33, adjust_args clause, Restrictions]
-  // If the `need_device_addr` adjust-op modifier is present, each list item
-  // that appears in the clause must refer to an argument in the declaration of
-  // the function variant that has a reference type
+  // OpenMP 6.0 [9.6.2]: if the need_device_addr adjust-op modifier
+  // is present, each list item that appears in the clause must refer to an
+  // argument in the declaration of the function variant that has a reference
+  // type. Unlike the need_device_ptr restriction, this one is not scoped to
+  // named items ("that refers to a specific named argument" is absent here),
+  // so positions and ranges are checked too, via the shared item-to-positions
+  // resolver.
   if (getLangOpts().OpenMP >= 60) {
-    for (Expr *E : AdjustArgsNeedDeviceAddr) {
-      E = E->IgnoreParenImpCasts();
-      if (const auto *DRE = dyn_cast<DeclRefExpr>(E)) {
-        if (const auto *VD = dyn_cast<VarDecl>(DRE->getDecl())) {
-          if (!VD->getType()->isReferenceType())
-            Diag(E->getExprLoc(),
+    for (const OMPAdjustArgsClause *Clause : AdjustArgs) {
+      if (Clause->AdjustOp != OMPC_ADJUST_ARGS_need_device_addr)
+        continue;
+      for (const OMPAdjustArgsItem &Item : Clause->items()) {
+        SmallVector<unsigned, 8> Positions;
+        // With no call site in hand, 'omp_num_args' is the declared parameter
+        // count (OpenMP 6.0 [20.1]). Positions past it denote variadic
+        // actuals, which have no declared parameter to check against, and are
+        // dropped by the resolver (OpenMP 6.0 [9.6.2]).
+        resolveOMPAdjustArgsItem(Item, FD, FD->getNumParams(), getASTContext(),
+                                 Positions);
+        for (unsigned Pos : Positions) {
+          if (!FD->getParamDecl(Pos - 1)->getType()->isReferenceType()) {
----------------
alexey-bataev wrote:

```suggestion
          QualType ParamTy = FD->getParamDecl(Pos - 1)->getType();
          if (ParamTy->isReferenceType() || ParamTy->isDependentType())
            continue;
```

https://github.com/llvm/llvm-project/pull/225081
_______________________________________________
cfe-commits mailing list
[email protected]
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits

Reply via email to