In an expression like a.f(), if f is a static member function, a is
still evaluated.  But if a is a volatile lvalue, we don't want to do
the discarded-value load; what's really evaluated is the 'this'
argument, which is the address of a.

Tested x86_64-pc-linux-gnu, applying to trunk and 7.
commit 50db20e0e5254f85f0e37659802dd9807455f74b
Author: Jason Merrill <ja...@redhat.com>
Date:   Fri Feb 16 15:43:07 2018 -0500

            PR c++/84151 - unnecessary volatile load with static member.
    
            * call.c (build_new_method_call_1): Avoid loading from a volatile
            lvalue used as the object argument for a static member function.

diff --git a/gcc/cp/call.c b/gcc/cp/call.c
index d3d0966f65c..7c93c6d8290 100644
--- a/gcc/cp/call.c
+++ b/gcc/cp/call.c
@@ -9284,8 +9284,14 @@ build_new_method_call_1 (tree instance, tree fns, 
vec<tree, va_gc> **args,
              if (TREE_CODE (TREE_TYPE (fn)) != METHOD_TYPE
                  && !is_dummy_object (instance)
                  && TREE_SIDE_EFFECTS (instance))
-               call = build2 (COMPOUND_EXPR, TREE_TYPE (call),
-                              instance, call);
+               {
+                 /* But avoid the implicit lvalue-rvalue conversion when 'a'
+                    is volatile.  */
+                 tree a = instance;
+                 if (TREE_THIS_VOLATILE (a))
+                   a = build_this (a);
+                 call = build2 (COMPOUND_EXPR, TREE_TYPE (call), a, call);
+               }
              else if (call != error_mark_node
                       && DECL_DESTRUCTOR_P (cand->fn)
                       && !VOID_TYPE_P (TREE_TYPE (call)))
diff --git a/gcc/testsuite/g++.dg/tree-ssa/volatile1.C 
b/gcc/testsuite/g++.dg/tree-ssa/volatile1.C
new file mode 100644
index 00000000000..00f04a07d84
--- /dev/null
+++ b/gcc/testsuite/g++.dg/tree-ssa/volatile1.C
@@ -0,0 +1,28 @@
+// PR c++/84151
+// { dg-additional-options "-fdump-tree-gimple" }
+// { dg-final { scan-tree-dump-not {\*this} "gimple" } }
+
+struct A {
+  static int& bar(int& a) {
+    return a;
+  }
+  static int i;
+
+  int foo() volatile {
+    int v = c;
+    return i + bar(v);
+  }
+
+  int c;
+};
+
+int A::i = 0;
+
+A a;
+
+int main() {
+  a.c = 2;
+  a.foo();
+
+  return 0;
+}

Reply via email to