The [[noreturn]] attribute can be applied to functions that are not meant to return. For example:
[[noreturn]] void will_throw() { throw std::r
I have grepped through the standard, and there's no indication that either [[noreturn]] specifically, or attributes more generally, are "inherited" by overriding functions.
It's hard to prove a negative, and the standard actually doesn't declare this either way but, since A::f() and B::f() are still distinct functions and the only behaviour described is defined in terms of functions, I think you're safe to mark A::f() as [[noreturn]].
That being said, I can't imagine what useful optimisation the compiler could subsequently perform, given the dynamic dispatch.