diff options
author | Faisal Vali <faisalv@yahoo.com> | 2013-08-22 01:49:11 +0000 |
---|---|---|
committer | Faisal Vali <faisalv@yahoo.com> | 2013-08-22 01:49:11 +0000 |
commit | fd5277c0635f74bbdbb2daa3bb95e08f39db7d63 (patch) | |
tree | 776347516605949ffff1243cb3f85194200e9452 /clang/lib/AST | |
parent | da68efdb689ee5b54bf3836add187b62b584de9a (diff) | |
download | bcm5719-llvm-fd5277c0635f74bbdbb2daa3bb95e08f39db7d63.tar.gz bcm5719-llvm-fd5277c0635f74bbdbb2daa3bb95e08f39db7d63.zip |
Implement a rudimentary form of generic lambdas.
Specifically, the following features are not included in this commit:
- any sort of capturing within generic lambdas
- nested lambdas
- conversion operator for captureless lambdas
- ensuring all visitors are generic lambda aware
As an example of what compiles:
template <class F1, class F2>
struct overload : F1, F2 {
using F1::operator();
using F2::operator();
overload(F1 f1, F2 f2) : F1(f1), F2(f2) { }
};
auto Recursive = [](auto Self, auto h, auto ... rest) {
return 1 + Self(Self, rest...);
};
auto Base = [](auto Self, auto h) {
return 1;
};
overload<decltype(Base), decltype(Recursive)> O(Base, Recursive);
int num_params = O(O, 5, 3, "abc", 3.14, 'a');
Please see attached tests for more examples.
Some implementation notes:
- Add a new Declarator context => LambdaExprParameterContext to
clang::Declarator to allow the use of 'auto' in declaring generic
lambda parameters
- Augment AutoType's constructor (similar to how variadic
template-type-parameters ala TemplateTypeParmDecl are implemented) to
accept an IsParameterPack to encode a generic lambda parameter pack.
- Add various helpers to CXXRecordDecl to facilitate identifying
and querying a closure class
- LambdaScopeInfo (which maintains the current lambda's Sema state)
was augmented to house the current depth of the template being
parsed (id est the Parser calls Sema::RecordParsingTemplateParameterDepth)
so that Sema::ActOnLambdaAutoParameter may use it to create the
appropriate list of corresponding TemplateTypeParmDecl for each
auto parameter identified within the generic lambda (also stored
within the current LambdaScopeInfo). Additionally,
a TemplateParameterList data-member was added to hold the invented
TemplateParameterList AST node which will be much more useful
once we teach TreeTransform how to transform generic lambdas.
- SemaLambda.h was added to hold some common lambda utility
functions (this file is likely to grow ...)
- Teach Sema::ActOnStartOfFunctionDef to check whether it
is being called to instantiate a generic lambda's call
operator, and if so, push an appropriately prepared
LambdaScopeInfo object on the stack.
- Teach Sema::ActOnStartOfLambdaDefinition to set the
return type of a lambda without a trailing return type
to 'auto' in C++1y mode, and teach the return type
deduction machinery in SemaStmt.cpp to process either
C++11 and C++14 lambda's correctly depending on the flag.
- various tests were added - but much more will be needed.
A greatful thanks to all reviewers including Eli Friedman,
James Dennett and the ever illuminating Richard Smith. And
yet I am certain that I have allowed unidentified bugs to creep in;
bugs, that I will do my best to slay, once identified!
Thanks!
llvm-svn: 188977
Diffstat (limited to 'clang/lib/AST')
-rw-r--r-- | clang/lib/AST/ASTContext.cpp | 17 | ||||
-rw-r--r-- | clang/lib/AST/ASTImporter.cpp | 4 | ||||
-rw-r--r-- | clang/lib/AST/DeclCXX.cpp | 45 | ||||
-rw-r--r-- | clang/lib/AST/ExprCXX.cpp | 14 | ||||
-rw-r--r-- | clang/lib/AST/Type.cpp | 4 |
5 files changed, 69 insertions, 15 deletions
diff --git a/clang/lib/AST/ASTContext.cpp b/clang/lib/AST/ASTContext.cpp index 29ddb37525d..b1b52fb1c57 100644 --- a/clang/lib/AST/ASTContext.cpp +++ b/clang/lib/AST/ASTContext.cpp @@ -3649,20 +3649,24 @@ QualType ASTContext::getUnaryTransformType(QualType BaseType, /// deduced to the given type, or to the canonical undeduced 'auto' type, or the /// canonical deduced-but-dependent 'auto' type. QualType ASTContext::getAutoType(QualType DeducedType, bool IsDecltypeAuto, - bool IsDependent) const { - if (DeducedType.isNull() && !IsDecltypeAuto && !IsDependent) + bool IsDependent, bool IsParameterPack) const { + if (DeducedType.isNull() && !IsDecltypeAuto && !IsDependent && + !IsParameterPack) return getAutoDeductType(); - + assert(!IsParameterPack || DeducedType.isNull() + && "Auto parameter pack: auto ... a should always be undeduced!"); // Look in the folding set for an existing type. void *InsertPos = 0; llvm::FoldingSetNodeID ID; - AutoType::Profile(ID, DeducedType, IsDecltypeAuto, IsDependent); + AutoType::Profile(ID, DeducedType, IsDecltypeAuto, IsDependent, + IsParameterPack); if (AutoType *AT = AutoTypes.FindNodeOrInsertPos(ID, InsertPos)) return QualType(AT, 0); AutoType *AT = new (*this, TypeAlignment) AutoType(DeducedType, IsDecltypeAuto, - IsDependent); + IsDependent, + IsParameterPack); Types.push_back(AT); if (InsertPos) AutoTypes.InsertNode(AT, InsertPos); @@ -3702,7 +3706,8 @@ QualType ASTContext::getAutoDeductType() const { if (AutoDeductTy.isNull()) AutoDeductTy = QualType( new (*this, TypeAlignment) AutoType(QualType(), /*decltype(auto)*/false, - /*dependent*/false), + /*dependent*/false, + /*IsParameterPack*/false), 0); return AutoDeductTy; } diff --git a/clang/lib/AST/ASTImporter.cpp b/clang/lib/AST/ASTImporter.cpp index 922172701f0..f03b66dfd88 100644 --- a/clang/lib/AST/ASTImporter.cpp +++ b/clang/lib/AST/ASTImporter.cpp @@ -1709,7 +1709,9 @@ QualType ASTNodeImporter::VisitAutoType(const AutoType *T) { return QualType(); } - return Importer.getToContext().getAutoType(ToDeduced, T->isDecltypeAuto()); + return Importer.getToContext().getAutoType(ToDeduced, T->isDecltypeAuto(), + /*IsDependent*/false, + T->containsUnexpandedParameterPack()); } QualType ASTNodeImporter::VisitRecordType(const RecordType *T) { diff --git a/clang/lib/AST/DeclCXX.cpp b/clang/lib/AST/DeclCXX.cpp index ccd8220a684..b50aa9337fe 100644 --- a/clang/lib/AST/DeclCXX.cpp +++ b/clang/lib/AST/DeclCXX.cpp @@ -20,6 +20,7 @@ #include "clang/AST/ExprCXX.h" #include "clang/AST/TypeLoc.h" #include "clang/Basic/IdentifierTable.h" +#include "clang/Sema/SemaLambda.h" #include "llvm/ADT/STLExtras.h" #include "llvm/ADT/SmallPtrSet.h" using namespace clang; @@ -930,6 +931,40 @@ bool CXXRecordDecl::isCLike() const { return isPOD() && data().HasOnlyCMembers; } +bool CXXRecordDecl::isGenericLambda() const { + return isLambda() && + getLambdaCallOperator()->getDescribedFunctionTemplate(); +} + +CXXMethodDecl* CXXRecordDecl::getLambdaCallOperator() const { + if (!isLambda()) return 0; + DeclarationName Name =
+ getASTContext().DeclarationNames.getCXXOperatorName(OO_Call);
+ DeclContext::lookup_const_result Calls = lookup(Name); +
+ assert(!Calls.empty() && "Missing lambda call operator!");
+ assert(Calls.size() == 1 && "More than one lambda call operator!");
+
+ NamedDecl *CallOp = Calls.front();
+ if (FunctionTemplateDecl *CallOpTmpl =
+ dyn_cast<FunctionTemplateDecl>(CallOp))
+ return cast<CXXMethodDecl>(CallOpTmpl->getTemplatedDecl());
+ + return cast<CXXMethodDecl>(CallOp); +} + +CXXMethodDecl* CXXRecordDecl::getLambdaStaticInvoker() const { + if (!isLambda()) return 0; + DeclarationName Name =
+ &getASTContext().Idents.get(getLambdaStaticInvokerName());
+ DeclContext::lookup_const_result Invoker = lookup(Name); + if (Invoker.empty()) return 0;
+ assert(Invoker.size() == 1 && "More than one static invoker operator!");
+ CXXMethodDecl *Result = cast<CXXMethodDecl>(Invoker.front());
+ return Result; + +} + void CXXRecordDecl::getCaptureFields( llvm::DenseMap<const VarDecl *, FieldDecl *> &Captures, FieldDecl *&ThisCapture) const { @@ -947,6 +982,14 @@ void CXXRecordDecl::getCaptureFields( } } +TemplateParameterList* + CXXRecordDecl::getGenericLambdaTemplateParameterList() const { + if (!isLambda()) return 0; + CXXMethodDecl *CallOp = getLambdaCallOperator(); + if (FunctionTemplateDecl *Tmpl = CallOp->getDescribedFunctionTemplate()) + return Tmpl->getTemplateParameters(); + return 0; +} static CanQualType GetConversionType(ASTContext &Context, NamedDecl *Conv) { QualType T; @@ -1493,7 +1536,7 @@ bool CXXMethodDecl::hasInlineBody() const { bool CXXMethodDecl::isLambdaStaticInvoker() const { return getParent()->isLambda() && - getIdentifier() && getIdentifier()->getName() == "__invoke"; + getParent()->getLambdaStaticInvoker() == this; } diff --git a/clang/lib/AST/ExprCXX.cpp b/clang/lib/AST/ExprCXX.cpp index 0609eb1d65d..28794d4f621 100644 --- a/clang/lib/AST/ExprCXX.cpp +++ b/clang/lib/AST/ExprCXX.cpp @@ -1026,13 +1026,13 @@ CXXRecordDecl *LambdaExpr::getLambdaClass() const { CXXMethodDecl *LambdaExpr::getCallOperator() const { CXXRecordDecl *Record = getLambdaClass(); - DeclarationName Name - = Record->getASTContext().DeclarationNames.getCXXOperatorName(OO_Call); - DeclContext::lookup_result Calls = Record->lookup(Name); - assert(!Calls.empty() && "Missing lambda call operator!"); - assert(Calls.size() == 1 && "More than one lambda call operator!"); - CXXMethodDecl *Result = cast<CXXMethodDecl>(Calls.front()); - return Result; + return Record->getLambdaCallOperator(); +} + +TemplateParameterList *LambdaExpr::getTemplateParameterList() const { + CXXRecordDecl *Record = getLambdaClass(); + return Record->getGenericLambdaTemplateParameterList(); + } CompoundStmt *LambdaExpr::getBody() const { diff --git a/clang/lib/AST/Type.cpp b/clang/lib/AST/Type.cpp index 44da348b0b7..bb6d0bf05d1 100644 --- a/clang/lib/AST/Type.cpp +++ b/clang/lib/AST/Type.cpp @@ -589,6 +589,10 @@ namespace { AutoType *VisitAttributedType(const AttributedType *T) { return Visit(T->getModifiedType()); } + AutoType *VisitPackExpansionType(const PackExpansionType *T) { + return Visit(T->getPattern()); + } + }; } |