diff --git a/flang/include/flang/Parser/openmp-utils.h b/flang/include/flang/Parser/openmp-utils.h index 98e849eef9bbc..e37e8d49e026e 100644 --- a/flang/include/flang/Parser/openmp-utils.h +++ b/flang/include/flang/Parser/openmp-utils.h @@ -49,7 +49,6 @@ MAKE_CONSTR_ID(OpenMPDeclareSimdConstruct, D::OMPD_declare_simd); MAKE_CONSTR_ID(OpenMPDeclareTargetConstruct, D::OMPD_declare_target); MAKE_CONSTR_ID(OpenMPExecutableAllocate, D::OMPD_allocate); MAKE_CONSTR_ID(OpenMPRequiresConstruct, D::OMPD_requires); -MAKE_CONSTR_ID(OpenMPThreadprivate, D::OMPD_threadprivate); #undef MAKE_CONSTR_ID @@ -110,8 +109,7 @@ struct DirectiveNameScope { std::is_same_v || std::is_same_v || std::is_same_v || - std::is_same_v || - std::is_same_v) { + std::is_same_v) { return MakeName(std::get(x.t).source, ConstructId::id); } else { return GetFromTuple( diff --git a/flang/include/flang/Parser/parse-tree.h b/flang/include/flang/Parser/parse-tree.h index 40ecd73697d0a..fa18a608e4963 100644 --- a/flang/include/flang/Parser/parse-tree.h +++ b/flang/include/flang/Parser/parse-tree.h @@ -5000,9 +5000,8 @@ struct OpenMPRequiresConstruct { // 2.15.2 threadprivate -> THREADPRIVATE (variable-name-list) struct OpenMPThreadprivate { - TUPLE_CLASS_BOILERPLATE(OpenMPThreadprivate); + WRAPPER_CLASS_BOILERPLATE(OpenMPThreadprivate, OmpDirectiveSpecification); CharBlock source; - std::tuple t; }; // 2.11.3 allocate -> ALLOCATE (variable-name-list) [clause] diff --git a/flang/include/flang/Semantics/openmp-utils.h b/flang/include/flang/Semantics/openmp-utils.h index 68318d6093a1e..65441728c5549 100644 --- a/flang/include/flang/Semantics/openmp-utils.h +++ b/flang/include/flang/Semantics/openmp-utils.h @@ -58,9 +58,10 @@ const parser::DataRef *GetDataRefFromObj(const parser::OmpObject &object); const parser::ArrayElement *GetArrayElementFromObj( const parser::OmpObject &object); const Symbol *GetObjectSymbol(const parser::OmpObject &object); -const Symbol *GetArgumentSymbol(const parser::OmpArgument &argument); std::optional GetObjectSource( const parser::OmpObject &object); +const Symbol *GetArgumentSymbol(const parser::OmpArgument &argument); +const parser::OmpObject *GetArgumentObject(const parser::OmpArgument &argument); bool IsCommonBlock(const Symbol &sym); bool IsExtendedListItem(const Symbol &sym); diff --git a/flang/lib/Parser/openmp-parsers.cpp b/flang/lib/Parser/openmp-parsers.cpp index 24d43171d5d9f..73069c65baa3c 100644 --- a/flang/lib/Parser/openmp-parsers.cpp +++ b/flang/lib/Parser/openmp-parsers.cpp @@ -1791,8 +1791,11 @@ TYPE_PARSER(sourced(construct( verbatim("REQUIRES"_tok), Parser{}))) // 2.15.2 Threadprivate directive -TYPE_PARSER(sourced(construct( - verbatim("THREADPRIVATE"_tok), parenthesized(Parser{})))) +TYPE_PARSER(sourced( // + construct( + predicated(OmpDirectiveNameParser{}, + IsDirective(llvm::omp::Directive::OMPD_threadprivate)) >= + Parser{}))) // 2.11.3 Declarative Allocate directive TYPE_PARSER( diff --git a/flang/lib/Parser/unparse.cpp b/flang/lib/Parser/unparse.cpp index e912ee3f7bffc..c0c26c0c4837b 100644 --- a/flang/lib/Parser/unparse.cpp +++ b/flang/lib/Parser/unparse.cpp @@ -2611,12 +2611,11 @@ class UnparseVisitor { } void Unparse(const OpenMPThreadprivate &x) { BeginOpenMP(); - Word("!$OMP THREADPRIVATE ("); - Walk(std::get(x.t)); - Put(")\n"); + Word("!$OMP "); + Walk(x.v); + Put("\n"); EndOpenMP(); } - bool Pre(const OmpMessageClause &x) { Walk(x.v); return false; diff --git a/flang/lib/Semantics/check-omp-structure.cpp b/flang/lib/Semantics/check-omp-structure.cpp index 39c6f9bda774d..8bcec2f852823 100644 --- a/flang/lib/Semantics/check-omp-structure.cpp +++ b/flang/lib/Semantics/check-omp-structure.cpp @@ -665,11 +665,6 @@ template struct DirectiveSpellingVisitor { checker_(x.v.DirName().source, Directive::OMPD_groupprivate); return false; } - bool Pre(const parser::OpenMPThreadprivate &x) { - checker_( - std::get(x.t).source, Directive::OMPD_threadprivate); - return false; - } bool Pre(const parser::OpenMPRequiresConstruct &x) { checker_(std::get(x.t).source, Directive::OMPD_requires); return false; @@ -1294,15 +1289,20 @@ void OmpStructureChecker::CheckThreadprivateOrDeclareTargetVar( } } +void OmpStructureChecker::CheckThreadprivateOrDeclareTargetVar( + const parser::OmpObject &object) { + common::visit( // + common::visitors{ + [&](auto &&s) { CheckThreadprivateOrDeclareTargetVar(s); }, + [&](const parser::OmpObject::Invalid &invalid) {}, + }, + object.u); +} + void OmpStructureChecker::CheckThreadprivateOrDeclareTargetVar( const parser::OmpObjectList &objList) { for (const auto &ompObject : objList.v) { - common::visit( // - common::visitors{ - [&](auto &&s) { CheckThreadprivateOrDeclareTargetVar(s); }, - [&](const parser::OmpObject::Invalid &invalid) {}, - }, - ompObject.u); + CheckThreadprivateOrDeclareTargetVar(ompObject); } } @@ -1362,18 +1362,20 @@ void OmpStructureChecker::Leave(const parser::OpenMPGroupprivate &x) { dirContext_.pop_back(); } -void OmpStructureChecker::Enter(const parser::OpenMPThreadprivate &c) { - const auto &dir{std::get(c.t)}; - PushContextAndClauseSets( - dir.source, llvm::omp::Directive::OMPD_threadprivate); +void OmpStructureChecker::Enter(const parser::OpenMPThreadprivate &x) { + const parser::OmpDirectiveName &dirName{x.v.DirName()}; + PushContextAndClauseSets(dirName.source, dirName.v); } -void OmpStructureChecker::Leave(const parser::OpenMPThreadprivate &c) { - const auto &dir{std::get(c.t)}; - const auto &objectList{std::get(c.t)}; - CheckSymbolNames(dir.source, objectList); - CheckVarIsNotPartOfAnotherVar(dir.source, objectList); - CheckThreadprivateOrDeclareTargetVar(objectList); +void OmpStructureChecker::Leave(const parser::OpenMPThreadprivate &x) { + const parser::OmpDirectiveSpecification &dirSpec{x.v}; + for (const parser::OmpArgument &arg : x.v.Arguments().v) { + if (auto *object{GetArgumentObject(arg)}) { + CheckSymbolName(dirSpec.source, *object); + CheckVarIsNotPartOfAnotherVar(dirSpec.source, *object); + CheckThreadprivateOrDeclareTargetVar(*object); + } + } dirContext_.pop_back(); } @@ -1672,30 +1674,35 @@ void OmpStructureChecker::Enter(const parser::OmpDeclareTargetWithList &x) { } } -void OmpStructureChecker::CheckSymbolNames( - const parser::CharBlock &source, const parser::OmpObjectList &objList) { - for (const auto &ompObject : objList.v) { - common::visit( - common::visitors{ - [&](const parser::Designator &designator) { - if (const auto *name{parser::Unwrap(ompObject)}) { - if (!name->symbol) { - context_.Say(source, - "The given %s directive clause has an invalid argument"_err_en_US, - ContextDirectiveAsFortran()); - } - } - }, - [&](const parser::Name &name) { - if (!name.symbol) { +void OmpStructureChecker::CheckSymbolName( + const parser::CharBlock &source, const parser::OmpObject &object) { + common::visit( + common::visitors{ + [&](const parser::Designator &designator) { + if (const auto *name{parser::Unwrap(object)}) { + if (!name->symbol) { context_.Say(source, "The given %s directive clause has an invalid argument"_err_en_US, ContextDirectiveAsFortran()); } - }, - [&](const parser::OmpObject::Invalid &invalid) {}, - }, - ompObject.u); + } + }, + [&](const parser::Name &name) { + if (!name.symbol) { + context_.Say(source, + "The given %s directive clause has an invalid argument"_err_en_US, + ContextDirectiveAsFortran()); + } + }, + [&](const parser::OmpObject::Invalid &invalid) {}, + }, + object.u); +} + +void OmpStructureChecker::CheckSymbolNames( + const parser::CharBlock &source, const parser::OmpObjectList &objList) { + for (const auto &ompObject : objList.v) { + CheckSymbolName(source, ompObject); } } diff --git a/flang/lib/Semantics/check-omp-structure.h b/flang/lib/Semantics/check-omp-structure.h index ce074f5f3f86e..6de69e1a8e4f1 100644 --- a/flang/lib/Semantics/check-omp-structure.h +++ b/flang/lib/Semantics/check-omp-structure.h @@ -228,7 +228,10 @@ class OmpStructureChecker const parser::OmpObjectList &objList, llvm::StringRef clause = ""); void CheckThreadprivateOrDeclareTargetVar(const parser::Designator &); void CheckThreadprivateOrDeclareTargetVar(const parser::Name &); + void CheckThreadprivateOrDeclareTargetVar(const parser::OmpObject &); void CheckThreadprivateOrDeclareTargetVar(const parser::OmpObjectList &); + void CheckSymbolName( + const parser::CharBlock &source, const parser::OmpObject &object); void CheckSymbolNames( const parser::CharBlock &source, const parser::OmpObjectList &objList); void CheckIntentInPointer(SymbolSourceMap &, const llvm::omp::Clause); diff --git a/flang/lib/Semantics/openmp-utils.cpp b/flang/lib/Semantics/openmp-utils.cpp index c62a1b33ed4e8..94ec9d06322b7 100644 --- a/flang/lib/Semantics/openmp-utils.cpp +++ b/flang/lib/Semantics/openmp-utils.cpp @@ -105,6 +105,16 @@ const Symbol *GetObjectSymbol(const parser::OmpObject &object) { return nullptr; } +std::optional GetObjectSource( + const parser::OmpObject &object) { + if (auto *name{std::get_if(&object.u)}) { + return name->source; + } else if (auto *desg{std::get_if(&object.u)}) { + return GetLastName(*desg).source; + } + return std::nullopt; +} + const Symbol *GetArgumentSymbol(const parser::OmpArgument &argument) { if (auto *locator{std::get_if(&argument.u)}) { if (auto *object{std::get_if(&locator->u)}) { @@ -114,14 +124,12 @@ const Symbol *GetArgumentSymbol(const parser::OmpArgument &argument) { return nullptr; } -std::optional GetObjectSource( - const parser::OmpObject &object) { - if (auto *name{std::get_if(&object.u)}) { - return name->source; - } else if (auto *desg{std::get_if(&object.u)}) { - return GetLastName(*desg).source; +const parser::OmpObject *GetArgumentObject( + const parser::OmpArgument &argument) { + if (auto *locator{std::get_if(&argument.u)}) { + return std::get_if(&locator->u); } - return std::nullopt; + return nullptr; } bool IsCommonBlock(const Symbol &sym) { diff --git a/flang/lib/Semantics/resolve-directives.cpp b/flang/lib/Semantics/resolve-directives.cpp index 570649995edb0..caee3af8a7ca1 100644 --- a/flang/lib/Semantics/resolve-directives.cpp +++ b/flang/lib/Semantics/resolve-directives.cpp @@ -2342,9 +2342,14 @@ bool OmpAttributeVisitor::Pre( } bool OmpAttributeVisitor::Pre(const parser::OpenMPThreadprivate &x) { - PushContext(x.source, llvm::omp::Directive::OMPD_threadprivate); - const auto &list{std::get(x.t)}; - ResolveOmpObjectList(list, Symbol::Flag::OmpThreadprivate); + const parser::OmpDirectiveName &dirName{x.v.DirName()}; + PushContext(dirName.source, dirName.v); + + for (const parser::OmpArgument &arg : x.v.Arguments().v) { + if (auto *object{omp::GetArgumentObject(arg)}) { + ResolveOmpObject(*object, Symbol::Flag::OmpThreadprivate); + } + } return true; } diff --git a/flang/test/Parser/OpenMP/threadprivate.f90 b/flang/test/Parser/OpenMP/threadprivate.f90 new file mode 100644 index 0000000000000..69b281f848375 --- /dev/null +++ b/flang/test/Parser/OpenMP/threadprivate.f90 @@ -0,0 +1,25 @@ +!RUN: %flang_fc1 -fdebug-unparse -fopenmp -fopenmp-version=60 %s | FileCheck --ignore-case --check-prefix="UNPARSE" %s +!RUN: %flang_fc1 -fdebug-dump-parse-tree -fopenmp -fopenmp-version=60 %s | FileCheck --check-prefix="PARSE-TREE" %s + +module m +implicit none +integer :: a, b +common /blk/ a + +!$omp threadprivate(/blk/, b) + +end module + +!UNPARSE: MODULE m +!UNPARSE: IMPLICIT NONE +!UNPARSE: INTEGER a, b +!UNPARSE: COMMON /blk/a +!UNPARSE: !$OMP THREADPRIVATE(/blk/, b) +!UNPARSE: END MODULE + +!PARSE-TREE: DeclarationConstruct -> SpecificationConstruct -> OpenMPDeclarativeConstruct -> OpenMPThreadprivate -> OmpDirectiveSpecification +!PARSE-TREE: | OmpDirectiveName -> llvm::omp::Directive = threadprivate +!PARSE-TREE: | OmpArgumentList -> OmpArgument -> OmpLocator -> OmpObject -> Name = 'blk' +!PARSE-TREE: | OmpArgument -> OmpLocator -> OmpObject -> Designator -> DataRef -> Name = 'b' +!PARSE-TREE: | OmpClauseList -> +!PARSE-TREE: | Flags = None