После поиска и нескольких перерывов при атаке на другие проблемы, я нашел ответ, который ясен и лаконичен (во всяком случае, для стандартного):
Вызов функции через выражение, тип функции которого имеет языковую связь, которая отличается от языковой связи типа функции определения вызываемой функции, не определена. [5.2.2 / 1]
Я по-прежнему утверждаю, что на фундаментальном уровне проблематично использовать текст из стандарта C ++ для определения поведения библиотеки C, скомпилированной с помощью компилятора C, и то, как именно эта межязыковая совместимость работает, очень зависит от реализации; тем не менее, это наиболее близкий, я думаю, любой из стандартов (в настоящее время) может надеяться определить такое взаимодействие.
В частности, это неопределенное поведение (и оно не использует библиотеку C, чтобы не возникало проблем):
void call(void (*pf)()) { pf(); } // pf() is the UB
extern "C" void f();
int main() { call(f); }
// though I'm unsure if a diagnostic is required for call(f)
Comeau дает диагностику на call(f)
(хотя он может сделать это, даже если диагностика не требуется).
Это не неопределенное поведение, и показывает, как включить языковые связи в тип указателя на функцию (через typedef):
extern "C" typedef void F();
void call(F* pf) { pf(); }
extern "C" void f();
int main() { call(f); }
Или можно написать:
extern "C" {
typedef void F();
void f();
}
void call(F* pf) { pf(); }
int main() { call(f); }