Add -fpch-instantiate-templates which makes template instantiations be performed already in the PCH instead of it being done in every single file that uses the PCH (but every single file will still do it as well in order to handle its own instantiations). I can see 20-30% build time saved with the few tests I've tried. The change may reorder compiler output and also generated code, but should be generally safe and produce functionally identical code. There are some rare cases that do not compile with it, such as test/PCH/pch-instantiate-templates-forward-decl.cpp. If template instantiation bailed out instead of reporting the error, these instantiations could even be postponed, which would make them work. Enable this by default for clang-cl. MSVC creates PCHs by compiling them using an empty .cpp file, which means templates are instantiated while building the PCH and so the .h needs to be self-contained, making test/PCH/pch-instantiate-templates-forward-decl.cpp to fail with MSVC anyway. So the option being enabled for clang-cl matches this. Differential Revision: https://reviews.llvm.org/D69585
128 lines
2.8 KiB
C++
128 lines
2.8 KiB
C++
// RUN: %clang_cc1 -std=c++2a -emit-pch %s -o %t-cxx2a
|
|
// RUN: %clang_cc1 -std=c++2a -DUSE_PCH -include-pch %t-cxx2a %s -ast-print -verify | FileCheck %s
|
|
|
|
// RUN: %clang_cc1 -std=c++2a -emit-pch -fpch-instantiate-templates %s -o %t-cxx2a
|
|
// RUN: %clang_cc1 -std=c++2a -DUSE_PCH -include-pch %t-cxx2a %s -ast-print -verify | FileCheck %s
|
|
|
|
#ifndef USE_PCH
|
|
namespace inheriting_constructor {
|
|
struct S {};
|
|
|
|
template<typename X, typename Y> struct T {
|
|
template<typename A>
|
|
explicit((Y{}, true)) T(A &&a) {}
|
|
};
|
|
|
|
template<typename X, typename Y> struct U : T<X, Y> {
|
|
using T<X, Y>::T;
|
|
};
|
|
|
|
U<S, char> foo(char ch) {
|
|
return U<S, char>(ch);
|
|
}
|
|
}
|
|
#else
|
|
namespace inheriting_constructor {
|
|
U<S, char> a = foo('0');
|
|
}
|
|
|
|
//CHECK: explicit((char{} , true))
|
|
|
|
#endif
|
|
|
|
namespace basic {
|
|
#ifndef USE_PCH
|
|
|
|
struct B {};
|
|
|
|
struct A {
|
|
explicit A(int);
|
|
explicit(false) operator bool();
|
|
explicit(true) operator B();
|
|
};
|
|
#else
|
|
//expected-note@-6+ {{candidate constructor}}
|
|
//expected-note@-9+ {{candidate constructor}}
|
|
//expected-note-re@-7+ {{explicit constructor is not a candidate{{$}}}}
|
|
//expected-note@-7+ {{candidate function}}
|
|
//expected-note@-7+ {{explicit conversion function is not a candidate (explicit specifier evaluates to true)}}
|
|
|
|
//CHECK: explicit{{ +}}A(
|
|
//CHECK-NEXT: explicit(false){{ +}}operator
|
|
//CHECK-NEXT: explicit(true){{ +}}operator
|
|
A a = 0; //expected-error {{no viable conversion}}
|
|
A a1(0);
|
|
|
|
bool b = a1;
|
|
B b1 = a1; //expected-error {{no viable conversion}}
|
|
|
|
#endif
|
|
}
|
|
|
|
|
|
namespace templ {
|
|
#ifndef USE_PCH
|
|
|
|
template<bool b>
|
|
struct B {
|
|
static constexpr bool value = b;
|
|
};
|
|
|
|
template<bool b>
|
|
struct A {
|
|
explicit(b) A(B<b>) {}
|
|
template<typename T>
|
|
explicit(b ^ T::value) operator T();
|
|
};
|
|
B<true> b_true;
|
|
B<false> b_false;
|
|
#else
|
|
//expected-note@-8 {{candidate template ignored}}
|
|
//expected-note@-8 {{explicit constructor declared here}}
|
|
//expected-note@-15+ {{candidate constructor}}
|
|
//expected-note@-8+ {{explicit conversion function is not a candidate (explicit specifier}}
|
|
//expected-note@-11 {{explicit constructor is not a candidate (explicit specifier}}
|
|
|
|
//CHECK: explicit(b){{ +}}A
|
|
//CHECK: explicit(b{{ +}}^{{ +}}T::value){{ +}}operator
|
|
|
|
A a = { b_true }; //expected-error {{class template argument deduction}}
|
|
A a0 = b_true; //expected-error {{no viable constructor or deduction guide}}
|
|
A a_true(b_true);
|
|
A a_false = b_false;
|
|
|
|
B<true> b = a_true;
|
|
B<true> b1 = a_false; //expected-error {{no viable conversion}}
|
|
B<false> b2(a_true);
|
|
|
|
#endif
|
|
|
|
}
|
|
|
|
namespace guide {
|
|
|
|
#ifndef USE_PCH
|
|
|
|
template<typename T>
|
|
struct A {
|
|
A(T);
|
|
};
|
|
|
|
template<typename T>
|
|
explicit(true) A(T) -> A<T>;
|
|
|
|
explicit(false) A(int) -> A<int>;
|
|
|
|
#else
|
|
//expected-note@-5 {{explicit deduction guide}}
|
|
|
|
//CHECK: explicit(true){{ +}}A(
|
|
//CHECK: explicit(false){{ +}}A(
|
|
|
|
A a = { 0.0 }; //expected-error {{explicit deduction guide}}
|
|
A a1 = { 0 };
|
|
|
|
#endif
|
|
|
|
}
|