[flang-commits] [flang] [flang] Improve error for misplaced statement after CONTAINS in derived type (PR #215886)
via flang-commits
flang-commits at lists.llvm.org
Wed Aug 12 13:19:54 PDT 2026
https://github.com/kwyatt-ext created https://github.com/llvm/llvm-project/pull/215886
A statement after `CONTAINS` in a derived type that is not a type-bound procedure binding (e.g. a second `CONTAINS`, an `IMPORT`, or a misplaced subprogram) leaked the intrinsic type-spec parse failures (`expected 'COMPLEX'`, `expected 'INTEGER'`, ...) instead of reporting that a type-bound procedure binding was expected. In the misplaced-subprogram case flang emitted an avalanche of unrelated `expected '<type-keyword>'` errors.
This is a diagnostic regression from #203379, which added `DataComponentDefStmt` as a trailing alternative in the type-bound-proc-binding parser. Its intended `fail<>()` message only fires when `DataComponentDefStmt` fully matches; for any other invalid statement the partial parse into `declarationTypeSpec` displaced the recovery message in `CombineFailedParses`.
This patch wraps the binding alternatives in `withMessage()` so that when none of them match a token a single clear message is emitted:
```
error: expected a type-bound procedure binding (PROCEDURE, GENERIC, or FINAL) after CONTAINS
```
The specific `component definition must precede CONTAINS in a derived type` message is still produced for a genuine misplaced component definition (`withMessage` only overrides when no tokens were matched), and malformed `PROCEDURE`/`GENERIC`/`FINAL`/component statements keep their own specific diagnostics.
`flang/test/Parser/recovery09.f90` is extended to cover the double-`CONTAINS`, `IMPORT`, and misplaced-subprogram cases.
>From 2ce23d7740b3907b799700ad2fe854bde33ef6d5 Mon Sep 17 00:00:00 2001
From: Kevin Wyatt <kwyatt at hpe.com>
Date: Wed, 12 Aug 2026 12:51:56 -0500
Subject: [PATCH] [flang] Improve error for misplaced statement after CONTAINS
in derived type
A statement after CONTAINS in a derived type that is not a type-bound
procedure binding (e.g. a second CONTAINS, an IMPORT, or a misplaced
subprogram) leaked the intrinsic type-spec parse failures ("expected
'COMPLEX'", "expected 'INTEGER'", ...) instead of reporting that a
type-bound procedure binding was expected. In the misplaced-subprogram
case flang emitted an avalanche of unrelated "expected '<type-keyword>'"
errors.
This was a diagnostic regression from #203379, which added
DataComponentDefStmt as a trailing alternative in the
type-bound-proc-binding parser. Its intended fail<>() message only fires
when DataComponentDefStmt fully matches; for any other invalid statement
the partial parse into declarationTypeSpec displaced the recovery message
in CombineFailedParses.
Wrap the binding alternatives in withMessage() so that when none of them
match a token a single clear message is emitted, while the specific
"component definition must precede CONTAINS in a derived type" message is
still produced for a genuine misplaced component definition and malformed
bindings keep their own diagnostics.
Extend recovery09.f90 to cover the double-CONTAINS, IMPORT, and
misplaced-subprogram cases.
---
flang/lib/Parser/Fortran-parsers.cpp | 15 +++++++-----
flang/test/Parser/recovery09.f90 | 35 ++++++++++++++++++++++++----
2 files changed, 40 insertions(+), 10 deletions(-)
diff --git a/flang/lib/Parser/Fortran-parsers.cpp b/flang/lib/Parser/Fortran-parsers.cpp
index ebae6bfa53cab..72de71bf0ac63 100644
--- a/flang/lib/Parser/Fortran-parsers.cpp
+++ b/flang/lib/Parser/Fortran-parsers.cpp
@@ -567,12 +567,15 @@ TYPE_CONTEXT_PARSER("type bound procedure part"_en_US,
// final-procedure-stmt
TYPE_CONTEXT_PARSER("type bound procedure binding"_en_US,
recovery(
- first(construct<TypeBoundProcBinding>(Parser<TypeBoundProcedureStmt>{}),
- construct<TypeBoundProcBinding>(Parser<TypeBoundGenericStmt>{}),
- construct<TypeBoundProcBinding>(Parser<FinalProcedureStmt>{}),
- Parser<DataComponentDefStmt>{} >>
- fail<TypeBoundProcBinding>(
- "component definition must precede CONTAINS in a derived type"_err_en_US)),
+ withMessage(
+ "expected a type-bound procedure binding (PROCEDURE, GENERIC, or FINAL) after CONTAINS"_err_en_US,
+ first(construct<TypeBoundProcBinding>(
+ Parser<TypeBoundProcedureStmt>{}),
+ construct<TypeBoundProcBinding>(Parser<TypeBoundGenericStmt>{}),
+ construct<TypeBoundProcBinding>(Parser<FinalProcedureStmt>{}),
+ Parser<DataComponentDefStmt>{} >>
+ fail<TypeBoundProcBinding>(
+ "component definition must precede CONTAINS in a derived type"_err_en_US))),
construct<TypeBoundProcBinding>(
!"END"_tok >> SkipTo<'\n'>{} >> construct<ErrorRecovery>())))
diff --git a/flang/test/Parser/recovery09.f90 b/flang/test/Parser/recovery09.f90
index 0642fc98a0674..327d37277da5f 100644
--- a/flang/test/Parser/recovery09.f90
+++ b/flang/test/Parser/recovery09.f90
@@ -1,12 +1,14 @@
! RUN: not %flang_fc1 -fsyntax-only %s 2>&1 | FileCheck %s
-! Verify that a data component definition appearing after CONTAINS in a
-! derived type gives a clear error instead of misleading
-! "expected 'FINAL'/'GENERIC'/'PROCEDURE'" messages.
+! Verify that a statement appearing after CONTAINS in a derived type that is not
+! a type-bound procedure binding gives a clear error instead of misleading
+! "expected 'FINAL'/'GENERIC'/'PROCEDURE'" or intrinsic-type-spec keyword
+! messages.
module m
implicit none
+ ! A data component definition after CONTAINS names the specific problem.
type, public :: t1
real :: x
contains
@@ -17,10 +19,35 @@ module m
! CHECK: error: component definition must precede CONTAINS in a derived type
! CHECK-NEXT: {{.*}}real, pointer, dimension(:,:,:), public :: gpoint => null()
real, pointer, dimension(:,:,:), public :: gpoint => null()
+ end type t1
+
+ ! A second CONTAINS is not a component definition.
+ type :: t2
+ contains
+ contains
+! CHECK: error: expected a type-bound procedure binding (PROCEDURE, GENERIC, or FINAL) after CONTAINS
+ end type t2
+
+ ! An IMPORT after CONTAINS is likewise not a binding.
+ type :: t3
+ contains
+ import
+! CHECK: error: expected a type-bound procedure binding (PROCEDURE, GENERIC, or FINAL) after CONTAINS
+ end type t3
+
+ ! A misplaced subprogram after CONTAINS.
+ type :: t4
+ contains
+ subroutine s
+ end subroutine
+! CHECK: error: expected a type-bound procedure binding (PROCEDURE, GENERIC, or FINAL) after CONTAINS
+ end type t4
+
! CHECK-NOT: expected 'FINAL'
! CHECK-NOT: expected 'GENERIC'
! CHECK-NOT: expected 'PROCEDURE'
- end type t1
+! CHECK-NOT: expected 'COMPLEX'
+! CHECK-NOT: expected 'INTEGER'
contains
subroutine init(this)
More information about the flang-commits
mailing list