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; +}