]> granicus.if.org Git - clang/commitdiff
Fix wrong-code bug: __imag on a scalar lvalue should produce a zero rvalue,
authorRichard Smith <richard-llvm@metafoo.co.uk>
Sat, 18 Feb 2012 20:53:32 +0000 (20:53 +0000)
committerRichard Smith <richard-llvm@metafoo.co.uk>
Sat, 18 Feb 2012 20:53:32 +0000 (20:53 +0000)
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

lib/CodeGen/CGExpr.cpp
lib/CodeGen/CGExprScalar.cpp
lib/Sema/SemaExpr.cpp
test/Sema/complex-imag.c [new file with mode: 0644]

index 3871f33a2645f6522d80025ffa43501b839c82f5..060841d50783e26de57ac31ddaeb0b26d8db2e79 100644 (file)
@@ -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<llvm::PointerType>(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<llvm::PointerType>(Addr->getType())
            ->getElementType()->isStructTy()) {
       assert(E->getSubExpr()->getType()->isArithmeticType());
       return LV;
index 8bd4c2b5aa2e110f33d130664cf3312d87ae5e27..6eed2ed346fb87fa34ede9338403b6afaf65e29a 100644 (file)
@@ -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()));
 }
 
index c727e88adb85d7ba1bb3ed2b5c9c599a5abc2cf5..3f1fabcaa350099f3e539eba2728feec620758b4 100644 (file)
@@ -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 (file)
index 0000000..1c6fb15
--- /dev/null
@@ -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;
+}