C++ allows us to reference static variables through member expressions. Prior to this patch, non-integer static variables that were referenced using a member expression were always emitted using lvalue loads. The old behaviour introduced an inconsistency between regular uses of static variables and member expressions uses, for example, the following program compiled and linked successfully:
struct Foo { constexpr static const char *name = "foo"; }; int main() { return Foo::name[0] == 'f'; }
but this program failed to link because "Foo::name" wasn't found:
struct Foo { constexpr static const char *name = "foo"; }; int main() { Foo f; return f.name[0] == 'f'; }
This patch ensures that constant static variables referenced through member expressions are emitted in the same way as ordinary static variable references.
rdar://33942261
The side effects here are those associated with the initializer of the referenced declaration, not the DRE itself. Some expressions can be constant-evaluated despite having side-effects because the side-effects occur in an ignored operand, like the LHS of a comma or the base of a MemberExpr that refers to a static member.
We can't allow side effects here because (1) we're not actually collecting the side-effectful expressions to emit and (2) we'd need some permission from the context to decide that we're allowed to do so anyway (with a lambda capture, those side-effects have actually already been emitted, but I'm not convinced that's always true).
On the other hand, I think we need to be able to emit MemberExprs to static members as constants despite the presence of side-effects in their base expressions, and I can't think of any reasonable way to do that except actually making a temporary DeclRefExpr to try to constant-emit instead.