Hi rsmith, doug.gregor,
See 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);
};
This is because when implicitly instantiating the generic lambda's call
operator specialization body, Sema gets confused and is unable to determine the
current 'this' type when transforming the MemberExpr 'm'.
That is SemaExprCXX.cpp:Sema::getCurrentThisType() is unable to calculate that
the this type should be X* since it looks for the nearest enclosing
FunctionDeclDC - which is obviously null.
I suppose there are 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 and return the appropriate this type.
I am not sure which way is definitely better - but either one seemed easy to
implement.
I chose #2 - although I can't think of a good reason for choosing it over #1.
Feedback will be welcome - and especially if there is another option that
might be even more robust.
Thanks!
http://reviews.llvm.org/D3935
Files:
lib/Sema/SemaExprCXX.cpp
test/SemaCXX/cxx1y-generic-lambdas-capturing.cpp
Index: lib/Sema/SemaExprCXX.cpp
===================================================================
--- lib/Sema/SemaExprCXX.cpp
+++ 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"
@@ -736,7 +737,20 @@
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 an NSDMI - 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()));
+ // Unlike for within methods, we don't have to worry about adding
+ // CVR qualifications in this context. Just get the pointer to
+ // the enclosing class.
+ return Context.getPointerType(ClassTy);
+ }
+ }
return ThisTy;
}
Index: test/SemaCXX/cxx1y-generic-lambdas-capturing.cpp
===================================================================
--- test/SemaCXX/cxx1y-generic-lambdas-capturing.cpp
+++ test/SemaCXX/cxx1y-generic-lambdas-capturing.cpp
@@ -1358,6 +1358,21 @@
int run_char = X<int>{}.foo('a');
int run_int = X<double>{}.foo(4);
}
+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{};
+
+
+}
#endif // MS_EXTENSIONS
Index: lib/Sema/SemaExprCXX.cpp
===================================================================
--- lib/Sema/SemaExprCXX.cpp
+++ 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"
@@ -736,7 +737,20 @@
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 an NSDMI - 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()));
+ // Unlike for within methods, we don't have to worry about adding
+ // CVR qualifications in this context. Just get the pointer to
+ // the enclosing class.
+ return Context.getPointerType(ClassTy);
+ }
+ }
return ThisTy;
}
Index: test/SemaCXX/cxx1y-generic-lambdas-capturing.cpp
===================================================================
--- test/SemaCXX/cxx1y-generic-lambdas-capturing.cpp
+++ test/SemaCXX/cxx1y-generic-lambdas-capturing.cpp
@@ -1358,6 +1358,21 @@
int run_char = X<int>{}.foo('a');
int run_int = X<double>{}.foo(4);
}
+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{};
+
+
+}
#endif // MS_EXTENSIONS
_______________________________________________
cfe-commits mailing list
[email protected]
http://lists.cs.uiuc.edu/mailman/listinfo/cfe-commits