From 2a8b87e5a89a647ed24098e700aab7f59a920064 Mon Sep 17 00:00:00 2001 From: Faisal Vali Date: Fri, 30 May 2014 04:39:37 +0000 Subject: [PATCH] Fix 'this' capturing Generic lambdas used within default initializers (PR19876) http://llvm.org/bugs/show_bug.cgi?id=19876 The following C++1y code results in a crash: struct X { int m = 10; int n = [this](auto) { return m; }(20); }; When implicitly instantiating the generic lambda's call operator specialization body, Sema is unable to determine the current 'this' type when transforming the MemberExpr 'm' - since it looks for the nearest enclosing FunctionDeclDC - which is obviously null. I considered two ways to fix this: 1) In InstantiateFunctionDefinition, when the context is saved after the lambda scope info is created, retain the 'this' pointer. 2) Teach getCurrentThisType() to recognize it is within a generic lambda within an NSDMI/default-initializer and return the appropriate this type. I chose to implement #2 (though I confess I do not have a compelling reason for choosing it over #1). Richard Smith accepted the patch: http://reviews.llvm.org/D3935 Thank you! git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@209874 91177308-0d34-0410-b5e6-96231b3b80d8 --- lib/Sema/SemaExprCXX.cpp | 16 +++++++++++++++- .../SemaCXX/cxx1y-generic-lambdas-capturing.cpp | 17 ++++++++++++++++- 2 files changed, 31 insertions(+), 2 deletions(-) diff --git a/lib/Sema/SemaExprCXX.cpp b/lib/Sema/SemaExprCXX.cpp index 6ebe974875..41eceb1560 100644 --- a/lib/Sema/SemaExprCXX.cpp +++ b/lib/Sema/SemaExprCXX.cpp @@ -15,6 +15,7 @@ #include "clang/Sema/SemaInternal.h" #include "TypeLocBuilder.h" #include "clang/AST/ASTContext.h" +#include "clang/AST/ASTLambda.h" #include "clang/AST/CXXInheritance.h" #include "clang/AST/CharUnits.h" #include "clang/AST/DeclObjC.h" @@ -732,7 +733,20 @@ QualType Sema::getCurrentThisType() { if (method && method->isInstance()) ThisTy = method->getThisType(Context); } - + if (ThisTy.isNull()) { + if (isGenericLambdaCallOperatorSpecialization(CurContext) && + CurContext->getParent()->getParent()->isRecord()) { + // This is a generic lambda call operator that is being instantiated + // within a default initializer - so use the enclosing class as 'this'. + // There is no enclosing member function to retrieve the 'this' pointer + // from. + QualType ClassTy = Context.getTypeDeclType( + cast(CurContext->getParent()->getParent())); + // There are no cv-qualifiers for 'this' within default initializers, + // per [expr.prim.general]p4. + return Context.getPointerType(ClassTy); + } + } return ThisTy; } diff --git a/test/SemaCXX/cxx1y-generic-lambdas-capturing.cpp b/test/SemaCXX/cxx1y-generic-lambdas-capturing.cpp index 8bd4f4242c..b08d58abd2 100644 --- a/test/SemaCXX/cxx1y-generic-lambdas-capturing.cpp +++ b/test/SemaCXX/cxx1y-generic-lambdas-capturing.cpp @@ -1358,6 +1358,21 @@ template struct X { int run_char = X{}.foo('a'); int run_int = X{}.foo(4); } - #endif // MS_EXTENSIONS +namespace nsdmi_capturing_this { +struct X { + int m = 10; + int n = [this](auto) { return m; }(20); +}; + +template +struct XT { + T m = 10; + T n = [this](auto) { return m; }(20); +}; + +XT xt{}; + + +} -- 2.40.0