[flang] Spurious "internal function may not be referenced in a specification expression" when the internal function is a losing generic candidate
- Dominant language
- LLVM
- Stars
- 40.5k
- Forks
- 18.7k
- PR merge metrics
- PR metrics pending
Description
(Generated by AI)
Consider:
```fortran
program main
interface sin
procedure :: mysin
end interface
call inner
contains
subroutine inner
real :: x(int(sin(0.5_8)+1.5_8))
x = 0.
print *, size(x)
end subroutine
function mysin(r)
real, intent(in) :: r
real :: mysin
mysin = r + 100.
end function
end program
```
The specification expression `int(sin(0.5_8)+1.5_8)` references the generic name `sin`. The generic's only specific, `mysin`, expects a default-real argument, so it is not consistent with the `real(8)` actual argument; per F2023 15.5.5.2 step (5) the reference resolves to the intrinsic `sin`. The internal function `mysin` is therefore never referenced, so the restriction on referencing internal functions in specification expressions (10.1.11 para 4) does not apply, and the program is conforming.
Flang rejects it:
```
error: Semantic errors in t.f90
t.f90:8:19: error: The internal function 'mysin' may not be referenced in a specification expression
real :: x(int(sin(0.5_8)+1.5_8))
^^^^^^^^^^
```
gfortran 16.1.0, ifx 2026.0.0, classic nvfortran, and NAG 7.2 all accept it, and the compiled program prints `1` (the array extent computed with the intrinsic). (NAG was tested with the `_8` literal kinds spelled `_dp` via `integer, parameter :: dp = kind(1.d0)`, because NAG's default kind numbering rejects `_8`; flang rejects that spelling identically.)
Root cause: while resolving the generic, `ExpressionAnalyzer::ResolveGeneric` (`flang/lib/Semantics/expression.cpp`) calls `ResolveForward` to characterize each specific procedure as a candidate. For a forward-referenced internal function, `ResolveForward` emits the error and poisons the symbol eagerly, before the candidate has lost the resolution:
```c++
} else { // 10.1.11 para 4
Say("The internal function '%s' may not be referenced in a specification expression"_err_en_US,
symbol.name());
context_.SetError(symbol);
return nullptr;
}
```
Merely characterizing a candidate that is ultimately not selected should not emit user-visible diagnostics or mark the symbol erroneous. Note that deferring or buffering the message alone would not be sufficient: the `context_.SetError(symbol)` side effect must also be deferred (or undone) when the candidate loses, because `ResolveForward` begins with `if (context_.HasError(symbol)) return nullptr;` — once poisoned, the specific silently vanishes as a candidate from every subsequent resolution in the file. The sibling branch just above (`The module function '%s' may not be referenced recursively in a specification expression`) has the same eager `Say` + `SetError` shape.
Tested with flang 24.0.0git at current main (commit a6f35d1c8751, 2026-08-20), x86_64 Linux.
Contributor guide
Research direction
Reproduce the supplied program with flang, then inspect flang/lib/Semantics/expression.cpp at ExpressionAnalyzer::ResolveGeneric and ResolveForward. Compare the internal-function and module-function branches, and trace how candidate loss affects diagnostics and symbol error state. Done means the generic resolves to the intrinsic without rejecting the program, while genuinely selected invalid references still produce the intended diagnostic.
Written by the indexing model from the issue text.
Assessment
- Tech stack
- fortran
- Domain
- compilers
- Issue type
- Bug
- Difficulty
- 4/5
- Estimated time
- 3-5 days
- Activity status
- Active
- Clarity
- Clearly specified
- Newbie friendliness
- 72/100