Skip to content

[Clang] Destructor definition is not compiled for local class in generic lambda initializing a variable template #132208

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
MagentaTreehouse opened this issue Mar 20, 2025 · 2 comments · Fixed by #134038
Labels
clang:codegen IR generation bugs: mangling, exceptions, etc. constexpr Anything related to constant evaluation lambda C++11 lambda expressions

Comments

@MagentaTreehouse
Copy link
Contributor

template <class>
constexpr auto f{[] (auto) {
    struct OnScopeExit { ~OnScopeExit() {} }
    pending;
}};

int main() {
    f<int>(0);
}

See https://compiler-explorer.com/z/6vneqf93z.

Warning and linker error since Clang 15:

<source>:3:26: warning: inline function '(anonymous class)::operator()(int)::OnScopeExit::~OnScopeExit' is not defined [-Wundefined-inline]
    3 |     struct OnScopeExit { ~OnScopeExit() {} }
      |                          ^
<source>:4:5: note: used here
    4 |     pending;
      |     ^
1 warning generated.
ASM generation compiler returned: 0
<source>:3:26: warning: inline function '(anonymous class)::operator()(int)::OnScopeExit::~OnScopeExit' is not defined [-Wundefined-inline]
    3 |     struct OnScopeExit { ~OnScopeExit() {} }
      |                          ^
<source>:4:5: note: used here
    4 |     pending;
      |     ^
1 warning generated.
/opt/compiler-explorer/gcc-snapshot/lib/gcc/x86_64-linux-gnu/15.0.1/../../../../x86_64-linux-gnu/bin/ld: /tmp/example-eeceaa.o: in function `auto f<int>::{lambda(auto:1)#1}::operator()<int>(int) const':
<source>:5:(.text._ZNK1fIiEMUlT_E_clIiEEDaS1_[_ZNK1fIiEMUlT_E_clIiEEDaS1_]+0x14): undefined reference to `f<int>::{lambda(auto:1)#1}::operator()<int>(int) const::OnScopeExit::~OnScopeExit()'
clang++: error: linker command failed with exit code 1 (use -v to see invocation)
@llvmbot llvmbot added the clang Clang issues not falling into any other category label Mar 20, 2025
@EugeneZelenko EugeneZelenko added clang:codegen IR generation bugs: mangling, exceptions, etc. lambda C++11 lambda expressions constexpr Anything related to constant evaluation and removed clang Clang issues not falling into any other category labels Mar 20, 2025
@llvmbot
Copy link
Member

llvmbot commented Mar 20, 2025

@llvm/issue-subscribers-clang-codegen

Author: None (MagentaTreehouse)

```c++ template <class> constexpr auto f{[] (auto) { struct OnScopeExit { ~OnScopeExit() {} } pending; }};

int main() {
f<int>(0);
}


See https://compiler-explorer.com/z/6vneqf93z.

Warning and linker error since Clang 15:
```console
&lt;source&gt;:3:26: warning: inline function '(anonymous class)::operator()(int)::OnScopeExit::~OnScopeExit' is not defined [-Wundefined-inline]
    3 |     struct OnScopeExit { ~OnScopeExit() {} }
      |                          ^
&lt;source&gt;:4:5: note: used here
    4 |     pending;
      |     ^
1 warning generated.
ASM generation compiler returned: 0
&lt;source&gt;:3:26: warning: inline function '(anonymous class)::operator()(int)::OnScopeExit::~OnScopeExit' is not defined [-Wundefined-inline]
    3 |     struct OnScopeExit { ~OnScopeExit() {} }
      |                          ^
&lt;source&gt;:4:5: note: used here
    4 |     pending;
      |     ^
1 warning generated.
/opt/compiler-explorer/gcc-snapshot/lib/gcc/x86_64-linux-gnu/15.0.1/../../../../x86_64-linux-gnu/bin/ld: /tmp/example-eeceaa.o: in function `auto f&lt;int&gt;::{lambda(auto:1)#<!-- -->1}::operator()&lt;int&gt;(int) const':
&lt;source&gt;:5:(.text._ZNK1fIiEMUlT_E_clIiEEDaS1_[_ZNK1fIiEMUlT_E_clIiEEDaS1_]+0x14): undefined reference to `f&lt;int&gt;::{lambda(auto:1)#<!-- -->1}::operator()&lt;int&gt;(int) const::OnScopeExit::~OnScopeExit()'
clang++: error: linker command failed with exit code 1 (use -v to see invocation)

@shafik
Copy link
Collaborator

shafik commented Mar 20, 2025

I was going to say it looks like this but this one is fixed in trunk: #115731

CC @cor3ntin @erichkeane

llvm-sync bot pushed a commit to arm/arm-toolchain that referenced this issue Apr 15, 2025
…038)

This patch fixes two long-standing bugs that prevent Clang from
instantiating local class members inside a dependent context. These bugs
were introduced in commits 21eb1af and 919df9d.

21eb1af introduced a concept called eligible methods such that it
did an attempt to skip past ineligible method instantiation when
instantiating class members. Unfortunately, this broke the instantiation
chain for local classes - getTemplateInstantiationPattern() would fail
to find the correct definition pattern if the class was defined within a
partially transformed dependent context.

919df9d introduced a separate issue by incorrectly copying the
DeclarationNameInfo during function definition instantiation from the
template pattern, even though that DNI might contain a transformed
TypeSourceInfo. Since that TSI was already updated when the declaration
was instantiated, this led to inconsistencies. As a result, the final
instantiated function could lose track of the transformed declarations,
hence we crash: https://compiler-explorer.com/z/vjvoG76Tf.

This PR corrects them by

1. Removing the bypass logic for method instantiation. The eligible flag
is independent of instantiation and can be updated properly afterward,
so skipping instantiation is unnecessary.

2. Carefully handling TypeSourceInfo by creating a new instance that
preserves the pattern's source location while using the already
transformed type.

Fixes llvm/llvm-project#59734
Fixes llvm/llvm-project#132208
var-const pushed a commit to ldionne/llvm-project that referenced this issue Apr 17, 2025
This patch fixes two long-standing bugs that prevent Clang from
instantiating local class members inside a dependent context. These bugs
were introduced in commits 21eb1af and 919df9d.

21eb1af introduced a concept called eligible methods such that it
did an attempt to skip past ineligible method instantiation when
instantiating class members. Unfortunately, this broke the instantiation
chain for local classes - getTemplateInstantiationPattern() would fail
to find the correct definition pattern if the class was defined within a
partially transformed dependent context.

919df9d introduced a separate issue by incorrectly copying the
DeclarationNameInfo during function definition instantiation from the
template pattern, even though that DNI might contain a transformed
TypeSourceInfo. Since that TSI was already updated when the declaration
was instantiated, this led to inconsistencies. As a result, the final
instantiated function could lose track of the transformed declarations,
hence we crash: https://compiler-explorer.com/z/vjvoG76Tf.

This PR corrects them by

1. Removing the bypass logic for method instantiation. The eligible flag
is independent of instantiation and can be updated properly afterward,
so skipping instantiation is unnecessary.

2. Carefully handling TypeSourceInfo by creating a new instance that
preserves the pattern's source location while using the already
transformed type.

Fixes llvm#59734
Fixes llvm#132208
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
clang:codegen IR generation bugs: mangling, exceptions, etc. constexpr Anything related to constant evaluation lambda C++11 lambda expressions
Projects
None yet
Development

Successfully merging a pull request may close this issue.

4 participants