Open Bug 1583449 Opened 5 years ago Updated 2 years ago

Cannot use lambda expression within MOZ_ASSERT

Categories

(Core :: MFBT, defect)

defect

Tracking

()

People

(Reporter: sg, Unassigned)

Details

Attempting to use a lambda expression as the condition of MOZ_ASSERT results in error: lambda expression in an unevaluated operand, e.g.

  MOZ_ASSERT([] { return true; }());

This example is not useful, but I stripped it down to show that it is unrelated to any other constructs. A useful example that yields the same error might be:

    MOZ_ASSERT(std::all_of(mObjectStores.cbegin(), mObjectStores.cend(),
                           [&name = aSpec.metadata().name()](const auto& objectStore) {
                             return objectStore->Name() != name;
                           }));

glibc's assert macro had a similar issue, which was solved by https://sourceware.org/git/?p=glibc.git;a=blobdiff;f=assert/assert.h;h=640c95c06344ffbf1971793e8aaf283aad6679e2;hp=6801cfeb10debf7a9e0d6e425ecfb0c68b2ca42a;hb=b5889d25e9bf944a89fdd7bcabf3b6c6f6bb6f7c;hpb=41e673c1e771075f413f8e8ecd9e108f5ae096d9 but the situation is different for MOZ_ASSERT, since MOZ_VALIDATE_ASSERT_CONDITION_TYPE involves decltype(cond). This issue will resolve with C++20 since it will incorporate a changed wording around lambdas in unevaluated contexts (cf. http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2017/p0315r3.pdf), however for the time being, a solution would be good. If MOZ_VALIDATE_ASSERT_CONDITION_TYPE should not be changed, maybe a variant of MOZ_ASSERT could be introduced that specifically works around this issue, but should not be used in cases where no lambda expression is involved.

Hmph. This is awkward, because to a human it's obvious that type of std::all_of(...) is bool, but the compiler, in the process of following its rules very precisely, gets caught up on the lambda. I wonder if we can find a way to make the compiler admit to the overall-bool-ness without worrying about the details.

Can we rewrite the validation without decltype? Maybe move the checks into a templated function like...

template <class T> bool CheckAssertType(T val) {
    static_assert(!IsArray<T>, etc);
    return val;
}

(We'd probably want to coordinate with MOZ_CHECK_ASSERT_ASSIGNMENT somehow)

One quick problem with comment 1's approach -- I'm fairly sure -- is that because of array-to-pointer decay that particular static assertion would never fail. (Function pointer testing, at least, would probably still work.)

Another possibility that occurred to me is having a bool b { expr }; check b; approach, on the theory that braced-init will forbid a narrowing conversion, but in practice it seems like function pointers can decay in such fashion. (Albeit with a warning in clang.) Maybe a warning is enough smell that such mistakes would get quickly sussed out, I dunno. Maybe?

There's probably some approach that works here, somehow or other.

I am wondering if we have tests that assert that certain code does not compile? If so, where can I find those?

We do that in clang-plugin tests: https://searchfox.org/mozilla-central/search?q=expected-error

In particular, TestAssertWithAssignment looks relevant to the problem at hand: https://searchfox.org/mozilla-central/source/build/clang-plugin/tests/TestAssertWithAssignment.cpp

Severity: normal → S3
You need to log in before you can comment on or make changes to this bug.