Windows integral promotions / uint64_t
Kim Barrett
kim.barrett at oracle.com
Thu Apr 28 16:14:48 UTC 2022
> On Apr 28, 2022, at 8:53 AM, Andrew Haley <aph-open at littlepinkcloud.com> wrote:
>
> I'm seeing this failure from the Windows/AArch64 C++ compiler:
>
> * For target hotspot_variant-server_libjvm_objs_stubGenerator_aarch64.obj:
> stubGenerator_aarch64.cpp
> d:\a\jdk\jdk\jdk\src\hotspot\cpu\aarch64\stubGenerator_aarch64.cpp(6524): error C2668: 'MacroAssembler::sub': ambiguous call to overloaded function
> d:\a\jdk\jdk\jdk\src\hotspot\cpu\aarch64\macroAssembler_aarch64.hpp(1174): note: could be 'void MacroAssembler::sub(Register,Register,Register)'
> d:\a\jdk\jdk\jdk\src\hotspot\cpu\aarch64\macroAssembler_aarch64.hpp(1174): note: or 'void MacroAssembler::sub(Register,Register,uint64_t)'
> d:\a\jdk\jdk\jdk\src\hotspot\cpu\aarch64\stubGenerator_aarch64.cpp(6524): note: while trying to match the argument list '(const Register, const Register, unsigned int)'
> ... (rest of output omitted)
>
> 6524: __ sub(sp, rfp, ((unsigned)framesize-4) << LogBytesPerInt); // prolog
>
>
> Is this a known bug in the compiler? It seems to me as though there is
> an implicit integral promotion from unsigned int to uint64_t, but there is no
> implicit conversion from unsigned int to Register (which is of pointer-
> to const RegisterImpl type). Therefore, according to the ranking of
> implicit conversion sequences rule, this should work.
>
> Or is the problem that, according to the Windows compiler, there is no
> implicit integral promotion from unsigned int to uint64_t? I guess that's
> possible if there is no standard type which corresponds to uint64_t, but
> surely that's unsigned long long. Isn't it?
>
> If this is the case, we could use some template magic to define conversions
> from the standard types to Xint64_t, and include them in the Windows build.
> That would reduce the pain.
I think what may be happening here is that the third argument to sub is a constant expression
whose value is 0, so is ambiguously either an integral 0 or a null pointer. C++14 says
only a literal 0 is supposed to be implicitly convertible to a pointer [1], but C++11 and earlier
allow any constexpr 0 to implicitly convert [2]. And I noticed a while ago that gcc seems to
have retained the old behavior even in C++14 mode (at least sometimes?). Maybe Visual
Studio is doing the same? But then, why aren’t we seeing similar problems with gcc?
[1] C++14 4.10/1 A null pointer constant is an integer literal (2.14.2) with value zero …
[2] C++11 4.10/1 A null pointer constant is an integral constant expression (5.19) prvalue of integer type that evaluates to zero…
A way to deal with this kind of thing is to use templates to inhibit conversions and use SFINAE
to select and forward to type-specific helpers. So something like
template<typename ThirdArgType, ENABLE_IF(std::is_integral<ThirdArgType>::value)>
void sub(Register arg0, Register arg1, ThirdArgType arg2) { sub_integral_third_arg(arg0, arg1, arg2); }
template<typename ThirdArgType, ENABLE_IF(std::is_pointer<ThirdArgType>::value)>
void sub(Register arg0, Register arg1, ThirdArgType arg2) { sub_ponter_third_arg(arg0, arg1, arg2); }
This is obviously pretty ugly, and not something I would really recommend here.
Once again the hacky way Register is defined is biting us.
More information about the hotspot-dev
mailing list