This is the mail archive of the
gcc-patches@gcc.gnu.org
mailing list for the GCC project.
[C++ PATCH] Fix extern "C" function and namespace handling (Revised)
- To: gcc-patches at gcc dot gnu dot org
- Subject: [C++ PATCH] Fix extern "C" function and namespace handling (Revised)
- From: Kriang Lerdsuwanakij <lerdsuwa at scf dot usc dot edu>
- Date: Tue, 10 Oct 2000 21:08:51 -0700 (PDT)
Hi
The included patch is a revised version of the patch posted earlier
to fix the extern "C" function and namespace handling to comply
with 7.5p6 of the standard. This version fixes a bug in
push_overloaded_decl() so that it returns the correct tree node.
There are some small test simplification and comment addition.
--Kriang
=================
2000-10-10 Kriang Lerdsuwanakij <lerdsuwa@users.sourceforge.net>
* decl.c (expand_binding): Split out from binding_for_name.
(binding_for_name): Use it.
(find_extern_c, find_extern_c_function,
extern_c_declare_context_p): New functions.
(decls_match): Test for extern "C" function declaration in
the scope of newdecl.
(duplicate_decls): Declarations in different contexts are not
the same function if both are not declared extern "C".
(push_overloaded_decl): Search for a C linkage function with the
same name.
(redeclaration_error_message): Test if both declarations are
extern "C" functions and enforce ODR.
diff -cprN gcc-old/cp/decl.c gcc/cp/decl.c
*** gcc-old/cp/decl.c Tue Oct 10 00:50:18 2000
--- gcc/cp/decl.c Tue Oct 10 18:16:41 2000
*************** static int add_binding PARAMS ((tree, tr
*** 143,148 ****
--- 143,152 ----
static void pop_binding PARAMS ((tree, tree));
static tree local_variable_p_walkfn PARAMS ((tree *, int *, void *));
static tree find_binding PARAMS ((tree, tree));
+ static tree expand_binding PARAMS ((tree));
+ static tree find_extern_c PARAMS ((tree));
+ static tree find_extern_c_function PARAMS ((tree));
+ static int extern_c_declare_context_p PARAMS ((tree, tree));
static tree select_decl PARAMS ((tree, int));
static int lookup_flags PARAMS ((int, int));
static tree qualify_lookup PARAMS ((tree, int));
*************** find_binding (name, scope)
*** 2212,2217 ****
--- 2216,2240 ----
return NULL_TREE;
}
+ /* Convert namespace_bindings to a list if it is not empty. */
+
+ static tree
+ expand_binding (name)
+ tree name;
+ {
+ tree b = IDENTIFIER_NAMESPACE_BINDINGS (name);
+
+ if (b && TREE_CODE (b) != CPLUS_BINDING)
+ {
+ /* Get rid of optimization for global scope. */
+ IDENTIFIER_NAMESPACE_BINDINGS (name) = NULL_TREE;
+ BINDING_VALUE (binding_for_name (name, global_namespace)) = b;
+ b = IDENTIFIER_NAMESPACE_BINDINGS (name);
+ }
+
+ return b;
+ }
+
/* Always returns a binding for name in scope. If the
namespace_bindings is not a list, convert it to one first.
If no binding is found, make a new one. */
*************** binding_for_name (name, scope)
*** 2221,2238 ****
tree name;
tree scope;
{
! tree b = IDENTIFIER_NAMESPACE_BINDINGS (name);
tree result;
scope = ORIGINAL_NAMESPACE (scope);
- if (b && TREE_CODE (b) != CPLUS_BINDING)
- {
- /* Get rid of optimization for global scope. */
- IDENTIFIER_NAMESPACE_BINDINGS (name) = NULL_TREE;
- BINDING_VALUE (binding_for_name (name, global_namespace)) = b;
- b = IDENTIFIER_NAMESPACE_BINDINGS (name);
- }
if (b && (result = find_binding (name, scope)))
return result;
/* Not found, make a new one. */
--- 2244,2254 ----
tree name;
tree scope;
{
! tree b = expand_binding (name);
tree result;
scope = ORIGINAL_NAMESPACE (scope);
if (b && (result = find_binding (name, scope)))
return result;
/* Not found, make a new one. */
*************** binding_for_name (name, scope)
*** 2245,2250 ****
--- 2261,2355 ----
return result;
}
+ /* Find an `extern "C"' function in BINDING. */
+
+ static tree
+ find_extern_c (binding)
+ tree binding;
+ {
+ tree value;
+ if (TREE_CODE (binding) != CPLUS_BINDING)
+ value = binding;
+ else
+ value = BINDING_VALUE (binding);
+ if (!value)
+ return value;
+
+ switch(TREE_CODE (value))
+ {
+ case FUNCTION_DECL:
+ if (DECL_EXTERN_C_P (value))
+ return value;
+ break;
+
+ case OVERLOAD:
+ for (; value; value = OVL_NEXT (value))
+ {
+ tree t = OVL_CURRENT (value);
+ if (DECL_EXTERN_C_P (t))
+ return t;
+ }
+ }
+
+ return NULL_TREE;
+ }
+
+ /* Find an `extern "C"' in all bindings associated with NAME. */
+
+ static tree
+ find_extern_c_function (name)
+ tree name;
+ {
+ tree iter;
+
+ for (iter = IDENTIFIER_NAMESPACE_BINDINGS (name); iter;
+ iter = TREE_CHAIN (iter))
+ {
+ tree value = find_extern_c (iter);
+ if (value)
+ return value;
+ }
+ return NULL_TREE;
+ }
+
+ /* If DECL is an `extern "C"' function, it can be declared in
+ several namespaces. For example:
+
+ extern "C" int f(); // 1
+ namespace n {
+ extern "C" int f(); // 2
+ int f(); // 3
+ }
+
+ When we process declaration 3, the same FUNCTION_DECL is used
+ for both declarations 1 and 2. So using CP_DECL_CONTEXT only
+ finds the namespace DECL f() is first declared. This function
+ correctly decides whether this function is declared in CONTEXT
+ by walking through all namespace bindings. So that declaration
+ 3 can inherit the C linkage from 2.
+
+ Returns 1 if DECL is an `extern "C"' function that is redeclared
+ in CONTEXT. Otherwise, returns 0. */
+
+ static int
+ extern_c_declare_context_p (decl, context)
+ tree decl;
+ tree context;
+ {
+ tree name = DECL_NAME (decl);
+ tree b = expand_binding (name);
+ tree result;
+
+ if (!DECL_EXTERN_C_P (decl))
+ return 0;
+
+ if (b && (result = find_binding (name, ORIGINAL_NAMESPACE (context)))
+ && find_extern_c (result))
+ return 1;
+ else
+ return 0;
+ }
+
/* Return the binding value for name in scope, considering that
namespace_binding may or may not be a list of CPLUS_BINDINGS. */
*************** decls_match (newdecl, olddecl)
*** 2979,2992 ****
tree p1 = TYPE_ARG_TYPES (f1);
tree p2 = TYPE_ARG_TYPES (f2);
- if (CP_DECL_CONTEXT (newdecl) != CP_DECL_CONTEXT (olddecl)
- && ! (DECL_EXTERN_C_P (newdecl)
- && DECL_EXTERN_C_P (olddecl)))
- return 0;
-
if (TREE_CODE (f1) != TREE_CODE (f2))
return 0;
if (same_type_p (TREE_TYPE (f1), TREE_TYPE (f2)))
{
if (p2 == NULL_TREE && DECL_EXTERN_C_P (olddecl)
--- 3084,3097 ----
tree p1 = TYPE_ARG_TYPES (f1);
tree p2 = TYPE_ARG_TYPES (f2);
if (TREE_CODE (f1) != TREE_CODE (f2))
return 0;
+ if (CP_DECL_CONTEXT (newdecl) != CP_DECL_CONTEXT (olddecl)
+ && ! (DECL_EXTERN_C_P (newdecl) && DECL_EXTERN_C_P (olddecl))
+ && !extern_c_declare_context_p (olddecl, CP_DECL_CONTEXT (newdecl)))
+ return 0;
+
if (same_type_p (TREE_TYPE (f1), TREE_TYPE (f2)))
{
if (p2 == NULL_TREE && DECL_EXTERN_C_P (olddecl)
*************** duplicate_decls (newdecl, olddecl)
*** 3241,3247 ****
}
else if (!types_match)
{
! if (CP_DECL_CONTEXT (newdecl) != CP_DECL_CONTEXT (olddecl))
/* These are certainly not duplicate declarations; they're
from different scopes. */
return 0;
--- 3346,3353 ----
}
else if (!types_match)
{
! if (CP_DECL_CONTEXT (newdecl) != CP_DECL_CONTEXT (olddecl)
! && ! (DECL_EXTERN_C_P (newdecl) && DECL_EXTERN_C_P (olddecl)))
/* These are certainly not duplicate declarations; they're
from different scopes. */
return 0;
*************** push_overloaded_decl (decl, flags)
*** 4615,4620 ****
--- 4721,4737 ----
if (flags & PUSH_USING)
OVL_USED (new_binding) = 1;
}
+ else if (DECL_EXTERN_C_P (decl))
+ {
+ /* An `extern "C"' function not previously declared in
+ this scope. */
+ tree d = find_extern_c_function (name);
+ if (d && duplicate_decls (decl, d))
+ /* Reuse old declaration. */
+ decl = d;
+
+ new_binding = decl;
+ }
else
/* NAME is not ambiguous. */
new_binding = decl;
*************** redeclaration_error_message (newdecl, ol
*** 4726,4731 ****
--- 4843,4862 ----
abort()). Don't complain about redefinition in this case. */
if (DECL_LANG_SPECIFIC (olddecl) && DECL_PURE_VIRTUAL_P (olddecl))
return 0;
+
+ /* If both are `extern "C"' functions or if an `extern "C"' function
+ is declared of OLDDECL in the scope of NEWDECL, this is a
+ redeclaration. */
+ if ((DECL_EXTERN_C_P (newdecl) && DECL_EXTERN_C_P (olddecl))
+ || extern_c_declare_context_p (olddecl, CP_DECL_CONTEXT (newdecl)))
+ {
+ /* Make sure it is not defined twice. */
+ if (DECL_INITIAL (olddecl) != NULL_TREE
+ && DECL_INITIAL (newdecl) != NULL_TREE)
+ return "redefinition of `%#D'";
+ else
+ return 0;
+ }
/* If both functions come from different namespaces, this is not
a redeclaration - this is a conflict with a used function. */
diff -cprN gcc-old/testsuite/g++.old-deja/g++.ns/extern2.C gcc/testsuite/g++.old-deja/g++.ns/extern2.C
*** gcc-old/testsuite/g++.old-deja/g++.ns/extern2.C Wed Dec 31 16:00:00 1969
--- gcc/testsuite/g++.old-deja/g++.ns/extern2.C Fri Oct 6 19:18:34 2000
***************
*** 0 ****
--- 1,18 ----
+ // Build don't link:
+ // Copyright (C) 2000 Free Software Foundation, Inc.
+ // Contributed by Kriang Lerdsuwanakij <lerdsuwa@users.sourceforge.net>
+
+ // Test if extern "C" functions refer to the same function.
+
+ extern "C" int f();
+ namespace n {
+ extern "C" int f();
+ };
+
+ using namespace n;
+
+ int main()
+ {
+ f();
+ n::f();
+ }
diff -cprN gcc-old/testsuite/g++.old-deja/g++.ns/extern3.C gcc/testsuite/g++.old-deja/g++.ns/extern3.C
*** gcc-old/testsuite/g++.old-deja/g++.ns/extern3.C Wed Dec 31 16:00:00 1969
--- gcc/testsuite/g++.old-deja/g++.ns/extern3.C Fri Oct 6 19:18:34 2000
***************
*** 0 ****
--- 1,19 ----
+ // Build don't link:
+ // Copyright (C) 2000 Free Software Foundation, Inc.
+ // Contributed by Kriang Lerdsuwanakij <lerdsuwa@users.sourceforge.net>
+
+ // Test if extern "C" function can be redeclared without linkage
+ // specification.
+
+ extern "C" int f();
+ namespace n {
+ extern "C" int f();
+ int f();
+ };
+ int f();
+
+ int main()
+ {
+ f();
+ n::f();
+ }
diff -cprN gcc-old/testsuite/g++.old-deja/g++.ns/extern4.C gcc/testsuite/g++.old-deja/g++.ns/extern4.C
*** gcc-old/testsuite/g++.old-deja/g++.ns/extern4.C Wed Dec 31 16:00:00 1969
--- gcc/testsuite/g++.old-deja/g++.ns/extern4.C Fri Oct 6 19:18:34 2000
***************
*** 0 ****
--- 1,23 ----
+ // Build don't run:
+ // Copyright (C) 2000 Free Software Foundation, Inc.
+ // Contributed by Kriang Lerdsuwanakij <lerdsuwa@users.sourceforge.net>
+
+ // Test defining extern "C" function.
+
+ extern "C" int f();
+ namespace n {
+ extern "C" int f();
+ };
+
+ int f()
+ {
+ return 0;
+ }
+
+ using namespace n;
+
+ int main()
+ {
+ f();
+ n::f();
+ }
diff -cprN gcc-old/testsuite/g++.old-deja/g++.ns/extern5.C gcc/testsuite/g++.old-deja/g++.ns/extern5.C
*** gcc-old/testsuite/g++.old-deja/g++.ns/extern5.C Wed Dec 31 16:00:00 1969
--- gcc/testsuite/g++.old-deja/g++.ns/extern5.C Fri Oct 6 19:18:34 2000
***************
*** 0 ****
--- 1,23 ----
+ // Build don't run:
+ // Copyright (C) 2000 Free Software Foundation, Inc.
+ // Contributed by Kriang Lerdsuwanakij <lerdsuwa@users.sourceforge.net>
+
+ // Test defining extern "C" function.
+
+ extern "C" int f();
+ namespace n {
+ extern "C" int f();
+ };
+
+ int n::f()
+ {
+ return 0;
+ }
+
+ using namespace n;
+
+ int main()
+ {
+ f();
+ n::f();
+ }
diff -cprN gcc-old/testsuite/g++.old-deja/g++.ns/extern6.C gcc/testsuite/g++.old-deja/g++.ns/extern6.C
*** gcc-old/testsuite/g++.old-deja/g++.ns/extern6.C Wed Dec 31 16:00:00 1969
--- gcc/testsuite/g++.old-deja/g++.ns/extern6.C Fri Oct 6 19:18:34 2000
***************
*** 0 ****
--- 1,28 ----
+ // Build don't link:
+ // Copyright (C) 2000 Free Software Foundation, Inc.
+ // Contributed by Kriang Lerdsuwanakij <lerdsuwa@users.sourceforge.net>
+
+ // Test extern "C" function one definition rule checking.
+
+ extern "C" int f();
+ namespace n {
+ extern "C" int f();
+ };
+
+ int f()
+ { // ERROR - referenced below
+ return 0;
+ }
+
+ int n::f()
+ { // ERROR - function redefined
+ return 0;
+ }
+
+ using namespace n;
+
+ int main()
+ {
+ f();
+ n::f();
+ }