Bug #5290
openint64_t issues for abs() with c++ out of stdlib.h
0%
Description
This is the original issue found is reproduced with the following program:
richard@omnis:/home/richard/src$ cat tabs.cc #include <stdlib.h> void tabs(int64_t foo) { int64_t bar = abs(foo); } richard@omnis:/home/richard/src$ /opt/gcc-4.8.1/bin/g++ -c tabs.cc tabs.cc: In function ‘void tabs(int64_t)’: tabs.cc:4:23: error: call of overloaded ‘abs(int64_t&)’ is ambiguous int64_t bar = abs(foo); ^ tabs.cc:4:23: note: candidates are: In file included from /usr/include/stdlib.h:37:0, from tabs.cc:1: /usr/include/iso/stdlib_iso.h:165:16: note: long int std::abs(long int) inline long abs(long _l) { return labs(_l); } ^ /usr/include/iso/stdlib_iso.h:119:12: note: int std::abs(int) extern int abs(int); ^ richard@omnis:/home/richard/src$ /opt/gcc-4.8.1/bin/g++ -m64 -c tabs.cc
There is (on i386) a first issue of a problematic definition when uint64_t (here long long) is used.
Then, by simply copying the .cc to a .c and trying again with gcc
richard@omnis:/home/richard/src$ cp tabs.cc tabs.c richard@omnis:/home/richard/src$ /opt/gcc-4.8.1/bin/gcc -c tabs.c tabs.c:2:11: error: unknown type name ‘int64_t’ void tabs(int64_t foo) ^ richard@omnis:/home/richard/src$ richard@omnis:/home/richard/src$ /opt/gcc-4.8.1/bin/gcc -m64 -c tabs.c tabs.c:2:11: error: unknown type name ‘int64_t’ void tabs(int64_t foo) ^
Here the ball is completely dropped.
outputting via '-E -dD -o <file>' indicates what is determined by the compiler.
Clang gives informative output as well:
richard@omnis:/home/richard/src$ clang++ -m32 -c tabs.cc tabs.cc:4:16: error: call to 'abs' is ambiguous int64_t bar = abs(foo); ^~~ /usr/include/iso/stdlib_iso.h:119:12: note: candidate function extern int abs(int); ^ /usr/include/iso/stdlib_iso.h:165:16: note: candidate function inline long abs(long _l) { return labs(_l); } ^ 1 error generated. richard@omnis:/home/richard/src$ clang++ -m64 -c tabs.cc richard@omnis:/home/richard/src$ clang -m32 -c tabs.c tabs.c:4:16: warning: absolute value function 'abs' given an argument of type 'int64_t' (aka 'long long') but has parameter of type 'int' which may cause truncation of value [-Wabsolute-value] int64_t bar = abs(foo); ^ tabs.c:4:16: note: use function 'llabs' instead int64_t bar = abs(foo); ^~~ llabs 1 warning generated. richard@omnis:/home/richard/src$ clang -m64 -c tabs.c tabs.c:4:16: warning: absolute value function 'abs' given an argument of type 'int64_t' (aka 'long') but has parameter of type 'int' which may cause truncation of value [-Wabsolute-value] int64_t bar = abs(foo); ^ tabs.c:4:16: note: use function 'labs' instead int64_t bar = abs(foo); ^~~ labs 1 warning generated.
Files
Updated by Richard PALO over 8 years ago
The output when using `-E -dD |egrep 'STDC|LP|LONGLONG|INT64|int64'` is interesting.
Is there also a gcc compiler issue in not defining int64_t that could explain the clang difference with 'c'?
Updated by Richard PALO over 8 years ago
I believe this is relatively recent.
Just tried on oi_151a9 with gcc44:
richard@smicro:~/src$ /opt/gcc/4.4.4/bin/g++ -m32 -c tabs.cc richard@smicro:~/src$ /opt/gcc/4.4.4/bin/g++ -m64 -c tabs.cc richard@smicro:~/src$ /opt/gcc/4.4.4/bin/gcc -m32 -c tabs.cc richard@smicro:~/src$ /opt/gcc/4.4.4/bin/gcc -m64 -c tabs.cc
to compare with omnios bloody and gcc-4.4.4
richard@omnis:/home/richard/src$ /opt/gcc-4.4.4/bin/g++ -m32 -c tabs.cc richard@omnis:/home/richard/src$ /opt/gcc-4.4.4/bin/g++ -m64 -c tabs.cc richard@omnis:/home/richard/src$ /opt/gcc-4.4.4/bin/gcc -m32 -c tabs.c tabs.c:2: error: expected ‘)’ before ‘foo’ richard@omnis:/home/richard/src$ /opt/gcc-4.4.4/bin/gcc -m64 -c tabs.c tabs.c:2: error: expected ‘)’ before ‘foo’
Updated by Richard PALO over 8 years ago
Still more curiously, gcc 3.4.3 on oi_151a9
richard@smicro:~/src$ gcc -v Reading specs from /usr/sfw/lib/gcc/i386-pc-solaris2.11/3.4.3/specs Configured with: /home/jt/OIDEV/151A-PRESTABLE9/newbuilds/sfw/usr/src/cmd/gcc/gcc-3.4.3/configure --prefix=/usr/sfw --with-as=/usr/sfw/bin/gas --with-gnu-as --with-ld=/usr/ccs/bin/ld --without-gnu-ld --enable-languages=c,c++,f77,objc --enable-shared Thread model: posix gcc version 3.4.3 (csl-sol210-3_4-20050802) richard@smicro:~/src$ g++ -m32 -c tabs.cc richard@smicro:~/src$ g++ -m64 -c tabs.cc richard@smicro:~/src$ gcc -m32 -c tabs.c tabs.c:2: error: syntax error before "foo" tabs.c: In function `tabs': tabs.c:4: error: `int64_t' undeclared (first use in this function) tabs.c:4: error: (Each undeclared identifier is reported only once tabs.c:4: error: for each function it appears in.) tabs.c:4: error: syntax error before "bar" richard@smicro:~/src$ gcc -m64 -c tabs.c tabs.c:2: error: syntax error before "foo" tabs.c: In function `tabs': tabs.c:4: error: `int64_t' undeclared (first use in this function) tabs.c:4: error: (Each undeclared identifier is reported only once tabs.c:4: error: for each function it appears in.) tabs.c:4: error: syntax error before "bar"
Updated by Richard PALO over 8 years ago
It appears that the 'long long' defs are missing for a number of functions.
For example, the following gets over the initial issue stated:
richard@omnis:/home/richard/src$ diff -u /usr/include/iso/stdlib_c99.h.orig /usr/include/iso/stdlib_c99.h --- /usr/include/iso/stdlib_c99.h.orig mar. sept. 30 07:57:17 2014 +++ /usr/include/iso/stdlib_c99.h jeu. nov. 6 12:39:43 2014 @@ -69,6 +69,7 @@ #if defined(_LONGLONG_TYPE) extern long long atoll(const char *); extern long long llabs(long long); +inline long long abs(long long _ll) { return llabs(_ll); } extern lldiv_t lldiv(long long, long long); extern long long strtoll(const char *_RESTRICT_KYWD, char **_RESTRICT_KYWD, int);
Updated by Richard PALO over 8 years ago
which, as of now, promptly causes the following problem :
richard@omnis:/home/richard/src$ /opt/gcc-4.8.1/bin/gcc -m32 -c tabs.c In file included from /usr/include/stdlib.h:38:0, from tabs.c:1: /usr/include/iso/stdlib_c99.h:72:18: error: conflicting types for ‘abs’ inline long long abs(long long _ll) { return llabs(_ll); } ^ tabs.c:2:11: error: unknown type name ‘int64_t’ void tabs(int64_t foo) ^ richard@omnis:/home/richard/src$ /opt/gcc-4.8.1/bin/gcc -D__EXTENSIONS__ -m32 -c tabs.c In file included from /usr/include/stdlib.h:38:0, from tabs.c:1: /usr/include/iso/stdlib_c99.h:72:18: error: conflicting types for ‘abs’ inline long long abs(long long _ll) { return llabs(_ll); } ^
and clang:
richard@omnis:/home/richard/src$ clang -m32 -c tabs.c In file included from tabs.c:1: In file included from /usr/include/stdlib.h:38: /usr/include/iso/stdlib_c99.h:72:18: error: conflicting types for 'abs' inline long long abs(long long _ll) { return llabs(_ll); } ^ /usr/include/iso/stdlib_iso.h:119:12: note: previous declaration is here extern int abs(int); ^ tabs.c:4:16: warning: absolute value function 'abs' given an argument of type 'int64_t' (aka 'long long') but has parameter of type 'int' which may cause truncation of value [-Wabsolute-value] int64_t bar = abs(foo); ^ tabs.c:4:16: note: use function 'llabs' instead int64_t bar = abs(foo); ^~~ llabs 1 warning and 1 error generated. richard@omnis:/home/richard/src$ clang -D__EXTENSIONS__ -m32 -c tabs.c In file included from tabs.c:1: In file included from /usr/include/stdlib.h:38: /usr/include/iso/stdlib_c99.h:72:18: error: conflicting types for 'abs' inline long long abs(long long _ll) { return llabs(_ll); } ^ /usr/include/iso/stdlib_iso.h:119:12: note: previous declaration is here extern int abs(int); ^ tabs.c:4:16: warning: absolute value function 'abs' given an argument of type 'int64_t' (aka 'long long') but has parameter of type 'int' which may cause truncation of value [-Wabsolute-value] int64_t bar = abs(foo); ^ tabs.c:4:16: note: use function 'llabs' instead int64_t bar = abs(foo); ^~~ llabs 1 warning and 1 error generated.
So the solution may not be so rudimentary...
Updated by Richard PALO over 8 years ago
So far, the most portable "workaround " found seems to be
resorting to c++ includes cstdlib + cmath as in the following:
#include <stdlib.h> #if defined(__sun) && defined(__cplusplus) #include <cstdlib> #include <cmath> #endif void tabs(int64_t foo) { int64_t bar = abs(foo); }
This pulls in:
# 173 "/opt/gcc-4.8.1/include/c++/4.8.1/cstdlib" 3 inline long long abs(long long __x) { return __builtin_llabs (__x); }
That's enough from me now, hopefully the math masters have a durable solution
that works for both i386 and x86_64 out of the box.
Updated by Igor Kozhukhov over 8 years ago
- /usr/gcc/4.8/bin/g++ -c tabs.cc
- gcc -v
Using built-in specs.
COLLECT_GCC=gcc
COLLECT_LTO_WRAPPER=/usr/gcc/4.8/lib/gcc/x86_64-pc-solaris2.11/4.8.3/lto-wrapper
Target: x86_64-pc-solaris2.11
Configured with: /myshare/builds/jenkins/src/du/dilos-userland-review/components/gcc48/gcc-4.8.3/configure --prefix=/usr/gcc/4.8 --mandir=/usr/gcc/4.8/share/man --bindir=/usr/gcc/4.8/bin --libdir=/usr/gcc/4.8/lib --sbindir=/usr/gcc/4.8/sbin --infodir=/usr/share/info --with-gnu-as --with-as=/usr/bin/gas --build=x86_64-pc-solaris2.11 --target=x86_64-pc-solaris2.11 --enable-targets=i386-pc-solaris2.11 --infodir=/usr/gcc/4.8/share/info --libexecdir=/usr/gcc/4.8/lib --enable-languages=c,c++,fortran,objc --enable-shared --enable-tls --enable-threads=posix --without-gnu-ld --with-ld=/usr/bin/ld
Thread model: posix
gcc version 4.8.3 (GCC)
- /usr/gcc/4.8/bin/g++ -m32 -c tabs.cc
tabs.cc: In function ‘void tabs(int64_t)’:
tabs.cc:4:26: error: call of overloaded ‘abs(int64_t&)’ is ambiguous
int64_t bar = abs(foo);
^
tabs.cc:4:26: note: candidates are:
In file included from /usr/include/stdlib.h:37:0,
from tabs.cc:1:
/usr/include/iso/stdlib_iso.h:165:16: note: long int std::abs(long int)
inline long abs(long _l) { return labs(_l); }
^
/usr/include/iso/stdlib_iso.h:119:12: note: int std::abs(int)
extern int abs(int);
^
- /usr/gcc/4.8/bin/g++ -m64 -c tabs.cc
root@srv115:/myshare/builds/dilos-userland/dilos-userland-review/components/2#
Updated by Rich Lowe over 8 years ago
This looks from a distance like the kind of thing that fix-includes may affect. If you're going to do comparitive testing, you should make certain that you're always using our headers, only.
That would involve deleting or moving aside the include-fixed directories of the various compilers.
Updated by Richard PALO over 8 years ago
PM: clang doesn't use gnu-c's fix-includes as far as I know. Also, I very quickly checked /opt/gcc-4.8.1/lib/gcc/i386-pc-solaris2.11/4.8.1/include-fixed (as well as the others used) to see if something might have come up...
Updated by Richard PALO over 8 years ago
For info: I updated the test program just a tad and filed a gnu c++ issue to get a response for an eventual compiler issue... https://gcc.gnu.org/bugzilla/show_bug.cgi?id=63789
Updated by Richard PALO over 8 years ago
Richard PALO wrote:
Still more curiously, gcc 3.4.3 on oi_151a9
[...]
just for completeness, adding #include <stdint.h> fixes the build on 3.4.3.
I needed the same for FreeBSD, that is why the test program is updated as follows:
#include <stdint.h> #include <stdlib.h> int64_t tabs(int64_t foo) { return abs(foo); }
Updated by Richard PALO over 8 years ago
Can anybody answer this?:
Marc Glisse 2014-11-09 11:55:02 UTC long long (or int64_t) is not part of C++03, so solaris headers don't provide the overload. We complete the set of overloads in c* headers, but there is a well known bug that we don't provide wrappers for the *.h headers. It would be interesting to see how Oracle is updating the solaris headers for C++11.
Updated by Richard PALO over 8 years ago
Can anybody post the tabs.ii output on latest Or*cle solaris for:(preferably gcc4[8-9])
`g++ -c tabs.cc -save-temps` where tabs.cc is from https://www.illumos.org/issues/5290#note-11
Updated by Alexander Eremin over 8 years ago
Richard PALO wrote:
Can anybody post the tabs.ii output on latest Or*cle solaris for:(preferably gcc4[8-9])
`g++ -c tabs.cc -save-temps` where tabs.cc is from https://www.illumos.org/issues/5290#note-11
S11.2 has same output for gcc4.8, tabs.ii is attached.
Updated by Richard PALO almost 7 years ago
I finally got annoyed enough to try something, anybody willing to take a look/try?
diff --git a/usr/src/head/iso/stdlib_iso.h b/usr/src/head/iso/stdlib_iso.h index 90af2de..cc00933 100644 --- a/usr/src/head/iso/stdlib_iso.h +++ b/usr/src/head/iso/stdlib_iso.h @@ -138,6 +138,9 @@ extern _NORETURN_KYWD void exit(int) extern void free(void *); extern char *getenv(const char *); extern long int labs(long); +#ifdef _LONGLONG_TYPE +extern long long int llabs(long long); +#endif extern ldiv_t ldiv(long, long); extern void *malloc(size_t); extern int mblen(const char *, size_t); @@ -165,6 +168,9 @@ extern size_t wcstombs(char *_RESTRICT_KYWD, const wchar_t *_RESTRICT_KYWD, #if __cplusplus >= 199711L extern "C++" { inline long abs(long _l) { return labs(_l); } +#ifdef _LONGLONG_TYPE + inline long long abs(long long _ll) { return llabs(_ll); } +#endif inline ldiv_t div(long _l1, long _l2) { return ldiv(_l1, _l2); } } #endif /* __cplusplus */
Updated by Richard PALO almost 7 years ago
except this isn't quite right since iso/stdlib_c99.h defines already llabs() correctly, but
scoping rules would prevent the abs() overload from working since stdlib_iso.h is included
prior to stdlib_{c99,c11}.h
Perhaps it is possible to legally rearrange things?
Updated by Richard PALO almost 7 years ago
This may work, though:
---- a/usr/src/head/iso/stdlib_c99.h +++ b/usr/src/head/iso/stdlib_c99.h @@ -84,6 +84,16 @@ extern long long strtoll(const char *_RESTRICT_KYWD, char **_RESTRICT_KYWD, int); extern unsigned long long strtoull(const char *_RESTRICT_KYWD, char **_RESTRICT_KYWD, int); + +#if __cplusplus >= 201103L +extern "C++" { + inline long long abs(long long _ll) { return (llabs(_ll)); } + inline lldiv_t div(long long _ll1, long long _ll2) { + return (lldiv(_ll1, _ll2)); + } +} +#endif /* __cplusplus */ + #endif /* defined(_LONGLONG_TYPE) */ #endif /* (!defined(_STRICT_STDC) && !defined(__XOPEN_OR_POSIX)) ... */
added div() for good measure.
Updated by Richard PALO almost 7 years ago
- Subject changed from int64_t issues out of stdlib.h to int64_t issues for abs() with c++ out of stdlib.h