[PATCH] [16,17 Regression] PR126872 Change in visibility of C bound functions with 16.2.0

Jerry D <[email protected]>
Newsgroups gmane.comp.gcc.patches,gmane.comp.gcc.fortran
Message-ID <[email protected]>
The attached patch fixes the regression introduced by the fix for PR125430. 
Fairly simple fix.

Assisted-by: Claude Opus 5

Regression tested on x86_64.

OK for mainline and backport to 16?

Regards,

Jerry
---
fortran: [PR126872] BIND(C) entities must keep default ELF
  visibility

Assisted-by: Claude Opus 5

A binding label gives an entity external linkage, so PRIVATE hides only
the Fortran name and must not lower the symbol's ELF visibility.  Three
sites gave hidden visibility to PRIVATE module entities without exempting
binding labels, so a BIND(C) procedure or variable in a module with a
PRIVATE default was not exported from a shared library.

The procedure case is a regression from r17-913 (PR fortran/125430),
backported to the 16 branch as r16-9113 and so present in 16.2.0 but not
16.1.0; the variable case dates from r6-2637, the introduction of
submodules (PR fortran/52846).  Module entities
without a binding label keep the hidden visibility that lets submodules
reach them via host association.

gcc/fortran/ChangeLog:

	PR fortran/126872
	* trans-decl.cc (gfc_finish_var_decl): Drop the unreachable
	hidden-visibility case in the BIND(C) block.  Do not give hidden
	visibility to a PRIVATE module variable with a binding label.
	(build_function_decl): Do not give hidden visibility to a PRIVATE
	module procedure with a binding label.

gcc/testsuite/ChangeLog:

	PR fortran/126872
	* gfortran.dg/bind_c_private_1.f90: New test.
---
PR126872-bind-c-private-visibility.patch (text/x-patch, 4.9 KB)
From bee116b9df9158bbc2c54fdd5656ecc09dcd40d2 Mon Sep 17 00:00:00 2001
From: Jerry DeLisle <[email protected]>
Date: Fri, 14 Aug 2026 12:20:35 -0700
Subject: [PATCH] fortran: [PR126872] BIND(C) entities must keep default ELF
 visibility

Assisted-by: Claude Opus 5

A binding label gives an entity external linkage, so PRIVATE hides only
the Fortran name and must not lower the symbol's ELF visibility.  Three
sites gave hidden visibility to PRIVATE module entities without exempting
binding labels, so a BIND(C) procedure or variable in a module with a
PRIVATE default was not exported from a shared library.

The procedure case is a regression from r17-913 (PR fortran/125430),
backported to the 16 branch as r16-9113 and so present in 16.2.0 but not
16.1.0; the variable case dates from r6-2637, the introduction of
submodules (PR fortran/52846).  Module entities
without a binding label keep the hidden visibility that lets submodules
reach them via host association.

gcc/fortran/ChangeLog:

	PR fortran/126872
	* trans-decl.cc (gfc_finish_var_decl): Drop the unreachable
	hidden-visibility case in the BIND(C) block.  Do not give hidden
	visibility to a PRIVATE module variable with a binding label.
	(build_function_decl): Do not give hidden visibility to a PRIVATE
	module procedure with a binding label.

gcc/testsuite/ChangeLog:

	PR fortran/126872
	* gfortran.dg/bind_c_private_1.f90: New test.
---
 gcc/fortran/trans-decl.cc                     | 17 +++++------
 .../gfortran.dg/bind_c_private_1.f90          | 30 +++++++++++++++++++
 2 files changed, 38 insertions(+), 9 deletions(-)
 create mode 100644 gcc/testsuite/gfortran.dg/bind_c_private_1.f90

