Make OP_REQUIRES_OK* macros work correctly regardless of lifetime of the status argument, and add unit tests.
Make OP_REQUIRES_OK* macros work correctly regardless of lifetime of the status argument, and add unit tests.

As part of this, we clarify that OP_REQUIRES_OK_ASYNC only evaluates its CALLBACK macro argument in the non-OK case, and we also clarify that OP_REQUIRES_OK expectes a single expression convertible to absl::Status, despite its variable arguments. Following a previous change [1] this was already implied, but prior to that change, multiple explicit constructor arguments for absl::Status would have been accepted, too. It appears (though we have no proof) that this was never an intended feature.

This is the second attempt at this change. The previous one had an error that is now fixed: we failed to notice the requirement for the CALLBACK argument to only be evaluated in the failure case, and the previous attempt evaluated it unconditionally. This was a behaviour change in cases where the evaluation of the CALLBACK expression itself has side effects. (Concretely, the side effect was a call of absl::Cleanup::Release.) In this version, we retain `(CALLBACK)();` in the top-level macro expansion rather than passing `(CALLBACK)` into the helper function.

This corrects earlier changes to OP_REQUIES_OK and OP_REQUIES_OK_ASYNC (e.g. [2]), which took a reference but did not extend the lifetime of potential intermediate temporaries. This would cause problems in situations where a short-lived status was passed in as something other than a prvalue, for example:

  struct T {
    const absl::Status& f() const { return s; }
    absl::Status s;
  };

  OP_REQUIRES_OK(T().f());

This becomes

  const absl::Status& _s(T().f());

which is instantly a dangling reference. (The added unit test catches this case when run under ASAN.)

To fix this, we move operations on user-provided arguments into a helper function, and ensure that the user-provided arguments are only used inside a single function call expression. All temporaries remain alive for the duration of the function call.
