[MSVC++] [C4146]: unary minus operator applied to unsigned type, result still unsigned

Issue #311 resolved
Matthias Moulin created an issue

When using template methods (e.g., blaze::submatrix) using size_t(-SIMDSIZE) (with SIMDSIZE an unsigned integral type), the Microsoft Visual C++ compiler (/std::c++latest /permissive-) reports a C4146, which is a level W2 warning, and fails compilation.

unsigned int i(-1);
unsigned int j(-2);
unsigned int k(-(1u)); // C4146 
unsigned int l(-(2u)); // C4146

A simple workaround consist of changing size_t(-SIMDSIZE) to size_t(0-SIMDSIZE).

Comments (11)

  1. Klaus Iglberger

    Hi Matthias!

    Thanks for creating this issue. We are aware of the problem, but consider this an issue of the MSVC compiler. According to the C++ standard (see [basic.fundamental], note 2), “The range of representable values for the unsigned type is 0 to 2N − 1 (inclusive); arithmetic for the unsigned type is performed modulo 2N . [Note: Unsigned arithmetic does not overflow. Overflow for signed arithmetic yields undefined behavior (7.1). —end note]“. This means that the expression size_t(-SIMDSIZE) is well defined according to the C++ standard. Also, the description and example in C4146 is clearly about a different problem that involved signed integral literals and thus does not fit the expression used in Blaze.

    Still, we’ll try to circumvent the problem by coming up with a working expression for MSVC. Until we come up with a solution, please explicitly disable the warning for Blaze by means of \wd4146. Thanks again,

    Best regards,

    Klaus!

  2. Klaus Iglberger

    Hi Matthias!

    Could you please share a link to the issue for the MSVC compiler team? Thanks a lot,

    Best regards,

    Klaus!

  3. Klaus Iglberger

    Hi Matthias!

    Thanks for creating the issue at the Microsoft developer community. I analysed the problem and compared compiler behavior by means of Compiler Explorer:

    int main()
    {
       size_t i;
       std::cin >> i;  // Runtime value
    
       constexpr size_t N( 4UL );  // Compile time value
    
       //const size_t res = i - ( i % N );  // (1)
       const size_t res = i & (-N);   // (2)
    
       std::cout << res;
    }
    

    Both GCC and Clang treat lines (1) and (2) equally and resolve it to a single and statement with -4. MSVC does the same for line (2) (without warning), but compiles line (1) into an and statement with 3, followed by a subtraction. Based on the standard specification, this may be a missed optimization opportunity.

    Best regards,

    Klaus!

  4. Matthias Moulin reporter

    I noticed that the /sdl compiler flag is the actual culprit treating that specific warning as an error. No idea what the underlying motivation is to do so.

  5. Klaus Iglberger

    Commit 3f637a3 resolves all MSVC C4146 warnings. The fix is immediately available via cloning the Blaze repository and will be officially released in Blaze 3.7.

  6. Log in to comment