[PATCH v2] Fix PR c++/25940

Patrick Palka patrick@parcs.ath.cx
Sun Mar 2 00:27:00 GMT 2014


Hi,

The following patch fixes two issues: the first issue is PR c++/25940 and the
second is related to PR c++/13699.

The first issue is that the C++ frontend fails to reject duplicate definitions
of functions declared to have C language linkage.  This results in the compiler
emitting ASM that defines the same symbol more than once.

The second issue is that upon encountering a redeclaration of an extern "C"
function with a different exception specification, the C++ frontend fails to
add the new declaration to the list of things declared in the current namespace
(because we exit early from pushdecl_maybe_friend_1).  This behavior makes the
new declaration appear to be not in scope.

I bootstrapped and regtested this patch on x86_64-unknown-linux-gnu.  I had a
few guality and cilk FAILs though I don't think they are related to this patch.

I have not yet finalized my copyright assignment but I would appreciate any
comments on the patch (this is my first substantive patch to GCC).  Would this
patch be OK for trunk once my copyright assignment is in place?

Changes in v2:
  No longer return error_mark_node after emitting a redefinition error.
  Simplified the new testcase "extern-c-redecl6.C".
  CC'd the C++ maintainer.

Regards,
Patrick


	PR c++/25940
	* name-lookup.c (pushdecl_maybe_friend_1): Emit an error when a
	function with C language linkage is redefined.  Don't return
	error_mark_node after a function with C language linkage is
	redeclared with a different exception specification.
	(lookup_extern_c_fun_in_all_ns): Prefer returning an existing
	function definition instead of a declaration.

	PR c++/25940
	* g++.dg/lookup/extern-c-redecl6.C: New test.
	* g++.dg/lookup/extern-c-redecl7.C: New test.
---
 gcc/cp/name-lookup.c                           | 23 ++++++++++++++++++-----
 gcc/testsuite/g++.dg/lookup/extern-c-redecl6.C | 25 +++++++++++++++++++++++++
 gcc/testsuite/g++.dg/lookup/extern-c-redecl7.C | 12 ++++++++++++
 3 files changed, 55 insertions(+), 5 deletions(-)
 create mode 100644 gcc/testsuite/g++.dg/lookup/extern-c-redecl6.C
 create mode 100644 gcc/testsuite/g++.dg/lookup/extern-c-redecl7.C

diff --git a/gcc/cp/name-lookup.c b/gcc/cp/name-lookup.c
index ea16061..c797193 100644
--- a/gcc/cp/name-lookup.c
+++ b/gcc/cp/name-lookup.c
@@ -861,6 +861,14 @@ pushdecl_maybe_friend_1 (tree x, bool is_friend)
 		  tree x_exception_spec = NULL_TREE;
 		  tree previous_exception_spec = NULL_TREE;
 
+		  if (DECL_INITIAL (x) && DECL_INITIAL (previous))
+		    {
+		      error_at (input_location,
+				"redefinition of %q+#D with C language linkage",
+				x);
+		      inform (input_location,
+			      "%q+#D previously defined here", previous);
+		    }
 		  x_exception_spec =
 				TYPE_RAISES_EXCEPTIONS (TREE_TYPE (x));
 		  previous_exception_spec =
@@ -877,7 +885,6 @@ pushdecl_maybe_friend_1 (tree x, bool is_friend)
 			       previous);
 		      pedwarn (input_location, 0,
                                "due to different exception specifications");
-		      return error_mark_node;
 		    }
 		  if (DECL_ASSEMBLER_NAME_SET_P (previous))
 		    SET_DECL_ASSEMBLER_NAME (x,
@@ -2142,8 +2149,10 @@ binding_for_name (cp_binding_level *scope, tree name)
 }
 
 /* Walk through the bindings associated to the name of FUNCTION,
-   and return the first declaration of a function with a
-   "C" linkage specification, a.k.a 'extern "C"'.
+   and return the first definition of a function with a
+   "C" linkage specification, a.k.a 'extern "C"'.  If no previous
+   definition exists, return the first declaration of the function.
+
    This function looks for the binding, regardless of which scope it
    has been defined in. It basically looks in all the known scopes.
    Note that this function does not lookup for bindings of builtin functions
@@ -2152,6 +2161,7 @@ static tree
 lookup_extern_c_fun_in_all_ns (tree function)
 {
   tree name;
+  tree ret = NULL_TREE;
   cxx_binding *iter;
 
   gcc_assert (function && TREE_CODE (function) == FUNCTION_DECL);
@@ -2172,11 +2182,14 @@ lookup_extern_c_fun_in_all_ns (tree function)
 	      && DECL_EXTERN_C_P (decl)
 	      && !DECL_ARTIFICIAL (decl))
 	    {
-	      return decl;
+	      if (DECL_INITIAL (decl))
+		return decl;
+	      if (!ret)
+		ret = decl;
 	    }
 	}
     }
-  return NULL;
+  return ret;
 }
 
 /* Returns a list of C-linkage decls with the name NAME.  */
diff --git a/gcc/testsuite/g++.dg/lookup/extern-c-redecl6.C b/gcc/testsuite/g++.dg/lookup/extern-c-redecl6.C
new file mode 100644
index 0000000..7577d3c
--- /dev/null
+++ b/gcc/testsuite/g++.dg/lookup/extern-c-redecl6.C
@@ -0,0 +1,25 @@
+// PR c++/25940
+
+namespace A {
+  extern "C" void foo () // { dg-message "previously defined" }
+  {
+  }
+}
+
+namespace Y {
+  extern "C" void foo ();
+}
+
+namespace B {
+  extern "C" void foo () // { dg-error "redefinition" }
+  {
+  }
+}
+
+namespace Z {
+  extern "C" void foo ();
+}
+
+extern "C" void foo () // { dg-error "redefinition" }
+{
+}
diff --git a/gcc/testsuite/g++.dg/lookup/extern-c-redecl7.C b/gcc/testsuite/g++.dg/lookup/extern-c-redecl7.C
new file mode 100644
index 0000000..2210417
--- /dev/null
+++ b/gcc/testsuite/g++.dg/lookup/extern-c-redecl7.C
@@ -0,0 +1,12 @@
+namespace A {
+  extern "C" void foo () throw (); // { dg-error "previous declaration" }
+}
+
+namespace B {
+  extern "C" void foo (); // { dg-error "declaration of|different exception" }
+}
+
+void bar ()
+{
+  B::foo ();
+}
-- 
1.9.0



More information about the Gcc-patches mailing list