llvm-project/clang/test/SemaCXX/cxx1z-lambda-star-this.cpp

232 lines
5.9 KiB
C++
Raw Normal View History

// RUN: %clang_cc1 -std=c++1z -verify -fsyntax-only -fblocks -emit-llvm-only %s
// RUN: %clang_cc1 -std=c++1z -verify -fsyntax-only -fblocks -fdelayed-template-parsing %s -DDELAYED_TEMPLATE_PARSING
// RUN: %clang_cc1 -std=c++1z -verify -fsyntax-only -fblocks -fms-extensions %s -DMS_EXTENSIONS
// RUN: %clang_cc1 -std=c++1z -verify -fsyntax-only -fblocks -fdelayed-template-parsing -fms-extensions %s -DMS_EXTENSIONS -DDELAYED_TEMPLATE_PARSING
Fix cv-qualification of '*this' captures and nasty bug PR27507 The bug report by Gonzalo (https://llvm.org/bugs/show_bug.cgi?id=27507 -- which results in clang crashing when generic lambdas that capture 'this' are instantiated in contexts where the Functionscopeinfo stack is not in a reliable state - yet getCurrentThisType expects it to be) - unearthed some additional bugs in regards to maintaining proper cv qualification through 'this' when performing by value captures of '*this'. This patch attempts to correct those bugs and makes the following changes: o) when capturing 'this', we do not need to remember the type of 'this' within the LambdaScopeInfo's Capture - it is never really used for a this capture - so remove it. o) teach getCurrentThisType to walk the stack of lambdas (even in scenarios where we run out of LambdaScopeInfo's such as when instantiating call operators) looking for by copy captures of '*this' and resetting the type of 'this' based on the constness of that capturing lambda's call operator. This patch has been baking in review-hell for > 6 weeks - all the comments so far have been addressed and the bug (that it addresses in passing, and I regret not submitting as a separate patch initially) has been reported twice independently, so is frequent and important for us not to just sit on. I merged the cv qualification-fix and the PR-fix initially in one patch, since they resulted from my initial implementation of star-this and so were related. If someone really feels strongly, I can put in the time to revert this - separate the two out - and recommit. I won't claim it's immunized against all bugs, but I feel confident enough about the fix to land it for now. llvm-svn: 272480
2016-06-12 00:41:54 +08:00
template<class, class> constexpr bool is_same = false;
template<class T> constexpr bool is_same<T, T> = true;
namespace test_star_this {
namespace ns1 {
class A {
int x = 345;
auto foo() {
(void) [*this, this] { }; //expected-error{{'this' can appear only once}}
(void) [this] { ++x; };
(void) [*this] { ++x; }; //expected-error{{read-only variable}}
(void) [*this] () mutable { ++x; };
(void) [=] { return x; };
(void) [&, this] { return x; };
(void) [=, *this] { return x; };
(void) [&, *this] { return x; };
}
};
} // end ns1
namespace ns2 {
class B {
B(const B&) = delete; //expected-note{{deleted here}}
int *x = (int *) 456;
void foo() {
(void)[this] { return x; };
(void)[*this] { return x; }; //expected-error{{call to deleted}}
}
};
} // end ns2
namespace ns3 {
class B {
B(const B&) = delete; //expected-note2{{deleted here}}
int *x = (int *) 456;
public:
template<class T = int>
void foo() {
(void)[this] { return x; };
(void)[*this] { return x; }; //expected-error2{{call to deleted}}
}
B() = default;
} b;
B *c = (b.foo(), nullptr); //expected-note{{in instantiation}}
} // end ns3
namespace ns4 {
template<class U>
class B {
B(const B&) = delete; //expected-note{{deleted here}}
double d = 3.14;
public:
template<class T = int>
auto foo() {
const auto &L = [*this] (auto a) mutable { //expected-error{{call to deleted}}
d += a;
return [this] (auto b) { return d +=b; };
};
}
B() = default;
};
void main() {
B<int*> b;
b.foo(); //expected-note{{in instantiation}}
} // end main
} // end ns4
Fix cv-qualification of '*this' captures and nasty bug PR27507 The bug report by Gonzalo (https://llvm.org/bugs/show_bug.cgi?id=27507 -- which results in clang crashing when generic lambdas that capture 'this' are instantiated in contexts where the Functionscopeinfo stack is not in a reliable state - yet getCurrentThisType expects it to be) - unearthed some additional bugs in regards to maintaining proper cv qualification through 'this' when performing by value captures of '*this'. This patch attempts to correct those bugs and makes the following changes: o) when capturing 'this', we do not need to remember the type of 'this' within the LambdaScopeInfo's Capture - it is never really used for a this capture - so remove it. o) teach getCurrentThisType to walk the stack of lambdas (even in scenarios where we run out of LambdaScopeInfo's such as when instantiating call operators) looking for by copy captures of '*this' and resetting the type of 'this' based on the constness of that capturing lambda's call operator. This patch has been baking in review-hell for > 6 weeks - all the comments so far have been addressed and the bug (that it addresses in passing, and I regret not submitting as a separate patch initially) has been reported twice independently, so is frequent and important for us not to just sit on. I merged the cv qualification-fix and the PR-fix initially in one patch, since they resulted from my initial implementation of star-this and so were related. If someone really feels strongly, I can put in the time to revert this - separate the two out - and recommit. I won't claim it's immunized against all bugs, but I feel confident enough about the fix to land it for now. llvm-svn: 272480
2016-06-12 00:41:54 +08:00
namespace ns5 {
struct X {
double d = 3.14;
X(const volatile X&);
void foo() {
}
void foo() const { //expected-note{{const}}
auto L = [*this] () mutable {
static_assert(is_same<decltype(this), X*>);
++d;
auto M = [this] {
static_assert(is_same<decltype(this), X*>);
++d;
auto N = [] {
static_assert(is_same<decltype(this), X*>);
};
};
};
auto L1 = [*this] {
static_assert(is_same<decltype(this), const X*>);
auto M = [this] () mutable {
static_assert(is_same<decltype(this), const X*>);
auto N = [] {
static_assert(is_same<decltype(this), const X*>);
};
};
auto M2 = [*this] () mutable {
static_assert(is_same<decltype(this), X*>);
auto N = [] {
static_assert(is_same<decltype(this), X*>);
};
};
};
auto GL1 = [*this] (auto a) {
static_assert(is_same<decltype(this), const X*>);
auto M = [this] (auto b) mutable {
static_assert(is_same<decltype(this), const X*>);
auto N = [] (auto c) {
static_assert(is_same<decltype(this), const X*>);
};
return N;
};
auto M2 = [*this] (auto a) mutable {
static_assert(is_same<decltype(this), X*>);
auto N = [] (auto b) {
static_assert(is_same<decltype(this), X*>);
};
return N;
};
return [=](auto a) mutable { M(a)(a); M2(a)(a); };
};
GL1("abc")("abc");
auto L2 = [this] () mutable {
static_assert(is_same<decltype(this), const X*>);
++d; //expected-error{{cannot assign}}
};
auto GL = [*this] (auto a) mutable {
static_assert(is_same<decltype(this), X*>);
++d;
auto M = [this] (auto b) {
static_assert(is_same<decltype(this), X*>);
++d;
auto N = [] (auto c) {
static_assert(is_same<decltype(this), X*>);
};
N(3.14);
};
M("abc");
};
GL(3.14);
}
void foo() volatile const {
auto L = [this] () {
static_assert(is_same<decltype(this), const volatile X*>);
auto M = [*this] () mutable {
static_assert(is_same<decltype(this), X*>);
auto N = [this] {
static_assert(is_same<decltype(this), X*>);
auto M = [] {
static_assert(is_same<decltype(this), X*>);
};
};
auto N2 = [*this] {
static_assert(is_same<decltype(this), const X*>);
};
};
auto M2 = [*this] () {
static_assert(is_same<decltype(this), const X*>);
auto N = [this] {
static_assert(is_same<decltype(this), const X*>);
};
};
};
}
};
} //end ns5
namespace ns6 {
struct X {
double d;
auto foo() const {
auto L = [*this] () mutable {
auto M = [=] (auto a) {
auto N = [this] {
++d;
static_assert(is_same<decltype(this), X*>);
auto O = [*this] {
static_assert(is_same<decltype(this), const X*>);
};
};
N();
static_assert(is_same<decltype(this), X*>);
};
return M;
};
return L;
}
};
int main() {
auto L = X{}.foo();
auto M = L();
M(3.14);
}
} // end ns6
namespace ns7 {
struct X {
double d;
X();
X(const X&);
X(X&) = delete;
auto foo() const {
//OK - the object used to initialize our capture is a const object and so prefers the non-deleted ctor.
const auto &&L = [*this] { };
}
};
int main() {
X x;
x.foo();
}
} // end ns7
} //end ns test_star_this
Fix cv-qualification of '*this' captures and nasty bug PR27507 The bug report by Gonzalo (https://llvm.org/bugs/show_bug.cgi?id=27507 -- which results in clang crashing when generic lambdas that capture 'this' are instantiated in contexts where the Functionscopeinfo stack is not in a reliable state - yet getCurrentThisType expects it to be) - unearthed some additional bugs in regards to maintaining proper cv qualification through 'this' when performing by value captures of '*this'. This patch attempts to correct those bugs and makes the following changes: o) when capturing 'this', we do not need to remember the type of 'this' within the LambdaScopeInfo's Capture - it is never really used for a this capture - so remove it. o) teach getCurrentThisType to walk the stack of lambdas (even in scenarios where we run out of LambdaScopeInfo's such as when instantiating call operators) looking for by copy captures of '*this' and resetting the type of 'this' based on the constness of that capturing lambda's call operator. This patch has been baking in review-hell for > 6 weeks - all the comments so far have been addressed and the bug (that it addresses in passing, and I regret not submitting as a separate patch initially) has been reported twice independently, so is frequent and important for us not to just sit on. I merged the cv qualification-fix and the PR-fix initially in one patch, since they resulted from my initial implementation of star-this and so were related. If someone really feels strongly, I can put in the time to revert this - separate the two out - and recommit. I won't claim it's immunized against all bugs, but I feel confident enough about the fix to land it for now. llvm-svn: 272480
2016-06-12 00:41:54 +08:00