Misleading error if the type in catch() is ambiguous

2011-12-20 Thread Peter A. Felvegi

Dear All,

I suspect there is a regression from g++ 4.4 in later versions. If the 
name of the class is ambiguous in a catch(), this fact is not reported.


I had checked bz, but not found this particular case:
http://gcc.gnu.org/bugzilla/buglist.cgi?quicksearch=ambiguous

Attached a simple test case. The lines of the errors are:
31: ambiguous parent class
37: ambiguous type name for variable
43: ambiguous type name for caught exception

I tested on an amd64 machine with Debian Wheezy, stock gcc-4.4, 4.5, 4.6 
and 4.7 built from the svn trunk:


$g++-4.4 -v
Using built-in specs.
Target: x86_64-linux-gnu
Configured with: ../src/configure -v --with-pkgversion='Debian 4.4.6-14' 
--with-bugurl=file:///usr/share/doc/gcc-4.4/README.Bugs 
--enable-languages=c,c++,fortran,objc,obj-c++ --prefix=/usr 
--program-suffix=-4.4 --enable-shared --enable-linker-build-id 
--with-system-zlib --libexecdir=/usr/lib --without-included-gettext 
--enable-threads=posix --with-gxx-include-dir=/usr/include/c++/4.4 
--libdir=/usr/lib --enable-nls --enable-clocale=gnu 
--enable-libstdcxx-debug --enable-objc-gc --with-arch-32=i586 
--with-tune=generic --enable-checking=release --build=x86_64-linux-gnu 
--host=x86_64-linux-gnu --target=x86_64-linux-gnu

Thread model: posix
gcc version 4.4.6 (Debian 4.4.6-14)

$g++-4.4 -c test_gccexbug.cpp
test_gccexbug.cpp:31: error: reference to ‘ex2’ is ambiguous
test_gccexbug.cpp:17: error: candidates are: class ex2
test_gccexbug.cpp:11: error: class t::ex2
test_gccexbug.cpp:31: error: reference to ‘ex2’ is ambiguous
test_gccexbug.cpp:17: error: candidates are: class ex2
test_gccexbug.cpp:11: error: class t::ex2
test_gccexbug.cpp: In function ‘void bar()’:
test_gccexbug.cpp:37: error: reference to ‘ex2’ is ambiguous
test_gccexbug.cpp:17: error: candidates are: class ex2
test_gccexbug.cpp:11: error: class t::ex2
test_gccexbug.cpp:37: error: reference to ‘ex2’ is ambiguous
test_gccexbug.cpp:17: error: candidates are: class ex2
test_gccexbug.cpp:11: error: class t::ex2
test_gccexbug.cpp:37: error: expected ‘;’ before ‘x’
test_gccexbug.cpp:43: error: reference to ‘ex2’ is ambiguous
test_gccexbug.cpp:17: error: candidates are: class ex2
test_gccexbug.cpp:11: error: class t::ex2
test_gccexbug.cpp:43: error: expected type-specifier before ‘ex2’
test_gccexbug.cpp:43: error: expected ‘)’ before ‘&’ token
test_gccexbug.cpp:43: error: expected ‘{’ before ‘&’ token
test_gccexbug.cpp:43: error: expected primary-expression before ‘)’ token
test_gccexbug.cpp:43: error: expected ‘;’ before ‘)’ token

Note: ambiguity errors are reported twice for lines 31 and 37 and once 
for line 43.


$g++-4.5 -v
Using built-in specs.
COLLECT_GCC=g++-4.5
COLLECT_LTO_WRAPPER=/usr/lib/gcc/x86_64-linux-gnu/4.5.3/lto-wrapper
Target: x86_64-linux-gnu
Configured with: ../src/configure -v --with-pkgversion='Debian 4.5.3-9' 
--with-bugurl=file:///usr/share/doc/gcc-4.5/README.Bugs 
--enable-languages=c,c++,fortran,objc,obj-c++ --prefix=/usr 
--program-suffix=-4.5 --enable-shared --enable-linker-build-id 
--with-system-zlib --libexecdir=/usr/lib --without-included-gettext 
--enable-threads=posix --with-gxx-include-dir=/usr/include/c++/4.5 
--libdir=/usr/lib --enable-nls --enable-clocale=gnu 
--enable-libstdcxx-debug --enable-libstdcxx-time=yes --enable-plugin 
--enable-gold --enable-ld=default --with-plugin-ld=ld.gold 
--enable-objc-gc --with-arch-32=i586 --with-tune=generic 
--enable-checking=release --build=x86_64-linux-gnu 
--host=x86_64-linux-gnu --target=x86_64-linux-gnu

Thread model: posix
gcc version 4.5.3 (Debian 4.5.3-9)

$g++-4.5 -c test_gccexbug.cpp
test_gccexbug.cpp:31:27: error: reference to ‘ex2’ is ambiguous
test_gccexbug.cpp:17:1: error: candidates are: class ex2
test_gccexbug.cpp:11:1: error: class t::ex2
test_gccexbug.cpp: In function ‘void bar()’:
test_gccexbug.cpp:37:7: error: reference to ‘ex2’ is ambiguous
test_gccexbug.cpp:17:1: error: candidates are: class ex2
test_gccexbug.cpp:11:1: error: class t::ex2
test_gccexbug.cpp:37:11: error: expected ‘;’ before ‘x’
test_gccexbug.cpp:43:17: error: expected type-specifier before ‘ex2’
test_gccexbug.cpp:43:20: error: expected ‘)’ before ‘&’ token
test_gccexbug.cpp:43:20: error: expected ‘{’ before ‘&’ token
test_gccexbug.cpp:43:21: error: expected primary-expression before ‘)’ token
test_gccexbug.cpp:43:21: error: expected ‘;’ before ‘)’ token

Note: ambiguity is reported once for lines 31 and 37, and no ambiguity 
is reported for line 43. The error is misleading imho, because it 
suggests that the type name is not know instead of being ambiguous.


I suspect that the fix that removed the duplicate ambiguity messages 
might have gone a bit too far in the case of the catch(), though I 
couldn't check this since I'm not familiar with the gcc source.


gcc-4.6 and gcc-4.7 (built from the svn trunk, r182460) give the same 
error as gcc-4.5 above.


Regards, Peter

// te

Re: Misleading error if the type in catch() is ambiguous

2011-12-20 Thread Peter A. Felvegi

I've submitted a bug:

