]> granicus.if.org Git - clang/commitdiff
Fix 'this' capturing Generic lambdas used within default initializers (PR19876)
authorFaisal Vali <faisalv@yahoo.com>
Fri, 30 May 2014 04:39:37 +0000 (04:39 +0000)
committerFaisal Vali <faisalv@yahoo.com>
Fri, 30 May 2014 04:39:37 +0000 (04:39 +0000)
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
test/SemaCXX/cxx1y-generic-lambdas-capturing.cpp

index 6ebe9748756099c77d12a27c1d0349df8a880fad..41eceb156079bcd976ed98e8e7ab4eb4cc3e0109 100644 (file)
@@ -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<CXXRecordDecl>(CurContext->getParent()->getParent()));
+      // There are no cv-qualifiers for 'this' within default initializers, 
+      // per [expr.prim.general]p4.
+      return Context.getPointerType(ClassTy);
+    }
+  }
   return ThisTy;
 }
 
index 8bd4f4242c1df30e219c32e4e242185fa5f194d9..b08d58abd2a9c3dedb590b76068427a95fdec868 100644 (file)
@@ -1358,6 +1358,21 @@ template<class R> struct X {
 int run_char = X<int>{}.foo('a');
 int run_int = X<double>{}.foo(4);
 }
-
 #endif // MS_EXTENSIONS
 
+namespace nsdmi_capturing_this {
+struct X {
+  int m = 10;
+  int n = [this](auto) { return m; }(20);
+};
+
+template<class T>
+struct XT {
+  T m = 10;
+  T n = [this](auto) { return m; }(20);
+};
+
+XT<int> xt{};
+
+
+}