llvm / llvm/llvm-project

[flang] Spurious "internal function may not be referenced in a specification expression" when the internal function is a losing generic candidate

Open
#217,754 1 comment 0 reactions 0 assignees View on GitHub
flang:frontend
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

Open the contributing 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

Get new issues in your inbox

A short digest of beginner-friendly GitHub issues.