llvm / llvm-project

The LLVM Project is a collection of modular and reusable compiler and toolchain technologies.
http://llvm.org
Other
28.03k stars 11.58k forks source link

clang will not accept certain std::bind usages when -stdlib=libc++ is specified. #64445

Open edfvogel opened 1 year ago

edfvogel commented 1 year ago

The following (very contrived) program shows a program that is accepted when the g++ headers are used, but not when the libc++ headers are used.

Not sure if this is a bug in libc++, but it can pose a porting issue. Any comments are welcome.

Thanks so much,

Ed Vogel

Here is the reproducer from a cygwin session:

$ cat b1.cpp
#include <functional>
#include <stddef.h>
using namespace std;
struct sockaddr {
  int a;
  int b;
};
extern "C" {
  int bind (int, const struct sockaddr *, size_t);
}
void f (void) {
  int sock2;
  sock2 = bind(sock2, (struct sockaddr *)&sock2, sizeof(sock2));
}

VogelEd@XLB3502Q4E ~
$ clang -c b1.cpp

VogelEd@XLB3502Q4E ~
$ clang -c -stdlib=libc++ b1.cpp
b1.cpp:13:11: error: assigning to 'int' from incompatible type '__bind<int &,
      sockaddr *, unsigned long>'
  sock2 = bind(sock2, (struct sockaddr *)&sock2, sizeof(sock2));
          ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
1 error generated.

Note that if there is no assignment of the return value, the program compiles.

llvmbot commented 1 year ago

@llvm/issue-subscribers-clang-frontend

edfvogel commented 1 year ago

Oh...I note that Microsoft Visual Studio (2019) gives a similar error. So maybe it's more likely that this is a g++ extension.

This was noticed by someone that was upgrading to C++11. Their program was calling the C function bind(). They had included (which includes functional in C++11) and had done a "using namespace std;" As the C++ bind function was introduced in C++11, the program stopped compiling.

MitalAshok commented 1 year ago

libstdc++ seems to explicitly disable std::bind if the first argument is an integral or enumeration type:

https://gcc.gnu.org/git/?p=gcc.git;a=blob;f=libstdc%2B%2B-v3/include/std/functional;h=4a4b8b2b2e618be4c41e1fa1f55d154d2766bc19;hb=refs/heads/trunk#l852

Which libc++ does not have: https://github.com/llvm/llvm-project/blob/main/libcxx/include/__functional/bind.h#L366

This can be supported in libc++ with:

template<class _Fp, class ..._BoundArgs, class = typename enable_if<!is_integral<typename decay<_Fp>::type>::value && !is_enum<typename decay<_Fp>::type>::value>::type>

But this would be non-standard (it would break valid code that looks like:

static_assert(requires{ std::bind(1); });

but I would think the benefits outweigh this edge case)

cpplearner commented 1 year ago

std::bind(1) is UB anyway because of [func.bind.bind]/3.