#include "TreeTransform.h"
#include "clang/AST/ASTConsumer.h"
#include "clang/AST/ASTContext.h"
-#include "clang/AST/ASTLambda.h"
#include "clang/AST/DeclTemplate.h"
#include "clang/AST/Expr.h"
#include "clang/Basic/LangOptions.h"
assert(Function->getPrimaryTemplate() && "No function template?");
if (Function->getPrimaryTemplate()->isMemberSpecialization())
break;
-
- // If this function is a generic lambda specialization, we are done.
- if (isGenericLambdaCallOperatorSpecialization(Function))
- break;
-
} else if (FunctionTemplateDecl *FunTmpl
= Function->getDescribedFunctionTemplate()) {
// Add the "injected" template arguments.
}
ExprResult TransformLambdaScope(LambdaExpr *E,
- CXXMethodDecl *NewCallOperator) {
- // If a lambda is undergoing transformation for instance in the
- // call to foo('a') below:
- // template<class T> void foo(T t) {
- // auto L1 = [](T a) { return a; };\r
- // auto L2 = [](char b) { return b; };
- // auto L3 = [](auto c) { return c; };
- // }
- // The AST nodes of the OldCallOperators within the primary template foo
- // are connected to the NewCallOperators within the specialization of foo.
- // - In the case of L1 and L2 we set the NewCallOperator to be considered
- // an instantiation of the OldCallOperator.
- // - In the generic lambda case, we set the NewTemplate to be considered
- // an "instantiation" of the OldTemplate.
- // See the documentation and use of get/setInstantiationOfMemberFunction
- // and get/setInstantiatedFromMemberTemplate to appreciate the relevance
- // of creating these links.
- // And so it goes on and on with nested generic lambdas.
- CXXMethodDecl *const OldCallOperator = E->getCallOperator();
- FunctionTemplateDecl *const NewCallOperatorTemplate =
- NewCallOperator->getDescribedFunctionTemplate();
- FunctionTemplateDecl *const OldCallOperatorTemplate =
- OldCallOperator->getDescribedFunctionTemplate();
-
- if (!NewCallOperatorTemplate)
- NewCallOperator->setInstantiationOfMemberFunction(OldCallOperator,
- TSK_ImplicitInstantiation);
- else {
- NewCallOperatorTemplate->setInstantiatedFromMemberTemplate(
- OldCallOperatorTemplate);
- // Set this as a specialization so we don't go digging into the
- // OldCallOperatorTemplate when retrieving the
- // 'FunctionDecl::getTemplateInstantiationPattern()'
- NewCallOperatorTemplate->setMemberSpecialization();
- }
- return inherited::TransformLambdaScope(E, NewCallOperator);
- }
- TemplateParameterList *TransformTemplateParameterList(\r
- TemplateParameterList *OrigTPL) {
- TemplateParameterList *NewTPL = 0;
- if (OrigTPL) {
- if (!OrigTPL->size()) return OrigTPL; // size 0, do nothing
-
- DeclContext *Owner = OrigTPL->getParam(0)->getDeclContext();
- TemplateDeclInstantiator DeclInstantiator(getSema(),
- /* DeclContext *Owner */ Owner, TemplateArgs);
- NewTPL = DeclInstantiator.SubstTemplateParams(OrigTPL);
- }
- return NewTPL;
+ CXXMethodDecl *CallOperator) {
+ CallOperator->setInstantiationOfMemberFunction(E->getCallOperator(),
+ TSK_ImplicitInstantiation);
+ return TreeTransform<TemplateInstantiator>::
+ TransformLambdaScope(E, CallOperator);
}
+
private:
ExprResult transformNonTypeTemplateParmRef(NonTypeTemplateParmDecl *parm,
SourceLocation loc,
/// \brief Transform the captures and body of a lambda expression.
ExprResult TransformLambdaScope(LambdaExpr *E, CXXMethodDecl *CallOperator);
- TemplateParameterList *TransformTemplateParameterList(
- TemplateParameterList *TPL) {
- return TPL;
- }
-
ExprResult TransformAddressOfOperand(Expr *E);
ExprResult TransformDependentScopeDeclRefExpr(DependentScopeDeclRefExpr *E,
bool IsAddressOfOperand);
QualType TreeTransform<Derived>::TransformDecltypeType(TypeLocBuilder &TLB,
DecltypeTypeLoc TL) {
const DecltypeType *T = TL.getTypePtr();
- // Don't transform a decltype construct that has already been transformed
- // into a non-dependent type.
- // Allows the following to compile:
- // auto L = [](auto a) {
- // return [](auto b) ->decltype(a) {
- // return b;
- // };
- //};
- if (!T->isInstantiationDependentType()) {
- DecltypeTypeLoc NewTL = TLB.push<DecltypeTypeLoc>(TL.getType());
- NewTL.setNameLoc(TL.getNameLoc());
- return NewTL.getType();
- }
// decltype expressions are not potentially evaluated contexts
EnterExpressionEvaluationContext Unevaluated(SemaRef, Sema::Unevaluated, 0,
ExprResult
TreeTransform<Derived>::TransformLambdaExpr(LambdaExpr *E) {
- getSema().PushLambdaScope();
- LambdaScopeInfo *LSI = getSema().getCurLambda();
- TemplateParameterList *const OrigTPL = E->getTemplateParameterList();
- TemplateParameterList *NewTPL = 0;
- // Transform the template parameters, and add them to the
- // current instantiation scope.
- if (OrigTPL) {
- NewTPL = getDerived().TransformTemplateParameterList(OrigTPL);
- }
- LSI->GLTemplateParameterList = NewTPL;
- // Transform the type of the lambda parameters and start the definition of
- // the lambda itself.
- TypeSourceInfo *OldCallOpTSI = E->getCallOperator()->getTypeSourceInfo();
- TypeSourceInfo *NewCallOpTSI = TransformType(OldCallOpTSI);
- if (!NewCallOpTSI)
+ // FIXME: Implement nested generic lambda transformations.
+ if (E->isGenericLambda()) {
+ getSema().Diag(E->getIntroducerRange().getBegin(),
+ diag::err_glambda_not_fully_implemented)
+ << " template transformation of generic lambdas not implemented yet";
+ return ExprError();
+ }
+ // Transform the type of the lambda parameters and start the definition of
+ // the lambda itself.
+ TypeSourceInfo *MethodTy
+ = TransformType(E->getCallOperator()->getTypeSourceInfo());
+ if (!MethodTy)
return ExprError();
// Create the local class that will describe the lambda.
CXXRecordDecl *Class
= getSema().createLambdaClosureType(E->getIntroducerRange(),
- NewCallOpTSI,
+ MethodTy,
/*KnownDependent=*/false);
getDerived().transformedLocalDecl(E->getLambdaClass(), Class);
E->getCallOperator()->param_size(),
0, ParamTypes, &Params))
return ExprError();
-
+ getSema().PushLambdaScope();
+ LambdaScopeInfo *LSI = getSema().getCurLambda();
+ // TODO: Fix for nested lambdas
+ LSI->GLTemplateParameterList = 0;
// Build the call operator.
- CXXMethodDecl *NewCallOperator
+ CXXMethodDecl *CallOperator
= getSema().startLambdaDefinition(Class, E->getIntroducerRange(),
- NewCallOpTSI,
+ MethodTy,
E->getCallOperator()->getLocEnd(),
Params);
- LSI->CallOperator = NewCallOperator;
- // Fix the Decl Contexts of the parameters within the call op function
- // prototype.
- getDerived().transformAttrs(E->getCallOperator(), NewCallOperator);
-
- TypeLoc NewCallOpTL = NewCallOpTSI->getTypeLoc();
- FunctionProtoTypeLoc NewFPTL = NewCallOpTL.castAs<FunctionProtoTypeLoc>();
- ParmVarDecl **NewParamDeclArray = NewFPTL.getParmArray();
- const unsigned NewNumArgs = NewFPTL.getNumArgs();
- for (unsigned I = 0; I < NewNumArgs; ++I) {
- NewParamDeclArray[I]->setOwningFunction(NewCallOperator);
- }
- // If this is a non-generic lambda, the parameters do not get added to the
- // current instantiation scope, so add them. This feels kludgey.
- // Anyway, it allows the following to compile when the enclosing template
- // is specialized and the entire lambda expression has to be
- // transformed. Without this FindInstantiatedDecl causes an assertion.
- // template<class T> void foo(T t) {
- // auto L = [](auto a) {
- // auto M = [](char b) { <-- note: non-generic lambda
- // auto N = [](auto c) {
- // int x = sizeof(a);
- // x = sizeof(b); <-- specifically this line
- // x = sizeof(c);
- // };
- // };
- // };
- // }
- // foo('a');
- //
- if (!E->isGenericLambda()) {
- for (unsigned I = 0; I < NewNumArgs; ++I)
- SemaRef.CurrentInstantiationScope->InstantiatedLocal(
- NewParamDeclArray[I], NewParamDeclArray[I]);
- }
- return getDerived().TransformLambdaScope(E, NewCallOperator);
+ getDerived().transformAttrs(E->getCallOperator(), CallOperator);
+
+ return getDerived().TransformLambdaScope(E, CallOperator);
}
template<typename Derived>
-// RUN: %clang_cc1 -std=c++1y -verify -fsyntax-only -fblocks -emit-llvm -o - %s
+// 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
//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);
void test(int i = [](auto a)->int { return a; }(3)) {
}
}
-
-namespace nested_non_capturing_lambda_tests {
-template<class ... Ts> void print(Ts ...) { }
-int test() {
-{
- auto L = [](auto a) {
- return [](auto b) {
- return b;
- };
- };
- auto M = L(3);
- M(4.15);
- }
-{
- int i = 10; //expected-note{{declared here}}
- auto L = [](auto a) {
- return [](auto b) { //expected-note{{begins here}}
- i = b; //expected-error{{cannot be implicitly captured}}
- return b;
- };
- };
- auto M = L(3);
- M(4.15); //expected-note{{instantiation}}
- }
- {
- auto L = [](auto a) {
- print("a = ", a, "\n");
- return [](auto b) ->decltype(a) {
- print("b = ", b, "\n");
- return b;
- };
- };
- auto M = L(3);
- M(4.15);
- }
-
-{
- auto L = [](auto a) ->decltype(a) {
- print("a = ", a, "\n");
- return [](auto b) ->decltype(a) { //expected-error{{no viable conversion}}\
- //expected-note{{candidate template ignored}}
- print("b = ", b, "\n");
- return b;
- };
- };
- auto M = L(3); //expected-note{{in instantiation of}}
- }
-{
- auto L = [](auto a) {
- print("a = ", a, "\n");
- return [](auto ... b) ->decltype(a) {
- print("b = ", b ..., "\n");
- return 4;
- };
- };
- auto M = L(3);
- M(4.15, 3, "fv");
-}
-
-{
- auto L = [](auto a) {
- print("a = ", a, "\n");
- return [](auto ... b) ->decltype(a) {
- print("b = ", b ..., "\n");
- return 4;
- };
- };
- auto M = L(3);
- int (*fp)(double, int, const char*) = M;
- fp(4.15, 3, "fv");
-}
-
-{
- auto L = [](auto a) {
- print("a = ", a, "\n");
- return [](char b) {
- return [](auto ... c) ->decltype(b) {
- print("c = ", c ..., "\n");
- return 42;
- };
- };
- };
- L(4);
- auto M = L(3);
- M('a');
- auto N = M('x');
- N("\n3 = ", 3, "\n6.14 = ", 6.14, "\n4'123'456 = ", 4'123'456);
- char (*np)(const char*, int, const char*, double, const char*, int) = N;
- np("\n3 = ", 3, "\n6.14 = ", 6.14, "\n4'123'456 = ", 4'123'456);
-}
-
-
-{
- auto L = [](auto a) {
- print("a = ", a, "\n");
- return [](decltype(a) b) {
- return [](auto ... c) ->decltype(b) {
- print("c = ", c ..., "\n");
- return 42;
- };
- };
- };
- L('4');
- auto M = L('3');
- M('a');
- auto N = M('x');
- N("\n3 = ", 3, "\n6.14 = ", 6.14, "\n4'123'456 = ", 4'123'456);
- char (*np)(const char*, int, const char*, double, const char*, int) = N;
- np("\n3 = ", 3, "\n6.14 = ", 6.14, "\n4'123'456 = ", 4'123'456);
-}
-
-
-{
- struct X {
- static void foo(double d) { }
- void test() {
- auto L = [](auto a) {
- print("a = ", a, "\n");
- foo(a);
- return [](decltype(a) b) {
- foo(b);
- foo(sizeof(a) + sizeof(b));
- return [](auto ... c) ->decltype(b) {
- print("c = ", c ..., "\n");
- foo(decltype(b){});
- foo(sizeof(decltype(a)*) + sizeof(decltype(b)*));
- return 42;
- };
- };
- };
- L('4');
- auto M = L('3');
- M('a');
- auto N = M('x');
- N("\n3 = ", 3, "\n6.14 = ", 6.14, "\n4'123'456 = ", 4'123'456);
- char (*np)(const char*, int, const char*, double, const char*, int) = N;
- np("\n3 = ", 3, "\n6.14 = ", 6.14, "\n4'123'456 = ", 4'123'456);
- }
-};
-X x;
-x.test();
-}
-// Make sure we can escape the function
-{
- struct X {
- static void foo(double d) { }
- auto test() {
- auto L = [](auto a) {
- print("a = ", a, "\n");
- foo(a);
- return [](decltype(a) b) {
- foo(b);
- foo(sizeof(a) + sizeof(b));
- return [](auto ... c) ->decltype(b) {
- print("c = ", c ..., "\n");
- foo(decltype(b){});
- foo(sizeof(decltype(a)*) + sizeof(decltype(b)*));
- return 42;
- };
- };
- };
- return L;
- }
-};
- X x;
- auto L = x.test();
- L('4');
- auto M = L('3');
- M('a');
- auto N = M('x');
- N("\n3 = ", 3, "\n6.14 = ", 6.14, "\n4'123'456 = ", 4'123'456);
- char (*np)(const char*, int, const char*, double, const char*, int) = N;
- np("\n3 = ", 3, "\n6.14 = ", 6.14, "\n4'123'456 = ", 4'123'456);
-}
-
-{
- struct X {
- static void foo(double d) { }
- auto test() {
- auto L = [](auto a) {
- print("a = ", a, "\n");
- foo(a);
- return [](decltype(a) b) {
- foo(b);
- foo(sizeof(a) + sizeof(b));
- return [](auto ... c) {
- print("c = ", c ..., "\n");
- foo(decltype(b){});
- foo(sizeof(decltype(a)*) + sizeof(decltype(b)*));
- return [](decltype(c) ... d) ->decltype(a) { //expected-note{{candidate}}
- print("d = ", d ..., "\n");
- foo(decltype(b){});
- foo(sizeof(decltype(a)*) + sizeof(decltype(b)*));
- return decltype(a){};
- };
- };
- };
- };
- return L;
- }
-};
- X x;
- auto L = x.test();
- L('4');
- auto M = L('3');
- M('a');
- auto N = M('x');
- auto O = N("\n3 = ", 3, "\n6.14 = ", 6.14, "\n4'123'456 = ", 4'123'456);
- char (*np)(const char*, int, const char*, double, const char*, int) = O;
- np("\n3 = ", 3, "\n6.14 = ", 6.14, "\n4'123'456 = ", 4'123'456);
- int (*np2)(const char*, int, const char*, double, const char*, int) = O; // expected-error{{no viable conversion}}
-
-}
-} // end test()
-
-namespace wrapped_within_templates {
-
-namespace explicit_return {
-template<class T> int fooT(T t) {
- auto L = [](auto a) -> void {
- auto M = [](char b) -> void {
- auto N = [](auto c) -> void {
- int x = 0;
- x = sizeof(a);
- x = sizeof(b);
- x = sizeof(c);
- };
- N('a');
- N(decltype(a){});
- };
- };
- L(t);
- L(3.14);
- return 0;
-}
-
-int run = fooT('a') + fooT(3.14);
-
-} // end explicit_return
-
-namespace implicit_return_deduction {
-template<class T> auto fooT(T t) {
- auto L = [](auto a) {
- auto M = [](char b) {
- auto N = [](auto c) {
- int x = 0;
- x = sizeof(a);
- x = sizeof(b);
- x = sizeof(c);
- };
- N('a');
- N(decltype(a){});
- };
- };
- L(t);
- L(3.14);
- return 0;
-}
-
-int run = fooT('a') + fooT(3.14);
-
-template<class ... Ts> void print(Ts ... ts) { }
-
-template<class F, class ... Rest> using first = F;
-
-template<class ... Ts> auto fooV(Ts ... ts) {
- auto L = [](auto ... a) {
- auto M = [](decltype(a) ... b) {
- auto N = [](auto c) {
- int x = 0;
- x = sizeof...(a);
- x = sizeof...(b);
- x = sizeof(c);
- };
- N('a');
- N(N);
- N(first<Ts...>{});
- };
- M(a...);
- print("a = ", a..., "\n");
- };
- L(L, ts...);
- print("ts = ", ts..., "\n");
- return 0;
-}
-
-int run2 = fooV(3.14, " ", '4', 5) + fooV("BC", 3, 2.77, 'A', float{}, short{}, unsigned{});
-
-} //implicit_return_deduction
-
-
-} //wrapped_within_templates
-
-namespace at_ns_scope {
- void foo(double d) { }
- auto test() {
- auto L = [](auto a) {
- print("a = ", a, "\n");
- foo(a);
- return [](decltype(a) b) {
- foo(b);
- foo(sizeof(a) + sizeof(b));
- return [](auto ... c) {
- print("c = ", c ..., "\n");
- foo(decltype(b){});
- foo(sizeof(decltype(a)*) + sizeof(decltype(b)*));
- return [](decltype(c) ... d) ->decltype(a) { //expected-note{{candidate}}
- print("d = ", d ..., "\n");
- foo(decltype(b){});
- foo(sizeof(decltype(a)*) + sizeof(decltype(b)*));
- return decltype(a){};
- };
- };
- };
- };
- return L;
- }
-auto L = test();
-auto L_test = L('4');
-auto M = L('3');
-auto M_test = M('a');
-auto N = M('x');
-auto O = N("\n3 = ", 3, "\n6.14 = ", 6.14, "\n4'123'456 = ", 4'123'456);
-char (*np)(const char*, int, const char*, double, const char*, int) = O;
-auto NP_result = np("\n3 = ", 3, "\n6.14 = ", 6.14, "\n4'123'456 = ", 4'123'456);
-int (*np2)(const char*, int, const char*, double, const char*, int) = O; // expected-error{{no viable conversion}}
-
-
-
-}
-
-namespace variadic_tests_1 {
-template<class ... Ts> void print(Ts ... ts) { }
-
-template<class F, class ... Rest> using FirstType = F;
-template<class F, class ... Rest> F& FirstArg(F& f, Rest...) { return f; }
-
-template<class ... Ts> int fooV(Ts ... ts) {
- auto L = [](auto ... a) -> void {
- auto M = [](decltype(a) ... b) -> void {
- auto N = [](auto c) -> void {
- int x = 0;
- x = sizeof...(a);
- x = sizeof...(b);
- x = sizeof(c);
- };
- N('a');
- N(N);
- N(FirstType<Ts...>{});
- };
- M(a...);
- print("a = ", a..., "\n");
- };
- L(L, ts...);
- print("ts = ", ts..., "\n");
- return 0;
-}
-
-int run2 = fooV(3.14, " ", '4', 5) + fooV("BC", 3, 2.77, 'A', float{}, short{}, unsigned{});
-
-namespace more_variadic_1 {
-
-template<class ... Ts> int fooV(Ts ... ts) {
- auto L = [](auto ... a) {
- auto M = [](decltype(a) ... b) -> void {
- auto N = [](auto c) -> void {
- int x = 0;
- x = sizeof...(a);
- x = sizeof...(b);
- x = sizeof(c);
- };
- N('a');
- N(N);
- N(FirstType<Ts...>{});
- };
- M(a...);
- return M;
- };
- auto M = L(L, ts...);
- decltype(L(L, ts...)) (*fp)(decltype(L), decltype(ts) ...) = L;
- void (*fp2)(decltype(L), decltype(ts) ...) = L(L, ts...);
-
- {
- auto L = [](auto ... a) {
- auto M = [](decltype(a) ... b) {
- auto N = [](auto c) -> void {
- int x = 0;
- x = sizeof...(a);
- x = sizeof...(b);
- x = sizeof(c);
- };
- N('a');
- N(N);
- N(FirstType<Ts...>{});
- return N;
- };
- M(a...);
- return M;
- };
- auto M = L(L, ts...);
- decltype(L(L, ts...)) (*fp)(decltype(L), decltype(ts) ...) = L;
- fp(L, ts...);
- decltype(L(L, ts...)(L, ts...)) (*fp2)(decltype(L), decltype(ts) ...) = L(L, ts...);
- fp2 = fp(L, ts...);
- void (*fp3)(char) = fp2(L, ts...);
- fp3('a');
- }
- return 0;
-}
-
-int run2 = fooV(3.14, " ", '4', 5) + fooV("BC", 3, 2.77, 'A', float{}, short{}, unsigned{});
-
-
-} //end ns more_variadic_1
-
-} // end ns variadic_tests_1
-
-namespace at_ns_scope_within_class_member {
- struct X {
- static void foo(double d) { }
- auto test() {
- auto L = [](auto a) {
- print("a = ", a, "\n");
- foo(a);
- return [](decltype(a) b) {
- foo(b);
- foo(sizeof(a) + sizeof(b));
- return [](auto ... c) {
- print("c = ", c ..., "\n");
- foo(decltype(b){});
- foo(sizeof(decltype(a)*) + sizeof(decltype(b)*));
- return [](decltype(c) ... d) ->decltype(a) { //expected-note{{candidate}}
- print("d = ", d ..., "\n");
- foo(decltype(b){});
- foo(sizeof(decltype(a)*) + sizeof(decltype(b)*));
- return decltype(a){};
- };
- };
- };
- };
- return L;
- }
-};
-X x;
-auto L = x.test();
-auto L_test = L('4');
-auto M = L('3');
-auto M_test = M('a');
-auto N = M('x');
-auto O = N("\n3 = ", 3, "\n6.14 = ", 6.14, "\n4'123'456 = ", 4'123'456);
-char (*np)(const char*, int, const char*, double, const char*, int) = O;
-auto NP_result = np("\n3 = ", 3, "\n6.14 = ", 6.14, "\n4'123'456 = ", 4'123'456);
-int (*np2)(const char*, int, const char*, double, const char*, int) = O; // expected-error{{no viable conversion}}
-
-} //end at_ns_scope_within_class_member
-
-
-namespace nested_generic_lambdas_123 {
-void test() {
- auto L = [](auto a) -> int {
- auto M = [](auto b, decltype(a) b2) -> int {
- return 1;
- };
- M(a, a);
- };
- L(3);
-}
-template<class T> void foo(T) {
- auto L = [](auto a) { return a; };
-}
-template void foo(int);
-} // end ns nested_generic_lambdas_123
-
-
-} // end ns nested_non_capturing_lambda_tests
-
\ No newline at end of file