Class Inheritance and Volatile Modifier

Hello,

We recently came across a “suspicious” behavior of Clang w.r.t. volatile accesses, and aren’t sure if this is expected or if this is a bug/limitation.

Here is the sample code:

struct parent { int a; };
struct child : parent { int x; };

int bar(volatile child &v) {
return v.x + v.a;
}

And here is the resulting IR:

%struct.child = type { %struct.parent, i32 }
%struct.parent = type { i32 }

define dso_local i32 @_Z3barRV5child(%struct.child* nonnull align 4 dereferenceable(8) %v) local_unnamed_addr #0 {
entry:
%x = getelementptr inbounds %struct.child, %struct.child* %v, i64 0, i32 1
%0 = load volatile i32, i32* %x, align 4, !tbaa !3
%a = getelementptr inbounds %struct.child, %struct.child* %v, i64 0, i32 0, i32 0
%1 = load i32, i32* %a, align 4, !tbaa !8
%add = add nsw i32 %1, %0
ret i32 %add
}

As you can see, only the access of the x field is volatile, not the a field (from the parent). As this is clearly different from what would happen to “const” modifier, I’m curious to know if that is standard? Maybe the standard is unspecified?

Here is a godbolt link to this example on trunk: https://godbolt.org/z/aT51sb4Pv

Best regards!

Yeah, seems pretty questionable - not sure what the C++ spec says about it though.

Similarly if you instead add a member of type “parent” to “child” and access that member, it does get a volatile load - which even if the C++ spec says the base object doesn’t need this handling, we should probably do it for consistency I’d imagine. But I doubt it’s high up anyone’s list - volatile’s generally only used in pretty narrow cases (memory mapped IO driver things maybe - unlikely to see novel C++ inheritance in mapping such structures)