clang-cl issue with MSVC's safeint.h and cast-to-self prvalue-ness

I came across the following problem with clang-cl (in the context of compiling LibreOffice) when using the MSVC-provided safeint.h (resp. its safeinit_internal.h helper; on my machine located at C:\Program Files (x86)\Windows Kits\10\Include\10.0.10240.0\ucrt\safeint_internal.h):

There is a specialization of some LargeIntRegMultiply::RegMultiply

template < typename E > class LargeIntRegMultiply< signed __int64, signed __int64, E >
    static SafeIntError RegMultiply( const signed __int64& a, const signed __int64& b, signed __int64& ret )
        bool aNegative = false;
        bool bNegative = false;

        unsigned __int64 tmp;
        __int64 a1 = a;
        __int64 b1 = b;


        if( LargeIntRegMultiply< unsigned __int64, unsigned __int64, E >::
            RegMultiply( (unsigned __int64)a1, (unsigned __int64)b1, (unsigned __int64)tmp ) == SafeIntNoError )


that calls another such specialization (namely

template< typename E > class LargeIntRegMultiply< unsigned __int64, unsigned __int64, E >
    static SafeIntError RegMultiply( const unsigned __int64& a, const unsigned __int64& b, unsigned __int64& ret )


for unsigned) which takes its third argument by non-const lvalue-reference. But what gets passed at the call site above,

                                                                     (unsigned __int64)tmp

is the result of needlessly casting tmp (which is already of type unsigned __int64), which shall produce a prvalue, which in turn cannot bind to a non-const lvalue-reference. So compiling that with clang-cl fails.

But with MSVC (at least 2013--2017) it succeeds. That compiler apparently has a bug or mis-feature so that the result of casting an lvalue to its own type produces an lvalue instead of a prvalue. (As verified, at least for C-style cast and static_cast, and at least if the type is some integral type).

Do we have some contact into the MSVC compiler group, so we can clarify whether that behavior is considered a mis-feature (so we would want to mimic it in some way in clang-cl, at least when compiling the MSVC-provided safeint.h) or a bug (so MSVC would want to fix their safeint.h, and we probably wouldn't want to duplicate that misbehavior in clang-cl)?

(I would assume it is a genuine bug, which that sloppy safeint_internal.h just happens to rely on by accident, as it makes the below program behave in an IMO non-conforming way by printing 1 instead of 0:

#include <iostream>
namespace {
    int n = 0;
    void f() { n = 1; }
    int g(int const & n) { f(); return n; }
int main() {
    std::cout << g(static_cast<int>(n)) << '\n';

But who knows.)

This bug appears to be fixed in the Win 10.0.10586.0 SDK:

if( LargeIntRegMultiply< unsigned __int64, unsigned __int64, E >::
RegMultiply( (unsigned __int64)a1, (unsigned __int64)b1, tmp ) == SafeIntNoError )

From the blog posts I see about safeint, it sounds like it’s supposed to be a portable to many platforms and compilers, so I think we can rely on Microsoft to keep fixing bugs in this header.

Is there a reason LibreOffice uses the 10240 SDK?

Ah, great. Thank you for checking with a later SDK.

There's probably no deeper reason why LibreOffice ended up using that specific SDK version for me. (The code we use to configure paths for the various MSVC stuff is a bit "magic", and maybe that version was all that happened to be available on the machine I tested with. I'll have a look.)