http://gcc.gnu.org/bugzilla/show_bug.cgi?id=51640

Regards, Peter



Re: Misleading error if the type in catch() is ambiguous

2012-01-04 Thread Peter A. Felvegi

Hello,

I pinpointed the commit that introduced the bug, see

http://gcc.gnu.org/bugzilla/show_bug.cgi?id=51640

Regards, Peter



Missed optimization opportunity

2012-01-09 Thread Peter A. Felvegi

Hello,

I've come across an issue when working on a smart pointer 
implementation. Gcc does not seem to propagate constants enough, missing 
some optimization opportunities. I don't think that this issue is 
specific to smart pointers, so there might be other cases when gcc 
generates suboptimal code.


Attached a simple test case. The smart pointer here is a unique pointer, 
always only a single instance holds a raw pointer to the resource. The 
deletion can be customized through a policy class. In main(), I allocate 
an int, then pass it through several smart pointers. At the end, the 
last smart pointer holds the raw pointer to the allocated memory.


Compiled as:
g++ -g -O3 -o gccoptbug.o -c gccoptbug.cpp
g++ -o gccoptbug gccoptbug.o

The generated code on AMD64 looks like this:
   0x004004d0 <+0>:sub$0x8,%rsp
   0x004004d4 <+4>:mov$0x4,%edi
   0x004004d9 <+9>:callq  0x4004c0 <_Znwm@plt> ; operator new
   0x004004de <+14>:mov%rax,%rdi
   0x004004e1 <+17>:callq  0x4004a0 <_ZdlPv@plt> ; operator 
delete

   0x004004e6 <+22>:xor%edi,%edi
   0x004004e8 <+24>:callq  0x4004a0 <_ZdlPv@plt>
   0x004004ed <+29>:xor%edi,%edi
   0x004004ef <+31>:callq  0x4004a0 <_ZdlPv@plt>
   0x004004f4 <+36>:xor%edi,%edi
   0x004004f6 <+38>:callq  0x4004a0 <_ZdlPv@plt>
   0x004004fb <+43>:xor%edi,%edi
   0x004004fd <+45>:callq  0x4004a0 <_ZdlPv@plt>
   0x00400502 <+50>:xor%eax,%eax
   0x00400504 <+52>:add$0x8,%rsp
   0x00400508 <+56>:retq

The allocated memory is freed, then op delete is called four times with 
a 0 pointer. The dtor and the called deleter fn was inlined. So far so good.


