Something doesn't have to be C to be useful, but it has to support all C language features to be C.
Fine.
XC8 on PIC18 supports every C feature.
Sure. PIC18 is considerably better in this regard than the earlier ones.
Enhanced midrange PIC16 (so 15yo parts) can as well but there is too little memory for it to be useful, so they chose to not implement them in the compiler
"too little memory" doesn't make sense. PIC16F18877 = 4k RAM and 56k flash.
That's double the size of the extremely popular ATMega328, which the entire C++-based Arduino ecosystem grew up around. Or the present day CH32V003, for that matter(2k RAM, 16k flash).
Heck, before the CH32V003 happened I regularly programmed the 512 byte RAM, 8k flash ATTiny85 in C/C++. There are of course severe limits on how MUCH of anything you can do, but no limit on what C features you can use to do it: pointers, pointers to functions, recursion ... it's all fine. The biggest hassle with all the AVRs is that you need to use an extension to C to use special pointers to access constant data in flash instead of having them copied to RAM at program startup. Everything
works if you don't do that -- you just gobble up RAM quickly if you have a lot of string constants etc.
The truth is that enhanced midrange PIC16 can NOT properly support C using native code. It's not a question of "chose to not implement them in the compiler". It is simply
impossible.
The better support for pointers to data is of course welcome.
But recursion is extremely limited with only an 8 level return address stack that is not accessible by software: no PUSH or POP etc.
But, worst, function pointers are not properly supported. You can fake them within a single compilation unit by knowing all possible functions that a given pointer can point to, and then make a jump table to them, and represent the function pointer as an index into the table.
That does not permit such standard C uses of function pointers as qsort() or bsearch().
Ironically, on PIC16 you can support C++ virtual functions more easily than C function pointers.
Even Tiny AVR has no problems with any of this. The stack is in RAM, fully accessible, limited only by RAM size. Function pointers are fully supported using ICALL. Recursion is limited only by RAM.