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

Stephan Bergmann via cfe-dev cfe-dev at lists.llvm.org
Fri Apr 7 00:42:55 PDT 2017


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 >
> {
> public:
>     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 >
> {
> public:
>     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.)



More information about the cfe-dev mailing list