Skip to content

Commit 24bd88c

Browse files
committedMar 26, 2018
[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 llvm-svn: 328567
1 parent f33d905 commit 24bd88c

File tree

5 files changed

+96
-2
lines changed

5 files changed

+96
-2
lines changed
 

‎clang/include/clang/Sema/Sema.h

+4
Original file line numberDiff line numberDiff line change
@@ -7550,6 +7550,10 @@ class Sema {
75507550
/// but have not yet been performed.
75517551
std::deque<PendingImplicitInstantiation> PendingInstantiations;
75527552

7553+
/// Queue of implicit template instantiations that cannot be performed
7554+
/// eagerly.
7555+
SmallVector<PendingImplicitInstantiation, 1> LateParsedInstantiations;
7556+
75537557
class GlobalEagerInstantiationScope {
75547558
public:
75557559
GlobalEagerInstantiationScope(Sema &S, bool Enabled)

‎clang/lib/Sema/Sema.cpp

+19
Original file line numberDiff line numberDiff line change
@@ -850,6 +850,20 @@ void Sema::ActOnEndOfTranslationUnit() {
850850
if (PP.isCodeCompletionEnabled())
851851
return;
852852

853+
// Transfer late parsed template instantiations over to the pending template
854+
// instantiation list. During normal compliation, the late template parser
855+
// will be installed and instantiating these templates will succeed.
856+
//
857+
// If we are building a TU prefix for serialization, it is also safe to
858+
// transfer these over, even though they are not parsed. The end of the TU
859+
// should be outside of any eager template instantiation scope, so when this
860+
// AST is deserialized, these templates will not be parsed until the end of
861+
// the combined TU.
862+
PendingInstantiations.insert(PendingInstantiations.end(),
863+
LateParsedInstantiations.begin(),
864+
LateParsedInstantiations.end());
865+
LateParsedInstantiations.clear();
866+
853867
// Complete translation units and modules define vtables and perform implicit
854868
// instantiations. PCH files do not.
855869
if (TUKind != TU_Prefix) {
@@ -879,8 +893,13 @@ void Sema::ActOnEndOfTranslationUnit() {
879893
PendingInstantiations.insert(PendingInstantiations.begin(),
880894
Pending.begin(), Pending.end());
881895
}
896+
882897
PerformPendingInstantiations();
883898

899+
assert(LateParsedInstantiations.empty() &&
900+
"end of TU template instantiation should not create more "
901+
"late-parsed templates");
902+
884903
if (LateTemplateParserCleanup)
885904
LateTemplateParserCleanup(OpaqueParser);
886905

‎clang/lib/Sema/SemaTemplateInstantiateDecl.cpp

+2-2
Original file line numberDiff line numberDiff line change
@@ -3837,8 +3837,8 @@ void Sema::InstantiateFunctionDefinition(SourceLocation PointOfInstantiation,
38373837
if (PatternDecl->isLateTemplateParsed() &&
38383838
!LateTemplateParser) {
38393839
Function->setInstantiationIsPending(true);
3840-
PendingInstantiations.push_back(
3841-
std::make_pair(Function, PointOfInstantiation));
3840+
LateParsedInstantiations.push_back(
3841+
std::make_pair(Function, PointOfInstantiation));
38423842
return;
38433843
}
38443844

Original file line numberDiff line numberDiff line change
@@ -0,0 +1,31 @@
1+
// RUN: %clang_cc1 -fdelayed-template-parsing -std=c++14 -emit-pch %s -o %t.pch -verify
2+
// RUN: %clang_cc1 -fdelayed-template-parsing -std=c++14 -include-pch %t.pch %s -verify
3+
4+
#ifndef HEADER_INCLUDED
5+
6+
#define HEADER_INCLUDED
7+
8+
// pr33561
9+
class ArrayBuffer;
10+
template <typename T> class Trans_NS_WTF_RefPtr {
11+
public:
12+
ArrayBuffer *operator->() { return nullptr; }
13+
};
14+
Trans_NS_WTF_RefPtr<ArrayBuffer> get();
15+
template <typename _Visitor>
16+
constexpr void visit(_Visitor __visitor) {
17+
__visitor(get()); // expected-note {{in instantiation}}
18+
}
19+
class ArrayBuffer {
20+
char data() {
21+
visit([](auto buffer) -> char { // expected-note {{in instantiation}}
22+
buffer->data();
23+
}); // expected-warning {{control reaches end of non-void lambda}}
24+
} // expected-warning {{control reaches end of non-void function}}
25+
};
26+
27+
#else
28+
29+
// expected-no-diagnostics
30+
31+
#endif
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,40 @@
1+
// RUN: %clang_cc1 -std=c++14 -verify %s
2+
3+
// pr33561
4+
class ArrayBuffer;
5+
template <typename T> class Trans_NS_WTF_RefPtr {
6+
public:
7+
ArrayBuffer *operator->() { return nullptr; }
8+
};
9+
Trans_NS_WTF_RefPtr<ArrayBuffer> get();
10+
template <typename _Visitor>
11+
constexpr void visit(_Visitor __visitor) {
12+
__visitor(get()); // expected-note {{in instantiation}}
13+
}
14+
class ArrayBuffer {
15+
char data() {
16+
visit([](auto buffer) -> char { // expected-note {{in instantiation}}
17+
buffer->data();
18+
}); // expected-warning {{control reaches end of non-void lambda}}
19+
} // expected-warning {{control reaches end of non-void function}}
20+
};
21+
22+
// pr34185
23+
template <typename Promise> struct coroutine_handle {
24+
Promise &promise() const { return
25+
*static_cast<Promise *>(nullptr); // expected-warning {{binding dereferenced null}}
26+
}
27+
};
28+
29+
template <typename Promise> auto GetCurrenPromise() {
30+
struct Awaiter { // expected-note {{in instantiation}}
31+
void await_suspend(coroutine_handle<Promise> h) {
32+
h.promise(); // expected-note {{in instantiation}}
33+
}
34+
};
35+
return Awaiter{};
36+
}
37+
38+
void foo() {
39+
auto &&p = GetCurrenPromise<int>(); // expected-note {{in instantiation}}
40+
}

0 commit comments

Comments
 (0)
Please sign in to comment.