llvm-project/clang/test/Modules/gh110401.cppm
Sirraide f01364ebc8
[Clang] Instantiate the correct lambda call operator (#110446)
This is a fix for the following issue: when a lambda’s class type is
merged across modules (e.g. because it is defined in a template in the
GMF of some module `A`, and some other module `B` both imports `A` and
has the same template in its GMF), then `getLambdaCallOperator()` might
return the wrong operator (e.g. while compiling `B`, the lambda’s class
type would be the one attached to `B`’s GMF, but the call operator ends
up being the one attached to `A`’s GMF).

This causes issues in situations where the call operator is in a
template and accesses declarations in the surrounding context: when
those declarations are instantated, a mapping is introduced from the
original node in the template to that of the instantiation. If such an
instantiation happens in `B`, and we then try to instantiate `A`’s call
operator, any nodes in that call operator refer to declarations in the
template in `A`, but the `LocalInstantiationScope` only contains
mappings for declarations in `B`! This causes the following assertion
(for godbolt links and more, see the issue below):

```
Assertion `isa<LabelDecl>(D) && "declaration not instantiated in this scope"' failed.
```

We now walk the redecl chain of the call operator to find the
one that is in the same module as the record decl.

This fixes #110401.
2024-10-08 13:34:00 +02:00

45 lines
992 B
C++

// RUN: rm -rf %t
// RUN: mkdir %t
// RUN: split-file %s %t
//
// RUN: %clang_cc1 -std=c++20 -triple x86_64-unknown-linux -emit-module-interface %t/a.cppm -o %t/A.pcm
// RUN: %clang_cc1 -std=c++20 -triple x86_64-unknown-linux -emit-module-interface -fprebuilt-module-path=%t %t/b.cppm -o %t/B.pcm
// Just check that this doesn't crash.
//--- a.cppm
module;
template <typename _Visitor>
void __do_visit(_Visitor &&__visitor) {
using _V0 = int;
[](_V0 __v) -> _V0 { return __v; } (1);
}
export module A;
void g() {
struct Visitor { };
__do_visit(Visitor());
}
//--- b.cppm
module;
template <typename _Visitor>
void __do_visit(_Visitor &&__visitor) {
using _V0 = int;
// Check that we instantiate this lambda's call operator in 'f' below
// instead of the one in 'a.cppm' here; otherwise, we won't find a
// corresponding instantiation of the using declaration above.
[](_V0 __v) -> _V0 { return __v; } (1);
}
export module B;
import A;
void f() {
__do_visit(1);
}