This PR completes the addition of enumeration types to the symbol table.
It adds core semantic analysis for ENUMERATION TYPE, name resolution,
expression analysis for constructors and relational operators, and
SELECT CASE support. Also includes a bug fix for non-constant
enumeration comparisons in Relate() (scope() → GetScope()).
It is the 2nd of 5 stacked PRs.
AI Usage Disclosure: AI tools (Claude Opus 4.6) were used to assist with
implementation of this feature and test code generation. I have
reviewed, modified, and tested all AI-generated code.
---------
Co-authored-by: Kevin Wyatt <kwyatt@hpe.com>
Under -gpu=mem:unified, the CUDA data attribute compatibility check
(AreCompatibleCUDADataAttrs) allows an unattributed actual argument to
bind to a Device/Managed/Unified dummy. This relaxation is correct for
variables whose storage is accessible from device code under unified
memory, but not for non-variable expression results (e.g. intrinsic call
results like RESHAPE(...)), which are host temporaries.
Without this fix, a generic SUM call like sum(reshape(hostArray, ...),
dim=2) could resolve to a device-specific overload instead of the
intrinsic, because the RESHAPE result was incorrectly considered
compatible with a DEVICE-attributed dummy.
This patch:
- Adds an actualIsVariable parameter to AreCompatibleCUDADataAttrs
(defaulting to true for backward compatibility) and gates the
unified-memory relaxation for Device/Managed/Unified dummies on it.
- Passes actualIsVariable from CheckExplicitDataArg in check-call.
- Stops setting actualCanUseImplicitCudaMemoryMode for non-variable
expressions in GetMatchingDistance, so the CUDA matching distance
ranking is also correct.
In CUDA device code, a host-only generic can shadow an intrinsic with
the same name and cause a valid call such as maxloc(a, 1) to be rejected
as non-device-callable. Retry intrinsic resolution for host-only generic
function calls in device context, preserving normal diagnostics when no
valid intrinsic matches.
https://github.com/llvm/llvm-project/pull/198610 caused a regression,
where the
code path for explicit interface checks was also used for the statement
functions arg check. Refactor the code to avoid explicit interface
checks.
Fixes#203500
Assisted-by: AI
Function calls and array element acceses have the same syntax, and some
array element accesses may be misparsed as calls. The ExprChecker will
identify and correct such cases in expressions, but they may also occur
outside of expressions (e.g. OpenMP directives and clauses).
To avoid code duplication extract the check into a new function
`IsMisparsedFunctionReference`.
Fix CUDA generic resolution under `-gpu=mem:unified` so unattributed
literals and expression temporaries are not treated as unified-memory
actuals.
Previously, a host scalar literal such as `1.0` could score as
compatible with a `DEVICE` dummy and incorrectly select the
device-scalar overload. This could pass a host stack address to a device
helper and fail at runtime. The fix applies the unified/managed memory
distance columns only to symbol-backed actuals.
**Problem**
Flang silently accepted keyword arguments in calls to statement
functions, violating F2018 C1535.
**Standard: F2018 §15.5.1 C1535**: In a reference to a procedure whose
interface is implicit at the point of the reference, the actual argument
shall not be a keyword argument.
Flang silently compiles the following code without giving error` Keyword
argument 'x' at (1) is invalid in a statement function
`
```
program test
integer :: f1, x, c
f1(x) = x / 2
c = f1(x=10) ! Should be an error
end program
```
**Summary**
Fixed an issue where statement functions were incorrectly treated as
having an explicit interface, causing argument checks to be skipped.
Now, statement functions are marked correctly so existing checks run and
proper errors are shown
**Fixes** : [198523](https://github.com/llvm/llvm-project/issues/198523)
---------
Co-authored-by: Jay Satish Kumar Patel <kumarpat@pe31.hpc.amslabs.hpecorp.net>
The CUDA generic resolution matching distance function did not handle
actual arguments with the `Constant` or `Shared` data attribute. These
attributes represent device memory but were unhandled, causing the
distance to fall through to infinity. Under `-gpu=mem:unified`, this led
to spurious ambiguity errors when multiple specifics (e.g.
host-to-device and device-to-device overloads) both became candidates
with tied infinite distances.
Treat Constant and Shared actuals the same as Device in the matching
distance table, since all three reside in device memory.
Continuation of #197821
The change only affects vector types; all other types preserve their
existing formatting behavior.
Co-authored-by: virsworld <virpatel@mac.home>
Improve Flang semantic diagnostics for vector types by printing vector
type spellings in Fortran syntax instead of internal builtin-derived
type names.
Use `DerivedTypeSpec::VectorTypeAsFortran()` when producing vector
operand type names in `ArgumentAnalyzer::TypeAsFortran()`, instead of
relying on the generic type formatting path.
This updates diagnostics to print vector types as Fortran source-like
spellings, such as:
- `vector(integer(4))`
- `vector(real(4))`
while preserving the existing formatting for non-vector derived types.
A device-typed dummy with `!dir$ ignore_tkr(m)` is meant to be an
overload discriminator (only selected for actuals with an explicit
`device/managed/unified` attribute). Skip the host->device relaxation in
AreCompatibleCUDADataAttrs when `IgnoreTKR::Managed` is set so
unattributed host actuals no longer bind to such a dummy.
Also document the §3.2.3 matching distance table next to
GetMatchingDistance and add LIT tests for the full Table 2 grid
and the ignore_tkr(m) carve-out.
Skip omitted optional arguments when computing CUDA address-space
matching distances, so -gpu=unified overload resolution does not compare
expanded dummy-argument lists of different sizes. Adds a regression
covering a unified-memory overload with optional extras.
After #195182 introduced the `UseDevice` attribute, a `use_device(...)`
actual was treated as compatible with **any** dummy attribute. Combined
with the matching distance returning ∞ for `UseDevice →
managed/unified`, this caused generic resolution to misreport a clean
"no match" as an **ambiguity** when only managed/unified specifics
existed.
This PR tightens `AreCompatibleCUDADataAttrs`: a `UseDevice` actual is
only compatible with a `Device` dummy or a host (no-attribute) dummy.
Other attributes (`Managed`, `Unified`, `Pinned`, ...) require their
actual to live in that specific kind of memory.
Symbols appearing in `!$acc host_data use_device(...)` were previously
marked with `CUDADataAttr::Device`, which caused generic resolution to
fail.
Introduce a new CUDADataAttr::UseDevice enumerator and use it in
`CopySymbolWithDevice` / `CloneDerivedTypeForUseDeviceImpl` instead of
Device. The new attribute is:
1. Compatible with any dummy in AreCompatibleCUDADataAttrs.
2. Ranked in the matching distance table (GetMatchingDistance): prefers
Device dummies (0), accepts Managed/Unified (2), and allows host dummies
(3).
3. Not user-spellable — only set internally during OpenACC name
resolution, never parsed from source or written to module files.
4. Treated like Device for non-host-array checks, I/O restrictions, and
MLIR lowering (mapped to `cuf::DataAttribute::Device`).
Implement parsing, unparsing, and parse tree nodes for the Fortran 2023
conditional argument syntax (F2023 R1526-R1528). This enables calls of
the form:
call sub((flag ? a : b))
call sub((x > 10 ? a : x > 5 ? b : c))
call sub((flag ? a : .NIL.))
- Add ConditionalArg and ConditionalArgTail parse tree nodes
- Add Nil empty class for .NIL. representation
- Add ConditionalArg as a new alternative in ActualArg
- Add parser rules for conditional-arg, consequent, and chained branches
- Add unparse support for round-trip printing
- Add dump-parse-tree and FeatureList support
- Add parser tests covering simple, multi-branch, .NIL., BOZ, NULL(),
keyword arguments, and module procedure cases
Add lowering support for polymorphic (`CLASS(T)`) conditional
expressions.
`ConditionalExpr::GetType()` now checks both branches and returns the
polymorphic type if either is polymorphic (F2023 10.1.4(7)). In
lowering, polymorphic conditionals use `fir::ClassType` instead of
`fir::BoxType` for the allocatable temporary so that dynamic type info
is preserved through `hlfir.assign` realloc.
Covers scalar, array, and mixed `TYPE(T)`/`CLASS(T)` operands. Unlimited
polymorphic `CLASS(*)` does not have a declared type, and is therefore
rejected in semantics. LIT tests for lowering and semantics have been
updated.
When -fno-realloc-lhs is specified and the LHS of an assignment is a
polymorphic allocatable (class(*) or class(T)), reallocation semantics
are required by the Fortran 2003 standard for dynamic type tracking and
cannot be safely skipped. Previously, the compiler generated invalid FIR
in such cases (type mismatch between i32 and
!fir.class<!fir.heap<none>>), causing a compilation error.
With this change, when -fno-realloc-lhs is in effect and a polymorphic
allocatable LHS is detected, the compiler emits a warning that the
option is being ignored for that assignment and proceeds with
reallocation semantics.
For interoperability between CUDA Fortran and OpenACC, the OpenACC
host_data use_device clause needs implicitly add the DEVICE attribute to
the object symbol for the duration of the region. When the object was a
component, we were adding the symbol to the base which is not what we
want.
Update the handling to copy the base symbol with a new DerivedTypeScope
and set the attribute on the component. New test is added to test the
behavior is indeed on the component.
## Implement Fortran 2023 Conditional Expressions (R1002)
***This PR contains the implementation for parsing and semantic
analysis. Lowering is implemented in a separate PR (#186490)***
Implements Fortran 2023 conditional expressions with syntax: `result =
(condition ? value1 : condition2 ? value2 : ... : elseValue)`
Issue: #176999
Discourse:
https://discourse.llvm.org/t/rfc-adding-conditional-expressions-in-flang-f2023/89869/1
-- note that some of the details provided in the RFC post are no longer
accurate
### Implementation Details
**Parser:**
- Added ConditionalExpr as primary expression (F2023 R1002)
- Right-associative chaining for multi-way conditionals
**Semantics:**
- Expression tree node ConditionalExpr<T> with N conditions and N+1
values
- Strict type checking: all values must have identical type, kind, and
rank
- Conditions must be scalar LOGICAL
**LIT Testing:**
- Parser tests: Syntax validation, precedence, nesting
- Semantic tests: Type checking, error messages
- Note: Executable tests will be added to the llvm-test-suite repo
(https://github.com/llvm/llvm-test-suite/pull/369)
**Limitations**
- Conditional arguments are not yet supported. This work is planned
- #180592
- Polymorphic types (CLASS) not yet supported in lowering
- Both limitations will emit clear error message if encountered
### Examples
```
! Simple conditional
x = (flag ? 10 : 20)
! Chained
result = (x > 0 ? 1 : x < 0 ? -1 : 0)
! Examples from F2023
( ABS (RESIDUAL)<=TOLERANCE ? ’ok’ : ’did not converge’ )
( I>0 .AND. I<=SIZE (A) ? A (I) : PRESENT (VAL) ? VAL : 0.0 )
```
AI Usage Disclosure: AI tools (Claude Sonnet 4.5) were used to assist
with implementation of this feature and test code generation. I have
reviewed, modified, and tested all AI-generated code.
When a reference to a generic procedure fails, the compiler explains why
each of the generic's specific procedures failed to match the actual
arguments. This code had a subtle bug: adjustments to the actual
arguments made for interface checking for earlier specific procedures
would persist and affect the checks for later specific procedures.
The compiler emits messages to explain why each of a generic procedure's
specific procedures is not a match for a given set of actual arguments.
In the case of specific procedures with PASS arguments in derived type
procedure bindings or procedure components, these explanatory messages
are often bogus, because the re-analysis didn't adjust the actual
arguments to account for the PASS argument. Fix.
Switch CUDA generic resolution to compare per‑argument CUDA matching
distances lexicographically instead of summing them. This prevents
ambiguous matches when different specifics yield the same total
distance.
When a pointer component has no default initialization in the derived
type definition and does not appear explicitly as a component in a
structure constructor, we assume that it is meant to be NULL() as an
extension. But there's no warning or documentation for this extension;
add them.
Fixes https://github.com/llvm/llvm-project/issues/179580.
I'm emitting a false warning "used without definition" warning for
variable cited in an inquiry intrinsic (e.g. LBOUND), and failing to
emit an "unused local" warning for allocatables that only appear in
ALLOCATE statements.
This patch makes the analysis more context-aware by rewriting it in
terms of typed expression traversal, and moves the analysis part into
Evaluate/check-expression.cpp from Semantics/expression.cpp.
When scanning the specific procedures of a generic interface for a match
for a set of actual arguments, accept a constant actual argument as a
match for a dummy argument with the DEVICE attribute.
Tweak the implementations of IsConstantExpr, IsInitialDataTarget, and
related utilities so that "free" instances of array constructor implied
DO indices are not treated as constant expressions when the surrounding
context (if any) doesn't contain their bounds. This fixes a current bug
in which a "free" implied DO index in a structure constructor got
wrapped up an a Constant<SomeDerived>, which led to a crash in lowering.
Remove `AmbiguousStructureConstructor` warnings. This removes harmless
warnings about standards-conforming generic function references that
are never ambiguous with structure constructors.
Derived type procedure bindings aren't always subject to the checks of
the function-vs-subroutine classification flags on their symbol table
entries in name resolution, and we're missing some cases that aren't
caught later in expression semantics, which assumed that name resolution
would have already handled them. So check function-vs-subroutine errors
on bindings in expression semantics entirely.
Fixes https://github.com/llvm/llvm-project/issues/177601.
Follow-up to PR175211.
There are still a few AST nodes that don't have any of the standard
traits (Wrapper/Tuple/etc). Because of that they require special
handling in the parse tree visitor.
Convert a subset of these nodes to the typical format, and remove the
special cases from the parse tree visitor.
The members of these nodes were frequently used, so instead of
extracting them by hand each time use helper member functions to access
them.
Follow-up to PR175211.
There are still a few AST nodes that don't have any of the standard
traits (Wrapper/Tuple/etc). Because of that they require special
handling in the parse tree visitor.
Convert a subset of these nodes to the typical format, and remove the
special cases from the parse tree visitor.
Fortran allows a scalar actual argument of any type to correspond with a
TYPE(*) dummy argument that is an assumed-size array. This usage isn't
portable, and it didn't work with a generic procedure with this
compiler, only specific procedures. It affected at least one API in
OpenMPI.
Fix generic resolution to allow for this case, add a distinguishability
test to detect generic interfaces that have ambiguous specific
procedures due to it, and add an optional portability warning (off by
default).
There are quite a few AST nodes that don't have any of the standard
traits (Wrapper/Tuple/etc). Because of that they require special
handling in the parse tree visitor.
Convert a subset of these nodes to the typical format, and remove the
special cases from the parse tree visitor.
A substring reference where the lower bound is higher than the upper
bound is defined in 9.4.1 to be zero-length.
Thus, a reference to a substring of a CHARACTER*(0) string such as
string(foo():2)
cannot be a compile-time error since we do not know the return value of
foo().
We also should not error if the lbound > ubound at compile time.
Errors in array constructor values result in the array having
less elements than it should, which can cause other errors that
will confuse the user. Avoid this by not returning an expression
on errors.
Fixes#127425
When semantics is checking expressions in known dead branches of IF
constructs, errors should not be fatal; emit warnings instead, and allow
them to be disabled.
Fixes https://github.com/llvm/llvm-project/issues/171844.
Add a requested warning for completely unused local variables. The
implementation runs a scan over typed expressions during the existing
expression semantics pass to detect variable uses, and a routine at the
end of semantics to take a pass over the symbol tables to find unused
locals.
The new infrastructure needed to detect variable uses, and the existing
infrastructure that detects potential variable definitions, then makes
it easy to detect variables that are used without any possible
initialization or definition, so I did that too.
The warning for unused locals is off by default -- they might indicate a
misspelling (that IMPLICIT NONE would have caught), but seem otherwise
generally benign. The warning for uses of completely uninitialized and
undefined variables, however, is enabled by default, since that's likely
to indicate a program bug that should be investigated.
This patch touches a lot of files lightly. Many of these files are tests
that would have produced needless warning noise; one new test was added.
Fixes https://github.com/llvm/llvm-project/issues/173276.
When folding intrinsic function calls for types like REAL(2) that don't
have host math library support, we convert them to a type that has
greater range and precision, call a host math library routine that does
exist, and convert the result back to the original result type. The
folding of this second conversion can elicit floating-point warnings
(usually overflow) that are somewhat unclear to the user. Add support
for adding contextual information to these warnings.
When a generic procedure reference does not match any of its specific
procedures, run through them and emit the errors for each attempted
match, so that the user has more information to resolve the problem by
adjusting the actual arguments.
Fix a false positive "NULL can't be an operand here" error message
arising in a defined generic interface for an intrinsic operator (==)
with multiple spellings.
Fixes https://github.com/llvm/llvm-project/issues/163255.