This is the mail archive of the libstdc++@sources.redhat.com mailing list for the libstdc++ project.


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

C++ PATCH: External linkage, templates, AIX, V3



The compiler had some internal confusion between implementation
details and language semantics.  In particular, we were testing for
external linkage in pt.c by using TREE_PUBLIC, which doesn't work
correctly on platforms that don't support weak linkage (like AIX).
This came up while trying to get V3 working on AIX.

There may be other places in the compiler where the same incorrect
assumption is made, but this case, at least, is fixed with the
attached patch.

David, let's see if that gets you a little further.

--
Mark Mitchell                   mark@codesourcery.com
CodeSourcery, LLC               http://www.codesourcery.com

2000-10-30  Mark Mitchell  <mark@codesourcery.com>

	* cp-tree.h (DECL_EXTERNAL_LINKAGE_P): New macro.
	(linkage_kind): New enumeration.
	(decl_linkage): New function.
	* decl2.c (comdat_linkage): Extend comment.
	* error.c (dump_function_decl): Print the arguments used to
	instantiate a template, even when not printing the type of the
	function.
	* pt.c (convert_nontype_argument): Use DECL_EXTERNAL_LINKAGE_P,
	not TREE_PUBLIC, to test for external linkage.
	* tree.c (decl_linkage): New function.

Index: testsuite/g++.old-deja/g++.other/linkage6.C
===================================================================
RCS file: linkage6.C
diff -N linkage6.C
*** /dev/null	Tue May  5 13:32:27 1998
--- linkage6.C	Mon Oct 30 17:26:58 2000
***************
*** 0 ****
--- 1,18 ----
+ // Build don't link:
+ // Special g++ Options: -fno-weak
+ // Origin: Mark Mitchell <mark@codesourcery.com>
+ 
+ template <typename T>
+ void f ();
+ 
+ void h () { f<int> (); }
+ 
+ template <void (*X)()>
+ void g () {}
+ 
+ template <typename T>
+ void f ()
+ {
+    g<&f<T> >();
+ }
+ 
Index: cp-tree.h
===================================================================
RCS file: /cvs/gcc/egcs/gcc/cp/cp-tree.h,v
retrieving revision 1.537
diff -c -p -r1.537 cp-tree.h
*** cp-tree.h	2000/10/19 17:57:49	1.537
--- cp-tree.h	2000/10/31 01:06:32
*************** extern int flag_new_for_scope;
*** 2498,2503 ****
--- 2498,2510 ----
  #define DECL_UNINLINABLE(NODE) \
    (DECL_LANG_SPECIFIC (NODE)->decl_flags.uninlinable)
  
+ /* Returns non-zero if DECL has external linkage, as specified by the
+    language standard.  (This predicate may hold even when the
+    corresponding entity is not actually given external linkage in the
+    object file; see decl_linkage for details.)  */
+ #define DECL_EXTERNAL_LINKAGE_P(DECL) \
+   (decl_linkage (DECL) == lk_external)
+ 
  #define INTEGRAL_CODE_P(CODE) \
    (CODE == INTEGER_TYPE || CODE == ENUMERAL_TYPE || CODE == BOOLEAN_TYPE)
  
*************** typedef enum special_function_kind {
*** 3145,3150 ****
--- 3152,3180 ----
    sfk_conversion           /* A conversion operator.  */
  } special_function_kind;
  
