return MD->getOverloadedOperator() == OO_Call;
}
+inline bool isLambdaCallOperator(const DeclContext *DC) {
+ if (!DC || !isa<CXXMethodDecl>(DC)) return false;
+ return isLambdaCallOperator(cast<CXXMethodDecl>(DC));
+}
+
inline bool isGenericLambdaCallOperatorSpecialization(CXXMethodDecl *MD) {
+ if (!MD) return false;
CXXRecordDecl *LambdaClass = MD->getParent();
if (LambdaClass && LambdaClass->isGenericLambda())
return isLambdaCallOperator(MD) &&
return isGenericLambdaCallOperatorSpecialization(
cast<CXXMethodDecl>(D));
}
+
+inline bool isLambdaConversionOperator(CXXConversionDecl *C) {
+ return C ? C->getParent()->isLambda() : false;
+}
+
+inline bool isLambdaConversionOperator(Decl *D) {
+ if (!D) return false;
+ if (CXXConversionDecl *Conv = dyn_cast<CXXConversionDecl>(D))
+ return isLambdaConversionOperator(Conv);
+ if (FunctionTemplateDecl *F = dyn_cast<FunctionTemplateDecl>(D))
+ if (CXXConversionDecl *Conv =
+ dyn_cast_or_null<CXXConversionDecl>(F->getTemplatedDecl()))
+ return isLambdaConversionOperator(Conv);
+ return false;
+}
+
+inline bool isGenericLambdaCallOperatorSpecialization(DeclContext *DC) {
+ return isGenericLambdaCallOperatorSpecialization(
+ dyn_cast<CXXMethodDecl>(DC));
+}
+
} // clang
#endif // LLVM_CLANG_AST_LAMBDA_H
DeclContext::lookup_const_result Invoker = lookup(Name);
if (Invoker.empty()) return 0;\r
assert(Invoker.size() == 1 && "More than one static invoker operator!"); \r
- CXXMethodDecl *Result = cast<CXXMethodDecl>(Invoker.front()); \r
- return Result;
-
+ NamedDecl *InvokerFun = Invoker.front();\r
+ if (FunctionTemplateDecl *InvokerTemplate =\r
+ dyn_cast<FunctionTemplateDecl>(InvokerFun)) \r
+ return cast<CXXMethodDecl>(InvokerTemplate->getTemplatedDecl());\r
+ \r
+ return cast<CXXMethodDecl>(InvokerFun);
}
void CXXRecordDecl::getCaptureFields(
}
bool CXXMethodDecl::isLambdaStaticInvoker() const {
- return getParent()->isLambda() &&
- getParent()->getLambdaStaticInvoker() == this;
+ const CXXRecordDecl *P = getParent();
+ if (P->isLambda()) {
+ if (const CXXMethodDecl *StaticInvoker = P->getLambdaStaticInvoker()) {
+ if (StaticInvoker == this) return true;
+ if (P->isGenericLambda() && this->isFunctionTemplateSpecialization())
+ return StaticInvoker == this->getPrimaryTemplate()->getTemplatedDecl();
+ }
+ }
+ return false;
}
-
CXXCtorInitializer::CXXCtorInitializer(ASTContext &Context,
TypeSourceInfo *TInfo, bool IsVirtual,
SourceLocation L, Expr *Init,
#include "CodeGenFunction.h"
#include "CGCXXABI.h"
#include "clang/AST/CXXInheritance.h"
+#include "clang/AST/DeclTemplate.h"
#include "clang/AST/EvaluatedExprVisitor.h"
#include "clang/AST/RecordLayout.h"
#include "clang/AST/StmtCXX.h"
return CGM.GetAddrOfFunction(MD, fnType);
}
-void CodeGenFunction::EmitForwardingCallToLambda(const CXXRecordDecl *lambda,
- CallArgList &callArgs) {
- // Lookup the call operator
- DeclarationName operatorName
- = getContext().DeclarationNames.getCXXOperatorName(OO_Call);
- CXXMethodDecl *callOperator =
- cast<CXXMethodDecl>(lambda->lookup(operatorName).front());
-
+void CodeGenFunction::EmitForwardingCallToLambda(
+ const CXXMethodDecl *callOperator,
+ CallArgList &callArgs) {
// Get the address of the call operator.
const CGFunctionInfo &calleeFnInfo =
CGM.getTypes().arrangeCXXMethodDeclaration(callOperator);
ParmVarDecl *param = *I;
EmitDelegateCallArg(CallArgs, param);
}
-
- EmitForwardingCallToLambda(Lambda, CallArgs);
+ assert(!Lambda->isGenericLambda() &&
+ "generic lambda interconversion to block not implemented");
+ EmitForwardingCallToLambda(Lambda->getLambdaCallOperator(), CallArgs);
}
void CodeGenFunction::EmitLambdaToBlockPointerBody(FunctionArgList &Args) {
ParmVarDecl *param = *I;
EmitDelegateCallArg(CallArgs, param);
}
-
- EmitForwardingCallToLambda(Lambda, CallArgs);
+ const CXXMethodDecl *CallOp = Lambda->getLambdaCallOperator();
+ // For a generic lambda, find the corresponding call operator specialization
+ // to which the call to the static-invoker shall be forwarded.
+ if (Lambda->isGenericLambda()) {
+ assert(MD->isFunctionTemplateSpecialization());
+ const TemplateArgumentList *TAL = MD->getTemplateSpecializationArgs();
+ FunctionTemplateDecl *CallOpTemplate = CallOp->getDescribedFunctionTemplate();
+ void *InsertPos = 0;
+ FunctionDecl *CorrespondingCallOpSpecialization =
+ CallOpTemplate->findSpecialization(TAL->data(), TAL->size(), InsertPos);
+ assert(CorrespondingCallOpSpecialization);
+ CallOp = cast<CXXMethodDecl>(CorrespondingCallOpSpecialization);
+ }
+ EmitForwardingCallToLambda(CallOp, CallArgs);
}
void CodeGenFunction::EmitLambdaStaticInvokeFunction(const CXXMethodDecl *MD) {
void emitImplicitAssignmentOperatorBody(FunctionArgList &Args);
void EmitFunctionBody(FunctionArgList &Args);
- void EmitForwardingCallToLambda(const CXXRecordDecl *Lambda,
+ void EmitForwardingCallToLambda(const CXXMethodDecl *LambdaCallOperator,
CallArgList &CallArgs);
void EmitLambdaToBlockPointerBody(FunctionArgList &Args);
void EmitLambdaBlockInvokeBody();
return FD->isDeleted() && FD->isDefaulted() && isa<CXXMethodDecl>(FD);
}
-/// \brief Mark the call operator of the given lambda closure type as "used".
-static void markLambdaCallOperatorUsed(Sema &S, CXXRecordDecl *Lambda) {
- CXXMethodDecl *CallOperator
- = cast<CXXMethodDecl>(
- Lambda->lookup(
- S.Context.DeclarationNames.getCXXOperatorName(OO_Call)).front());
- CallOperator->setReferenced();
- CallOperator->markUsed(S.Context);
-}
-
void Sema::DefineImplicitLambdaToFunctionPointerConversion(
- SourceLocation CurrentLocation,
- CXXConversionDecl *Conv)
-{
- CXXRecordDecl *LambdaClass = Conv->getParent();
-
- // Make sure that the lambda call operator is marked used.
- markLambdaCallOperatorUsed(*this, LambdaClass);
-
- Conv->markUsed(Context);
+ SourceLocation CurrentLocation,
+ CXXConversionDecl *Conv) {
+ CXXRecordDecl *Lambda = Conv->getParent();
+ CXXMethodDecl *CallOp = Lambda->getLambdaCallOperator();
+ // If we are defining a specialization of a conversion to function-ptr
+ // cache the deduced template arguments for this specialization
+ // so that we can use them to retrieve the corresponding call-operator
+ // and static-invoker.
+ const TemplateArgumentList *DeducedTemplateArgs = 0;
+
+ // Retrieve the corresponding call-operator specialization.
+ if (Lambda->isGenericLambda()) {
+ assert(Conv->isFunctionTemplateSpecialization());
+ FunctionTemplateDecl *CallOpTemplate =
+ CallOp->getDescribedFunctionTemplate();
+ DeducedTemplateArgs = Conv->getTemplateSpecializationArgs();
+ void *InsertPos = 0;
+ FunctionDecl *CallOpSpec = CallOpTemplate->findSpecialization(
+ DeducedTemplateArgs->data(),
+ DeducedTemplateArgs->size(),
+ InsertPos);
+ assert(CallOpSpec &&
+ "Conversion operator must have a corresponding call operator");
+ CallOp = cast<CXXMethodDecl>(CallOpSpec);
+ }
+ // Mark the call operator referenced (and add to pending instantiations
+ // if necessary).
+ // For both the conversion and static-invoker template specializations
+ // we construct their body's in this function, so no need to add them
+ // to the PendingInstantiations.
+ MarkFunctionReferenced(CurrentLocation, CallOp);
+
SynthesizedFunctionScope Scope(*this, Conv);
DiagnosticErrorTrap Trap(Diags);
+
+ // Retreive the static invoker...
+ CXXMethodDecl *Invoker = Lambda->getLambdaStaticInvoker();
+ // ... and get the corresponding specialization for a generic lambda.
+ if (Lambda->isGenericLambda()) {
+ assert(DeducedTemplateArgs &&
+ "Must have deduced template arguments from Conversion Operator");
+ FunctionTemplateDecl *InvokeTemplate =
+ Invoker->getDescribedFunctionTemplate();
+ void *InsertPos = 0;
+ FunctionDecl *InvokeSpec = InvokeTemplate->findSpecialization(
+ DeducedTemplateArgs->data(),
+ DeducedTemplateArgs->size(),
+ InsertPos);
+ assert(InvokeSpec &&
+ "Must have a corresponding static invoker specialization");
+ Invoker = cast<CXXMethodDecl>(InvokeSpec);
+ }
+ // Construct the body of the conversion function { return __invoke; }.
+ Expr *FunctionRef = BuildDeclRefExpr(Invoker, Invoker->getType(),
+ VK_LValue, Conv->getLocation()).take();
+ assert(FunctionRef && "Can't refer to __invoke function?");
+ Stmt *Return = ActOnReturnStmt(Conv->getLocation(), FunctionRef).take();
+ Conv->setBody(new (Context) CompoundStmt(Context, Return,
+ Conv->getLocation(),
+ Conv->getLocation()));
+
+ Conv->markUsed(Context);
+ Conv->setReferenced();
- // Return the address of the __invoke function.
-
- CXXMethodDecl *Invoke = LambdaClass->getLambdaStaticInvoker();
- Expr *FunctionRef = BuildDeclRefExpr(Invoke, Invoke->getType(),
- VK_LValue, Conv->getLocation()).take();
- assert(FunctionRef && "Can't refer to lambda static invoker function?");
- Stmt *Return = ActOnReturnStmt(Conv->getLocation(), FunctionRef).take();
- Conv->setBody(new (Context) CompoundStmt(Context, Return,
- Conv->getLocation(),
- Conv->getLocation()));
-
- // Fill in the static invoker function with a dummy implementation.
- // IR generation will fill in the actual details.
- Invoke->markUsed(Context);
- Invoke->setReferenced();
- Invoke->setBody(new (Context) CompoundStmt(Conv->getLocation()));
-
+ // Fill in the __invoke function with a dummy implementation. IR generation
+ // will fill in the actual details.
+ Invoker->markUsed(Context);
+ Invoker->setReferenced();
+ Invoker->setBody(new (Context) CompoundStmt(Conv->getLocation()));
+
if (ASTMutationListener *L = getASTMutationListener()) {
L->CompletedImplicitDefinition(Conv);
- L->CompletedImplicitDefinition(Invoke);
- }
+ L->CompletedImplicitDefinition(Invoker);
+ }
}
+
+
void Sema::DefineImplicitLambdaToBlockPointerConversion(
SourceLocation CurrentLocation,
CXXConversionDecl *Conv)
{
+ assert(!Conv->getParent()->isGenericLambda());\r
+
Conv->markUsed(Context);
SynthesizedFunctionScope Scope(*this, Conv);
SourceRange IntroducerRange,
CXXRecordDecl *Class,
CXXMethodDecl *CallOperator) {
- // FIXME: The conversion operator needs to be fixed for generic lambdas.
- if (Class->isGenericLambda()) return;
// Add the conversion to function pointer.
const FunctionProtoType *Proto
= CallOperator->getType()->getAs<FunctionProtoType>();
CallOperator->getBody()->getLocEnd());
Conversion->setAccess(AS_public);
Conversion->setImplicit(true);
- Class->addDecl(Conversion);
+
+ if (Class->isGenericLambda()) {
+ // Create a template version of the conversion operator, using the template
+ // parameter list of the function call operator.
+ FunctionTemplateDecl *TemplateCallOperator =
+ CallOperator->getDescribedFunctionTemplate();
+ FunctionTemplateDecl *ConversionTemplate =
+ FunctionTemplateDecl::Create(S.Context, Class,
+ Loc, Name,
+ TemplateCallOperator->getTemplateParameters(),
+ Conversion);
+ ConversionTemplate->setAccess(AS_public);
+ ConversionTemplate->setImplicit(true);
+ Conversion->setDescribedFunctionTemplate(ConversionTemplate);
+ Class->addDecl(ConversionTemplate);
+ } else
+ Class->addDecl(Conversion);
// Add a non-static member function that will be the result of
// the conversion with a certain unique ID.
Name = &S.Context.Idents.get(getLambdaStaticInvokerName());
+ // FIXME: Instead of passing in the CallOperator->getTypeSourceInfo()
+ // we should get a prebuilt TrivialTypeSourceInfo from Context
+ // using FunctionTy & Loc and get its TypeLoc as a FunctionProtoTypeLoc
+ // then rewire the parameters accordingly, by hoisting up the InvokeParams
+ // loop below and then use its Params to set Invoke->setParams(...) below.
+ // This would avoid the 'const' qualifier of the calloperator from
+ // contaminating the type of the invoker, which is currently adjusted
+ // in SemaTemplateDeduction.cpp:DeduceTemplateArguments.
CXXMethodDecl *Invoke
= CXXMethodDecl::Create(S.Context, Class, Loc,
DeclarationNameInfo(Name, Loc), FunctionTy,
Invoke->setParams(InvokeParams);
Invoke->setAccess(AS_private);
Invoke->setImplicit(true);
- Class->addDecl(Invoke);
+ if (Class->isGenericLambda()) {
+ FunctionTemplateDecl *TemplateCallOperator =
+ CallOperator->getDescribedFunctionTemplate();
+ FunctionTemplateDecl *StaticInvokerTemplate = FunctionTemplateDecl::Create(
+ S.Context, Class, Loc, Name,
+ TemplateCallOperator->getTemplateParameters(),
+ Invoke);
+ StaticInvokerTemplate->setAccess(AS_private);
+ StaticInvokerTemplate->setImplicit(true);
+ Invoke->setDescribedFunctionTemplate(StaticInvokerTemplate);
+ Class->addDecl(StaticInvokerTemplate);
+ } else
+ Class->addDecl(Invoke);
}
/// \brief Add a lambda's conversion to block pointer.
// non-explicit const conversion function to a block pointer having the
// same parameter and return types as the closure type's function call
// operator.
- if (getLangOpts().Blocks && getLangOpts().ObjC1)
+ // FIXME: Fix generic lambda to block conversions.
+ if (getLangOpts().Blocks && getLangOpts().ObjC1 &&
+ !Class->isGenericLambda())
addBlockPointerConversion(*this, IntroducerRange, Class, CallOperator);
// Finalize the lambda class.
}
// TODO: Implement capturing.
if (Lambda->isGenericLambda()) {
- if (Lambda->getCaptureDefault() != LCD_None) {
+ if (!Captures.empty() || Lambda->getCaptureDefault() != LCD_None) {
Diag(Lambda->getIntroducerRange().getBegin(),
diag::err_glambda_not_fully_implemented)
<< " capturing not implemented yet";
#include "clang/Sema/TemplateDeduction.h"
#include "TreeTransform.h"
#include "clang/AST/ASTContext.h"
+#include "clang/AST/ASTLambda.h"
#include "clang/AST/DeclObjC.h"
#include "clang/AST/DeclTemplate.h"
#include "clang/AST/Expr.h"
namespace clang {
using namespace sema;
-
/// \brief Various flags that control template argument deduction.
///
/// These flags can be bitwise-OR'd together.
return TDK_Success;
}
+/// \brief Given a function declaration (e.g. a generic lambda conversion \r
+/// function) that contains an 'auto' in its result type, substitute it \r
+/// with the same Deduced type that the TypeToReplaceAutoWith was deduced \r
+/// with.\r
+static inline void
+ReplaceAutoWithinFunctionReturnType(FunctionDecl *F,
+ QualType TypeToReplaceAutoWith, Sema &S) {
+ if (TypeToReplaceAutoWith->getContainedAutoType())
+ TypeToReplaceAutoWith = TypeToReplaceAutoWith->
+ getContainedAutoType()->getDeducedType();
+
+ QualType AutoResultType = F->getResultType();\r
+ assert(AutoResultType->getContainedAutoType()); \r
+ QualType DeducedResultType = S.SubstAutoType(AutoResultType, \r
+ TypeToReplaceAutoWith);
+ S.Context.adjustDeducedFunctionResultType(F, DeducedResultType);
+}
/// \brief Deduce template arguments for a templated conversion
/// function (C++ [temp.deduct.conv]) and, if successful, produce a
/// conversion function template specialization.
Sema::TemplateDeductionResult
-Sema::DeduceTemplateArguments(FunctionTemplateDecl *FunctionTemplate,
+Sema::DeduceTemplateArguments(FunctionTemplateDecl *ConversionTemplate,
QualType ToType,
CXXConversionDecl *&Specialization,
TemplateDeductionInfo &Info) {
- if (FunctionTemplate->isInvalidDecl())
+ if (ConversionTemplate->isInvalidDecl())
return TDK_Invalid;
CXXConversionDecl *Conv
- = cast<CXXConversionDecl>(FunctionTemplate->getTemplatedDecl());
+ = cast<CXXConversionDecl>(ConversionTemplate->getTemplatedDecl());
+
QualType FromType = Conv->getConversionType();
// Canonicalize the types for deduction.
// type that is required as the result of the conversion (call it
// A) as described in 14.8.2.4.
TemplateParameterList *TemplateParams
- = FunctionTemplate->getTemplateParameters();
+ = ConversionTemplate->getTemplateParameters();
SmallVector<DeducedTemplateArgument, 4> Deduced;
Deduced.resize(TemplateParams->size());
= DeduceTemplateArgumentsByTypeMatch(*this, TemplateParams,
P, A, Info, Deduced, TDF))
return Result;
-
+\r
+ // Create an Instantiation Scope for finalizing the operator.\r
+ LocalInstantiationScope InstScope(*this);\r
+ \r
+ CXXMethodDecl *LambdaCallOpSpec = 0;\r
+ bool GenericLambdaCallOperatorHasDeducedReturnType = false;
+ \r
+ // Having successfully deduced and matched the type of the conversion\r
+ // function against the destination type, if the destination type\r
+ // is a ptr-to-function and the source type is a generic lambda conversion\r
+ // to ptr-to-function, we know that the parameters of the destination \r
+ // ptr-to-function have matched successfully against those of our \r
+ // lambda's conversion function. \r
+ // For instance:\r
+ // int (*fp)(int) = [](auto a) { return a; };\r
+ // [template<class T> operator id<auto(*)(T)>() const]\r
+ // If it is indeed the conversion operator of a generic lambda then if\r
+ // not already done, create the corresponding specializations of the call \r
+ // operator and the static-invoker; and if the return type is auto, \r
+ // deduce the return type, and then check and see if it matches the ToType.\r
+\r
+ const bool IsGenericLambdaConversionOperator = \r
+ isLambdaConversionOperator(Conv);\r
+ if (IsGenericLambdaConversionOperator) {\r
+ const Type *FromTypePtr = P.getTypePtr();\r
+ const Type *ToTypePtr = A.getTypePtr();\r
+\r
+ assert(P->isPointerType()); \r
+ FromTypePtr = P->getPointeeType().getTypePtr();\r
+ assert(A->isPointerType());\r
+ ToTypePtr = A->getPointeeType().getTypePtr();\r
+ \r
+ CXXRecordDecl *LambdaClass = Conv->getParent();\r
+ assert(LambdaClass && LambdaClass->isGenericLambda()); \r
+\r
+ const FunctionType *ToFunType = ToTypePtr->getAs<FunctionType>();\r
+\r
+ // The specialization of the Generic Lambda Call Op, instantiated\r
+ // using the deduced parameters from the conversion function\r
+ // i.e.\r
+ // auto L = [](auto a) { return f(a); };\r
+ // int (*fp)(int) = L;\r
+ //\r
+\r
+ CXXMethodDecl *CallOp = LambdaClass->getLambdaCallOperator();\r
+ QualType CallOpResultType = CallOp->getResultType(); \r
+ GenericLambdaCallOperatorHasDeducedReturnType = \r
+ CallOpResultType->getContainedAutoType();\r
+ FunctionTemplateDecl *CallOpTemplate = \r
+ CallOp->getDescribedFunctionTemplate();\r
+\r
+ TemplateDeductionInfo OpInfo(Info.getLocation()); \r
+ FunctionDecl *CallOpSpec = 0;\r
+ // Use the deduced arguments so far, to specialize our generic\r
+ // lambda's call operator.\r
+ if (TemplateDeductionResult Result\r
+ = FinishTemplateArgumentDeduction(CallOpTemplate, Deduced, \r
+ 0, CallOpSpec, OpInfo))\r
+ return Result;\r
+ \r
+ bool HadToDeduceReturnTypeDuringCurrentCall = false;\r
+ // If we need to deduce the return type, do so (instantiates the callop).\r
+ if (GenericLambdaCallOperatorHasDeducedReturnType && \r
+ CallOpSpec->getResultType()->isUndeducedType()) {\r
+ HadToDeduceReturnTypeDuringCurrentCall = true;\r
+ DeduceReturnType(CallOpSpec, CallOpSpec->getPointOfInstantiation(),\r
+ /*Diagnose*/ true);\r
+ }\r
+ \r
+ LambdaCallOpSpec = cast<CXXMethodDecl>(CallOpSpec);\r
+ \r
+ // Check to see if the return type of the destination ptr-to-function\r
+ // matches the return type of the call operator.\r
+ if (!Context.hasSameType(LambdaCallOpSpec->getResultType(), \r
+ ToFunType->getResultType()))\r
+ return TDK_NonDeducedMismatch;\r
+ // Since we have succeeded in matching the source and destination\r
+ // ptr-to-functions (now including return type), and have successfully \r
+ // specialized our corresponding call operator, we are ready to\r
+ // specialize the static invoker with the deduced arguments of our\r
+ // ptr-to-function.\r
+ FunctionDecl *InvokerSpecialization = 0;\r
+ FunctionTemplateDecl *InvokerTemplate = LambdaClass->\r
+ getLambdaStaticInvoker()->getDescribedFunctionTemplate();\r
+\r
+ TemplateDeductionResult Result\r
+ = FinishTemplateArgumentDeduction(InvokerTemplate, Deduced, 0, \r
+ InvokerSpecialization, Info);\r
+ assert(Result == TDK_Success);\r
+ // Set the result type to match the corresponding call operator\r
+ // specialization's result type.\r
+ if (GenericLambdaCallOperatorHasDeducedReturnType && \r
+ InvokerSpecialization->getResultType()->isUndeducedType())\r
+ ReplaceAutoWithinFunctionReturnType(InvokerSpecialization,\r
+ LambdaCallOpSpec->getResultType(), *this);\r
+
+ // Ensure that static invoker doesn't have a const qualifier.
+ // FIXME: When creating the InvokerTemplate in SemaLambda.cpp
+ // do not use the CallOperator's TypeSourceInfo which allows
+ // the const qualifier to leak through.
+ const FunctionProtoType *InvokerFPT = InvokerSpecialization->
+ getType().getTypePtr()->castAs<FunctionProtoType>();
+ FunctionProtoType::ExtProtoInfo EPI = InvokerFPT->getExtProtoInfo();
+ EPI.TypeQuals = 0;
+ InvokerSpecialization->setType(Context.getFunctionType(
+ InvokerFPT->getResultType(), InvokerFPT->getArgTypes(),EPI));\r
+ \r
+ // Since the original conversion operator's parameters are the same \r
+ // entities as the lambda's call operator's, we introduce a mapping\r
+ // from the generic to the specialized parameters of the call operators.\r
+ // This only needs to be done in the absence of return type deduction,\r
+ // since deducing the return type entails instantiation which adds\r
+ // the parameter mapping to the CurrentInstantiationScope. \r
+ // This is necessary when transforming nested lambdas that do not\r
+ // capture.\r
+ // FIXME: This will be fixed once nested lambdas and capturing\r
+ // is implemented since it does require handling parameter \r
+ // packs correctly which might require careful calls to\r
+ // SemaTemplateInstantiate::addInstantiatedParametersToScope.\r
+ // if (!HadToDeduceReturnTypeDuringCurrentCall) { ... }
+ }
+ \r
+ \r
// Finish template argument deduction.
- LocalInstantiationScope InstScope(*this);
- FunctionDecl *Spec = 0;
- TemplateDeductionResult Result
- = FinishTemplateArgumentDeduction(FunctionTemplate, Deduced, 0, Spec,
- Info);
- Specialization = cast_or_null<CXXConversionDecl>(Spec);
+ FunctionDecl *ConversionSpec = 0;\r
+ TemplateDeductionResult Result\r
+ = FinishTemplateArgumentDeduction(ConversionTemplate, Deduced, 0, \r
+ ConversionSpec, Info);\r
+ Specialization = cast_or_null<CXXConversionDecl>(ConversionSpec);\r
+ if (Result == TDK_Success && GenericLambdaCallOperatorHasDeducedReturnType) {\r
+ // Set the return type of the conversion specialization, since even \r
+ // though we have ensured that the return types are compatible, if \r
+ // there is an auto in the return type of this conversion function, \r
+ // replace it permanently with the return type of the deduced lambda\r
+ // so we don't try and deduce against it.\r
+ assert(LambdaCallOpSpec);\r
+ if (ConversionSpec->getResultType()->isUndeducedType())\r
+ ReplaceAutoWithinFunctionReturnType(ConversionSpec, \r
+ LambdaCallOpSpec->getResultType(),\r
+ *this);\r
+ }
return Result;
}
// RUN: %clang_cc1 -fsyntax-only -std=c++1y %s -verify
-namespace return_type_deduction_ok {
- auto l = [](auto a) ->auto { return a; }(2);
- auto l2 = [](auto a) ->decltype(auto) { return a; }(2);
- auto l3 = [](auto a) { return a; }(2);
-
-}
namespace lambda_capturing {
// FIXME: Once return type deduction is implemented for generic lambdas
// this will need to be updated.
void test() {
int i = 10;
- auto L = [=](auto a) -> int { //expected-error{{unimplemented}}
- return i + a;
- };
- L(3);
+ {
+ auto L = [=](auto a) -> int { //expected-error{{unimplemented}}
+ return i + a;
+ };
+ L(3);
+ }
+ {
+ auto L = [i](auto a) -> int { //expected-error{{unimplemented}}
+ return i + a;
+ };
+ L(3);
+ }
+ {
+ auto L = [i = i](auto a) -> int { //expected-error{{unimplemented}}
+ return i + a;
+ };
+ L(3);
+ }
+
+
}
}
template void foo(int); //expected-note{{in instantiation of}}
}
-namespace conversion_operator {
-void test() {
- auto L = [](auto a) -> int { return a; };
- int (*fp)(int) = L; //expected-error{{no viable conversion}}
- }
-}
-
-namespace generic_lambda_as_default_argument_ok {
- void test(int i = [](auto a)->int { return a; }(3)) {
-
- }
-
-}
--- /dev/null
+// RUN: %clang_cc1 -std=c++1y -verify -fsyntax-only -fblocks %s
+// DONTRUNYET: %clang_cc1 -std=c++1y -verify -fsyntax-only -fblocks -fdelayed-template-parsing %s -DDELAYED_TEMPLATE_PARSING
+// DONTRUNYET: %clang_cc1 -std=c++1y -verify -fsyntax-only -fblocks -fms-extensions %s -DMS_EXTENSIONS
+// DONTRUNYET: %clang_cc1 -std=c++1y -verify -fsyntax-only -fblocks -fdelayed-template-parsing -fms-extensions %s -DMS_EXTENSIONS -DDELAYED_TEMPLATE_PARSING
+
+namespace explicit_call {
+int test() {
+ auto L = [](auto a) { return a; };
+ L.operator()(3);
+ L.operator()<char>(3.14); //expected-warning{{implicit conversion}}
+ return 0;
+}
+} //end ns
+
+namespace test_conversion_to_fptr {
+
+void f1(int (*)(int)) { }
+void f2(char (*)(int)) { } // expected-note{{candidate}}
+void g(int (*)(int)) { } // #1 expected-note{{candidate}}
+void g(char (*)(char)) { } // #2 expected-note{{candidate}}
+void h(int (*)(int)) { } // #3
+void h(char (*)(int)) { } // #4
+
+int test() {
+{
+ auto glambda = [](auto a) { return a; };
+ glambda(1);
+ f1(glambda); // OK
+ f2(glambda); // expected-error{{no matching function}}
+ g(glambda); // expected-error{{call to 'g' is ambiguous}}
+ h(glambda); // OK: calls #3 since it is convertible from ID
+
+ int& (*fpi)(int*) = [](auto* a) -> auto& { return *a; }; // OK
+
+}
+{
+
+ auto L = [](auto a) { return a; };
+ int (*fp)(int) = L;
+ fp(5);
+ L(3);
+ char (*fc)(char) = L;
+ fc('b');
+ L('c');
+ double (*fd)(double) = L;
+ fd(3.14);
+ fd(6.26);
+ L(4.25);
+}
+{
+ auto L = [](auto a) ->int { return a; }; //expected-note 2{{candidate template ignored}}
+ int (*fp)(int) = L;
+ char (*fc)(char) = L; //expected-error{{no viable conversion}}
+ double (*fd)(double) = L; //expected-error{{no viable conversion}}
+}
+
+}
+
+namespace more_converion_to_ptr_to_function_tests {
+
+
+int test() {
+ {
+ int& (*fpi)(int*) = [](auto* a) -> auto& { return *a; }; // OK
+ int (*fp2)(int) = [](auto b) -> int { return b; };
+ int (*fp3)(char) = [](auto c) -> int { return c; };
+ char (*fp4)(int) = [](auto d) { return d; }; //expected-error{{no viable conversion}}\
+ //expected-note{{candidate template ignored}}
+ char (*fp5)(char) = [](auto e) -> int { return e; }; //expected-error{{no viable conversion}}\
+ //expected-note{{candidate template ignored}}
+
+ fp2(3);
+ fp3('\n');
+ fp3('a');
+ return 0;
+ }
+} // end test()
+
+template<class ... Ts> void vfun(Ts ... ) { }
+
+int variadic_test() {
+
+ int (*fp)(int, char, double) = [](auto ... a) -> int { vfun(a...); return 4; };
+ fp(3, '4', 3.14);
+
+ int (*fp2)(int, char, double) = [](auto ... a) { vfun(a...); return 4; };
+ fp(3, '4', 3.14);
+ return 2;
+}
+
+} // end ns
+
+namespace conversion_operator {
+void test() {
+ auto L = [](auto a) -> int { return a; };
+ int (*fp)(int) = L;
+ int (&fp2)(int) = [](auto a) { return a; }; // expected-error{{non-const lvalue}}
+ int (&&fp3)(int) = [](auto a) { return a; }; // expected-error{{no viable conversion}}\
+ //expected-note{{candidate}}
+ }
+}
+
+}
+
+
+namespace return_type_deduction_ok {
+ auto l = [](auto a) ->auto { return a; }(2);
+ auto l2 = [](auto a) ->decltype(auto) { return a; }(2);
+ auto l3 = [](auto a) { return a; }(2);
+
+}
+
+namespace generic_lambda_as_default_argument_ok {
+ void test(int i = [](auto a)->int { return a; }(3)) {
+ }
+}