From: Richard Smith Date: Mon, 14 May 2012 21:57:21 +0000 (+0000) Subject: Implement IRGen for C++11's "T{1, 2, 3}", where T is an aggregate and the X-Git-Url: https://granicus.if.org/sourcecode?a=commitdiff_plain;h=13ec9100ca6bc03b5ce8832e4a0fcb724d47bcb1;p=clang Implement IRGen for C++11's "T{1, 2, 3}", where T is an aggregate and the expression is treated as an lvalue. git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@156781 91177308-0d34-0410-b5e6-96231b3b80d8 --- diff --git a/lib/CodeGen/CGExpr.cpp b/lib/CodeGen/CGExpr.cpp index 979454bdc8..d4e4c402b7 100644 --- a/lib/CodeGen/CGExpr.cpp +++ b/lib/CodeGen/CGExpr.cpp @@ -671,10 +671,7 @@ LValue CodeGenFunction::EmitLValue(const Expr *E) { case Expr::PseudoObjectExprClass: return EmitPseudoObjectLValue(cast(E)); case Expr::InitListExprClass: - assert(cast(E)->getNumInits() == 1 && - "Only single-element init list can be lvalue."); - return EmitLValue(cast(E)->getInit(0)); - + return EmitInitListLValue(cast(E)); case Expr::CXXTemporaryObjectExprClass: case Expr::CXXConstructExprClass: return EmitCXXConstructLValue(cast(E)); @@ -2129,6 +2126,16 @@ LValue CodeGenFunction::EmitCompoundLiteralLValue(const CompoundLiteralExpr *E){ return Result; } +LValue CodeGenFunction::EmitInitListLValue(const InitListExpr *E) { + if (!E->isGLValue()) + // Initializing an aggregate temporary in C++11: T{...}. + return EmitAggExprToLValue(E); + + // An lvalue initializer list must be initializing a reference. + assert(E->getNumInits() == 1 && "reference init with multiple values"); + return EmitLValue(E->getInit(0)); +} + LValue CodeGenFunction:: EmitConditionalOperatorLValue(const AbstractConditionalOperator *expr) { if (!expr->isGLValue()) { @@ -2188,11 +2195,11 @@ EmitConditionalOperatorLValue(const AbstractConditionalOperator *expr) { return MakeAddrLValue(phi, expr->getType()); } -/// EmitCastLValue - Casts are never lvalues unless that cast is a dynamic_cast. -/// If the cast is a dynamic_cast, we can have the usual lvalue result, +/// EmitCastLValue - Casts are never lvalues unless that cast is to a reference +/// type. If the cast is to a reference, we can have the usual lvalue result, /// otherwise if a cast is needed by the code generator in an lvalue context, /// then it must mean that we need the address of an aggregate in order to -/// access one of its fields. This can happen for all the reasons that casts +/// access one of its members. This can happen for all the reasons that casts /// are permitted with aggregate result, including noop aggregate casts, and /// cast from scalar to union. LValue CodeGenFunction::EmitCastLValue(const CastExpr *E) { diff --git a/lib/CodeGen/CodeGenFunction.h b/lib/CodeGen/CodeGenFunction.h index 8d48a0b24e..91022de59e 100644 --- a/lib/CodeGen/CodeGenFunction.h +++ b/lib/CodeGen/CodeGenFunction.h @@ -2104,6 +2104,7 @@ public: LValue EmitMemberExpr(const MemberExpr *E); LValue EmitObjCIsaExpr(const ObjCIsaExpr *E); LValue EmitCompoundLiteralLValue(const CompoundLiteralExpr *E); + LValue EmitInitListLValue(const InitListExpr *E); LValue EmitConditionalOperatorLValue(const AbstractConditionalOperator *E); LValue EmitCastLValue(const CastExpr *E); LValue EmitNullInitializationLValue(const CXXScalarValueInitExpr *E); diff --git a/test/CodeGenCXX/cxx0x-initializer-references.cpp b/test/CodeGenCXX/cxx0x-initializer-references.cpp index 4c847b8e58..660b018460 100644 --- a/test/CodeGenCXX/cxx0x-initializer-references.cpp +++ b/test/CodeGenCXX/cxx0x-initializer-references.cpp @@ -28,6 +28,10 @@ namespace reference { // CHECK-NEXT: store %{{.*}}* %{{.*}}, %{{.*}}** % A &ra1a = {a}; + using T = A&; + // CHECK-NEXT: store %{{.*}}* %{{.*}}, %{{.*}}** % + A &ra1b = T{a}; + // CHECK-NEXT: ret } diff --git a/test/CodeGenCXX/cxx11-initializer-aggregate.cpp b/test/CodeGenCXX/cxx11-initializer-aggregate.cpp new file mode 100644 index 0000000000..f96638184e --- /dev/null +++ b/test/CodeGenCXX/cxx11-initializer-aggregate.cpp @@ -0,0 +1,25 @@ +// RUN: %clang_cc1 -std=c++11 -S -emit-llvm -o - %s -triple x86_64-linux-gnu | FileCheck %s + +struct A { int a, b; int f(); }; + +// CHECK: define {{.*}}@_Z3fn1i( +int fn1(int x) { + // CHECK: %[[INITLIST:.*]] = alloca %struct.A + // CHECK: %[[A:.*]] = getelementptr inbounds %struct.A* %[[INITLIST]], i32 0, i32 0 + // CHECK: store i32 %{{.*}}, i32* %[[A]], align 4 + // CHECK: %[[B:.*]] = getelementptr inbounds %struct.A* %[[INITLIST]], i32 0, i32 1 + // CHECK: store i32 5, i32* %[[B]], align 4 + // CHECK: call i32 @_ZN1A1fEv(%struct.A* %[[INITLIST]]) + return A{x, 5}.f(); +} + +struct B { int &r; int &f() { return r; } }; + +// CHECK: define {{.*}}@_Z3fn2Ri( +int &fn2(int &v) { + // CHECK: %[[INITLIST2:.*]] = alloca %struct.B, align 8 + // CHECK: %[[R:.*]] = getelementptr inbounds %struct.B* %[[INITLIST2:.*]], i32 0, i32 0 + // CHECK: store i32* %{{.*}}, i32** %[[R]], align 8 + // CHECK: %call = call i32* @_ZN1B1fEv(%struct.B* %[[INITLIST2:.*]]) + return B{v}.f(); +}