Hello,
Currently, Flang reports an error if the type of a variable is specified after it was declared as threadprivate. There is an open issue for it: [Flang][OpenMP] Compilation error when declarations within threadprivate directive and explicit declarations · Issue #106021 · llvm/llvm-project · GitHub.
The example below triggers this error:
subroutine s1
save x1
!$omp threadprivate (x1)
integer x1
end subroutine
error: Semantic errors in test.f90
./test.f90:4:11: error: The type of 'x1' has already been implicitly declared
integer x1
^^
./test.f90:2:8: Implicit declaration of 'x1'
save x1
^^
However, I couldn’t find in the OpenMP standard if a type declaration after threadprivate is used should be allowed or not. Gfortran allows it, but ifort and ifx report the following error:
This name cannot be assigned this data type because it conflicts with prior uses of the name
With Flang, AFAIU, what happens is that x1
in !$omp threadprivate (x1)
is handled as a data reference and its type is determined at that moment. In the example above, implicit rules are used and the resulting type is REAL. When integer x1
is processed, an error occurs, as the type was already implicitly declared as REAL. This behavior seems similar to that of ifort and ifx.
A change that could be made to support declarations with multiple parts, where !$omp threadprivate
is not the last part, would be to skip resolving threadprivate variable names in ResolveSpecificationParts()
and only resolve them later, in ResolveOmpParts()
.
The changes below are enough to support the previous example:
diff --git a/flang/lib/Semantics/resolve-directives.cpp b/flang/lib/Semantics/resolve-directives.cpp
index 4aecb8b8e7b4..34b3b37e2900 100644
--- a/flang/lib/Semantics/resolve-directives.cpp
+++ b/flang/lib/Semantics/resolve-directives.cpp
@@ -2319,6 +2319,9 @@ void OmpAttributeVisitor::ResolveOmpObject(
[&](const parser::Designator &designator) {
if (const auto *name{
semantics::getDesignatorNameIfDataRef(designator)}) {
+ if (!name->symbol) {
+ name->symbol = ResolveName(name);
+ }
if (auto *symbol{ResolveOmp(*name, ompFlag, currScope())}) {
auto checkExclusivelists =
[&](const Symbol *symbol1, Symbol::Flag firstOmpFlag,
@@ -2429,6 +2432,9 @@ void OmpAttributeVisitor::ResolveOmpObject(
}
},
[&](const parser::Name &name) { // common block
+ if (!name.symbol) {
+ name.symbol = ResolveName(&name);
+ }
if (auto *symbol{ResolveOmpCommonBlockName(&name)}) {
if (!dataCopyingAttributeFlags.test(ompFlag)) {
CheckMultipleAppearances(
diff --git a/flang/lib/Semantics/resolve-names.cpp b/flang/lib/Semantics/resolve-names.cpp
index ec8f854f64d1..a37d00291866 100644
--- a/flang/lib/Semantics/resolve-names.cpp
+++ b/flang/lib/Semantics/resolve-names.cpp
@@ -1489,6 +1489,9 @@ public:
void Post(const parser::OmpEndCriticalDirective &) {
messageHandler().set_currStmtSource(std::nullopt);
}
+ bool Pre(const parser::OpenMPThreadprivate &) {
+ return false;
+ }
};
bool OmpVisitor::NeedsScope(const parser::OpenMPBlockConstruct &x) {
But as OmpAttributeVisitor::ResolveName
performs only a simple symbol lookup, it can’t handle more complex specifications, such as structure elements, that are handled by DeclarationVisitor::ResolveDesignator
. Exporting it somehow to OmpAttributeVisitor
would be a bigger change.
But should Flang support type declaration after threadprivate?