public inbox for gcc@gcc.gnu.org
 help / color / mirror / Atom feed
* Re: Why warning on static local variables ... ?
@ 1998-04-20 15:27 Munagala V. S. Ramanath
  0 siblings, 0 replies; 4+ messages in thread
From: Munagala V. S. Ramanath @ 1998-04-20 15:27 UTC (permalink / raw)
  To: oliva, ram; +Cc: egcs

Alexandre Oliva <oliva@dcc.unicamp.br> writes:

> Munagala V S Ramanath <ram@netcom.com> writes:
> 
> > tmp1.C: In function `struct A<int,8> Mul<A<int,8>>(const struct A<int,8> &, const struct A<int,8> &)':
> > tmp1.C:51: warning: sorry: semantics of inline function static data `int const n' are wrong (you'll wind up with multiple copies)
> 
> AFAIK, this occurs only on some targets that do not support ELF weak
> symbols, or something like that.  It does not occur on Solaris 2.[56], 
> for instance, but it does occur in SunOS 4.1.3.  You can only notice
> this problem if the inline function is instantiated in two different
> compilation units.

    Ok, I'm on SunOS 4.1.2, so I guess I'll just have to live with the
    problem. I'm no expert on load module formats but I had assumed
    that the linker that comes with egcs had the necessary smarts to
    eliminate duplicate symbols of this sort.
    
    Does this also mean I have to use -fno-implicit-templates and
    manually instantiate templates (or use -frepo) to avoid duplicate
    copies of all templates (as I was doing with gcc-2.7.2) on SunOS ?

> > PROBLEM 2: As can be seen from the above program output, it seems to
> >    be invoking the wrong constructor [A(int) instead of A(&A)] for the
> >    declaration like: B f3( Mul<B>( f1, f1 ) );
> >    Is there some default rule that I'm overlooking or is it a bug ?
> 
> The compiler is allowed to optimize away such copy-constructor call.
> Instead of copy-constructing the object returned by Mul<B> into f3 and
> f4, egcs arranges that Mul<B> constructs f3 and f4 directly, in-place.

    This explains why A(&A) is _not_ called but does not explain why
    A(int) _is_ called instead in this case; as I see it, in the program
    output:

A(int): val = 2560
A(int): val = 2304
Mul: &n = 0x22a0, n = 8
A(int): val = 6553600
Mul: &n = 0x22a0, n = 8
A(int): val = 5308416
f1 = 10, f3 = 25600, f2 = 9, f4 = 20736

    The first two calls of A(int) are for f1 and f2; then Mul is called
    for f3 but then we have _another_ call to A(int) followed by yet
    another call to A(int) after Mul is called for f4 which is what I
    still don't understand.

    Thanks for all the explanations.

    Ram

^ permalink raw reply	[flat|nested] 4+ messages in thread

* Re: Why warning on static local variables ... ?
@ 1998-04-20 18:01 Munagala V. S. Ramanath
  0 siblings, 0 replies; 4+ messages in thread
From: Munagala V. S. Ramanath @ 1998-04-20 18:01 UTC (permalink / raw)
  To: oliva, ram; +Cc: egcs

Alexandre Oliva <oliva@dcc.unicamp.br> writes:

    [... stuff deleted ...]

>> The compiler is allowed to optimize away such copy-constructor call.
>> Instead of copy-constructing the object returned by Mul<B> into f3 and
>> f4, egcs arranges that Mul<B> constructs f3 and f4 directly, in-place.

To which I replied:

>    This explains why A(&A) is _not_ called but does not explain why
>    A(int) _is_ called instead in this case; as I see it, in the program
>    output:
>
>A(int): val = 2560
>A(int): val = 2304
>Mul: &n = 0x22a0, n = 8
>A(int): val = 6553600
>Mul: &n = 0x22a0, n = 8
>A(int): val = 5308416
>f1 = 10, f3 = 25600, f2 = 9, f4 = 20736
>
>    The first two calls of A(int) are for f1 and f2; then Mul is called
>    for f3 but then we have _another_ call to A(int) followed by yet
>    another call to A(int) after Mul is called for f4 which is what I
>    still don't understand.

Oops, my mistake: the 3rd and 4th calls to the A(int) constructors are
from the return at the end of the Mul routine. Just didn't see it.

Sorry about that.

Ram

^ permalink raw reply	[flat|nested] 4+ messages in thread

* Re: Why warning on static local variables ... ?
  1998-04-19 19:06 Munagala V. S. Ramanath
