From f56f6c27c700c02c03810c5a1f4fb19a389ac73c Mon Sep 17 00:00:00 2001 From: Akash Banerjee Date: Thu, 16 Oct 2025 21:36:07 +0100 Subject: [PATCH 1/5] [Flang][OpenMP] Update declare mapper lookup via use-module - Implemented semantic TODO to catch undeclared mappers. - Fix mapper lookup to include modules imported through USE. - Update and add tests. Fixes #163385. --- flang/lib/Lower/OpenMP/ClauseProcessor.cpp | 12 ++++--- flang/lib/Semantics/resolve-names.cpp | 31 +++++++++++++------ flang/test/Lower/OpenMP/declare-mapper.f90 | 25 ++++++++++++++- flang/test/Parser/OpenMP/map-modifiers.f90 | 7 ++--- .../Semantics/OpenMP/map-clause-symbols.f90 | 8 ++--- 5 files changed, 59 insertions(+), 24 deletions(-) diff --git a/flang/lib/Lower/OpenMP/ClauseProcessor.cpp b/flang/lib/Lower/OpenMP/ClauseProcessor.cpp index 1c163e6de7e5a..56e482cbe22b0 100644 --- a/flang/lib/Lower/OpenMP/ClauseProcessor.cpp +++ b/flang/lib/Lower/OpenMP/ClauseProcessor.cpp @@ -1392,10 +1392,14 @@ bool ClauseProcessor::processMap( } if (mappers) { assert(mappers->size() == 1 && "more than one mapper"); - mapperIdName = mappers->front().v.id().symbol->name().ToString(); - if (mapperIdName != "default") - mapperIdName = converter.mangleName( - mapperIdName, mappers->front().v.id().symbol->owner()); + const semantics::Symbol *mapperSym = mappers->front().v.id().symbol; + mapperIdName = mapperSym->name().ToString(); + if (mapperIdName != "default") { + // Mangle with the ultimate owner so that use-associated mapper + // identifiers resolve to the same symbol as their defining scope. + const semantics::Symbol &ultimate = mapperSym->GetUltimate(); + mapperIdName = converter.mangleName(mapperIdName, ultimate.owner()); + } } processMapObjects(stmtCtx, clauseLocation, diff --git a/flang/lib/Semantics/resolve-names.cpp b/flang/lib/Semantics/resolve-names.cpp index f88af5fac0bbd..98758a05eda9e 100644 --- a/flang/lib/Semantics/resolve-names.cpp +++ b/flang/lib/Semantics/resolve-names.cpp @@ -1852,21 +1852,24 @@ bool OmpVisitor::Pre(const parser::OmpMapClause &x) { // TODO: Do we need a specific flag or type here, to distinghuish against // other ConstructName things? Leaving this for the full implementation // of mapper lowering. - auto *misc{symbol->detailsIf()}; + const Symbol &ultimate{symbol->GetUltimate()}; + auto *misc{const_cast(ultimate).detailsIf()}; if (!misc || misc->kind() != MiscDetails::Kind::ConstructName) context().Say(mapper->v.source, "Name '%s' should be a mapper name"_err_en_US, mapper->v.source); else mapper->v.symbol = symbol; } else { - mapper->v.symbol = - &MakeSymbol(mapper->v, MiscDetails{MiscDetails::Kind::ConstructName}); - // TODO: When completing the implementation, we probably want to error if - // the symbol is not declared, but right now, testing that the TODO for - // OmpMapClause happens is obscured by the TODO for declare mapper, so - // leaving this out. Remove the above line once the declare mapper is - // implemented. context().Say(mapper->v.source, "'%s' not - // declared"_err_en_US, mapper->v.source); + // Allow the special 'default' mapper identifier without prior + // declaration so lowering can recognize and handle it. Emit an + // error for any other missing mapper identifier. + if (mapper->v.source.ToString() == "default") { + mapper->v.symbol = &MakeSymbol( + mapper->v, MiscDetails{MiscDetails::Kind::ConstructName}); + } else { + context().Say( + mapper->v.source, "'%s' not declared"_err_en_US, mapper->v.source); + } } } return true; @@ -3611,10 +3614,18 @@ void ModuleVisitor::Post(const parser::UseStmt &x) { rename.u); } for (const auto &[name, symbol] : *useModuleScope_) { + // Default USE imports public names, excluding intrinsic-only and most + // miscellaneous details. However, allow OpenMP mapper identifiers, + // which are currently represented with MiscDetails::ConstructName. + bool isMapper{false}; + if (const auto *misc{symbol->detailsIf()}) { + isMapper = misc->kind() == MiscDetails::Kind::ConstructName; + } if (symbol->attrs().test(Attr::PUBLIC) && !IsUseRenamed(symbol->name()) && (!symbol->implicitAttrs().test(Attr::INTRINSIC) || symbol->has()) && - !symbol->has() && useNames.count(name) == 0) { + (!symbol->has() || isMapper) && + useNames.count(name) == 0) { SourceName location{x.moduleName.source}; if (auto *localSymbol{FindInScope(name)}) { DoAddUse(location, localSymbol->name(), *localSymbol, *symbol); diff --git a/flang/test/Lower/OpenMP/declare-mapper.f90 b/flang/test/Lower/OpenMP/declare-mapper.f90 index c389d0ff4bd15..2ed1e2e4c942e 100644 --- a/flang/test/Lower/OpenMP/declare-mapper.f90 +++ b/flang/test/Lower/OpenMP/declare-mapper.f90 @@ -6,7 +6,8 @@ ! RUN: %flang_fc1 -emit-hlfir -fopenmp -fopenmp-version=50 %t/omp-declare-mapper-3.f90 -o - | FileCheck %t/omp-declare-mapper-3.f90 ! RUN: %flang_fc1 -emit-hlfir -fopenmp -fopenmp-version=50 %t/omp-declare-mapper-4.f90 -o - | FileCheck %t/omp-declare-mapper-4.f90 ! RUN: %flang_fc1 -emit-hlfir -fopenmp -fopenmp-version=50 %t/omp-declare-mapper-5.f90 -o - | FileCheck %t/omp-declare-mapper-5.f90 -! RUN: %flang_fc1 -emit-hlfir -fopenmp -fopenmp-version=51 %t/omp-declare-mapper-6.f90 -o - | FileCheck %t/omp-declare-mapper-6.f90 +! RUN: %flang_fc1 -emit-hlfir -fopenmp -fopenmp-version=50 %t/omp-declare-mapper-6.f90 -o - | FileCheck %t/omp-declare-mapper-6.f90 +! RUN: %flang_fc1 -emit-hlfir -fopenmp -fopenmp-version=50 %t/omp-declare-mapper-7.f90 -o - | FileCheck %t/omp-declare-mapper-7.f90 !--- omp-declare-mapper-1.f90 subroutine declare_mapper_1 @@ -301,3 +302,25 @@ subroutine declare_mapper_nested_parent r%real_arr = r%base_arr(1) + r%inner%deep_arr(1) !$omp end target end subroutine declare_mapper_nested_parent + +!--- omp-declare-mapper-7.f90 +! Check mappers declared inside modules and used via USE association. +module m_mod + implicit none + type :: mty + integer :: x + end type mty + !$omp declare mapper(mymap : mty :: v) map(tofrom: v%x) +end module m_mod + +program use_module_mapper + use m_mod + implicit none + type(mty) :: a + + ! CHECK: omp.declare_mapper @[[MODMAP:[^ ]*mymap]] + ! CHECK: %{{.*}} = omp.map.info {{.*}} mapper(@[[MODMAP]]) {{.*}} {name = "a"} + !$omp target map(mapper(mymap) : a) + a%x = 42 + !$omp end target +end program use_module_mapper diff --git a/flang/test/Parser/OpenMP/map-modifiers.f90 b/flang/test/Parser/OpenMP/map-modifiers.f90 index 83662b70f08f5..7d9b8856ac833 100644 --- a/flang/test/Parser/OpenMP/map-modifiers.f90 +++ b/flang/test/Parser/OpenMP/map-modifiers.f90 @@ -320,7 +320,7 @@ subroutine f21(x, y) integer :: x(10) integer :: y integer, parameter :: p = 23 - !$omp target map(mapper(xx), from: x) + !$omp target map(mapper(default), from: x) x = x + 1 !$omp end target end @@ -329,7 +329,7 @@ subroutine f21(x, y) !UNPARSE: INTEGER x(10_4) !UNPARSE: INTEGER y !UNPARSE: INTEGER, PARAMETER :: p = 23_4 -!UNPARSE: !$OMP TARGET MAP(MAPPER(XX), FROM: X) +!UNPARSE: !$OMP TARGET MAP(MAPPER(DEFAULT), FROM: X) !UNPARSE: x=x+1_4 !UNPARSE: !$OMP END TARGET !UNPARSE: END SUBROUTINE @@ -337,7 +337,7 @@ subroutine f21(x, y) !PARSE-TREE: OmpBeginDirective !PARSE-TREE: | OmpDirectiveName -> llvm::omp::Directive = target !PARSE-TREE: | OmpClauseList -> OmpClause -> Map -> OmpMapClause -!PARSE-TREE: | | Modifier -> OmpMapper -> Name = 'xx' +!PARSE-TREE: | | Modifier -> OmpMapper -> Name = 'default' !PARSE-TREE: | | Modifier -> OmpMapType -> Value = From !PARSE-TREE: | | OmpObjectList -> OmpObject -> Designator -> DataRef -> Name = 'x' @@ -375,4 +375,3 @@ subroutine f22(x) !PARSE-TREE: | | SectionSubscript -> Integer -> Expr = 'i' !PARSE-TREE: | | | Designator -> DataRef -> Name = 'i' !PARSE-TREE: | bool = 'true' - diff --git a/flang/test/Semantics/OpenMP/map-clause-symbols.f90 b/flang/test/Semantics/OpenMP/map-clause-symbols.f90 index 1d6315b4a2312..cdb65a71e8887 100644 --- a/flang/test/Semantics/OpenMP/map-clause-symbols.f90 +++ b/flang/test/Semantics/OpenMP/map-clause-symbols.f90 @@ -1,6 +1,5 @@ -! RUN: %flang_fc1 -fdebug-dump-symbols -fopenmp -fopenmp-version=50 %s | FileCheck %s +! RUN: not %flang_fc1 -fopenmp -fopenmp-version=50 %s 2>&1 | FileCheck %s program main -!CHECK-LABEL: MainProgram scope: MAIN integer, parameter :: n = 256 real(8) :: a(256) !$omp target map(mapper(xx), from:a) @@ -8,7 +7,6 @@ program main a(i) = 4.2 end do !$omp end target -!CHECK: OtherConstruct scope: size=0 alignment=1 sourceRange=74 bytes -!CHECK: OtherClause scope: size=0 alignment=1 sourceRange=0 bytes -!CHECK: xx: Misc ConstructName end program main + +! CHECK: error: '{{.*}}' not declared From 117d77e24760436ad1706b078b05d2bbbdb48643 Mon Sep 17 00:00:00 2001 From: Akash Banerjee Date: Thu, 16 Oct 2025 21:51:22 +0100 Subject: [PATCH 2/5] code cleanup --- flang/lib/Semantics/resolve-names.cpp | 92 +++++++++++++-------------- 1 file changed, 45 insertions(+), 47 deletions(-) diff --git a/flang/lib/Semantics/resolve-names.cpp b/flang/lib/Semantics/resolve-names.cpp index 98758a05eda9e..1944b856df2d7 100644 --- a/flang/lib/Semantics/resolve-names.cpp +++ b/flang/lib/Semantics/resolve-names.cpp @@ -1852,8 +1852,7 @@ bool OmpVisitor::Pre(const parser::OmpMapClause &x) { // TODO: Do we need a specific flag or type here, to distinghuish against // other ConstructName things? Leaving this for the full implementation // of mapper lowering. - const Symbol &ultimate{symbol->GetUltimate()}; - auto *misc{const_cast(ultimate).detailsIf()}; + auto *misc{symbol->GetUltimate().detailsIf()}; if (!misc || misc->kind() != MiscDetails::Kind::ConstructName) context().Say(mapper->v.source, "Name '%s' should be a mapper name"_err_en_US, mapper->v.source); @@ -2373,7 +2372,7 @@ void AttrsVisitor::SetBindNameOn(Symbol &symbol) { } symbol.SetBindName(std::move(*label)); if (!oldBindName.empty()) { - if (const std::string * newBindName{symbol.GetBindName()}) { + if (const std::string *newBindName{symbol.GetBindName()}) { if (oldBindName != *newBindName) { Say(symbol.name(), "The entity '%s' has multiple BIND names ('%s' and '%s')"_err_en_US, @@ -2499,7 +2498,7 @@ void DeclTypeSpecVisitor::Post(const parser::TypeSpec &typeSpec) { // expression semantics if the DeclTypeSpec is a valid TypeSpec. // The grammar ensures that it's an intrinsic or derived type spec, // not TYPE(*) or CLASS(*) or CLASS(T). - if (const DeclTypeSpec * spec{state_.declTypeSpec}) { + if (const DeclTypeSpec *spec{state_.declTypeSpec}) { switch (spec->category()) { case DeclTypeSpec::Numeric: case DeclTypeSpec::Logical: @@ -2507,7 +2506,7 @@ void DeclTypeSpecVisitor::Post(const parser::TypeSpec &typeSpec) { typeSpec.declTypeSpec = spec; break; case DeclTypeSpec::TypeDerived: - if (const DerivedTypeSpec * derived{spec->AsDerived()}) { + if (const DerivedTypeSpec *derived{spec->AsDerived()}) { CheckForAbstractType(derived->typeSymbol()); // C703 typeSpec.declTypeSpec = spec; } @@ -3098,8 +3097,8 @@ Symbol &ScopeHandler::MakeSymbol(const parser::Name &name, Attrs attrs) { Symbol &ScopeHandler::MakeHostAssocSymbol( const parser::Name &name, const Symbol &hostSymbol) { Symbol &symbol{*NonDerivedTypeScope() - .try_emplace(name.source, HostAssocDetails{hostSymbol}) - .first->second}; + .try_emplace(name.source, HostAssocDetails{hostSymbol}) + .first->second}; name.symbol = &symbol; symbol.attrs() = hostSymbol.attrs(); // TODO: except PRIVATE, PUBLIC? // These attributes can be redundantly reapplied without error @@ -3187,7 +3186,7 @@ void ScopeHandler::ApplyImplicitRules( if (context().HasError(symbol) || !NeedsType(symbol)) { return; } - if (const DeclTypeSpec * type{GetImplicitType(symbol)}) { + if (const DeclTypeSpec *type{GetImplicitType(symbol)}) { if (!skipImplicitTyping_) { symbol.set(Symbol::Flag::Implicit); symbol.SetType(*type); @@ -3287,7 +3286,7 @@ const DeclTypeSpec *ScopeHandler::GetImplicitType( const auto *type{implicitRulesMap_->at(scope).GetType( symbol.name(), respectImplicitNoneType)}; if (type) { - if (const DerivedTypeSpec * derived{type->AsDerived()}) { + if (const DerivedTypeSpec *derived{type->AsDerived()}) { // Resolve any forward-referenced derived type; a quick no-op else. auto &instantiatable{*const_cast(derived)}; instantiatable.Instantiate(currScope()); @@ -4310,7 +4309,7 @@ Scope *ModuleVisitor::FindModule(const parser::Name &name, if (scope) { if (DoesScopeContain(scope, currScope())) { // 14.2.2(1) std::optional submoduleName; - if (const Scope * container{FindModuleOrSubmoduleContaining(currScope())}; + if (const Scope *container{FindModuleOrSubmoduleContaining(currScope())}; container && container->IsSubmodule()) { submoduleName = container->GetName(); } @@ -4415,7 +4414,7 @@ bool InterfaceVisitor::isAbstract() const { void InterfaceVisitor::AddSpecificProcs( const std::list &names, ProcedureKind kind) { - if (Symbol * symbol{GetGenericInfo().symbol}; + if (Symbol *symbol{GetGenericInfo().symbol}; symbol && symbol->has()) { for (const auto &name : names) { specificsForGenericProcs_.emplace(symbol, std::make_pair(&name, kind)); @@ -4515,7 +4514,7 @@ void GenericHandler::DeclaredPossibleSpecificProc(Symbol &proc) { } void InterfaceVisitor::ResolveNewSpecifics() { - if (Symbol * generic{genericInfo_.top().symbol}; + if (Symbol *generic{genericInfo_.top().symbol}; generic && generic->has()) { ResolveSpecificsInGeneric(*generic, false); } @@ -4600,7 +4599,7 @@ bool SubprogramVisitor::HandleStmtFunction(const parser::StmtFunctionStmt &x) { name.source); MakeSymbol(name, Attrs{}, UnknownDetails{}); } else if (auto *entity{ultimate.detailsIf()}; - entity && !ultimate.has()) { + entity && !ultimate.has()) { resultType = entity->type(); ultimate.details() = UnknownDetails{}; // will be replaced below } else { @@ -4659,7 +4658,7 @@ bool SubprogramVisitor::Pre(const parser::Suffix &suffix) { } else { Message &msg{Say(*suffix.resultName, "RESULT(%s) may appear only in a function"_err_en_US)}; - if (const Symbol * subprogram{InclusiveScope().symbol()}) { + if (const Symbol *subprogram{InclusiveScope().symbol()}) { msg.Attach(subprogram->name(), "Containing subprogram"_en_US); } } @@ -5175,7 +5174,7 @@ Symbol *ScopeHandler::FindSeparateModuleProcedureInterface( symbol = generic->specific(); } } - if (const Symbol * defnIface{FindSeparateModuleSubprogramInterface(symbol)}) { + if (const Symbol *defnIface{FindSeparateModuleSubprogramInterface(symbol)}) { // Error recovery in case of multiple definitions symbol = const_cast(defnIface); } @@ -5314,8 +5313,8 @@ bool SubprogramVisitor::HandlePreviousCalls( return generic->specific() && HandlePreviousCalls(name, *generic->specific(), subpFlag); } else if (const auto *proc{symbol.detailsIf()}; proc && - !proc->isDummy() && - !symbol.attrs().HasAny(Attrs{Attr::INTRINSIC, Attr::POINTER})) { + !proc->isDummy() && + !symbol.attrs().HasAny(Attrs{Attr::INTRINSIC, Attr::POINTER})) { // There's a symbol created for previous calls to this subprogram or // ENTRY's name. We have to replace that symbol in situ to avoid the // obligation to rewrite symbol pointers in the parse tree. @@ -5357,7 +5356,7 @@ const Symbol *SubprogramVisitor::CheckExtantProc( if (prev) { if (IsDummy(*prev)) { } else if (auto *entity{prev->detailsIf()}; - IsPointer(*prev) && entity && !entity->type()) { + IsPointer(*prev) && entity && !entity->type()) { // POINTER attribute set before interface } else if (inInterfaceBlock() && currScope() != prev->owner()) { // Procedures in an INTERFACE block do not resolve to symbols @@ -5429,7 +5428,7 @@ Symbol *SubprogramVisitor::PushSubprogramScope(const parser::Name &name, } set_inheritFromParent(false); // interfaces don't inherit, even if MODULE } - if (Symbol * found{FindSymbol(name)}; + if (Symbol *found{FindSymbol(name)}; found && found->has()) { found->set(subpFlag); // PushScope() created symbol } @@ -6280,9 +6279,9 @@ void DeclarationVisitor::Post(const parser::VectorTypeSpec &x) { vectorDerivedType.CookParameters(GetFoldingContext()); } - if (const DeclTypeSpec * - extant{ppcBuiltinTypesScope->FindInstantiatedDerivedType( - vectorDerivedType, DeclTypeSpec::Category::TypeDerived)}) { + if (const DeclTypeSpec *extant{ + ppcBuiltinTypesScope->FindInstantiatedDerivedType( + vectorDerivedType, DeclTypeSpec::Category::TypeDerived)}) { // This derived type and parameter expressions (if any) are already present // in the __ppc_intrinsics scope. SetDeclTypeSpec(*extant); @@ -6304,7 +6303,7 @@ bool DeclarationVisitor::Pre(const parser::DeclarationTypeSpec::Type &) { void DeclarationVisitor::Post(const parser::DeclarationTypeSpec::Type &type) { const parser::Name &derivedName{std::get(type.derived.t)}; - if (const Symbol * derivedSymbol{derivedName.symbol}) { + if (const Symbol *derivedSymbol{derivedName.symbol}) { CheckForAbstractType(*derivedSymbol); // C706 } } @@ -6373,8 +6372,8 @@ void DeclarationVisitor::Post(const parser::DerivedTypeSpec &x) { if (!spec->MightBeParameterized()) { spec->EvaluateParameters(context()); } - if (const DeclTypeSpec * - extant{currScope().FindInstantiatedDerivedType(*spec, category)}) { + if (const DeclTypeSpec *extant{ + currScope().FindInstantiatedDerivedType(*spec, category)}) { // This derived type and parameter expressions (if any) are already present // in this scope. SetDeclTypeSpec(*extant); @@ -6405,8 +6404,7 @@ void DeclarationVisitor::Post(const parser::DeclarationTypeSpec::Record &rec) { if (auto spec{ResolveDerivedType(typeName)}) { spec->CookParameters(GetFoldingContext()); spec->EvaluateParameters(context()); - if (const DeclTypeSpec * - extant{currScope().FindInstantiatedDerivedType( + if (const DeclTypeSpec *extant{currScope().FindInstantiatedDerivedType( *spec, DeclTypeSpec::TypeDerived)}) { SetDeclTypeSpec(*extant); } else { @@ -7417,7 +7415,7 @@ bool DeclarationVisitor::PassesLocalityChecks( "Coarray '%s' not allowed in a %s locality-spec"_err_en_US, specName); return false; } - if (const DeclTypeSpec * type{symbol.GetType()}) { + if (const DeclTypeSpec *type{symbol.GetType()}) { if (type->IsPolymorphic() && IsDummy(symbol) && !IsPointer(symbol) && !isReduce) { // F'2023 C1130 SayWithDecl(name, symbol, @@ -7644,7 +7642,7 @@ Symbol *DeclarationVisitor::NoteInterfaceName(const parser::Name &name) { } void DeclarationVisitor::CheckExplicitInterface(const parser::Name &name) { - if (const Symbol * symbol{name.symbol}) { + if (const Symbol *symbol{name.symbol}) { const Symbol &ultimate{symbol->GetUltimate()}; if (!context().HasError(*symbol) && !context().HasError(ultimate) && !BypassGeneric(ultimate).HasExplicitInterface()) { @@ -7963,7 +7961,7 @@ bool ConstructVisitor::Pre(const parser::DataStmtValue &x) { auto &mutableData{const_cast(data)}; if (auto *elem{parser::Unwrap(mutableData)}) { if (const auto *name{std::get_if(&elem->base.u)}) { - if (const Symbol * symbol{FindSymbol(*name)}; + if (const Symbol *symbol{FindSymbol(*name)}; symbol && symbol->GetUltimate().has()) { mutableData.u = elem->ConvertToStructureConstructor( DerivedTypeSpec{name->source, *symbol}); @@ -8109,15 +8107,15 @@ void ConstructVisitor::Post(const parser::SelectTypeStmt &x) { } } } else { - if (const Symbol * - whole{UnwrapWholeSymbolDataRef(association.selector.expr)}) { + if (const Symbol *whole{ + UnwrapWholeSymbolDataRef(association.selector.expr)}) { ConvertToObjectEntity(const_cast(*whole)); if (!IsVariableName(*whole)) { Say(association.selector.source, // C901 "Selector is not a variable"_err_en_US); association = {}; } - if (const DeclTypeSpec * type{whole->GetType()}) { + if (const DeclTypeSpec *type{whole->GetType()}) { if (!type->IsPolymorphic()) { // C1159 Say(association.selector.source, "Selector '%s' in SELECT TYPE statement must be " @@ -8257,8 +8255,8 @@ Symbol *ConstructVisitor::MakeAssocEntity() { "The associate name '%s' is already used in this associate statement"_err_en_US); return nullptr; } - } else if (const Symbol * - whole{UnwrapWholeSymbolDataRef(association.selector.expr)}) { + } else if (const Symbol *whole{ + UnwrapWholeSymbolDataRef(association.selector.expr)}) { symbol = &MakeSymbol(whole->name()); } else { return nullptr; @@ -8878,7 +8876,7 @@ bool DeclarationVisitor::CheckForHostAssociatedImplicit( if (name.symbol) { ApplyImplicitRules(*name.symbol, true); } - if (Scope * host{GetHostProcedure()}; host && !isImplicitNoneType(*host)) { + if (Scope *host{GetHostProcedure()}; host && !isImplicitNoneType(*host)) { Symbol *hostSymbol{nullptr}; if (!name.symbol) { if (currScope().CanImport(name.source)) { @@ -8949,7 +8947,7 @@ const parser::Name *DeclarationVisitor::FindComponent( if (!type) { return nullptr; // should have already reported error } - if (const IntrinsicTypeSpec * intrinsic{type->AsIntrinsic()}) { + if (const IntrinsicTypeSpec *intrinsic{type->AsIntrinsic()}) { auto category{intrinsic->category()}; MiscDetails::Kind miscKind{MiscDetails::Kind::None}; if (component.source == "kind") { @@ -8971,7 +8969,7 @@ const parser::Name *DeclarationVisitor::FindComponent( } } else if (DerivedTypeSpec * derived{type->AsDerived()}) { derived->Instantiate(currScope()); // in case of forward referenced type - if (const Scope * scope{derived->scope()}) { + if (const Scope *scope{derived->scope()}) { if (Resolve(component, scope->FindComponent(component.source))) { if (auto msg{CheckAccessibleSymbol(currScope(), *component.symbol)}) { context().Say(component.source, *msg); @@ -9122,8 +9120,8 @@ void DeclarationVisitor::PointerInitialization( if (evaluate::IsNullProcedurePointer(&*expr)) { CHECK(!details->init()); details->set_init(nullptr); - } else if (const Symbol * - targetSymbol{evaluate::UnwrapWholeSymbolDataRef(*expr)}) { + } else if (const Symbol *targetSymbol{ + evaluate::UnwrapWholeSymbolDataRef(*expr)}) { CHECK(!details->init()); details->set_init(*targetSymbol); } else { @@ -9692,7 +9690,7 @@ void ResolveNamesVisitor::EarlyDummyTypeDeclaration( for (const auto &ent : entities) { const auto &objName{std::get(ent.t)}; Resolve(objName, FindInScope(currScope(), objName)); - if (Symbol * symbol{objName.symbol}; + if (Symbol *symbol{objName.symbol}; symbol && IsDummy(*symbol) && NeedsType(*symbol)) { if (!type) { type = ProcessTypeSpec(declTypeSpec); @@ -9831,7 +9829,7 @@ void ResolveNamesVisitor::FinishSpecificationPart( if (auto *proc{symbol.detailsIf()}; proc && !proc->isDummy() && !IsPointer(symbol) && !symbol.attrs().test(Attr::BIND_C)) { - if (const Symbol * iface{proc->procInterface()}; + if (const Symbol *iface{proc->procInterface()}; iface && IsBindCProcedure(*iface)) { SetImplicitAttr(symbol, Attr::BIND_C); SetBindNameOn(symbol); @@ -9964,7 +9962,7 @@ bool ResolveNamesVisitor::Pre(const parser::PointerAssignmentStmt &x) { Symbol *ptrSymbol{parser::GetLastName(dataRef).symbol}; Walk(bounds); // Resolve unrestricted specific intrinsic procedures as in "p => cos". - if (const parser::Name * name{parser::Unwrap(expr)}) { + if (const parser::Name *name{parser::Unwrap(expr)}) { if (NameIsKnownOrIntrinsic(*name)) { if (Symbol * symbol{name->symbol}) { if (IsProcedurePointer(ptrSymbol) && @@ -10411,8 +10409,8 @@ void ResolveNamesVisitor::ResolveSpecificationParts(ProgramTree &node) { // implied SAVE so that evaluate::IsSaved() will return true. if (node.scope()->kind() == Scope::Kind::MainProgram) { if (const auto *object{symbol.detailsIf()}) { - if (const DeclTypeSpec * type{object->type()}) { - if (const DerivedTypeSpec * derived{type->AsDerived()}) { + if (const DeclTypeSpec *type{object->type()}) { + if (const DerivedTypeSpec *derived{type->AsDerived()}) { if (!IsSaved(symbol) && FindCoarrayPotentialComponent(*derived)) { SetImplicitAttr(symbol, Attr::SAVE); } @@ -10669,7 +10667,7 @@ void ResolveNamesVisitor::FinishDerivedTypeInstantiation(Scope &scope) { if (DerivedTypeSpec * spec{scope.derivedTypeSpec()}) { spec->Instantiate(currScope()); const Symbol &origTypeSymbol{spec->typeSymbol()}; - if (const Scope * origTypeScope{origTypeSymbol.scope()}) { + if (const Scope *origTypeScope{origTypeSymbol.scope()}) { CHECK(origTypeScope->IsDerivedType() && origTypeScope->symbol() == &origTypeSymbol); auto &foldingContext{GetFoldingContext()}; @@ -10680,7 +10678,7 @@ void ResolveNamesVisitor::FinishDerivedTypeInstantiation(Scope &scope) { if (IsPointer(comp)) { if (auto *details{comp.detailsIf()}) { auto origDetails{origComp.get()}; - if (const MaybeExpr & init{origDetails.init()}) { + if (const MaybeExpr &init{origDetails.init()}) { SomeExpr newInit{*init}; MaybeExpr folded{FoldExpr(std::move(newInit))}; details->set_init(std::move(folded)); From 6e233523308d9e9ed07f4cbf8b3751243ae8178f Mon Sep 17 00:00:00 2001 From: Akash Banerjee Date: Wed, 22 Oct 2025 22:36:10 +0100 Subject: [PATCH 3/5] Emit declare_mapper to .mod file. Update test to check separate module and program file compilation. --- flang/include/flang/Lower/OpenMP.h | 7 +++ flang/include/flang/Semantics/symbol.h | 20 ++++++- flang/lib/Lower/Bridge.cpp | 7 +++ flang/lib/Lower/OpenMP/OpenMP.cpp | 55 +++++++++++++++++-- flang/lib/Semantics/mod-file.cpp | 12 ++++ flang/lib/Semantics/resolve-names.cpp | 29 +++++++--- flang/lib/Semantics/symbol.cpp | 6 +- flang/test/Lower/OpenMP/declare-mapper.f90 | 13 +++-- .../OpenMP/declare-mapper-symbols.f90 | 5 +- 9 files changed, 129 insertions(+), 25 deletions(-) diff --git a/flang/include/flang/Lower/OpenMP.h b/flang/include/flang/Lower/OpenMP.h index df01a7b82c66c..962abd8952073 100644 --- a/flang/include/flang/Lower/OpenMP.h +++ b/flang/include/flang/Lower/OpenMP.h @@ -97,6 +97,13 @@ bool markOpenMPDeferredDeclareTargetFunctions( AbstractConverter &); void genOpenMPRequires(mlir::Operation *, const Fortran::semantics::Symbol *); +// Materialize omp.declare_mapper ops for mapper declarations found in +// imported modules. If \p scope is null, materialize for the whole +// semantics global scope; otherwise, operate recursively starting at \p scope. +void materializeOpenMPDeclareMappers( + Fortran::lower::AbstractConverter &, Fortran::semantics::SemanticsContext &, + const Fortran::semantics::Scope *scope = nullptr); + } // namespace lower } // namespace Fortran diff --git a/flang/include/flang/Semantics/symbol.h b/flang/include/flang/Semantics/symbol.h index cb27d544ed9f5..95efe1ae2bd5e 100644 --- a/flang/include/flang/Semantics/symbol.h +++ b/flang/include/flang/Semantics/symbol.h @@ -777,6 +777,24 @@ class UserReductionDetails { DeclVector declList_; }; +// Used for OpenMP DECLARE MAPPER, it holds the declaration constructs +// so they can be serialized into module files and later re-parsed when +// USE-associated. +class MapperDetails { +public: + using DeclVector = std::vector; + + MapperDetails() = default; + + void AddDecl(const parser::OpenMPDeclarativeConstruct *decl) { + declList_.emplace_back(decl); + } + const DeclVector &GetDeclList() const { return declList_; } + +private: + DeclVector declList_; +}; + class UnknownDetails {}; using Details = std::variant; + TypeParamDetails, MiscDetails, UserReductionDetails, MapperDetails>; llvm::raw_ostream &operator<<(llvm::raw_ostream &, const Details &); std::string DetailsToString(const Details &); diff --git a/flang/lib/Lower/Bridge.cpp b/flang/lib/Lower/Bridge.cpp index 6e729874eb5e6..484aecdbed0a5 100644 --- a/flang/lib/Lower/Bridge.cpp +++ b/flang/lib/Lower/Bridge.cpp @@ -448,6 +448,13 @@ class FirConverter : public Fortran::lower::AbstractConverter { } }); + // Ensure imported OpenMP declare mappers are materialized at module + // scope before lowering any constructs that may reference them. + createBuilderOutsideOfFuncOpAndDo([&]() { + Fortran::lower::materializeOpenMPDeclareMappers( + *this, bridge.getSemanticsContext()); + }); + // Create definitions of intrinsic module constants. createBuilderOutsideOfFuncOpAndDo( [&]() { createIntrinsicModuleDefinitions(pft); }); diff --git a/flang/lib/Lower/OpenMP/OpenMP.cpp b/flang/lib/Lower/OpenMP/OpenMP.cpp index 71067283d13f7..a2af38a47b4b6 100644 --- a/flang/lib/Lower/OpenMP/OpenMP.cpp +++ b/flang/lib/Lower/OpenMP/OpenMP.cpp @@ -3543,10 +3543,10 @@ genOMP(lower::AbstractConverter &converter, lower::SymMap &symTable, TODO(converter.getCurrentLocation(), "OpenMPDeclareSimdConstruct"); } -static void genOMP(lower::AbstractConverter &converter, lower::SymMap &symTable, - semantics::SemanticsContext &semaCtx, - lower::pft::Evaluation &eval, - const parser::OpenMPDeclareMapperConstruct &construct) { +static void genOpenMPDeclareMapperImpl( + lower::AbstractConverter &converter, semantics::SemanticsContext &semaCtx, + const parser::OpenMPDeclareMapperConstruct &construct, + const semantics::Symbol *mapperSymOpt = nullptr) { mlir::Location loc = converter.genLocation(construct.source); fir::FirOpBuilder &firOpBuilder = converter.getFirOpBuilder(); const parser::OmpArgumentList &args = construct.v.Arguments(); @@ -3562,8 +3562,17 @@ static void genOMP(lower::AbstractConverter &converter, lower::SymMap &symTable, "Expected derived type"); std::string mapperNameStr = mapperName; - if (auto *sym = converter.getCurrentScope().FindSymbol(mapperNameStr)) + if (mapperSymOpt && mapperNameStr != "default") { + mapperNameStr = converter.mangleName(mapperNameStr, mapperSymOpt->owner()); + } else if (auto *sym = + converter.getCurrentScope().FindSymbol(mapperNameStr)) { mapperNameStr = converter.mangleName(mapperNameStr, sym->owner()); + } + + // If the mapper op already exists (e.g., created by regular lowering), + // do not recreate it. + if (converter.getModuleOp().lookupSymbol(mapperNameStr)) + return; // Save current insertion point before moving to the module scope to create // the DeclareMapperOp @@ -3586,6 +3595,13 @@ static void genOMP(lower::AbstractConverter &converter, lower::SymMap &symTable, mlir::omp::DeclareMapperInfoOp::create(firOpBuilder, loc, clauseOps.mapVars); } +static void genOMP(lower::AbstractConverter &converter, lower::SymMap &symTable, + semantics::SemanticsContext &semaCtx, + lower::pft::Evaluation &eval, + const parser::OpenMPDeclareMapperConstruct &construct) { + genOpenMPDeclareMapperImpl(converter, semaCtx, construct); +} + static void genOMP(lower::AbstractConverter &converter, lower::SymMap &symTable, semantics::SemanticsContext &semaCtx, lower::pft::Evaluation &eval, @@ -4229,3 +4245,32 @@ void Fortran::lower::genOpenMPRequires(mlir::Operation *mod, offloadMod.setRequires(mlirFlags); } } + +// Walk scopes and materialize omp.declare_mapper ops for mapper declarations +// found in imported modules. If \p scope is null, start from the global scope. +void Fortran::lower::materializeOpenMPDeclareMappers( + Fortran::lower::AbstractConverter &converter, + semantics::SemanticsContext &semaCtx, const semantics::Scope *scope) { + const semantics::Scope &root = scope ? *scope : semaCtx.globalScope(); + + // Recurse into child scopes first (modules, submodules, etc.). + for (const semantics::Scope &child : root.children()) + materializeOpenMPDeclareMappers(converter, semaCtx, &child); + + // Only consider module scopes to avoid duplicating local constructs. + if (!root.IsModule()) + return; + + // Scan symbols in this module scope for MapperDetails. + for (auto &it : root) { + const semantics::Symbol &sym = *it.second; + if (auto *md = sym.detailsIf()) { + for (const auto *decl : md->GetDeclList()) { + if (const auto *mapperDecl = + std::get_if(&decl->u)) { + genOpenMPDeclareMapperImpl(converter, semaCtx, *mapperDecl, &sym); + } + } + } + } +} diff --git a/flang/lib/Semantics/mod-file.cpp b/flang/lib/Semantics/mod-file.cpp index b419864f73b8e..840b98dd42139 100644 --- a/flang/lib/Semantics/mod-file.cpp +++ b/flang/lib/Semantics/mod-file.cpp @@ -59,6 +59,7 @@ static void PutBound(llvm::raw_ostream &, const Bound &); static void PutShapeSpec(llvm::raw_ostream &, const ShapeSpec &); static void PutShape( llvm::raw_ostream &, const ArraySpec &, char open, char close); +static void PutMapper(llvm::raw_ostream &, const Symbol &, SemanticsContext &); static llvm::raw_ostream &PutAttr(llvm::raw_ostream &, Attr); static llvm::raw_ostream &PutType(llvm::raw_ostream &, const DeclTypeSpec &); @@ -938,6 +939,7 @@ void ModFileWriter::PutEntity(llvm::raw_ostream &os, const Symbol &symbol) { [&](const ProcEntityDetails &) { PutProcEntity(os, symbol); }, [&](const TypeParamDetails &) { PutTypeParam(os, symbol); }, [&](const UserReductionDetails &) { PutUserReduction(os, symbol); }, + [&](const MapperDetails &) { PutMapper(decls_, symbol, context_); }, [&](const auto &) { common::die("PutEntity: unexpected details: %s", DetailsToString(symbol.details()).c_str()); @@ -1101,6 +1103,16 @@ void ModFileWriter::PutUserReduction( } } +static void PutMapper( + llvm::raw_ostream &os, const Symbol &symbol, SemanticsContext &context) { + const auto &details{symbol.get()}; + // Emit each saved DECLARE MAPPER construct as-is, so that consumers of the + // module can reparse it and recreate the mapper symbol and semantics state. + for (const auto *decl : details.GetDeclList()) { + Unparse(os, *decl, context.langOptions()); + } +} + void PutInit(llvm::raw_ostream &os, const Symbol &symbol, const MaybeExpr &init, const parser::Expr *unanalyzed, SemanticsContext &context) { if (IsNamedConstant(symbol) || symbol.owner().IsDerivedType()) { diff --git a/flang/lib/Semantics/resolve-names.cpp b/flang/lib/Semantics/resolve-names.cpp index 1944b856df2d7..3fdeb3155cb8c 100644 --- a/flang/lib/Semantics/resolve-names.cpp +++ b/flang/lib/Semantics/resolve-names.cpp @@ -1852,8 +1852,10 @@ bool OmpVisitor::Pre(const parser::OmpMapClause &x) { // TODO: Do we need a specific flag or type here, to distinghuish against // other ConstructName things? Leaving this for the full implementation // of mapper lowering. - auto *misc{symbol->GetUltimate().detailsIf()}; - if (!misc || misc->kind() != MiscDetails::Kind::ConstructName) + auto &ultimate{symbol->GetUltimate()}; + auto *misc{ultimate.detailsIf()}; + auto *md{ultimate.detailsIf()}; + if (!md && (!misc || misc->kind() != MiscDetails::Kind::ConstructName)) context().Say(mapper->v.source, "Name '%s' should be a mapper name"_err_en_US, mapper->v.source); else @@ -1882,8 +1884,15 @@ void OmpVisitor::ProcessMapperSpecifier(const parser::OmpMapperSpecifier &spec, // the type has been fully processed. BeginDeclTypeSpec(); auto &mapperName{std::get(spec.t)}; - MakeSymbol(parser::CharBlock(mapperName), Attrs{}, - MiscDetails{MiscDetails::Kind::ConstructName}); + // Create or update the mapper symbol with MapperDetails and + // keep track of the declarative construct for module emission. + Symbol &mapperSym{MakeSymbol(parser::CharBlock(mapperName), Attrs{})}; + if (auto *md{mapperSym.detailsIf()}) { + md->AddDecl(declaratives_.back()); + } else if (mapperSym.has() || mapperSym.has()) { + mapperSym.set_details(MapperDetails{}); + mapperSym.get().AddDecl(declaratives_.back()); + } PushScope(Scope::Kind::OtherConstruct, nullptr); Walk(std::get(spec.t)); auto &varName{std::get(spec.t)}; @@ -3614,11 +3623,13 @@ void ModuleVisitor::Post(const parser::UseStmt &x) { } for (const auto &[name, symbol] : *useModuleScope_) { // Default USE imports public names, excluding intrinsic-only and most - // miscellaneous details. However, allow OpenMP mapper identifiers, - // which are currently represented with MiscDetails::ConstructName. - bool isMapper{false}; - if (const auto *misc{symbol->detailsIf()}) { - isMapper = misc->kind() == MiscDetails::Kind::ConstructName; + // miscellaneous details. Allow OpenMP mapper identifiers represented + // as MapperDetails, and also legacy MiscDetails::ConstructName. + bool isMapper{symbol->has()}; + if (!isMapper) { + if (const auto *misc{symbol->detailsIf()}) { + isMapper = misc->kind() == MiscDetails::Kind::ConstructName; + } } if (symbol->attrs().test(Attr::PUBLIC) && !IsUseRenamed(symbol->name()) && (!symbol->implicitAttrs().test(Attr::INTRINSIC) || diff --git a/flang/lib/Semantics/symbol.cpp b/flang/lib/Semantics/symbol.cpp index 0ec44b7c40491..ed0715a422e78 100644 --- a/flang/lib/Semantics/symbol.cpp +++ b/flang/lib/Semantics/symbol.cpp @@ -338,7 +338,8 @@ std::string DetailsToString(const Details &details) { [](const TypeParamDetails &) { return "TypeParam"; }, [](const MiscDetails &) { return "Misc"; }, [](const AssocEntityDetails &) { return "AssocEntity"; }, - [](const UserReductionDetails &) { return "UserReductionDetails"; }}, + [](const UserReductionDetails &) { return "UserReductionDetails"; }, + [](const MapperDetails &) { return "MapperDetails"; }}, details); } @@ -379,6 +380,7 @@ bool Symbol::CanReplaceDetails(const Details &details) const { [&](const UserReductionDetails &) { return has(); }, + [&](const MapperDetails &) { return has(); }, [](const auto &) { return false; }, }, details); @@ -685,6 +687,8 @@ llvm::raw_ostream &operator<<(llvm::raw_ostream &os, const Details &details) { DumpType(os, type); } }, + // Avoid recursive streaming for MapperDetails; nothing more to dump + [&](const MapperDetails &) {}, [&](const auto &x) { os << x; }, }, details); diff --git a/flang/test/Lower/OpenMP/declare-mapper.f90 b/flang/test/Lower/OpenMP/declare-mapper.f90 index 2ed1e2e4c942e..e4c010156ee39 100644 --- a/flang/test/Lower/OpenMP/declare-mapper.f90 +++ b/flang/test/Lower/OpenMP/declare-mapper.f90 @@ -7,7 +7,8 @@ ! RUN: %flang_fc1 -emit-hlfir -fopenmp -fopenmp-version=50 %t/omp-declare-mapper-4.f90 -o - | FileCheck %t/omp-declare-mapper-4.f90 ! RUN: %flang_fc1 -emit-hlfir -fopenmp -fopenmp-version=50 %t/omp-declare-mapper-5.f90 -o - | FileCheck %t/omp-declare-mapper-5.f90 ! RUN: %flang_fc1 -emit-hlfir -fopenmp -fopenmp-version=50 %t/omp-declare-mapper-6.f90 -o - | FileCheck %t/omp-declare-mapper-6.f90 -! RUN: %flang_fc1 -emit-hlfir -fopenmp -fopenmp-version=50 %t/omp-declare-mapper-7.f90 -o - | FileCheck %t/omp-declare-mapper-7.f90 +! RUN: %flang_fc1 -emit-hlfir -fopenmp -fopenmp-version=50 -module-dir %t %t/omp-declare-mapper-7.mod.f90 -o - >/dev/null +! RUN: %flang_fc1 -emit-hlfir -fopenmp -fopenmp-version=50 -J %t %t/omp-declare-mapper-7.use.f90 -o - | FileCheck %t/omp-declare-mapper-7.use.f90 !--- omp-declare-mapper-1.f90 subroutine declare_mapper_1 @@ -303,8 +304,8 @@ subroutine declare_mapper_nested_parent !$omp end target end subroutine declare_mapper_nested_parent -!--- omp-declare-mapper-7.f90 -! Check mappers declared inside modules and used via USE association. +!--- omp-declare-mapper-7.mod.f90 +! Module with DECLARE MAPPER to be compiled separately module m_mod implicit none type :: mty @@ -313,13 +314,13 @@ module m_mod !$omp declare mapper(mymap : mty :: v) map(tofrom: v%x) end module m_mod +!--- omp-declare-mapper-7.use.f90 +! Consumer program that USEs the module and applies the mapper by name. +! CHECK: %{{.*}} = omp.map.info {{.*}} mapper(@{{.*mymap}}) {{.*}} {name = "a"} program use_module_mapper use m_mod implicit none type(mty) :: a - - ! CHECK: omp.declare_mapper @[[MODMAP:[^ ]*mymap]] - ! CHECK: %{{.*}} = omp.map.info {{.*}} mapper(@[[MODMAP]]) {{.*}} {name = "a"} !$omp target map(mapper(mymap) : a) a%x = 42 !$omp end target diff --git a/flang/test/Semantics/OpenMP/declare-mapper-symbols.f90 b/flang/test/Semantics/OpenMP/declare-mapper-symbols.f90 index e57a5c0c1cea6..5d77540aa6453 100644 --- a/flang/test/Semantics/OpenMP/declare-mapper-symbols.f90 +++ b/flang/test/Semantics/OpenMP/declare-mapper-symbols.f90 @@ -11,9 +11,9 @@ program main !$omp declare mapper(ty :: maptwo) map(maptwo, maptwo%x) !! Note, symbols come out in their respective scope, but not in declaration order. -!CHECK: mymapper: Misc ConstructName +!CHECK: mymapper: MapperDetails !CHECK: ty: DerivedType components: x -!CHECK: ty.omp.default.mapper: Misc ConstructName +!CHECK: ty.omp.default.mapper: MapperDetails !CHECK: DerivedType scope: ty !CHECK: OtherConstruct scope: !CHECK: mapped (OmpMapToFrom) {{.*}} ObjectEntity type: TYPE(ty) @@ -21,4 +21,3 @@ program main !CHECK: maptwo (OmpMapToFrom) {{.*}} ObjectEntity type: TYPE(ty) end program main - From 672eb0ef3605fd6c286396eae59da60540aab9eb Mon Sep 17 00:00:00 2001 From: Akash Banerjee Date: Fri, 24 Oct 2025 19:31:51 +0100 Subject: [PATCH 4/5] Address reviewer comments. Add test to check declare mapper export to .mod file. --- flang/lib/Lower/OpenMP/OpenMP.cpp | 8 ++ flang/lib/Semantics/resolve-names.cpp | 89 ++++++++++--------- .../OpenMP/declare-mapper-modfile.f90 | 14 +++ .../Semantics/OpenMP/map-clause-symbols.f90 | 14 +-- 4 files changed, 76 insertions(+), 49 deletions(-) create mode 100644 flang/test/Semantics/OpenMP/declare-mapper-modfile.f90 diff --git a/flang/lib/Lower/OpenMP/OpenMP.cpp b/flang/lib/Lower/OpenMP/OpenMP.cpp index a2af38a47b4b6..e911af92bfdf6 100644 --- a/flang/lib/Lower/OpenMP/OpenMP.cpp +++ b/flang/lib/Lower/OpenMP/OpenMP.cpp @@ -4261,6 +4261,14 @@ void Fortran::lower::materializeOpenMPDeclareMappers( if (!root.IsModule()) return; + // Only materialize for modules coming from mod files to avoid duplicates. + if (const semantics::Symbol *modSym = root.symbol()) { + if (!modSym->test(semantics::Symbol::Flag::ModFile)) + return; + } else { + return; + } + // Scan symbols in this module scope for MapperDetails. for (auto &it : root) { const semantics::Symbol &sym = *it.second; diff --git a/flang/lib/Semantics/resolve-names.cpp b/flang/lib/Semantics/resolve-names.cpp index 3fdeb3155cb8c..faa158f88d058 100644 --- a/flang/lib/Semantics/resolve-names.cpp +++ b/flang/lib/Semantics/resolve-names.cpp @@ -2381,7 +2381,7 @@ void AttrsVisitor::SetBindNameOn(Symbol &symbol) { } symbol.SetBindName(std::move(*label)); if (!oldBindName.empty()) { - if (const std::string *newBindName{symbol.GetBindName()}) { + if (const std::string * newBindName{symbol.GetBindName()}) { if (oldBindName != *newBindName) { Say(symbol.name(), "The entity '%s' has multiple BIND names ('%s' and '%s')"_err_en_US, @@ -2507,7 +2507,7 @@ void DeclTypeSpecVisitor::Post(const parser::TypeSpec &typeSpec) { // expression semantics if the DeclTypeSpec is a valid TypeSpec. // The grammar ensures that it's an intrinsic or derived type spec, // not TYPE(*) or CLASS(*) or CLASS(T). - if (const DeclTypeSpec *spec{state_.declTypeSpec}) { + if (const DeclTypeSpec * spec{state_.declTypeSpec}) { switch (spec->category()) { case DeclTypeSpec::Numeric: case DeclTypeSpec::Logical: @@ -2515,7 +2515,7 @@ void DeclTypeSpecVisitor::Post(const parser::TypeSpec &typeSpec) { typeSpec.declTypeSpec = spec; break; case DeclTypeSpec::TypeDerived: - if (const DerivedTypeSpec *derived{spec->AsDerived()}) { + if (const DerivedTypeSpec * derived{spec->AsDerived()}) { CheckForAbstractType(derived->typeSymbol()); // C703 typeSpec.declTypeSpec = spec; } @@ -3106,8 +3106,8 @@ Symbol &ScopeHandler::MakeSymbol(const parser::Name &name, Attrs attrs) { Symbol &ScopeHandler::MakeHostAssocSymbol( const parser::Name &name, const Symbol &hostSymbol) { Symbol &symbol{*NonDerivedTypeScope() - .try_emplace(name.source, HostAssocDetails{hostSymbol}) - .first->second}; + .try_emplace(name.source, HostAssocDetails{hostSymbol}) + .first->second}; name.symbol = &symbol; symbol.attrs() = hostSymbol.attrs(); // TODO: except PRIVATE, PUBLIC? // These attributes can be redundantly reapplied without error @@ -3195,7 +3195,7 @@ void ScopeHandler::ApplyImplicitRules( if (context().HasError(symbol) || !NeedsType(symbol)) { return; } - if (const DeclTypeSpec *type{GetImplicitType(symbol)}) { + if (const DeclTypeSpec * type{GetImplicitType(symbol)}) { if (!skipImplicitTyping_) { symbol.set(Symbol::Flag::Implicit); symbol.SetType(*type); @@ -3295,7 +3295,7 @@ const DeclTypeSpec *ScopeHandler::GetImplicitType( const auto *type{implicitRulesMap_->at(scope).GetType( symbol.name(), respectImplicitNoneType)}; if (type) { - if (const DerivedTypeSpec *derived{type->AsDerived()}) { + if (const DerivedTypeSpec * derived{type->AsDerived()}) { // Resolve any forward-referenced derived type; a quick no-op else. auto &instantiatable{*const_cast(derived)}; instantiatable.Instantiate(currScope()); @@ -4320,7 +4320,7 @@ Scope *ModuleVisitor::FindModule(const parser::Name &name, if (scope) { if (DoesScopeContain(scope, currScope())) { // 14.2.2(1) std::optional submoduleName; - if (const Scope *container{FindModuleOrSubmoduleContaining(currScope())}; + if (const Scope * container{FindModuleOrSubmoduleContaining(currScope())}; container && container->IsSubmodule()) { submoduleName = container->GetName(); } @@ -4425,7 +4425,7 @@ bool InterfaceVisitor::isAbstract() const { void InterfaceVisitor::AddSpecificProcs( const std::list &names, ProcedureKind kind) { - if (Symbol *symbol{GetGenericInfo().symbol}; + if (Symbol * symbol{GetGenericInfo().symbol}; symbol && symbol->has()) { for (const auto &name : names) { specificsForGenericProcs_.emplace(symbol, std::make_pair(&name, kind)); @@ -4525,7 +4525,7 @@ void GenericHandler::DeclaredPossibleSpecificProc(Symbol &proc) { } void InterfaceVisitor::ResolveNewSpecifics() { - if (Symbol *generic{genericInfo_.top().symbol}; + if (Symbol * generic{genericInfo_.top().symbol}; generic && generic->has()) { ResolveSpecificsInGeneric(*generic, false); } @@ -4610,7 +4610,7 @@ bool SubprogramVisitor::HandleStmtFunction(const parser::StmtFunctionStmt &x) { name.source); MakeSymbol(name, Attrs{}, UnknownDetails{}); } else if (auto *entity{ultimate.detailsIf()}; - entity && !ultimate.has()) { + entity && !ultimate.has()) { resultType = entity->type(); ultimate.details() = UnknownDetails{}; // will be replaced below } else { @@ -4669,7 +4669,7 @@ bool SubprogramVisitor::Pre(const parser::Suffix &suffix) { } else { Message &msg{Say(*suffix.resultName, "RESULT(%s) may appear only in a function"_err_en_US)}; - if (const Symbol *subprogram{InclusiveScope().symbol()}) { + if (const Symbol * subprogram{InclusiveScope().symbol()}) { msg.Attach(subprogram->name(), "Containing subprogram"_en_US); } } @@ -5185,7 +5185,7 @@ Symbol *ScopeHandler::FindSeparateModuleProcedureInterface( symbol = generic->specific(); } } - if (const Symbol *defnIface{FindSeparateModuleSubprogramInterface(symbol)}) { + if (const Symbol * defnIface{FindSeparateModuleSubprogramInterface(symbol)}) { // Error recovery in case of multiple definitions symbol = const_cast(defnIface); } @@ -5324,8 +5324,8 @@ bool SubprogramVisitor::HandlePreviousCalls( return generic->specific() && HandlePreviousCalls(name, *generic->specific(), subpFlag); } else if (const auto *proc{symbol.detailsIf()}; proc && - !proc->isDummy() && - !symbol.attrs().HasAny(Attrs{Attr::INTRINSIC, Attr::POINTER})) { + !proc->isDummy() && + !symbol.attrs().HasAny(Attrs{Attr::INTRINSIC, Attr::POINTER})) { // There's a symbol created for previous calls to this subprogram or // ENTRY's name. We have to replace that symbol in situ to avoid the // obligation to rewrite symbol pointers in the parse tree. @@ -5367,7 +5367,7 @@ const Symbol *SubprogramVisitor::CheckExtantProc( if (prev) { if (IsDummy(*prev)) { } else if (auto *entity{prev->detailsIf()}; - IsPointer(*prev) && entity && !entity->type()) { + IsPointer(*prev) && entity && !entity->type()) { // POINTER attribute set before interface } else if (inInterfaceBlock() && currScope() != prev->owner()) { // Procedures in an INTERFACE block do not resolve to symbols @@ -5439,7 +5439,7 @@ Symbol *SubprogramVisitor::PushSubprogramScope(const parser::Name &name, } set_inheritFromParent(false); // interfaces don't inherit, even if MODULE } - if (Symbol *found{FindSymbol(name)}; + if (Symbol * found{FindSymbol(name)}; found && found->has()) { found->set(subpFlag); // PushScope() created symbol } @@ -6290,9 +6290,9 @@ void DeclarationVisitor::Post(const parser::VectorTypeSpec &x) { vectorDerivedType.CookParameters(GetFoldingContext()); } - if (const DeclTypeSpec *extant{ - ppcBuiltinTypesScope->FindInstantiatedDerivedType( - vectorDerivedType, DeclTypeSpec::Category::TypeDerived)}) { + if (const DeclTypeSpec * + extant{ppcBuiltinTypesScope->FindInstantiatedDerivedType( + vectorDerivedType, DeclTypeSpec::Category::TypeDerived)}) { // This derived type and parameter expressions (if any) are already present // in the __ppc_intrinsics scope. SetDeclTypeSpec(*extant); @@ -6314,7 +6314,7 @@ bool DeclarationVisitor::Pre(const parser::DeclarationTypeSpec::Type &) { void DeclarationVisitor::Post(const parser::DeclarationTypeSpec::Type &type) { const parser::Name &derivedName{std::get(type.derived.t)}; - if (const Symbol *derivedSymbol{derivedName.symbol}) { + if (const Symbol * derivedSymbol{derivedName.symbol}) { CheckForAbstractType(*derivedSymbol); // C706 } } @@ -6383,8 +6383,8 @@ void DeclarationVisitor::Post(const parser::DerivedTypeSpec &x) { if (!spec->MightBeParameterized()) { spec->EvaluateParameters(context()); } - if (const DeclTypeSpec *extant{ - currScope().FindInstantiatedDerivedType(*spec, category)}) { + if (const DeclTypeSpec * + extant{currScope().FindInstantiatedDerivedType(*spec, category)}) { // This derived type and parameter expressions (if any) are already present // in this scope. SetDeclTypeSpec(*extant); @@ -6415,7 +6415,8 @@ void DeclarationVisitor::Post(const parser::DeclarationTypeSpec::Record &rec) { if (auto spec{ResolveDerivedType(typeName)}) { spec->CookParameters(GetFoldingContext()); spec->EvaluateParameters(context()); - if (const DeclTypeSpec *extant{currScope().FindInstantiatedDerivedType( + if (const DeclTypeSpec * + extant{currScope().FindInstantiatedDerivedType( *spec, DeclTypeSpec::TypeDerived)}) { SetDeclTypeSpec(*extant); } else { @@ -7426,7 +7427,7 @@ bool DeclarationVisitor::PassesLocalityChecks( "Coarray '%s' not allowed in a %s locality-spec"_err_en_US, specName); return false; } - if (const DeclTypeSpec *type{symbol.GetType()}) { + if (const DeclTypeSpec * type{symbol.GetType()}) { if (type->IsPolymorphic() && IsDummy(symbol) && !IsPointer(symbol) && !isReduce) { // F'2023 C1130 SayWithDecl(name, symbol, @@ -7653,7 +7654,7 @@ Symbol *DeclarationVisitor::NoteInterfaceName(const parser::Name &name) { } void DeclarationVisitor::CheckExplicitInterface(const parser::Name &name) { - if (const Symbol *symbol{name.symbol}) { + if (const Symbol * symbol{name.symbol}) { const Symbol &ultimate{symbol->GetUltimate()}; if (!context().HasError(*symbol) && !context().HasError(ultimate) && !BypassGeneric(ultimate).HasExplicitInterface()) { @@ -7972,7 +7973,7 @@ bool ConstructVisitor::Pre(const parser::DataStmtValue &x) { auto &mutableData{const_cast(data)}; if (auto *elem{parser::Unwrap(mutableData)}) { if (const auto *name{std::get_if(&elem->base.u)}) { - if (const Symbol *symbol{FindSymbol(*name)}; + if (const Symbol * symbol{FindSymbol(*name)}; symbol && symbol->GetUltimate().has()) { mutableData.u = elem->ConvertToStructureConstructor( DerivedTypeSpec{name->source, *symbol}); @@ -8118,15 +8119,15 @@ void ConstructVisitor::Post(const parser::SelectTypeStmt &x) { } } } else { - if (const Symbol *whole{ - UnwrapWholeSymbolDataRef(association.selector.expr)}) { + if (const Symbol * + whole{UnwrapWholeSymbolDataRef(association.selector.expr)}) { ConvertToObjectEntity(const_cast(*whole)); if (!IsVariableName(*whole)) { Say(association.selector.source, // C901 "Selector is not a variable"_err_en_US); association = {}; } - if (const DeclTypeSpec *type{whole->GetType()}) { + if (const DeclTypeSpec * type{whole->GetType()}) { if (!type->IsPolymorphic()) { // C1159 Say(association.selector.source, "Selector '%s' in SELECT TYPE statement must be " @@ -8266,8 +8267,8 @@ Symbol *ConstructVisitor::MakeAssocEntity() { "The associate name '%s' is already used in this associate statement"_err_en_US); return nullptr; } - } else if (const Symbol *whole{ - UnwrapWholeSymbolDataRef(association.selector.expr)}) { + } else if (const Symbol * + whole{UnwrapWholeSymbolDataRef(association.selector.expr)}) { symbol = &MakeSymbol(whole->name()); } else { return nullptr; @@ -8887,7 +8888,7 @@ bool DeclarationVisitor::CheckForHostAssociatedImplicit( if (name.symbol) { ApplyImplicitRules(*name.symbol, true); } - if (Scope *host{GetHostProcedure()}; host && !isImplicitNoneType(*host)) { + if (Scope * host{GetHostProcedure()}; host && !isImplicitNoneType(*host)) { Symbol *hostSymbol{nullptr}; if (!name.symbol) { if (currScope().CanImport(name.source)) { @@ -8958,7 +8959,7 @@ const parser::Name *DeclarationVisitor::FindComponent( if (!type) { return nullptr; // should have already reported error } - if (const IntrinsicTypeSpec *intrinsic{type->AsIntrinsic()}) { + if (const IntrinsicTypeSpec * intrinsic{type->AsIntrinsic()}) { auto category{intrinsic->category()}; MiscDetails::Kind miscKind{MiscDetails::Kind::None}; if (component.source == "kind") { @@ -8980,7 +8981,7 @@ const parser::Name *DeclarationVisitor::FindComponent( } } else if (DerivedTypeSpec * derived{type->AsDerived()}) { derived->Instantiate(currScope()); // in case of forward referenced type - if (const Scope *scope{derived->scope()}) { + if (const Scope * scope{derived->scope()}) { if (Resolve(component, scope->FindComponent(component.source))) { if (auto msg{CheckAccessibleSymbol(currScope(), *component.symbol)}) { context().Say(component.source, *msg); @@ -9131,8 +9132,8 @@ void DeclarationVisitor::PointerInitialization( if (evaluate::IsNullProcedurePointer(&*expr)) { CHECK(!details->init()); details->set_init(nullptr); - } else if (const Symbol *targetSymbol{ - evaluate::UnwrapWholeSymbolDataRef(*expr)}) { + } else if (const Symbol * + targetSymbol{evaluate::UnwrapWholeSymbolDataRef(*expr)}) { CHECK(!details->init()); details->set_init(*targetSymbol); } else { @@ -9701,7 +9702,7 @@ void ResolveNamesVisitor::EarlyDummyTypeDeclaration( for (const auto &ent : entities) { const auto &objName{std::get(ent.t)}; Resolve(objName, FindInScope(currScope(), objName)); - if (Symbol *symbol{objName.symbol}; + if (Symbol * symbol{objName.symbol}; symbol && IsDummy(*symbol) && NeedsType(*symbol)) { if (!type) { type = ProcessTypeSpec(declTypeSpec); @@ -9840,7 +9841,7 @@ void ResolveNamesVisitor::FinishSpecificationPart( if (auto *proc{symbol.detailsIf()}; proc && !proc->isDummy() && !IsPointer(symbol) && !symbol.attrs().test(Attr::BIND_C)) { - if (const Symbol *iface{proc->procInterface()}; + if (const Symbol * iface{proc->procInterface()}; iface && IsBindCProcedure(*iface)) { SetImplicitAttr(symbol, Attr::BIND_C); SetBindNameOn(symbol); @@ -9973,7 +9974,7 @@ bool ResolveNamesVisitor::Pre(const parser::PointerAssignmentStmt &x) { Symbol *ptrSymbol{parser::GetLastName(dataRef).symbol}; Walk(bounds); // Resolve unrestricted specific intrinsic procedures as in "p => cos". - if (const parser::Name *name{parser::Unwrap(expr)}) { + if (const parser::Name * name{parser::Unwrap(expr)}) { if (NameIsKnownOrIntrinsic(*name)) { if (Symbol * symbol{name->symbol}) { if (IsProcedurePointer(ptrSymbol) && @@ -10420,8 +10421,8 @@ void ResolveNamesVisitor::ResolveSpecificationParts(ProgramTree &node) { // implied SAVE so that evaluate::IsSaved() will return true. if (node.scope()->kind() == Scope::Kind::MainProgram) { if (const auto *object{symbol.detailsIf()}) { - if (const DeclTypeSpec *type{object->type()}) { - if (const DerivedTypeSpec *derived{type->AsDerived()}) { + if (const DeclTypeSpec * type{object->type()}) { + if (const DerivedTypeSpec * derived{type->AsDerived()}) { if (!IsSaved(symbol) && FindCoarrayPotentialComponent(*derived)) { SetImplicitAttr(symbol, Attr::SAVE); } @@ -10678,7 +10679,7 @@ void ResolveNamesVisitor::FinishDerivedTypeInstantiation(Scope &scope) { if (DerivedTypeSpec * spec{scope.derivedTypeSpec()}) { spec->Instantiate(currScope()); const Symbol &origTypeSymbol{spec->typeSymbol()}; - if (const Scope *origTypeScope{origTypeSymbol.scope()}) { + if (const Scope * origTypeScope{origTypeSymbol.scope()}) { CHECK(origTypeScope->IsDerivedType() && origTypeScope->symbol() == &origTypeSymbol); auto &foldingContext{GetFoldingContext()}; @@ -10689,7 +10690,7 @@ void ResolveNamesVisitor::FinishDerivedTypeInstantiation(Scope &scope) { if (IsPointer(comp)) { if (auto *details{comp.detailsIf()}) { auto origDetails{origComp.get()}; - if (const MaybeExpr &init{origDetails.init()}) { + if (const MaybeExpr & init{origDetails.init()}) { SomeExpr newInit{*init}; MaybeExpr folded{FoldExpr(std::move(newInit))}; details->set_init(std::move(folded)); diff --git a/flang/test/Semantics/OpenMP/declare-mapper-modfile.f90 b/flang/test/Semantics/OpenMP/declare-mapper-modfile.f90 new file mode 100644 index 0000000000000..480f87bc0f8e9 --- /dev/null +++ b/flang/test/Semantics/OpenMP/declare-mapper-modfile.f90 @@ -0,0 +1,14 @@ +! RUN: split-file %s %t +! RUN: %flang_fc1 -fsyntax-only -fopenmp -fopenmp-version=50 -module-dir %t %t/m.f90 +! RUN: cat %t/m.mod | FileCheck --ignore-case %s + +!--- m.f90 +module m + implicit none + type :: t + integer :: x + end type t + !$omp declare mapper(mymap : t :: v) map(v%x) +end module m + +!CHECK: !$OMP DECLARE MAPPER(mymap:t::v) MAP(v%x) diff --git a/flang/test/Semantics/OpenMP/map-clause-symbols.f90 b/flang/test/Semantics/OpenMP/map-clause-symbols.f90 index cdb65a71e8887..3b723e817ce87 100644 --- a/flang/test/Semantics/OpenMP/map-clause-symbols.f90 +++ b/flang/test/Semantics/OpenMP/map-clause-symbols.f90 @@ -1,12 +1,16 @@ -! RUN: not %flang_fc1 -fopenmp -fopenmp-version=50 %s 2>&1 | FileCheck %s +! RUN: %flang_fc1 -fdebug-dump-symbols -fopenmp -fopenmp-version=50 %s | FileCheck %s program main +!CHECK-LABEL: MainProgram scope: MAIN + type ty + real(4) :: x + end type ty + !$omp declare mapper(xx : ty :: v) map(v) integer, parameter :: n = 256 - real(8) :: a(256) + type(ty) :: a(256) !$omp target map(mapper(xx), from:a) do i=1,n - a(i) = 4.2 + a(i)%x = 4.2 end do !$omp end target +!CHECK: xx: MapperDetails end program main - -! CHECK: error: '{{.*}}' not declared From 83ab55ca94a99f2475d49d28ecaf6d29006d8a58 Mon Sep 17 00:00:00 2001 From: Akash Banerjee Date: Mon, 27 Oct 2025 14:01:52 +0000 Subject: [PATCH 5/5] Address copilot comments. --- flang/lib/Lower/OpenMP/OpenMP.cpp | 10 +++------- 1 file changed, 3 insertions(+), 7 deletions(-) diff --git a/flang/lib/Lower/OpenMP/OpenMP.cpp b/flang/lib/Lower/OpenMP/OpenMP.cpp index e911af92bfdf6..10fe6b79a6a6a 100644 --- a/flang/lib/Lower/OpenMP/OpenMP.cpp +++ b/flang/lib/Lower/OpenMP/OpenMP.cpp @@ -3569,8 +3569,8 @@ static void genOpenMPDeclareMapperImpl( mapperNameStr = converter.mangleName(mapperNameStr, sym->owner()); } - // If the mapper op already exists (e.g., created by regular lowering), - // do not recreate it. + // If the mapper op already exists (e.g., created by regular lowering or by + // materialization of imported mappers), do not recreate it. if (converter.getModuleOp().lookupSymbol(mapperNameStr)) return; @@ -4262,12 +4262,8 @@ void Fortran::lower::materializeOpenMPDeclareMappers( return; // Only materialize for modules coming from mod files to avoid duplicates. - if (const semantics::Symbol *modSym = root.symbol()) { - if (!modSym->test(semantics::Symbol::Flag::ModFile)) - return; - } else { + if (!root.symbol() || !root.symbol()->test(semantics::Symbol::Flag::ModFile)) return; - } // Scan symbols in this module scope for MapperDetails. for (auto &it : root) {