If I modify the deleter policy to call op delete only when the pointer 
is not zero (#if 1 at line 6), the generated code changes to:

   0x004004d0 <+0>:sub$0x58,%rsp
   0x004004d4 <+4>:mov$0x4,%edi
   0x004004d9 <+9>:callq  0x4004c0 <_Znwm@plt>
   0x004004de <+14>:lea0x40(%rsp),%rdi
   0x004004e3 <+19>:mov%rax,0x40(%rsp)
   0x004004e8 <+24>:movq   $0x0,(%rsp)
   0x004004f0 <+32>:movq   $0x0,0x10(%rsp)
   0x004004f9 <+41>:movq   $0x0,0x20(%rsp)
   0x00400502 <+50>:movq   $0x0,0x30(%rsp)
   0x0040050b <+59>:callq  0x400630  
>::~Ptr()>

   0x00400510 <+64>:lea0x30(%rsp),%rdi
   0x00400515 <+69>:callq  0x400630  
>::~Ptr()>

   0x0040051a <+74>:lea0x20(%rsp),%rdi
   0x0040051f <+79>:callq  0x400630  
>::~Ptr()>

   0x00400524 <+84>:lea0x10(%rsp),%rdi
   0x00400529 <+89>:callq  0x400630  
>::~Ptr()>

   0x0040052e <+94>:mov%rsp,%rdi
   0x00400531 <+97>:callq  0x400630  
>::~Ptr()>

   0x00400536 <+102>:xor%eax,%eax
   0x00400538 <+104>:add$0x58,%rsp
   0x0040053c <+108>:retq

Instead of eliminating the calls to op delete, the actual smart ptr 
objects appear on the stack, and the dtor is not inlined anymore.


gcc 4.4 and 4.5 optimizes as expected:
   0x00400640 <+0>:sub$0x8,%rsp
   0x00400644 <+4>:mov$0x4,%edi
   0x00400649 <+9>:callq  0x400540 <_Znwm@plt>
   0x0040064e <+14>:test   %rax,%rax
   0x00400651 <+17>:je 0x40065b 
   0x00400653 <+19>:mov%rax,%rdi
   0x00400656 <+22>:callq  0x400510 <_ZdlPv@plt>
   0x0040065b <+27>:xor%eax,%eax
   0x0040065d <+29>:add$0x8,%rsp
   0x00400661 <+33>:retq

4.6 and 4.7 (r182889) generates the suboptimal code as above.

I've checked bugzilla, and #46076 
(http://gcc.gnu.org/bugzilla/show_bug.cgi?id=46076) is related, I guess. 
There, Jan Hubicka 2010-10-19 03:20:48 UTC writes that main() is 
optimized for size. To check this, I've added foo() to the test case, 
and it is optimized correctly w/ 4.6 and 4.7. Moreover, -Os produces the 
same foo() and main() functions. However, the size optimized version is 
more than 3 times as large as the other one. Is this normal?


Regards, Peter

template
struct Deleter
{
	static void Delete(T* p_) 
	{
#if 0 // if enabled, Delete() is not inlined
		if (p_)
#endif
	 		delete p_; 
	}
};

template >
class Ptr
{
public:
	Ptr() :	m_ptr(0)
	{
	}

	Ptr(T* p_) : m_ptr(p_)
	{
	}

	Ptr(const Ptr& p_) : m_ptr(p_.Forget())
	{
	}

	~Ptr()
	{
		D::Delete(m_ptr);
	}

	T* Forget() const
	{
		T* s = m_ptr;
		m_ptr = 0;
		return s;
	}

private:
	mutable T*	m_ptr;
};

int main()
{
	typedef Ptr MyPtr;

	MyPtr p0 = new int;
	MyPtr p1 = p0;
	MyPtr p2 = p1;
	MyPtr p3 = p2;
	MyPtr p4 = p3;
}


multiple destructor calls of static objects

2012-01-24 Thread Peter A. Felvegi

Hello,

I ran into a bug with 4.6, when implementing a custom rtti framework, on 
an Amd64 Debian Wheezy box. It seems that at certain optimization 
levels, dtors of static objects are called multiple times. Attached a 
test case. It will print 'DEADBEEF' when the bug is hit. Searched 
bugzilla for "multiple destructor call", but found nothing relevant. The 
bug appears with only 4.6.x, and only at -O2, 3 and s.


Tested with:
* gcc-4.4.7 20111231 (prerelease) (GCC), compiled from source
* gcc-4.5.3, stock debian wheezy
* gcc-4.6.2, stock debian wheezy
* gcc-4.6.3 20120120 (prerelease) (GCC), compiled from source
* gcc-4.7.0 20120104 (experimental) (GCC), compiled from source

Should I file a bugreport and / or search for the commit that introduced 
the bug?


Regards, Peter


#include 

struct Info
{
Info(int v_ = 0) : 
		alive(1), 
		var(v_) 
	{
		printf("%p Info(%d)\n", this, v_); 
	}

~Info() 
	{ 
		if (alive) { 
			printf("%p ~Info(%d)\n", this, var); 
			alive = 0; 
		} else {
			printf("%p ~Info(%d) : DEADBEEF!\n", this, var); 
		} 
	}

int alive;
int var;
};


template
inline
const Info& foo()
{
static Info info;
return info;
}

template<>
inline
const Info& foo() __attribute__((constructor));
template<>
inline
const Info& foo()
{
static Info info(1);
return info;
}

template<>
inline
const Info& foo() __attribute__((constructor));
template<>
inline
const Info& foo()
{
static Info info(2);
return info;
}

int main()
{
	printf("> main()\n");
// if both #if's are 1, the dtors will be called multiple times
// if compiled w/ gcc 4.6, -Os, -O2 or -O3. 
// -O0 and -O1 are OK
#if 1
	foo();
	foo();
	foo();
#endif

#if 1
	foo();
	foo();
	foo();
#endif
	printf("< main()\n");
	return 0;
}


Misleading error message with templated c++ code

2012-02-03 Thread Peter A. Felvegi

Hello,

compiling the following:
---8<---8<---8<---8<---
template
struct Base
{
typename T::Typevar;
};
template
struct Derived : Base >
{
typedef U   Type;
};
void foo()
{
Derived i;
}
---8<---8<---8<---8<---
gives the error

gcctempl.cpp: In instantiation of ‘struct Base >’:
gcctempl.cpp:7:8:   required from ‘struct Derived’
gcctempl.cpp:13:15:   required from here
gcctempl.cpp:4:19: error: no type named ‘Type’ in ‘struct Derived’

on all tested gcc versions (4.4, 4.5, 4.6,4.7). There is definitely a 
type called 'Type' in struct 'Derived'. I'm not sure, the above code 
might be ill-formed, but then I'd like to see a specific error message.


Regards, Peter




array subscript is below array bounds : false positive?

2009-09-15 Thread Peter A. Felvegi

Hello,

I've run into this strange warning when compiling w/ optimization:
gcc-4.3 -O2 -Werror -Wall -c -o t.o t.c
cc1: warnings being treated as errors
t.c: In function ‘foo’:
t.c:25: error: array subscript is below array bounds

gcc-4.4 gives the same warning/error, however, gcc 4.1 and 4.2 compiles 
the source.


gcc-4.1 -v says:
Using built-in specs.
Target: x86_64-linux-gnu
Configured with: ../src/configure -v --enable-languages=c,c++ 
--prefix=/usr --enable-shared --with-system-zlib --libexecdir=/usr/lib 
--without-included-gettext --enable-threads=posix --enable-nls 
--with-gxx-include-dir=/usr/include/c++/4.1.3 --program-suffix=-4.1 
--enable-__cxa_atexit --enable-clocale=gnu --enable-libstdcxx-debug 
--with-tune=generic --enable-checking=release x86_64-linux-gnu

Thread model: posix
gcc version 4.1.3 20080704 (prerelease) (Debian 4.1.2-27)

gcc-4.2 -v says:
Using built-in specs.
Target: x86_64-linux-gnu
Configured with: ../src/configure -v 
--enable-languages=c,c++,fortran,objc,obj-c++ --prefix=/usr 
--enable-shared --with-system-zlib --libexecdir=/usr/lib 
--without-included-gettext --enable-threads=posix --enable-nls 
--with-gxx-include-dir=/usr/include/c++/4.2 --program-suffix=-4.2 
--enable-clocale=gnu --enable-libstdcxx-debug --enable-objc-gc 
--enable-mpfr --with-tune=generic --enable-checking=release 
--build=x86_64-linux-gnu --host=x86_64-linux-gnu --target=x86_64-linux-gnu

Thread model: posix
gcc version 4.2.4 (Debian 4.2.4-6)

gcc-4.3 -v says:
Using built-in specs.
Target: x86_64-linux-gnu
Configured with: ../src/configure -v --with-pkgversion='Debian 4.3.4-2' 
--with-bugurl=file:///usr/share/doc/gcc-4.3/README.Bugs 
--enable-languages=c,c++,fortran,objc,obj-c++ --prefix=/usr 
--enable-shared --enable-multiarch --enable-linker-build-id 
--with-system-zlib --libexecdir=/usr/lib --without-included-gettext 
--enable-threads=posix --enable-nls 
--with-gxx-include-dir=/usr/include/c++/4.3 --program-suffix=-4.3 
--enable-clocale=gnu --enable-libstdcxx-debug --enable-objc-gc 
--enable-mpfr --with-tune=generic --enable-checking=release 
--build=x86_64-linux-gnu --host=x86_64-linux-gnu --target=x86_64-linux-gnu

Thread model: posix
gcc version 4.3.4 (Debian 4.3.4-2)

gcc-4.4 -v says:
Using built-in specs.
Target: x86_64-linux-gnu
Configured with: ../src/configure -v --with-pkgversion='Debian 4.4.1-1' 
--with-bugurl=file:///usr/share/doc/gcc-4.4/README.Bugs 
--enable-languages=c,c++,fortran,objc,obj-c++ --prefix=/usr 
--enable-shared --enable-multiarch --enable-linker-build-id 
--with-system-zlib --libexecdir=/usr/lib --without-included-gettext 
--enable-threads=posix --with-gxx-include-dir=/usr/include/c++/4.4 
--program-suffix=-4.4 --enable-nls --enable-clocale=gnu 
--enable-libstdcxx-debug --enable-mpfr --enable-objc-gc 
--with-arch-32=i486 --with-tune=generic --enable-checking=release 
--build=x86_64-linux-gnu --host=x86_64-linux-gnu --target=x86_64-linux-gnu

Thread model: posix
gcc version 4.4.1 (Debian 4.4.1-1)

t.c is :
>8>8>8>8>8>8>8>8>8>8
#define ASSERT(x)   if (x) { } else { __asm__("int $0x03"); }
#define SIZE5

char hnd[SIZE];
char flg[SIZE];

char crd();
int  idx(char);
void set(int i, char v);

#if 1
void set(int i, char v)
{
ASSERT(i >=0 && i < SIZE);
flg[i] = v;
}
#endif


void foo()
{
char c = crd();
int  i = idx(0);
ASSERT(i != -1);
hnd[i] = c; // array subscript is below array bounds
set(i, 1);
}
>8>8>8>8>8>8>8>8>8>8

Suppose that idx(c) returns the position of c in an array, an the return 
value of -1 means that c is not in the array. The assertion checks that.


The funny thing is, if I change the source a bit, the warning goes away:
1) set '#if 1' to '#if 0' so that only the prototype of set() is visible
2) comment out the ASSERT() int set()
3) comment out ASSERT() just before the marked line
4) comment out set(i, 1) just after the marked line

