Solved Weird libc++ experience

jbo@

Developer
I'm sorry for the weird title of this thread but I'm really not sure what I'm currently experience.
The problem I am experiencing is that devel/llvm13 doesn't know about std::invocable.

Minimum test case as follows:

main.cpp:
Code:
#include <concepts>

void func(int);

int main()
{
    return std::invocable<decltype(&func), int>;
}

CMakeLists.txt:
Code:
cmake_minimum_required(VERSION 3.21)
project(llvm_test)

set(TARGET llvm_test)

add_executable(${TARGET})

target_compile_features(
    ${TARGET}
    PRIVATE
        cxx_std_20
)

target_sources(
    ${TARGET}
    PRIVATE
        main.cpp
)

Compilation output:
Code:
====================[ Build | llvm_test | Debug ]===============================
/usr/local/bin/cmake --build /home/jbo/projects/llvm_test/cmake-build-debug --target llvm_test -- -j 9
Scanning dependencies of target llvm_test
[ 50%] Building CXX object CMakeFiles/llvm_test.dir/main.cpp.o
/home/jbo/projects/llvm_test/main.cpp:6:42: error: expected '(' for function-style cast or type construction
    return std::invocable<decltype(&func), int>;
                          ~~~~~~~~~~~~~~~^
/home/jbo/projects/llvm_test/main.cpp:6:17: error: no member named 'invocable' in namespace 'std'
    return std::invocable<decltype(&func), int>;
           ~~~~~^
2 errors generated.
gmake[3]: *** [CMakeFiles/llvm_test.dir/build.make:72: CMakeFiles/llvm_test.dir/main.cpp.o] Error 1
gmake[2]: *** [CMakeFiles/Makefile2:83: CMakeFiles/llvm_test.dir/all] Error 2
gmake[1]: *** [CMakeFiles/Makefile2:90: CMakeFiles/llvm_test.dir/rule] Error 2
gmake: *** [Makefile:124: llvm_test] Error 2

The test case above compiles fine with both devel/gcc10 and devel/gcc11. But also devel/llvm-devel is struggling on this one.
I'm aware that std::invocable is a concept provided by the STL. It's not a compiler built-in language feature. Clang by default uses libc++.

The confusing part is that the same code on godbolt works fine, even when explicitly stating the use of libc++: https://godbolt.org/z/1P9b549qa
This would indicate that libc++ shipping with clang 13 implements std::invocable.

Could somebody explain to me what I'm missing here?
 
Does cmake really set the -std=c++20 flag? Unfortunately impossible to see in the build log. Standard libraries often hide declarations based on the standard version...
 
Interesting... setting set(CMAKE_CXX_STANDARD 20) actually makes this compile as expected.

I have to check the cmake documentation. So far I have been using
Code:
target_compile_features(
    ${TARGET}
    PRIVATE
        cxx_std_20
)
successfully with both GCC and MSVC.
 
Well, I have no idea about cmake (never used it), but the truth lies in the flags passed to the compiler :cool: maybe the construct you're using just checks for compiler support?

About GCC and MSVC: If you don't explicitly request a standard version, you get whatever the compiler defaults to.
 
I agree with what you say. I merely meant to communicate that I have used this successfully before but will certainly need to look into it.

From the cmake documentation of target_compile_features():
Specifies compiler features required when compiling a given target.
[...]
If the use of the feature requires an additional compiler flag, such as -std=gnu++11, the flag will be added automatically.

From other projects I have seen this working (by also checking the compiler flags passed to the compiler as well as by being able to use C++17 and C++20 features successfully).

I'll certainly check which flags are passed to clang in my test case above.
 
Which version of CMake are you using?
Which version of llvm are you using? clang -v

Have you tried to get CMake to output more info on the generated llvm command line command options generated?
Activate CMAKE_VERBOSE_MAKEFILE (see: CMAKE_VERBOSE_MAKEFILE) e.g.:
set(CMAKE_VERBOSE_MAKEFILE ON)

Compare the various outputs (especially those that differ in the desired result); for example with set(CMAKE_CXX_STANDARD 20) versus not with that set command and only:
Code:
target_compile_features(
    ${TARGET}
    PRIVATE
        cxx_std_20
)
 
I figured this out a couple of weeks/months ago but didn't come back to actually close the issue. So here's the update from my side.
TL;DR: libc++ from base was not recent enough.

The problem isn't or wasn't the C++20 compiler flag that is being passed to clang. Instead, the problem was that the libc++ from the base system was not recent enough.
When I posted this:
Interesting... setting set(CMAKE_CXX_STANDARD 20) actually makes this compile as expected.
I was actually misled. When I did that test I was sitting in a train with a newly acquired laptop that required stable/13 to be usable. The version of libc++ provided by base was more recent than on my desktop which was a 13.0-RELEASE machine at the time.
 
Back
Top