Quuxplusone / LLVMBugzillaTest

0 stars 0 forks source link

Address of compound literal fails in gnu++0x but not C99 #10416

Open Quuxplusone opened 13 years ago

Quuxplusone commented 13 years ago
Bugzilla Link PR10107
Status REOPENED
Importance P normal
Reported by Allan Odgaard (691D2C6C-B023-46A5-B1D7-ACCBA4713A87@uuid-mail.com)
Reported on 2011-06-09 02:42:15 -0700
Last modified on 2012-01-12 15:56:30 -0800
Version 2.9
Hardware Macintosh MacOS X
CC dgregor@apple.com, efriedma@quicinc.com, llvm-bugs@lists.llvm.org, richard-llvm@metafoo.co.uk, scshunt@csclub.uwaterloo.ca, zaffanella@cs.unipr.it
Fixed by commit(s)
Attachments
Blocks
Blocked by
See also
The code below is C99 and supported by GCC in C++ mode since they allow
C99 features.

Clang accepts the code in C99 mode, it (correctly) says that compound
literals are a C99-specific feature in C++ mode, but with -std=gnu++0x
(which should support GCC extensions, i.e. C99) I get the following
error:

    error: taking the address of a temporary object of type 'struct
point' [-Waddress-of-temporary]

----------8<----------

struct point { int x; int y; };
void draw_point (struct point const* aPoint) { }

int main (int argc, char const* argv[])
{
    draw_point(&(struct point){ 1, 2 });
    return 0;
}
Quuxplusone commented 13 years ago

GCC warns here but accepts the code.

Quuxplusone commented 13 years ago
Clang errors in all C++ modes, since this is an extension that is extremely
unsafe. You can downgrade the error to a warning with the

  -Wno-error=address-of-temporary

command-line option or turn it off entirely with

  -Wno-address-of-temporary
Quuxplusone commented 12 years ago
As of r147790, clang still crashes on the following line of code, if -W[no-
]address-of-temporary is used:

$ cat bug.cc
int (*pa)[1] = &(int[]) { 1 };

$ clang++ -c bug.cc
bug.cc:1:16: error: taking the address of a temporary object of type
'int [1]'
      [-Waddress-of-temporary]
int (*pa)[1] = &(int[]) { 1 };
               ^~~~~~~~~~~~~~
1 error generated.

$ clang++ -Waddress-of-temporary -c bug.cc
bug.cc:1:16: warning: taking the address of a temporary object of type
'int [1]'
      [-Waddress-of-temporary]
int (*pa)[1] = &(int[]) { 1 };
               ^~~~~~~~~~~~~~
clang: <path>/tools/clang/lib/AST/ExprConstant.cpp:2479: bool
EvaluateLValue(const clang::Expr*, <unnamed>::LValue&,
<unnamed>::EvalInfo&): Assertion `(E->isGLValue() ||
E->getType()->isFunctionType() || E->getType()->isVoidType() ||
isa<CXXTemporaryObjectExpr>(E)) && "can't evaluate expression as an
lvalue"' failed.
[...]
Quuxplusone commented 12 years ago
We're building an AST that looks like this:

      (UnaryOperator 0x56cd290 <col:40, col:46> 'struct S *' prefix '&'
        (CompoundLiteralExpr 0x56ccfd0 <col:41, col:46> 'struct S'
          (InitListExpr 0x56ccf80 <col:44, col:46> 'struct S'

This doesn't seem right to me. I would expect that either the compound literal
expression should be an lvalue, or we should be materializing a temporary for
it. Is this really how we want to represent this construct in C++?

For reference, on the following example:

  struct S { int n; };
  int f() {
    struct S *p = &(struct S){1};
    return p->n;
  }

g++ compiles this to 'return 1' in -x c, and to 'return 0' in -x c++ -
fpermissive, which strongly suggests that in gnu++ mode we should be
materializing a temporary to match g++'s semantics.