1) Polymorphism is NOT functional programming. Using function pointers, which you seem to detest, is one aspect of functional programming. If you've only used C++, then you don't know what you're missing from languages like Lisp or JavaScript. (I should know. I was once like that.)
2) I seriously doubt the Linux kernel avoids function pointers. Ever heard of dispatch tables? Good C hackers know that smarter data structures make for simpler code.
3) Any feature that can go horribly wrong will go horribly wrong when you have a large project with lots of contributors. Everybody who successfully uses C++ on a large project has a huge "coding standards" document to keep the project from crashing and burning. I know Google has it, and I've seen others, too. Even I have it for my own personal C++ projects!
4) What Linus meant by "context dependency" is that you have to know the object's type in order to know what the function will do and you even have to figure out which version of the function will be called, based on the arguments. This is hell when you get a small patch in the middle of a larger function.
2) Declaring, initializing, and using dispatch tables requires a boat load of syntax, or GTK+ style macro hell. To the best of my recollection, Linux only goes to the trouble for a few large, complex subsystems, like networking and filesystems. Many other areas could probably benefit from it but cannot afford the price.
3) True. But once you climb the hill, you get to offload a lot of crap onto the compiler. Forever.
4) Linus already applies his +18 Axe of Correction to large functions and nesting depth. Anybody who reviews patches without a color-highlighting code browser deserves what they get.
However, I don't buy his argument that C++ is unsuitable because it's linguistically a high-context language. Part of this problem of context is solved by having disciplined, humble coders who know the limits of human intelligence. (I do not think these are new requirements that would exclude existing kernel contributors. C has, and the kernel uses, macros.) Part of the problem is solved by having a unified culture. The rest of the problem of "context" in C++ is really what would be called "state" in C, and of course you can't read state in the text of a C program. If you could magically create a unified and disciplined culture of C++ usage in the kernel, it would be fine. But that can't happen, so C++ is out of the question.
Which aspects of functional programming are you talking about?
For me it isn't better than function pointers, also because of method - function distinction we have 2 different incompatibile kinds of functions.
Passing around things that do work on other things -- easy with C++ worker objects, painful with C function pointers (or worse, pointers to structs full of function pointers).
If somebody uses too much overloading, reject their patch. If somebody makes a template tarpit, abuses operator(), or gets too fancy with operator overloading, send it back to 'em.
Context dependency bad? I like having the superclass define a contract so that you can ignore which subclass is being used. And C++ even rubs your nose in the name of the superclass, to avoid duck typing (which Python/Ruby use with near impunity anyway).
Polymorphism also gives you what amounts to functional programming without touching C's awful function pointer syntax. I suspect a lot of Linux code uses baroque switch/case or "if" statements just to avoid the pain of function pointers.
Edited.