Dear All,

the attached patch addresses a rather old (> 14 years) issue.
We generated warnings for standard conforming code, where a symbol
was given a bind(c) attribute and at the same time declared PRIVATE.

I checked a bunch of compilers, and none gave warnings, except for
NAG, which did warn, but only if the binding name were the same as
the default name.

I considered this to be a good solution, and decided to "hide" the
warning behind -Wsurprising (contained in -Wall).

What do others think?

Attached has been regtested on x86_64-pc-linux-gnu.  OK for mainline?

Thanks,
Harald

From 20391f46a7052c0faf85aee666e995d2a538498d Mon Sep 17 00:00:00 2001
From: Harald Anlauf <[email protected]>
Date: Tue, 7 Oct 2025 21:54:45 +0200
Subject: [PATCH] Fortran: fix warnings for symbols with C binding and declared
 PRIVATE [PR49111]

The Fortran standard does not prohibit restricting the accessibility of a
symbol by use of the PRIVATE attribute and exposing it via a C binding
label.  Instead of unconditionally generating a warning, only warn if the
binding label is surprisingly identical to the privatized Fortran symbol
and when -Wsurprising is specified.

	PR fortran/49111

gcc/fortran/ChangeLog:

	* decl.cc (verify_bind_c_sym): Modify condition for generation of
	accessibility warning, and adjust warning message.

gcc/testsuite/ChangeLog:

	* gfortran.dg/binding_label_tests_9.f03: Adjust test.
	* gfortran.dg/module_private_2.f90: Likewise.
	* gfortran.dg/public_private_module_2.f90: Likewise.
	* gfortran.dg/binding_label_tests_35.f90: New test.
---
 gcc/fortran/decl.cc                           | 18 +++++++------
 .../gfortran.dg/binding_label_tests_35.f90    | 21 +++++++++++++++
 .../gfortran.dg/binding_label_tests_9.f03     |  5 ++--
 .../gfortran.dg/module_private_2.f90          |  2 +-
 .../gfortran.dg/public_private_module_2.f90   | 26 +++++++++----------
 5 files changed, 48 insertions(+), 24 deletions(-)
 create mode 100644 gcc/testsuite/gfortran.dg/binding_label_tests_35.f90

diff --git a/gcc/fortran/decl.cc b/gcc/fortran/decl.cc
index 3761b6589e8..65c8829e741 100644
--- a/gcc/fortran/decl.cc
+++ b/gcc/fortran/decl.cc
@@ -6373,15 +6373,17 @@ verify_bind_c_sym (gfc_symbol *tmp_sym, gfc_typespec *ts,
 			 &(tmp_sym->declared_at));
     }
 
-  /* See if the symbol has been marked as private.  If it has, make sure
-     there is no binding label and warn the user if there is one.  */
+  /* See if the symbol has been marked as private.  If it has, warn if
+     there is a binding label with default binding name.  */
   if (tmp_sym->attr.access == ACCESS_PRIVATE
-      && tmp_sym->binding_label)
-      /* Use gfc_warning_now because we won't say that the symbol fails
-	 just because of this.	*/
-      gfc_warning_now (0, "Symbol %qs at %L is marked PRIVATE but has been "
-		       "given the binding label %qs", tmp_sym->name,
-		       &(tmp_sym->declared_at), tmp_sym->binding_label);
+      && tmp_sym->binding_label
+      && strcmp (tmp_sym->name, tmp_sym->binding_label) == 0
+      && (tmp_sym->attr.flavor == FL_VARIABLE
+	  || tmp_sym->attr.if_source == IFSRC_DECL))
+    gfc_warning (OPT_Wsurprising,
+		 "Symbol %qs at %L is marked PRIVATE but is accessible "
+		 "via its default binding name %qs", tmp_sym->name,
+		 &(tmp_sym->declared_at), tmp_sym->binding_label);
 
   return retval;
 }
diff --git a/gcc/testsuite/gfortran.dg/binding_label_tests_35.f90 b/gcc/testsuite/gfortran.dg/binding_label_tests_35.f90
new file mode 100644
index 00000000000..ae3973fe5bf
--- /dev/null
+++ b/gcc/testsuite/gfortran.dg/binding_label_tests_35.f90
@@ -0,0 +1,21 @@
+! { dg-do compile }
+! { dg-options "-Wsurprising" }
+! PR fortran/49111
+!
+! Do not warn for interface declarations with C binding declared PRIVATE
+
+module mod1
+  use iso_c_binding
+  implicit none
+  save
+
+  interface
+     function strerror(errnum) bind(C, NAME = 'strerror')
+       import
+       type(C_PTR) :: strerror
+       integer(C_INT), value :: errnum
+     end function strerror
+  end interface
+
+  private strerror
+end module mod1
diff --git a/gcc/testsuite/gfortran.dg/binding_label_tests_9.f03 b/gcc/testsuite/gfortran.dg/binding_label_tests_9.f03
index bb61cbf12c7..81d74af019e 100644
--- a/gcc/testsuite/gfortran.dg/binding_label_tests_9.f03
+++ b/gcc/testsuite/gfortran.dg/binding_label_tests_9.f03
@@ -1,4 +1,5 @@
 ! { dg-do compile }
