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

Kriang Lerdsuwanakij lerdsuwa@scf.usc.edu
Tue Oct 10 21:09:00 GMT 2000


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();
+ }



More information about the Gcc-patches mailing list