
Following of https://github.com/llvm/llvm-project/pull/92085. #### motivation The motivation is still cutting of the unnecessary change in the dependency chain. See the above link (recursively) for details. And this will be the last patch of the `no-transitive-*-change` series. If there are any following patches, they might be C++20 Named modules specific to handle special grammars like `ADL` (See the reply in https://discourse.llvm.org/t/rfc-c-20-modules-introduce-thin-bmi-and-decls-hash/74755/53 for example). So they won't affect the whole serialization part as the series patch did. #### example After this patch, finally we are able to cut of unnecessary change of types. For example, ``` //--- m-partA.cppm export module m:partA; //--- m-partA.v1.cppm export module m:partA; namespace NS { class A { public: int getValue() { return 43; } }; } //--- m-partB.cppm export module m:partB; export inline int getB() { return 430; } //--- m.cppm export module m; export import :partA; export import :partB; //--- useBOnly.cppm export module useBOnly; import m; export inline int get() { return getB(); } ``` The BMI of `useBOnly.cppm` is expected to not change if we only add a new class in `m:partA`. This will be pretty useful in practice. #### implementation details The key idea of this patch is similar with the previous patches: extend the 32bits type ID to 64bits so that we can store the module file index in the higher bits. Then the encoding of the type ID is independent on the imported modules. But there are two differences from the previous patches: - TypeID is not completely an index of serialized types. We used the lower 3 bits to store the qualifiers. - TypeID won't take part in any lookup process. So the uses of TypeID is much less than the previous patches. The first difference make we have some more slightly complex bit operations. And the second difference makes the patch much simpler than the previous ones.
103 lines
2.5 KiB
C++
103 lines
2.5 KiB
C++
// Testing that changing a declaration in an unused module file won't change
|
|
// the BMI of the current module file.
|
|
//
|
|
// RUN: rm -rf %t
|
|
// RUN: split-file %s %t
|
|
//
|
|
// RUN: %clang_cc1 -std=c++20 %t/m-partA.cppm -emit-reduced-module-interface -o %t/m-partA.pcm
|
|
// RUN: %clang_cc1 -std=c++20 %t/m-partA.v1.cppm -emit-reduced-module-interface -o \
|
|
// RUN: %t/m-partA.v1.pcm
|
|
// RUN: %clang_cc1 -std=c++20 %t/m-partB.cppm -emit-reduced-module-interface -o %t/m-partB.pcm
|
|
// RUN: %clang_cc1 -std=c++20 %t/m.cppm -emit-reduced-module-interface -o %t/m.pcm \
|
|
// RUN: -fmodule-file=m:partA=%t/m-partA.pcm -fmodule-file=m:partB=%t/m-partB.pcm
|
|
// RUN: %clang_cc1 -std=c++20 %t/m.cppm -emit-reduced-module-interface -o %t/m.v1.pcm \
|
|
// RUN: -fmodule-file=m:partA=%t/m-partA.v1.pcm -fmodule-file=m:partB=%t/m-partB.pcm
|
|
//
|
|
// RUN: %clang_cc1 -std=c++20 %t/useBOnly.cppm -emit-reduced-module-interface -o %t/useBOnly.pcm \
|
|
// RUN: -fmodule-file=m=%t/m.pcm -fmodule-file=m:partA=%t/m-partA.pcm \
|
|
// RUN: -fmodule-file=m:partB=%t/m-partB.pcm
|
|
// RUN: %clang_cc1 -std=c++20 %t/useBOnly.cppm -emit-reduced-module-interface -o %t/useBOnly.v1.pcm \
|
|
// RUN: -fmodule-file=m=%t/m.v1.pcm -fmodule-file=m:partA=%t/m-partA.v1.pcm \
|
|
// RUN: -fmodule-file=m:partB=%t/m-partB.pcm
|
|
// Since useBOnly only uses partB from module M, the change in partA shouldn't affect
|
|
// useBOnly.
|
|
// RUN: diff %t/useBOnly.pcm %t/useBOnly.v1.pcm &> /dev/null
|
|
|
|
//--- m-partA.cppm
|
|
export module m:partA;
|
|
|
|
namespace A_Impl {
|
|
inline int getAImpl() {
|
|
return 43;
|
|
}
|
|
|
|
inline int getA2Impl() {
|
|
return 43;
|
|
}
|
|
}
|
|
|
|
namespace A {
|
|
using A_Impl::getAImpl;
|
|
}
|
|
|
|
export inline int getA() {
|
|
return 43;
|
|
}
|
|
|
|
//--- m-partA.v1.cppm
|
|
export module m:partA;
|
|
|
|
namespace A_Impl {
|
|
inline int getAImpl() {
|
|
return 43;
|
|
}
|
|
|
|
inline int getA2Impl() {
|
|
return 43;
|
|
}
|
|
}
|
|
|
|
namespace A {
|
|
using A_Impl::getAImpl;
|
|
using A_Impl::getA2Impl;
|
|
}
|
|
|
|
inline int getA() {
|
|
return 43;
|
|
}
|
|
|
|
// The consuming module which didn't use m:partA completely is expected to be
|
|
// not changed.
|
|
inline int getB(int) {
|
|
return 88;
|
|
}
|
|
|
|
//--- m-partB.cppm
|
|
export module m:partB;
|
|
|
|
export inline int getB() {
|
|
return 430;
|
|
}
|
|
|
|
//--- m.cppm
|
|
export module m;
|
|
export import :partA;
|
|
export import :partB;
|
|
|
|
//--- useBOnly.cppm
|
|
export module useBOnly;
|
|
import m;
|
|
|
|
export inline int get() {
|
|
return getB();
|
|
}
|
|
|
|
//--- useAOnly.cppm
|
|
export module useAOnly;
|
|
import m;
|
|
|
|
export inline int get() {
|
|
A<int> a;
|
|
return a.getValue();
|
|
}
|