MSVC warnings when compiling Lua as C++

106 views
Skip to first unread message

Sainan

unread,
Jul 29, 2026, 8:21:52 AMJul 29
to lu...@googlegroups.com
Hi, I feel like this topic is brought up every so often and not like it's majorly urgent, but I'll just throw it here.

As of the current latest commit (7579fc9d7ed90240487251dfb69168f8e64e9294), there's the following warnings when compiling Lua as C++ with MSVC:

1>...\lua\lgc.c(488,21): warning C4334: '<<': result of 32-bit shift implicitly converted to 64 bits (was 64-bit shift intended?)
1>...\lua\lgc.c(577,21): warning C4334: '<<': result of 32-bit shift implicitly converted to 64 bits (was 64-bit shift intended?)
1>...\lua\lgc.c(792,19): warning C4334: '<<': result of 32-bit shift implicitly converted to 64 bits (was 64-bit shift intended?)
1>...\lua\lgc.c(811,23): warning C4334: '<<': result of 32-bit shift implicitly converted to 64 bits (was 64-bit shift intended?)
1>...\lua\ltable.c(389,10): warning C4334: '<<': result of 32-bit shift implicitly converted to 64 bits (was 64-bit shift intended?)

And my 2 cents for the patch; in lobject.h on line 829:

-#define twoto(x) (1u<<(x))
+#define twoto(x) (1ull<<(x))

This change results in these warnings disappearing.

-- Sainan

Roberto Ierusalimschy

unread,
Jul 29, 2026, 11:10:20 AMJul 29
to 'Sainan' via lua-l
> Hi, I feel like this topic is brought up every so often and not like it's majorly urgent, but I'll just throw it here.
>
> As of the current latest commit (7579fc9d7ed90240487251dfb69168f8e64e9294), there's the following warnings when compiling Lua as C++ with MSVC:
>
> 1>...\lua\lgc.c(488,21): warning C4334: '<<': result of 32-bit shift implicitly converted to 64 bits (was 64-bit shift intended?)
[...]
>
> And my 2 cents for the patch; in lobject.h on line 829:
>
> -#define twoto(x) (1u<<(x))
> +#define twoto(x) (1ull<<(x))
>
> This change results in these warnings disappearing.

The point is that we do want a 32-bit shift. This warning seems to be a
bug: In all those warnings, the result of the shift is being explicitly
casted to size_t, which I believe is 64 bits. (Or not??) So, there is no
"implicit" conversion to 64 bits.

We really don't know how to silence this warning without worsening the
code.

-- Roberto

Sainan

unread,
Jul 29, 2026, 11:24:39 AMJul 29
to lu...@googlegroups.com
Hmm, I guess MSVC wants you to be explicit about what result type you expect in this case.

-#define sizenode(t) (twoto((t)->lsizenode))
+#define sizenode(t) (cast_int(twoto((t)->lsizenode)))

This also suppresses it.

-- Sainan

Roberto Ierusalimschy

unread,
Jul 29, 2026, 12:14:23 PMJul 29
to 'Sainan' via lua-l
It is funny, casting an int expression to int :-) But if it suppresses
the warning, we can live with that.

As we are here, can you check whether this cast to int supersedes the
previous cast to size_t? In particular:

In lgc.c:
-#define gnodelast(h) gnode(h, cast_sizet(sizenode(h)))
+#define gnodelast(h) gnode(h, sizenode(h))

Many thanks,

-- Roberto

Sainan

unread,
Jul 29, 2026, 2:11:55 PMJul 29
to lu...@googlegroups.com
I'm not sure I entirely understand what you're asking, but that patch for lgc.c does not seem to change the warnings MSVC emits.

-- Sainan

eugeny gladkih

unread,
Jul 29, 2026, 4:06:49 PMJul 29
to lu...@googlegroups.com


> On 29 Jul 2026, at 21:11, 'Sainan' via lua-l <lu...@googlegroups.com> wrote:
>
> I'm not sure I entirely understand what you're asking, but that patch for lgc.c does not seem to change the warnings MSVC emits.
>

guess things

sizeof(int) == 4
sizeof(long int) == 4
sizeof(void*) == 8 // or size_t

--
Yours sincerely, Eugeny.


bil til

unread,
Jul 30, 2026, 12:55:22 AMJul 30
to lu...@googlegroups.com
Am Mi., 29. Juli 2026 um 22:06 Uhr schrieb 'eugeny gladkih' via lua-l
<lu...@googlegroups.com>:
> sizeof(int) == 4
> sizeof(long int) == 4
> sizeof(void*) == 8 // or size_t

This was the typical nasty (and from my point of view quite ingenious)
trick of MSVS-C++, when they introduced 64 bit Windows. They kept the
"int" to be 32 bit.

Like this older 32bit code, which of course is VERY MUCH code :) ,
could be translated very easily to 64bit output... .

(although of course "strictly spoken" int in a 64bit system should be
64bit ... but for calculations in typical software 32bit is completely
sufficient for 99% of computation tasks ... 64bit is then "merely"
necessary to handle the 64bit pointer arithmetic, which in typical C++
code the compiler would organize internally anyway...).

Sainan

unread,
Jul 30, 2026, 2:20:10 AMJul 30
to lu...@googlegroups.com
Ah, I actually didn't know that 'int' was ever not 32-bit. The only quirk I ever ran into was 'char' meaning 'unsigned char' on some ARM compilers.

Maybe there would be some value in using int32_t, uint32_t, int64_t, etc. when C99 is available.

-- Sainan

Francisco Olarte

