hsutter / cppfront

A personal experimental C++ Syntax 2 -> Syntax 1 compiler
Other
5.24k stars 224 forks source link

[SUGGESTION] Allow `main()` to be `constexpr` and to be called from user code #1054

Closed LocalSpook closed 1 week ago

LocalSpook commented 2 months ago

In C++, main cannot be called from user code and cannot be constexpr (section [basic.start.main] of the standard).

The workaround is to define main to do nothing but delegate to an ordinary function without these restrictions:

// Compute 10^argc, recursively.
constexpr int my_main(const int argc, const char * const * const argv) {
    return (argc <= 0) ? 1 : 10 * my_main(argc - 1, argv + 1);
}

// Test main() at compile time.
static_assert(my_main(2, (const char *[]){"a", "b", nullptr}) == 100);

int main(int argc, char ** argv) {
    return my_main(argc, argv);
}

I propose that cppfront does this automatically, making something like the following code valid:

main: (args) -> int == /* note ==, not = */ (args.argc <= 0) ? 1 : 10 * main(args.argc - 1, args.argv + 1);

This would reduce main's inconsistency and eliminate potential undefined behavior.

Cppfront would have to

jcanizales commented 2 months ago

Other than consistency (which is a good reason on its own), are there actual use cases for this?

SebastianTroy commented 2 months ago

Does constexpr main make sense given that args are runtime parameters by design?

LocalSpook commented 2 months ago

The best example I've been able to come up with is the POSIX test/[ command. It exists to return 0 if the given condition is true, 1 if false. With constexpr main, you could test a subset of its functionality at compile time.

static_assert(main("[", "-2", "-le", "0", "-a", "foo", "=", "foo", "]") == 0);
Xeverous commented 1 week ago

@LocalSpook True but in such case you might aswell go the 2-layer main approach and just test the inner function.

I think that the workaround to this issue is so easy to come up with and so trivial to implement that it is not worth the bureaucratic effort of changing the standard.

On the contrary, is there any "official justification" why the main function has such special rules?

hsutter commented 1 week ago

Thanks! I'm not against doing this, but I don't think it's one of the more pressing safety or simplicity issues with C++ and I need to prioritize... so I'll close this for the time being in favor of other bug fixes and new features. But I appreciate the suggestion, and thanks for understanding!