mirror of https://github.com/microsoft/clang.git
[MS] Fix late-parsed template infinite loop in eager instantiation
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
This commit is contained in:
parent
b303637398
commit
a307b9d3d8
|
@ -7550,6 +7550,10 @@ public:
|
|||
/// 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)
|
||||
|
|
|
@ -850,6 +850,20 @@ void Sema::ActOnEndOfTranslationUnit() {
|
|||
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) {
|
||||
|
@ -879,8 +893,13 @@ void Sema::ActOnEndOfTranslationUnit() {
|
|||
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);
|
||||
|
||||
|
|
|
@ -3837,8 +3837,8 @@ void Sema::InstantiateFunctionDefinition(SourceLocation PointOfInstantiation,
|
|||
if (PatternDecl->isLateTemplateParsed() &&
|
||||
!LateTemplateParser) {
|
||||
Function->setInstantiationIsPending(true);
|
||||
PendingInstantiations.push_back(
|
||||
std::make_pair(Function, PointOfInstantiation));
|
||||
LateParsedInstantiations.push_back(
|
||||
std::make_pair(Function, PointOfInstantiation));
|
||||
return;
|
||||
}
|
||||
|
||||
|
|
|
@ -0,0 +1,31 @@
|
|||
// 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
|
|
@ -0,0 +1,40 @@
|
|||
// 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}}
|
||||
}
|
Loading…
Reference in New Issue