From ecba6c56dbf5914ef24bcce66db3c4cffcd30e22 Mon Sep 17 00:00:00 2001 From: Dodji Seketeli Date: Wed, 16 Jul 2008 23:44:02 +0000 Subject: [PATCH] re PR c++/13699 (Extern "C" routine in different namespaces accepted with different exception signature) 2008-07-16 Dodji Seketeli 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 --- gcc/cp/ChangeLog | 8 ++ gcc/cp/name-lookup.c | 76 +++++++++++++++++++ gcc/testsuite/ChangeLog | 5 ++ gcc/testsuite/g++.dg/lookup/extern-c-redecl.C | 11 +++ 4 files changed, 100 insertions(+) create mode 100644 gcc/testsuite/g++.dg/lookup/extern-c-redecl.C diff --git a/gcc/cp/ChangeLog b/gcc/cp/ChangeLog index 62d2335dde1..8f87551ee36 100644 --- a/gcc/cp/ChangeLog +++ b/gcc/cp/ChangeLog @@ -1,3 +1,11 @@ +2008-07-16 Dodji Seketeli + + 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 * lex.c (init_reswords): Always set D_OBJC. diff --git a/gcc/cp/name-lookup.c b/gcc/cp/name-lookup.c index e42f60afba7..45899c535e6 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 diff --git a/gcc/testsuite/ChangeLog b/gcc/testsuite/ChangeLog index 33d94fceaec..76d17516bc6 100644 --- a/gcc/testsuite/ChangeLog +++ b/gcc/testsuite/ChangeLog @@ -1,3 +1,8 @@ +2008-07-16 Dodji Seketeli + + PR c++/13699 + * g++.dg/lookup/extern-c-redecl.C: New test. + 2008-07-15 Richard Guenther PR middle-end/36369 diff --git a/gcc/testsuite/g++.dg/lookup/extern-c-redecl.C b/gcc/testsuite/g++.dg/lookup/extern-c-redecl.C new file mode 100644 index 00000000000..31d100a74f9 --- /dev/null +++ b/gcc/testsuite/g++.dg/lookup/extern-c-redecl.C @@ -0,0 +1,11 @@ +// Contributed by Dodji Seketeli +// Origin: PR c++/13699 +// { dg-do compile } + +namespace A { + extern "C" void foo_func () throw(); // { dg-error "conflicts" } +} +// next line should trigger an error because +// it conflicts with previous declaration of foo_func (), due to +// different exception specifications. +extern "C" void foo_func (); // { dg-error "C language|exception specifications" } -- 2.30.2