Why is dereferencing of nullptr while using a static method not undefined behaviour in C++?

Regular member functions have an implicit this-pointer while static functions don't. When you call a static member function, you don't need an instance, but only a type.

The usual syntax is

A::static_mem_fn();

Standard citations in this answer are from the C++17 spec (N4713).

One of the sections cited in your question answers the question for non-static member functions. [class.mfct.non-static]/2:

If a non-static member function of a class X is called for an object that is not of type X, or of a type derived from X, the behavior is undefined.

This applies to, for example, accessing an object through a different pointer type:

std::string foo;

A *ptr = reinterpret_cast<A *>(&foo); // not UB by itself
ptr->non_static_mem_fn();             // UB by [class.mfct.non-static]/2

A null pointer doesn't point at any valid object, so it certainly doesn't point to an object of type A either. Using your own example:

p->non_static_mem_fn(); // UB by [class.mfct.non-static]/2

With that out of the way, why does this work in the static case? Let's pull together two parts of the standard:

[expr.ref]/2:

... The expression E1->E2 is converted to the equivalent form (*(E1)).E2 ...

[class.static]/1 (emphasis mine):

... A static member may be referred to using the class member access syntax, in which case the object expression is evaluated.

The second block, in particular, says that the object expression is evaluated even for static member access. This is important if, for example, it is a function call with side effects.

Put together, this implies that these two blocks are equivalent:

// 1
p->static_mem_fn();

// 2
*p;
A::static_mem_fn();

So the final question to answer is whether *p alone is undefined behavior when p is a null pointer value.

Conventional wisdom would say "yes" but this is not actually true. There is nothing in the standard that states dereferencing a null pointer alone is UB and there are several discussions that directly support this:

  • Issue 315, as you have mentioned in your question, explicitly states that *p is not UB when the result is unused.
  • DR 1102 removes "dereferencing the null pointer" as an example of UB. The given rationale is:

    There are core issues surrounding the undefined behavior of dereferencing a null pointer. It appears the intent is that dereferencing is well defined, but using the result of the dereference will yield undefined behavior. This topic is too confused to be the reference example of undefined behavior, or should be stated more precisely if it is to be retained.

  • This DR links to issue 232 where it is discussed to add wording that explicitly indicates *p as defined behavior when p is a null pointer, as long as the result is not used.

In conclusion:

p->non_static_mem_fn(); // UB by [class.mfct.non-static]/2
p->static_mem_fn();     // Defined behavior per issue 232 and 315.