The warning is not present under -O2.

Is this warning legal?

Cheers, Peter


Compiler error w/ templates and default argument value

2008-10-10 Thread Peter A. Felvegi

Hello All,

I've run into this:

8<8<8<
template
class B
{
protected:
static const int i = 42;
};

template
class D : protected B
{
public:
D(int n_ = B::i); // line 12
};
8<8<8<

gcc-4.1 and 4.3 give the same error message:

t.cpp:12: error: expected ‘,’ or ‘...’ before ‘>’ token
t.cpp:12: error: wrong number of template arguments (1, should be 2)
t.cpp:2: error: provided for ‘template class B’
t.cpp:12: error: default argument missing for parameter 2 of ‘DA>::D(int, A)’


If I write D(int n_ = (B::i) ), then it compiles. Imho it should 
compile w/o the extra parentheses. VC++ 2008 Express compiled it. Wanted 
to test gcc 4.4, too, but I wasn't able to compile the 20081003 snapshot 
(/usr/include/gnu/stubs.h:7:27: error: gnu/stubs-32.h: No such file or 
directory). I have a debian lenny/amd64 system.


Regards, P


Possible optimizer bug?

2008-10-27 Thread Peter A. Felvegi

Hello all,

I've run today into an infinite loop when compiled a test suite w/ 
optimizations. The original tests were to do some loops with all the 
nonnegative values of some integral types. Instead of hardwiring the 
max values, I thought testing for overflow into the negative domain is 
ok.


Here is the source to reproduce the bug:

8<8<8<8<
#include 
#include 

int f(int(*ff)(int))
{
int8_t i = 0; /* the real loop counter */
int ii = 0; /* loop counter for the test */
do {
if (ff(ii)) { /* test ii through a fn ptr call */
printf("ouch!\n"); /* too many loops */
return ii;
}
++ii;
} while (++i > 0);
/*
 * the loop should stop when i overflows from 0x7f to
 * 0x80 (ie -128) : 128 iterations
 * if optimizations are enabled, it won't stop.
 */
return 0;
}

extern int g_tr;

int foo(int i)
{
return i > g_tr;
}

int main(void)
{
f(&foo);

return 0;
}

int g_tr = 0x200;
8<8<8<8<

The call through the function pointer to test the loop counter is only for 
disabling inlining. If i put everything into f(), it just prints "ouch" 
and returns 0x201, the loop is optimized away completely.


The expected behaviour is present (stopping after 128 iterations) if 
compiled w/ -O0 or -O1, however, -O2 and above, and -Os result in an 
infinite loop.


The disassembly has an unconditional jump instruction after incrementing 
the loop counter.


Tested on: Debian Lenny (i386 and amd64), gcc 4.1, 4.2 and 4.3.

Compile as:
$ gcc -g -O2 t.c

then run as
$ ./a.out

Is the above code considered illegal, or is it an issue with the 
optimizer?


Regards, Peter



Failed access check

2012-04-23 Thread Peter A. Felvegi

Hello,

clang gave an error on a code that compiled with gcc so far. The reduced 
test case is:


8<8<8<8<---
class V;

struct E
{
E(const V& v_);

char* c;
V* v;
int i;
};

class V
{
private:
union {
char* c;
struct {
V* v;
int i;
};
};
};

E::E(const V& v_) :
c(v_.c), // line 25
v(v_.v),
i(v_.i)
{
}

8<8<8<8<---

Tried with gcc 4.4, 4.5, 4.6, 4.7, 4.8, all gave the same error:

gcc-4.8 -c gccaccessbug.cpp -Wall -Wextra
gccaccessbug.cpp: In constructor ‘E::E(const V&)’:
gccaccessbug.cpp:16:9: error: ‘char* Vc’ is private
gccaccessbug.cpp:25:7: error: within this context

Line 25 is where E::c is initialized, V::c is private so the error is 
due. However, V::v and V::i are also private, but no diagnostic is 
given. If I comment out 'c(v_.c)', the source compiles w/o error.


Should I file a bug report? Checked BZ for 'access control', but found 
nothing relevant, only bugs related to templated code.


Regards, Peter



Re: Failed access check

2012-04-26 Thread Peter A. Felvegi

On 04/23/2012 08:20 PM, Jonathan Wakely wrote:

On 23 April 2012 18:48, Ian Lance Taylor wrote:

"Peter A. Felvegi"  writes:


Should I file a bug report?

Yes, please.  Thanks.

Please check it's not http://gcc.gnu.org/bugzilla/show_bug.cgi?id=24926 first

Hello,

it seems to be the same issue, quite dated, though.

Regards, Peter



Insufficient access check for private static member in base class

2012-05-18 Thread Peter A. Felvegi

Hello,

I've bumped into the following:

8<8<8<8<
class Base
{
static
int foo;
};

#if 0
class Deriv : public Base
{
public:
int Foo() { return foo; }
};
#endif

template
class DerivT : public Base
{
public:
int Foo() { return foo; }
};

void bar()
{
DerivT dt;
dt.Foo();
}
8<8<8<8<

