[flang-commits] [flang] 3f420c9 - [flang] Diagnose BIND(C) procedures in submodules without ancestor interfaces (#194571)

via flang-commits flang-commits at lists.llvm.org
Thu May 14 20:59:13 PDT 2026


Author: Sairudra More
Date: 2026-05-15T09:29:08+05:30
New Revision: 3f420c96cdeb88a6db520b5f5e7f31596ce5ef07

URL: https://github.com/llvm/llvm-project/commit/3f420c96cdeb88a6db520b5f5e7f31596ce5ef07
DIFF: https://github.com/llvm/llvm-project/commit/3f420c96cdeb88a6db520b5f5e7f31596ce5ef07.diff

LOG: [flang] Diagnose BIND(C) procedures in submodules without ancestor interfaces (#194571)

This diagnoses `BIND(C)` procedures defined in submodules when their
interface is not declared in the ancestor module.

The check is added in `CheckBindC()` and covers plain `BIND(C)`,
explicit `NAME=`, empty/all-blank `NAME=`, valid ancestor-module
interfaces, and nested submodule cases.

Fixes #194570.

Co-authored-by: Sairudra More <moresair at pe31.hpc.amslabs.hpecorp.net>

Added: 
    flang/test/Semantics/bind-c19.f90

Modified: 
    flang/lib/Semantics/check-declarations.cpp

Removed: 
    


################################################################################
diff  --git a/flang/lib/Semantics/check-declarations.cpp b/flang/lib/Semantics/check-declarations.cpp
index d1475176215d3..470fd78629700 100644
--- a/flang/lib/Semantics/check-declarations.cpp
+++ b/flang/lib/Semantics/check-declarations.cpp
@@ -3540,6 +3540,24 @@ void CheckHelper::CheckBindC(const Symbol &symbol) {
       context_.SetError(symbol);
     }
   }
+  // F2023 C1807 - a procedure defined in a submodule shall not have a binding
+  // label unless its interface is declared in the ancestor module.
+  const std::string *bindName{symbol.GetBindName()};
+  if (symbol.has<SubprogramDetails>() &&
+      !symbol.get<SubprogramDetails>().isInterface() && bindName &&
+      !bindName->empty() && symbol.owner().IsSubmodule()) {
+    const Symbol *iface{FindSeparateModuleSubprogramInterface(&symbol)};
+    bool ok{false};
+    if (iface) {
+      const Scope *ifaceModule{FindModuleOrSubmoduleContaining(iface->owner())};
+      ok = ifaceModule && ifaceModule->IsModule();
+    }
+    if (!ok) {
+      messages_.Say(symbol.name(),
+          "A procedure defined in a submodule shall not have a binding label unless its interface is declared in the ancestor module"_err_en_US);
+      context_.SetError(symbol);
+    }
+  }
   if (symbol.has<ObjectEntityDetails>()) {
     whyNot = WhyNotInteroperableObject(symbol);
   } else if (symbol.has<ProcEntityDetails>() ||

diff  --git a/flang/test/Semantics/bind-c19.f90 b/flang/test/Semantics/bind-c19.f90
new file mode 100644
index 0000000000000..4a1027727b023
--- /dev/null
+++ b/flang/test/Semantics/bind-c19.f90
@@ -0,0 +1,117 @@
+! RUN: %python %S/test_errors.py %s %flang_fc1
+! Check for C1807: A procedure defined in a submodule shall not have a
+! binding label unless its interface is declared in the ancestor module.
+
+module m1
+  implicit none
+end module
+
+! Submodule with BIND(C) procedures that have no interface in the ancestor
+! module - these violate C1807.
+submodule(m1) sm1
+  implicit none
+contains
+  !ERROR: A procedure defined in a submodule shall not have a binding label unless its interface is declared in the ancestor module
+  subroutine sub1() bind(c)
+  end subroutine
+  !ERROR: A procedure defined in a submodule shall not have a binding label unless its interface is declared in the ancestor module
+  subroutine sub2() bind(c, name="my_sub2")
+  end subroutine
+  !ERROR: A procedure defined in a submodule shall not have a binding label unless its interface is declared in the ancestor module
+  function func1() bind(c)
+    use, intrinsic :: iso_c_binding, only: c_int
+    integer(c_int) :: func1
+    func1 = 0
+  end function
+end submodule
+
+! Valid: interfaces declared in ancestor module.
+module m2
+  implicit none
+  interface
+    module subroutine sub3() bind(c, name="sub3")
+    end subroutine
+    module function func2() bind(c) result(res)
+      use, intrinsic :: iso_c_binding, only: c_int
+      integer(c_int) :: res
+    end function
+  end interface
+end module
+
+submodule(m2) sm2
+  implicit none
+contains
+  module subroutine sub3() bind(c, name="sub3")
+  end subroutine
+  module function func2() bind(c) result(res)
+    use, intrinsic :: iso_c_binding, only: c_int
+    integer(c_int) :: res
+    res = 0
+  end function
+end submodule
+
+! Valid: BIND(C,NAME="") gives no binding label.
+module m3
+  implicit none
+end module
+
+submodule(m3) sm3
+  implicit none
+contains
+  subroutine sub4() bind(c, name="")
+  end subroutine
+end submodule
+
+! Valid: BIND(C,NAME=" ") gives no binding label (blanks are discarded).
+module m4
+  implicit none
+end module
+
+submodule(m4) sm4
+  implicit none
+contains
+  subroutine sub5() bind(c, name=" ")
+  end subroutine
+end submodule
+
+! Invalid: interface declared in a parent submodule, not the ancestor module.
+! C1807 requires the interface be in the ancestor module.
+module m5
+  implicit none
+end module
+
+submodule(m5) sm5parent
+  implicit none
+  interface
+    module subroutine sub6() bind(c, name="sub6")
+    end subroutine
+  end interface
+end submodule
+
+submodule(m5:sm5parent) sm5child
+  implicit none
+contains
+  !ERROR: A procedure defined in a submodule shall not have a binding label unless its interface is declared in the ancestor module
+  module subroutine sub6() bind(c, name="sub6")
+  end subroutine
+end submodule
+
+! Valid: interface declared in the ancestor module, definition in a child
+! submodule - C1807 is satisfied because the interface is in the module.
+module m6
+  implicit none
+  interface
+    module subroutine sub7() bind(c, name="sub7")
+    end subroutine
+  end interface
+end module
+
+submodule(m6) sm6parent
+end submodule
+
+submodule(m6:sm6parent) sm6child
+  implicit none
+contains
+  module subroutine sub7() bind(c, name="sub7")
+  end subroutine
+end submodule


        


More information about the flang-commits mailing list