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

Richard Smith richard at metafoo.co.uk
Thu Feb 2 14:27:40 PST 2012


On Thu, Feb 2, 2012 at 10:40 AM, Matthieu Monrocq <
matthieu.monrocq at gmail.com> wrote:

> Le 1 février 2012 23:34, Richard Smith <richard at metafoo.co.uk> a écrit :
>
>> On Wed, Feb 1, 2012 at 12:14 PM, Matthieu Monrocq <
>> matthieu.monrocq at gmail.com> wrote:
>>
>>> 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.
>>>
>>
>> If I understand you correctly, you seem to be assuming that we can just
>> decide for ourselves what is and is not a constant expression? We cannot;
>> this is specified (though, in this case, not clearly) by the language
>> semantics, and a non-conforming implementation (whether it treats too many,
>> or too few, expressions as constant expressions) will reject valid code,
>> accept invalid code, and give the wrong semantics to some code.
>>
>> - Richard
>>
>
> Not at all :) I hope Clang keeps aiming at maximum standard conformance.
>
> I was reacting to this (from you):
>
>
> > 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.
>
> I disagreed here on what is the range of representable values of an
> enumeration type and gave the formula to compute it: it is slightly broader
> than [Min...Max].
>

That's right. The "values of the enumeration" is a term of art, defined in
the standard in [dcl.enum]p7 to what you are describing [ apart from an
off-by-one error in your description for negative enumerators ;-) ]. It is
not simply the range of values of the enumerators. Sorry for not making
that clear :)

> 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.
>
> Which here will affect which values are out-of-range and thus
> non-constant, I think.
>

Yes, absolutely. As in my original example:

   enum E { n = 2 };
   E e = (E)5;

Here, I think that (E)5 is not a constant expression, but (E)3 is. Possibly
we're in violent agreement about that?

- Richard
-------------- next part --------------
An HTML attachment was scrubbed...
URL: <http://lists.llvm.org/pipermail/cfe-commits/attachments/20120202/94974b91/attachment.html>


More information about the cfe-commits mailing list