All versions I've tried (4.4, 4.5, 4.6, 4.7) compiles the code. clang 
gives proper diagnostic stating that Base::foo is private.


If base::foo is not static, gcc catches the error, too:
gccacbug.cpp: In member function ‘int DerivT::Foo() [with T = void]’:
gccacbug.cpp:25: instantiated from here
gccacbug.cpp:4: error: ‘int Base::foo’ is private
gccacbug.cpp:19: error: within this context

If I enable the non-templated Deriv class, I get an error (twice):
gccacbug.cpp: In member function ‘int Deriv::Foo()’:
gccacbug.cpp:3:13: error: ‘int Base::foo’ is private
gccacbug.cpp:10:21: error: within this context
gccacbug.cpp:3:13: error: ‘int Base::foo’ is private
gccacbug.cpp:10:21: error: within this context

Searching bugzilla for 'static member access' didn't give any results. 
Should I file a bug report?


Regards, Peter



error: call of overloaded ‘foo(int)’ is ambiguous (0 vs null ptr)

2012-05-24 Thread Peter A. Felvegi

Hello,

I'm not sure whether this is standard behaviour or not; nonetheless I 
was quite surprised:


8<8<8<
void foo(long);
void foo(const char*);

void bar()
{
foo(0);
foo(0+0); // !
foo(1-1); // !
foo(1);
}
8<8<8<

The first call to foo() in bar() is ambiguous, all right (integral or 
ptr), but the next two (marked w/ !) ? Shouldn't the compiler know that 
0+0 or 1-1, etc can't be a null pointer? I tried all minor versions from 
4.4 to 4.8.


Somewhat connected question: if I use |-Wzero-as-null-pointer-constant 
to detect cases where 0 means null pointer, shouldn't there be a switch 
that forbids conversion from 0 to null ptr? I have a class that has 
operator() overloaded for size_t and for const char* (access elements by 
index or by name). All is well, except for the index 0: the call would 
be ambiguous. I tried to trick this with 0+0, etc, hence the whole post. 
0.0 works, though. Any better ideas? Explicit cast?


Supposing that I eliminated all 0's that meant null ptr, using the 
switch could eliminate this kind of ambiguity, and I could use 0 where I 
mean 0, without any trickery.


Regards, Peter

|


Code optimization: warning for code that hangs

2012-06-23 Thread Peter A. Felvegi

Hello,

I bumped into a strange bug today: the program hang at a point, 
inspecting the disassembly revealed that it was a single jmp instruction 
which jumped onto itself. Most of the code from the C++ function was 
missing. The bug occurs at -O2 or -O3, -O1 generates correct code. The 
function itself didn't change recently, but some referenced classes did; 
earlier the code was correct even at -O3.


It turned out that during maintenance, an infinite recursion creeped in. 
At -O1, the program crashed with SIGSEGV as expected due to exhausting 
the stack.


Details:

The original structure looked like this:

struct J;

struct S
{
J& m_root;
S(J& j) : m_root(j) {}
void Dump(Printer&);
};

struct J
{
S m_root;
J() : m_root(*this) {}
S& GetRoot() { return m_root; }
void Dump(Printer& p) { m_root.Dump(p); }
};

An S is embedded in J, and J::Dump() is forwarded to it. Then, some 
minor changes occured: instead of embedding S, inheritance was used:


struct J : S
{
// m_root removed
J() : S(*this);
// GetRoot() removed
void Dump(Printer& p) { m_root.Dump(p); }
};

Accidentally, J::Dump() was not removed, and by the incident that both S 
and J had an m_root member in the first version, m_root.Dump(p) called 
itself in an infinite recursion.


Here is the test case:
8<---8<8<---8<8<---8<8<---8<---
struct J;

struct S
{
J&  j;

S(J& j_) : j(j_) { }
voidF() { }
};

struct J : S
{
J() : S(*this) { }
voidF() { j.F(); }
};

void foo()
{
J j;
j.F();
}

int main()
{
foo();
}
8<---8<8<---8<8<---8<8<---8<---

The generated code at -O3 is:

(gdb) disassemble foo
Dump of assembler code for function foo():
   0x00400470 <+0>:jmp0x400470 
End of assembler dump.

-O1 is interesting:

(gdb) disassemble foo
Dump of assembler code for function foo():
   0x0040046c <+0>:subrsp,0x18
   0x00400470 <+4>:learax,[rsp]
   0x00400474 <+8>:movQWORD PTR [rsp],rax
   0x00400478 <+12>:movrdi,rsp
   0x0040047b <+15>:call   0x400498 
   0x00400480 <+20>:addrsp,0x18
   0x00400484 <+24>:ret
End of assembler dump.

So far so good, but J::F() is strange:

Dump of assembler code for function J::F():
   0x00400498 <+0>:subrsp,0x8
   0x0040049c <+4>:movrax,QWORD PTR [rdi]
   0x0040049f <+7>:movrax,QWORD PTR [rax]
   0x004004a2 <+10>:movrax,QWORD PTR [rax]
   0x004004a5 <+13>:movrax,QWORD PTR [rax]
   0x004004a8 <+16>:movrax,QWORD PTR [rax]
   0x004004ab <+19>:movrax,QWORD PTR [rax]
   0x004004ae <+22>:movrax,QWORD PTR [rax]
   0x004004b1 <+25>:movrax,QWORD PTR [rax]
   0x004004b4 <+28>:movrdi,QWORD PTR [rax]
   0x004004b7 <+31>:call   0x400498 
   0x004004bc <+36>:addrsp,0x8
   0x004004c0 <+40>:ret
End of assembler dump.

What are those mov rax,QWORD PTR [rax]'s ?

My question is: wouldn't it be possible to print a warning when a jmp to 
itself or trivial infinite recursion is generated? The code compiled 
fine w/ -Wall -Wextra -Werror w/ 4.6 and 4.7.


Cheers, Peter



Re: Code optimization: warning for code that hangs

2012-06-25 Thread Peter A. Felvegi

Hello,



So far so good, but J::F() is strange:

