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/Sema/SemaStmt.cpp | |
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/Sema/SemaStmt.cpp')
-rw-r--r-- | clang/lib/Sema/SemaStmt.cpp | 66 |
1 files changed, 42 insertions, 24 deletions
diff --git a/clang/lib/Sema/SemaStmt.cpp b/clang/lib/Sema/SemaStmt.cpp index 0570a60a0a0..5434e987e9e 100644 --- a/clang/lib/Sema/SemaStmt.cpp +++ b/clang/lib/Sema/SemaStmt.cpp @@ -2487,12 +2487,31 @@ Sema::ActOnCapScopeReturnStmt(SourceLocation ReturnLoc, Expr *RetValExp) { // [expr.prim.lambda]p4 in C++11; block literals follow the same rules. CapturingScopeInfo *CurCap = cast<CapturingScopeInfo>(getCurFunction()); QualType FnRetType = CurCap->ReturnType; - - // For blocks/lambdas with implicit return types, we check each return - // statement individually, and deduce the common return type when the block - // or lambda is completed. - if (CurCap->HasImplicitReturnType) { - // FIXME: Fold this into the 'auto' codepath below. + LambdaScopeInfo *const LambdaSI = getCurLambda(); + // In C++1y, an implicit return type behaves as if 'auto' was + // the return type. + if (FnRetType.isNull() && getLangOpts().CPlusPlus1y) { + if (LambdaSI) { + FunctionDecl *CallOp = LambdaSI->CallOperator; + FnRetType = CallOp->getResultType(); + assert(FnRetType->getContainedAutoType()); + } + } + + // For blocks/lambdas with implicit return types in C++11, we check each + // return statement individually, and deduce the common return type when + // the block or lambda is completed. In C++1y, the return type deduction + // of a lambda is specified in terms of auto. + // Notably, in C++11, we take the type of the expression after decay and + // lvalue-to-rvalue conversion, so a class type can be cv-qualified. + // In C++1y, we perform template argument deduction as if the return + // type were 'auto', so an implicit return type is never cv-qualified. + // i.e if (getLangOpts().CPlusPlus1y && FnRetType.hasQualifiers()) + // FnRetType = FnRetType.getUnqualifiedType(); + // Return type deduction is unchanged for blocks in C++1y. + // FIXME: Fold this into the 'auto' codepath below. + if (CurCap->HasImplicitReturnType && + (!LambdaSI || !getLangOpts().CPlusPlus1y)) { if (RetValExp && !isa<InitListExpr>(RetValExp)) { ExprResult Result = DefaultFunctionArrayLvalueConversion(RetValExp); if (Result.isInvalid()) @@ -2500,13 +2519,7 @@ Sema::ActOnCapScopeReturnStmt(SourceLocation ReturnLoc, Expr *RetValExp) { RetValExp = Result.take(); if (!CurContext->isDependentContext()) { - FnRetType = RetValExp->getType(); - // In C++11, we take the type of the expression after decay and - // lvalue-to-rvalue conversion, so a class type can be cv-qualified. - // In C++1y, we perform template argument deduction as if the return - // type were 'auto', so an implicit return type is never cv-qualified. - if (getLangOpts().CPlusPlus1y && FnRetType.hasQualifiers()) - FnRetType = FnRetType.getUnqualifiedType(); + FnRetType = RetValExp->getType(); } else FnRetType = CurCap->ReturnType = Context.DependentTy; } else { @@ -2517,7 +2530,6 @@ Sema::ActOnCapScopeReturnStmt(SourceLocation ReturnLoc, Expr *RetValExp) { Diag(ReturnLoc, diag::err_lambda_return_init_list) << RetValExp->getSourceRange(); } - FnRetType = Context.VoidTy; } @@ -2526,7 +2538,8 @@ Sema::ActOnCapScopeReturnStmt(SourceLocation ReturnLoc, Expr *RetValExp) { if (CurCap->ReturnType.isNull()) CurCap->ReturnType = FnRetType; } else if (AutoType *AT = - FnRetType.isNull() ? 0 : FnRetType->getContainedAutoType()) { + (FnRetType.isNull() || !LambdaSI) ? 0 + : FnRetType->getContainedAutoType()) { // In C++1y, the return type may involve 'auto'. FunctionDecl *FD = cast<LambdaScopeInfo>(CurCap)->CallOperator; if (CurContext->isDependentContext()) { @@ -2534,7 +2547,7 @@ Sema::ActOnCapScopeReturnStmt(SourceLocation ReturnLoc, Expr *RetValExp) { // Return type deduction [...] occurs when the definition is // instantiated even if the function body contains a return // statement with a non-type-dependent operand. - CurCap->ReturnType = FnRetType = Context.DependentTy; + CurCap->ReturnType = FnRetType; } else if (DeduceFunctionTypeFromReturnExpr(FD, ReturnLoc, RetValExp, AT)) { FD->setInvalidDecl(); return StmtError(); @@ -2564,7 +2577,7 @@ Sema::ActOnCapScopeReturnStmt(SourceLocation ReturnLoc, Expr *RetValExp) { // pickier with blocks than for normal functions because we don't have GCC // compatibility to worry about here. const VarDecl *NRVOCandidate = 0; - if (FnRetType->isDependentType()) { + if (FnRetType->isDependentType() || FnRetType->isUndeducedType()) { // Delay processing for now. TODO: there are lots of dependent // types we can conclusively prove aren't void. } else if (FnRetType->isVoidType()) { @@ -2624,7 +2637,6 @@ Sema::ActOnCapScopeReturnStmt(SourceLocation ReturnLoc, Expr *RetValExp) { return Owned(Result); } - /// Deduce the return type for a function from a returned expression, per /// C++1y [dcl.spec.auto]p6. bool Sema::DeduceFunctionTypeFromReturnExpr(FunctionDecl *FD, @@ -2634,7 +2646,6 @@ bool Sema::DeduceFunctionTypeFromReturnExpr(FunctionDecl *FD, TypeLoc OrigResultType = FD->getTypeSourceInfo()->getTypeLoc(). IgnoreParens().castAs<FunctionProtoTypeLoc>().getResultLoc(); QualType Deduced; - if (RetExpr && isa<InitListExpr>(RetExpr)) { // If the deduction is for a return statement and the initializer is // a braced-init-list, the program is ill-formed. @@ -2692,9 +2703,18 @@ bool Sema::DeduceFunctionTypeFromReturnExpr(FunctionDecl *FD, AutoType *NewAT = Deduced->getContainedAutoType(); if (!FD->isDependentContext() && !Context.hasSameType(AT->getDeducedType(), NewAT->getDeducedType())) { - Diag(ReturnLoc, diag::err_auto_fn_different_deductions) - << (AT->isDecltypeAuto() ? 1 : 0) - << NewAT->getDeducedType() << AT->getDeducedType(); + LambdaScopeInfo *const LambdaSI = getCurLambda(); + if (LambdaSI && LambdaSI->HasImplicitReturnType) { + Diag(ReturnLoc, + diag::err_typecheck_missing_return_type_incompatible) + << NewAT->getDeducedType() << AT->getDeducedType() + << true /*IsLambda*/; + } + else { + Diag(ReturnLoc, diag::err_auto_fn_different_deductions) + << (AT->isDecltypeAuto() ? 1 : 0) + << NewAT->getDeducedType() << AT->getDeducedType(); + } return true; } } else if (!FD->isInvalidDecl()) { @@ -2710,10 +2730,8 @@ Sema::ActOnReturnStmt(SourceLocation ReturnLoc, Expr *RetValExp) { // Check for unexpanded parameter packs. if (RetValExp && DiagnoseUnexpandedParameterPack(RetValExp)) return StmtError(); - if (isa<CapturingScopeInfo>(getCurFunction())) return ActOnCapScopeReturnStmt(ReturnLoc, RetValExp); - QualType FnRetType; QualType RelatedRetType; if (const FunctionDecl *FD = getCurFunctionDecl()) { |