[cfe-commits] libc++ and const expr.

Richard Smith richard at metafoo.co.uk
Sat Feb 4 14:57:16 PST 2012


On Sat, Feb 4, 2012 at 11:49 AM, Howard Hinnant <hhinnant at apple.com> wrote:

> On Feb 4, 2012, at 2:29 PM, Eli Friedman wrote:
> > On Sat, Feb 4, 2012 at 10:50 AM, Howard Hinnant <hhinnant at apple.com>
> wrote:
> >> On Feb 4, 2012, at 1:19 PM, Howard Hinnant wrote:
> >>
> >>> On Feb 4, 2012, at 1:16 PM, Sebastian Redl wrote:
> >>>
> >>>>
> >>>> On 04.02.2012, at 19:06, Howard Hinnant wrote:
> >>>>
> >>>>> On Feb 4, 2012, at 12:52 PM, Howard Hinnant wrote:
> >>>>>
> >>>>>> On Feb 4, 2012, at 12:04 PM, Eli Friedman wrote:
> >>>>>>>
> >>>>>>> [expr.shift]p2: [...] if E1 has a signed type and non-negative
> value,
> >>>>>>> and E1×2E2 is representable in the result type, then that is the
> >>>>>>> resulting value; otherwise, the behavior is undefined.
> >>>>>>>
> >>>>>>> -Eli
> >>>>>>
> >>>>>> I see, you're point is that I've walked into undefined territory
> because I set the sign bit on the long long?  Does changing 1LL to 1ULL
> make the compiler happy?
>

Yes, that should be fine.


> >>>>> Another question:  Is there a motivation for giving the compile time
> behavior of these operations a different behavior than they would have at
> run time?
> >>>>
> >>>> The runtime behavior is undefined. Do you really want the compile
> time behavior to be the same?
> >>>>
> >>>> As a side note, I think the diagnostics here could still be improved.
>

I agree; wording suggestions would be appreciated.


> >>>> Sebastian
> >>>
> >>> It is undefined by the standards committee which has not had the
> willpower to abandon 1's complement hardware.  I believe it is well defined
> behavior on every platform we support (2's complement hardware).  I believe
> this compile time behavior is overly pedantic, does not reveal any
> programming error, and will only serve up busy work for clang's clients.
>

I defer to your insight here, but I'd previously thought that the intention
was to avoid signed integer overflow. If this is an integer representation
issue, it's not clear to me why this isn't implementation-defined (like a
right shift of a negative value is).


> >>>
> >>> Howard
> >>
> >> Just noticed:
> >>
> >> On Feb 3, 2012, at 7:33 PM, Richard Smith wrote:
> >>
> >>> constexpr:
> >>>  The recent support for potential constant expressions exposed a bug
> in the
> >>>  implementation of libstdc++4.6, where numeric_limits<int>::min() is
> defined
> >>>  as (int)1 << 31, which isn't a constant expression. Disable the
> 'constexpr
> >>>  function never produces a constant expression' error inside system
> headers
> >>>  to compensate.
> >>
> >> So it appears already that this is an issue wider than just libc++.
>  And I would be surprised if the issue isn't wide spread.  Just did a quick
> search of Boost and found this:
>

A bug has already been filed against libstdc++, and it appears they intend
to fix it. It's not clear whether g++ will implement this check on left
shifts.


> >>      static BOOST_LLT min BOOST_PREVENT_MACRO_SUBSTITUTION (){ return
> 1LL << (sizeof(BOOST_LLT) * CHAR_BIT - 1); }
> >>
> >> Please reduce this to a pedantic warning and provide a way to turn it
> off locally even then.
>

That is technically a little challenging; this is a note, not an error, and
it's attached to probably over a dozen separate diagnostics. Plus, we'd
need to somehow deal with the cases where an expression contains such a
shift and also another subexpression which renders it non-constant. I'd
much prefer to either keep the check or ditch it entirely -- I think we
need to discuss this at Kona to choose which.


> > The problem is, this affects SFINAE...
>
> You are much more familiar with Chapter 14 than I am.  However in all
> places I'm aware, if the standard says that something is undefined
> behavior, the implementation can do anything it wants.  It can cause
> toilets to explode.  Or it can simply do what it believes its customers
> wanted in the first place.  I believe this is a case where we should do the
> latter.
>

The trouble is that this isn't undefined behavior -- the overflowing left
shift makes the expression non-constant (because the result of multiplying
by 2^N isn't a representable value of the type, or post-DR1313 because the
expression would otherwise have undefined behavior), and if the expression
is not evaluated (for instance, if it's part of a function type in a SFINAE
context) then the program has a well-defined meaning. Let's make this a bit
more concrete:

template<int n> auto f(int (&x)[n]) -> typename std::enable_if<(1 << n) <
kMaxTableSize, int>::type {
  // ...

Here, if the 1<<n calculation overflows, the expression is non-constant and
substitution fails.

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


More information about the cfe-commits mailing list