Add workaround for Win32 wrong type for size_t
GCC std::array uses std::size_t for its size_type. On Linux/amd64, `std::size_t` is `unsigned long`. On Win32, `std::size_t` is `unsigned int`. This provokes format string warnings because an unsigned int is passed where the format string declares an unsigned long. On Win32, `unsigned int` and `unsigned long` are the same size, so `unsigned long` could have been used to avoid this problem by maintaining consistency with Linux, but it was not. This may have been an attempt to achieve bug compatibility with Microsoft's types. Add a workaround by defining a macro DXX_PRI_size_type in the style of inttypes.h PRI* macros. Use an SConf test to determine the correct value by inspecting which compilation runs succeed. Currently, Linux needs "l", Win32 needs "", and Win64 needs "I64".
This commit is contained in:
parent
a9aa5552b7
commit
674a9213f8
94
SConstruct
94
SConstruct
|
@ -1744,6 +1744,100 @@ help:always wipe certain freed memory
|
|||
poison = True
|
||||
if poison:
|
||||
context.sconf.Define('DXX_HAVE_POISON')
|
||||
implicit_tests.append(_implicit_test.RecordedTest('check_size_type_long', "assume size_t is formatted as `unsigned long`"))
|
||||
implicit_tests.append(_implicit_test.RecordedTest('check_size_type_int', "assume size_t is formatted as `unsigned int`"))
|
||||
implicit_tests.append(_implicit_test.RecordedTest('check_size_type_I64', "assume size_t is formatted as `unsigned I64`"))
|
||||
@_custom_test
|
||||
def _check_size_type_format_modifier(self,context,_text='''
|
||||
#include <cstddef>
|
||||
#define DXX_PRI_size_type %s
|
||||
__attribute_format_printf(1, 2)
|
||||
void f(const char *, ...);
|
||||
''',_main='''
|
||||
std::size_t s = 0;
|
||||
f("%" DXX_PRI_size_type, s);
|
||||
'''):
|
||||
'''
|
||||
The test must declare a custom function to call with this format string.
|
||||
gcc has hardcoded knowledge about how printf works, but that knowledge
|
||||
on Mingw64 differs from the processing of
|
||||
__attribute__((format(printf,...))). Mingw64 requires I64u for
|
||||
__attribute__((format)) functions, but llu for printf. Mingw32 is
|
||||
consistent in its use of u. Linux gcc is consistent in its use of
|
||||
lu.
|
||||
|
||||
-- cut --
|
||||
#include <cstdio>
|
||||
#include <cstddef>
|
||||
__attribute__((format(printf,1,2))) void f(const char *,...);
|
||||
void a() {
|
||||
std::size_t b = 0;
|
||||
printf("%I64u", b);
|
||||
f("%I64u", b);
|
||||
printf("%llu", b);
|
||||
f("%llu", b);
|
||||
printf("%lu", b);
|
||||
f("%lu", b);
|
||||
printf("%u", b);
|
||||
f("%u", b);
|
||||
}
|
||||
-- cut --
|
||||
|
||||
$ x86_64-w64-mingw32-g++-5.4.0 -x c++ -S -Wformat -o /dev/null -
|
||||
<stdin>: In function 'void a()':
|
||||
<stdin>:6:19: warning: format '%u' expects argument of type 'unsigned int', but argument 2 has type 'std::size_t {aka long long unsigned int}' [-Wformat=]
|
||||
<stdin>:9:13: warning: unknown conversion type character 'l' in format [-Wformat=]
|
||||
<stdin>:9:13: warning: too many arguments for format [-Wformat-extra-args]
|
||||
<stdin>:10:17: warning: format '%lu' expects argument of type 'long unsigned int', but argument 2 has type 'std::size_t {aka long long unsigned int}' [-Wformat=]
|
||||
<stdin>:11:12: warning: format '%lu' expects argument of type 'long unsigned int', but argument 2 has type 'std::size_t {aka long long unsigned int}' [-Wformat=]
|
||||
<stdin>:12:16: warning: format '%u' expects argument of type 'unsigned int', but argument 2 has type 'std::size_t {aka long long unsigned int}' [-Wformat=]
|
||||
<stdin>:13:11: warning: format '%u' expects argument of type 'unsigned int', but argument 2 has type 'std::size_t {aka long long unsigned int}' [-Wformat=]
|
||||
|
||||
$ i686-w64-mingw32-g++-5.4.0 -x c++ -S -Wformat -o /dev/null -
|
||||
<stdin>: In function 'void a()':
|
||||
<stdin>:7:14: warning: format '%I64u' expects argument of type 'long long unsigned int', but argument 2 has type 'std::size_t {aka unsigned int}' [-Wformat=]
|
||||
<stdin>:8:18: warning: format '%llu' expects argument of type 'long long unsigned int', but argument 2 has type 'std::size_t {aka unsigned int}' [-Wformat=]
|
||||
<stdin>:9:13: warning: unknown conversion type character 'l' in format [-Wformat=]
|
||||
<stdin>:9:13: warning: too many arguments for format [-Wformat-extra-args]
|
||||
<stdin>:10:17: warning: format '%lu' expects argument of type 'long unsigned int', but argument 2 has type 'std::size_t {aka unsigned int}' [-Wformat=]
|
||||
<stdin>:11:12: warning: format '%lu' expects argument of type 'long unsigned int', but argument 2 has type 'std::size_t {aka unsigned int}' [-Wformat=]
|
||||
|
||||
$ mingw32-g++-5.4.0 -x c++ -S -Wformat -o /dev/null -
|
||||
<stdin>: In function 'void a()':
|
||||
<stdin>:6:19: warning: format '%I64u' expects argument of type 'long long unsigned int', but argument 2 has type 'std::size_t {aka unsigned int}' [-Wformat=]
|
||||
<stdin>:7:14: warning: format '%I64u' expects argument of type 'long long unsigned int', but argument 2 has type 'std::size_t {aka unsigned int}' [-Wformat=]
|
||||
<stdin>:8:18: warning: unknown conversion type character 'l' in format [-Wformat=]
|
||||
<stdin>:8:18: warning: too many arguments for format [-Wformat-extra-args]
|
||||
<stdin>:9:13: warning: unknown conversion type character 'l' in format [-Wformat=]
|
||||
<stdin>:9:13: warning: too many arguments for format [-Wformat-extra-args]
|
||||
<stdin>:10:17: warning: format '%lu' expects argument of type 'long unsigned int', but argument 2 has type 'std::size_t {aka unsigned int}' [-Wformat=]
|
||||
<stdin>:11:12: warning: format '%lu' expects argument of type 'long unsigned int', but argument 2 has type 'std::size_t {aka unsigned int}' [-Wformat=]
|
||||
|
||||
$ x86_64-pc-linux-gnu-g++-5.4.0 -x c++ -S -Wformat -o /dev/null -
|
||||
<stdin>: In function 'void a()':
|
||||
<stdin>:6:19: warning: format '%u' expects argument of type 'unsigned int', but argument 2 has type 'std::size_t {aka long unsigned int}' [-Wformat=]
|
||||
<stdin>:7:14: warning: format '%u' expects argument of type 'unsigned int', but argument 2 has type 'std::size_t {aka long unsigned int}' [-Wformat=]
|
||||
<stdin>:8:18: warning: format '%llu' expects argument of type 'long long unsigned int', but argument 2 has type 'std::size_t {aka long unsigned int}' [-Wformat=]
|
||||
<stdin>:9:13: warning: format '%llu' expects argument of type 'long long unsigned int', but argument 2 has type 'std::size_t {aka long unsigned int}' [-Wformat=]
|
||||
<stdin>:12:16: warning: format '%u' expects argument of type 'unsigned int', but argument 2 has type 'std::size_t {aka long unsigned int}' [-Wformat=]
|
||||
<stdin>:13:11: warning: format '%u' expects argument of type 'unsigned int', but argument 2 has type 'std::size_t {aka long unsigned int}' [-Wformat=]
|
||||
|
||||
'''
|
||||
# Test types in order of decreasing probability.
|
||||
for how in (
|
||||
# Linux
|
||||
('l', 'size_type_long'),
|
||||
# Win64
|
||||
('I64', 'size_type_I64'),
|
||||
# Win32
|
||||
('', 'size_type_int'),
|
||||
):
|
||||
DXX_PRI_size_type = how[0]
|
||||
f = '"%su"' % DXX_PRI_size_type
|
||||
if self.Compile(context, text=_text % f, main=_main, msg='whether to format std::size_t with "%%%su"' % DXX_PRI_size_type, calling_function=how[1]):
|
||||
context.sconf.Define('DXX_PRI_size_type', f)
|
||||
return
|
||||
raise SCons.Errors.StopError("C++ compiler rejects all candidate format strings for std::size_t.")
|
||||
@_custom_test
|
||||
def check_strcasecmp_present(self,context,_successflags={'CPPDEFINES' : ['DXX_HAVE_STRCASECMP']}):
|
||||
main = '''
|
||||
|
|
|
@ -471,12 +471,12 @@ void bm_read_extra_robots(const char *fname, Mission::descent_version_type type)
|
|||
|
||||
t = PHYSFSX_readInt(fp);
|
||||
if (N_D2_OBJBITMAPS+t >= ObjBitmaps.size())
|
||||
Error("Too many object bitmaps (%d) in <%s>. Max is %lu.", t, fname, ObjBitmaps.size() - N_D2_OBJBITMAPS);
|
||||
Error("Too many object bitmaps (%d) in <%s>. Max is %" DXX_PRI_size_type "u.", t, fname, ObjBitmaps.size() - N_D2_OBJBITMAPS);
|
||||
bitmap_index_read_n(fp, partial_range(ObjBitmaps, N_D2_OBJBITMAPS, N_D2_OBJBITMAPS + t));
|
||||
|
||||
t = PHYSFSX_readInt(fp);
|
||||
if (N_D2_OBJBITMAPPTRS+t >= ObjBitmapPtrs.size())
|
||||
Error("Too many object bitmap pointers (%d) in <%s>. Max is %lu.", t, fname, ObjBitmapPtrs.size() - N_D2_OBJBITMAPPTRS);
|
||||
Error("Too many object bitmap pointers (%d) in <%s>. Max is %" DXX_PRI_size_type "u.", t, fname, ObjBitmapPtrs.size() - N_D2_OBJBITMAPPTRS);
|
||||
range_for (auto &i, partial_range(ObjBitmapPtrs, N_D2_OBJBITMAPPTRS, N_D2_OBJBITMAPPTRS + t))
|
||||
i = PHYSFSX_readShort(fp);
|
||||
}
|
||||
|
@ -537,7 +537,7 @@ void load_robot_replacements(const d_fname &level_name)
|
|||
for (j=0;j<t;j++) {
|
||||
i = PHYSFSX_readInt(fp); //read objbitmap number
|
||||
if (i < 0 || i >= ObjBitmaps.size())
|
||||
Error("Object bitmap number (%d) out of range in (%s). Range = [0..%lu].", i, static_cast<const char *>(level_name), ObjBitmaps.size() - 1);
|
||||
Error("Object bitmap number (%d) out of range in (%s). Range = [0..%" DXX_PRI_size_type "].", i, static_cast<const char *>(level_name), ObjBitmaps.size() - 1);
|
||||
bitmap_index_read(fp, ObjBitmaps[i]);
|
||||
}
|
||||
|
||||
|
@ -545,7 +545,7 @@ void load_robot_replacements(const d_fname &level_name)
|
|||
for (j=0;j<t;j++) {
|
||||
i = PHYSFSX_readInt(fp); //read objbitmapptr number
|
||||
if (i < 0 || i >= ObjBitmapPtrs.size())
|
||||
Error("Object bitmap pointer (%d) out of range in (%s). Range = [0..%lu].", i, static_cast<const char *>(level_name), ObjBitmapPtrs.size() - 1);
|
||||
Error("Object bitmap pointer (%d) out of range in (%s). Range = [0..%" DXX_PRI_size_type "].", i, static_cast<const char *>(level_name), ObjBitmapPtrs.size() - 1);
|
||||
ObjBitmapPtrs[i] = PHYSFSX_readShort(fp);
|
||||
}
|
||||
Robot_replacements_loaded = 1;
|
||||
|
|
Loading…
Reference in a new issue