This is the mail archive of the gcc-bugs@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]

Template instanciantion problem on Red-Hat 6.2 & 6.1


Hello,

gcc-2.95.2 (release, october 1999), seems to have problems
to correctly instanciate templates on Red-Hat 6.1/6.2 even on 
very simple examples.

Attached
---------

WorkSession.[Ch]
WSHistLog.h
List.[Ch]        template class

WorkSession.rpo      ==> repository file produced on red-hat 6.2
WorkSession.rpo.sol7 ==> repository file produced on solaris7

OS (uname -a):
---------

Linux [hostname] 2.2.14-24mdk_i486 #1 Sun Feb 13 21:52:19 CET 2000 i686
unknown

AND

Linux [hostname] 2.2.14-6.1.1 #1 Thu Apr 13 20:01:58 EDT 2000 i686
unknown

GCC (gcc -v)
-------------

Reading specs from
/u/nobili/linux/lib/gcc-lib/i686-pc-linux-gnu/2.95.2/specs
gcc version 2.95.2 19991024 (release)

++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++

How to reproduce:
-----------------

a) gcc -c -frepo WorkSession.C
============================

Generates WorkSession.o and WorkSession.rpo
Output: none

b) gcc WorkSession.o
==========

Makes the necessary template instanciations, recompiling 
WorkSession.C if needed and places instanciations in 
WorkSession.o

Ouput: (NOT OK)
======

