C++ Logo

sg7

Advanced search

Re: [SG7] Disambiguating constexpr overflow behaviour

From: Jens Maurer <Jens.Maurer_at_[hidden]>
Date: Mon, 16 Dec 2019 22:56:40 +0100
On 16/12/2019 18.32, philippe dunski via SG7 wrote:
> Hello,
>
> It seems there is some confusion between overflow in a constexpr and overflow in a runtime behaviour.
I don't think so.

Note that in the below example, there are actually three cases:

 - Values with types smaller than "int" are promoted to "int", the arithmetic
is performed successfully, and then converting the result to the type of
the non-type template parameter fails. No overflow/underflow occurs for the
arithmetic.

 - Values with signed types at least as large as "int" are not
promoted and yield an error for the overflowing/underflowing arithmetic.

 - Values with unsigned types at least as large as "int" are not
promoted and compilation succeeds due to the wrapping behavior (mod 2^n)
of unsigned arithmetic.

It would certainly be surprising if integral promotions would not
apply to constant expressions. (This would also cause an incompatibility
with C.)

Jens



> Let me explain:
>
> main.cpp tries to define a constexpr with (MIN - 1) and (MAX + 1) for each of
> - std::int8_t
> - std::int16_t
> - std::int32_t
> - std::int64_t
> - std::uint8_t
> - std::uint16_t
> - std::uint32_t
> - std::uint64_t
>
> IMO, when specifically speaking about constexpr overflow should, simply, produce a compile time error, because developer specifically ask to the compiler to hold a value which doesn't fits in the providen type.
>
> As you can see in error_clang.txt file, clang 9.0.0 only recognize 12 case on 16 as compile time error.
>
> Depending of its version Gcc's behaviour is more "erratic" and justify the error in at least two ways (sometime because of overflow, sometimes because, when microsoft's compiler only produces some warning, but agrees to compile this code
>
> But they are some rules about promotion <https://en.cppreference.com/w/cpp/language/implicit_conversion#Integral_promotion>that contradict such behaviour.
>
> I'm in peace with those rules, as far as they apply at runtime. But, at compile time, and more specifically when dealing with constexpr they are, IMO, just irrelevant, because compiler should not be able to say "wel, I know that you asked a (u)intX_t value, but I give you a (u)int2X_t one, because of the overflow".
>
> In the same time, we have the overflow rules which says that (UINT_MAX + 1) and (UINT_IN -1) are equal to 0.
>
> Once again, I'm in peace with that ... in a runtime context.
>
> But, once again, in a constexpr context, those rule is IMO irrelevant.
>
> Maybe should you disambiguating such behaviour by explicitly saying that constexpr should be constrainted to the range allowed by them type. In other words that
> static constexpr (u)intX_t min = std::numeric_limits<(u)intX_t>::min() -1; and
> static constexpr (u)intX_t max = std::numeric_limits<(u)intX_t>::max() +1; should always produce a compile time error, even if
> static constepxr (u)int2X_t = std::numeric_limits<(u)intX_t>::min() -1; is always a correct conversion / promotion, holding a correct value.
>
> I will not try to express such thing in the standard, but maybe some of you could do it?
>
> PS: forgive my poor english, but my mother tongue is French
>

Received on 2019-12-16 15:59:10