This is the mail archive of the gcc-patches@gcc.gnu.org mailing list for the GCC project.


Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]
Other format: [Raw text]

[PATCH] Fix PR c++/25940


Hi,

The following patch fixes two issues: the first 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 with 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.  This 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 but I don't think they are related to this patch.

	PR c++/25940
	* name-lookup.c (pushdecl_maybe_friend_1): Bail 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.

diff --git a/gcc/cp/name-lookup.c b/gcc/cp/name-lookup.c
index ea16061..0ee4f4c 100644
--- a/gcc/cp/name-lookup.c
+++ b/gcc/cp/name-lookup.c
@@ -861,6 +861,15 @@ 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);
+		      return error_mark_node;
+		    }
 		  x_exception_spec =
 				TYPE_RAISES_EXCEPTIONS (TREE_TYPE (x));
 		  previous_exception_spec =
@@ -877,7 +886,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 +2150,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 +2162,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 +2183,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..37424d6
--- /dev/null
+++ b/gcc/testsuite/g++.dg/lookup/extern-c-redecl6.C
@@ -0,0 +1,29 @@
+// PR c++/25940
+
+namespace X {
+  extern "C" void foo () throw ();
+}
+
+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 ();
+}
-- 


Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]