unread,
Jul 30, 2026, 3:01:04 AMJul 30
to lu...@googlegroups.com
On Thu, 30 Jul 2026 at 08:20, 'Sainan' via lua-l <lu...@googlegroups.com> wrote:
> Ah, I actually didn't know that 'int' was ever not 32-bit. The only quirk I ever ran into was 'char' meaning 'unsigned char' on some ARM compilers.

Int was 16 bit for a lot of architectures. Or, is, int the few still
used. It is supposed to be the natural/faster one.
16<=short<=int<=long and, IIRC, 32<=long.

Changing int to 64 will lead to still more ram bloat ( and cache
usage, and speed loss ), probably kill many ( not too correct ) legacy
code, and some other problems. And anyway, people are used to
sizeof(void*) != sizeof(int) ( my people anyway, comming all the way
from 80[2]86 and its weird memory models ).

Francisco Olarte.

Francisco Olarte

unread,
Jul 30, 2026, 3:06:10 AMJul 30
to lu...@googlegroups.com
On Thu, 30 Jul 2026 at 06:55, bil til <bilt...@gmail.com> wrote:
>
> This was the typical nasty (and from my point of view quite ingenious)
> trick of MSVS-C++, when they introduced 64 bit Windows. They kept the
> "int" to be 32 bit.

IIRC the "natural" and faster int for X86-64 is 32, 64 bits needs a
prefix and is sometimes slower ( think DIV/IDIV ).

So, not a trick. The trick was *ix programmers assuming everywhere
pointer and int round trip (been there, done that, patched it to int
typedefs, std now, compiler specific back then ).


Francisco Olarte.

Sean Conner

unread,
Jul 30, 2026, 4:14:22 AMJul 30
to 'Sainan' via lua-l
It was thus said that the Great 'Sainan' via lua-l once stated:
> Ah, I actually didn't know that 'int' was ever not 32-bit. The only quirk
> I ever ran into was 'char' meaning 'unsigned char' on some ARM compilers.

Technically, whether a bare 'char' is signed or unsigned is implementation
dependent. On Windows, it tends to be unsigned, and on Unix, it tends to be
signed, at least in my experience.

-spc

Sainan

unread,
Jul 30, 2026, 4:19:20 AMJul 30
to lu...@googlegroups.com
Other way around, in my experience.

-- Sainan

Sainan

unread,
Jul 30, 2026, 4:26:19 AMJul 30
to lu...@googlegroups.com
Although I might be misremembering. int8_t and uint8_t are also great. Anyway, way off topic now.

-- Sainan

ppp vvv

unread,
Jul 30, 2026, 5:36:45 AMJul 30
to lua-l
> Maybe there would be some value in using int32_t, uint32_t, int64_t, etc. when C99 is available.

it is a good idea to use proper stdint types even without C99,

and then "backport" it to C89 if needed in luaconf.h

#if defined(LUA_USE_C89)
typedef char int8_t;
typedef unsigned char uint8_t;
typedef short  int16_t;
typedef unsigned short uint16_t;
typedef int int32_t;
typedef unsigned int uint32_t;
typedef long long  int64_t;
typedef unsigned long long uint64_t;

probably with a few more #ifdefs for signed/unsigned chars and 32 bit ints on x64, etc

четверг, 30 июля 2026 г. в 08:20:10 UTC+2, Sainan:

Roberto Ierusalimschy

unread,
Jul 30, 2026, 12:24:31 PMJul 30
to lu...@googlegroups.com
> > Maybe there would be some value in using int32_t, uint32_t, int64_t, etc.
> when C99 is available.
>
> it is a good idea to use proper stdint types even without C99,
>
> and then "backport" it to C89 if needed in luaconf.h

Note that all these types (exact-width integer types) are optional in C99.
We should use int_least32_t, uint_least32_t, int_least64_t, etc.

-- Roberto

Roberto Ierusalimschy

unread,
Jul 30, 2026, 12:32:32 PMJul 30
to 'Sainan' via lua-l
> I'm not sure I entirely understand what you're asking, but that patch for lgc.c does not seem to change the warnings MSVC emits.

The first time this warning appeared (around 2011, I guess), we added
a cast whenever sizenode was used as an array index, as here:

-#define gnodelast(h) gnode(h, sizenode(h))
+#define gnodelast(h) gnode(h, cast_sizet(sizenode(h)))

The rationale was that, as it complained of an implicit conversion, we
made the conversion explicit. As far as I can tell, that change stopped
the warnings at that time.

If adding a cast to int stops the warning, maybe we won't need this
other cast anymore.

-- Roberto

Sainan

unread,
Jul 30, 2026, 12:59:21 PMJul 30
to lu...@googlegroups.com
> If adding a cast to int stops the warning, maybe we won't need this other cast anymore.

Indeed. Removing the cast_sizet does not cause a warning as long as sizenode uses cast_int or cast_uint.

-- Sainan

Sean Conner

unread,
Jul 30, 2026, 3:40:36 PMJul 30
to lu...@googlegroups.com
It was thus said that the Great ppp vvv once stated:
> > Maybe there would be some value in using int32_t, uint32_t, int64_t, etc.
> when C99 is available.
>
> it is a good idea to use proper stdint types even without C99,
>
> and then "backport" it to C89 if needed in luaconf.h
>
> #if defined(LUA_USE_C89)
> typedef char int8_t;

This needs to be

typedef signed char int8_t;

It is implementation defined if a char is signed or unsigned.

> typedef long long int64_t;
> typedef unsigned long long uint64_t;

C89 does not support the 'long long' type.

-spc
Reply all
Reply to author
Forward
0 new messages