+! { dg-options "-Wsurprising" }
 module x
   use iso_c_binding
   implicit none
@@ -7,13 +8,13 @@ module x
   private :: my_private_sub_2
   public :: my_public_sub
 contains
-  subroutine bar() bind(c,name="foo") ! { dg-warning "PRIVATE but has been given the binding label" }
+  subroutine bar() bind(c,name="foo")
   end subroutine bar
   
   subroutine my_private_sub() bind(c, name="")
   end subroutine my_private_sub
 
-  subroutine my_private_sub_2() bind(c) ! { dg-warning "PRIVATE but has been given the binding label" }
+  subroutine my_private_sub_2() bind(c) ! { dg-warning "is marked PRIVATE" }
   end subroutine my_private_sub_2
 
   subroutine my_public_sub() bind(c, name="my_sub")
diff --git a/gcc/testsuite/gfortran.dg/module_private_2.f90 b/gcc/testsuite/gfortran.dg/module_private_2.f90
index 847c58d5e37..58dbb1e23fe 100644
--- a/gcc/testsuite/gfortran.dg/module_private_2.f90
+++ b/gcc/testsuite/gfortran.dg/module_private_2.f90
@@ -1,5 +1,5 @@
 ! { dg-do compile }
-! { dg-options "-O2 -fdump-tree-optimized" }
+! { dg-options "-O2 -Wsurprising -fdump-tree-optimized" }
 !
 ! PR fortran/47266
 !
diff --git a/gcc/testsuite/gfortran.dg/public_private_module_2.f90 b/gcc/testsuite/gfortran.dg/public_private_module_2.f90
index e84429e1003..87276ccdfd1 100644
--- a/gcc/testsuite/gfortran.dg/public_private_module_2.f90
+++ b/gcc/testsuite/gfortran.dg/public_private_module_2.f90
@@ -1,5 +1,5 @@
 ! { dg-do compile }
-! { dg-options "-O2" }
+! { dg-options "-O2 -Wsurprising" }
 ! { dg-require-visibility "" }
 !
 ! PR fortran/52751 (top, "module mod")
@@ -8,16 +8,16 @@
 ! Ensure that (only) those module variables and procedures which are PRIVATE
 ! and have no C-binding label are optimized away.
 !
-      module mod
-        integer :: aa
-        integer, private :: iii
-        integer, private, bind(C) :: jj             ! { dg-warning "PRIVATE but has been given the binding label" }
-        integer, private, bind(C,name='lll') :: kk  ! { dg-warning "PRIVATE but has been given the binding label" }
-        integer, private, bind(C,name='') :: mmmm
-        integer, bind(C) :: nnn
-        integer, bind(C,name='oo') :: pp
-        integer, bind(C,name='') :: qq
-      end module mod
+module mod
+  integer :: aa
+  integer, private :: iii
+  integer, private, bind(C) :: jj       ! { dg-warning "is marked PRIVATE" }
+  integer, private, bind(C,name='lll') :: kk
+  integer, private, bind(C,name='') :: mmmm
+  integer, bind(C) :: nnn
+  integer, bind(C,name='oo') :: pp
+  integer, bind(C,name='') :: qq
+end module mod
 
 ! The two xfails below have appeared with the introduction of submodules. 'iii' and
 ! 'mmm' now are TREE_PUBLIC but has DECL_VISIBILITY (decl) = VISIBILITY_HIDDEN set.
@@ -43,10 +43,10 @@ CONTAINS
   integer FUNCTION two()
      two = 42
   END FUNCTION two
-  integer FUNCTION three() bind(C) ! { dg-warning "PRIVATE but has been given the binding label" }
+  integer FUNCTION three() bind(C) ! { dg-warning "is marked PRIVATE" }
      three = 43
   END FUNCTION three
-  integer FUNCTION four() bind(C, name='five') ! { dg-warning "PRIVATE but has been given the binding label" }
+  integer FUNCTION four() bind(C, name='five')
      four = 44
   END FUNCTION four
   integer FUNCTION six() bind(C, name='')
-- 
2.51.0

Reply via email to