[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
Thu Aug 13 11:47:56 PDT 2026
https://github.com/kwyatt-ext updated https://github.com/llvm/llvm-project/pull/215886
>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 1/2] [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)
>From d6f02e3a82f3ad3c562ac1df84eb421ad24cb27a Mon Sep 17 00:00:00 2001
From: Kevin Wyatt <kwyatt at hpe.com>
Date: Thu, 13 Aug 2026 13:47:42 -0500
Subject: [PATCH 2/2] Modified test per review comments.
---
flang/test/Parser/recovery09.f90 | 20 +++++++++++---------
1 file changed, 11 insertions(+), 9 deletions(-)
diff --git a/flang/test/Parser/recovery09.f90 b/flang/test/Parser/recovery09.f90
index 327d37277da5f..9dd8d3ae2c517 100644
--- a/flang/test/Parser/recovery09.f90
+++ b/flang/test/Parser/recovery09.f90
@@ -1,9 +1,15 @@
-! RUN: not %flang_fc1 -fsyntax-only %s 2>&1 | FileCheck %s
+! RUN: not %flang_fc1 -fsyntax-only %s 2>&1 | FileCheck %s \
+! RUN: --implicit-check-not="expected 'FINAL'" \
+! RUN: --implicit-check-not="expected 'GENERIC'" \
+! RUN: --implicit-check-not="expected 'PROCEDURE'" \
+! RUN: --implicit-check-not="expected 'COMPLEX'" \
+! RUN: --implicit-check-not="expected 'INTEGER'"
! 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.
+! messages. The --implicit-check-not options above assert, across the whole
+! output, that none of those spurious messages reappear.
module m
implicit none
@@ -26,6 +32,7 @@ module m
contains
contains
! CHECK: error: expected a type-bound procedure binding (PROCEDURE, GENERIC, or FINAL) after CONTAINS
+! CHECK-NEXT: {{.*}}contains
end type t2
! An IMPORT after CONTAINS is likewise not a binding.
@@ -33,22 +40,17 @@ module m
contains
import
! CHECK: error: expected a type-bound procedure binding (PROCEDURE, GENERIC, or FINAL) after CONTAINS
+! CHECK-NEXT: {{.*}}import
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
+! CHECK-NEXT: {{.*}}subroutine s
end type t4
-! CHECK-NOT: expected 'FINAL'
-! CHECK-NOT: expected 'GENERIC'
-! CHECK-NOT: expected 'PROCEDURE'
-! CHECK-NOT: expected 'COMPLEX'
-! CHECK-NOT: expected 'INTEGER'
-
contains
subroutine init(this)
class(t1), intent(inout) :: this
More information about the flang-commits
mailing list