@@ -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. */
new file mode 100644
@@ -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" }
+{
+}
new file mode 100644
@@ -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 ();
+}