From: Richard Smith Date: Sat, 18 Feb 2012 20:53:32 +0000 (+0000) Subject: Fix wrong-code bug: __imag on a scalar lvalue should produce a zero rvalue, X-Git-Url: https://granicus.if.org/sourcecode?a=commitdiff_plain;h=dfb80ded6767f7b79a0f1fa4f6921d543ff0a643;p=clang Fix wrong-code bug: __imag on a scalar lvalue should produce a zero rvalue, rather than an lvalue referring to the scalar. git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@150889 91177308-0d34-0410-b5e6-96231b3b80d8 --- diff --git a/lib/CodeGen/CGExpr.cpp b/lib/CodeGen/CGExpr.cpp index 3871f33a26..060841d507 100644 --- a/lib/CodeGen/CGExpr.cpp +++ b/lib/CodeGen/CGExpr.cpp @@ -1465,9 +1465,10 @@ LValue CodeGenFunction::EmitUnaryOpLValue(const UnaryOperator *E) { assert(LV.isSimple() && "real/imag on non-ordinary l-value"); llvm::Value *Addr = LV.getAddress(); - // real and imag are valid on scalars. This is a faster way of - // testing that. - if (!cast(Addr->getType()) + // __real is valid on scalars. This is a faster way of testing that. + // __imag can only produce an rvalue on scalars. + if (E->getOpcode() == UO_Real && + !cast(Addr->getType()) ->getElementType()->isStructTy()) { assert(E->getSubExpr()->getType()->isArithmeticType()); return LV; diff --git a/lib/CodeGen/CGExprScalar.cpp b/lib/CodeGen/CGExprScalar.cpp index 8bd4c2b5aa..6eed2ed346 100644 --- a/lib/CodeGen/CGExprScalar.cpp +++ b/lib/CodeGen/CGExprScalar.cpp @@ -1642,7 +1642,10 @@ Value *ScalarExprEmitter::VisitUnaryImag(const UnaryOperator *E) { // __imag on a scalar returns zero. Emit the subexpr to ensure side // 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())); } diff --git a/lib/Sema/SemaExpr.cpp b/lib/Sema/SemaExpr.cpp index c727e88adb..3f1fabcaa3 100644 --- a/lib/Sema/SemaExpr.cpp +++ b/lib/Sema/SemaExpr.cpp @@ -8095,11 +8095,17 @@ ExprResult Sema::CreateBuiltinUnaryOp(SourceLocation OpLoc, case UO_Real: case UO_Imag: 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.get()->getValueKind() != VK_RValue && - Input.get()->getObjectKind() == OK_Ordinary) - VK = Input.get()->getValueKind(); + if (Opc == UO_Real || Input.get()->getType()->isAnyComplexType()) { + if (Input.get()->getValueKind() != VK_RValue && + 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; case UO_Extension: resultType = Input.get()->getType(); diff --git a/test/Sema/complex-imag.c b/test/Sema/complex-imag.c new file mode 100644 index 0000000000..1c6fb159bc --- /dev/null +++ b/test/Sema/complex-imag.c @@ -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; +}