]> granicus.if.org Git - clang/commitdiff
Expression statements undergo lvalue-to-rvalue conversion in C,
authorJohn McCall <rjmccall@apple.com>
Wed, 25 Aug 2010 02:50:31 +0000 (02:50 +0000)
committerJohn McCall <rjmccall@apple.com>
Wed, 25 Aug 2010 02:50:31 +0000 (02:50 +0000)
but not in C++, so don't emit aggregate loads of volatile references
in null context in C++.  Happens to have been caught by an assertion.
We do not get the scalar case right.  Volatiles are really broken.

git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@112019 91177308-0d34-0410-b5e6-96231b3b80d8

lib/CodeGen/CGExprAgg.cpp
test/CodeGenCXX/volatile.cpp [new file with mode: 0644]

index 1b6254f1923382b1dc2eaeb2d2578cf573e56498..89fea398d33477351b5b599e3a7fa1e9d9e7fddb 100644 (file)
@@ -192,10 +192,18 @@ void AggExprEmitter::EmitGCMove(const Expr *E, RValue Src) {
 void AggExprEmitter::EmitFinalDestCopy(const Expr *E, RValue Src, bool Ignore) {
   assert(Src.isAggregate() && "value must be aggregate value!");
 
-  // If the result is ignored, don't copy from the value.
+  // If DestPtr is null, then we're evaluating an aggregate expression
+  // in a context (like an expression statement) that doesn't care
+  // about the result.  C says that an lvalue-to-rvalue conversion is
+  // performed in these cases; C++ says that it is not.  In either
+  // case, we don't actually need to do anything unless the value is
+  // volatile.
   if (DestPtr == 0) {
-    if (!Src.isVolatileQualified() || (IgnoreResult && Ignore))
+    if (!Src.isVolatileQualified() ||
+        CGF.CGM.getLangOptions().CPlusPlus ||
+        (IgnoreResult && Ignore))
       return;
+
     // If the source is volatile, we must read from it; to do that, we need
     // some place to put it.
     DestPtr = CGF.CreateMemTemp(E->getType(), "agg.tmp");
diff --git a/test/CodeGenCXX/volatile.cpp b/test/CodeGenCXX/volatile.cpp
new file mode 100644 (file)
index 0000000..58f433f
--- /dev/null
@@ -0,0 +1,35 @@
+// RUN: %clang_cc1 %s -triple=x86_64-apple-darwin10 -emit-llvm -o - | FileCheck %s
+
+// Check that IR gen doesn't try to do an lvalue-to-rvalue conversion
+// on a volatile reference result.  rdar://problem/8338198
+namespace test0 {
+  struct A {
+    A(const A& t);
+    A& operator=(const A& t);
+    volatile A& operator=(const volatile A& t) volatile;
+  };
+
+  volatile A *array;
+
+  // CHECK: define void @_ZN5test04testENS_1AE(
+  void test(A t) {
+    // CHECK:      [[ARR:%.*]] = load [[A:%.*]]** @_ZN5test05arrayE, align 8
+    // CHECK-NEXT: [[IDX:%.*]] = getelementptr inbounds [[A]]* [[ARR]], i64 0
+    // CHECK-NEXT: [[TMP:%.*]] = call [[A]]* @_ZNV5test01AaSERVKS0_([[A]]* [[IDX]], [[A]]* [[T:%.*]])
+    // CHECK-NEXT: ret void
+    array[0] = t;
+  }
+}
+
+namespace test1 {
+  volatile int *x;
+
+  // CHECK: define void @_ZN5test14testEv()
+  void test() {
+    // CHECK:      [[TMP:%.*]] = load i32** @_ZN5test11xE, align 8
+    // *** FIXME: no! bad! should not be loaded! ***
+    // CHECK-NEXT: [[TMP1:%.*]] = volatile load i32* [[TMP]]
+    // CHECK-NEXT: ret void
+    *x;
+  }
+}