Summary:
This fixes PR33561 and PR34185.
Don't store pending template instantiations for late-parsed templates in
the normal PendingInstantiations queue. Instead, use a separate list
that will only be parsed and instantiated at end of TU when late
template parsing actually works and doesn't infinite loop.
Reviewers: rsmith, thakis, hans
Subscribers: cfe-commits
Differential Revision: https://reviews.llvm.org/D44846
git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@328567
91177308-0d34-0410-b5e6-
96231b3b80d8
/// but have not yet been performed.
std::deque<PendingImplicitInstantiation> PendingInstantiations;
+ /// Queue of implicit template instantiations that cannot be performed
+ /// eagerly.
+ SmallVector<PendingImplicitInstantiation, 1> LateParsedInstantiations;
+
class GlobalEagerInstantiationScope {
public:
GlobalEagerInstantiationScope(Sema &S, bool Enabled)
if (PP.isCodeCompletionEnabled())
return;
+ // Transfer late parsed template instantiations over to the pending template
+ // instantiation list. During normal compliation, the late template parser
+ // will be installed and instantiating these templates will succeed.
+ //
+ // If we are building a TU prefix for serialization, it is also safe to
+ // transfer these over, even though they are not parsed. The end of the TU
+ // should be outside of any eager template instantiation scope, so when this
+ // AST is deserialized, these templates will not be parsed until the end of
+ // the combined TU.
+ PendingInstantiations.insert(PendingInstantiations.end(),
+ LateParsedInstantiations.begin(),
+ LateParsedInstantiations.end());
+ LateParsedInstantiations.clear();
+
// Complete translation units and modules define vtables and perform implicit
// instantiations. PCH files do not.
if (TUKind != TU_Prefix) {
PendingInstantiations.insert(PendingInstantiations.begin(),
Pending.begin(), Pending.end());
}
+
PerformPendingInstantiations();
+ assert(LateParsedInstantiations.empty() &&
+ "end of TU template instantiation should not create more "
+ "late-parsed templates");
+
if (LateTemplateParserCleanup)
LateTemplateParserCleanup(OpaqueParser);
if (PatternDecl->isLateTemplateParsed() &&
!LateTemplateParser) {
Function->setInstantiationIsPending(true);
- PendingInstantiations.push_back(
- std::make_pair(Function, PointOfInstantiation));
+ LateParsedInstantiations.push_back(
+ std::make_pair(Function, PointOfInstantiation));
return;
}
--- /dev/null
+// RUN: %clang_cc1 -fdelayed-template-parsing -std=c++14 -emit-pch %s -o %t.pch -verify
+// RUN: %clang_cc1 -fdelayed-template-parsing -std=c++14 -include-pch %t.pch %s -verify
+
+#ifndef HEADER_INCLUDED
+
+#define HEADER_INCLUDED
+
+// pr33561
+class ArrayBuffer;
+template <typename T> class Trans_NS_WTF_RefPtr {
+public:
+ ArrayBuffer *operator->() { return nullptr; }
+};
+Trans_NS_WTF_RefPtr<ArrayBuffer> get();
+template <typename _Visitor>
+constexpr void visit(_Visitor __visitor) {
+ __visitor(get()); // expected-note {{in instantiation}}
+}
+class ArrayBuffer {
+ char data() {
+ visit([](auto buffer) -> char { // expected-note {{in instantiation}}
+ buffer->data();
+ }); // expected-warning {{control reaches end of non-void lambda}}
+ } // expected-warning {{control reaches end of non-void function}}
+};
+
+#else
+
+// expected-no-diagnostics
+
+#endif
--- /dev/null
+// RUN: %clang_cc1 -std=c++14 -verify %s
+
+// pr33561
+class ArrayBuffer;
+template <typename T> class Trans_NS_WTF_RefPtr {
+public:
+ ArrayBuffer *operator->() { return nullptr; }
+};
+Trans_NS_WTF_RefPtr<ArrayBuffer> get();
+template <typename _Visitor>
+constexpr void visit(_Visitor __visitor) {
+ __visitor(get()); // expected-note {{in instantiation}}
+}
+class ArrayBuffer {
+ char data() {
+ visit([](auto buffer) -> char { // expected-note {{in instantiation}}
+ buffer->data();
+ }); // expected-warning {{control reaches end of non-void lambda}}
+ } // expected-warning {{control reaches end of non-void function}}
+};
+
+// pr34185
+template <typename Promise> struct coroutine_handle {
+ Promise &promise() const { return
+ *static_cast<Promise *>(nullptr); // expected-warning {{binding dereferenced null}}
+ }
+};
+
+template <typename Promise> auto GetCurrenPromise() {
+ struct Awaiter { // expected-note {{in instantiation}}
+ void await_suspend(coroutine_handle<Promise> h) {
+ h.promise(); // expected-note {{in instantiation}}
+ }
+ };
+ return Awaiter{};
+}
+
+void foo() {
+ auto &&p = GetCurrenPromise<int>(); // expected-note {{in instantiation}}
+}