This is the mail archive of the gcc-patches@gcc.gnu.org mailing list for the GCC project.


Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]
Other format: [Raw text]

[PATCH] Builtins and C++ and such (take 3)



Following concerns that my builtins patch may affect the libstdc++-v3
ABI, I've spent some more time analysing the libstdc++ testsuite
failures with the previous verion of my patch, but without the proposed
changes to cmath.  It transpires that the unresolved symbol problems,
std::abs(double), are caused by a latent bug in g++ and not by any
differences in C/C++ linkage.

The symbols are unresolved not because they are missing from the
libstdc++.{a,so} library, but because they are inline declarations
that are failing to be emitted out-of-line.  Indeed, compiling the
failing cases at -O or -O2 resolves the problems.  The cause is
in duplicate_decls where the DECL_RTL of the redeclaration wasn't
replacing the DECL_RTL of the old declaration.  This then caused
the inlining logic to believe the function had already been output.

The one line fix is the "SET_DECL_RTL (olddecl, DECL_RTL (newdecl))"
hunk in the patch below.  With this hopefully "obvious" change, the
modifications to libstdc++'s cmath are now only required for
performance.  The comment in the code above this change, even mentions
that the old RTL is no longer valid!

I apologise for believing it was a linkage issue.  Once cmath was
reordered for performance reasons, the linker errors went away, and
there were no new regressions in any of the testsuites.  Thanks to
Fergus and Gabriel for forcing me to do the leg work.

I'm resending the entire C++ builtins patch with this one change.
I've also added an extra testcase for the g++ testsuite for this
issue, builtins9.C below.  Tested once again on i686-pc-linux-gnu,
and I've now also tested without this tweak on alphaev67-dec-osf5.1.



2002-03-28  Roger Sayle  <roger@eyesopen.com>
	* decl.c (cxx_init_decl_processing): Re-enable built-in functions
	in the g++ front-end.
	(duplicate_decl): Allow redefinition of anticipated built-ins.
	Fix inlining problem by over-writing the old DECL_RTL.
	(lookup_namespace_name): Fail to find an identifier in the
	specified namespace if its still anticipated.
	(builtin_function_1): New function split out from builtin_function
	to create a builtin in the current namespace with given context.
	(builtin_function): Call builtin_function_1 to define the
	appropriate builtins in both the std and global namespaces.
	(select_decl): Don't test for anticipated decls here.
	(unqualified_namespace_lookup): Instead ignore them whilst
	searching through scopes and namespaces.

	* decl2.c (do_nonmember_using_decl): If a using declaration
	specifies an anticipated built-in function, mark it as no longer
	anticipated in that scope.
	(ambiguous_decl):  Avoid resolving to an anticipated decl.

	* lex.c (do_scoped_id): Fail to find an identifier in the global
	namespace if its still anticipated.

2002-03-28  Roger Sayle  <roger@eyesopen.com>
	* g++.old-deja/g++.other/builtins5.C: New test.
	* g++.old-deja/g++.other/builtins6.C: New test.
	* g++.old-deja/g++.other/builtins7.C: New test.
	* g++.old-deja/g++.other/builtins8.C: New test.
	* g++.old-deja/g++.other/builtins9.C: New test.


diff -c3pr gcc/gcc/cp/decl.c patch/gcc/cp/decl.c
*** gcc/gcc/cp/decl.c	Tue Mar 19 21:31:30 2002
--- patch/gcc/cp/decl.c	Thu Mar 28 05:21:07 2002
*************** static tree lookup_tag PARAMS ((enum tre
*** 87,92 ****
--- 87,94 ----
  static void set_identifier_type_value_with_scope
  	PARAMS ((tree, tree, struct binding_level *));
  static void record_unknown_type PARAMS ((tree, const char *));
+ static tree builtin_function_1 PARAMS ((const char *, tree, tree, int,
+                                       enum built_in_class, const char *));
  static tree build_library_fn_1 PARAMS ((tree, enum tree_code, tree));
  static int member_function_or_else PARAMS ((tree, tree, enum overload_flags));
  static void bad_specifiers PARAMS ((tree, const char *, int, int, int, int,
*************** duplicate_decls (newdecl, olddecl)
*** 3145,3150 ****
--- 3147,3156 ----
      {
        if (TREE_CODE (newdecl) != FUNCTION_DECL)
  	{
+           /* Avoid warnings redeclaring anticipated built-ins.  */
+           if (DECL_ANTICIPATED (olddecl))
+             return 0;
+
  	  /* If you declare a built-in or predefined function name as static,
  	     the old definition is overridden, but optionally warn this was a
  	     bad choice of name.  */
*************** duplicate_decls (newdecl, olddecl)
*** 3172,3178 ****
  	}
        else if (!types_match)
  	{
! 	  if ((DECL_EXTERN_C_P (newdecl)
  	       && DECL_EXTERN_C_P (olddecl))
  	      || compparms (TYPE_ARG_TYPES (TREE_TYPE (newdecl)),
  			    TYPE_ARG_TYPES (TREE_TYPE (olddecl))))
--- 3178,3187 ----
  	}
        else if (!types_match)
  	{
!           /* Avoid warnings redeclaring anticipated built-ins.  */
!           if (DECL_ANTICIPATED (olddecl))
!             ;  /* Do nothing yet.  */
! 	  else if ((DECL_EXTERN_C_P (newdecl)
  	       && DECL_EXTERN_C_P (olddecl))
  	      || compparms (TYPE_ARG_TYPES (TREE_TYPE (newdecl)),
  			    TYPE_ARG_TYPES (TREE_TYPE (olddecl))))
*************** duplicate_decls (newdecl, olddecl)
*** 3614,3619 ****
--- 3623,3629 ----
        TREE_READONLY (olddecl) = TREE_READONLY (newdecl);
        TREE_THIS_VOLATILE (olddecl) = TREE_THIS_VOLATILE (newdecl);
        TREE_SIDE_EFFECTS (olddecl) = TREE_SIDE_EFFECTS (newdecl);
+       SET_DECL_RTL (olddecl, DECL_RTL (newdecl));
      }

    /* Merge the storage class information.  */
*************** lookup_namespace_name (namespace, name)
*** 5507,5513 ****
        /* If we have a single function from a using decl, pull it out.  */
        if (TREE_CODE (val) == OVERLOAD && ! really_overloaded_fn (val))
  	val = OVL_FUNCTION (val);
!       return val;
      }

    error ("`%D' undeclared in namespace `%D'", name, namespace);
--- 5517,5528 ----
        /* If we have a single function from a using decl, pull it out.  */
        if (TREE_CODE (val) == OVERLOAD && ! really_overloaded_fn (val))
  	val = OVL_FUNCTION (val);
!
!       /* Ignore built-in functions that haven't been prototyped yet.  */
!       if (!val || !DECL_P(val)
!           || !DECL_LANG_SPECIFIC(val)
!           || !DECL_ANTICIPATED (val))
!         return val;
      }

    error ("`%D' undeclared in namespace `%D'", name, namespace);
*************** select_decl (binding, flags)
*** 5786,5799 ****
    tree val;
    val = BINDING_VALUE (binding);

-   /* When we implicitly declare some builtin entity, we mark it
-      DECL_ANTICIPATED, so that we know to ignore it until it is
-      really declared.  */
-   if (val && DECL_P (val)
-       && DECL_LANG_SPECIFIC (val)
-       && DECL_ANTICIPATED (val))
-     return NULL_TREE;
-
    if (LOOKUP_NAMESPACES_ONLY (flags))
      {
        /* We are not interested in types. */
--- 5801,5806 ----
*************** unqualified_namespace_lookup (name, flag
*** 5843,5851 ****
  	*spacesp = tree_cons (scope, NULL_TREE, *spacesp);
        val = binding_for_name (name, scope);

!       /* Initialize binding for this context. */
!       BINDING_VALUE (b) = BINDING_VALUE (val);
!       BINDING_TYPE (b) = BINDING_TYPE (val);

        /* Add all _DECLs seen through local using-directives. */
        for (level = current_binding_level;
--- 5850,5870 ----
  	*spacesp = tree_cons (scope, NULL_TREE, *spacesp);
        val = binding_for_name (name, scope);

!       /* Ignore anticipated built-in functions.  */
!       if (val && BINDING_VALUE (val)
!           && DECL_P (BINDING_VALUE (val))
!           && DECL_LANG_SPECIFIC (BINDING_VALUE (val))
!           && DECL_ANTICIPATED (BINDING_VALUE (val)))
!         {
!           BINDING_VALUE (b) = NULL_TREE;
!           BINDING_TYPE (b) = NULL_TREE;
!         }
!       else
!         {
!           /* Initialize binding for this context. */
!           BINDING_VALUE (b) = BINDING_VALUE (val);
!           BINDING_TYPE (b) = BINDING_TYPE (val);
!         }

        /* Add all _DECLs seen through local using-directives. */
        for (level = current_binding_level;
*************** cxx_init_decl_processing ()
*** 6435,6446 ****
        flag_inline_functions = 0;
      }

-   /* In C++, we never create builtin functions whose name does not
-      begin with `__'.  Users should be using headers to get prototypes
-      in C++.  It would be nice if we could warn when `-fbuiltin' is
-      used explicitly, but we do not have that information.  */
-   flag_no_builtin = 1;
-
    /* Initially, C.  */
    current_lang_name = lang_name_c;

--- 6454,6459 ----
*************** cp_make_fname_decl (id, type_dep)
*** 6704,6713 ****
    return decl;
  }

! /* Entry point for the benefit of c_common_nodes_and_builtins.
!
!    Make a definition for a builtin function named NAME and whose data type
!    is TYPE.  TYPE should be a function type with argument types.

     CLASS and CODE tell later passes how to compile calls to this function.
     See tree.h for possible values.
--- 6717,6725 ----
    return decl;
  }

! /* Make a definition for a builtin function named NAME in the current
!    namespace, whose data type is TYPE and whose context is CONTEXT.
!    TYPE should be a function type with argument types.

     CLASS and CODE tell later passes how to compile calls to this function.
     See tree.h for possible values.
*************** cp_make_fname_decl (id, type_dep)
*** 6715,6724 ****
     If LIBNAME is nonzero, use that for DECL_ASSEMBLER_NAME,
     the name to be called if we can't opencode the function.  */

! tree
! builtin_function (name, type, code, class, libname)
       const char *name;
       tree type;
       int code;
       enum built_in_class class;
       const char *libname;
--- 6727,6737 ----
     If LIBNAME is nonzero, use that for DECL_ASSEMBLER_NAME,
     the name to be called if we can't opencode the function.  */

! static tree
! builtin_function_1 (name, type, context, code, class, libname)
       const char *name;
       tree type;
+      tree context;
       int code;
       enum built_in_class class;
       const char *libname;
*************** builtin_function (name, type, code, clas
*** 6726,6748 ****
    tree decl = build_library_fn_1 (get_identifier (name), ERROR_MARK, type);
    DECL_BUILT_IN_CLASS (decl) = class;
    DECL_FUNCTION_CODE (decl) = code;

    /* The return builtins leave the current function.  */
    if (code == BUILT_IN_RETURN || code == BUILT_IN_EH_RETURN)
      TREE_THIS_VOLATILE (decl) = 1;

-   my_friendly_assert (DECL_CONTEXT (decl) == NULL_TREE, 392);
-
-   /* All builtins that don't begin with an `_' should go in the `std'
-      namespace.  */
-   if (name[0] != '_')
-     {
-       push_namespace (std_identifier);
-       DECL_CONTEXT (decl) = std_node;
-     }
    pushdecl (decl);
-   if (name[0] != '_')
-     pop_namespace ();

    /* Since `pushdecl' relies on DECL_ASSEMBLER_NAME instead of DECL_NAME,
       we cannot change DECL_ASSEMBLER_NAME until we have installed this
--- 6739,6751 ----
    tree decl = build_library_fn_1 (get_identifier (name), ERROR_MARK, type);
    DECL_BUILT_IN_CLASS (decl) = class;
    DECL_FUNCTION_CODE (decl) = code;
+   DECL_CONTEXT (decl) = context;

    /* The return builtins leave the current function.  */
    if (code == BUILT_IN_RETURN || code == BUILT_IN_EH_RETURN)
      TREE_THIS_VOLATILE (decl) = 1;

    pushdecl (decl);

    /* Since `pushdecl' relies on DECL_ASSEMBLER_NAME instead of DECL_NAME,
       we cannot change DECL_ASSEMBLER_NAME until we have installed this
*************** builtin_function (name, type, code, clas
*** 6762,6767 ****
--- 6765,6803 ----
    return decl;
  }

+ /* Entry point for the benefit of c_common_nodes_and_builtins.
+
+    Make a defintion for a builtin function named NAME and whose data type
+    is TYPE.  TYPE should be a function type with argument types.  This
+    function places the anticipated declaration in the global namespace
+    and additionally in the std namespace if appropriate.
+
+    CLASS and CODE tell later passes how to compile calls to this function.
+    See tree.h for possible values.
+
+    If LIBNAME is nonzero, use that for DECL_ASSEMBLER_NAME,
+    the name to be called if we can't opencode the function.  */
+
+ tree
+ builtin_function (name, type, code, class, libname)
+      const char *name;
+      tree type;
+      int code;
+      enum built_in_class class;
+      const char *libname;
+ {
+   /* All builtins that don't begin with an '_' should additionally
+      go in the 'std' namespace.  */
+   if (name[0] != '_')
+     {
+       push_namespace (std_identifier);
+       builtin_function_1 (name, type, std_node, code, class, libname);
+       pop_namespace ();
+     }
+
+   return builtin_function_1 (name, type, NULL_TREE, code, class, libname);
+ }
+
  /* Generate a FUNCTION_DECL with the typical flags for a runtime library
     function.  Not called directly.  */

diff -c3pr gcc/gcc/cp/decl2.c patch/gcc/cp/decl2.c
*** gcc/gcc/cp/decl2.c	Wed Mar 20 21:08:25 2002
--- patch/gcc/cp/decl2.c	Sat Mar 23 00:29:58 2002
*************** ambiguous_decl (name, old, new, flags)
*** 4176,4181 ****
--- 4176,4186 ----
          if (LOOKUP_TYPES_ONLY (flags))
            val = NULL_TREE;
          break;
+       case FUNCTION_DECL:
+         /* Ignore built-in functions that are still anticipated.  */
+         if (LOOKUP_QUALIFIERS_ONLY (flags) || DECL_ANTICIPATED (val))
+           val = NULL_TREE;
+         break;
        default:
          if (LOOKUP_QUALIFIERS_ONLY (flags))
            val = NULL_TREE;
*************** do_nonmember_using_decl (scope, name, ol
*** 4928,4933 ****
--- 4933,4947 ----
  	      else if (compparms (TYPE_ARG_TYPES (TREE_TYPE (new_fn)),
  		  		  TYPE_ARG_TYPES (TREE_TYPE (old_fn))))
  		{
+                   /* If this using declaration introduces a function
+                      recognized as a built-in, no longer mark it as
+                      anticipated in this scope.  */
+                   if (DECL_ANTICIPATED (old_fn))
+                     {
+                       DECL_ANTICIPATED (old_fn) = 0;
+                       break;
+                     }
+
  	          /* There was already a non-using declaration in
  		     this scope with the same parameter types. If both
  	             are the same extern "C" functions, that's ok.  */
diff -c3pr gcc/gcc/cp/lex.c patch/gcc/cp/lex.c
*** gcc/gcc/cp/lex.c	Wed Mar 20 21:08:25 2002
--- patch/gcc/cp/lex.c	Sat Mar 23 00:29:09 2002
*************** do_scoped_id (token, parsing)
*** 1325,1331 ****
      id = IDENTIFIER_GLOBAL_VALUE (token);
    if (parsing && yychar == YYEMPTY)
      yychar = yylex ();
!   if (! id)
      {
        if (processing_template_decl)
  	{
--- 1325,1332 ----
      id = IDENTIFIER_GLOBAL_VALUE (token);
    if (parsing && yychar == YYEMPTY)
      yychar = yylex ();
!   if (!id || (TREE_CODE (id) == FUNCTION_DECL
! 	      && DECL_ANTICIPATED (id)))
      {
        if (processing_template_decl)
  	{
*** /dev/null	Thu Aug 30 14:30:55 2001
--- builtins5.C	Wed Mar 20 21:55:21 2002
***************
*** 0 ****
--- 1,16 ----
+ // Build don't link:
+ // Test that built-in functions aren't recognized without a prototype.
+ // Origin: Roger Sayle  Mar 20, 2002
+ // Copyright (C) 2002 Free Software Foundation.
+
+ int
+ foo ()
+ {
+   return (int) ::strlen ("foo"); // ERROR - undeclared
+ }
+
+ int
+ bar ()
+ {
+   return (int) std::strlen ("bar"); // ERROR - undeclared
+ }
*** /dev/null	Thu Aug 30 14:30:55 2001
--- builtins6.C	Thu Mar 21 14:49:57 2002
***************
*** 0 ****
--- 1,18 ----
+ // Test that built-in functions are recognized with a prototype.
+ // Origin: Roger Sayle  Mar 20, 2002
+ // Copyright (C) 2002 Free Software Foundation.
+ //
+ // Special g++ Options: -O2
+
+ typedef __SIZE_TYPE__ size_t;
+ extern "C" size_t strlen (const char*);
+ extern "C" void link_error (void);
+
+ int
+ main ()
+ {
+   if (strlen ("foo") != 3)
+     link_error ();
+   return 0;
+ }
+
*** /dev/null	Thu Aug 30 14:30:55 2001
--- builtins7.C	Thu Mar 21 14:50:08 2002
***************
*** 0 ****
--- 1,20 ----
+ // Test that built-in functions are recognized with a prototype.
+ // Origin: Roger Sayle  Mar 20, 2002
+ // Copyright (C) 2002 Free Software Foundation.
+ //
+ // Special g++ Options: -O2
+
+ extern "C" void link_error (void);
+
+ namespace std {
+ typedef __SIZE_TYPE__ size_t;
+ extern "C" size_t strlen (const char*);
+ }
+
+ int
+ main ()
+ {
+   if (std::strlen ("foo") != 3)
+     link_error ();
+   return 0;
+ }
*** /dev/null	Thu Aug 30 14:30:55 2001
--- builtins8.C	Thu Mar 21 14:50:23 2002
***************
*** 0 ****
--- 1,24 ----
+ // Test that built-in functions are recognized with a prototype.
+ // Origin: Roger Sayle  Mar 20, 2002
+ // Copyright (C) 2002 Free Software Foundation.
+ //
+ // Special g++ Options: -O2
+
+
+ extern "C" void link_error (void);
+
+ namespace std {
+ typedef __SIZE_TYPE__ size_t;
+ extern "C" size_t strlen (const char*);
+ }
+
+ using namespace std;
+
+ int
+ main ()
+ {
+   if (strlen ("foo") != 3)
+     link_error ();
+   return 0;
+ }
+
*** /dev/null	Thu Aug 30 14:30:55 2001
--- builtins9.C	Thu Mar 28 05:54:24 2002
***************
*** 0 ****
--- 1,13 ----
+ // Test that inline redeclarations of builtins are emitted.
+ // Origin: Roger Sayle  Mar 28, 2002
+ // Copyright (C) 2002 Free Software Foundation.
+
+ namespace std {
+    inline int fabs (void) { return 0; }
+ }
+
+
+ int main ()
+ {
+    return std::fabs ();
+ }


Roger
--
Roger Sayle,                         E-mail: roger@eyesopen.com
OpenEye Scientific Software,         WWW: http://www.eyesopen.com/
Suite 1107, 3600 Cerrillos Road,     Tel: (+1) 505-473-7385
Santa Fe, New Mexico, 87507.         Fax: (+1) 505-473-0833


Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]