@ 1998-04-20 15:27 ` Alexandre Oliva
  0 siblings, 0 replies; 4+ messages in thread
From: Alexandre Oliva @ 1998-04-20 15:27 UTC (permalink / raw)
  To: Munagala V. S. Ramanath; +Cc: egcs

Munagala V S Ramanath <ram@netcom.com> writes:

> tmp1.C: In function `struct A<int,8> Mul<A<int,8>>(const struct A<int,8> &, const struct A<int,8> &)':
> tmp1.C:51: warning: sorry: semantics of inline function static data `int const n' are wrong (you'll wind up with multiple copies)

AFAIK, this occurs only on some targets that do not support ELF weak
symbols, or something like that.  It does not occur on Solaris 2.[56], 
for instance, but it does occur in SunOS 4.1.3.  You can only notice
this problem if the inline function is instantiated in two different
compilation units.

> PROBLEM 2: As can be seen from the above program output, it seems to
>    be invoking the wrong constructor [A(int) instead of A(&A)] for the
>    declaration like: B f3( Mul<B>( f1, f1 ) );
>    Is there some default rule that I'm overlooking or is it a bug ?

The compiler is allowed to optimize away such copy-constructor call.
Instead of copy-constructing the object returned by Mul<B> into f3 and
f4, egcs arranges that Mul<B> constructs f3 and f4 directly, in-place.

> PROBLEM 3: If the "#define WORKS" is commented out, it gets all
>    confused about instantiationg operator<<; even adding an explicit
>    instantiation does not help. Here is the initial part of the list of
>    diagnostics I get:

> ========================================================================
> tmp1.C: In function `class ostream & operator <<<char[15]>(class ostream &, const char (&)[15])':
> tmp1.C:66: request for member `val' in `a', which is of non-aggregate type `char[15]'
> tmp1.C:66: `char[15]' is not an aggregate type

The problem is that the ostream class (which should be a
specialization of template basic_ostream, but that's another story)
provides member operators for outputting `char *' and `const char *'
(these operators should have been global functions instead of member
ones, BTW), but not for `char[]' and `const char[]'.  Since a string
literal has type `char [n]' (according to the C++ Standard, it should
be `const char [n]', but that's yet another story), your global
operator << is a exact match that requires an identity conversion
(i.e., no conversion), whereas the member function is an exact match
that requires an lvalue-transformation (array-to-pointer conversion).
Hence, your global operator<< is a better match, so it is preferred.

As a rule of thumb, don't ever define such a general template for
stream classes; overloading operator<< for the particular type or
template class you have defined is a much safer approach.

-- 
Alexandre Oliva
mailto:oliva@dcc.unicamp.br mailto:aoliva@acm.org
http://www.dcc.unicamp.br/~oliva
Universidade Estadual de Campinas, SP, Brasil


^ permalink raw reply	[flat|nested] 4+ messages in thread

* Why warning on static local variables ... ?
@ 1998-04-19 19:06 Munagala V. S. Ramanath
  1998-04-20 15:27 ` Alexandre Oliva
  0 siblings, 1 reply; 4+ messages in thread
From: Munagala V. S. Ramanath @ 1998-04-19 19:06 UTC (permalink / raw)
  To: egcs

Hi,

The following program illustrates several puzzling elements in the
behavior of egcs-1.0.2; I'm not sure if they are bugs in my
understanding of templates or bugs in egcs, so I thought I'd ask here:

PROBLEM 1. When compiled as is with "gcc -Wall tmp1.C -lstdc++", I get:

========================================================================
tmp1.C: In function `struct A<int,8> Mul<A<int,8>>(const struct A<int,8> &, const struct A<int,8> &)':
tmp1.C:51: warning: sorry: semantics of inline function static data `int const n' are wrong (you'll wind up with multiple copies)
========================================================================

   When I run the resulting executable, I get:

========================================================================
A(int): val = 2560
A(int): val = 2304
Mul: &n = 0x22a0, n = 8
A(int): val = 6553600
Mul: &n = 0x22a0, n = 8
A(int): val = 5308416
f1 = 10, f3 = 25600, f2 = 9, f4 = 20736
========================================================================

   Why does it warn about "multiple copies" on static local data in
   inline template functions ?  I could think of 3 possible situations:
   (a) Multiple copies in different specializations. This cannot be the
       problem because in that case, "multiple" copies is precisely what
       the user wants -- one per specialization.
   (b) Multiple copies of the same specialization at multiple call
       sites. As the above output shows, it does _not_ in fact create
       "multiple" copies since the address of 'n' is 0x22a0 in both
       invocations of Mul().
   (c) Same as (b) but call sites in different compilation units.  Given
       the complexity of template code that egcs already correctly
       handles, it does not seem that hard to avoid duplicates in this
       case.

   So I'm really puzzled about this warning and wondering if there is
   some way to use static local data in inline template functions
   without drawing this warning with -Wall.

PROBLEM 2: As can be seen from the above program output, it seems to
   be invoking the wrong constructor [A(int) instead of A(&A)] for the
   declaration like: B f3( Mul<B>( f1, f1 ) );
   Is there some default rule that I'm overlooking or is it a bug ?

PROBLEM 3: If the "#define WORKS" is commented out, it gets all
   confused about instantiationg operator<<; even adding an explicit
   instantiation does not help. Here is the initial part of the list of
   diagnostics I get:

========================================================================
tmp1.C: In function `struct A<int,8> Mul<A<int,8>>(const struct A<int,8> &, const struct A<int,8> &)':
tmp1.C:51: warning: sorry: semantics of inline function static data `int const n' are wrong (you'll wind up with multiple copies)
tmp1.C: In function `class ostream & operator <<<char[15]>(class ostream &, const char (&)[15])':
tmp1.C:66: request for member `val' in `a', which is of non-aggregate type `char[15]'
tmp1.C:66: `char[15]' is not an aggregate type
tmp1.C:66: warning: control reaches end of non-void function `operator <<<char[15]>(ostream &, const char (&)[15])'
tmp1.C: In function `class ostream & operator <<<char[11]>(class ostream &, const char (&)[11])':
tmp1.C:66: request for member `val' in `a', which is of non-aggregate type `char[11]'
tmp1.C:66: `char[11]' is not an aggregate type
tmp1.C:66: warning: control reaches end of non-void function `operator <<<char[11]>(ostream &, const char (&)[11])'
tmp1.C: In function `class ostream & operator <<<const int *>(class ostream &, const int *const &)':
tmp1.C:66: request for member `val' in `a', which is of non-aggregate type `const int *'
tmp1.C:66: `const int *' is not an aggregate type
tmp1.C:66: warning: control reaches end of non-void function `operator <<<const int *>(ostream &, const int *const &)'
...
========================================================================

    Thanks for any help.

    Ram

