// RUN: rm -rf %t // RUN: mkdir %t // RUN: split-file %s %t // // RUN: cd %t // // RUN: %clang_cc1 -fmodules -fno-implicit-modules -fmodule-name=c \ // RUN: -fmodule-map-file=c.cppmap -xc++ c.cppmap -emit-module -o c.pcm // RUN: %clang_cc1 -fmodules -fno-implicit-modules -fmodule-name=a \ // RUN: -fmodule-map-file=a.cppmap -fmodule-map-file=c.cppmap -xc++ a.cppmap \ // RUN: -emit-module -o a.pcm // RUN: %clang_cc1 -fmodules -fno-implicit-modules -fmodule-name=b \ // RUN: -fmodule-map-file=b.cppmap -fmodule-map-file=c.cppmap -xc++ b.cppmap \ // RUN: -emit-module -o b.pcm // RUN: %clang_cc1 -fmodules -fno-implicit-modules -fmodule-name=test \ // RUN: -fmodule-map-file=test.cppmap -fmodule-map-file=a.cppmap \ // RUN: -fmodule-map-file=b.cppmap -fmodule-file=a.pcm -fmodule-file=b.pcm -xc++ \ // RUN: test.cc -S -emit-llvm -o - | FileCheck test.cc //--- a.cppmap module "a" { export * module "a.h" { export * header "a.h" } use "c" } //--- b.cppmap module "b" { export * module "b.h" { export * header "b.h" } use "c" } //--- c.cppmap module "c" { export * module "c1.h" { export * textual header "c1.h" } module "c2.h" { export * textual header "c2.h" } module "c3.h" { export * textual header "c3.h" } } //--- test.cppmap module "test" { export * use "a" use "b" } //--- a.h #ifndef A_H_ #define A_H_ #include "c1.h" namespace q { template ::value>::type> class X {}; } // namespace q #include "c3.h" #endif // A_H_ //--- b.h #ifndef B_H_ #define B_H_ #include "c2.h" #endif // B_H_ //--- c1.h #ifndef C1_H_ #define C1_H_ namespace std { template struct integral_constant { static constexpr const _Tp value = __v; typedef _Tp value_type; typedef integral_constant type; constexpr operator value_type() const noexcept { return value; } constexpr value_type operator()() const noexcept { return value; } }; template constexpr const _Tp integral_constant<_Tp, __v>::value; typedef integral_constant true_type; typedef integral_constant false_type; template struct enable_if {}; template struct enable_if { typedef _Tp type; }; } // namespace std namespace p { template struct P : ::std::false_type {}; } #endif // C1_H_ //--- c2.h #ifndef C2_H_ #define C2_H_ #include "c3.h" enum E {}; namespace p { template <> struct P : std::true_type {}; } // namespace proto2 inline void f(::util::EnumErrorSpace) {} #endif // C2_H_ //--- c3.h #ifndef C3_H_ #define C3_H_ #include "c1.h" namespace util { template class ErrorSpaceImpl; class ErrorSpace { protected: template struct OdrUse { constexpr OdrUse() : b(*addr) {} bool& b; }; template struct Registerer { static bool register_token; static constexpr OdrUse<®ister_token> kRegisterTokenUse{}; }; private: template static const ErrorSpace* GetBase() { return 0; } static bool Register(const ErrorSpace* (*space)()) { return true; } }; template bool ErrorSpace::Registerer::register_token = Register(&ErrorSpace::GetBase); template class ErrorSpaceImpl : public ErrorSpace { private: static constexpr Registerer kRegisterer{}; }; template ::value>::type> class EnumErrorSpace : public ErrorSpaceImpl> {}; } // namespace util #endif // C3_H_ //--- test.cc #include "a.h" #include "b.h" int main(int, char**) {} // CHECK-NOT: error