<table border="1" cellspacing="0" cellpadding="8">
    <tr>
        <th>Issue</th>
        <td>
            <a href=https://github.com/llvm/llvm-project/issues/121797>121797</a>
        </td>
    </tr>

    <tr>
        <th>Summary</th>
        <td>
            [C++20][modules] Combining modules, concepts (and a JSON library) leads to a linkage error
        </td>
    </tr>

    <tr>
      <th>Labels</th>
      <td>
            new issue
      </td>
    </tr>

    <tr>
      <th>Assignees</th>
      <td>
      </td>
    </tr>

    <tr>
      <th>Reporter</th>
      <td>
          AlbertSSj
      </td>
    </tr>
</table>

<pre>
    I have a small module (A) that defines a template function on objects that can be casted to an nlohmann::json object, and a concept to enable the operation. I have a separate module (B) to use the operation.
When used in a module, this leads to a linkage error. The linker seems to believe that the symbols for some of the JSON operation have to be provided by module A.

What is interesting is that by forcing module A to generate the symbols, by creating an exported function that does a bunch of JSON conversions, the linkage can complete successfully. So for now I'm adding one by one the JSON conversions that are required by B in A.

I don't even need to use my function to cause the issue, just defining a JSON object is enough.

Below is a set of files that can reproduce the problem:

**module_a.cppm**

```c++
module;

#include <nlohmann/json.hpp>

export module module_a;

namespace module_a {

template <typename T>
concept FromOrderedJson = requires(T t) {
    { static_cast<nlohmann::ordered_json>(t) };
};

template <typename T>
concept FromJson = requires(T t) {
    { static_cast<nlohmann::json>(t) };
};

export template <typename T>
 requires(FromOrderedJson<T>)
std::string MakeString(T value)
{
    return nlohmann::ordered_json(value);
}

export template <typename T>
 requires(FromJson<T>)
std::string MakeString(T value)
{
    return nlohmann::json(value);
}

} // namespace module_a
```

**module_b.cpp**
```c++
module;

#include <iostream>
#include <nlohmann/json.hpp>

export module module_b;
import module_a;

namespace {
struct MyJsonData
{
    std::string a;
    int b;
    bool c;
};

void to_json(nlohmann::json& j, const MyJsonData& p)
{
    j["a"] = p.a;
    j["b"] = p.b;
    j["c"] = nlohmann::json(p.c);
}
} // namespace

int main(int argc, char* argv[])
{
    MyJsonData value;
    auto x = nlohmann::json(value);
}
```

**CMakeLists.txt**
```cmake
add_library(module_a SHARED)
target_sources(
    module_a
    PUBLIC FILE_SET modules TYPE CXX_MODULES FILES
        module_a.cppm
)
target_compile_options(
 module_a
    #PUBLIC
 #-fexperimental-modules-reduced-bmi
)
target_link_libraries(
 module_a
)
add_executable(module_b)
target_sources(
    module_b
 PUBLIC FILE_SET modules TYPE CXX_MODULES FILES
 module_b.cpp
)
target_link_libraries(
    module_b
    PUBLIC
 module_a
)
```

The error is this:
```
/usr/bin/ld: module_b.cpp.o: in function `_ZN8nlohmann10basic_jsonISt3mapSt6vectorNSt7__cxx1112basic_stringIcSt11char_traitsIcESaIcEEEblmdSaNS_14adl_serializerES2_IhSaIhEEEC2IRKbbTnNSt9enable_ifIXaantsr6detail13is_basic_jsonIT0_EE5valuesr6detail18is_compatible_typeISC_SH_EE5valueEiE4typeELi0EEEOT_':
module_b.cpp:17931:(.text._ZN8nlohmann10basic_jsonISt3mapSt6vectorNSt7__cxx1112basic_stringIcSt11char_traitsIcESaIcEEEblmdSaNS_14adl_serializerES2_IhSaIhEEEC2IRKbbTnNSt9enable_ifIXaantsr6detail13is_basic_jsonIT0_EE5valuesr6detail18is_compatible_typeISC_SH_EE5valueEiE4typeELi0EEEOT_[_ZN8nlohmann10basic_jsonISt3mapSt6vectorNSt7__cxx1112basic_stringIcSt11char_traitsIcESaIcEEEblmdSaNS_14adl_serializerES2_IhSaIhEEEC2IRKbbTnNSt9enable_ifIXaantsr6detail13is_basic_jsonIT0_EE5valuesr6detail18is_compatible_typeISC_SH_EE5valueEiE4typeELi0EEEOT_]+0x34): undefined reference to `decltype ((nlohmann::(anonymous namespace)::to_json({parm#1}, (std::forward<bool const&>)({parm#2}))),((void)())) nlohmann::adl_serializer<bool, void>::to_json<nlohmann::basic_json<std::map, std::vector, std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> >, bool, long, unsigned long, double, std::allocator, nlohmann::adl_serializer, std::vector<unsigned char, std::allocator<unsigned char> > >, bool const&>(nlohmann::basic_json<std::map, std::vector, std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> >, bool, long, unsigned long, double, std::allocator, nlohmann::adl_serializer, std::vector<unsigned char, std::allocator<unsigned char> > >&, bool const&)'
```

Which basically means that the symbol for the JSON conversion from bool is missing (I think).

