[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