Dump of assembler code for function J::F():
   0x00400498 <+0>:subrsp,0x8
   0x0040049c <+4>:movrax,QWORD PTR [rdi]
   0x0040049f <+7>:movrax,QWORD PTR [rax]
   0x004004a2 <+10>:movrax,QWORD PTR [rax]
   0x004004a5 <+13>:movrax,QWORD PTR [rax]
   0x004004a8 <+16>:movrax,QWORD PTR [rax]
   0x004004ab <+19>:movrax,QWORD PTR [rax]
   0x004004ae <+22>:movrax,QWORD PTR [rax]
   0x004004b1 <+25>:movrax,QWORD PTR [rax]
   0x004004b4 <+28>:movrdi,QWORD PTR [rax]
   0x004004b7 <+31>:call   0x400498 
   0x004004bc <+36>:addrsp,0x8
   0x004004c0 <+40>:ret
End of assembler dump.

What are those mov rax,QWORD PTR [rax]'s ?
No comments on this part? Shouldn't the optimizer eliminated a few of 
those loads?


Regards, Peter



Regression: incorrect line numbers in debug info since 4.5+

2012-06-25 Thread Peter A. Felvegi

Hello,

I found out while single stepping a new template function in gdb that 
gcc generates bad/inaccurate line numbers in the debug info. 
Optimization was turned off, but the execution jumped strangely, see 
below. gcc-4.4 and the current clang produced the expected results, gcc 
4.5, 4.6, 4.7, 4.8 all had problems. The code was factored out from a 
proof-of-concept hack.


Here is the trace that was produced in gdb by single stepping the 
program with 'n'. The program was compiled w/ gcc 4.8.0 git commit e7ae865c:


COLLECT_GCC=gcc-4.8.0
COLLECT_LTO_WRAPPER=/home/usr-local/bin/../libexec/gcc/x86_64-unknown-linux-gnu/4.8.0/lto-wrapper
Target: x86_64-unknown-linux-gnu
Configured with: ./configure --enable-languages=c,c++ 
--program-suffix=-4.8.0

Thread model: posix
gcc version 4.8.0 20120605 (experimental) (GCC)

g++-4.8.0 -g -O0 -Wall -Wextra -o dbginfobug.o -c dbginfobug.cpp
g++-4.8.0 -g -o dbginfobug dbginfobug.o