+ /* The various kinds of linkage.  From [basic.link], 
+    
+       A name is said to have linkage when it might denote the same
+       object, reference, function, type, template, namespace or value
+       as a name introduced in another scope:
+ 
+       -- When a name has external linkage, the entity it denotes can
+          be referred to from scopes of other translation units or from
+ 	 other scopes of the same translation unit.
+ 
+       -- When a name has internal linkage, the entity it denotes can
+          be referred to by names from other scopes in the same
+ 	 translation unit.
+ 
+       -- When a name has no linkage, the entity it denotes cannot be
+          referred to by names from other scopes.  */
+ 
+ typedef enum linkage_kind {
+   lk_none,                 /* No linkage.  */
+   lk_internal,             /* Internal linkage.  */
+   lk_external              /* External linkage.  */
+ } linkage_kind;
+ 
  /* Bitmask flags to pass to instantiate_type.  */
  typedef enum instantiate_type_flags {
    itf_none = 0,               /* nothing special */
*************** extern int count_trees                  
*** 4443,4448 ****
--- 4473,4479 ----
  extern int char_type_p                          PARAMS ((tree));
  extern void verify_stmt_tree                    PARAMS ((tree));
  extern tree find_tree                           PARAMS ((tree, tree));
+ extern linkage_kind decl_linkage                PARAMS ((tree));
  
  /* in typeck.c */
  extern int string_conv_p			PARAMS ((tree, tree, int));
Index: decl2.c
===================================================================
RCS file: /cvs/gcc/egcs/gcc/cp/decl2.c,v
retrieving revision 1.406
diff -c -p -r1.406 decl2.c
*** decl2.c	2000/10/22 01:38:35	1.406
--- decl2.c	2000/10/31 01:06:35
*************** comdat_linkage (decl)
*** 2427,2434 ****
    if (flag_weak)
      make_decl_one_only (decl);
    else if (TREE_CODE (decl) == FUNCTION_DECL || DECL_VIRTUAL_P (decl))
!     /* We can just emit functions and vtables statically; it doesn't really
!        matter if we have multiple copies.  */
      TREE_PUBLIC (decl) = 0;
    else
      {
--- 2427,2439 ----
    if (flag_weak)
      make_decl_one_only (decl);
    else if (TREE_CODE (decl) == FUNCTION_DECL || DECL_VIRTUAL_P (decl))
!     /* We can just emit functions and vtables statically; having
!        multiple copies is (for the most part) only a waste of space.
!        There is at least one correctness issue, however: the address
!        of a template instantiation with external linkage should be the
!        same, independent of what translation unit asks for the
!        address, and this will not hold when we emit multiple copies of
!        the function.  However, there's little else we can do.  */
      TREE_PUBLIC (decl) = 0;
    else
      {
Index: error.c
===================================================================
RCS file: /cvs/gcc/egcs/gcc/cp/error.c,v
retrieving revision 1.138
diff -c -p -r1.138 error.c
*** error.c	2000/10/26 05:50:19	1.138
--- error.c	2000/10/31 01:06:36
*************** dump_function_decl (t, flags)
*** 1284,1310 ****
  
    dump_function_name (t, flags);
  
!   if (!(flags & TS_DECL_TYPE))
!     return;
!   if (TREE_CODE (fntype) == METHOD_TYPE && parmtypes)
!     /* Skip "this" parameter.  */
!     parmtypes = TREE_CHAIN (parmtypes);
  
!   /* Skip past the "in_charge" parameter.  */
!   if (DECL_HAS_IN_CHARGE_PARM_P (t))
!     parmtypes = TREE_CHAIN (parmtypes);
  
!   dump_parameters (parmtypes, flags);
  
!   if (show_return)
!     dump_type_suffix (TREE_TYPE (fntype), flags);
  
!   if (TREE_CODE (fntype) == METHOD_TYPE)
!     dump_qualifiers (TREE_TYPE (TREE_VALUE (TYPE_ARG_TYPES (fntype))),
! 		     before);
  
!   if (flags & TS_FUNC_THROW)
!     dump_exception_spec (TYPE_RAISES_EXCEPTIONS (fntype), flags);
  
    /* If T is a template instantiation, dump the parameter binding.  */
    if (template_parms != NULL_TREE && template_args != NULL_TREE)
--- 1284,1311 ----
  
    dump_function_name (t, flags);
  
!   if (flags & TS_DECL_TYPE) 
!     {
!       if (TREE_CODE (fntype) == METHOD_TYPE && parmtypes)
! 	/* Skip "this" parameter.  */
! 	parmtypes = TREE_CHAIN (parmtypes);
  
!       /* Skip past the "in_charge" parameter.  */
!       if (DECL_HAS_IN_CHARGE_PARM_P (t))
! 	parmtypes = TREE_CHAIN (parmtypes);
  
!       dump_parameters (parmtypes, flags);
  
!       if (show_return)
! 	dump_type_suffix (TREE_TYPE (fntype), flags);
  
!       if (TREE_CODE (fntype) == METHOD_TYPE)
! 	dump_qualifiers (TREE_TYPE (TREE_VALUE (TYPE_ARG_TYPES (fntype))),
! 			 before);
  
!       if (flags & TS_FUNC_THROW)
! 	dump_exception_spec (TYPE_RAISES_EXCEPTIONS (fntype), flags);
!     }
  
    /* If T is a template instantiation, dump the parameter binding.  */
    if (template_parms != NULL_TREE && template_args != NULL_TREE)
Index: pt.c
===================================================================
RCS file: /cvs/gcc/egcs/gcc/cp/pt.c,v
retrieving revision 1.472
diff -c -p -r1.472 pt.c
*** pt.c	2000/10/28 21:37:21	1.472
--- pt.c	2000/10/31 01:06:43
*************** convert_nontype_argument (type, expr)
*** 2808,2814 ****
  	;
        else if (TREE_CODE (referent) != VAR_DECL)
  	goto bad_argument;
!       else if (!TREE_PUBLIC (referent))
  	{
  	  cp_error ("address of non-extern `%E' cannot be used as template argument", referent); 
  	  return error_mark_node;
--- 2808,2814 ----
  	;
        else if (TREE_CODE (referent) != VAR_DECL)
  	goto bad_argument;
!       else if (!DECL_EXTERNAL_LINKAGE_P (referent))
  	{
  	  cp_error ("address of non-extern `%E' cannot be used as template argument", referent); 
  	  return error_mark_node;
*************** convert_nontype_argument (type, expr)
*** 2915,2921 ****
  	    if (fn == error_mark_node)
  	      return error_mark_node;
  
! 	    if (!TREE_PUBLIC (fn))
  	      {
  		if (really_overloaded_fn (fns))
  		  return error_mark_node;
--- 2915,2921 ----
  	    if (fn == error_mark_node)
  	      return error_mark_node;
  
! 	    if (!DECL_EXTERNAL_LINKAGE_P (fn))
  	      {
  		if (really_overloaded_fn (fns))
  		  return error_mark_node;
*************** convert_nontype_argument (type, expr)
*** 2980,2986 ****
  	    if (fn == error_mark_node)
  	      return error_mark_node;
  
! 	    if (!TREE_PUBLIC (fn))
  	      {
  		if (really_overloaded_fn (expr))
  		  /* Don't issue an error here; we might get a different
--- 2980,2986 ----
  	    if (fn == error_mark_node)
  	      return error_mark_node;
  
! 	    if (!DECL_EXTERNAL_LINKAGE_P (fn))
  	      {
  		if (really_overloaded_fn (expr))
  		  /* Don't issue an error here; we might get a different
Index: tree.c
===================================================================
RCS file: /cvs/gcc/egcs/gcc/cp/tree.c,v
retrieving revision 1.219
diff -c -p -r1.219 tree.c
*** tree.c	2000/10/22 01:38:35	1.219
--- tree.c	2000/10/31 01:06:44
*************** char_type_p (type)
*** 2597,2599 ****
--- 2597,2642 ----
  	  || same_type_p (type, signed_char_type_node)
  	  || same_type_p (type, wchar_type_node));
  }
+ 
+ /* Returns the kind of linkage associated with the indicated DECL.  Th
+    value returned is as specified by the language standard; it is
+    independent of implementation details regarding template
+    instantiation, etc.  For example, it is possible that a declaration
+    to which this function assigns external linkage would not show up
+    as a global symbol when you run `nm' on the resulting object file.  */
+ 
+ linkage_kind
+ decl_linkage (decl)
+      tree decl;
+ {
+   /* This function doesn't attempt to calculate the linkage from first
+      principles as given in [basic.link].  Instead, it makes use of
+      the fact that we have already set TREE_PUBLIC appropriately, and
+      then handles a few special cases.  Ideally, we would calculate
+      linkage first, and then transform that into a concrete
+      implementation.  */
+ 
+   /* Things that don't have names have no linkage.  */
+   if (!DECL_NAME (decl))
+     return lk_none;
+ 
+   /* Things that are TREE_PUBLIC have external linkage.  */
+   if (TREE_PUBLIC (decl))
+     return lk_external;
+ 
+   /* Some things that are not TREE_PUBLIC have external linkage, too.
+      For example, on targets that don't have weak symbols, we make all
+      template instantiations have internal linkage (in the object
+      file), but the symbols should still be treated as having external
+      linkage from the point of view of the language.  */
+   if (DECL_LANG_SPECIFIC (decl) && DECL_COMDAT (decl))
+     return lk_external;
+ 
+   /* Things in local scope do not have linkage, if they don't have
+      TREE_PUBLIC set.  */
+   if (decl_function_context (decl))
+     return lk_none;
+ 
+   /* Everything else has internal linkage.  */
+   return lk_internal;
+ }

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