Index: clang/lib/Sema/SemaExpr.cpp =================================================================== --- clang/lib/Sema/SemaExpr.cpp +++ clang/lib/Sema/SemaExpr.cpp @@ -5619,6 +5619,14 @@ *this, dyn_cast<UnresolvedMemberExpr>(Fn->IgnoreParens()), Fn->getBeginLoc()); + // Mark this capture as ODR-used if we are in a lambda + // expression and the callee is UnresolvedMemberExpr. + LambdaScopeInfo *CurLSI = getCurLambda(); + if (CurLSI && isa<UnresolvedMemberExpr>(Fn->IgnoreParens())) + for (auto &Capture : CurLSI->Captures) + if (Capture.isThisCapture()) + Capture.markUsed(/*IsODRUse=*/true); + return CallExpr::Create(Context, Fn, ArgExprs, Context.DependentTy, VK_RValue, RParenLoc); } Index: clang/test/SemaCXX/warn-unused-lambda-capture-this.cpp =================================================================== --- /dev/null +++ clang/test/SemaCXX/warn-unused-lambda-capture-this.cpp @@ -0,0 +1,80 @@ +// RUN: %clang_cc1 -fsyntax-only -Wunused-lambda-capture -verify %s + +template <typename A> +class TemplatedStatic { +public: + TemplatedStatic() { + [this](auto value) { Construct(value); }(5); // expected-warning {{lambda capture 'this' is not used}} + } + + template <typename Arg> + static void Construct(Arg value) {} +}; + +template <typename A> +class TemplatedMember { +public: + TemplatedMember() { + [this](auto value) { Construct(value); }(5); + } + + template <typename Arg> + void Construct(Arg value) {} +}; + +template <typename A> +class OverloadedStatic { +public: + OverloadedStatic() { + [this](auto value) { Construct(value); }(5); // expected-warning {{lambda capture 'this' is not used}} + } + + static void Construct(int value) {} + static void Construct(float value) {} +}; + +template <typename A> +class OverloadedMember { +public: + OverloadedMember() { + [this](auto value) { Construct(value); }(5); + } + + void Construct(int value) {} + void Construct(float value) {} +}; + +template <typename A> +class OverloadedMixTrueNegative { +public: + OverloadedMixTrueNegative() { + [this](auto value) { Construct(value); }(5); + } + + void Construct(int value) {} + static void Construct(float value) {} +}; + +template <typename A> +class OverloadedMixFalseNegative { +public: + OverloadedMixFalseNegative() { + // Currently we mark this capture as used whenever UnresolvedMemberExpr + // happens, even if "Construct" will be resolved to the static one. + // Ideally we should issue 'this' not used warning. + [this](auto value) { Construct(value); }(5); + } + + static void Construct(int value) {} + void Construct(float value) {} +}; + +int main() { + TemplatedStatic<int> t1; // expected-note {{in instantiation of member function 'TemplatedStatic<int>::TemplatedStatic' requested here}} + TemplatedMember<int> t2; + OverloadedStatic<int> t3; // expected-note {{in instantiation of member function 'OverloadedStatic<int>::OverloadedStatic' requested here}} + OverloadedMember<int> t4; + OverloadedMixTrueNegative<int> t5; + OverloadedMixFalseNegative<int> t6; + return 0; +}