The evidence favors accepting both compilation layouts in llvm/llvm-project#219570. The issue's expected-behavior section instead calls for rejection.
Standards conformance should determine the intended behavior. The implementation discussion below concerns the effort needed to achieve that behavior.
The producer module is implicit_intrinsic_source. The facade module is implicit_intrinsic_facade.
In the combined layout, both modules are compiled from one source file. In the separate layout, the producer is compiled first and the facade is then compiled against the producer's module file.
module implicit_intrinsic_source
integer, parameter :: value = max(1, 2)
end module
module implicit_intrinsic_facade
use implicit_intrinsic_source
end moduleEach layout then compiles this downstream function separately:
integer function imported_max(a, b)
use implicit_intrinsic_facade, only : max
integer, intent(in) :: a, b
imported_max = max(a, b)
end functionThe issue reports that Flang trunk 24.0.0git rejects the combined layout and accepts the separate layout. The reported gfortran trunk 17.0.0 and nvfortran 26.5 reject both. The reported ifx 2025.3.2 and Cray Fortran 19.0.0 accept both. These results have not been rerun for this analysis.
The combined-layout diagnostic reported in the issue is:
error: 'max' not found in module 'implicit_intrinsic_facade'
F90/000078, "Intrinsic functions in MODULE specification statements" has status Published in archive member 95-006r5/95-006r5.b040. Both cases in the interpretation invoke the specific intrinsic IABS in a module specification expression. One module contains an INTRINSIC IABS statement. The other omits that statement.
In both cases, IABS denotes an intrinsic procedure in module SPEC. Procedures are entities which may be made accessible by USE association, and in the absence of a PRIVATE declaration applicable to IABS, they are made accessible.
The interpretation rejects both consuming programs because each redeclares IABS as an array after importing it. It does not reject the module that omits INTRINSIC.
The F90/000143 erratum specifies adding the explicit-INTRINSIC-or-use requirement to F90 11.3.2. Its record in archive member 95-006r5/95-006r5.b120 has status WG5 approved; ready for SC22. The requirement appears in F95 11.3.2.
The requirement says that an intrinsic procedure "with public accessibility" must receive INTRINSIC explicitly or be used as intrinsic in the module. It is consistent with F90/000078, but the condition does not independently prove that every use declares an entity.
Citations use J3/24-007, the Fortran 2023 Interpretation Document, not the published ISO standard.
Specific IABS and generic MAX are different cases. F2023 8.5.11 p1 recognizes both intrinsic-name kinds, and F2023 14.2.2 p2 permits association of procedures and generic identifiers. Neither supplies a generic-name accessibility exception.
- The producer's call follows F2023 15.5.5.4 p2. MAX is elemental under F2023 16.9.135, and F2023 10.1.12 p1(7) permits this constant expression.
- F2023 14.2.1 p4 requires an intrinsic declared in a module to receive an
INTRINSICspecification or be used as intrinsic there. This condition does not independently define declaration through usage. F90/000078 supplies the historical accessibility premise. - The producer's
maxdefaults to PUBLIC under F2023 8.5.2 p3-p4 and F2023 8.6.1 p1. The facade importsmaxunder F2023 14.2.2 p4. The use-associated identifier also has default PUBLIC accessibility in the facade. - Downstream
ONLY: maxtherefore satisfies F2023 C1409. Its call conforms to MAX's interface. File grouping does not merge module scoping units.
An empty producer has no public max for an ONLY list. A PRIVATE max is also unavailable through its module.
A consumer that imports max cannot also declare a local array max, under F2023 19.3.1 p1 and p3. Accepting the original call does not permit conflicting local redeclarations.
The compatibility argument needs a conforming consumer, not the invalid redeclarations in F90/000078. A consumer that merely imports and invokes that module's IABS supplies the positive case. F2023 4.3.7 p1 preserves its conformance without a relevant exception. F2023 4.3.5 p1 and 4.3.6 p1 provide corresponding guarantees for Fortran 2003 and Fortran 95.
F2023 15.5.5.2 orders resolution for established generic names, not module exports. Its p3 considers an INTRINSIC specification or association from a module where the corresponding name has that specification. The use-associated alternative presupposes accessibility. Its p4 considers host generics before p5 intrinsic fallback.
An explicit INTRINSIC statement can change how F2023 15.5.5.1 classifies a name. Exporting the intrinsic does not by itself answer whether that classification change affects a reference.
Source inspection at upstream d90d78fe5ba15d66fea0fd0f9a3977f20f34aceb shows that HandleProcedureName already creates the intrinsic symbol and ApplyDefaultAccess assigns PUBLIC here. Unrestricted USE reaches AddUseForPublicSymbols, whose filter requires:
(!symbol->implicitAttrs().test(Attr::INTRINSIC) || symbol->has<UseDetails>())The condition excludes the producer-owned, implicitly recognized max from the combined-layout facade.
PutProcEntity already writes intrinsic::name. In the issue's implicit_intrinsic_source.mod, value has folded to 2_4. The file contains intrinsic::max, but no remaining max(...) call.
The module reader parses that declaration as explicit INTRINSIC. HandleAttributeStmt invokes SetExplicitAttr, which clears the implicit attribute bit. The separate-layout facade can therefore pass the filter's first alternative.
Explicit ONLY/rename uses AddUse and FindInScope without the implicit-INTRINSIC exclusion.
Acceptance therefore appears to have a local starting point in the unrestricted-USE filter. The displayed missing-name case does not appear to require a new module format. The apparent locality comes from source inspection, not from a completed patch.
One option raised in the issue is to omit implicitly recognized intrinsics from module files. Changing only the writer would leave the in-memory plain-USE and ONLY/rename paths inconsistent. The standards argument also opposes omission for this case.
AcquireIntrinsicProcedureFlags calls SetImplicitAttr unconditionally, setting ordinary and implicit INTRINSIC bits. A local UseDetails symbol retains only ASYNCHRONOUS/VOLATILE implicit flags but still has a pointer to the used symbol. The implicit bit cannot be assumed to record immutable declaration history. These facts also do not prove that all provenance is lost in memory.
Origin preservation would cover several areas: producer symbols, use association, serialization, reader recovery, and affected resolution decisions. The displayed missing-name reproducer does not establish an observable provenance-dependent resolution difference. The interaction with host generics in F2023 15.5.5.2 deserves separate analysis before a module-format change is justified on that basis.
An eventual patch needs downstream coverage in both compilation layouts. Its checks should cover: PRIVATE, explicit ONLY, renaming, empty producer modules, conflicting local redeclarations, references confined to contained procedures, explicit INTRINSIC declarations, facade and multiple imports, generic interactions, and the configured implicit-USE caller.
The acceptance conclusion applies a published F90 interpretation to current clauses. The bounded research found no later reversal. It was not an exhaustive survey of interpretations.
AI assistance: GPT-6 Astra, Claude Fable 5.1, GPT-5.6 Sol, and Claude Opus 5.