Skip to content

[clang] Linker failure for std::visit with a templated lambda using a forward declared templated function #115731

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Closed
StefanPaulet opened this issue Nov 11, 2024 · 9 comments · May be fixed by #117167
Labels
clang:frontend Language frontend issues, e.g. anything involving "Sema" diverges-from:gcc Does the clang frontend diverge from gcc on this issue diverges-from:msvc Does the clang frontend diverge from msvc on this issue

Comments

@StefanPaulet
Copy link

StefanPaulet commented Nov 11, 2024

#include <type_traits>
#include <variant>

using MyType = std::variant<double, int>;

template <typename T>
auto foo(T&& arg) -> std::remove_cvref_t<T>;

auto bar(MyType const& v) {
    auto callable = []<typename Arg>(Arg&& arg) -> MyType {
        return foo(std::forward<Arg>(arg));
    };
    return std::visit(callable, v);
}

template <typename T>
auto foo(T&& arg) -> std::remove_cvref_t<T> {
    return arg;
}

int main() {
    MyType b {5.3};
    bar(b);
}

https://godbolt.org/z/n54f19hn5

It seems that only the declarations get generated for foo, but no definitions. However, if foo is no longer forward declared, everything works: https://godbolt.org/z/c1WY647af.

Diagnostics:

/opt/compiler-explorer/gcc-snapshot/lib/gcc/x86_64-linux-gnu/15.0.0/../../../../x86_64-linux-gnu/bin/ld: /tmp/example-c83671.o: in function `std::variant<double, int> bar(std::variant<double, int> const&)::$_0::operator()<double const&>(double const&) const':
<source>:11:(.text+0x315): undefined reference to `std::remove_cvref<double const&>::type foo<double const&>(double const&)'
/opt/compiler-explorer/gcc-snapshot/lib/gcc/x86_64-linux-gnu/15.0.0/../../../../x86_64-linux-gnu/bin/ld: /tmp/example-c83671.o: in function `std::variant<double, int> bar(std::variant<double, int> const&)::$_0::operator()<int const&>(int const&) const':
<source>:11:(.text+0x3f5): undefined reference to `std::remove_cvref<int const&>::type foo<int const&>(int const&)'
@github-actions github-actions bot added the clang Clang issues not falling into any other category label Nov 11, 2024
@StefanPaulet
Copy link
Author

Might be related to #57561

@AaronBallman AaronBallman added the clang:frontend Language frontend issues, e.g. anything involving "Sema" label Nov 11, 2024
@llvmbot
Copy link
Member

llvmbot commented Nov 11, 2024

@llvm/issue-subscribers-clang-frontend

Author: None (StefanPaulet)

```cpp #include <type_traits> #include <variant>

using MyType = std::variant<double, int>;

template <typename T>
auto foo(T&& arg) -> std::remove_cvref_t<T>;

auto bar(MyType const& v) {
auto callable = []<typename Arg>(Arg&& arg) -> MyType {
return foo(std::forward<Arg>(arg));
};
return std::visit(callable, v);
}

template <typename T>
auto foo(T&& arg) -> std::remove_cvref_t<T> {
return arg;
}

int main() {
MyType b {5.3};
bar(b);
}

https://godbolt.org/z/n54f19hn5

It seems that only the declarations get generated for `foo`, but no definitions. However, if `foo` is no longer forward declared, everything works: https://godbolt.org/z/c1WY647af.
</details>

@AaronBallman AaronBallman added diverges-from:gcc Does the clang frontend diverge from gcc on this issue diverges-from:msvc Does the clang frontend diverge from msvc on this issue labels Nov 11, 2024
@shafik
Copy link
Collaborator

shafik commented Nov 13, 2024

Adding diagnostics b/c it helps w/ searchability for folks looking for the same issue.

@StefanPaulet
Copy link
Author

Managed to reduce the code and remove all includes:
https://godbolt.org/z/aMdr9P4eY

Also found that when the lambda has a deduced return type or when it is not locally declared inside the function everything works:
https://godbolt.org/z/dqGdW381M

The problem seems to be that a locally declared lambda without a deduced return type gets eagerly instantiated and that it recursively tries to instantiate foo before it has a definition.

@EugeneZelenko EugeneZelenko removed the clang Clang issues not falling into any other category label Nov 19, 2024
@StefanPaulet
Copy link
Author

I would like to try and tackle this issue. However, I'm having a hard time understanding what the expected behaviour should be.
I looked into Sema::PerformPendingInstantiations and the problem might be that if a function is not instantiated after InstantiateFunctionDefinition is called, no attempt to do it again at the end of the translation unit is made.
On the other hand, the problem might also be that instantiating operator() on the lambda should not try to recursively instantiate foo.
Any indications?

@zyn0217
Copy link
Contributor

zyn0217 commented Nov 19, 2024

Also found that when the lambda has a deduced return type or when it is not locally declared inside the function everything works:
https://godbolt.org/z/dqGdW381M

The symptom then looks like a duplicate of #35052 to me. I tried to instantiate the local lambda eagerly so the constant evaluation would find a definition before it evaluates anything, but changing that behavior turns out to break DeduceReturnType for one case, so it gets reverted, unfortunately.

@StefanPaulet
Copy link
Author

The symptom then looks like a duplicate of #35052 to me. I tried to instantiate the local lambda eagerly so the constant evaluation would find a definition before it evaluates anything, but changing that behavior turns out to break DeduceReturnType for one case, so it gets reverted, unfortunately.

Yep, they seem to be related. Although one is an issue of generic lambdas being too eagerly instantiated, and the other of a generic lambda not getting instantiated for constant evaluation (I think).
I've found out the issue actually goes much deeper, as instantiation for generic lambdas has some problems. I will have a look at it based on the discussion from #117167

@shafik
Copy link
Collaborator

shafik commented Mar 20, 2025

Looks fixed in clang trunk but I have no idea why: https://godbolt.org/z/o4c8xfxYM

CC @erichkeane @cor3ntin

@zyn0217
Copy link
Contributor

zyn0217 commented Mar 21, 2025

Looks fixed in clang trunk but I have no idea why: https://godbolt.org/z/o4c8xfxYM

CC @erichkeane @cor3ntin

#126723

@shafik shafik closed this as completed Mar 21, 2025
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
clang:frontend Language frontend issues, e.g. anything involving "Sema" diverges-from:gcc Does the clang frontend diverge from gcc on this issue diverges-from:msvc Does the clang frontend diverge from msvc on this issue
Projects
None yet
6 participants