Taking pointer to member std::string::size fails to link with libc++ but works with libstdc++

跟風遠走 提交于 2019-12-05 19:51:40

This looks like a libc++ bug by this thread: _LIBCPP_INLINE_VISIBILITY and std::string::length which doing something similar and Howard Hinnant's response is:

I believe this is due to a poor interaction in the compiler between extern templates and __attribute__ ((__always_inline__)). If std::string is not declared extern template, then the compiler will outline a size() member and you won't get this link error.

In my opinion, clang should not assume that extern templates have definitions for inlined members, especially those marked always_inline, and the fact that it does is a clang bug resulting in the link error you see.

The rationale for the use of always_inline in libc++ is to control the ABI of libc++. In the past I have watched compilers use different heuristics from release to release on making the inline/outline decision. This can cause code to be silently added to and removed from a dylib. With the use of always_inline, I am telling the compiler to never add that code to the libc++.dylib binary.

Each of the macros defined and used by libc++ can be overridden.

_LIBCPP_INLINE_VISIBILITY controls how an inlined function is attributed and defaults to:

#ifndef _LIBCPP_INLINE_VISIBILITY
#define _LIBCPP_INLINE_VISIBILITY __attribute__ ((__visibility__("hidden"), __always_inline__))
#endif

You can turn this off with:

-D_LIBCPP_INLINE_VISIBILITY=""

And extern templates are done with:

#ifndef _LIBCPP_EXTERN_TEMPLATE
#define _LIBCPP_EXTERN_TEMPLATE(...) extern template __VA_ARGS__;
#endif

This latter one is more difficult to "turn off". The incantation is:

-D'_LIBCPP_EXTERN_TEMPLATE(...)='

Using either (or both) of these workarounds will silence your link error. But a bug report against clang might be a better long term solution.

I can not reproduce this on coliru but I can on wandbox and using optimization which uses the -O2 flag makes the problem go away. I was not able to make wandbox accept the -D options suggested above, so not sure if that works.

On my local machine Howard's solution works:

clang++ -D_LIBCPP_INLINE_VISIBILITY="" -D'_LIBCPP_EXTERN_TEMPLATE(...)='

I have not found a bug report, if I don't find one it may make sense to file one.

Filipe Figueiredo

After looking into Shafik Yaghmour information, I found a solution that doesn't require modifying the compilation flags.

The solution is forcing the compiler to instantiate the extern template class. The final code is the following:

#include <string>

template class std::basic_string<char>;

int main()
{
    std::string::size_type (std::string::*function)() const = &std::string::size;
    return 0;
}

More information here: using extern template (C++11)

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!