[cfe-dev] constexpr difference between gcc and clang

Eli Friedman eli.friedman at gmail.com
Mon Aug 6 22:59:45 PDT 2012


On Mon, Aug 6, 2012 at 10:44 PM, Richard Smith <richard at metafoo.co.uk> wrote:
> Hi David,
>
>> On Mon, Aug 6, 2012 at 6:54 PM, David Wood <dswood at gmail.com> wrote:
>> > The following compiles fine in macports gcc 4.7, but does not in clang
>> > svn
>> > 161307.  I believe the key is the const reference in combination with
>> > the ?:
>> > operator.
>> >
>> > #include <stdexcept>
>> >
>> > struct A {
>> >   constexpr A(int a) : value(a) {}
>> >
>> >   constexpr int get() { return value; }
>> >
>> > private:
>> >   int value;
>> > };
>> >
>> > constexpr A someFn(const A& a) {
>> >   return a.get() == 0 ? throw std::exception() : a;
>> > }
>> >
>> > int main(int argc, char** argv) {
>> >   constexpr A a(4);
>> >   static_assert( someFn(a).get() == 4, "error" );
>> > }
>> >
>> > Some digging on the internets reveals
>> >
>> > http://stackoverflow.com/questions/5605142/stdmax-and-stdmin-not-constexpr,
>> > which seems to point to lvalues, glvalues and memory allocation,
>> > although I
>> > did not follow it very well.  There is also the particularly interesting
>> > comment :
>> >
>> > The C++ committee have suggested that it was intended to be possible for
>> > function invocation substitution to produce an lvalue referring to a
>> > temporary. g++ behaves that way, but clang currently implements the
>> > standard
>> > as written.
>
>
> That comment is out of date. At the most recent C++ standards committee
> meeting, we decided to allow such cases, and Clang now supports them.
>
>>
>> > So, I have two questions.  1) Is the way clang handles this in fact
>> > conformant to the spec, and gcc is lax?
>
>
> This code is well-formed, we're incorrect to reject it. Please file a bug at
> llvm.org/bugs.
>
> We are rejecting it because we have produced a broken AST:
>
> (CompoundStmt 0x4024650 <<stdin>:10:32, line:12:1>
>   (ReturnStmt 0x4024630 <line:11:3, col:35>
>     (CXXConstructExpr 0x40245f8 <col:10, col:35> 'struct A''void (const
> struct A &) noexcept' elidable
>       (MaterializeTemporaryExpr 0x40244d0 <col:10, col:35> 'const struct A'
> lvalue
>         (ConditionalOperator 0x4024128 <col:10, col:35> 'const struct A'
>           (BinaryOperator 0x4024098 <col:10, col:21> '_Bool' '=='
>             (CXXMemberCallExpr 0x4024050 <col:10, col:16> 'int'
>               (MemberExpr 0x4024020 <col:10, col:12> '<bound member function
> type>' .get 0x4023af0
>                 (DeclRefExpr 0x4023ff8 <col:10> 'const struct A' lvalue
> ParmVar 0x4023e90 'a' 'const struct A &')))
>             (IntegerLiteral 0x4024078 <col:21> 'int' 0))
>           (CXXThrowExpr 0x40240e0 <col:25, col:31> 'void'
>             (IntegerLiteral 0x40240c0 <col:31> 'int' 0))
>           (DeclRefExpr 0x4024100 <col:35> 'const struct A' lvalue ParmVar
> 0x4023e90 'a' 'const struct A &'))))))
>
> Note that the ConditionalOperator is an rvalue, but its third operand is an
> lvalue, with no intervening CXXConstructExpr. That's wrong -- we're supposed
> to perform an lvalue-to-rvalue conversion on this operand (see
> [expr.cond]p2).

Err, oops, you're right; I somehow misread the testcase.

-Eli



More information about the cfe-dev mailing list