In case it helps, I'm using clang version 19.1.6 and cmake version 3.28.3.
</pre>
<img width="1" height="1" alt="" src="http://email.email.llvm.org/o/eJzsWEuP4zYS_jXsC9GGRbVfBx_cbjXi7GQmiDrI7F4Miirb7KFILUl52vvrF0VKsux2BpPdzWkDCLBF1uOrF1kq7pzca4AlmTySydMdb_zB2OVKFWB9nr_eFaY8LTf0wI9AOXUVV4pWpmwUUMLmK8IW1B-4pyXspAZHOfVQ1Yp7oLtGCy-NpvgUryC8i7SCa1oAFdx5KKk3lGuqlTlUXGuSrki6enU9D2FrynVJORVGC6g9MoDmhQLqD0BNDZajmhE9w4SaW4RwRvoYkBrauGs2Ml79dgCNOyWVmvKWCxX7g3RUAS9dgEmV1F_4HihYa-yIvhwgLIGlDqAKRAUoCUeIlqImd6oKoxzdGUudqYCaXVj_Mf_08QwjQg_8tLbmKEsoaXHqLFghzICUeyodldqDBeel3uNrUFacUIfApY4LBe5BQ3DGAAzaVpyosMCDCK4pvNXGYjz6sMW4mhDUotHigMgDamH0EayTRrvoJeg9g7EVpqoVeKCuEQKc2zVKnUY0N8EH2nylG8JmFeVlicqNBgSDP71fBhoiDm6BWvhnI230yyOGqvPKhpZGEzbzFI6gqYaYVhjr6jQwyFDBuwSQzjUhxq-Na9M3eKKNS8g9dC1o0-wPraJHUOYrrmKOefTHTioYpLWF2pqyEVFHbU2hoMKcDuyE4RODs-UjUddVXGq3p-P4CMIe8Rm3tCR97ASkUgvVlEBJuu5rhj1jwYwOdU3SLFLGcHaJ0KnsBWlegau5OG9RMmv3-gIm6dqfakBa-hIldzX4bE31yZZgofwRa5WkT114HGHzF-qx3qJISin-o85zL8UWy34IPhS8ibK2aAdqYvNWwFMLuf_z_fj-J8C-B1Dr62_hGmK48h1J14GILch45XwZ9TpvMR1_4l8gD38D-CNXmLSLAKAzwYJv7PUJeuFQNu8Ze_D_KfI_D_K3oZLZEyXsmbBn-j55h8Vzo9QKLLVzpf3BMpPGeQu8amvrvyvBIiqR1WDvZl1GZzlvG-HpTyd0-xP3_MKN165v5eCW1J4W59fCGEXF-9Q9GolHZZcmtwIypa94TAqj3QUQNqX1dVxfsY1gjBPGyOQpFF89GqBq94uL_eLdvhjs38yReiSuM-RGekQT0RMVl8iGf7ndi2DPgVvCVvh-jM3PtTFnW9sk7mHyxhv69vvwbqbwrfxcY7F8kM67kX_zNzK04l_QDF6WWyULy-2JsHl_ZOc_rH7JWtye2z34rTONFaFYW6yDEsHXn399_LBZ0-fNh2ybZy_ttqMvf_85o-vPn7c_fXr69UOWB4q8ZRrKibcWGjDQije-VLA1tY9NQdB-pZqwNGrHd8LS-x281WBlBdpzdd8iubeA92d5X1TyWg02Ga0fJNzQEonRWfAGovHYJJ79VXyXowp8_eNeujhpvgf2lcY-NDdNukoe7DtDCxp7P-naDmNIxZ4bZwl7LjDznxUeFBcgRwZXpD63R2Q63v7jY38GJOOCOynC0bDJfVrxOvfTIwhv7Mfcz7Zb8faWJAmLZPEI2ojcJwnW1tZbLr3biCznG5FlWaGqMucf823ywEu1dWAlV_JfYLOcbTeHnG8OWZat2eaXvxXFi_6Y-0Vs87dyt_nMufbOTkvwXKoklW47QPcy3mbZJFTdmWYuXchL7iUKwXttk6-3-Q89bSazB1zOPshxlmWfXraEzaIrL8KZrpLZIk1wh81HHt786P_eUZPHv1zwRNjj-C19CCf9ijY6fgSX1MIOLGgRPujIdFyCUMiMH6LvblnC5lwbfapM4wZ3V5BJ0tX5ciazx5rbirA0wSuFrVFc3wLsjP3KbUnSdbzr8bombNq2aUNuFrgX3bOOoLATaCm7vavL7TISrSKEEVjT7BLvdSN9DgFJ1z3qitcooX-PKXOx1ObOUErMH5Ku4yU-IB5kU7eNDhhQcKWM4Kik36ctTWePMti7rmmjw3Ck7BdK0xRxMHBDHFt_2183zEzXvYp3lgxxXlJFwEPQl9Ge_-X4P9_x0_e-x5qZvb-sfztIcaDBf1ypE62Ad0ON80QmTEZuTD_ozpoq6pGOVtI57PMJm2_w3tdfCFt0MxBNBXdApacHUHUYzMQxSxN4hOJ6TzuxyWKUjKZhsBZ6zH4jHbH5KB3dlcu0XKQLfgfLZJZOk_l4MZndHZbTB148AHsodrOE7yZTsWCT-TSdj8U8FYw93MklG7PJOBlPkylbJLMRFGxWzMV8MZmMUzYD8jCGiks1UupYjYzd34VRzDJhyWwxu1O8AOWW8UNAw9duUIMfBHd2iUz3RbN35GGsQuPci_HSqzDIXMfvOjbGI3ry2DZv-EGxNlUR5zzdYvyyEVB7R8NJXHYjoL7fXvzuBPCusWp58L4ODVj4-thLf2iKkTAVdl3q2P3c19bEceZzMMgR9txafFyyfwcAAP__W6rfLw">