[flang-commits] [flang] [flang][OpenMP] Reorganize ALLOCATE-related semantic checks (PR #165719)
via flang-commits
flang-commits at lists.llvm.org
Thu Oct 30 06:45:46 PDT 2025
llvmbot wrote:
<!--LLVM PR SUMMARY COMMENT-->
@llvm/pr-subscribers-flang-openmp
Author: Krzysztof Parzyszek (kparzysz)
<details>
<summary>Changes</summary>
For ALLOCATORS and executable ALLOCATE first perform list item checks in the context of an individual ALLOCATE clause or directive respectively, then perform "global" checks, e.g. whether all list items are present on the ALLOCATE statement.
These changes allowed to simplify the checks for presence on ALLOCATE statement and the use of a predefined allocator.
Additionally, allow variable list item lists to be empty, add a test for the related spec restriction.
This is a first step towards unifying OpenMPDeclarativeAllocate and OpenMPExecutableAllocate into a single directive.
---
Patch is 36.50 KiB, truncated to 20.00 KiB below, full version: https://github.com/llvm/llvm-project/pull/165719.diff
16 Files Affected:
- (modified) flang/include/flang/Parser/parse-tree.h (+1-1)
- (modified) flang/include/flang/Semantics/openmp-utils.h (+2)
- (modified) flang/lib/Parser/openmp-parsers.cpp (+8-6)
- (modified) flang/lib/Parser/unparse.cpp (+1-1)
- (modified) flang/lib/Semantics/check-omp-structure.cpp (+241-194)
- (modified) flang/lib/Semantics/check-omp-structure.h (-10)
- (modified) flang/lib/Semantics/openmp-utils.cpp (+17)
- (modified) flang/lib/Semantics/resolve-directives.cpp (+3-2)
- (modified) flang/test/Semantics/OpenMP/allocate08.f90 (+4-4)
- (modified) flang/test/Semantics/OpenMP/allocate09.f90 (+2-2)
- (added) flang/test/Semantics/OpenMP/allocate10.f90 (+11)
- (added) flang/test/Semantics/OpenMP/allocate11.f90 (+27)
- (modified) flang/test/Semantics/OpenMP/allocators01.f90 (+1-1)
- (removed) flang/test/Semantics/OpenMP/allocators04.f90 (-31)
- (modified) flang/test/Semantics/OpenMP/allocators05.f90 (+1-1)
- (modified) flang/test/Semantics/OpenMP/allocators07.f90 (+3-3)
``````````diff
diff --git a/flang/include/flang/Parser/parse-tree.h b/flang/include/flang/Parser/parse-tree.h
index 375790af90b74..4dd5e84f60dfe 100644
--- a/flang/include/flang/Parser/parse-tree.h
+++ b/flang/include/flang/Parser/parse-tree.h
@@ -5155,7 +5155,7 @@ struct OpenMPThreadprivate {
struct OpenMPDeclarativeAllocate {
TUPLE_CLASS_BOILERPLATE(OpenMPDeclarativeAllocate);
CharBlock source;
- std::tuple<Verbatim, OmpObjectList, OmpClauseList> t;
+ std::tuple<Verbatim, std::optional<OmpObjectList>, OmpClauseList> t;
};
struct OpenMPDeclarativeConstruct {
diff --git a/flang/include/flang/Semantics/openmp-utils.h b/flang/include/flang/Semantics/openmp-utils.h
index 032944d8be370..14a4f0e93bda5 100644
--- a/flang/include/flang/Semantics/openmp-utils.h
+++ b/flang/include/flang/Semantics/openmp-utils.h
@@ -72,6 +72,8 @@ const parser::OmpObject *GetArgumentObject(const parser::OmpArgument &argument);
bool IsCommonBlock(const Symbol &sym);
bool IsExtendedListItem(const Symbol &sym);
bool IsVariableListItem(const Symbol &sym);
+bool IsTypeParamInquiry(const Symbol &sym);
+bool IsStructureComponent(const Symbol &sym);
bool IsVarOrFunctionRef(const MaybeExpr &expr);
bool IsMapEnteringType(parser::OmpMapType::Value type);
diff --git a/flang/lib/Parser/openmp-parsers.cpp b/flang/lib/Parser/openmp-parsers.cpp
index 4159d2e41b78c..a9de26ea09ff8 100644
--- a/flang/lib/Parser/openmp-parsers.cpp
+++ b/flang/lib/Parser/openmp-parsers.cpp
@@ -2045,11 +2045,12 @@ TYPE_PARSER(sourced(construct<OpenMPCriticalConstruct>(
OmpBlockConstructParser{llvm::omp::Directive::OMPD_critical})))
// 2.11.3 Executable Allocate directive
-TYPE_PARSER(
- sourced(construct<OpenMPExecutableAllocate>(verbatim("ALLOCATE"_tok),
- maybe(parenthesized(Parser<OmpObjectList>{})), Parser<OmpClauseList>{},
- maybe(nonemptyList(Parser<OpenMPDeclarativeAllocate>{})) / endOmpLine,
- statement(allocateStmt))))
+TYPE_PARSER(sourced(construct<OpenMPExecutableAllocate>(
+ verbatim("ALLOCATE"_tok), maybe(parenthesized(Parser<OmpObjectList>{})),
+ Parser<OmpClauseList>{},
+ maybe(nonemptyList(startOmpLine >> Parser<OpenMPDeclarativeAllocate>{})) /
+ endOmpLine,
+ statement(allocateStmt))))
// 2.8.2 Declare Simd construct
TYPE_PARSER(sourced(construct<OpenMPDeclareSimdConstruct>(
@@ -2079,7 +2080,8 @@ TYPE_PARSER(sourced( //
// 2.11.3 Declarative Allocate directive
TYPE_PARSER(
sourced(construct<OpenMPDeclarativeAllocate>(verbatim("ALLOCATE"_tok),
- parenthesized(Parser<OmpObjectList>{}), Parser<OmpClauseList>{})) /
+ maybe(parenthesized(Parser<OmpObjectList>{})),
+ Parser<OmpClauseList>{})) /
lookAhead(endOmpLine / !statement(allocateStmt)))
// Assumes Construct
diff --git a/flang/lib/Parser/unparse.cpp b/flang/lib/Parser/unparse.cpp
index 9b38cfc40c5b2..b3a395c4d72e1 100644
--- a/flang/lib/Parser/unparse.cpp
+++ b/flang/lib/Parser/unparse.cpp
@@ -2503,7 +2503,7 @@ class UnparseVisitor {
BeginOpenMP();
Word("!$OMP ALLOCATE");
Put(" (");
- Walk(std::get<OmpObjectList>(x.t));
+ Walk(std::get<std::optional<OmpObjectList>>(x.t));
Put(")");
Walk(std::get<OmpClauseList>(x.t));
Put("\n");
diff --git a/flang/lib/Semantics/check-omp-structure.cpp b/flang/lib/Semantics/check-omp-structure.cpp
index aaaf1ec5d4626..ece179c4a66fc 100644
--- a/flang/lib/Semantics/check-omp-structure.cpp
+++ b/flang/lib/Semantics/check-omp-structure.cpp
@@ -667,49 +667,6 @@ void OmpStructureChecker::HasInvalidTeamsNesting(
}
}
-void OmpStructureChecker::CheckPredefinedAllocatorRestriction(
- const parser::CharBlock &source, const parser::Name &name) {
- if (const auto *symbol{name.symbol}) {
- const auto *commonBlock{FindCommonBlockContaining(*symbol)};
- const auto &scope{context_.FindScope(symbol->name())};
- const Scope &containingScope{GetProgramUnitContaining(scope)};
- if (!isPredefinedAllocator &&
- (IsSaved(*symbol) || commonBlock ||
- containingScope.kind() == Scope::Kind::Module)) {
- context_.Say(source,
- "If list items within the %s directive have the "
- "SAVE attribute, are a common block name, or are "
- "declared in the scope of a module, then only "
- "predefined memory allocator parameters can be used "
- "in the allocator clause"_err_en_US,
- ContextDirectiveAsFortran());
- }
- }
-}
-
-void OmpStructureChecker::CheckPredefinedAllocatorRestriction(
- const parser::CharBlock &source,
- const parser::OmpObjectList &ompObjectList) {
- for (const auto &ompObject : ompObjectList.v) {
- common::visit(
- common::visitors{
- [&](const parser::Designator &designator) {
- if (const auto *dataRef{
- std::get_if<parser::DataRef>(&designator.u)}) {
- if (const auto *name{std::get_if<parser::Name>(&dataRef->u)}) {
- CheckPredefinedAllocatorRestriction(source, *name);
- }
- }
- },
- [&](const parser::Name &name) {
- CheckPredefinedAllocatorRestriction(source, name);
- },
- [&](const parser::OmpObject::Invalid &invalid) {},
- },
- ompObject.u);
- }
-}
-
void OmpStructureChecker::Enter(const parser::OmpClause::Hint &x) {
CheckAllowedClause(llvm::omp::Clause::OMPC_hint);
auto &dirCtx{GetContext()};
@@ -1710,12 +1667,51 @@ void OmpStructureChecker::Leave(const parser::OpenMPRequiresConstruct &) {
dirContext_.pop_back();
}
+static std::pair<const parser::AllocateStmt *, parser::CharBlock>
+getAllocateStmtAndSource(const parser::Statement<parser::AllocateStmt> &stmt) {
+ return {&stmt.statement, stmt.source};
+}
+
+static std::pair<const parser::AllocateStmt *, parser::CharBlock>
+getAllocateStmtAndSource(const parser::ExecutionPartConstruct *epc) {
+ if (SourcedActionStmt as{GetActionStmt(epc)}) {
+ using IndirectionAllocateStmt = common::Indirection<parser::AllocateStmt>;
+ if (auto *indirect{std::get_if<IndirectionAllocateStmt>(&as.stmt->u)}) {
+ return {&indirect->value(), as.source};
+ }
+ }
+ return {nullptr, ""};
+}
+
+// Collect symbols that correspond to non-component objects on the
+// ALLOCATE statement.
+static UnorderedSymbolSet GetNonComponentSymbols(
+ const parser::AllocateStmt &stmt) {
+ UnorderedSymbolSet symbols;
+ for (auto &alloc : std::get<std::list<parser::Allocation>>(stmt.t)) {
+ auto &object{std::get<parser::AllocateObject>(alloc.t)};
+ if (auto *name{std::get_if<parser::Name>(&object.u)}) {
+ if (name->symbol) {
+ symbols.insert(name->symbol->GetUltimate());
+ }
+ }
+ }
+ return symbols;
+}
+
+static const parser::OmpObjectList &GetObjectsOrEmpty(
+ const std::optional<parser::OmpObjectList> &maybeObjects) {
+ static parser::OmpObjectList empty{std::list<parser::OmpObject>{}};
+ if (maybeObjects) {
+ return *maybeObjects;
+ }
+ return empty;
+}
+
void OmpStructureChecker::CheckAllocateDirective(parser::CharBlock source,
const parser::OmpObjectList &objects,
const parser::OmpClauseList &clauses) {
const Scope &thisScope{context_.FindScope(source)};
- SymbolSourceMap symbols;
- GetSymbolsInObjectList(objects, symbols);
auto maybeHasPredefinedAllocator{[&](const parser::OmpClause *calloc) {
// Return "true" if the ALLOCATOR clause was provided with an argument
@@ -1741,7 +1737,17 @@ void OmpStructureChecker::CheckAllocateDirective(parser::CharBlock source,
return true;
}};
- const auto *allocator{FindClause(llvm::omp::Clause::OMPC_allocator)};
+ const auto *allocator{[&]() {
+ // Can't use FindClause in Enter (because clauses haven't been visited
+ // yet).
+ for (const parser::OmpClause &c : clauses.v) {
+ if (c.Id() == llvm::omp::Clause::OMPC_allocator) {
+ return &c;
+ }
+ }
+ return static_cast<const parser::OmpClause *>(nullptr);
+ }()};
+
if (InTargetRegion()) {
bool hasDynAllocators{
HasRequires(llvm::omp::Clause::OMPC_dynamic_allocators)};
@@ -1753,61 +1759,85 @@ void OmpStructureChecker::CheckAllocateDirective(parser::CharBlock source,
auto maybePredefined{maybeHasPredefinedAllocator(allocator)};
- for (auto &[symbol, source] : symbols) {
+ unsigned version{context_.langOptions().OpenMPVersion};
+ std::string condStr{version == 50
+ ? "a named common block, has SAVE attribute or is declared in the "
+ "scope of a module"
+ : "a named common block or has SAVE attribute"};
+
+ auto checkSymbol{[&](const Symbol &symbol, parser::CharBlock source) {
if (!inExecutableAllocate_) {
- if (symbol->owner() != thisScope) {
+ // For structure members, the scope is the derived type, which is
+ // never "this" scope. Ignore this check for members, they will be
+ // flagged anyway.
+ if (symbol.owner() != thisScope && !IsStructureComponent(symbol)) {
context_.Say(source,
"A list item on a declarative ALLOCATE must be declared in the same scope in which the directive appears"_err_en_US);
}
- if (IsPointer(*symbol) || IsAllocatable(*symbol)) {
+ if (IsPointer(symbol) || IsAllocatable(symbol)) {
context_.Say(source,
"A list item in a declarative ALLOCATE cannot have the ALLOCATABLE or POINTER attribute"_err_en_US);
}
}
- if (symbol->GetUltimate().has<AssocEntityDetails>()) {
+ if (symbol.GetUltimate().has<AssocEntityDetails>()) {
context_.Say(source,
"A list item in a declarative ALLOCATE cannot be an associate name"_err_en_US);
}
- if (symbol->attrs().test(Attr::SAVE) || IsCommonBlock(*symbol)) {
+ bool inModule{
+ version == 50 && symbol.owner().kind() == Scope::Kind::Module};
+ if (symbol.attrs().test(Attr::SAVE) || IsCommonBlock(symbol) || inModule) {
if (!allocator) {
context_.Say(source,
- "If a list item is a named common block or has SAVE attribute, an ALLOCATOR clause must be present with a predefined allocator"_err_en_US);
+ "If a list item is %s, an ALLOCATOR clause must be present with a predefined allocator"_err_en_US,
+ condStr);
} else if (!maybePredefined) {
context_.Say(source,
- "If a list item is a named common block or has SAVE attribute, only a predefined allocator may be used on the ALLOCATOR clause"_err_en_US);
+ "If a list item is %s, only a predefined allocator may be used on the ALLOCATOR clause"_err_en_US,
+ condStr);
}
}
- if (FindCommonBlockContaining(*symbol)) {
+ if (FindCommonBlockContaining(symbol)) {
context_.Say(source,
"A variable that is part of a common block may not be specified as a list item in an ALLOCATE directive, except implicitly via the named common block"_err_en_US);
}
+ }};
+
+ for (const parser::OmpObject &object : objects.v) {
+ parser::CharBlock objSource{[&]() {
+ if (auto &&maybeSource{GetObjectSource(object)}) {
+ return *maybeSource;
+ }
+ return source;
+ }()};
+ if (const Symbol *symbol{GetObjectSymbol(object)}) {
+ if (!IsTypeParamInquiry(*symbol)) {
+ checkSymbol(*symbol, objSource);
+ }
+ CheckVarIsNotPartOfAnotherVar(source, object);
+ }
}
- CheckVarIsNotPartOfAnotherVar(source, objects);
}
void OmpStructureChecker::Enter(const parser::OpenMPDeclarativeAllocate &x) {
const auto &dir{std::get<parser::Verbatim>(x.t)};
PushContextAndClauseSets(dir.source, llvm::omp::Directive::OMPD_allocate);
-}
-void OmpStructureChecker::Leave(const parser::OpenMPDeclarativeAllocate &x) {
if (!inExecutableAllocate_) {
const auto &dir{std::get<parser::Verbatim>(x.t)};
- const auto &clauseList{std::get<parser::OmpClauseList>(x.t)};
- const auto &objectList{std::get<parser::OmpObjectList>(x.t)};
+ const auto &clauses{std::get<parser::OmpClauseList>(x.t)};
+ const auto &objects{
+ GetObjectsOrEmpty(std::get<std::optional<parser::OmpObjectList>>(x.t))};
- isPredefinedAllocator = true;
- CheckAllocateDirective(dir.source, objectList, clauseList);
+ CheckAllocateDirective(dir.source, objects, clauses);
}
+}
+
+void OmpStructureChecker::Leave(const parser::OpenMPDeclarativeAllocate &x) {
dirContext_.pop_back();
}
void OmpStructureChecker::Enter(const parser::OmpClause::Allocator &x) {
CheckAllowedClause(llvm::omp::Clause::OMPC_allocator);
- // Note: Predefined allocators are stored in ScalarExpr as numbers
- // whereas custom allocators are stored as strings, so if the ScalarExpr
- // actually has an int value, then it must be a predefined allocator
- isPredefinedAllocator = GetIntValue(x.v).has_value();
RequiresPositiveParameter(llvm::omp::Clause::OMPC_allocator, x.v);
}
@@ -1823,16 +1853,6 @@ void OmpStructureChecker::Enter(const parser::OmpClause::Allocate &x) {
"The alignment value should be a constant positive integer"_err_en_US);
}
}
- // The simple and complex modifiers have the same structure. They only
- // differ in their syntax.
- if (auto *alloc{OmpGetUniqueModifier<parser::OmpAllocatorComplexModifier>(
- modifiers)}) {
- isPredefinedAllocator = GetIntValue(alloc->v).has_value();
- }
- if (auto *alloc{OmpGetUniqueModifier<parser::OmpAllocatorSimpleModifier>(
- modifiers)}) {
- isPredefinedAllocator = GetIntValue(alloc->v).has_value();
- }
}
}
@@ -2115,44 +2135,6 @@ void OmpStructureChecker::Enter(const parser::OmpClause::At &x) {
}
}
-// Goes through the names in an OmpObjectList and checks if each name appears
-// in the given allocate statement
-void OmpStructureChecker::CheckAllNamesInAllocateStmt(
- const parser::CharBlock &source, const parser::OmpObjectList &ompObjectList,
- const parser::AllocateStmt &allocate) {
- for (const auto &obj : ompObjectList.v) {
- if (const auto *d{std::get_if<parser::Designator>(&obj.u)}) {
- if (const auto *ref{std::get_if<parser::DataRef>(&d->u)}) {
- if (const auto *n{std::get_if<parser::Name>(&ref->u)}) {
- CheckNameInAllocateStmt(source, *n, allocate);
- }
- }
- }
- }
-}
-
-void OmpStructureChecker::CheckNameInAllocateStmt(
- const parser::CharBlock &source, const parser::Name &name,
- const parser::AllocateStmt &allocate) {
- for (const auto &allocation :
- std::get<std::list<parser::Allocation>>(allocate.t)) {
- const auto &allocObj = std::get<parser::AllocateObject>(allocation.t);
- if (const auto *n{std::get_if<parser::Name>(&allocObj.u)}) {
- if (n->source == name.source) {
- return;
- }
- }
- }
- unsigned version{context_.langOptions().OpenMPVersion};
- context_.Say(source,
- "Object '%s' in %s directive not "
- "found in corresponding ALLOCATE statement"_err_en_US,
- name.ToString(),
- parser::ToUpperCaseLetters(
- llvm::omp::getOpenMPDirectiveName(GetContext().directive, version)
- .str()));
-}
-
void OmpStructureChecker::Enter(const parser::OpenMPExecutableAllocate &x) {
inExecutableAllocate_ = true;
const auto &dir{std::get<parser::Verbatim>(x.t)};
@@ -2164,34 +2146,10 @@ void OmpStructureChecker::Enter(const parser::OpenMPExecutableAllocate &x) {
"The executable form of the OpenMP ALLOCATE directive has been deprecated, please use ALLOCATORS instead"_warn_en_US);
}
- const auto &allocateStmt =
- std::get<parser::Statement<parser::AllocateStmt>>(x.t).statement;
- if (const auto &list{std::get<std::optional<parser::OmpObjectList>>(x.t)}) {
- CheckAllNamesInAllocateStmt(
- std::get<parser::Verbatim>(x.t).source, *list, allocateStmt);
- }
- if (const auto &subDirs{
- std::get<std::optional<std::list<parser::OpenMPDeclarativeAllocate>>>(
- x.t)}) {
- for (const auto &dalloc : *subDirs) {
- CheckAllNamesInAllocateStmt(std::get<parser::Verbatim>(dalloc.t).source,
- std::get<parser::OmpObjectList>(dalloc.t), allocateStmt);
- }
- }
-
- isPredefinedAllocator = true;
-}
-
-void OmpStructureChecker::Leave(const parser::OpenMPExecutableAllocate &x) {
- parser::OmpObjectList empty{std::list<parser::OmpObject>{}};
- auto &objects{[&]() -> const parser::OmpObjectList & {
- if (auto &objects{std::get<std::optional<parser::OmpObjectList>>(x.t)}) {
- return *objects;
- } else {
- return empty;
- }
- }()};
+ auto &objects{
+ GetObjectsOrEmpty(std::get<std::optional<parser::OmpObjectList>>(x.t))};
auto &clauses{std::get<parser::OmpClauseList>(x.t)};
+
CheckAllocateDirective(
std::get<parser::Verbatim>(x.t).source, objects, clauses);
@@ -2201,82 +2159,171 @@ void OmpStructureChecker::Leave(const parser::OpenMPExecutableAllocate &x) {
for (const auto &dalloc : *subDirs) {
const auto &dir{std::get<parser::Verbatim>(x.t)};
const auto &clauses{std::get<parser::OmpClauseList>(dalloc.t)};
- const auto &objects{std::get<parser::OmpObjectList>(dalloc.t)};
+ const auto &objects{GetObjectsOrEmpty(
+ std::get<std::optional<parser::OmpObjectList>>(dalloc.t))};
CheckAllocateDirective(dir.source, objects, clauses);
}
}
+}
+
+void OmpStructureChecker::Leave(const parser::OpenMPExecutableAllocate &x) {
+ auto [allocStmt, allocSource]{getAllocateStmtAndSource(
+ std::get<parser::Statement<parser::AllocateStmt>>(x.t))};
+
+ UnorderedSymbolSet allocateSyms{GetNonComponentSymbols(*allocStmt)};
+ SymbolSourceMap directiveSyms;
+ auto &objects{
+ GetObjectsOrEmpty(std::get<std::optional<parser::OmpObjectList>>(x.t))};
+ auto emptyListCount{static_cast<size_t>(objects.v.empty())};
+ auto checkObjects{[&](const parser::OmpObjectList &objects,
+ parser::CharBlock dirSource,
+ parser::CharBlock allocSource) {
+ for (const parser::OmpObject &object : objects.v) {
+ parser::CharBlock objSource{[&]() {
+ if (auto &&maybeSource{GetObjectSource(object)}) {
+ return *maybeSource;
+ }
+ return dirSource;
+ }()};
+ if (auto *sym{GetObjectSymbol(object)}) {
+ // Ignore these checks for structure members. They are not allowed
+ // in the first place, so don't tell the users that they nened to
+ // be specified somewhere,
+ if (IsStructureComponent(*sym)) {
+ continue;
+ }
+ if (auto f{directiveSyms.find(sym)}; f != directiveSyms.end()) {
+ parser::MessageFormattedText txt(
+ "A list item on an executable ALLOCATE may only be specified once"_err_en_US);
+ parser::Message message(objSource, txt);
+ message.Attach(f->second, "The list item was specified here"_en_US);
+ context_.Say(std::move(message));
+ } else {
+ directiveSyms.insert(std::make_pair(sym, objSource));
+ }
+
+ if (auto f{allocateSyms.find(*sym)}; f == allocateSyms.end()) {
+ context_
+ .Say(objSource,
+ "A list item on an executable ALLOCATE must be specified on the associated ALLOCATE statement"_err_en_US)
+ .Attach(allocSource, "The ALLOCATE statement"_en_US);
+ }
+ }
+ }
+ }};
+
+ checkObjects(objects, std::get<parser::Verbatim>(x.t).source, allocSource);
+
+ const auto &subDirs{
+ std::get<std::optional<std::list<parser::OpenMPDeclarativeAllocate>>>(
+ x.t)};
+ if (!subDirs) {
+ inExecutableAllocate_ = false;
+ dirContext_.pop_back();
+ return;
+ }
+
+ for (const parser::OpenMPDeclarativeAllocate &ompAlloc : *subDirs) {
+ parser::CharBlock dirSource{std::get<parser::Verbatim>(ompAlloc.t).source};
+ auto &objects{GetObjectsOrEmpty(
+ std::get<std::optional<parser::OmpObjectList>>(ompAlloc.t))};
+ if (objects.v.empty()) {
+ // Only show the message once per construct.
+ if (++emptyListCount == 2 && subDirs->size() >= 1) {
+ context_.Say(dirSource,
+ "If multiple directives are present in an executable ALLOCATE directive, at most one of them may specify no list items"_err_en_US);
+ }
+ }
+ checkObjects(objects, dirSource, allocSource);
+ }
- dirContext_.pop_back();
inExecutableAllocate_ = false;
+ dirContext_.pop_back();
}
void Om...
[truncated]
``````````
</details>
https://github.com/llvm/llvm-project/pull/165719
More information about the flang-commits
mailing list