Constructing a std::move_only_function with a std::bind_front object does not compile with all clang versions

I am using clang extensively due to it’s compilation speed compared to other compilers and liking it so far.

While trying to upgrade clang in our codebase from 19 to 21 I ran into an issue when compiling code like this:

struct SomeObject {
    void fn() noexcept;
};

std::move_only_function<void() noexcept> example1(SomeObject* o) {
    return std::bind_front(&SomeObject::fn, o);
}

The compile error that I get is the following:

<source>:24:12: error: no viable conversion from returned value of type '_Bind_front_t<void (SomeObject::*)() noexcept, SomeObject *&>' (aka '_Bind_front<void (SomeObject::*)() noexcept, SomeObject *>') to function return type 'std::move_only_function<void () noexcept>'
[...]

What is strange to me is that it seems quite inconsistent with which clang versions it fails to compile. Here is a compiler explorer link ( Compiler Explorer ) with the following versions:

  • compiler explorer x64-64 clang 21.1.0 - ok
  • compiler explorer x64-64 clang 20.1.0 - error
  • compiler explorer x64-64 clang 19.1.0 - ok

I also did some tests of my own: (linux runs in docker containers, windows runs on the host)

  • linux (x86_64-pc-linux-gnu) clang 19.1.7 - ok
  • linux (x86_64-pc-linux-gnu) clang 20.1.8 - error
  • linux (x86_64-pc-linux-gnu) clang 21.1.3 - error
  • windows (x86_64-pc-windows-msvc) clang 21.1.3 - ok
  • all other versions on windows that I tried worked as well

I also found a another snippet that might be related:

struct SomeObject {
    void fn() noexcept;
};

using T = std::invoke_result_t<decltype(std::bind_front(
    &SomeObject::fn, std::declval<SomeObject*>()))>;
static_assert(std::is_same_v<T, void>);

Here it seems that std::bind_front isn’t invokable, which can’t be right?

Compiler Explorer: Compiler Explorer


I am wondering:

  • Am I doing something wrong here?
  • Is this one of the things that clang just doesn’t support yet, out of the C++23 standard? If this is true, why could it be that clang 19 works?

Thanks for your time!

Can you please file this as a Github issue instead? You should add the libc++ tag on the issue since that would be a libc++ issue, not a Clang issue. That is the preferred way of reporting these kinds of issues. Someone should be able to take a look pretty quickly since you have reproducers (which is great, thanks for that).

Cheers!

This is a good point you are making.

Since I am actually using libstdc++, I got the suspicion that maybe my own containers (and maybe the ones from compiler explorer too) use an incompatible version.

In our containers, we also install GCC 14, which I suspect brings the libstdc++ library.

I will test this first by using the official guide (A guide to Dockerfiles for building LLVM — LLVM 22.0.0git documentation) to build a docker container and see whether the code snippets work or not that way.

Looks like it is indeed a problem with the version of libstdc++ that is installed in the system.

I just built a docker container for clang 21.1.4 using the instructions from About — LLVM 22.0.0git documentation . In there I had to install libstdc++-12-dev (which installed libstdc++ version 12.2.0-14+deb12u1) and then the example programs worked flawlessly.


Working container (built according to docs) with version 21.1.4:

root@f66ad858d547:/# clang -v
clang version 21.1.4 (https://github.com/llvm/llvm-project.git 222fc11f2b8f25f6a0f4976272ef1bb7bf49521d)
Target: x86_64-unknown-linux-gnu
Thread model: posix
InstalledDir: /usr/local/bin
Found candidate GCC installation: /usr/lib/gcc/x86_64-linux-gnu/11
Found candidate GCC installation: /usr/lib/gcc/x86_64-linux-gnu/12
Selected GCC installation: /usr/lib/gcc/x86_64-linux-gnu/12
Candidate multilib: .;@m64
Selected multilib: .;@m64
root@f66ad858d547:/# echo "#include <functional>" | clang -x c++ -std=c++23 -stdlib=libstdc++ -dM -E - | grep -e "__GLIBC__\|__GLIBC_MINOR__"
#define __GLIBC_MINOR__ 36
#define __GLIBC_PREREQ(maj,min) ((__GLIBC__ << 16) + __GLIBC_MINOR__ >= ((maj) << 16) + (min))
#define __GLIBC__ 2

Broken container (built with our flawed approach) with version 21.1.3:

root@7aa29af6d985:/workspaces# clang -v       
Ubuntu clang version 21.1.3 (++20251017113517+570c4c944338-1~exp1~20251017113708.50)
Target: x86_64-pc-linux-gnu
Thread model: posix
InstalledDir: /usr/lib/llvm-21/bin
Found candidate GCC installation: /usr/lib/gcc/x86_64-linux-gnu/13
Found candidate GCC installation: /usr/lib/gcc/x86_64-linux-gnu/14
Selected GCC installation: /usr/lib/gcc/x86_64-linux-gnu/14
Candidate multilib: .;@m64
Selected multilib: .;@m64
root@7aa29af6d985:/workspaces# echo "#include <functional>" | clang -x c++ -std=c++23 -stdlib=libstdc++ -dM -E - | grep -e "__GLIBC__\|__GLIBC_MINOR__"
#define __GLIBC_MINOR__ 39
#define __GLIBC_PREREQ(maj,min) ((__GLIBC__ << 16) + __GLIBC_MINOR__ >= ((maj) << 16) + (min))
#define __GLIBC__ 2

Working container (built with our flawed approach) with version 19.1.7:

root@a2a60c68eff6:/workspaces# clang -v
Ubuntu clang version 19.1.7 (++20250804090312+cd708029e0b2-1~exp1~20250804210325.79)
Target: x86_64-pc-linux-gnu
Thread model: posix
InstalledDir: /usr/lib/llvm-19/bin
Found candidate GCC installation: /usr/lib/gcc/x86_64-linux-gnu/13
Found candidate GCC installation: /usr/lib/gcc/x86_64-linux-gnu/14
Selected GCC installation: /usr/lib/gcc/x86_64-linux-gnu/14
Candidate multilib: .;@m64
Selected multilib: .;@m64
root@a2a60c68eff6:/workspaces# echo "#include <functional>" | clang -x c++ -std=c++23 -stdlib=libstdc++ -dM -E - | grep -e "__GLIBC__\|__GLIBC_MINOR__" 
#define __GLIBC_MINOR__ 39
#define __GLIBC_PREREQ(maj,min) ((__GLIBC__ << 16) + __GLIBC_MINOR__ >= ((maj) << 16) + (min))
#define __GLIBC__ 2

To me this looks like some kind of incompatibility between clang > 19 and libstdc++ 2.39.

For our purposes, we are going to ensure that clang uses the working libstdc++ 2.36 in our containers instead of the newer one from a more recent GCC installation.

The question is, is this still a bug that I should report somewhere or is this expected behavior?

Oh, I hadn’t understood your setup. I initially thought you were using libc++, not libstdc++.

I believe it would make sense to report this to libstdc++, since the issue seems to be that it’s broken with newer Clangs. I’m not certain what their stance is with respect to support Clang so I don’t know whether they will be willing to investigate. However, if they do investigate and it turns out that their code is conforming, then I would expect them to send it back to Clang instead for investigation – it’s usually how I’d expect the bug to flow through library/compiler.

Ok, thanks for your insight!

I will try to create a bug on libstdc++ over at https://gcc.gnu.org/bugzilla/ next week, when I have more time.