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]

Re: [C++ PATCH]: __FUNCTION__ handling


Mark Mitchell wrote:

> Go for it with the patch.
I installed the attached

rth> How odd.  Well, that probably rules out using the constant pool.
rth> At least without being clever.
Yup, the original c9x proposal explicitly said it was unspecified
whether string merging happened. The C99 FCD does not.

Note that the C frontend will still do merging after this patch,
as it is harder to delay the emission of __FUNCTION__ if we
were to try and DTRT. C++ can do it thanks to the function at a time
translation we now have.

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-08  Nathan Sidwell  <nathan@codesourcery.com>

	* c-common.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-08  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.h
===================================================================
RCS file: /cvs/gcc/egcs/gcc/c-common.h,v
retrieving revision 1.10
diff -c -3 -p -r1.10 c-common.h
*** c-common.h	2000/02/26 05:45:17	1.10
--- c-common.h	2000/03/08 10:31:21
*************** extern tree c_global_trees[CTI_MAX];
*** 74,79 ****
--- 74,86 ----
  #define int_ftype_int			c_global_trees[CTI_INT_FTYPE_INT]
  #define ptr_ftype_sizetype		c_global_trees[CTI_PTR_FTYPE_SIZETYPE]
  
+ /* 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));
+ 
  extern void declare_function_name		PARAMS ((void));
  extern void decl_attributes			PARAMS ((tree, tree, tree));
  extern void init_function_format_info		PARAMS ((void));
Index: c-common.c
===================================================================
RCS file: /cvs/gcc/egcs/gcc/c-common.c,v
retrieving revision 1.96
diff -c -3 -p -r1.96 c-common.c
*** c-common.c	2000/03/07 11:41:15	1.96
--- c-common.c	2000/03/08 10:31:22
*************** 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,310 ****
  	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;
!   unsigned 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 (compare_tree_int (TYPE_MAX_VALUE (TYPE_DOMAIN (type)), vlen) < 0
!       || 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.101
diff -c -3 -p -r1.101 c-decl.c
*** c-decl.c	2000/03/07 11:41:15	1.101
--- c-decl.c	2000/03/08 10:31:24
*************** 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,3127 ----
  		mark_binding_level);
    ggc_add_tree_root (&static_ctors, 1);
    ggc_add_tree_root (&static_dtors, 1);
+ }
+ 
+ /* Create the VAR_DECL for __FUNCTION__ etc. ID is the name to give the
+    decl, NAME is the initialization string and TYPE_DEP indicates whether
+    NAME depended on the type of the function.  As we don't yet implement
+    delayed emission of static data, we mark the decl as emitted
+    so it is not placed in the output.  Anything using it must therefore pull
+    out the STRING_CST initializer directly.  This does mean that these names
+    are string merging candidates, which C99 does not permit.  */
+ 
+ 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: cp/decl.c
===================================================================
RCS file: /cvs/gcc/egcs/gcc/cp/decl.c,v
retrieving revision 1.558
diff -c -3 -p -r1.558 decl.c
*** decl.c	2000/03/04 00:45:23	1.558
--- decl.c	2000/03/08 10:31:37
*************** 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,6456 ----
    ggc_add_tree_root (&static_aggregates, 1);
  }
  
+ /* Create the VAR_DECL for __FUNCTION__ etc. ID is the name to give the
+    decl, NAME is the initialization string and TYPE_DEP indicates whether
+    NAME depended on the type of the function. We make use of that to detect
+    __PRETTY_FUNCTION__ inside a template fn.  Because we build a tree for
+    the function before emitting any of it, we don't need to treat the
+    VAR_DECL specially. We can decide whether to emit it later, if it was
+    used.  */
+ 
+ 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.  */
--- 7686,7691 ----
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/08 10:31:38
*************** 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)
*** 2397,2403 ****
  		  expand_anon_union_decl (decl, NULL_TREE, 
  					  DECL_ANON_UNION_ELEMS (decl));
  	      }
! 	    else if (TREE_CODE (decl) == VAR_DECL && TREE_STATIC (decl))
  	      make_rtl_for_local_static (decl);
  	  }
  	  break;
--- 2392,2402 ----
  		  expand_anon_union_decl (decl, NULL_TREE, 
  					  DECL_ANON_UNION_ELEMS (decl));
  	      }
! 	    else if (TREE_CODE (decl) == VAR_DECL && TREE_STATIC (decl)
! 	             && TREE_USED (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.  */
  	      make_rtl_for_local_static (decl);
  	  }
  	  break;
Index: cp/typeck.c
===================================================================
RCS file: /cvs/gcc/egcs/gcc/cp/typeck.c,v
retrieving revision 1.260
diff -c -3 -p -r1.260 typeck.c
*** typeck.c	2000/03/08 10:26:05	1.260
--- typeck.c	2000/03/08 10:31:40
*************** 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);
2000-03-08  Nathan Sidwell  <nathan@codesourcery.com>

	* g++.old-deja/g++.brendan/misc12.C: Removed.
	* g++.old-deja/g++.pt/memtemp77.C: Constify.
	* g++.old-deja/g++.ext/pretty4.C: New test.

Index: testsuite/g++.old-deja/g++.brendan/misc12.C
===================================================================
RCS file: misc12.C
diff -N misc12.C
*** /sourceware/cvs-tmp/cvsI6iBcD	Wed Mar  8 02:57:03 2000
--- /dev/null	Tue May  5 13:32:27 1998
***************
*** 1,16 ****
- // GROUPS passed miscellaneous
- extern "C" void exit (int);
- extern "C" int printf (const char *, ...);
- 
- /* Make sure cp-lex.c handles these properly--if this links, that means
-    it emitted the strings instead of __FUNCTION__.0, etc.  */
- 
- int
- main()
- {
-   char *a = __FUNCTION__;
-   char *b = __PRETTY_FUNCTION__;
- 
-   printf ("PASS\n");
-   exit (0);
- }
--- 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/08 10:57:03
*************** 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;
Index: testsuite/g++.old-deja/g++.ext/pretty4.C
===================================================================
RCS file: pretty4.C
diff -N pretty4.C
*** /dev/null	Tue May  5 13:32:27 1998
--- pretty4.C	Wed Mar  8 02:57:03 2000
***************
*** 0 ****
--- 1,84 ----
+ // 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__;
+   // there should be no string const merging
+   if (ptr == "baz")
+     fail = 1;
+   // but all uses should be the same.
+   if (ptr != __FUNCTION__)
+     fail = 1;
+ }
+ 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 (fail)
+     return 1;
+   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;
+ }

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