
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.
109 lines
3.0 KiB
C++
109 lines
3.0 KiB
C++
// Testing that adding an new identifier 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
|
|
//
|
|
// RUN: %clang_cc1 -std=c++20 %t/useAOnly.cppm -emit-reduced-module-interface -o %t/useAOnly.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/useAOnly.cppm -emit-reduced-module-interface -o %t/useAOnly.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
|
|
// useAOnly should differ
|
|
// RUN: not diff %t/useAOnly.pcm %t/useAOnly.v1.pcm &> /dev/null
|
|
|
|
//--- m-partA.cppm
|
|
export module m:partA;
|
|
|
|
export inline int getA() {
|
|
return 43;
|
|
}
|
|
|
|
export class A {
|
|
public:
|
|
int getMem();
|
|
};
|
|
|
|
export template <typename T>
|
|
class ATempl {
|
|
public:
|
|
T getT();
|
|
};
|
|
|
|
//--- m-partA.v1.cppm
|
|
export module m:partA;
|
|
|
|
export inline int getA() {
|
|
return 43;
|
|
}
|
|
|
|
// The consuming module which didn't use m:partA completely is expected to be
|
|
// not changed.
|
|
export inline int getA2() {
|
|
return 88;
|
|
}
|
|
|
|
export class A {
|
|
public:
|
|
int getMem();
|
|
|
|
// The consuming module which didn't use m:partA completely is expected to be
|
|
// not changed.
|
|
int getMem2();
|
|
};
|
|
|
|
export template <typename T>
|
|
class ATempl {
|
|
public:
|
|
T getT();
|
|
T getT2();
|
|
};
|
|
|
|
//--- 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() {
|
|
return getA();
|
|
}
|