зеркало из https://github.com/microsoft/clang-1.git
Fix PCH bug with member templates of local classes in nontemplate functions.
As noted by Richard in the post: http://lists.cs.uiuc.edu/pipermail/cfe-commits/Week-of-Mon-20130624/082605.html, the following code should not add an entry into PendingLocalImplicitInstantiations, since local instantiations should only occur within the context of other instantiations: int foo(double y) { struct Lambda { template<class T> T operator()(T t) const { return t; }; } lambda; return lambda(y); } Hence the attached code does the following: 1) In MarkFunctionReferenced, check if ActiveInstantiations.size() is non-zero before adding to PendingLocalImplicitInstantiations. 2) In InstantiateFunctionDefinition, we swap out/in PendingLocalImplicitInstantiations so that only those pending local instantiations that are added during the instantiation of the current function are instantiated recursively. git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@184903 91177308-0d34-0410-b5e6-96231b3b80d8
This commit is contained in:
Родитель
7b6301f7f5
Коммит
86648b13eb
|
@ -10893,7 +10893,8 @@ void Sema::MarkFunctionReferenced(SourceLocation Loc, FunctionDecl *Func) {
|
|||
|
||||
if (!AlreadyInstantiated || Func->isConstexpr()) {
|
||||
if (isa<CXXRecordDecl>(Func->getDeclContext()) &&
|
||||
cast<CXXRecordDecl>(Func->getDeclContext())->isLocalClass())
|
||||
cast<CXXRecordDecl>(Func->getDeclContext())->isLocalClass() &&
|
||||
ActiveTemplateInstantiations.size())
|
||||
PendingLocalImplicitInstantiations.push_back(
|
||||
std::make_pair(Func, PointOfInstantiation));
|
||||
else if (Func->isConstexpr())
|
||||
|
|
|
@ -2918,6 +2918,10 @@ void Sema::InstantiateFunctionDefinition(SourceLocation PointOfInstantiation,
|
|||
// while we're still within our own instantiation context.
|
||||
SmallVector<VTableUse, 16> SavedVTableUses;
|
||||
std::deque<PendingImplicitInstantiation> SavedPendingInstantiations;
|
||||
std::deque<PendingImplicitInstantiation>
|
||||
SavedPendingLocalImplicitInstantiations;
|
||||
SavedPendingLocalImplicitInstantiations.swap(
|
||||
PendingLocalImplicitInstantiations);
|
||||
if (Recursive) {
|
||||
VTableUses.swap(SavedVTableUses);
|
||||
PendingInstantiations.swap(SavedPendingInstantiations);
|
||||
|
@ -2998,6 +3002,8 @@ void Sema::InstantiateFunctionDefinition(SourceLocation PointOfInstantiation,
|
|||
"PendingInstantiations should be empty before it is discarded.");
|
||||
PendingInstantiations.swap(SavedPendingInstantiations);
|
||||
}
|
||||
SavedPendingLocalImplicitInstantiations.swap(
|
||||
PendingLocalImplicitInstantiations);
|
||||
}
|
||||
|
||||
/// \brief Instantiate the definition of the given variable from its
|
||||
|
|
|
@ -0,0 +1,55 @@
|
|||
// RUN: %clang_cc1 -pedantic-errors -std=c++11 -emit-pch %s -o %t-cxx11
|
||||
// RUN: %clang_cc1 -ast-print -pedantic-errors -std=c++11 -include-pch %t-cxx11 %s | FileCheck -check-prefix=CHECK-PRINT %s
|
||||
|
||||
#ifndef HEADER_INCLUDED
|
||||
|
||||
#define HEADER_INCLUDED
|
||||
|
||||
int nontemplate_test(double d) {
|
||||
struct Local {
|
||||
template<class T> T foo(T t) {
|
||||
return t;
|
||||
}
|
||||
};
|
||||
return Local{}.foo(d);
|
||||
}
|
||||
|
||||
template<class U>
|
||||
U template_test(U d) {
|
||||
struct Local {
|
||||
template<class T> T foo(T t) {
|
||||
return t;
|
||||
}
|
||||
};
|
||||
return Local{}.foo(d);
|
||||
}
|
||||
|
||||
int nested_local() {
|
||||
struct Inner1 {
|
||||
int inner1_foo(char c) {
|
||||
struct Inner2 {
|
||||
template<class T> T inner2_foo(T t) {
|
||||
return t;
|
||||
}
|
||||
};
|
||||
return Inner2{}.inner2_foo(3.14);
|
||||
}
|
||||
};
|
||||
return Inner1{}.inner1_foo('a');
|
||||
}
|
||||
|
||||
#else
|
||||
|
||||
// CHECK-PRINT: U template_test
|
||||
|
||||
// CHECK-PRINT: int nontemplate_test(double)
|
||||
|
||||
int nontemplate_test(double);
|
||||
|
||||
template double template_test(double);
|
||||
int test2(int y) {
|
||||
return nontemplate_test(y) + template_test(y);
|
||||
}
|
||||
|
||||
|
||||
#endif
|
|
@ -0,0 +1,58 @@
|
|||
// RUN: %clang_cc1 -pedantic-errors -std=c++1y -emit-pch %s -o %t-cxx1y
|
||||
// RUN: %clang_cc1 -ast-print -pedantic-errors -std=c++1y -include-pch %t-cxx1y %s | FileCheck -check-prefix=CHECK-PRINT %s
|
||||
|
||||
#ifndef HEADER_INCLUDED
|
||||
|
||||
#define HEADER_INCLUDED
|
||||
|
||||
auto nested_local_call_all() {
|
||||
struct Inner1 {
|
||||
auto inner1_foo(char c) {
|
||||
struct Inner2 {
|
||||
template<class T> T inner2_foo(T t) {
|
||||
return t;
|
||||
}
|
||||
};
|
||||
return Inner2{};
|
||||
}
|
||||
};
|
||||
return Inner1{}.inner1_foo('a').inner2_foo(4);
|
||||
}
|
||||
|
||||
|
||||
auto nested_local() {
|
||||
struct Inner1 {
|
||||
auto inner1_foo(char c) {
|
||||
struct Inner2 {
|
||||
template<class T> T inner2_foo(T t) {
|
||||
return t;
|
||||
}
|
||||
};
|
||||
return Inner2{};
|
||||
}
|
||||
};
|
||||
return Inner1{};
|
||||
}
|
||||
|
||||
|
||||
int test() {
|
||||
auto A = nested_local_call_all();
|
||||
auto B = nested_local();
|
||||
auto C = B.inner1_foo('a');
|
||||
C.inner2_foo(3.14);
|
||||
|
||||
}
|
||||
|
||||
|
||||
#else
|
||||
|
||||
// CHECK-PRINT: int nested_local_call_all
|
||||
// CHECK-PRINT: nested_local
|
||||
auto nested_local_call_all();
|
||||
|
||||
int test(int y) {
|
||||
return nested_local_call_all();
|
||||
}
|
||||
|
||||
|
||||
#endif
|
Загрузка…
Ссылка в новой задаче