forked from OSchip/llvm-project
Teach getTemplateInstantiationPattern to deal with generic lambdas.
No functionality change. When determining the pattern for instantiating a generic lambda call operator specialization - we must not go drilling down for the 'prototype' (i.e. as written) pattern - rather we must use our partially transformed pattern (whose DeclRefExprs are wired correctly to any enclosing lambda's decls that should be mapped correctly in a local instantiation scope) that is the templated pattern of the specialization's primary template (even though the primary template might be instantiated from a 'prototype' member-template). Previously, the drilling down was haltted by marking the instantiated-from primary template as a member-specialization (incorrectly). This prompted Richard to remark (http://llvm-reviews.chandlerc.com/D1784?id=4687#inline-10272) "It's a bit nasty to (essentially) set this bit incorrectly. Can you put the check into getTemplateInstantiationPattern instead?" In my reckless youth, I chose to ignore that comment. With the passage of time, I have come to learn the value of bowing to the will of the angry Gods ;) llvm-svn: 205543
This commit is contained in:
parent
265f2f0440
commit
b90b211eea
|
@ -36,9 +36,9 @@ inline bool isLambdaCallOperator(const DeclContext *DC) {
|
|||
return isLambdaCallOperator(cast<CXXMethodDecl>(DC));
|
||||
}
|
||||
|
||||
inline bool isGenericLambdaCallOperatorSpecialization(CXXMethodDecl *MD) {
|
||||
inline bool isGenericLambdaCallOperatorSpecialization(const CXXMethodDecl *MD) {
|
||||
if (!MD) return false;
|
||||
CXXRecordDecl *LambdaClass = MD->getParent();
|
||||
const CXXRecordDecl *LambdaClass = MD->getParent();
|
||||
if (LambdaClass && LambdaClass->isGenericLambda())
|
||||
return isLambdaCallOperator(MD) &&
|
||||
MD->isFunctionTemplateSpecialization();
|
||||
|
|
|
@ -13,6 +13,7 @@
|
|||
|
||||
#include "clang/AST/Decl.h"
|
||||
#include "clang/AST/ASTContext.h"
|
||||
#include "clang/AST/ASTLambda.h"
|
||||
#include "clang/AST/ASTMutationListener.h"
|
||||
#include "clang/AST/Attr.h"
|
||||
#include "clang/AST/DeclCXX.h"
|
||||
|
@ -2830,14 +2831,34 @@ FunctionDecl *FunctionDecl::getTemplateInstantiationPattern() const {
|
|||
// Handle class scope explicit specialization special case.
|
||||
if (getTemplateSpecializationKind() == TSK_ExplicitSpecialization)
|
||||
return getClassScopeSpecializationPattern();
|
||||
|
||||
// If this is a generic lambda call operator specialization, its
|
||||
// instantiation pattern is always its primary template's pattern
|
||||
// even if its primary template was instantiated from another
|
||||
// member template (which happens with nested generic lambdas).
|
||||
// Since a lambda's call operator's body is transformed eagerly,
|
||||
// we don't have to go hunting for a prototype definition template
|
||||
// (i.e. instantiated-from-member-template) to use as an instantiation
|
||||
// pattern.
|
||||
|
||||
if (isGenericLambdaCallOperatorSpecialization(
|
||||
dyn_cast<CXXMethodDecl>(this))) {
|
||||
assert(getPrimaryTemplate() && "A generic lambda specialization must be "
|
||||
"generated from a primary call operator "
|
||||
"template");
|
||||
assert(getPrimaryTemplate()->getTemplatedDecl()->getBody() &&
|
||||
"A generic lambda call operator template must always have a body - "
|
||||
"even if instantiated from a prototype (i.e. as written) member "
|
||||
"template");
|
||||
return getPrimaryTemplate()->getTemplatedDecl();
|
||||
}
|
||||
|
||||
if (FunctionTemplateDecl *Primary = getPrimaryTemplate()) {
|
||||
while (Primary->getInstantiatedFromMemberTemplate()) {
|
||||
// If we have hit a point where the user provided a specialization of
|
||||
// this template, we're done looking.
|
||||
if (Primary->isMemberSpecialization())
|
||||
break;
|
||||
|
||||
Primary = Primary->getInstantiatedFromMemberTemplate();
|
||||
}
|
||||
|
||||
|
|
|
@ -837,8 +837,6 @@ namespace {
|
|||
OldCallOperator->getDescribedFunctionTemplate();
|
||||
NewCallOperatorTemplate->setInstantiatedFromMemberTemplate(
|
||||
OldCallOperatorTemplate);
|
||||
// Mark the NewCallOperatorTemplate a specialization.
|
||||
NewCallOperatorTemplate->setMemberSpecialization();
|
||||
} else
|
||||
// For a non-generic lambda we set the NewCallOperator to
|
||||
// be an instantiation of the OldCallOperator.
|
||||
|
|
Loading…
Reference in New Issue