The moral of the story is, just let dplyr use these hybrid evaluation functions, and there currently is no way for you to access enough information at the R level to create custom ones for your own use.
this has changed, maybe due to new behaviour, a breaking change
Some thoughts about how it works and why you observe this:
some of dplyr magic comes from something called hybrid evaluation. You'll find some reference of in release candidate blog post
basically, dplyr executes some codes in C++ not R, and try to identify some function call to use either c++ call or R call. (or at least I think of it that way... ). So when it identifies row_number() inside a mutate or a summary, it does not call the R version. (At least version <= 0.7.6).
There is some C code about row_number dispatch that illustrate this
new version has a help hybrid_call to see some of that dark magic
#> Attachement du package : 'dplyr'
#> The following objects are masked from 'package:stats':
#> filter, lag
#> The following objects are masked from 'package:base':
#> intersect, setdiff, setequal, union
#>  '0.8.0.9000'
hybrid_call(mutate(row = row_number()))
#> <standard evaluation>
#> call : mutate(row = row_number())
it does not back me up in new >= 0.8 version though as it said standard evalutation...
But as you found code changed and R function row_number() now deals with empty x.
NEWS from 0.8.0 says
Hybrid evaluation has been completely redesigned for better performance and stability.
So it may be why difficult to explain or illustrate previous behavioir
Hope it is not too confusing and it helps in some ways