From cdb466e58fa7d766cf0402b5b52638acf581e545 Mon Sep 17 00:00:00 2001 From: Douglas Gregor Date: Thu, 15 Jul 2010 18:58:16 +0000 Subject: [PATCH] Reinstate the scalar-cast-to-const-reference improvements, this time with the proper spelling of "non-class prvalue". Silly me, I think class rvalues were xvalues rather than prvalues! Hah hah hah. llvm-svn: 108443 --- clang/lib/CodeGen/CGExpr.cpp | 55 ++++++-- clang/test/CodeGenCXX/reference-cast.cpp | 170 +++++++++++++++++++++++ 2 files changed, 213 insertions(+), 12 deletions(-) create mode 100644 clang/test/CodeGenCXX/reference-cast.cpp diff --git a/clang/lib/CodeGen/CGExpr.cpp b/clang/lib/CodeGen/CGExpr.cpp index 43bab9fece6e..fa5ac8fb14f9 100644 --- a/clang/lib/CodeGen/CGExpr.cpp +++ b/clang/lib/CodeGen/CGExpr.cpp @@ -1749,8 +1749,48 @@ CodeGenFunction::EmitConditionalOperatorLValue(const ConditionalOperator* E) { /// cast from scalar to union. LValue CodeGenFunction::EmitCastLValue(const CastExpr *E) { switch (E->getCastKind()) { - default: + case CastExpr::CK_ToVoid: return EmitUnsupportedLValue(E, "unexpected cast lvalue"); + + case CastExpr::CK_NoOp: + if (E->getSubExpr()->Classify(getContext()).getKind() + != Expr::Classification::CL_PRValue) { + LValue LV = EmitLValue(E->getSubExpr()); + if (LV.isPropertyRef()) { + QualType QT = E->getSubExpr()->getType(); + RValue RV = EmitLoadOfPropertyRefLValue(LV, QT); + assert(!RV.isScalar() && "EmitCastLValue-scalar cast of property ref"); + llvm::Value *V = RV.getAggregateAddr(); + return LValue::MakeAddr(V, MakeQualifiers(QT)); + } + return LV; + } + // Fall through to synthesize a temporary. + + case CastExpr::CK_Unknown: + case CastExpr::CK_BitCast: + case CastExpr::CK_ArrayToPointerDecay: + case CastExpr::CK_FunctionToPointerDecay: + case CastExpr::CK_NullToMemberPointer: + case CastExpr::CK_IntegralToPointer: + case CastExpr::CK_PointerToIntegral: + case CastExpr::CK_VectorSplat: + case CastExpr::CK_IntegralCast: + case CastExpr::CK_IntegralToFloating: + case CastExpr::CK_FloatingToIntegral: + case CastExpr::CK_FloatingCast: + case CastExpr::CK_DerivedToBaseMemberPointer: + case CastExpr::CK_BaseToDerivedMemberPointer: + case CastExpr::CK_MemberPointerToBoolean: + case CastExpr::CK_AnyPointerToBlockPointerCast: { + // These casts only produce lvalues when we're binding a reference to a + // temporary realized from a (converted) pure rvalue. Emit the expression + // as a value, copy it into a temporary, and return an lvalue referring to + // that temporary. + llvm::Value *V = CreateMemTemp(E->getType(), "ref.temp"); + EmitAnyExprToMem(E, V, false, false); + return LValue::MakeAddr(V, MakeQualifiers(E->getType())); + } case CastExpr::CK_Dynamic: { LValue LV = EmitLValue(E->getSubExpr()); @@ -1760,17 +1800,6 @@ LValue CodeGenFunction::EmitCastLValue(const CastExpr *E) { MakeQualifiers(E->getType())); } - case CastExpr::CK_NoOp: { - LValue LV = EmitLValue(E->getSubExpr()); - if (LV.isPropertyRef()) { - QualType QT = E->getSubExpr()->getType(); - RValue RV = EmitLoadOfPropertyRefLValue(LV, QT); - assert(!RV.isScalar() && "EmitCastLValue - scalar cast of property ref"); - llvm::Value *V = RV.getAggregateAddr(); - return LValue::MakeAddr(V, MakeQualifiers(QT)); - } - return LV; - } case CastExpr::CK_ConstructorConversion: case CastExpr::CK_UserDefinedConversion: case CastExpr::CK_AnyPointerToObjCPointerCast: @@ -1826,6 +1855,8 @@ LValue CodeGenFunction::EmitCastLValue(const CastExpr *E) { return LValue::MakeAddr(V, MakeQualifiers(E->getType())); } } + + llvm_unreachable("Unhandled lvalue cast kind?"); } LValue CodeGenFunction::EmitNullInitializationLValue( diff --git a/clang/test/CodeGenCXX/reference-cast.cpp b/clang/test/CodeGenCXX/reference-cast.cpp new file mode 100644 index 000000000000..49409d7be164 --- /dev/null +++ b/clang/test/CodeGenCXX/reference-cast.cpp @@ -0,0 +1,170 @@ +// RUN: %clang_cc1 -emit-llvm -triple x86_64-apple-darwin10 -o - %s | FileCheck %s + +// PR6024 +extern int i; + +// CHECK: define i32* @_Z16lvalue_noop_castv() nounwind +const int &lvalue_noop_cast() { + if (i == 0) + // CHECK: store i32 17, i32* + return (const int&)17; + else if (i == 1) + // CHECK: store i32 17, i32* + return static_cast(17); + // CHECK: store i32 17, i32* + return 17; +} + +// CHECK: define i16* @_Z20lvalue_integral_castv() +const short &lvalue_integral_cast() { + if (i == 0) + // CHECK: store i16 17, i16* + return (const short&)17; + else if (i == 1) + // CHECK: store i16 17, i16* + return static_cast(17); + // CHECK: store i16 17, i16* + return 17; +} + +// CHECK: define i16* @_Z29lvalue_floating_integral_castv() +const short &lvalue_floating_integral_cast() { + if (i == 0) + // CHECK: store i16 17, i16* + return (const short&)17.5; + else if (i == 1) + // CHECK: store i16 17, i16* + return static_cast(17.5); + // CHECK: store i16 17, i16* + return 17.5; +} + +// CHECK: define float* @_Z29lvalue_integral_floating_castv() +const float &lvalue_integral_floating_cast() { + if (i == 0) + // CHECK: store float 1.700000e+01, float* + return (const float&)17; + else if (i == 1) + // CHECK: store float 1.700000e+01, float* + return static_cast(17); + // CHECK: store float 1.700000e+01, float* + return 17; +} + +// CHECK: define float* @_Z20lvalue_floating_castv() +const float &lvalue_floating_cast() { + if (i == 0) + // CHECK: store float 1.700000e+01, float* + return (const float&)17.0; + else if (i == 1) + // CHECK: store float 1.700000e+01, float* + return static_cast(17.0); + // CHECK: store float 1.700000e+01, float* + return 17.0; +} + +int get_int(); + +// CHECK: define i8* @_Z24lvalue_integer_bool_castv() +const bool &lvalue_integer_bool_cast() { + if (i == 0) + // CHECK: call i32 @_Z7get_intv() + // CHECK: store i8 + return (const bool&)get_int(); + else if (i == 1) + // CHECK: call i32 @_Z7get_intv() + // CHECK: store i8 + return static_cast(get_int()); + // CHECK: call i32 @_Z7get_intv() + // CHECK: store i8 + return get_int(); +} + +float get_float(); + +// CHECK: define i8* @_Z25lvalue_floating_bool_castv() +const bool &lvalue_floating_bool_cast() { + if (i == 0) + // CHECK: call float @_Z9get_floatv() + // CHECK: fcmp une float + // CHECK: store i8 + return (const bool&)get_float(); + else if (i == 1) + // CHECK: call float @_Z9get_floatv() + // CHECK: fcmp une float + // CHECK: store i8 + return static_cast(get_float()); + // CHECK: call float @_Z9get_floatv() + // CHECK: fcmp une float + // CHECK: store i8 + return get_float(); +} + +struct X { }; +typedef int X::*pm; +typedef int (X::*pmf)(int); + +pm get_pointer_to_member_data(); +pmf get_pointer_to_member_function(); + +// CHECK: define i8* @_Z26lvalue_ptrmem_to_bool_castv() +const bool &lvalue_ptrmem_to_bool_cast() { + if (i == 0) + // CHECK: call i64 @_Z26get_pointer_to_member_datav() + // CHECK: store i8 + // CHECK: store i8* + return (const bool&)get_pointer_to_member_data(); + else if (i == 1) + // CHECK: call i64 @_Z26get_pointer_to_member_datav() + // CHECK: store i8 + // CHECK: store i8* + return static_cast(get_pointer_to_member_data()); + // CHECK: call i64 @_Z26get_pointer_to_member_datav() + // CHECK: store i8 + // CHECK: store i8* + return get_pointer_to_member_data(); +} + +// CHECK: define i8* @_Z27lvalue_ptrmem_to_bool_cast2v +const bool &lvalue_ptrmem_to_bool_cast2() { + if (i == 0) + // CHECK: {{call.*_Z30get_pointer_to_member_functionv}} + // CHECK: store i8 + // CHECK: store i8* + return (const bool&)get_pointer_to_member_function(); + else if (i == 1) + // CHECK: {{call.*_Z30get_pointer_to_member_functionv}} + // CHECK: store i8 + // CHECK: store i8* + return static_cast(get_pointer_to_member_function()); + // CHECK: {{call.*_Z30get_pointer_to_member_functionv}} + // CHECK: store i8 + // CHECK: store i8* + return get_pointer_to_member_function(); +} + +_Complex double get_complex_double(); + +// CHECK: {{define.*_Z2f1v}} +const _Complex float &f1() { + if (i == 0) + // CHECK: {{call.*_Z18get_complex_doublev}} + // CHECK: fptrunc + // CHECK: fptrunc + // CHECK: store float + // CHECK: store float + return (const _Complex float&)get_complex_double(); + else if (i == 1) + // CHECK: {{call.*_Z18get_complex_doublev}} + // CHECK: fptrunc + // CHECK: fptrunc + // CHECK: store float + // CHECK: store float + return static_cast(get_complex_double()); + // CHECK: {{call.*_Z18get_complex_doublev}} + // CHECK: fptrunc + // CHECK: fptrunc + // CHECK: store float + // CHECK: store float + return get_complex_double(); +}