From: Douglas Gregor Date: Thu, 16 Feb 2012 21:36:18 +0000 (+0000) Subject: Lambda closure types are always considered to be like "local" classes, X-Git-Url: https://granicus.if.org/sourcecode?a=commitdiff_plain;h=7bdc15252ca2415f149ad812f0e5184d758e6105;p=clang Lambda closure types are always considered to be like "local" classes, even if they are not within a function scope. Teach template instantiation to treat them as such, and make sure that we have a local instantiation scope when instantiating default arguments and static data members. git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@150725 91177308-0d34-0410-b5e6-96231b3b80d8 --- diff --git a/lib/Sema/SemaExpr.cpp b/lib/Sema/SemaExpr.cpp index 6b66a42ad3..5202f96354 100644 --- a/lib/Sema/SemaExpr.cpp +++ b/lib/Sema/SemaExpr.cpp @@ -3128,6 +3128,7 @@ ExprResult Sema::BuildCXXDefaultArgExpr(SourceLocation CallLoc, // the semantic constraints are checked, at the point where the // default argument expression appears. ContextRAII SavedContext(*this, FD); + LocalInstantiationScope Local(*this); Result = SubstExpr(UninstExpr, ArgList); } if (Result.isInvalid()) diff --git a/lib/Sema/SemaTemplateInstantiateDecl.cpp b/lib/Sema/SemaTemplateInstantiateDecl.cpp index f480825412..d491dfc51e 100644 --- a/lib/Sema/SemaTemplateInstantiateDecl.cpp +++ b/lib/Sema/SemaTemplateInstantiateDecl.cpp @@ -2629,7 +2629,8 @@ void Sema::InstantiateStaticDataMemberDefinition( // Enter the scope of this instantiation. We don't use // PushDeclContext because we don't have a scope. ContextRAII previousContext(*this, Var->getDeclContext()); - + LocalInstantiationScope Local(*this); + VarDecl *OldVar = Var; Var = cast_or_null(SubstDecl(Def, Var->getDeclContext(), getTemplateInstantiationArgs(Var))); @@ -2644,7 +2645,8 @@ void Sema::InstantiateStaticDataMemberDefinition( DeclGroupRef DG(Var); Consumer.HandleTopLevelDecl(DG); } - + Local.Exit(); + if (Recursive) { // Define any newly required vtables. DefineUsedVTables(); @@ -3096,7 +3098,8 @@ NamedDecl *Sema::FindInstantiatedDecl(SourceLocation Loc, NamedDecl *D, DeclContext *ParentDC = D->getDeclContext(); if (isa(D) || isa(D) || isa(D) || isa(D) || - (ParentDC->isFunctionOrMethod() && ParentDC->isDependentContext())) { + (ParentDC->isFunctionOrMethod() && ParentDC->isDependentContext()) || + (isa(D) && cast(D)->isLambda())) { // D is a local of some kind. Look into the map of local // declarations to their instantiations. typedef LocalInstantiationScope::DeclArgumentPack DeclArgumentPack; diff --git a/test/CXX/expr/expr.prim/expr.prim.lambda/templates.cpp b/test/CXX/expr/expr.prim/expr.prim.lambda/templates.cpp index 14491cc3b2..49b9c66b1c 100644 --- a/test/CXX/expr/expr.prim/expr.prim.lambda/templates.cpp +++ b/test/CXX/expr/expr.prim/expr.prim.lambda/templates.cpp @@ -114,3 +114,36 @@ namespace p5 { template void double_capture(NonConstCopy&); } + +namespace NonLocalLambdaInstantation { + template + struct X { + static int value; + }; + + template + int X::value = []{ return T(); }(); // expected-error{{cannot initialize a variable of type 'int' with an rvalue of type 'int *'}} + + template int X::value; + template int X::value; + template int X::value; // expected-note{{in instantiation of static data member }} + + template + void defaults(int x = []{ return T(); }()) { }; // expected-error{{cannot initialize a parameter of type 'int' with an rvalue of type 'int *'}} \ + // expected-note{{passing argument to parameter 'x' here}} + + void call_defaults() { + defaults(); + defaults(); + defaults(); // expected-note{{in instantiation of default function argument expression for 'defaults' required here}} + } + + template + struct X2 { + int x = []{ return T(); }(); // expected-error{{cannot initialize a member subobject of type 'int' with an rvalue of type 'int *'}} + }; + + X2 x2i; + X2 x2f; + X2 x2ip; // expected-note{{in instantiation of template class 'NonLocalLambdaInstantation::X2' requested here}} +}