//-----------  CUT HERE  ---------------------  CUT HERE  --------------
// illustrates 3 problems in egcs-1.0.2:
// 1. unnecessary warning for static local variables in template
//    functions
// 2. seems to invoke the wrong constructor
// 3. templated operator<< declaration needs to be more elaborate than
//    necessary.
//
#include <fstream.h>

// forward declarations needed for the friend declarations below
template< class T, int NUM > struct A;
template< class T > inline T Mul( const T &a1, const T &a2 );

// commenting out following line yields diagnostics
#define WORKS

#ifdef WORKS
template< class T, int NUM > ostream &
    operator<<( ostream &os, const A< T, NUM > &a );
#else
template< class T > ostream & operator<<( ostream &os, const T &a );
#endif

template< class T, int NUM >
struct A {

    friend A Mul< A > ( const A &a1, const A &a2 );

#ifdef WORKS
    friend ostream & operator<< < T, NUM >(
        ostream &os, const A< T, NUM > &a );
#else
    friend ostream & operator<< < T >(
        ostream &os, const T &a );
#endif

    static const int N = NUM;
    static const int ONE = 1 << NUM;
    A( const int a ) : val( a << NUM ) {
        cerr << "A(int): val = " << val << endl; }
    A( const A &a ) : val( a.val ) {
        cerr << "A(&A): val = " << val << endl; }
    T val;
};

typedef A< int, 8 > B;

template< class T > inline T
Mul( const T &a1, const T &a2 ) {

    static const int n = T::N;
    cout << "Mul: &n = " << &n << ", n = " << n << endl;
    return (a1.val * a2.val) >> n;
}

#ifdef WORKS
template< class T, int NUM > ostream &
operator<<( ostream &os, const A< T, NUM > &a )
{
    return os << a.val / static_cast<double>(A<T,NUM>::ONE);
}
#else
template< class T > ostream &
operator<<( ostream &os, const T &a )
{
    return os << a.val / static_cast<double>(T::ONE);
}
// even adding an explicit instantiation does not help this case
template ostream &operator<< < B >( ostream &, const B & );
#endif

main()
{
    B f1( 10 ), f2( 9 ), f3( Mul<B>( f1, f1 ) ), f4( Mul<B>( f2, f2 ) );
    cout << "f1 = " << f1 << ", f3 = " << f3
         << ", f2 = " << f2 << ", f4 = " << f4 << endl;
    return 0;
}

^ permalink raw reply	[flat|nested] 4+ messages in thread

end of thread, other threads:[~1998-04-20 18:01 UTC | newest]

Thread overview: 4+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
1998-04-20 15:27 Why warning on static local variables ... ? Munagala V. S. Ramanath
  -- strict thread matches above, loose matches on Subject: below --
1998-04-20 18:01 Munagala V. S. Ramanath
1998-04-19 19:06 Munagala V. S. Ramanath
1998-04-20 15:27 ` Alexandre Oliva

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for read-only IMAP folder(s) and NNTP newsgroup(s).