[flang] EXTERNAL/INTRINSIC + legacy initializer in type declaration silently accepted, initializer dropped
- Dominant language
- LLVM
- Stars
- 40.5k
- Forks
- 18.7k
- PR merge metrics
- PR metrics pending
Description
The legacy (extension) form of initialization in a type declaration statement is silently accepted — and the initializer silently dropped — when the name was previously declared EXTERNAL or INTRINSIC.
```fortran
program p
external foo
integer foo /1/
end program
```
```
$ flang -c ext.f90
$ echo $?
0
```
This compiles cleanly, but the initializer never reaches the emitted code. Compare with the same declaration without EXTERNAL:
```fortran
program p
integer foo /1/
end program
```
which emits the expected static-storage global:
```llvm
@_QFEfoo = internal global i32 1
```
With `external foo` present, `-S -emit-llvm` output contains no `foo` and no initializer at all — the `/1/` is dropped without any diagnostic.
The acceptance is order-dependent. Reversing the two statements produces the expected error:
```fortran
program p
integer foo /1/
external foo
end program
```
```
error: 'foo' is a data object and may not be EXTERNAL
```
The same silent acceptance happens with INTRINSIC:
```fortran
program p
intrinsic sin
integer sin /1/
end program
```
also compiles with exit status 0 and drops the initializer.
Expected behavior: an error in both orders (a procedure cannot have a DATA-style initializer), consistent with the diagnostic already produced for the reversed order.
Mechanism, as far as I can tell: in `DataChecker::Leave(const parser::EntityDecl &)` (`flang/lib/Semantics/check-data.cpp`), the initializer is accumulated for the symbol, which by then has procedure details (from EXTERNAL/INTRINSIC). `ExpressionAnalyzer::Designate` happily returns a `ProcedureDesignator` for it, no error is ever reported on the symbol, and the initialization is later discarded without a diagnostic.
Related: #220846 / #221170 fixed the crash on this same code path when the redeclaration itself errors; this case is different in that no error is reported at all, so the recently added `HasError` guard does not (and should not) fire.
Tested at current llvm-project main (also reproduces on builds predating #221170, with identical behavior).
Contributor guide
Assessment
This issue has not been assessed yet.