aboutsummaryrefslogtreecommitdiff
path: root/gcc/cp
diff options
context:
space:
mode:
authorDodji Seketeli <dseketel@redhat.com>2008-07-16 23:44:02 +0000
committerDodji Seketeli <dodji@gcc.gnu.org>2008-07-17 01:44:02 +0200
commitecba6c56dbf5914ef24bcce66db3c4cffcd30e22 (patch)
treeaa1a421373609e8d5b06caf8be49f16a831f2782 /gcc/cp
parent7386e3ee260414735222ea6559f3bb94ecd011f9 (diff)
downloadgcc-ecba6c56dbf5914ef24bcce66db3c4cffcd30e22.zip
gcc-ecba6c56dbf5914ef24bcce66db3c4cffcd30e22.tar.gz
gcc-ecba6c56dbf5914ef24bcce66db3c4cffcd30e22.tar.bz2
re PR c++/13699 (Extern "C" routine in different namespaces accepted with different exception signature)
2008-07-16 Dodji Seketeli <dseketel@redhat.com> PR c++/13699 * gcc/cp/name-lookup.c (lookup_extern_c_fun_binding_in_all_ns): New function. (pushdecl_maybe_friend): Check if a redeclaration of extern C function complies with exception specification constraints. From-SVN: r137904
Diffstat (limited to 'gcc/cp')
-rw-r--r--gcc/cp/ChangeLog8
-rw-r--r--gcc/cp/name-lookup.c76
2 files changed, 84 insertions, 0 deletions
diff --git a/gcc/cp/ChangeLog b/gcc/cp/ChangeLog
index 62d2335..8f87551 100644
--- a/gcc/cp/ChangeLog
+++ b/gcc/cp/ChangeLog
@@ -1,3 +1,11 @@
+2008-07-16 Dodji Seketeli <dseketel@redhat.com>
+
+ PR c++/13699
+ * gcc/cp/name-lookup.c (lookup_extern_c_fun_binding_in_all_ns):
+ New function.
+ (pushdecl_maybe_friend): Check if a redeclaration of extern C function
+ complies with exception specification constraints.
+
2008-07-14 Jason Merrill <jason@redhat.com>
* lex.c (init_reswords): Always set D_OBJC.
diff --git a/gcc/cp/name-lookup.c b/gcc/cp/name-lookup.c
index e42f60a..45899c5 100644
--- a/gcc/cp/name-lookup.c
+++ b/gcc/cp/name-lookup.c
@@ -50,6 +50,7 @@ static bool qualified_lookup_using_namespace (tree, tree,
struct scope_binding *, int);
static tree lookup_type_current_level (tree);
static tree push_using_directive (tree);
+static cxx_binding* lookup_extern_c_fun_binding_in_all_ns (tree);
/* The :: namespace. */
@@ -763,6 +764,48 @@ pushdecl_maybe_friend (tree x, bool is_friend)
}
}
+ /* If x has C linkage-specification, (extern "C"),
+ lookup its binding, in case it's already bound to an object.
+ The lookup is done in all namespaces.
+ If we find an existing binding, make sure it has the same
+ exception specification as x, otherwise, bail in error [7.5, 7.6]. */
+ if ((TREE_CODE (x) == FUNCTION_DECL)
+ && DECL_EXTERN_C_P (x)
+ /* We should ignore declarations happening in system headers. */
+ && !DECL_IN_SYSTEM_HEADER (x))
+ {
+ cxx_binding *function_binding =
+ lookup_extern_c_fun_binding_in_all_ns (x);
+ if (function_binding
+ && !DECL_IN_SYSTEM_HEADER (function_binding->value))
+ {
+ tree previous = function_binding->value;
+
+ /* In case either x or previous is declared to throw an exception,
+ make sure both exception speficications are equal. */
+ if (decls_match (x, previous))
+ {
+ tree x_exception_spec = NULL_TREE;
+ tree previous_exception_spec = NULL_TREE;
+
+ x_exception_spec =
+ TYPE_RAISES_EXCEPTIONS (TREE_TYPE (x));
+ previous_exception_spec =
+ TYPE_RAISES_EXCEPTIONS (TREE_TYPE (previous));
+ if (!comp_except_specs (previous_exception_spec,
+ x_exception_spec,
+ true))
+ {
+ pedwarn ("declaration of %q#D with C language linkage", x);
+ pedwarn ("conflicts with previous declaration %q+#D",
+ previous);
+ pedwarn ("due to different exception specifications");
+ POP_TIMEVAR_AND_RETURN (TV_NAME_LOOKUP, error_mark_node);
+ }
+ }
+ }
+ }
+
if (TREE_CODE (x) == FUNCTION_DECL || DECL_FUNCTION_TEMPLATE_P (x))
check_default_args (x);
@@ -1831,6 +1874,39 @@ binding_for_name (cxx_scope *scope, tree name)
return result;
}
+/* Walk through the bindings associated to the name of FUNCTION,
+ and return the first binding that declares a function with a
+ "C" linkage specification, a.k.a 'extern "C"'.
+ 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
+ or for functions declared in system headers. */
+static cxx_binding*
+lookup_extern_c_fun_binding_in_all_ns (tree function)
+{
+ tree name;
+ cxx_binding *iter;
+
+ gcc_assert (function && TREE_CODE (function) == FUNCTION_DECL);
+
+ name = DECL_NAME (function);
+ gcc_assert (name && TREE_CODE (name) == IDENTIFIER_NODE);
+
+ for (iter = IDENTIFIER_NAMESPACE_BINDINGS (name);
+ iter;
+ iter = iter->previous)
+ {
+ if (iter->value
+ && TREE_CODE (iter->value) == FUNCTION_DECL
+ && DECL_EXTERN_C_P (iter->value)
+ && !DECL_ARTIFICIAL (iter->value))
+ {
+ return iter;
+ }
+ }
+ return NULL;
+}
+
/* Insert another USING_DECL into the current binding level, returning
this declaration. If this is a redeclaration, do nothing, and
return NULL_TREE if this not in namespace scope (in namespace