Summary: C in itself doesn't know what exactly has gone wrong, it just knows something is wrong. So to maintain generic standard it just returns -1 as a signal to notify the caller that error has occurred, now it is up to the caller to check the errno for what exactly.
Brief Explanation:
The reason is that all the errno returned from the kernel are defined in the kernel itself.
C is just a generic programing language that receives the errno from the kernel and sets the variable according to it and returns -1 as a signal to indicate an error or failure. So C language in itself doesn't know what exactly has gone wrong, it just receives a signal from the registered error handler of the kernel that some error has occurred, and this error handler then supplies the actual error code.
So for maintaining generic nature C just returns -1. This is useful in other scenarios, lets say you were using C for some other purpose like embedded systems development. Now here several error codes are different from the Linux kernel error codes. So how does C know what error code to return if something goes wrong in the embedded system?
The answer is C doesn't actually know what is wrong. The registered error handler of the system will signal your C program that something has gone wrong and give you the appropriate error code for it and C will return -1 and set the errno.
Now, why can't C return the Errno: Answer is to maintain generic design. This allowed C developers to not care much about the return type of the error signal. If you interpret it correctly -1 returned by the C program is just a generic signal to userland API or shell script invoking the C program that something has gone wrong and if the invoker of C program needs to know what exactly has gone wrong they can check up the errno variable.