collect: recompiling WorkSession.C
collect: relinking
/usr/lib/crt1.o(.text+0x18): undefined reference to `main'
WorkSession.o: In function `GmList<GmWorkSessionHistoryLog
*>::~GmList(void)':
WorkSession.o(.text+0xfb): undefined reference to
`GmList<GmWorkSessionHistoryLog *>::clear(void)'
collect2: ld returned 1 exit status

The compiler failed to instanciate 
-----------------------------------

'GmList<GmWorkSessionHistoryLog *>::clear(void)'


=====================================================================
Hint:  comparing with what happend on solaris 7
====================================================================

If I compare the repository file obtained on Linux (WorkSession.rpo)
with that obtained on Solaris-7 (WorkSession.rpo.sol7), the two
following lines differ :

> diff WorkSession.rpo  WorkSession.rpo.sol7

Produces:

5c5,6
< O clear__t6GmList1ZP23GmWorkSessionHistoryLog
---
> O _._t10GmListNode1ZP23GmWorkSessionHistoryLog
> C clear__t6GmList1ZP23GmWorkSessionHistoryLog

The line '_._t10GmListNode1ZP23GmWorkSessionHistoryLog' is not
present on Linux, whereas the line
'clear__t6GmList1ZP23GmWorkSessionHistoryLog' is flagged 
'O' instead of 'C'

OS (uname -a):
-------------------

SunOS [hostname] 5.7 Generic_106541-09 sun4u sparc SUNW,Ultra-80

GCC (gcc -v):
-------------

Reading specs from
/usr/local/lib/gcc-lib/sparc-sun-solaris2.7/2.95.2/specs
gcc version 2.95.2 19991024 (release)

+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++

Results on Solaris 7 :
=======================================

a) gcc -c -frepo WorkSession.C
b) gcc WorkSession.o

    Ouput: (OK)

collect: recompiling WorkSession.C
collect: relinking
collect: recompiling WorkSession.C
collect: relinking
Undefined                       first referenced
 symbol                             in file
main                               
/usr/local/lib/gcc-lib/sparc-sun-solaris2.7/2.95.2/crt1.o
ld: fatal: Symbol referencing errors. No output written to a.out
collect2: ld returned 1 exit status

All templates are correctly instanciated
-----------------------------------------

Thank you for your help,
Cheers,
        P. Nobili

-- 
___________________________________________________________
Philippe Nobili
CGG
Office M1 335
1, rue Leon Migaux, 91341 Massy Cedex

Tel : 01 64 47 40 90
Fax : 01 64 47 45 14         E-mail : pnobili@cgg.com
___________________________________________________________
#ifndef List_C
#define List_C

#include "List.h"


#include <stdlib.h>
#include <iostream.h>




// List's nodes...
////////////////////////////////////////////////////////////////////////////////

template <class T>
class GmListNode
{

public :
	GmListNode<T>* tl ;
	T              hd ;

	GmListNode()  {}
	~GmListNode() {}

	GmListNode( const T& h, GmListNode<T>* t = 0) : hd(h), tl(t) {}

#ifdef POOL // voir fin du fichier
	void * operator new( size_t )      { return pool_.alloc() ; }
	void   operator delete( void * p ) { pool_.free( p ) ; }

private :
	static <T>Pool pool_ ;
#endif // POOL
} ;


// GmList
////////////////////////////////////////////////////////////////////////////////


#ifdef POOL // voir fin du fichier
<T>Pool <T>GmListNode::pool_( sizeof(<T>GmListNode) ) ;
#endif // POOL



template <class T>
GmList<T>::GmList()
{
	P = 0 ;
}


template <class T>
GmList<T>::GmList( const GmList<T>& a ) 
{
	if( a.P == 0 ) 
	{
		P = 0 ;
		return ;
	}

	GmListNode<T> * p = a.P->tl ;
	GmListNode<T> * h = new GmListNode<T>( p->hd ) ;
	
	P = h ;

	for( ;; ) 
	{
		if( p == a.P ) 
		{
			P->tl = h ;
			return ;
		}
		p = p->tl ;
		GmListNode<T> * n = new GmListNode<T>( p->hd ) ;
		P->tl = n ;
		P = n ;
	}
}


template <class T>
GmList<T>::~GmList() 
{
	clear() ;
}


template <class T>
GmList<T>& GmList<T>::operator = ( const GmList<T>& a )
{
	if( P == a.P ) return *this ;

	clear() ;

	if( a.P == 0 ) return *this ;

	GmListNode<T> * p = a.P->tl ;
	GmListNode<T> * h = new GmListNode<T>( p->hd ) ;

	P = h ;

	for( ;; )
	{
		if( p == a.P )
		{
			P->tl = h ;
			break ;
		}
		p = p->tl ;
		GmListNode<T> * n = new GmListNode<T>( p->hd ) ;
		P->tl = n ;
		P = n ;
	}

	return *this ;
}


template <class T>
void GmList<T>::append( GmList<T>& b )
{
	GmListNode<T> * t = b.P ;

	// destructif : la liste b est dorenavant vide.
	b.P = 0 ;

	if( P == 0 )
	{
		P = t ;
	}
	else if( t != 0 )
	{
		GmListNode<T> * f = P->tl ;
		P->tl = t->tl ;
		t->tl = f ;
		P = t ;
	}
}


template <class T>
void GmList<T>::prepend( GmList<T>& b )
{
	GmListNode<T> * t = b.P ;

	// destructif : la liste b est dorenavant vide.
	b.P = 0 ;

	if( P == 0 )
	{
		P = t ;
	}
	else if( t != 0 )
	{
		GmListNode<T> * f = P->tl ;
		P->tl = t->tl ;
		t->tl = f ;
	}
}


template <class T>
GmBoolean GmList<T>::isEmpty() const
{

	return P == 0 ? GmTRUE : GmFALSE ;
}


template <class T>
int GmList<T>::count() const
{

	int sum = 0 ;

	GmListNode<T> * n = P ;
	if( n )
	{
		do
		{
			n = n->tl ;
			sum++ ;
		} while( n != P ) ;
	}
	return sum ;
}


template <class T>
void GmList<T>::clear()
{

	if( P == 0 ) return ;

	GmListNode<T> * p = P->tl ;
	P->tl = 0 ;
	P = 0 ;

	while( p != 0 )
	{
		GmListNode<T> * nxt = p->tl ;
		delete p ;
		p = nxt ;
	}
}


template <class T>
GmAny GmList<T>::append( const T& item )
{

	GmListNode<T> * t = new GmListNode<T>(item) ;

	if( P == 0 )
	{
		t->tl = P = t ;
	}
	else
	{
		t->tl = P->tl ;
		P->tl = t ;
		P = t ;
	}

	return GmAny(t) ;
}


template <class T>
GmAny GmList<T>::prepend( const T& item )
{

	GmListNode<T> * t = new GmListNode<T>(item) ;

	if( P == 0 )
	{
		t->tl = P = t ;
	}
	else
	{
		t->tl = P->tl ;
		P->tl = t ;
	}

	return GmAny(t) ;
}


template <class T>
GmAny GmList<T>::first() const
{
	return !P ? 0 : GmAny( P->tl ) ;
}


template <class T>
GmAny GmList<T>::seek( const T& item ) const
{
	if( P == 0 )
	{
		return GmAny( 0 ) ; // empty list
	}

	GmListNode<T> * t = P->tl ; // first

	do
	{
		if( t->hd == item ) break ; // found
		t = t->tl ;
	} while( t != P ) ;

	if( t->hd != item ) return GmAny( 0 ) ; // not found

	return GmAny( t ) ;
}


template <class T>
GmAny GmList<T>::seek( unsigned int pos ) const
{
	if( P == 0 )
	{
		return GmAny( 0 ) ; // empty list
	}

	int l = 0 ;
	GmListNode<T> * t = P->tl ;

	do
	{
		if( l == pos )
		{
			return GmAny( t ) ;
		}
		t = t->tl ;
		l++ ;
	} while( t != P->tl ) ;

	return GmAny( 0 ) ;
}


template <class T>
void GmList<T>::next( GmAny& p ) const
{
	p = (p==0 || p==P) ? 0 : GmAny( ((GmListNode<T>*)p)->tl ) ;
}


template <class T>
T& GmList<T>::operator () ( GmAny p ) const
{
	if( !p )
	{
		GmFatalError( "T& GmList<T>::operator () ( GmAny p )",
			      "Null iterator p" ) ;
	}

	return ((GmListNode<T>*)p)->hd ;
}


template <class T>
T GmList<T>::pop()
{
	if( P == 0 )
	{
		GmFatalError( "T GmList<T>::pop()", "Empty list" ) ;
	}

	GmListNode<T> * t = P->tl ;
	T             res = t->hd ;

	if( t == P )
	{
		P = 0 ;
	}
	else
	{
		P->tl = t->tl ;
	}

	delete t ;
	return res ;
}


template <class T>
GmBoolean GmList<T>::owns( GmAny p ) const
{
	GmListNode<T> * t = P ;

	if( t != 0 && p != 0 )
	{
		do
		{
			if( GmAny(t) == p ) return GmTRUE ;
			t = t->tl ;
		} while( t != P ) ;
	}

	return GmFALSE ;
}


template <class T>
GmBoolean GmList<T>::owns( const T& item ) const
{
	GmListNode<T>* t = P ;

	if( t == 0 )
	{
		return GmFALSE ;
	}

	do
	{
		if( t->hd == item )
		{
			return GmTRUE ;
		}
		t = t->tl ;

	} while( t != P ) ;

	return GmFALSE ;
}


template <class T>
T& GmList<T>::head() const
{
	if( P == 0 )
	{
		GmFatalError( "T& GmList<T>::head()", "Empty list" ) ;
	}

	return P->tl->hd ;
}


template <class T>
T& GmList<T>::tail() const
{
	if( P == 0 )
	{
		GmFatalError( "T& GmList<T>::tail()", "Empty list" ) ;
	}

	return P->hd ;
}


template <class T>
GmAny GmList<T>::insertAfter( GmAny p, const T& item )
{
	GmListNode<T> * u = (GmListNode<T>*)p ;
	GmListNode<T> * t = new GmListNode<T>( item ) ;

	if( P == 0 )
	{
		t->tl = P = t ;
	}
	else if ( u == 0 )
	{
		// insertAfter 0 means prepend
		t->tl = P->tl ;
		P->tl = t ;
	}
	else
	{
		t->tl = u->tl ;
		u->tl = t ;
		if( u == P ) P = t ;
	}

	return GmAny( t ) ;
}


template <class T>
void GmList<T>::substitute( GmAny p, const T& item )
{
	if( p == 0 )
	{
		GmError(
			"void GmList<T>::substitute( GmAny p, const T& item )",
			"Null iterator p" ) ;
		return ;
	}

	GmListNode<T> * u = (GmListNode<T>*)p ;

	u->hd = item ;
}


template <class T>
void GmList<T>::removeAfter( GmAny p )
{
	GmListNode<T> * u = (GmListNode<T>*)p ;

	// cannot del_after last
	if( P == 0 )
	{
		GmError(
			"void GmList<T>::removeAfter( GmAny p )",
			"Empty list" ) ;
		return ;
	}

	if( u == P )
	{
		GmError(
			"void GmList<T>::removeAfter( GmAny p )",
			"Can't remove after list item" ) ;
		return ;
	}

	if( u == 0 ) u = P ; // del_after 0 means delete first
	GmListNode<T> * t = u->tl ;
	if( u == t )
	{
		P = 0 ;
	}
	else
	{
		u->tl = t->tl ;
		if( P == t ) P = u ;
	}

	delete t ;
}


template <class T>
void GmList<T>::remove( const T& item )
{
	if( P == 0 )
	{
		GmError(
			"void GmList<T>::remove( const T& item )",
			"Empty list" ) ;
		return ;
	}

	GmListNode<T> * t = P->tl ; // first
	GmListNode<T> * p = 0 ; // previous node

	do
	{
		if( t->hd == item ) break ; // found
		p = t ;
		t = t->tl ;
	} while( t != P ) ;

	if( t->hd != item )
	{
		GmError(
			"void GmList<T>::remove( const T& item )",
			"Unable to found item" ) ;
		return ; // not found
	}

	removeAfter( GmAny(p) ) ;
}


template <class T>
void GmList<T>::reverse()
{
	if( P == 0 )
	{
		return ; // empty list
	}

	GmListNode<T> * l = P ;
	GmListNode<T> * p = P->tl ; 
	GmListNode<T> * new_last = p ; 

	while( p != P )
	{
		GmListNode<T> * nxt = p->tl ;
		p->tl = l ;
		l = p ;
		p = nxt ;
	}
	P->tl = l ;

	P = new_last ;
}


template <class T>
void GmList<T>::sort( GmBoolean (*sort_proc)( T&, T& ) )
{
	GmList<T> sorted ;

	if( isEmpty() ) return ;

	// le premier element appartient forcement a la liste triee.

	sorted.append( head() ) ;
	GmAny i = first() ;

	for( next( i ) ; i!=0 ; next( i ) )
	{
		T to_sort = (*this)(i) ;

		GmAny j, j_prev=0 ;
		// recherche du 1er element superieur a l'item a classer.
		for( j=sorted.first() ; j!=0 ; sorted.next( j ) )
		{
			if( (*sort_proc)( to_sort, sorted( j ) ) ) break ;
			j_prev = j ;
		}
		// j_prev = 0 correspond a un prepend.
		// si j == 0, j_prev pointe sur le dernier elt de sorted.
		sorted.insertAfter( j_prev, to_sort ) ;
	}

	clear() ;
	append( sorted ) ;
}



#ifdef POOL
///////////////////////////////// POOL /////////////////////////////////////////

/*
	Systeme d'allocation specifique des noeuds de liste
	qui s'est avere efficace lors de la destruction de
	listes de plusieurs milliers d'elements.
	Conserve ici pour une evolution possible...
*/


class <T>Pool {
	private :
		struct Link { Link * next ; } ;

		unsigned esize ; // element size.
		Link   * head ;

		<T>Pool( <T>Pool& ) {} // forbid copy.
		void operator=( <T>Pool& ) {} // idem.

		void grow() ;

	public :
		<T>Pool( unsigned ) ;
		~<T>Pool() ;

		void * alloc() ;
		void   free( void* ) ;
} ;


<T>Pool::<T>Pool( unsigned size ) : esize( size ) {

	head = 0 ;
}


<T>Pool::~<T>Pool() {

}


void <T>Pool::grow() {

	const int overhead   = 12 ;
	const int chunk_size = 8*1024-overhead ;
	const int nelem      = (chunk_size-esize)/esize ;

	char * start = new char[chunk_size] ;
	char * last  = &start[(nelem-1)*esize] ;

	for( char * p=start ; p<last ; p+=esize ) {
		((Link*)p)->next = (Link*)(p+esize) ;
	}
	((Link*)last)->next = 0 ;
	head = (Link*)start ;
}


void * <T>Pool::alloc() {

	if( head == 0 ) grow() ;

	Link * p = head ;
	head = p->next ;
	return p ;
}


void <T>Pool::free( void * b ) {

	Link * p = (Link*)b ;
	p->next = head ;
	head = p ;
}
#endif // POOL

#endif // List_C
#ifndef _Gm_List_h_
#define _Gm_List_h_ 1

typedef unsigned char GmBoolean ;
typedef void*         GmAny     ;

#ifdef __xlC__
#pragma implementation("List.C")
#endif

template <class T>
class GmListNode ;

template <class T>
class GmList
{

public :
	                GmList() ;
	                GmList( const GmList<T>& ) ;
	                ~GmList() ;
	
	GmList<T>&      operator=( const GmList<T>& ) ;
	void            append( GmList<T>& ) ;
	void            prepend( GmList<T>& ) ;

	GmBoolean       isEmpty() const ;
	int             count() const ;

	void            clear() ;

	GmAny           prepend( const T& ) ;
	GmAny           append ( const T& ) ;

	GmAny           first() const ;
	GmAny           seek( const T& ) const ;
	GmAny           seek( unsigned int ) const ;
	void            next( GmAny& ) const ;
	T&              operator()( GmAny ) const ;
	T               pop() ;

	void            substitute( GmAny, const T& ) ;

	GmBoolean       owns( GmAny ) const ;
	GmBoolean       owns( const T& ) const ;

	T&              head() const ;
	T&              tail() const ;

	GmAny           insertAfter( GmAny, const T& ) ;
	void            removeAfter( GmAny ) ;
	void            remove( const T& ) ;

	void            reverse() ;
	void            sort( GmBoolean (*)( T&, T& ) ) ;

protected :
	GmListNode<T> * P ;
} ;

#if defined(__GNUC__)
#include "List.C"
#endif

#endif // ! _Gm_List_h_
#include "WorkSession.h"
#include "WSHistLog.h"

GmWorkSession::GmWorkSession()
{
	state_ = GmWS_IDLE;
}

GmWorkSession::~GmWorkSession()
{
}

void GmWorkSession::addHistoryLog( GmWorkSessionHistoryLog& w_s_hist_log )
/*
	Purpose : Ajout d'un histoy_log.
*/
{
	history_logs_.append( &w_s_hist_log );
}
#ifndef _Gm_WorkSession_h_
#define _Gm_WorkSession_h_


#include "List.h"

class GmWorkSessionHistoryLog;

enum GmWorkSessionState
{
	GmWS_IDLE,
	GmWS_WORKING
};

class GmWorkSession {
public :
	GmWorkSession();
	virtual ~GmWorkSession();

	virtual void			addHistoryLog( GmWorkSessionHistoryLog&);

protected :
	GmWorkSessionState			state_;
	GmList<GmWorkSessionHistoryLog*>	history_logs_;

private :
};

#endif /* _Gm_WorkSession_h_ */
M WorkSession.C
D /gem/gemdev/Core-Linux/Core/lib/Linux2.2/static/lintest
A '-c' '-frepo'
O __t10GmListNode1ZP23GmWorkSessionHistoryLogRCP23GmWorkSessionHistoryLogPt10GmListNode1ZP23GmWorkSessionHistoryLog
O clear__t6GmList1ZP23GmWorkSessionHistoryLog
C append__t6GmList1ZP23GmWorkSessionHistoryLogRCP23GmWorkSessionHistoryLog
C _._t6GmList1ZP23GmWorkSessionHistoryLog
C __t6GmList1ZP23GmWorkSessionHistoryLog
M WorkSession.C
D /gem/gemdev/Core-Linux/Core/lib/Linux2.2/static/lintest
A '-c' '-frepo'
O __t10GmListNode1ZP23GmWorkSessionHistoryLogRCP23GmWorkSessionHistoryLogPt10GmListNode1ZP23GmWorkSessionHistoryLog
O _._t10GmListNode1ZP23GmWorkSessionHistoryLog
C clear__t6GmList1ZP23GmWorkSessionHistoryLog
C append__t6GmList1ZP23GmWorkSessionHistoryLogRCP23GmWorkSessionHistoryLog
C _._t6GmList1ZP23GmWorkSessionHistoryLog
C __t6GmList1ZP23GmWorkSessionHistoryLog
#ifndef _Gm_WSHistLog_h_
#define _Gm_WSHistLog_h_

#include "List.h"

class GmWorkSession;
class GmWorkSessionEvent;

class GmWorkSessionHistoryLog
{
public :
	GmWorkSessionHistoryLog( GmWorkSession& work_session);
	virtual ~GmWorkSessionHistoryLog();

	virtual void			record( GmWorkSessionEvent& w_s_event );

private :
	GmList<GmWorkSessionEvent*>	work_session_events_;
	GmWorkSession&			work_session_;
};

#endif /* _Gm_WSHistLog_h_ */

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