[C++ PATCH] Fix extern "C" function and namespace handling

Kriang Lerdsuwanakij lerdsuwa@scf.usc.edu
Fri Oct 6 20:24:00 GMT 2000


Hi

The included patch fix the extern "C" function and namespace handling
to comply with 7.5p6 of the standard.  Declarations for such functions
in different namespaces are treated as the same function.  One
definition rule is also enforced for these functions across the
namespaces.

The patch make bindings for the name in different namespace point
to the same FUNCTION_DECL.  When a new extern "C" function declaration 
is encountered, find_extern_c* functions will locate the previous 
declaration to reuse in push_overloaded_decl().
The rest of the changes update the rule deciding whether two decl 
nodes refers the same function.  

Test cases are also included in the patch.

--Kriang

==========

2000-10-06  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_redeclare_context): New functions.
	(decls_match): Test if an extern "C" function is redeclared
	in the new scope.
	(duplicate_decls): Test if both decls are not extern "C"
	functions.
	(push_overloaded_decl): Search for a C linkage function with the
	same name.
	(redeclaration_error_message): Test if both boths are extern "C"
	functions and enforce ODR.

==========

diff -cprN gcc-old/cp/decl.c gcc/cp/decl.c
*** gcc-old/cp/decl.c	Fri Oct  6 19:19:32 2000
--- gcc/cp/decl.c	Fri Oct  6 19:18:50 2000
*************** static int add_binding PARAMS ((tree, tr
*** 127,132 ****
--- 127,135 ----
  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 tree select_decl PARAMS ((tree, int));
  static int lookup_flags PARAMS ((int, int));
  static tree qualify_lookup PARAMS ((tree, int));
*************** find_binding (name, scope)
*** 2196,2201 ****
--- 2199,2223 ----
    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)
*** 2205,2222 ****
       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. */
--- 2227,2237 ----
       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)
*** 2229,2234 ****
--- 2244,2327 ----
    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.  The tree node is shared so that its
+    CP_DECL_CONTEXT only contains the namespace DECL is first declared.
+    This function provides the correct result by walking through
+    all bindings.
+ 
+    Returns 1 if DECL is an `extern "C"' function that is redeclared
+    in CONTEXT.  Otherwise, returns 0.  */
+ 
+ static int
+ extern_c_redeclare_context (decl, context)
+      tree decl, 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)
*** 2965,2971 ****
  
        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))
--- 3058,3065 ----
  
        if (CP_DECL_CONTEXT (newdecl) != CP_DECL_CONTEXT (olddecl)
  	  && ! (DECL_EXTERN_C_P (newdecl)
! 		&& DECL_EXTERN_C_P (olddecl))
! 	  && !extern_c_redeclare_context (olddecl, CP_DECL_CONTEXT (newdecl)))
  	return 0;
  
        if (TREE_CODE (f1) != TREE_CODE (f2))
*************** duplicate_decls (newdecl, olddecl)
*** 3225,3231 ****
      }
    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;
--- 3319,3327 ----
      }
    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)
*** 4599,4604 ****
--- 4695,4710 ----
        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))
+ 	new_binding = d;
+       else
+ 	new_binding = decl;
+     }
    else
      /* NAME is not ambiguous.  */
      new_binding = decl;
*************** redeclaration_error_message (newdecl, ol
*** 4710,4715 ****
--- 4816,4836 ----
  	 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 from different namespaces,
+ 	 or if an `extern "C"' function declaration of OLDDECL in the scope
+ 	 of NEWDECL exists, this is a redeclaration.  */
+       if ((DECL_EXTERN_C_P (newdecl) && DECL_EXTERN_C_P (olddecl)
+ 	   && DECL_CONTEXT (olddecl) != DECL_CONTEXT (newdecl))
+ 	  || extern_c_redeclare_context (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();
+ }



More information about the Gcc-patches mailing list