* 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
* Re: Why warning on static local variables ... ?
1998-04-19 19:06 Why warning on static local variables ... ? 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
* 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-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
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-19 19:06 Why warning on static local variables ... ? Munagala V. S. Ramanath
1998-04-20 15:27 ` Alexandre Oliva
1998-04-20 15:27 Munagala V. S. Ramanath
1998-04-20 18:01 Munagala V. S. Ramanath
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).