diff --git a/gcc/fortran/trans-decl.cc b/gcc/fortran/trans-decl.cc
index 0e2d1955927..23cca238882 100644
--- a/gcc/fortran/trans-decl.cc
+++ b/gcc/fortran/trans-decl.cc
@@ -709,14 +709,11 @@ gfc_finish_var_decl (tree decl, gfc_symbol * sym)
 	 into common space, then C cannot initialize global Fortran
 	 variables that it interoperates with and the draft says that
 	 either Fortran or C should be able to initialize it (but not
-	 both, of course.) (J3/04-007, section 15.3).  */
+	 both, of course.) (J3/04-007, section 15.3).  A binding label has
+	 external linkage, so PRIVATE hides only the Fortran name and must
+	 not restrict the symbol's visibility.  */
       TREE_PUBLIC(decl) = 1;
       DECL_COMMON(decl) = 1;
-      if (sym->attr.access == ACCESS_PRIVATE && !sym->attr.public_used)
-	{
-	  DECL_VISIBILITY (decl) = VISIBILITY_HIDDEN;
-	  DECL_VISIBILITY_SPECIFIED (decl) = true;
-	}
     }
 
   /* If a variable is USE associated, it's always external.  */
@@ -742,7 +739,8 @@ gfc_finish_var_decl (tree decl, gfc_symbol * sym)
 
       TREE_PUBLIC (decl) = 1;
       TREE_STATIC (decl) = 1;
-      if (sym->attr.access == ACCESS_PRIVATE && !sym->attr.public_used)
+      if (sym->attr.access == ACCESS_PRIVATE && !sym->attr.public_used
+	  && !sym->binding_label)
 	{
 	  DECL_VISIBILITY (decl) = VISIBILITY_HIDDEN;
 	  DECL_VISIBILITY_SPECIFIED (decl) = true;
@@ -2639,9 +2637,10 @@ build_function_decl (gfc_symbol * sym, bool global)
       /* Mirror the variable treatment (see gfc_finish_var_decl): PRIVATE
 	 module procedures get global linkage but hidden visibility so the
 	 symbol is reachable from submodules in the same link without being
-	 exported to external DSOs.  */
+	 exported to external DSOs.  A binding label has external linkage,
+	 so PRIVATE hides only the Fortran name.  */
       if (in_module_contains && sym->attr.access == ACCESS_PRIVATE
-	  && !sym->attr.public_used)
+	  && !sym->attr.public_used && !sym->binding_label)
 	{
 	  DECL_VISIBILITY (fndecl) = VISIBILITY_HIDDEN;
 	  DECL_VISIBILITY_SPECIFIED (fndecl) = true;
diff --git a/gcc/testsuite/gfortran.dg/bind_c_private_1.f90 b/gcc/testsuite/gfortran.dg/bind_c_private_1.f90
new file mode 100644
index 00000000000..9caacbb21c7
--- /dev/null
+++ b/gcc/testsuite/gfortran.dg/bind_c_private_1.f90
@@ -0,0 +1,30 @@
+! { dg-do compile }
+! { dg-require-visibility "" }
+!
+! PR fortran/126872
+!
+! A binding label gives external linkage, so PRIVATE must hide only the
+! Fortran name and must not give the symbol hidden ELF visibility.
+! Module entities without a binding label keep the hidden visibility
+! introduced by PR fortran/125430.
+
+module m
+  use iso_c_binding
+  implicit none
+  private
+  integer(c_int), bind(C, name="bc_var") :: bc_var
+  integer :: plain_var
+contains
+  subroutine bc_named() bind(C, name="bc_named")
+  end subroutine bc_named
+  subroutine bc_unnamed() bind(C)
+  end subroutine bc_unnamed
+  subroutine plain_sub()
+  end subroutine plain_sub
+end module m
+
+! { dg-final { scan-assembler-not "\\.hidden\[ \t\]+bc_var" } }
+! { dg-final { scan-assembler-not "\\.hidden\[ \t\]+bc_named" } }
+! { dg-final { scan-assembler-not "\\.hidden\[ \t\]+bc_unnamed" } }
+! { dg-final { scan-assembler "\\.hidden\[ \t\]+__m_MOD_plain_var" } }
+! { dg-final { scan-assembler "\\.hidden\[ \t\]+__m_MOD_plain_sub" } }
-- 
2.55.0
lmpx.com only provides a reader for public news (NNTP) servers. It is not affiliated with the servers or forums shown here and is not responsible for the content of articles, which is written by their respective authors.