Fix wrong-code bug: __imag on a scalar lvalue should produce a zero rvalue,

rather than an lvalue referring to the scalar.

llvm-svn: 150889
This commit is contained in:
Richard Smith 2012-02-18 20:53:32 +00:00
parent e98d63a823
commit 0b6b8e490c
4 changed files with 47 additions and 8 deletions

View File

@ -1465,9 +1465,10 @@ LValue CodeGenFunction::EmitUnaryOpLValue(const UnaryOperator *E) {
assert(LV.isSimple() && "real/imag on non-ordinary l-value"); assert(LV.isSimple() && "real/imag on non-ordinary l-value");
llvm::Value *Addr = LV.getAddress(); llvm::Value *Addr = LV.getAddress();
// real and imag are valid on scalars. This is a faster way of // __real is valid on scalars. This is a faster way of testing that.
// testing that. // __imag can only produce an rvalue on scalars.
if (!cast<llvm::PointerType>(Addr->getType()) if (E->getOpcode() == UO_Real &&
!cast<llvm::PointerType>(Addr->getType())
->getElementType()->isStructTy()) { ->getElementType()->isStructTy()) {
assert(E->getSubExpr()->getType()->isArithmeticType()); assert(E->getSubExpr()->getType()->isArithmeticType());
return LV; return LV;

View File

@ -1642,7 +1642,10 @@ Value *ScalarExprEmitter::VisitUnaryImag(const UnaryOperator *E) {
// __imag on a scalar returns zero. Emit the subexpr to ensure side // __imag on a scalar returns zero. Emit the subexpr to ensure side
// effects are evaluated, but not the actual value. // effects are evaluated, but not the actual value.
CGF.EmitScalarExpr(Op, true); if (Op->isGLValue())
CGF.EmitLValue(Op);
else
CGF.EmitScalarExpr(Op, true);
return llvm::Constant::getNullValue(ConvertType(E->getType())); return llvm::Constant::getNullValue(ConvertType(E->getType()));
} }

View File

@ -8095,11 +8095,17 @@ ExprResult Sema::CreateBuiltinUnaryOp(SourceLocation OpLoc,
case UO_Real: case UO_Real:
case UO_Imag: case UO_Imag:
resultType = CheckRealImagOperand(*this, Input, OpLoc, Opc == UO_Real); resultType = CheckRealImagOperand(*this, Input, OpLoc, Opc == UO_Real);
// _Real and _Imag map ordinary l-values into ordinary l-values. // _Real maps ordinary l-values into ordinary l-values. _Imag maps ordinary
// complex l-values to ordinary l-values and all other values to r-values.
if (Input.isInvalid()) return ExprError(); if (Input.isInvalid()) return ExprError();
if (Input.get()->getValueKind() != VK_RValue && if (Opc == UO_Real || Input.get()->getType()->isAnyComplexType()) {
Input.get()->getObjectKind() == OK_Ordinary) if (Input.get()->getValueKind() != VK_RValue &&
VK = Input.get()->getValueKind(); Input.get()->getObjectKind() == OK_Ordinary)
VK = Input.get()->getValueKind();
} else if (!getLangOptions().CPlusPlus) {
// In C, a volatile scalar is read by __imag. In C++, it is not.
Input = DefaultLvalueConversion(Input.take());
}
break; break;
case UO_Extension: case UO_Extension:
resultType = Input.get()->getType(); resultType = Input.get()->getType();

View File

@ -0,0 +1,29 @@
// RUN: %clang_cc1 -verify %s
void f1() {
int a = 1;
int b = __imag a;
int *c = &__real a;
int *d = &__imag a; // expected-error {{must be an lvalue}}
}
void f2() {
_Complex int a = 1;
int b = __imag a;
int *c = &__real a;
int *d = &__imag a;
}
void f3() {
double a = 1;
double b = __imag a;
double *c = &__real a;
double *d = &__imag a; // expected-error {{must be an lvalue}}
}
void f4() {
_Complex double a = 1;
double b = __imag a;
double *c = &__real a;
double *d = &__imag a;
}