[cfe-commits] r149286 - in /cfe/trunk: lib/AST/ExprConstant.cpp lib/Sema/SemaOverload.cpp test/CXX/expr/expr.const/p2-0x.cpp

Matthieu Monrocq matthieu.monrocq at gmail.com
Wed Feb 1 12:14:18 PST 2012


Le 31 janvier 2012 22:57, Richard Smith <richard at metafoo.co.uk> a écrit :

> On Tue, Jan 31, 2012 at 12:40 AM, Abramo Bagnara <abramo.bagnara at gmail.com
> > wrote:
>
>> Il 31/01/2012 03:22, Eli Friedman ha scritto:
>> > On Mon, Jan 30, 2012 at 6:01 PM, Richard Smith <richard at metafoo.co.uk>
>> wrote:
>> >> On Mon, Jan 30, 2012 at 4:29 PM, Eli Friedman <eli.friedman at gmail.com>
>> >> wrote:
>> >>>
>> >>> On Mon, Jan 30, 2012 at 2:27 PM, Richard Smith
>> >>> <richard-llvm at metafoo.co.uk> wrote:
>> >>>> Author: rsmith
>> >>>> Date: Mon Jan 30 16:27:01 2012
>> >>>> New Revision: 149286
>> >>>>
>> >>>> URL: http://llvm.org/viewvc/llvm-project?rev=149286&view=rev
>> >>>> Log:
>> >>>> constexpr: disallow signed integer overflow in integral conversions
>> in
>> >>>> constant
>> >>>> expressions in C++11.
>> >>>
>> >>> Standard citation?  As far as I can tell, the result of
>> >>> (int)0x80000000u is implementation-defined, but it's still a constant
>> >>> expression given how we define it.
>> >>
>> >>
>> >> Oops, r149327. This was (incorrectly) factored out of another change
>> which
>> >> I'm still questioning... Consider:
>> >>
>> >>   enum E { n = 2 };
>> >>   E e = (E)5;
>> >>
>> >> 5 is not in the range of values of the enumeration (which is 0..3 by
>> >> [dcl.enum]p7), but is clearly in the underlying type. Is this value in
>> the
>> >> range of representable values for its type (or is this undefined
>> behavior by
>> >> [expr]p4)?
>> >
>> > I think the relevant passage is actually [expr.static.cast]p10:
>> >
>> > A value of integral or enumeration type can be explicitly converted to
>> > an enumeration type. The value is unchanged if the original value is
>> > within the range of the enumeration values (7.2). Otherwise, the
>> > resulting value is unspecified (and might not be in that range).
>> >
>> >
>> > That doesn't sound like undefined behavior to me.
>>
>> Yes, you're definitely right from a standard point of view, but using
>> the point of view of constant evaluator, does it make a difference?
>>
>> I.e., the conversion of an integer out of enum range specified by
>> [decl.enum]p7 to that enum type should be a known constant?
>>
>> I don't think so, but I'd like to hear your opinion.
>
>
> In C++11, all conditional-expressions are core constant expressions,
> except those explicitly blacklisted in [expr.const]p2. The only relevant
> exemption there is "a result that is not mathematically defined or not in
> the range of representable values for its type;" (which DR1313 generalizes
> to "an operation that would have undefined behavior").
>
> The standard does not make obvious what it means by "the range of
> representable values" for an enumeration type. Is it the range of values of
> the enumeration, or is it the range of representable values of the
> underlying type, or something else? And, when casting an out-of-range value
> to an enumeration, can the resulting unspecified value be out of the range
> of representable values for the type?
>
> To address the first question, [class.bit]p4 says:
>
> "If the value of an enumerator is stored into a bit-field of the same
> enumeration type and the number of bits in the bit-field is large enough to
> hold all the values of that enumeration type (7.2), the original enumerator
> value and the value of the bit-field shall compare equal."
>
> From this, and the behavior of integral promotions on enumerations, I
> believe we can conclude that the range of representable values of an
> enumeration type is the range of values of the enumeration.
>
> Eli's quotation states that casting an out-of-range value to an
> enumeration produces a value which need not be in the range of values of
> the enumeration. Therefore, if the unspecified value is not in that range
> (which by [expr.static.cast]p10 it might not be), then behavior is
> undefined, and the result of the cast is not a constant expression.
>
> That said, such deductive reasoning applied to the (sadly, often imprecise
> and inconsistent) standard wording has led me to unintended conclusions
> several times before, so I'm still not certain whether such cases should be
> constant expressions.
>
> - Richard
>
>
> As far as the interpretation of "If the value of an enumerator is stored
into a bit-field of the same enumeration type and the number of bits in the
bit-field is large enough to hold all the values of that enumeration type
(7.2), the original enumerator value and the value of the bit-field shall
compare equal." I always understood:

Given Min the smallest enumerator value and Max the biggest enumerator
value of the enumeration:

- if Min is negative and Max positive, then we deduce M = max(abs(Min),
abs(Max)) and the bitfield should be *just* enough to represent all values
in [0, M] + a bit sign.
- if both Min and Max are negative, then the bitfield should be *just*
enough to represent all values in [0, -Min] + a bit sign.
- if both Min and Max are positive, then the bitfield should be *just*
enough to represent all values in [0, Max] (no bit sign).

So, you are looking for K such that 2^(K-1) <= max(abs(Min), abs(Max)) <
2^K and all values in [0, 2^K-1] are representable, as well as those in
[-2^K, 0] if any enumerator was negative.


Summary:
* Min = min { enumerators }
* Max = max { enumerators }
* K positive such that 2^(K-1) <= max(abs(Min), abs(Max)) < 2^K

If Min < 0, then the representable range is [-2^K, 2^K-1], else it is [0,
2^K-1].

Any value outside this range cannot reliably represented, and it is
unspecified what happens if one tries to assign such a value. The
underlying type does not come into play, in the standard.


Now, as a compiler implementation, I think that Clang can make the
additional guarantee (*) that as long as it fits into the underlying type,
it's okay (it's probably what gcc does, so consistency is good) and that
otherwise it just "wraps around" (not sure if it should for a signed
underlying type...), this is the freedom that "unspecified behavior" gives
us.

And if my reasoning is not totally skewed, then it means this *can* be
treated as a constant expression.


(*) Even though we can guarantee it, I guess a warning that this is
formally unspecified should be emitted.


Note: As far as I understand, the rule about the representable range was
originally developped to allow flag composition:

  enum Flag { CaseInsensitive = 1 << 1, Fuzzy = 1 << 2 };

  compare(left, right, CaseInsensitive | Fuzzy);

And if we take the "spirit" behind the rule, then all the savant definition
of the representable range just make sense.

-- Matthieu
-------------- next part --------------
An HTML attachment was scrubbed...
URL: <http://lists.llvm.org/pipermail/cfe-commits/attachments/20120201/40c6d37f/attachment.html>


More information about the cfe-commits mailing list