Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Integral constant overflow in MSVC #68

Open
uecasm opened this issue Feb 13, 2019 · 8 comments
Open

Integral constant overflow in MSVC #68

uecasm opened this issue Feb 13, 2019 · 8 comments

Comments

@uecasm
Copy link

uecasm commented Feb 13, 2019

constexpr auto data = frozen::make_unordered_set<unsigned>({ 5u, 6u });

On MSVC 15.8.5, this reports

warning C4307: '+': integral constant overflow

Which then causes compilation to fail if using warnings as errors. This also occurs with unordered_map, but not with set or map. Oddly the warning goes away if constexpr is removed.

Is this warning benign or worrisome? Can it be fixed inside frozen somewhere? (Unfortunately it doesn't indicate which particular use of + causes the overflow -- it just reports on that line above, not on something inside frozen.)

@uecasm
Copy link
Author

uecasm commented Feb 13, 2019

It looks like changing the definition of elsa to this fixes it for 32-bit MSVC. I assume that it would be more complicated for 64-bit, since it would have to do a 128-bit add. Unfortunately there doesn't appear to be any way to suppress the warning inside elsa itself, if it's called in a constexpr context, since the warning is raised at the point of use, not at its own code.

#if defined(_MSC_VER) && !defined(_WIN64)
  constexpr std::size_t operator()(T const &value, std::size_t seed) const {
      std::size_t key = seed ^ static_cast<std::size_t>(value);
      key = static_cast<std::size_t>(static_cast<uint64_t>(~key) + (key << 21));
      key = key ^ (key >> 24);
      key = static_cast<std::size_t>(static_cast<uint64_t>(key) + (key << 3) + (key << 8));
      key = key ^ (key >> 14);
      key = static_cast<std::size_t>(static_cast<uint64_t>(key) + (key << 2) + (key << 4));
      key = key ^ (key >> 28);
      key = static_cast<std::size_t>(static_cast<uint64_t>(key) + (key << 31));
      return key;
  }
#else
  constexpr std::size_t operator()(T const &value, std::size_t seed) const {
    std::size_t key = seed ^ static_cast<std::size_t>(value);
    key = (~key) + (key << 21); // key = (key << 21) - key - 1;
    key = key ^ (key >> 24);
    key = (key + (key << 3)) + (key << 8); // key * 265
    key = key ^ (key >> 14);
    key = (key + (key << 2)) + (key << 4); // key * 21
    key = key ^ (key >> 28);
    key = key + (key << 31);
    return key;
  }
#endif

@serge-sans-paille
Copy link
Owner

I'd say overflow on a plus on unsigned type is not an issue because it's perfectly defined (unlike the signed version). What could be done instead of your cast is to apply a mask, as in (~key + (key << 21)) & ~std::size_t(0), does that silent the warning? or maybe static_caststd::size_t(~key + (key << 21)` ? If either of these work, feel free to open a PR!

@uecasm
Copy link
Author

uecasm commented Feb 17, 2019

No, those don't help; but I wouldn't really expect them to, since the warning is raised for the + operator itself, not the assignment back into key.

@degski
Copy link

degski commented Feb 22, 2019

@serge-sans-paille clang-cl doesn't warn on this. Maybe just suppress the warning?

@uecasm
Copy link
Author

uecasm commented Feb 22, 2019

Sadly the warning is raised at point of constexpr variable use, not anywhere inside elsa itself, as I mentioned above. This makes it impossible to suppress the warning inside the library, except by changing the operand types of + as proposed above so that overflow can't occur.

I did file a bug with MS about the warning behaviour, so we can just sit on it and see if anything comes of that.

@serge-sans-paille
Copy link
Owner

serge-sans-paille commented Feb 25, 2019 via email

@degski
Copy link

degski commented Feb 26, 2019

@serge-sans-paille Yes, something like this, there are various options, more or less portable.

@uecasm
Copy link
Author

uecasm commented Feb 28, 2019

@degski So, how many different ways do you want me to tell you that pragma suppressions don't work? Because this is the third time I've said that.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

3 participants