This is the mail archive of the
gcc-patches@gcc.gnu.org
mailing list for the GCC project.
[C++ PATCH]: __FUNCTION__ handling
- To: gcc-patches at gcc dot gnu dot org
- Subject: [C++ PATCH]: __FUNCTION__ handling
- From: Nathan Sidwell <nathan at codesourcery dot com>
- Date: Sun, 05 Mar 2000 10:33:05 +0000
- Organization: CodeSourcery, LLC
Hi,
here's a patch to rework the __FUNCTION__ mechanism in C++, and
add some hooks into C for it. There are a number of bugs in the current
mechanism. The one I originally found was that
template <int I> void foo (char (&)[I]) {};
int main ()
{
foo (__FUNCTION__);
}
wouldn't link, it was missing a definition of `__FUNCTION__.1' (note
the pass by reference).
* The type of __FUNCTION__ elements is `char' not `const char'.
* The size of the array turned out to be 201, not 5 (in this case).
* We failed to emit the local var, when used as a reference (or pointer)
so couldn't link.
* We failed to treat it as
char const __FUNCTION__[] = "main";
but as something akin to
char const (&__FUNCTION)[5] = "main";
This is subtly different, as the latter allows merging all functions
named `main' to the same string (ok, `main's a bad example, as there
can only be one of them). The former is what we and c9x specify the
behaviour as, and allows __func__ to be a unique key for a function.
(The original proposal for __func allowed merging, but no such comment
appears in the FCD. http://wwwold.dkuug.dk/jtc1/sc22/open/n2794/n2794.txt)
To generate the correct array type, required a language dependant hook,
for C it's build_array_type, for C++, build_cplus_array_type is
necessary. Given this necessity, I chose to add a hook which creates
the entire VAR_DECL. The C specific function is essentially what was
declare_hidden_char_array, but the array is the correct type now. C is
otherwise unchanged.
On the C++ side new function cp_make_fname_decl can do all the right
things to create the VAR_DECL, and removes the need from the nadgering
which cp_finish_decl currently does in this regard. This gives things
the correct type, but does not solve the merging or linking problem.
To deal with the merging, I remove a few places where we treat these
VAR_DECL's specially. Finally, as that special handling is removed, we
have to really emit the VAR_DECL, when it's needed. Normally a static
VAR_DECL is emitted at the point of it's definition, but we don't want
to do that, as these VAR_DECLs are created at the start of a function,
before we know whether they are really needed (TREE_ASM_WRITTEN is
currently dinked to prevent the emission). Fortunately, we have
function at a time mode, which gets us out of this bind. We build the
function's statement tree, and add an extra check in expand_stmt (and
wrapup_globals_for_namespace for the top level __FUNCTION__ VAR_DECLs),
which prevents emission of unused static vars. This optimisation is
applied to user statics too.
The C front end is unaffected and will merge common strings, and fails to
link
void foo (char (*)[5]) {}
int main ()
{
foo (&__FUNCTION__);
return 0;
}
to fix these will require function at a time mode in C as well. (Well
delayed emission of static vars at least.)
I attach a test case too, this supercedes g++.brendan/misc12.C.
Ok?
nathan
--
Dr Nathan Sidwell :: http://www.codesourcery.com :: CodeSourcery LLC
'But that's a lie.' - 'Yes it is. What's your point?'
nathan@codesourcery.com : http://www.cs.bris.ac.uk/~nathan/ : nathan@acm.org
gcc/ChangeLog:
2000-03-04 Nathan Sidwell <nathan@codesourcery.com>
* tree.h (make_fname_decl): Declare.
* c-common.c (make_fname_decl): Define.
(declare_hidden_char_array): Remove.
(declare_function_name): Use make_fname_decl.
* c-decl.c (c_make_fname_decl): New function.
(init_decl_processing): Set make_fname_decl.
gcc/cp/ChangeLog:
2000-03-04 Nathan Sidwell <nathan@codesourcery.com>
* decl.c (cp_make_fname_decl): New function.
(wrapup_globals_for_namespace): Don't emit unused static vars.
(init_decl_processing): Remove comment about use of
array_domain_type. Set make_fname_decl.
(cp_finish_decl): Remove __FUNCTION__ nadgering.
* semantics.c (begin_compound_stmt): Remove
current_function_name_declared flagging.
(expand_stmt): Don't emit unused local statics.
* typeck.c (decay_conversion): Don't treat __FUNCTION__ decls
specially.
Index: c-common.c
===================================================================
RCS file: /cvs/gcc/egcs/gcc/c-common.c,v
retrieving revision 1.95
diff -c -3 -p -r1.95 c-common.c
*** c-common.c 2000/03/02 18:29:55 1.95
--- c-common.c 2000/03/04 10:52:07
*************** enum cpp_token cpp_token;
*** 135,140 ****
--- 135,142 ----
tree c_global_trees[CTI_MAX];
+ tree (*make_fname_decl) PARAMS ((tree, const char *, int));
+
/* Nonzero means the expression being parsed will never be evaluated.
This is a count, since unevaluated expressions can nest. */
int skip_evaluation;
*************** enum attrs {A_PACKED, A_NOCOMMON, A_COMM
*** 148,154 ****
enum format_type { printf_format_type, scanf_format_type,
strftime_format_type };
- static void declare_hidden_char_array PARAMS ((const char *, const char *));
static void add_attribute PARAMS ((enum attrs, const char *,
int, int, int));
static void init_attributes PARAMS ((void));
--- 150,155 ----
*************** declare_function_name ()
*** 269,309 ****
name = "";
printable_name = (*decl_printable_name) (current_function_decl, 2);
}
!
! declare_hidden_char_array ("__FUNCTION__", name);
! declare_hidden_char_array ("__PRETTY_FUNCTION__", printable_name);
/* The ISO C people "of course" couldn't use __FUNCTION__ in the
ISO C 99 standard; instead a new variable is invented. */
! declare_hidden_char_array ("__func__", name);
! }
!
! static void
! declare_hidden_char_array (name, value)
! const char *name, *value;
! {
! tree decl, type, init;
! int vlen;
!
! /* If the default size of char arrays isn't big enough for the name,
! or if we want to give warnings for large objects, make a bigger one. */
! vlen = strlen (value) + 1;
! type = char_array_type_node;
! if (TREE_INT_CST_LOW (TYPE_MAX_VALUE (TYPE_DOMAIN (type))) < vlen
! || warn_larger_than)
! type = build_array_type (char_type_node,
! build_index_type (build_int_2 (vlen, 0)));
! decl = build_decl (VAR_DECL, get_identifier (name), type);
! TREE_STATIC (decl) = 1;
! TREE_READONLY (decl) = 1;
! TREE_ASM_WRITTEN (decl) = 1;
! DECL_SOURCE_LINE (decl) = 0;
! DECL_ARTIFICIAL (decl) = 1;
! DECL_IN_SYSTEM_HEADER (decl) = 1;
! DECL_IGNORED_P (decl) = 1;
! init = build_string (vlen, value);
! TREE_TYPE (init) = type;
! DECL_INITIAL (decl) = init;
! finish_decl (pushdecl (decl), init, NULL_TREE);
}
/* Given a chain of STRING_CST nodes,
--- 270,281 ----
name = "";
printable_name = (*decl_printable_name) (current_function_decl, 2);
}
!
! (*make_fname_decl) (get_identifier ("__FUNCTION__"), name, 0);
! (*make_fname_decl) (get_identifier ("__PRETTY_FUNCTION__"), printable_name, 1);
/* The ISO C people "of course" couldn't use __FUNCTION__ in the
ISO C 99 standard; instead a new variable is invented. */
! (*make_fname_decl) (get_identifier ("__func__"), name, 0);
}
/* Given a chain of STRING_CST nodes,
Index: c-decl.c
===================================================================
RCS file: /cvs/gcc/egcs/gcc/c-decl.c,v
retrieving revision 1.100
diff -c -3 -p -r1.100 c-decl.c
*** c-decl.c 2000/02/29 23:33:48 1.100
--- c-decl.c 2000/03/04 10:52:08
*************** static tree grokdeclarator PARAMS ((tre
*** 288,293 ****
--- 288,294 ----
int));
static tree grokparms PARAMS ((tree, int));
static void layout_array_type PARAMS ((tree));
+ static tree c_make_fname_decl PARAMS ((tree, const char *, int));
/* C-specific option variables. */
*************** init_decl_processing ()
*** 3059,3064 ****
--- 3060,3066 ----
pedantic_lvalues = pedantic;
/* Create the global bindings for __FUNCTION__ and __PRETTY_FUNCTION__. */
+ make_fname_decl = c_make_fname_decl;
declare_function_name ();
start_identifier_warnings ();
*************** init_decl_processing ()
*** 3083,3088 ****
--- 3085,3119 ----
mark_binding_level);
ggc_add_tree_root (&static_ctors, 1);
ggc_add_tree_root (&static_dtors, 1);
+ }
+
+ static tree
+ c_make_fname_decl (id, name, type_dep)
+ tree id;
+ const char *name;
+ int type_dep ATTRIBUTE_UNUSED;
+ {
+ tree decl, type, init;
+ size_t length = strlen (name);
+
+ type = build_array_type
+ (build_qualified_type (char_type_node, TYPE_QUAL_CONST),
+ build_index_type (build_int_2 (length, 0)));
+
+ decl = build_decl (VAR_DECL, id, type);
+ TREE_STATIC (decl) = 1;
+ TREE_READONLY (decl) = 1;
+ TREE_ASM_WRITTEN (decl) = 1;
+ DECL_SOURCE_LINE (decl) = 0;
+ DECL_ARTIFICIAL (decl) = 1;
+ DECL_IN_SYSTEM_HEADER (decl) = 1;
+ DECL_IGNORED_P (decl) = 1;
+ init = build_string (length + 1, name);
+ TREE_TYPE (init) = type;
+ DECL_INITIAL (decl) = init;
+ finish_decl (pushdecl (decl), init, NULL_TREE);
+
+ return decl;
}
/* Return a definition for a builtin function named NAME and whose data type
Index: tree.h
===================================================================
RCS file: /cvs/gcc/egcs/gcc/tree.h,v
retrieving revision 1.130
diff -c -3 -p -r1.130 tree.h
*** tree.h 2000/03/03 02:27:12 1.130
--- tree.h 2000/03/04 10:52:14
*************** extern int all_types_permanent;
*** 2113,2118 ****
--- 2113,2125 ----
extern const char *(*decl_printable_name) PARAMS ((tree, int));
+ /* Pointer to function to generate the VAR_DECL for __FUNCTION__ etc.
+ ID is the identifier to use, NAME is the string.
+ TYPE_DEP indicates whether it depends on type of the function or not
+ (i.e. __PRETTY_FUNCTION__). */
+
+ extern tree (*make_fname_decl) PARAMS ((tree, const char *, int));
+
/* Pointer to function to finish handling an incomplete decl at the
end of compilation. */
Index: cp/decl.c
===================================================================
RCS file: /cvs/gcc/egcs/gcc/cp/decl.c,v
retrieving revision 1.557
diff -c -3 -p -r1.557 decl.c
*** decl.c 2000/03/03 18:05:07 1.557
--- decl.c 2000/03/04 10:52:26
*************** static tree get_atexit_node PARAMS ((voi
*** 182,187 ****
--- 182,188 ----
static tree get_dso_handle_node PARAMS ((void));
static tree start_cleanup_fn PARAMS ((void));
static void end_cleanup_fn PARAMS ((void));
+ static tree cp_make_fname_decl PARAMS ((tree, const char *, int));
#if defined (DEBUG_CP_BINDING_LEVELS)
static void indent PARAMS ((void));
*************** wrapup_globals_for_namespace (namespace,
*** 1784,1790 ****
Put them into VEC from back to front, then take out from front. */
for (i = 0, decl = globals; i < len; i++, decl = TREE_CHAIN (decl))
! vec[len - i - 1] = decl;
if (last_time)
{
--- 1785,1799 ----
Put them into VEC from back to front, then take out from front. */
for (i = 0, decl = globals; i < len; i++, decl = TREE_CHAIN (decl))
! {
! /* Pretend we've output an unused static variable. This ensures
! that the toplevel __FUNCTION__ etc won't be emitted, unless
! needed. */
! if (TREE_CODE (decl) == VAR_DECL && TREE_STATIC (decl)
! && !TREE_USED (decl))
! TREE_ASM_WRITTEN (decl) = 1;
! vec[len - i - 1] = decl;
! }
if (last_time)
{
*************** init_decl_processing ()
*** 6168,6176 ****
/* Make a type to be the domain of a few array types
whose domains don't really matter.
! 200 is small enough that it always fits in size_t
! and large enough that it can hold most function names for the
! initializations of __FUNCTION__ and __PRETTY_FUNCTION__. */
array_domain_type = build_index_type (build_int_2 (200, 0));
/* Make a type for arrays of characters.
--- 6177,6183 ----
/* Make a type to be the domain of a few array types
whose domains don't really matter.
! 200 is small enough that it always fits in size_t. */
array_domain_type = build_index_type (build_int_2 (200, 0));
/* Make a type for arrays of characters.
*************** init_decl_processing ()
*** 6340,6345 ****
--- 6347,6353 ----
flag_weak = 0;
/* Create the global bindings for __FUNCTION__ and __PRETTY_FUNCTION__. */
+ make_fname_decl = cp_make_fname_decl;
declare_function_name ();
/* Prepare to check format strings against argument lists. */
*************** init_decl_processing ()
*** 6390,6395 ****
--- 6398,6448 ----
ggc_add_tree_root (&static_aggregates, 1);
}
+ static tree
+ cp_make_fname_decl (id, name, type_dep)
+ tree id;
+ const char *name;
+ int type_dep;
+ {
+ tree decl, type, init;
+ size_t length = strlen (name);
+ tree domain = NULL_TREE;
+
+ if (!processing_template_decl)
+ type_dep = 0;
+ if (!type_dep)
+ domain = build_index_type (build_int_2 (length, 0));
+
+ type = build_cplus_array_type
+ (build_qualified_type (char_type_node, TYPE_QUAL_CONST),
+ domain);
+
+ decl = build_lang_decl (VAR_DECL, id, type);
+ TREE_STATIC (decl) = 1;
+ TREE_READONLY (decl) = 1;
+ DECL_SOURCE_LINE (decl) = 0;
+ DECL_ARTIFICIAL (decl) = 1;
+ DECL_IN_SYSTEM_HEADER (decl) = 1;
+ pushdecl (decl);
+ if (processing_template_decl)
+ decl = push_template_decl (decl);
+ if (type_dep)
+ {
+ init = build (FUNCTION_NAME, type);
+ DECL_PRETTY_FUNCTION_P (decl) = 1;
+ }
+ else
+ {
+ init = build_string (length + 1, name);
+ TREE_TYPE (init) = type;
+ }
+ DECL_INITIAL (decl) = init;
+ cp_finish_decl (decl, init, NULL_TREE, LOOKUP_ONLYCONVERTING);
+
+ /* We will have to make sure we only emit this, if it is actually used. */
+ return decl;
+ }
+
/* Function to print any language-specific context for an error message. */
static void
*************** cp_finish_decl (decl, init, asmspec_tree
*** 7625,7650 ****
if (init)
error ("assignment (not initialization) in declaration");
return;
- }
-
- /* Handling __FUNCTION__ and its ilk in a template-function requires
- some special processing because we are called from
- language-independent code. */
- if (cfun && processing_template_decl
- && current_function_name_declared == 2)
- {
- /* Since we're in a template function, we need to
- push_template_decl. The language-independent code in
- declare_hidden_char_array doesn't know to do this. */
- retrofit_lang_decl (decl);
- decl = push_template_decl (decl);
-
- if (strcmp (IDENTIFIER_POINTER (DECL_NAME (decl)),
- "__PRETTY_FUNCTION__") == 0)
- {
- init = build (FUNCTION_NAME, const_string_type_node);
- DECL_PRETTY_FUNCTION_P (decl) = 1;
- }
}
/* If a name was specified, get the string. */
--- 7678,7683 ----
Index: cp/semantics.c
===================================================================
RCS file: /cvs/gcc/egcs/gcc/cp/semantics.c,v
retrieving revision 1.128
diff -c -3 -p -r1.128 semantics.c
*** semantics.c 2000/02/27 05:30:00 1.128
--- semantics.c 2000/03/04 10:52:26
*************** begin_compound_stmt (has_no_scope)
*** 980,992 ****
&& !current_function_name_declared
&& !has_no_scope)
{
- /* When we get callbacks from the middle-end, we need to know
- we're in the midst of declaring these variables. */
- current_function_name_declared = 2;
- /* Actually insert the declarations. */
- declare_function_name ();
- /* And now just remember that we're all done. */
current_function_name_declared = 1;
}
return r;
--- 980,987 ----
&& !current_function_name_declared
&& !has_no_scope)
{
current_function_name_declared = 1;
+ declare_function_name ();
}
return r;
*************** expand_stmt (t)
*** 2398,2404 ****
DECL_ANON_UNION_ELEMS (decl));
}
else if (TREE_CODE (decl) == VAR_DECL && TREE_STATIC (decl))
! make_rtl_for_local_static (decl);
}
break;
--- 2393,2405 ----
DECL_ANON_UNION_ELEMS (decl));
}
else if (TREE_CODE (decl) == VAR_DECL && TREE_STATIC (decl))
! {
! /* Do not emit unused decls. This is not just an
! optimization. We really do not want to emit
! __PRETTY_FUNCTION__ etc, if they're never used. */
! if (TREE_USED (decl))
! make_rtl_for_local_static (decl);
! }
}
break;
Index: cp/typeck.c
===================================================================
RCS file: /cvs/gcc/egcs/gcc/cp/typeck.c,v
retrieving revision 1.256
diff -c -3 -p -r1.256 typeck.c
*** typeck.c 2000/03/03 02:27:15 1.256
--- typeck.c 2000/03/04 10:52:27
*************** decay_conversion (exp)
*** 1716,1727 ****
/* Replace a nonvolatile const static variable with its value. We
don't do this for arrays, though; we want the address of the
first element of the array, not the address of the first element
! of its initializing constant. We *do* replace variables that the
! user isn't really supposed to know about; this is a hack to deal
! with __PRETTY_FUNCTION__ and the like. */
! else if (TREE_READONLY_DECL_P (exp)
! && (code != ARRAY_TYPE
! || (TREE_CODE (exp) == VAR_DECL && DECL_IGNORED_P (exp))))
{
exp = decl_constant_value (exp);
type = TREE_TYPE (exp);
--- 1716,1723 ----
/* Replace a nonvolatile const static variable with its value. We
don't do this for arrays, though; we want the address of the
first element of the array, not the address of the first element
! of its initializing constant. */
! else if (TREE_READONLY_DECL_P (exp) && code != ARRAY_TYPE)
{
exp = decl_constant_value (exp);
type = TREE_TYPE (exp);
Index: testsuite/g++.old-deja/g++.brendan/misc12.C
===================================================================
RCS file: /cvs/gcc/egcs/gcc/testsuite/g++.old-deja/g++.brendan/misc12.C,v
retrieving revision 1.3
diff -c -3 -p -r1.3 misc12.C
*** misc12.C 2000/01/04 15:52:22 1.3
--- misc12.C 2000/03/04 10:52:32
*************** extern "C" int printf (const char *, ...
*** 8,15 ****
int
main()
{
! char *a = __FUNCTION__;
! char *b = __PRETTY_FUNCTION__;
printf ("PASS\n");
exit (0);
--- 8,15 ----
int
main()
{
! const char *a = __FUNCTION__;
! const char *b = __PRETTY_FUNCTION__;
printf ("PASS\n");
exit (0);
Index: testsuite/g++.old-deja/g++.pt/memtemp77.C
===================================================================
RCS file: /cvs/gcc/egcs/gcc/testsuite/g++.old-deja/g++.pt/memtemp77.C,v
retrieving revision 1.5
diff -c -3 -p -r1.5 memtemp77.C
*** memtemp77.C 1999/11/23 02:49:40 1.5
--- memtemp77.C 2000/03/04 10:52:34
*************** template <class T>
*** 4,24 ****
struct S3
{
template <class U>
! static char* h(U);
};
template <>
template <>
! char* S3<double>::h(int) { return __PRETTY_FUNCTION__; }
template <>
template <>
! char* S3<char>::h(int) { return __PRETTY_FUNCTION__; }
int main()
{
if (strcmp (S3<double>::h(7),
! "char *S3<T>::h (U) [with U = int, T = double]") == 0)
return 0;
else
return 1;
--- 4,24 ----
struct S3
{
template <class U>
! static const char* h(U);
};
template <>
template <>
! const char* S3<double>::h(int) { return __PRETTY_FUNCTION__; }
template <>
template <>
! const char* S3<char>::h(int) { return __PRETTY_FUNCTION__; }
int main()
{
if (strcmp (S3<double>::h(7),
! "const char *S3<T>::h (U) [with U = int, T = double]") == 0)
return 0;
else
return 1;
// Copyright (C) 2000 Free Software Foundation, Inc.
// Contributed by Nathan Sidwell 3 Mar 2000 <nathan@codesourcery.com>
// __PRETTY_FUNCTION__, __FUNCTION__ and __function__ should have the
// type char const [X], where X is the right value for that particular function
static void const *strings[4];
static void const *tpls[4];
static unsigned pos = 0;
static int fail;
static void const *ptr = 0;
void unover (char const (*)[5]) {}
void foo (char const (*)[5]) {}
void foo (void *) {fail = 1;}
void foo (void const *) {fail = 1;}
void baz (char const (&)[5]) {}
template<unsigned I> void PV (char const (&objRef)[I])
{
strings[pos] = objRef;
tpls[pos] = __PRETTY_FUNCTION__;
pos++;
}
void fn ()
{
PV (__FUNCTION__);
PV (__func__);
PV (__PRETTY_FUNCTION__);
PV ("wibble");
}
void baz ()
{
ptr = __FUNCTION__;
}
int baz (int)
{
return ptr == __FUNCTION__;
}
int main ()
{
// make sure we actually emit the VAR_DECL when needed, and things have the
// expected type.
foo (&__FUNCTION__);
baz (__FUNCTION__);
unover (&__FUNCTION__);
if (fail)
return 1;
// __FUNCTION__ should be unique across functions with the same base name
// (it's a local static, _not_ a string).
baz ();
if (baz (1))
return 1;
fn ();
// Check the names of fn. They should all be distinct strings (though two
// will have the same value).
if (strings[0] == strings[1])
return 1;
if (strings[0] == strings[2])
return 1;
if (strings[1] == strings[2])
return 1;
// check the names of the template functions so invoked
if (tpls[0] != tpls[1])
return 1;
if (tpls[0] == tpls[2])
return 1;
return 0;
}