While this does not work for OP's circumstance as posted, on account of bar() invoking foo() from within the library's header, there is a straightforward solution that is applicable to anyone facing the same issue without that specific constraint. So it could be useful to other people landing here.
Effectively, you want two different sets of headers. One when users of the library use it, and one when the library itself uses it. We can do this in this case because [[deprecated]] is not supposed to have any influence on the resulting generated code.
You "could" just maintain both of them separately, but that would obviously be very fragile. Thankfully, the language does provide us with a way to have two "versions" of the same header in one single file: The oft-maligned, and to be fair also oft-misused, Macro.
As a bonus, if [[deprecated]] happens to be what forces users to use C++14 or above, you can provide support for older versions of the standard at the same time by checking __cplusplus or the appropriate feature macro.
//mylib.h
#if !defined(MY_LIB_NO_DEPRECATE) && __has_cpp_attribute(deprecated)
#define MY_LIB_DEPRECATED [[deprecated]]
#else
#define MY_LIB_DEPRECATED
#endif
// ...
MY_LIB_DEPRECATED void foo();
MY_LIB_DEPRECATED void bar();
// ...
#undef MY_LIB_DEPRECATED
Compile the library with -DMY_LIB_NO_DEPRECATE, and it's like the deprecation warnings are not there for that specific phase of the process. Users will still get all the deprecation warnings, unless they explicitly opt out of them by also defining MY_LIB_NO_DEPRECATE.
Don't get spooked by the use of macros here. Using them to distinguish between internal/external versions of the same header is a common and well established practice. Windows dlls would be practically impossible to write without it.
In OP's case, if moving bar()'s definition from the header into the library's implementation is a possibility, then they should be good to go as well.