11  while (C c = *f++) {
12  if (c == '$') {
56  if (o < e) {
57  *o = c;
59  ++o;
// the first anomaly: the line printed is AFTER the loop, while we're 
still in the loop

// this happens only with 4.8, after each iteration
62  printf("RESULT (%zu chars): '%s'\n", o - buf, buf);
11  while (C c = *f++) {
12  if (c == '$') {
56  if (o < e) {
57  *o = c;
59  ++o;
62  printf("RESULT (%zu chars): '%s'\n", o - buf, buf);
...
62  printf("RESULT (%zu chars): '%s'\n", o - buf, buf);
11  while (C c = *f++) {
12  if (c == '$') {
13  C c2 = *f;
14  if (c2 == '$') {
18  unsigned ai = gai;
19  if (c2 == '{') {
20  ++f;
21  C c3 = *f;
22  if (c3 >= '0' &&  c3 <= '9') {
23  ai = 0;
24  while (C c4 = *f) {
25  if (c4 < '0'  
||  c4 > '9') {

28  ai *= 10;
29  ai += c4 - '0';
30  ++f;
24  while (C c4 = *f) {
25  if (c4 < '0'  
||  c4 > '9') {

// doesn't stop on the break with 4.8, stops with earlier versions

// !!! we should be after the closing brace of the loop, yet we're still 
inside

30  ++f;
(gdb) p c4
// this is quite a gotcha: c4 of type C is not in the scope anymore, but 
some constant

// of type mynumber creeps in the scope from libm.
// this wasn't too helpful understanding what's going on...
$16 = {i = {1431655765, -1079683755}, x = -0.041664}
(gdb) p f
$17 = 0x400a18 "}\n"
36  C x = *f++;
// f was not incremented (correctly), despite it stood on the line ++f
(gdb) p f
$18 = 0x400a18 "}\n"
37  if (x == '}') {
// now it stops on this break. what's the difference compared to the 
above if() where it didn't stop?

38  break;
62  printf("RESULT (%zu chars): '%s'\n", o - buf, buf);
11  while (C c = *f++) {
12  if (c == '$') {

I attached the cpp source, and also the preprocessed version, if it 
makes any difference.


I couldn't find anything similar in bz, please let me know whether this 
is a new issue and I will file a bugreport.


Regards, Peter

#include 
#include 

template
void do_print(C* buf, size_t siz, const C* fmt)
{
	const C* f = fmt;
	C* o = buf;
	C* e = buf + siz;
	unsigned gai = 0;
	while (C c = *f++) {
		if (c == '$') {
			C c2 = *f;
			if (c2 == '$') {
++f;
goto lit;
			}
			unsigned ai = gai;
			if (c2 == '{') {
++f;
C c3 = *f;
if (c3 >= '0'  &&  c3 <= '9') {
	ai = 0;
	while (C c4 = *f) {
		if (c4 < '0'  ||  c4 > '9') {
			break;
		}
		ai *= 10;
		ai += c4 - '0';
		++f;
	}
} else {
	++gai;
}
do {
	C x = *f++;
	if (x == '}') {
		break;
	}
	if (x == 0) {
		fprintf(stderr, "ERROR: no closing brace\n");
		return;
	}
	if (x == 'f') {
		break;
	} else {
		fprintf(stderr, "ERROR: invalid format specifier char '%c'\n", x);
		return;
	}
} while (1);
			} else {
++gai;
			}
		} else {
		lit:
			if (o < e) {
*o = c;
			}
			++o;
		}
	}
	printf("RESULT (%zu chars): '%s'\n", o - buf, buf);
}

void fo

Re: Regression: incorrect line numbers in debug info since 4.5+

2012-06-25 Thread Peter A. Felvegi

Hello,

Which version of GDB?

As documented at http://gcc.gnu.org/gcc-4.5/changes.html

GCC now generates unwind info also for epilogues. DWARF debuginfo
generated by GCC now uses more features of DWARF3 than before, and
also some DWARF4 features. GDB older than 7.0 is not able to handle
either of these, so to debug GCC 4.5 generated binaries or libraries
GDB 7.0 or later is needed. You can disable use of DWARF4 features
with the -gdwarf-3 -gstrict-dwarf options, or use -gdwarf-2
-gstrict-dwarf to restrict GCC to just DWARF2, but epilogue unwind
info is emitted unconditionally whenever unwind info is emitted.
I was using 7.4.1, under Debian Wheezy, amd64. Tried the dwarf 2 
options, but then I wasn't even able to step into the template function 
from foo(): when hitting step on the function name, the next line was 
the fn closing brace, in asm it jumped from preparing the reg args to 
the leaveq after the call. When stepped inside the fn via si, the first 
'next' attempt failed gdb saying that the fn contained no line number 
info, and stopped at the outer leaveq as before.


With dwarf-3 and 4, the already reported buggy behaviour occured when 
single stepping the function.


Regards, Peter



Re: Regression: incorrect line numbers in debug info since 4.5+

2012-06-25 Thread Peter A. Felvegi

The bug is at:
http://gcc.gnu.org/bugzilla/show_bug.cgi?id=53770

Regards, Peter



Regression/bug in 4.7 regarding typedef in templated class

2012-10-27 Thread Peter A. Felvegi

Hello,

after upgrading gcc one of my classes failed to compile. Stock 
Debian/Wheezy 4.4, 4.5, 4.6 compiled the code, also compiled a version 
of 4.7.0 that was built by me from sources some time ago. Clang 3.0-6 
also compiled, but stock 4.7.1-7, the head of 4.7 (4.7.3 d51dc77f, 
r192839) and the head of master (4.8.0 1a2798ac, r192875) didn't.


Reduced the code to a test case:

8<8<8<8<8<8<8<
class Id
{
public:
Id();
Id(char a, char b);
explicitId(int v);
Id(const char* id_);
};

template
class Foo
{
public:
//  typedef ID  IdType;
void Bar(const ID& id_);
typedef ID  IdType;

};

template
void Foo::Bar(const IdType& id_)
//void Foo::Bar(const ID& id_)
{
}

void foo()
{
Foo f;
f.Bar("hello");
}
8<8<8<8<8<8<8<

$ g++ -c gcctypedef.cpp
gcctypedef.cpp: In function ‘void foo()’:
gcctypedef.cpp:29:15: error: no matching function for call to 
‘Foo::Bar(const char [6])’

gcctypedef.cpp:29:15: note: candidate is:
gcctypedef.cpp:21:6: note: void Foo::Bar(const IdType&) [with ID = 
Id; Foo::IdType = Id]
gcctypedef.cpp:21:6: note:   no known conversion for argument 1 from 
‘const char [6]’ to ‘Id&’


4.8 gives the same error, but in prettier, more verbose format.

If the typedef in class Foo is _before_ the Bar fn declaration, gcc 
compiles the code.


If instead of the typedef (IdType) the original type (ID) is used in the 
argument of the Bar fn at the definition, gcc compiles the code.


I git bisect'd the commit that introduced the regression/bug:

commit 44f861fca343148a1b0720105ec2b7f14bbcc849
Author: jason 
Date:   Wed Feb 8 09:52:11 2012 +

PR c++/52035
* pt.c (tsubst): Strip uninstantiated typedef.

git-svn-id: svn+ssh://gcc.gnu.org/svn/gcc/trunk@184000 
138bc75d-0d04-0410-961f-82ee72b054a4


I didn't find anything relevant in Bugzilla when searching for 'typedef 
template'. Should I file a bug report?


Kind regards, Peter




Copy constructor access check while initializing a reference

2008-03-03 Thread Peter A. Felvegi
hello,

i've found this in the known non-bugs list
(http://gcc.gnu.org/bugs.html#known), after running into the issue. gcc
3.4-4.2 gives a compile error, but 4.3 compiles it. is this a
regression, or the rules were relaxed somewhat (c++0x?) ? i checked the
changelog, but couldn't find any relevant entries there.

could someone explain the rationale behind this extra access check,
please? i'm puzzled, since the copy ctor is not needed and is not called
from the generated code.

regards, p




signature.asc
Description: OpenPGP digital signature


va_list bug?

2008-03-18 Thread Peter A. Felvegi
hello,

please try the little program at the end. my naive assumption was that
it will print "hello world" two times.

if compiled with gcc 3.4, 4.1, 4.2 or 4.3 for i386, it will print "hello
world" two times all right.

however, if compiled with 3.3, 3.4, 4.1 or 4.3 for amd64, the second
time it will print "hello @[EMAIL PROTECTED]" (garbage).

it seems that the gp_offset field of the va struct gets modified by
someone, so the second vprintf prints garbage:

vp (fmt=0x400672 "hello %s\n", args=0x7fff0e83aec0) at v.c:6
6   vprintf(fmt, args);
(gdb) display *args
1: *args = {gp_offset = 8, fp_offset = 48, overflow_arg_area =
0x7fff0e83afa0, reg_save_area = 0x7fff0e83aee0}
(gdb) n
hello world
7   vprintf(fmt, args);
1: *args = {gp_offset = 16, fp_offset = 48, overflow_arg_area =
0x7fff0e83afa0, reg_save_area = 0x7fff0e83aee0}

i don't know whether this is a gcc issue or a libc issue, but i suspect
that it's a bug. please clarify.
i have a debian etch amd64 system, glibc is 2.3.6.

searching for "gcc glibc variadic argument bug" didn't give any relevant
pages.

regards, peter

8<8<8<8<8<8<8<8<8<
#include 
#include 

void vp(const char* fmt, va_list args)
{
vprintf(fmt, args);
vprintf(fmt, args);
}

void p(const char* fmt, ...)
{
va_list args;
va_start(args, fmt);
vp(fmt, args);
va_end(args);
}

int main()
{
p("hello %s\n", "world");
}




signature.asc
Description: OpenPGP digital signature


can't reinterpret_cast to/from the same type

2007-09-06 Thread Peter A. Felvegi
hello,

i don't know if it's a bug, please clarify:

rc.cpp:
--8<--
void f()
{
int x = 0;
int y = reinterpret_cast(x);
}
--8<--
gcc -v:
Using built-in specs.
Target: i486-linux-gnu
Configured with: ../src/configure -v
--enable-languages=c,c++,fortran,objc,obj-c++,treelang --prefix=/usr
--enable-shared --with-system-zlib --libexecdir=/usr/lib
--without-included-gettext --enable-threads=posix --enable-nls
--program-suffix=-4.1 --enable-__cxa_atexit --enable-clocale=gnu
--enable-libstdcxx-debug --enable-mpfr --with-tune=i686
--enable-checking=release i486-linux-gnu
Thread model: posix
gcc version 4.1.2 20061115 (prerelease) (Debian 4.1.1-21)

gcc -c rc.cpp:
rc.cpp: In function ‘void f()’:
rc.cpp:4: error: invalid cast from type ‘int’ to type ‘int’

i suspected that one could cast from int to int.

google hasn't found any relevant pages for 'gcc reinterpret cast bug'

regards, peter




function overloading and variadic arguments

2007-09-20 Thread Peter A. Felvegi
hello,

today i've spent a few hours debugging... consider the following code:

>8>8>8>8>8>8
// test.cpp
#include 
#include 

int prn(const char* fmt_);
int prn(const char* fmt_, ...) __attribute__((format(printf, 1, 2)));
int prn(const char* fmt_, va_list args_);

int prn(const char* fmt_)
{
return 0;
}

int prn(const char* fmt_, ...)
{
va_list args;

va_start(args, fmt_);
int r = prn(fmt_, args);
va_end(args);
return r;
}

int prn(const char* fmt_, va_list args_)
{
char out[4096];

return vsnprintf(out, sizeof(out), fmt_, args_);
}

int main(int argc_, char** argv_)
{
int s0 = prn("%s %s", "hello", "world");
int s1 = prn("hello %s", "world");
int s2 = prn("hello %s", argv_[0]);
int s3 = prn("hello %d", 42);
return 0;
}
>8>8>8>8>8>8

it turns out, that when initializing s1, the function with the va_list
second arg is called, not the variadic version, which results in a sigsegv.

tried gcc-2.95, 3.3, 4.1 and 4.2, with -Wall -W[extra]. 4.2 warns about
the deprecated conversion from string constant to char* (which needs
some interpretation), but the others are silent about the issue.

a warning would be nice, if the compiler detects that there's an
ambiguity: passing an argument that would fit the variadic and the
va_list (or any other type) argument versions of the functions, too.

the solution is to name the functions differently, but unfortunately
pinning down the source of the bug took me quite some time (the original
code was more complex of course ;)

i'd like to hear your comments.

regards, p



Re: function overloading and variadic arguments

2007-09-21 Thread Peter A. Felvegi
>> i'd like to hear your comments.
> 
>   Is va_list a typedef for char* on your system, then?  What ever happened to
> it being an alias for __builtin_va_list via __gnuc_va_list?

i don't know what happened, but it seems like a char*. my system is a
debian i636 etch, here are compiler versions:

$ gcc-4.3-exp -v
Using built-in specs.
Target: i686-pc-linux-gnu
Configured with: ./configure --program-suffix=-4.3-exp
Thread model: posix
gcc version 4.3.0 20070914 (experimental) (GCC)

gives 'warning: deprecated conversion from string constant to ‘char*’'



$ gcc-4.2 -v
Using built-in specs.
Target: i686-pc-linux-gnu
Configured with: ./configure --program-suffix=-4.2
Thread model: posix
gcc version 4.2.1

gives the same warning



$ gcc-4.1 -v
Using built-in specs.
Target: i486-linux-gnu
Configured with: ../src/configure -v
--enable-languages=c,c++,fortran,objc,obj-c++,treelang --prefix=/usr
--enable-shared --with-system-zlib --libexecdir=/usr/lib
--without-included-gettext --enable-threads=posix --enable-nls
--program-suffix=-4.1 --enable-__cxa_atexit --enable-clocale=gnu
--enable-libstdcxx-debug --enable-mpfr --with-tune=i686
--enable-checking=release i486-linux-gnu
Thread model: posix
gcc version 4.1.2 20061115 (prerelease) (Debian 4.1.1-21)

no warning



$ gcc-3.3 -v
Reading specs from /usr/lib/gcc-lib/i486-linux-gnu/3.3.6/specs
Configured with: ../src/configure -v --enable-languages=c,c++
--prefix=/usr --mandir=/usr/share/man --infodir=/usr/share/info
--with-gxx-include-dir=/usr/include/c++/3.3 --enable-shared
--enable-__cxa_atexit --with-system-zlib --enable-nls
--without-included-gettext --enable-clocale=gnu --enable-debug
i486-linux-gnu
Thread model: posix
gcc version 3.3.6 (Debian 1:3.3.6-15)

no warning



regards, p


ctor style cast vs c style cast

2007-12-13 Thread Peter A. Felvegi
hello all,

today i've run into this: if i cast a double value to an unsigned int
using the C style cast when passing it to printf, it's fine. however, if
i use the ctor style cast, i get a compile error. in theory, these two
should do the same: create a temporary unsigned int, and assign the
double to it after conversion, just the syntax is different. made a
little test, see attachment. plain int's are ok, but when qualified with
signed/unsigned the error occurs.

i can't judge whether this is an error or not, please clarify.

$ gcc -v
Using built-in specs.
Target: x86_64-linux-gnu
Configured with: ../src/configure -v
--enable-languages=c,c++,fortran,objc,obj-c++,treelang --prefix=/usr
--enable-shared --with-system-zlib --libexecdir=/usr/lib
--without-included-gettext --enable-threads=posix --enable-nls
--program-suffix=-4.1 --enable-__cxa_atexit --enable-clocale=gnu
--enable-libstdcxx-debug --enable-mpfr --enable-checking=release
x86_64-linux-gnu
Thread model: posix
gcc version 4.1.2 20061115 (prerelease) (Debian 4.1.1-21)

regards, p

void f(int i)
{
}

void g(unsigned int j)
{
}

class X
{
public:
	 X(double);
};

void t()
{
	// named variables with ctor syntax : all ok
	int  i1(1.0);
	signed int   i2(1.0);
	unsigned int i3(1.0);

	const int  ci1(1.0);
	const signed int   ci2(1.0);
	const unsigned int ci3(1.0);

	// unnamed temporaries with ctor syntax
	int(1.0);
	signed int(1.0);   // error
	unsigned int(1.0); // error

	const int(1.0);  // error
	const signed int(1.0);   // error
	const unsigned int(1.0); // error

	// unnamed temporaries with C style cast
	(signed int)(1.0);
	(unsigned int)(1.0); 
	(const signed int)(1.0);
	(const unsigned int)(1.0);

	// named variable and unnamed temporary of class X
	X x(1.0);
	X(1.0);

	const X cx(1.0);
	const X(1.0);

	// new ctor style casts
	f(int(1.0));
	f(signed int(1.0));  // error
	g(unsigned int(1.0)); // error

	// old c style casts
	f((int)1.0);
	f((signed int)1.0);
	g((unsigned int)1.0);
}


signature.asc
Description: OpenPGP digital signature