Handle compound assignment expressions (i += j) as lvalues, which is

permitted in C++ but not in C. Fixes PR6900. Clang can now handle all
of Boost.Lambda's regression tests.

llvm-svn: 102170
This commit is contained in:
Douglas Gregor 2010-04-23 04:16:32 +00:00
parent 11373b5277
commit 914af2182b
4 changed files with 93 additions and 12 deletions

View File

@ -478,6 +478,8 @@ LValue CodeGenFunction::EmitLValue(const Expr *E) {
return EmitObjCIsaExpr(cast<ObjCIsaExpr>(E));
case Expr::BinaryOperatorClass:
return EmitBinaryOperatorLValue(cast<BinaryOperator>(E));
case Expr::CompoundAssignOperatorClass:
return EmitCompoundAssignOperatorLValue(cast<CompoundAssignOperator>(E));
case Expr::CallExprClass:
case Expr::CXXMemberCallExprClass:
case Expr::CXXOperatorCallExprClass:

View File

@ -314,6 +314,10 @@ public:
}
BinOpInfo EmitBinOps(const BinaryOperator *E);
LValue EmitCompoundAssignLValue(const CompoundAssignOperator *E,
Value *(ScalarExprEmitter::*F)(const BinOpInfo &),
Value *&BitFieldResult);
Value *EmitCompoundAssign(const CompoundAssignOperator *E,
Value *(ScalarExprEmitter::*F)(const BinOpInfo &));
@ -1103,22 +1107,24 @@ BinOpInfo ScalarExprEmitter::EmitBinOps(const BinaryOperator *E) {
return Result;
}
Value *ScalarExprEmitter::EmitCompoundAssign(const CompoundAssignOperator *E,
Value *(ScalarExprEmitter::*Func)(const BinOpInfo &)) {
bool Ignore = TestAndClearIgnoreResultAssign();
LValue ScalarExprEmitter::EmitCompoundAssignLValue(
const CompoundAssignOperator *E,
Value *(ScalarExprEmitter::*Func)(const BinOpInfo &),
Value *&BitFieldResult) {
QualType LHSTy = E->getLHS()->getType();
BitFieldResult = 0;
BinOpInfo OpInfo;
if (E->getComputationResultType()->isAnyComplexType()) {
// This needs to go through the complex expression emitter, but it's a tad
// complicated to do that... I'm leaving it out for now. (Note that we do
// actually need the imaginary part of the RHS for multiplication and
// division.)
CGF.ErrorUnsupported(E, "complex compound assignment");
return llvm::UndefValue::get(CGF.ConvertType(E->getType()));
llvm::UndefValue::get(CGF.ConvertType(E->getType()));
return LValue();
}
// Emit the RHS first. __block variables need to have the rhs evaluated
// first, plus this should improve codegen a little.
OpInfo.RHS = Visit(E->getRHS());
@ -1129,13 +1135,13 @@ Value *ScalarExprEmitter::EmitCompoundAssign(const CompoundAssignOperator *E,
OpInfo.LHS = EmitLoadOfLValue(LHSLV, LHSTy);
OpInfo.LHS = EmitScalarConversion(OpInfo.LHS, LHSTy,
E->getComputationLHSType());
// Expand the binary operator.
Value *Result = (this->*Func)(OpInfo);
// Convert the result back to the LHS type.
Result = EmitScalarConversion(Result, E->getComputationResultType(), LHSTy);
// Store the result value into the LHS lvalue. Bit-fields are handled
// specially because the result is altered by the store, i.e., [C99 6.5.16p1]
// 'An assignment expression has the value of the left operand after the
@ -1144,11 +1150,23 @@ Value *ScalarExprEmitter::EmitCompoundAssign(const CompoundAssignOperator *E,
if (!LHSLV.isVolatileQualified()) {
CGF.EmitStoreThroughBitfieldLValue(RValue::get(Result), LHSLV, LHSTy,
&Result);
return Result;
BitFieldResult = Result;
return LHSLV;
} else
CGF.EmitStoreThroughBitfieldLValue(RValue::get(Result), LHSLV, LHSTy);
} else
CGF.EmitStoreThroughLValue(RValue::get(Result), LHSLV, LHSTy);
return LHSLV;
}
Value *ScalarExprEmitter::EmitCompoundAssign(const CompoundAssignOperator *E,
Value *(ScalarExprEmitter::*Func)(const BinOpInfo &)) {
bool Ignore = TestAndClearIgnoreResultAssign();
Value *BitFieldResult;
LValue LHSLV = EmitCompoundAssignLValue(E, Func, BitFieldResult);
if (BitFieldResult)
return BitFieldResult;
if (Ignore)
return 0;
return EmitLoadOfLValue(LHSLV, E->getType());
@ -1914,3 +1932,53 @@ LValue CodeGenFunction::EmitObjCIsaExpr(const ObjCIsaExpr *E) {
return LV;
}
LValue CodeGenFunction::EmitCompoundAssignOperatorLValue(
const CompoundAssignOperator *E) {
ScalarExprEmitter Scalar(*this);
Value *BitFieldResult = 0;
switch (E->getOpcode()) {
#define COMPOUND_OP(Op) \
case BinaryOperator::Op##Assign: \
return Scalar.EmitCompoundAssignLValue(E, &ScalarExprEmitter::Emit##Op, \
BitFieldResult)
COMPOUND_OP(Mul);
COMPOUND_OP(Div);
COMPOUND_OP(Rem);
COMPOUND_OP(Add);
COMPOUND_OP(Sub);
COMPOUND_OP(Shl);
COMPOUND_OP(Shr);
COMPOUND_OP(And);
COMPOUND_OP(Xor);
COMPOUND_OP(Or);
#undef COMPOUND_OP
case BinaryOperator::PtrMemD:
case BinaryOperator::PtrMemI:
case BinaryOperator::Mul:
case BinaryOperator::Div:
case BinaryOperator::Rem:
case BinaryOperator::Add:
case BinaryOperator::Sub:
case BinaryOperator::Shl:
case BinaryOperator::Shr:
case BinaryOperator::LT:
case BinaryOperator::GT:
case BinaryOperator::LE:
case BinaryOperator::GE:
case BinaryOperator::EQ:
case BinaryOperator::NE:
case BinaryOperator::And:
case BinaryOperator::Xor:
case BinaryOperator::Or:
case BinaryOperator::LAnd:
case BinaryOperator::LOr:
case BinaryOperator::Assign:
case BinaryOperator::Comma:
assert(false && "Not valid compound assignment operators");
break;
}
llvm_unreachable("Unhandled compound assignment operator");
}

View File

@ -1043,6 +1043,7 @@ public:
// Note: only availabe for agg return types
LValue EmitBinaryOperatorLValue(const BinaryOperator *E);
LValue EmitCompoundAssignOperatorLValue(const CompoundAssignOperator *E);
// Note: only available for agg return types
LValue EmitCallExprLValue(const CallExpr *E);
// Note: only available for agg return types

View File

@ -1,4 +1,4 @@
// RUN: %clang_cc1 %s -emit-llvm-only -verify
// RUN: %clang_cc1 %s -triple x86_64-apple-darwin10 -emit-llvm -verify -o - |FileCheck %s
class x {
public: int operator=(int);
@ -7,3 +7,13 @@ void a() {
x a;
a = 1u;
}
void f(int i, int j) {
// CHECK: load i32
// CHECK: load i32
// CHECK: add nsw i32
// CHECK: store i32
// CHECK: store i32 17, i32
// CHECK: ret
(i += j) = 17;
}