I forgot the () in the lambda definition, this should be: .. auto l = [this] { auto l = []() EXCLUSIVE_LOCKS_REQUIRED(mu_) {}; }; ..
Doesn't change the fact that clang segfaults without this revert, though. On Tue, May 2, 2017 at 2:38 PM, Daniel Jasper via cfe-commits < cfe-commits@lists.llvm.org> wrote: > Author: djasper > Date: Tue May 2 07:38:27 2017 > New Revision: 301916 > > URL: http://llvm.org/viewvc/llvm-project?rev=301916&view=rev > Log: > Revert r301735 (and subsequent r301786). > > It leads to clang crashing, e.g. on this short code fragment (added to > test/SemaCXX/warn-thread-safety-parsing.cpp): > > class SomeClass { > public: > void foo() { > auto l = [this] { auto l = [] EXCLUSIVE_LOCKS_REQUIRED(mu_) {}; }; > } > Mutex mu_; > }; > > Modified: > cfe/trunk/lib/Sema/SemaExprCXX.cpp > cfe/trunk/test/SemaCXX/cxx1z-lambda-star-this.cpp > > Modified: cfe/trunk/lib/Sema/SemaExprCXX.cpp > URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Sema/ > SemaExprCXX.cpp?rev=301916&r1=301915&r2=301916&view=diff > ============================================================ > ================== > --- cfe/trunk/lib/Sema/SemaExprCXX.cpp (original) > +++ cfe/trunk/lib/Sema/SemaExprCXX.cpp Tue May 2 07:38:27 2017 > @@ -901,35 +901,17 @@ static QualType adjustCVQualifiersForCXX > // capturing lamdbda's call operator. > // > > - // Since the FunctionScopeInfo stack is representative of the lexical > - // nesting of the lambda expressions during initial parsing (and is the > best > - // place for querying information about captures about lambdas that are > - // partially processed) and perhaps during instantiation of function > templates > - // that contain lambda expressions that need to be transformed BUT not > - // necessarily during instantiation of a nested generic lambda's > function call > - // operator (which might even be instantiated at the end of the TU) - > at which > - // time the DeclContext tree is mature enough to query capture > information > - // reliably - we use a two pronged approach to walk through all the > lexically > - // enclosing lambda expressions: > - // > - // 1) Climb down the FunctionScopeInfo stack as long as each item > represents > - // a Lambda (i.e. LambdaScopeInfo) AND each LSI's 'closure-type' is > lexically > - // enclosed by the call-operator of the LSI below it on the stack > (while > - // tracking the enclosing DC for step 2 if needed). Note the topmost > LSI on > - // the stack represents the innermost lambda. > - // > - // 2) Iterate out through the DeclContext chain (if it represents a > lambda's > - // call operator, and therefore must be a generic lambda's call > operator, > - // which is the only time an inconsistency between the LSI and the > - // DeclContext should occur) querying closure types regarding capture > - // information. > + // The issue is that we cannot rely entirely on the FunctionScopeInfo > stack > + // since ScopeInfos are pushed on during parsing and treetransforming. > But > + // since a generic lambda's call operator can be instantiated anywhere > (even > + // end of the TU) we need to be able to examine its enclosing lambdas > and so > + // we use the DeclContext to get a hold of the closure-class and query > it for > + // capture information. The reason we don't just resort to always > using the > + // DeclContext chain is that it is only mature for lambda expressions > + // enclosing generic lambda's call operators that are being > instantiated. > > - > - // 1) Climb down the function scope info stack. > for (int I = FunctionScopes.size(); > - I-- && isa<LambdaScopeInfo>(FunctionScopes[I]) && > - (!CurLSI || CurLSI->Lambda->getDeclContext() == > - cast<LambdaScopeInfo>(FunctionScopes[I])-> > CallOperator); > + I-- && isa<LambdaScopeInfo>(FunctionScopes[I]); > CurDC = getLambdaAwareParentOfDeclContext(CurDC)) { > CurLSI = cast<LambdaScopeInfo>(FunctionScopes[I]); > > @@ -945,17 +927,11 @@ static QualType adjustCVQualifiersForCXX > return ASTCtx.getPointerType(ClassType); > } > } > - > - // 2) We've run out of ScopeInfos but check if CurDC is a lambda (which > can > - // happen during instantiation of its nested generic lambda call > operator) > + // We've run out of ScopeInfos but check if CurDC is a lambda (which can > + // happen during instantiation of generic lambdas) > if (isLambdaCallOperator(CurDC)) { > - assert(CurLSI && "While computing 'this' capture-type for a generic " > - "lambda, we must have a corresponding > LambdaScopeInfo"); > - assert(isGenericLambdaCallOperatorSpecialization(CurLSI->CallOperator) > && > - "While computing 'this' capture-type for a generic lambda, > when we " > - "run out of enclosing LSI's, yet the enclosing DC is a " > - "lambda-call-operator we must be (i.e. Current LSI) in a > generic " > - "lambda call oeprator"); > + assert(CurLSI); > + assert(isGenericLambdaCallOperatorSpecialization(CurLSI-> > CallOperator)); > assert(CurDC == getLambdaAwareParentOfDeclCont > ext(CurLSI->CallOperator)); > > auto IsThisCaptured = > > Modified: cfe/trunk/test/SemaCXX/cxx1z-lambda-star-this.cpp > URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/ > SemaCXX/cxx1z-lambda-star-this.cpp?rev=301916&r1=301915& > r2=301916&view=diff > ============================================================ > ================== > --- cfe/trunk/test/SemaCXX/cxx1z-lambda-star-this.cpp (original) > +++ cfe/trunk/test/SemaCXX/cxx1z-lambda-star-this.cpp Tue May 2 07:38:27 > 2017 > @@ -1,293 +1,231 @@ > -// 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 > - > -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; }; > - } > -}; > -} // namespace 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}} > - } > -}; > -} // namespace 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}} > -} // namespace 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 > -} // namespace ns4 > - > -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 *>); > - }; > - }; > - }; > - } > -}; > - > -} // namespace 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); > -} > -} // namespace 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(); > -} > -} // namespace ns7 > - > -} // namespace test_star_this > - > -namespace PR32831 { > -// https://bugs.llvm.org/show_bug.cgi?id=32831 > -namespace ns1 { > -template <typename Func> > -void fun_template(Func func) { > - (void)[&]() { > - func(0); > - }; > -} > - > -class A { > - void member_foo() { > - (void)[this] { > - (void)[this] { > - fun_template( > - [this](auto X) { > - auto L = [this](auto Y) { member_foo(); }; > - L(5); > - }); > - fun_template( > - [this](auto) { member_foo(); }); > - }; > - }; > - } > -}; > -} // namespace ns1 > - > -namespace ns2 { > - > -struct B { > - int data = 0; > - template <class F> > - void mem2(F f) { > - (void)[&](auto f) { > - (void)[&] { f(this->data); }; > - } > - (f); > - } > -}; > - > -class A { > - void member_foo() { > - (void)[this] { > - (void)[this] { > - B{}.mem2( > - [this](auto X) { > - auto L = [this](auto Y) { member_foo(); }; > - L(5); > - }); > - B{}.mem2( > - [this](auto) { member_foo(); }); > - }; > - }; > - } > -}; > - > -} // namespace ns2 > - > -} // namespace PR32831 > - > +// 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 > + > +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 > +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 > + > > > _______________________________________________ > cfe-commits mailing list > cfe-commits@lists.llvm.org > http://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits >
_______________________________________________ cfe-commits mailing list cfe-commits@lists.llvm.org http://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits