This is the mail archive of the
gcc-patches@gcc.gnu.org
mailing list for the GCC project.
[PATCH] Builtins and C++ and such (take 3)
- From: Roger Sayle <roger at eyesopen dot com>
- To: Mark Mitchell <mark at codesourcery dot com>, <gcc-patches at gcc dot gnu dot org>
- Cc: Gabriel Dos Reis <gdr at codesourcery dot com>, Fergus Henderson <fjh at cs dot mu dot oz dot au>, Jason Merrill <jason at redhat dot com>, Benjamin Kosnik <bkoz at redhat dot com>, <libstdc++ at gcc dot gnu dot org>
- Date: Thu, 28 Mar 2002 06:41:32 -0700 (MST)
- Subject: [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