[flang-commits] [flang] [llvm] [Flang][OpenMP] Implement variable-category for default clause (OMP 6.0) (PR #223476)

Phoebe Linck via flang-commits flang-commits at lists.llvm.org
Mon Sep 14 10:52:47 PDT 2026


https://github.com/phi-bee created https://github.com/llvm/llvm-project/pull/223476

Implements the `variable-category` modifier for the `default` clause, a feature introduced in OpenMP 6.0.

>From 42170e41664e04fa46b0075da4167df0c20c1a84 Mon Sep 17 00:00:00 2001
From: Phoebe Linck <phoebe.linck at hpe.com>
Date: Fri, 14 Aug 2026 17:17:08 -0500
Subject: [PATCH] [Flang][OpenMP] Implement variable-category for default
 clause (OMP 6.0)

---
 flang/include/flang/Parser/dump-parse-tree.h  |   1 +
 flang/include/flang/Parser/parse-tree.h       |   6 +-
 flang/include/flang/Semantics/openmp-utils.h  |   8 ++
 flang/lib/Lower/OpenMP/Clauses.cpp            |  21 ++-
 .../lib/Lower/OpenMP/DataSharingProcessor.cpp |  67 ++++++++-
 flang/lib/Parser/openmp-parsers.cpp           |   6 +-
 flang/lib/Semantics/check-omp-structure.cpp   |  21 +++
 flang/lib/Semantics/check-omp-structure.h     |   1 +
 flang/lib/Semantics/check-omp-variant.cpp     |   3 +-
 flang/lib/Semantics/openmp-utils.cpp          |  61 +++++++++
 flang/lib/Semantics/resolve-directives.cpp    | 128 +++++++-----------
 .../Semantics/OpenMP/default-category.f90     |  14 ++
 .../OpenMP/default-none-category.f90          |  53 ++++++++
 llvm/include/llvm/Frontend/OpenMP/ClauseT.h   |   5 +-
 14 files changed, 301 insertions(+), 94 deletions(-)
 create mode 100644 flang/test/Semantics/OpenMP/default-category.f90
 create mode 100644 flang/test/Semantics/OpenMP/default-none-category.f90

diff --git a/flang/include/flang/Parser/dump-parse-tree.h b/flang/include/flang/Parser/dump-parse-tree.h
index 3b4d467f14345..2758ea64d4306 100644
--- a/flang/include/flang/Parser/dump-parse-tree.h
+++ b/flang/include/flang/Parser/dump-parse-tree.h
@@ -602,6 +602,7 @@ class ParseTreeDumper {
   NODE(parser, OmpDeclareVariantDirective)
   NODE(parser, OmpDefaultClause)
   NODE_ENUM(OmpDefaultClause, DataSharingAttribute)
+  NODE(OmpDefaultClause, Modifier)
   NODE(parser, OmpDefaultmapClause)
   NODE(parser, OmpDefaultVariantClause)
   NODE(OmpDefaultmapClause, Modifier)
diff --git a/flang/include/flang/Parser/parse-tree.h b/flang/include/flang/Parser/parse-tree.h
index 3e9a035d0bfee..06146cbc6a8cc 100644
--- a/flang/include/flang/Parser/parse-tree.h
+++ b/flang/include/flang/Parser/parse-tree.h
@@ -4604,8 +4604,10 @@ struct OmpApplyClause {
 //    SHARED | NONE |                               // since 4.5
 //    PRIVATE | FIRSTPRIVATE                        // since 5.0
 struct OmpDefaultClause {
-  ENUM_CLASS(DataSharingAttribute, Private, Firstprivate, Shared, None)
-  WRAPPER_CLASS_BOILERPLATE(OmpDefaultClause, DataSharingAttribute);
+  ENUM_CLASS(DataSharingAttribute, Private, Firstprivate, Shared, None);
+  TUPLE_CLASS_BOILERPLATE(OmpDefaultClause);
+  MODIFIER_BOILERPLATE(OmpVariableCategory);
+  std::tuple<DataSharingAttribute, MODIFIERS()> t;
 };
 
 // Ref: [4.5:103-107], [5.0:324-325], [5.1:357-358], [5.2:161-162]
diff --git a/flang/include/flang/Semantics/openmp-utils.h b/flang/include/flang/Semantics/openmp-utils.h
index 769140a3147ed..4973a4599d5e2 100644
--- a/flang/include/flang/Semantics/openmp-utils.h
+++ b/flang/include/flang/Semantics/openmp-utils.h
@@ -48,6 +48,14 @@ using Fortran::parser::omp::is_range_v;
 using Fortran::parser::omp::LoopNestIterator;
 using Fortran::parser::omp::LoopRange;
 
+bool DefaultMapCategoryMatchesSymbol(
+    parser::OmpVariableCategory::Value category, const Symbol &symbol);
+
+bool IsOpenMPPointer(const Symbol &symbol);
+
+bool IsOpenMPAggregate(const Symbol &symbol);
+bool IsOpenMPScalar(const Symbol &symbol);
+
 template <typename T, typename U = std::remove_const_t<T>> U AsRvalue(T &t) {
   return U(t);
 }
diff --git a/flang/lib/Lower/OpenMP/Clauses.cpp b/flang/lib/Lower/OpenMP/Clauses.cpp
index ee16ae55af30f..4933b53a4a946 100644
--- a/flang/lib/Lower/OpenMP/Clauses.cpp
+++ b/flang/lib/Lower/OpenMP/Clauses.cpp
@@ -661,7 +661,7 @@ Default make(const parser::OmpClause::Default &inp,
   using wrapped = parser::OmpDefaultClause;
 
   CLAUSET_ENUM_CONVERT( //
-      convert, wrapped::DataSharingAttribute, Default::DataSharingAttribute,
+      convert1, wrapped::DataSharingAttribute, Default::DataSharingAttribute,
       // clang-format off
       MS(Firstprivate, Firstprivate)
       MS(None,         None)
@@ -670,7 +670,24 @@ Default make(const parser::OmpClause::Default &inp,
       // clang-format on
   );
 
-  return Default{/*DataSharingAttribute=*/convert(inp.v.v)};
+  CLAUSET_ENUM_CONVERT( //
+      convert2, parser::OmpVariableCategory::Value, Default::VariableCategory,
+      // clang-format off
+        MS(Aggregate,    Aggregate)
+        MS(All,          All)
+        MS(Allocatable,  Allocatable)
+        MS(Pointer,      Pointer)
+        MS(Scalar,       Scalar)
+      // clang-format on
+  );
+
+  auto &mods = semantics::OmpGetModifiers(inp.v);
+  auto &t0 = std::get<wrapped::DataSharingAttribute>(inp.v.t);
+  auto *t1 = semantics::OmpGetUniqueModifier<parser::OmpVariableCategory>(mods);
+
+  auto category = t1 ? convert2(t1->v) : Default::VariableCategory::All;
+
+  return Default{/*DataSharingAttribute=*/{convert1(t0), category}};
 }
 
 // Lower the DefaultVariant (specific to OpenMP 5.0 and 5.1) directly to
diff --git a/flang/lib/Lower/OpenMP/DataSharingProcessor.cpp b/flang/lib/Lower/OpenMP/DataSharingProcessor.cpp
index 8d0d191058cfb..d9ff057f0e69c 100644
--- a/flang/lib/Lower/OpenMP/DataSharingProcessor.cpp
+++ b/flang/lib/Lower/OpenMP/DataSharingProcessor.cpp
@@ -684,14 +684,71 @@ void DataSharingProcessor::collectSymbols(
 
 void DataSharingProcessor::collectDefaultSymbols() {
   using DataSharingAttribute = omp::clause::Default::DataSharingAttribute;
+  using VariableCategory = omp::clause::Default::VariableCategory;
   for (const omp::Clause &clause : clauses) {
     if (const auto *defaultClause =
             std::get_if<omp::clause::Default>(&clause.u)) {
-      if (defaultClause->v == DataSharingAttribute::Private)
-        collectSymbols(semantics::Symbol::Flag::OmpPrivate, &defaultSymbols);
-      else if (defaultClause->v == DataSharingAttribute::Firstprivate)
-        collectSymbols(semantics::Symbol::Flag::OmpFirstPrivate,
-                       &defaultSymbols);
+      auto &dsa{std::get<DataSharingAttribute>(defaultClause->t)};
+      auto &varcat{std::get<1>(defaultClause->t)};
+
+      llvm::SetVector<const semantics::Symbol *> allSymbols;
+      semantics::Symbol::Flag flag;
+      if (dsa == DataSharingAttribute::Private) {
+        flag = semantics::Symbol::Flag::OmpPrivate;
+        converter.collectSymbolSet(eval, allSymbols,
+                                   semantics::Symbol::Flag::OmpPrivate,
+                                   /*collectSymbols=*/true,
+                                   /*collectHostAssociatedSymbols=*/true);
+      } else if (dsa == DataSharingAttribute::Firstprivate) {
+
+        flag = semantics::Symbol::Flag::OmpFirstPrivate;
+        converter.collectSymbolSet(eval, allSymbols,
+                                   semantics::Symbol::Flag::OmpFirstPrivate,
+                                   /*collectSymbols=*/true,
+                                   /*collectHostAssociatedSymbols=*/true);
+      }
+      if (!allSymbols.empty()) {
+        for (const auto *symbol : allSymbols) {
+          switch (varcat.value_or(VariableCategory::All)) {
+          case VariableCategory::All:
+            break;
+          case VariableCategory::Scalar:
+            if (!semantics::omp::DefaultMapCategoryMatchesSymbol(
+                    parser::OmpVariableCategory::Value::Scalar, *symbol)) {
+              allSymbols.remove(symbol);
+            }
+            break;
+          case VariableCategory::Aggregate:
+            if (!semantics::omp::DefaultMapCategoryMatchesSymbol(
+                    parser::OmpVariableCategory::Value::Aggregate, *symbol)) {
+              allSymbols.remove(symbol);
+            }
+            break;
+          case VariableCategory::Allocatable:
+            if (!semantics::omp::DefaultMapCategoryMatchesSymbol(
+                    parser::OmpVariableCategory::Value::Allocatable, *symbol)) {
+              allSymbols.remove(symbol);
+            }
+            break;
+          case VariableCategory::Pointer:
+            if (!semantics::omp::DefaultMapCategoryMatchesSymbol(
+                    parser::OmpVariableCategory::Value::Pointer, *symbol)) {
+              allSymbols.remove(symbol);
+            }
+            break;
+          }
+        }
+      } else {
+        continue;
+      }
+      llvm::SetVector<const semantics::Symbol *> symbolsInNestedRegions;
+      collectSymbolsInNestedRegions(eval, flag, symbolsInNestedRegions);
+      for (auto *symbol : allSymbols) {
+        if (visitor.isSymbolDefineBy(symbol, eval)) {
+          symbolsInNestedRegions.remove(symbol);
+        }
+      }
+      collectPrivatizedSymbols(flag, allSymbols, symbolsInNestedRegions);
     }
   }
 }
diff --git a/flang/lib/Parser/openmp-parsers.cpp b/flang/lib/Parser/openmp-parsers.cpp
index 5e80af0cfc634..9a0436ca32cce 100644
--- a/flang/lib/Parser/openmp-parsers.cpp
+++ b/flang/lib/Parser/openmp-parsers.cpp
@@ -1114,6 +1114,9 @@ TYPE_PARSER(sourced(
 TYPE_PARSER(
     sourced(construct<OmpDoacross::Modifier>(Parser<OmpDependenceType>{})))
 
+TYPE_PARSER(sourced(
+    construct<OmpDefaultClause::Modifier>(Parser<OmpVariableCategory>{})))
+
 TYPE_PARSER(sourced( //
     construct<OmpDependClause::TaskDep::Modifier>(Parser<OmpIterator>{}) ||
     construct<OmpDependClause::TaskDep::Modifier>(
@@ -1340,7 +1343,8 @@ TYPE_PARSER(construct<OmpDefaultClause::DataSharingAttribute>(
     "NONE" >> pure(OmpDefaultClause::DataSharingAttribute::None)))
 
 TYPE_PARSER(construct<OmpDefaultClause>(
-    Parser<OmpDefaultClause::DataSharingAttribute>{}))
+    Parser<OmpDefaultClause::DataSharingAttribute>{},
+    maybe(":" >> nonemptyList(Parser<OmpDefaultClause::Modifier>{}))))
 
 TYPE_PARSER(construct<OmpDefaultVariantClause>(
     indirect(OmpDirectiveSpecificationParser(/*allowCommas=*/false))))
diff --git a/flang/lib/Semantics/check-omp-structure.cpp b/flang/lib/Semantics/check-omp-structure.cpp
index dffece95796cc..68e4ec4216cc4 100644
--- a/flang/lib/Semantics/check-omp-structure.cpp
+++ b/flang/lib/Semantics/check-omp-structure.cpp
@@ -4598,6 +4598,27 @@ void OmpStructureChecker::Enter(const parser::OmpClause::Aligned &x) {
   // 2.8.1 TODO: list-item attribute check
 }
 
+void OmpStructureChecker::Enter(const parser::OmpClause::Default &x) {
+  llvm::omp::Version version{context_.langOptions().getOpenMPVersion()};
+  auto &modifiers{OmpGetModifiers(x.v)};
+  auto *maybeCategory{
+      OmpGetUniqueModifier<parser::OmpVariableCategory>(modifiers)};
+  if (maybeCategory) {
+    using VariableCategory = parser::OmpVariableCategory;
+    VariableCategory::Value category{maybeCategory->v};
+    llvm::omp::Version tryVersion;
+    if (version < 60) {
+      tryVersion = llvm::omp::Version(60);
+    }
+    if (tryVersion) {
+      context_.Say(GetContext().clauseSource,
+          "%s is not allowed in %s, %s"_warn_en_US,
+          parser::ToUpperCaseLetters(VariableCategory::EnumToString(category)),
+          ThisVersion(version), TryVersion(tryVersion));
+    }
+  }
+}
+
 void OmpStructureChecker::Enter(const parser::OmpClause::Defaultmap &x) {
   llvm::omp::Version version{context_.langOptions().getOpenMPVersion()};
   using ImplicitBehavior = parser::OmpDefaultmapClause::ImplicitBehavior;
diff --git a/flang/lib/Semantics/check-omp-structure.h b/flang/lib/Semantics/check-omp-structure.h
index 41b866337c4f1..ec0d05715399d 100644
--- a/flang/lib/Semantics/check-omp-structure.h
+++ b/flang/lib/Semantics/check-omp-structure.h
@@ -211,6 +211,7 @@ class OmpStructureChecker : public OmpStructureCheckerBase {
   void Enter(const parser::OmpClause::Collapse &x);
   void Enter(const parser::OmpClause::Copyin &x);
   void Enter(const parser::OmpClause::Copyprivate &x);
+  void Enter(const parser::OmpClause::Default &x);
   void Enter(const parser::OmpClause::Defaultmap &x);
   void Enter(const parser::OmpClause::Depend &x);
   void Enter(const parser::OmpClause::Depth &x);
diff --git a/flang/lib/Semantics/check-omp-variant.cpp b/flang/lib/Semantics/check-omp-variant.cpp
index 5526b5cc3d08a..09a0b8058d72b 100644
--- a/flang/lib/Semantics/check-omp-variant.cpp
+++ b/flang/lib/Semantics/check-omp-variant.cpp
@@ -54,7 +54,8 @@ bool HasDefaultNone(const parser::OmpDirectiveSpecification &spec) {
     return false;
   }
   const auto &defaultClause{std::get<parser::OmpClause::Default>(clause->u)};
-  return defaultClause.v.v == DataSharingAttribute::None;
+  return std::get<DataSharingAttribute>(defaultClause.v.t) ==
+      DataSharingAttribute::None;
 }
 
 bool HasNestedPrivateDSA(const Symbol &symbol, const Scope &scope) {
diff --git a/flang/lib/Semantics/openmp-utils.cpp b/flang/lib/Semantics/openmp-utils.cpp
index a341cf4fa1706..d37f762680ae6 100644
--- a/flang/lib/Semantics/openmp-utils.cpp
+++ b/flang/lib/Semantics/openmp-utils.cpp
@@ -59,6 +59,67 @@
 namespace Fortran::semantics::omp {
 using namespace Fortran::parser::omp;
 
+bool IsOpenMPPointer(const Symbol &symbol) {
+  if (IsPointer(symbol) || IsBuiltinCPtr(symbol))
+    return true;
+  return false;
+}
+
+bool IsOpenMPAggregate(const Symbol &symbol) {
+  if (IsAllocatable(symbol) || IsOpenMPPointer(symbol))
+    return false;
+
+  const auto *type{symbol.GetType()};
+  // OpenMP categorizes Fortran characters as aggregates.
+  if (type->category() == Fortran::semantics::DeclTypeSpec::Category::Character)
+    return true;
+
+  if (const auto *det{symbol.GetUltimate()
+              .detailsIf<Fortran::semantics::ObjectEntityDetails>()})
+    if (det->IsArray())
+      return true;
+
+  if (type->AsDerived())
+    return true;
+
+  if (IsDeferredShape(symbol) || IsAssumedRank(symbol) ||
+      IsAssumedShape(symbol))
+    return true;
+  return false;
+}
+
+bool IsOpenMPScalar(const Symbol &symbol) {
+  if (IsOpenMPAggregate(symbol) || IsOpenMPPointer(symbol) ||
+      IsAllocatable(symbol))
+    return false;
+  const auto *type{symbol.GetType()};
+  if ((!symbol.GetShape() || symbol.GetShape()->empty()) &&
+      (type->category() ==
+              Fortran::semantics::DeclTypeSpec::Category::Numeric ||
+          type->category() ==
+              Fortran::semantics::DeclTypeSpec::Category::Logical))
+    return true;
+  return false;
+}
+
+bool DefaultMapCategoryMatchesSymbol(
+    parser::OmpVariableCategory::Value category, const Symbol &symbol) {
+  using VarCat = parser::OmpVariableCategory::Value;
+  switch (category) {
+  case VarCat::Scalar:
+    return IsOpenMPScalar(symbol);
+  case VarCat::Allocatable:
+    return IsAllocatable(symbol);
+  case VarCat::Aggregate:
+    return IsOpenMPAggregate(symbol);
+  case VarCat::Pointer:
+    return IsOpenMPPointer(symbol);
+  case VarCat::All:
+    return true;
+  }
+  return false;
+}
+
 const Scope &GetScopingUnit(const Scope &scope) {
   const Scope *iter{&scope};
   for (; !iter->IsTopLevel(); iter = &iter->parent()) {
diff --git a/flang/lib/Semantics/resolve-directives.cpp b/flang/lib/Semantics/resolve-directives.cpp
index 143fe385768d7..879dde5671ba1 100644
--- a/flang/lib/Semantics/resolve-directives.cpp
+++ b/flang/lib/Semantics/resolve-directives.cpp
@@ -59,7 +59,8 @@ template <typename T> class DirectiveAttributeVisitor {
     parser::CharBlock directiveSource;
     T directive;
     Scope &scope;
-    Symbol::Flag defaultDSA{Symbol::Flag::AccShared}; // TODOACC
+    std::map<parser::OmpVariableCategory::Value, Symbol::Flag> defaultDSA{
+        {parser::OmpVariableCategory::Value::All, Symbol::Flag::AccShared}};
     std::map<const Symbol *, Symbol::Flag> objectWithDSA;
     std::map<const Symbol *, Symbol::Flags> commonBlockClauseFlags;
     std::map<parser::OmpVariableCategory::Value,
@@ -105,8 +106,18 @@ template <typename T> class DirectiveAttributeVisitor {
       parser::OmpDefaultmapClause::ImplicitBehavior ImpBehav) {
     GetContext().defaultMap[VarCat] = ImpBehav;
   }
-  void SetContextDefaultDSA(Symbol::Flag flag) {
-    GetContext().defaultDSA = flag;
+  void SetContextDefaultDSA(Symbol::Flag flag,
+      parser::OmpVariableCategory::Value VarCat =
+          parser::OmpVariableCategory::Value::All) {
+    GetContext().defaultDSA = {{VarCat, flag}};
+  }
+  Symbol::Flag DefaultDSAForSymbol(
+      const DirContext &dirContext, const Symbol &symbol) {
+    for (auto defaults : dirContext.defaultDSA) {
+      if (omp::DefaultMapCategoryMatchesSymbol(defaults.first, symbol)) {
+        return defaults.second;
+      }
+    }
   }
   void AddToContextObjectWithDSA(
       const Symbol &symbol, Symbol::Flag flag, DirContext &context) {
@@ -1870,9 +1881,10 @@ void AccAttributeVisitor::Post(const parser::Name &name) {
           // adjust the symbol within the region
           // TODO: why didn't name resolution set the right name originally?
           name.symbol = found;
-        } else if (GetContext().defaultDSA == Symbol::Flag::AccNone) {
-          // 2.5.14. Pre-OpenACC-3.2 behavior: implicit scalars warn instead of
-          // error unless strict mode is enabled.
+        } else if (DefaultDSAForSymbol(GetContext(), symbol) ==
+            Symbol::Flag::AccNone) {
+          // 2.5.14. Pre-OpenACC-3.2 behavior: implicit scalars warn instead
+          // of error unless strict mode is enabled.
           if (IsAccScalar(symbol) &&
               !context_.IsEnabled(
                   common::LanguageFeature::OpenAccDefaultNoneScalarsStrict)) {
@@ -2540,20 +2552,32 @@ void OmpAttributeVisitor::Post(const parser::OmpClause::Defaultmap &x) {
 void OmpAttributeVisitor::Post(const parser::OmpDefaultClause &x) {
   // The DEFAULT clause may also be used on METADIRECTIVE. In that case
   // there is nothing to do.
+  using VariableCategory = parser::OmpVariableCategory;
   using DataSharingAttribute = parser::OmpDefaultClause::DataSharingAttribute;
+  VariableCategory::Value varCategory;
+
+  auto dsa{std::get<DataSharingAttribute>(x.t)};
+  auto &modifiers{OmpGetModifiers(x)};
+  auto *maybeCategory{
+      OmpGetUniqueModifier<parser::OmpVariableCategory>(modifiers)};
+  if (maybeCategory)
+    varCategory = maybeCategory->v;
+  else
+    varCategory = VariableCategory::Value::All;
+
   if (!dirContext_.empty()) {
-    switch (x.v) {
+    switch (dsa) {
     case DataSharingAttribute::Private:
-      SetContextDefaultDSA(Symbol::Flag::OmpPrivate);
+      SetContextDefaultDSA(Symbol::Flag::OmpPrivate, varCategory);
       break;
     case DataSharingAttribute::Firstprivate:
-      SetContextDefaultDSA(Symbol::Flag::OmpFirstPrivate);
+      SetContextDefaultDSA(Symbol::Flag::OmpFirstPrivate, varCategory);
       break;
     case DataSharingAttribute::Shared:
-      SetContextDefaultDSA(Symbol::Flag::OmpShared);
+      SetContextDefaultDSA(Symbol::Flag::OmpShared, varCategory);
       break;
     case DataSharingAttribute::None:
-      SetContextDefaultDSA(Symbol::Flag::OmpNone);
+      SetContextDefaultDSA(Symbol::Flag::OmpNone, varCategory);
       break;
     }
   }
@@ -2752,7 +2776,7 @@ void OmpAttributeVisitor::CreateImplicitSymbols(
       }
     }
     if (dsa.none() && crayPtrDSA.none() &&
-        dirContext.defaultDSA == Symbol::Flag::OmpNone) {
+        DefaultDSAForSymbol(dirContext, *symbol) == Symbol::Flag::OmpNone) {
       checkDefaultNone = true;
     }
     bool hasDefaultNoneError{false};
@@ -2825,18 +2849,19 @@ void OmpAttributeVisitor::CreateImplicitSymbols(
     //      Ideally, lowering should be changed and all implicit symbols
     //      should be marked with OmpImplicit.
 
-    if (dirContext.defaultDSA == Symbol::Flag::OmpPrivate ||
-        dirContext.defaultDSA == Symbol::Flag::OmpFirstPrivate ||
-        dirContext.defaultDSA == Symbol::Flag::OmpShared ||
-        (dirContext.defaultDSA == Symbol::Flag::OmpNone &&
+    if (DefaultDSAForSymbol(dirContext, *symbol) == Symbol::Flag::OmpPrivate ||
+        DefaultDSAForSymbol(dirContext, *symbol) ==
+            Symbol::Flag::OmpFirstPrivate ||
+        DefaultDSAForSymbol(dirContext, *symbol) == Symbol::Flag::OmpShared ||
+        (DefaultDSAForSymbol(dirContext, *symbol) == Symbol::Flag::OmpNone &&
             !hasDefaultNoneError)) {
       // 1) default
       // Allowed only with parallel, teams and task generating constructs.
       if (!parallelDir && !taskGenDir && !teamsDir) {
         return;
       }
-      dsa = {dirContext.defaultDSA};
-      if (dirContext.defaultDSA != Symbol::Flag::OmpNone) {
+      dsa = {DefaultDSAForSymbol(dirContext, *symbol)};
+      if (DefaultDSAForSymbol(dirContext, *symbol) != Symbol::Flag::OmpNone) {
         makeSymbol(dsa);
       }
       PRINT_IMPLICIT_RULE("1) default");
@@ -2890,67 +2915,6 @@ void OmpAttributeVisitor::CreateImplicitSymbols(
   }
 }
 
-static bool IsOpenMPPointer(const Symbol &symbol) {
-  if (IsPointer(symbol) || IsBuiltinCPtr(symbol))
-    return true;
-  return false;
-}
-
-static bool IsOpenMPAggregate(const Symbol &symbol) {
-  if (IsAllocatable(symbol) || IsOpenMPPointer(symbol))
-    return false;
-
-  const auto *type{symbol.GetType()};
-  // OpenMP categorizes Fortran characters as aggregates.
-  if (type->category() == Fortran::semantics::DeclTypeSpec::Category::Character)
-    return true;
-
-  if (const auto *det{symbol.GetUltimate()
-              .detailsIf<Fortran::semantics::ObjectEntityDetails>()})
-    if (det->IsArray())
-      return true;
-
-  if (type->AsDerived())
-    return true;
-
-  if (IsDeferredShape(symbol) || IsAssumedRank(symbol) ||
-      IsAssumedShape(symbol))
-    return true;
-  return false;
-}
-
-static bool IsOpenMPScalar(const Symbol &symbol) {
-  if (IsOpenMPAggregate(symbol) || IsOpenMPPointer(symbol) ||
-      IsAllocatable(symbol))
-    return false;
-  const auto *type{symbol.GetType()};
-  if ((!symbol.GetShape() || symbol.GetShape()->empty()) &&
-      (type->category() ==
-              Fortran::semantics::DeclTypeSpec::Category::Numeric ||
-          type->category() ==
-              Fortran::semantics::DeclTypeSpec::Category::Logical))
-    return true;
-  return false;
-}
-
-static bool DefaultMapCategoryMatchesSymbol(
-    parser::OmpVariableCategory::Value category, const Symbol &symbol) {
-  using VarCat = parser::OmpVariableCategory::Value;
-  switch (category) {
-  case VarCat::Scalar:
-    return IsOpenMPScalar(symbol);
-  case VarCat::Allocatable:
-    return IsAllocatable(symbol);
-  case VarCat::Aggregate:
-    return IsOpenMPAggregate(symbol);
-  case VarCat::Pointer:
-    return IsOpenMPPointer(symbol);
-  case VarCat::All:
-    return true;
-  }
-  return false;
-}
-
 // For OpenMP constructs, check all the data-refs within the constructs
 // and adjust the symbol for each Name if necessary
 void OmpAttributeVisitor::Post(const parser::Name &name) {
@@ -2989,10 +2953,12 @@ void OmpAttributeVisitor::Post(const parser::Name &name) {
           for (auto defaults : dMap) {
             if (defaults.second ==
                 parser::OmpDefaultmapClause::ImplicitBehavior::None) {
-              if (DefaultMapCategoryMatchesSymbol(defaults.first, *found)) {
+              if (omp::DefaultMapCategoryMatchesSymbol(
+                      defaults.first, *found)) {
                 if (!IsObjectWithDSA(*symbol)) {
                   context_.Say(name.source,
-                      "The DEFAULTMAP(NONE) clause requires that '%s' must be "
+                      "The DEFAULTMAP(NONE) clause requires that '%s' must "
+                      "be "
                       "listed in a "
                       "data-sharing attribute, data-mapping attribute, or is_device_ptr clause"_err_en_US,
                       symbol->name());
diff --git a/flang/test/Semantics/OpenMP/default-category.f90 b/flang/test/Semantics/OpenMP/default-category.f90
new file mode 100644
index 0000000000000..36d199287b0e7
--- /dev/null
+++ b/flang/test/Semantics/OpenMP/default-category.f90
@@ -0,0 +1,14 @@
+!RUN: %flang_fc1 -fopenmp -fopenmp-version=60 -fdebug-dump-symbols %s | FileCheck %s
+
+program omp_default_category
+  integer :: a
+  integer :: b(10)
+
+  !$omp parallel default(private:scalar)
+    !CHECK: a (OmpPrivate): HostAssoc
+    !CHECK: b (OmpShared): HostAssoc
+    a = 1
+    b = 1
+  !$omp end parallel
+
+end program omp_default_category
diff --git a/flang/test/Semantics/OpenMP/default-none-category.f90 b/flang/test/Semantics/OpenMP/default-none-category.f90
new file mode 100644
index 0000000000000..224db92c11d45
--- /dev/null
+++ b/flang/test/Semantics/OpenMP/default-none-category.f90
@@ -0,0 +1,53 @@
+!RUN: %python %S/../test_errors.py %s %flang -fopenmp -fopenmp-version=60
+
+program omp_default_none_category
+  integer :: a
+  integer, pointer :: b
+  integer, allocatable :: c
+  integer :: d(10)
+
+  !$omp parallel default(none:scalar)
+  !ERROR: The DEFAULT(NONE) clause requires that 'a' must be listed in a data-sharing attribute clause
+    print *, a
+    print *, b
+    print *, c
+    print *, d
+  !$omp end parallel
+
+  !$omp parallel default(none:pointer)
+    print *, a
+  !ERROR: The DEFAULT(NONE) clause requires that 'b' must be listed in a data-sharing attribute clause
+    print *, b
+    print *, c
+    print *, d
+
+  !$omp end parallel
+
+  !$omp parallel default(none:allocatable)
+    print *, a
+    print *, b
+  !ERROR: The DEFAULT(NONE) clause requires that 'c' must be listed in a data-sharing attribute clause
+    print *, c
+    print *, d
+
+  !$omp end parallel
+ 
+  !$omp parallel default(none:aggregate)
+    print *, a
+    print *, b
+    print *, c
+  !ERROR: The DEFAULT(NONE) clause requires that 'd' must be listed in a data-sharing attribute clause
+    print *, d
+  !$omp end parallel
+
+  !$omp parallel default(none:all)
+  !ERROR: The DEFAULT(NONE) clause requires that 'a' must be listed in a data-sharing attribute clause
+    print *, a
+  !ERROR: The DEFAULT(NONE) clause requires that 'b' must be listed in a data-sharing attribute clause
+    print *, b
+  !ERROR: The DEFAULT(NONE) clause requires that 'c' must be listed in a data-sharing attribute clause
+    print *, c
+  !ERROR: The DEFAULT(NONE) clause requires that 'd' must be listed in a data-sharing attribute clause
+    print *, d
+  !$omp end parallel
+  end program omp_default_none_category
diff --git a/llvm/include/llvm/Frontend/OpenMP/ClauseT.h b/llvm/include/llvm/Frontend/OpenMP/ClauseT.h
index 246d730724c81..d930a7b280415 100644
--- a/llvm/include/llvm/Frontend/OpenMP/ClauseT.h
+++ b/llvm/include/llvm/Frontend/OpenMP/ClauseT.h
@@ -513,8 +513,9 @@ struct CountsT {
 template <typename T, typename I, typename E> //
 struct DefaultT {
   ENUM(DataSharingAttribute, Firstprivate, None, Private, Shared);
-  using WrapperTrait = std::true_type;
-  DataSharingAttribute v;
+  ENUM(VariableCategory, All, Scalar, Aggregate, Pointer, Allocatable);
+  using TupleTrait = std::true_type;
+  std::tuple<DataSharingAttribute, OPT(VariableCategory)> t;
 };
 
 // V5.2: [5.8.7] `defaultmap` clause



More information about the flang-commits mailing list