https://bugs.llvm.org/show_bug.cgi?id=31977 makes the good point that this is warning on a certain idiomatic use of capture-by-value to extend the lifetime of an RAII object; consider:
shared_ptr<Foo> p = /*...*/; int *q = &p->n; return [=, p] { return *q++; } Here, we'll warn that the capture of p is unused, but it's not -- the "use" is to hold a reference to keep the Foo object alive. I'd suggest suppressing the warning for a by-copy capture of a variable with a non-trivial destructor (this mirrors what we do for -Wunused-variable). On 13 January 2017 at 07:01, Malcolm Parsons via cfe-commits < cfe-commits@lists.llvm.org> wrote: > Author: malcolm.parsons > Date: Fri Jan 13 09:01:06 2017 > New Revision: 291905 > > URL: http://llvm.org/viewvc/llvm-project?rev=291905&view=rev > Log: > [Sema] Add warning for unused lambda captures > > Summary: > Warn when a lambda explicitly captures something that is not used in its > body. > > The warning is part of -Wunused and can be enabled with > -Wunused-lambda-capture. > > Reviewers: rsmith, arphaman, jbcoe, aaron.ballman > > Subscribers: Quuxplusone, arphaman, cfe-commits > > Differential Revision: https://reviews.llvm.org/D28467 > > Added: > cfe/trunk/test/SemaCXX/warn-unused-lambda-capture.cpp > Modified: > cfe/trunk/include/clang/Basic/DiagnosticGroups.td > cfe/trunk/include/clang/Basic/DiagnosticSemaKinds.td > cfe/trunk/include/clang/Sema/ScopeInfo.h > cfe/trunk/include/clang/Sema/Sema.h > cfe/trunk/lib/Sema/SemaExpr.cpp > cfe/trunk/lib/Sema/SemaExprCXX.cpp > cfe/trunk/lib/Sema/SemaLambda.cpp > cfe/trunk/test/CXX/expr/expr.prim/expr.prim.lambda/p12.cpp > cfe/trunk/test/CXX/expr/expr.prim/expr.prim.lambda/p13.cpp > cfe/trunk/test/CXX/expr/expr.prim/expr.prim.lambda/p16.cpp > cfe/trunk/test/CXX/expr/expr.prim/expr.prim.lambda/p18.cpp > cfe/trunk/test/CXX/expr/expr.prim/expr.prim.lambda/p19.cpp > cfe/trunk/test/SemaCXX/uninitialized.cpp > > Modified: cfe/trunk/include/clang/Basic/DiagnosticGroups.td > URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/include/ > clang/Basic/DiagnosticGroups.td?rev=291905&r1=291904&r2=291905&view=diff > ============================================================ > ================== > --- cfe/trunk/include/clang/Basic/DiagnosticGroups.td (original) > +++ cfe/trunk/include/clang/Basic/DiagnosticGroups.td Fri Jan 13 09:01:06 > 2017 > @@ -480,6 +480,7 @@ def UnusedFunction : DiagGroup<"unused-f > def UnusedMemberFunction : DiagGroup<"unused-member-function", > [UnneededMemberFunction]>; > def UnusedLabel : DiagGroup<"unused-label">; > +def UnusedLambdaCapture : DiagGroup<"unused-lambda-capture">; > def UnusedParameter : DiagGroup<"unused-parameter">; > def UnusedResult : DiagGroup<"unused-result">; > def PotentiallyEvaluatedExpression : DiagGroup<"potentially- > evaluated-expression">; > @@ -617,8 +618,9 @@ def Unused : DiagGroup<"unused", > [UnusedArgument, UnusedFunction, UnusedLabel, > // UnusedParameter, (matches GCC's behavior) > // UnusedMemberFunction, (clean-up llvm before > enabling) > - UnusedPrivateField, UnusedLocalTypedef, > - UnusedValue, UnusedVariable, UnusedPropertyIvar]>, > + UnusedPrivateField, UnusedLambdaCapture, > + UnusedLocalTypedef, UnusedValue, UnusedVariable, > + UnusedPropertyIvar]>, > DiagCategory<"Unused Entity Issue">; > > // Format settings. > > Modified: cfe/trunk/include/clang/Basic/DiagnosticSemaKinds.td > URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/include/clang/Basic/ > DiagnosticSemaKinds.td?rev=291905&r1=291904&r2=291905&view=diff > ============================================================ > ================== > --- cfe/trunk/include/clang/Basic/DiagnosticSemaKinds.td (original) > +++ cfe/trunk/include/clang/Basic/DiagnosticSemaKinds.td Fri Jan 13 > 09:01:06 2017 > @@ -316,6 +316,9 @@ def warn_unneeded_member_function : Warn > InGroup<UnneededMemberFunction>, DefaultIgnore; > def warn_unused_private_field: Warning<"private field %0 is not used">, > InGroup<UnusedPrivateField>, DefaultIgnore; > +def warn_unused_lambda_capture: Warning<"lambda capture %0 is not " > + "%select{used|required to be captured for use in an unevaluated > context}1">, > + InGroup<UnusedLambdaCapture>, DefaultIgnore; > > def warn_parameter_size: Warning< > "%0 is a large (%1 bytes) pass-by-value argument; " > > Modified: cfe/trunk/include/clang/Sema/ScopeInfo.h > URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/include/ > clang/Sema/ScopeInfo.h?rev=291905&r1=291904&r2=291905&view=diff > ============================================================ > ================== > --- cfe/trunk/include/clang/Sema/ScopeInfo.h (original) > +++ cfe/trunk/include/clang/Sema/ScopeInfo.h Fri Jan 13 09:01:06 2017 > @@ -452,6 +452,14 @@ public: > /// non-static data member that would hold the capture. > QualType CaptureType; > > + /// \brief Whether an explicit capture has been odr-used in the body > of the > + /// lambda. > + bool ODRUsed; > + > + /// \brief Whether an explicit capture has been non-odr-used in the > body of > + /// the lambda. > + bool NonODRUsed; > + > public: > Capture(VarDecl *Var, bool Block, bool ByRef, bool IsNested, > SourceLocation Loc, SourceLocation EllipsisLoc, > @@ -460,7 +468,8 @@ public: > InitExprAndCaptureKind( > Cpy, !Var ? Cap_VLA : Block ? Cap_Block : ByRef ? Cap_ByRef > : > Cap_ByCopy), > - Loc(Loc), EllipsisLoc(EllipsisLoc), CaptureType(CaptureType) {} > + Loc(Loc), EllipsisLoc(EllipsisLoc), CaptureType(CaptureType), > + ODRUsed(false), NonODRUsed(false) {} > > enum IsThisCapture { ThisCapture }; > Capture(IsThisCapture, bool IsNested, SourceLocation Loc, > @@ -468,7 +477,8 @@ public: > : VarAndNestedAndThis( > nullptr, (IsThisCaptured | (IsNested ? IsNestedCapture : > 0))), > InitExprAndCaptureKind(Cpy, ByCopy ? Cap_ByCopy : Cap_ByRef), > - Loc(Loc), EllipsisLoc(), CaptureType(CaptureType) {} > + Loc(Loc), EllipsisLoc(), CaptureType(CaptureType), > ODRUsed(false), > + NonODRUsed(false) {} > > bool isThisCapture() const { > return VarAndNestedAndThis.getInt() & IsThisCaptured; > @@ -491,6 +501,9 @@ public: > bool isNested() const { > return VarAndNestedAndThis.getInt() & IsNestedCapture; > } > + bool isODRUsed() const { return ODRUsed; } > + bool isNonODRUsed() const { return NonODRUsed; } > + void markUsed(bool IsODRUse) { (IsODRUse ? ODRUsed : NonODRUsed) = > true; } > > VarDecl *getVariable() const { > return VarAndNestedAndThis.getPointer(); > > Modified: cfe/trunk/include/clang/Sema/Sema.h > URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/include/ > clang/Sema/Sema.h?rev=291905&r1=291904&r2=291905&view=diff > ============================================================ > ================== > --- cfe/trunk/include/clang/Sema/Sema.h (original) > +++ cfe/trunk/include/clang/Sema/Sema.h Fri Jan 13 09:01:06 2017 > @@ -5323,6 +5323,9 @@ public: > ExprResult ActOnLambdaExpr(SourceLocation StartLoc, Stmt *Body, > Scope *CurScope); > > + /// \brief Diagnose if an explicit lambda capture is unused. > + void DiagnoseUnusedLambdaCapture(const sema::LambdaScopeInfo::Capture > &From); > + > /// \brief Complete a lambda-expression having processed and attached > the > /// lambda body. > ExprResult BuildLambdaExpr(SourceLocation StartLoc, SourceLocation > EndLoc, > > Modified: cfe/trunk/lib/Sema/SemaExpr.cpp > URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Sema/ > SemaExpr.cpp?rev=291905&r1=291904&r2=291905&view=diff > ============================================================ > ================== > --- cfe/trunk/lib/Sema/SemaExpr.cpp (original) > +++ cfe/trunk/lib/Sema/SemaExpr.cpp Fri Jan 13 09:01:06 2017 > @@ -13916,8 +13916,10 @@ bool Sema::tryCaptureVariable( > > // Check whether we've already captured it. > if (isVariableAlreadyCapturedInScopeInfo(CSI, Var, Nested, > CaptureType, > - DeclRefType)) > + DeclRefType)) { > + CSI->getCapture(Var).markUsed(BuildAndDiagnose); > break; > + } > // If we are instantiating a generic lambda call operator body, > // we do not want to capture new variables. What was captured > // during either a lambdas transformation or initial parsing > > Modified: cfe/trunk/lib/Sema/SemaExprCXX.cpp > URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Sema/ > SemaExprCXX.cpp?rev=291905&r1=291904&r2=291905&view=diff > ============================================================ > ================== > --- cfe/trunk/lib/Sema/SemaExprCXX.cpp (original) > +++ cfe/trunk/lib/Sema/SemaExprCXX.cpp Fri Jan 13 09:01:06 2017 > @@ -1106,6 +1106,7 @@ bool Sema::CheckCXXThisCapture(SourceLoc > dyn_cast<CapturingScopeInfo>(FunctionScopes[idx])) { > if (CSI->CXXThisCaptureIndex != 0) { > // 'this' is already being captured; there isn't anything more to > do. > + CSI->Captures[CSI->CXXThisCaptureIndex - > 1].markUsed(BuildAndDiagnose); > break; > } > LambdaScopeInfo *LSI = dyn_cast<LambdaScopeInfo>(CSI); > > Modified: cfe/trunk/lib/Sema/SemaLambda.cpp > URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Sema/ > SemaLambda.cpp?rev=291905&r1=291904&r2=291905&view=diff > ============================================================ > ================== > --- cfe/trunk/lib/Sema/SemaLambda.cpp (original) > +++ cfe/trunk/lib/Sema/SemaLambda.cpp Fri Jan 13 09:01:06 2017 > @@ -1384,7 +1384,7 @@ static void addBlockPointerConversion(Se > } > > static ExprResult performLambdaVarCaptureInitialization( > - Sema &S, LambdaScopeInfo::Capture &Capture, FieldDecl *Field) { > + Sema &S, const LambdaScopeInfo::Capture &Capture, FieldDecl *Field) { > assert(Capture.isVariableCapture() && "not a variable capture"); > > auto *Var = Capture.getVariable(); > @@ -1438,6 +1438,21 @@ mapImplicitCaptureStyle(CapturingScopeIn > llvm_unreachable("Unknown implicit capture style"); > } > > +void Sema::DiagnoseUnusedLambdaCapture(const LambdaScopeInfo::Capture > &From) { > + if (!From.isVLATypeCapture()) { > + Expr *Init = From.getInitExpr(); > + if (Init && Init->HasSideEffects(Context)) > + return; > + } > + > + auto diag = Diag(From.getLocation(), diag::warn_unused_lambda_capture); > + if (From.isThisCapture()) > + diag << "'this'"; > + else > + diag << From.getVariable(); > + diag << From.isNonODRUsed(); > +} > + > ExprResult Sema::BuildLambdaExpr(SourceLocation StartLoc, SourceLocation > EndLoc, > LambdaScopeInfo *LSI) { > // Collect information from the lambda scope. > @@ -1476,10 +1491,14 @@ ExprResult Sema::BuildLambdaExpr(SourceL > // Translate captures. > auto CurField = Class->field_begin(); > for (unsigned I = 0, N = LSI->Captures.size(); I != N; ++I, > ++CurField) { > - LambdaScopeInfo::Capture From = LSI->Captures[I]; > + const LambdaScopeInfo::Capture &From = LSI->Captures[I]; > assert(!From.isBlockCapture() && "Cannot capture __block > variables"); > bool IsImplicit = I >= LSI->NumExplicitCaptures; > > + // Warn about unused explicit captures. > + if (!CurContext->isDependentContext() && !IsImplicit && > !From.isODRUsed()) > + DiagnoseUnusedLambdaCapture(From); > + > // Handle 'this' capture. > if (From.isThisCapture()) { > Captures.push_back( > > Modified: cfe/trunk/test/CXX/expr/expr.prim/expr.prim.lambda/p12.cpp > URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/CXX/ > expr/expr.prim/expr.prim.lambda/p12.cpp?rev=291905&r1= > 291904&r2=291905&view=diff > ============================================================ > ================== > --- cfe/trunk/test/CXX/expr/expr.prim/expr.prim.lambda/p12.cpp (original) > +++ cfe/trunk/test/CXX/expr/expr.prim/expr.prim.lambda/p12.cpp Fri Jan 13 > 09:01:06 2017 > @@ -1,4 +1,4 @@ > -// RUN: %clang_cc1 -std=c++11 %s -Wunused -verify > +// RUN: %clang_cc1 -std=c++11 %s -Wunused -Wno-unused-lambda-capture > -verify > > void odr_used() { > int i = 17; > > Modified: cfe/trunk/test/CXX/expr/expr.prim/expr.prim.lambda/p13.cpp > URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/CXX/ > expr/expr.prim/expr.prim.lambda/p13.cpp?rev=291905&r1= > 291904&r2=291905&view=diff > ============================================================ > ================== > --- cfe/trunk/test/CXX/expr/expr.prim/expr.prim.lambda/p13.cpp (original) > +++ cfe/trunk/test/CXX/expr/expr.prim/expr.prim.lambda/p13.cpp Fri Jan 13 > 09:01:06 2017 > @@ -1,4 +1,4 @@ > -// RUN: %clang_cc1 -std=c++11 %s -Wunused -verify > +// RUN: %clang_cc1 -std=c++11 %s -Wunused -Wno-unused-lambda-capture > -verify > > void f2() { > int i = 1; > > Modified: cfe/trunk/test/CXX/expr/expr.prim/expr.prim.lambda/p16.cpp > URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/CXX/ > expr/expr.prim/expr.prim.lambda/p16.cpp?rev=291905&r1= > 291904&r2=291905&view=diff > ============================================================ > ================== > --- cfe/trunk/test/CXX/expr/expr.prim/expr.prim.lambda/p16.cpp (original) > +++ cfe/trunk/test/CXX/expr/expr.prim/expr.prim.lambda/p16.cpp Fri Jan 13 > 09:01:06 2017 > @@ -1,4 +1,4 @@ > -// RUN: %clang_cc1 -std=c++11 %s -Wunused -verify > +// RUN: %clang_cc1 -std=c++11 %s -Wunused -Wno-unused-lambda-capture > -verify > > > struct X { > > Modified: cfe/trunk/test/CXX/expr/expr.prim/expr.prim.lambda/p18.cpp > URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/CXX/ > expr/expr.prim/expr.prim.lambda/p18.cpp?rev=291905&r1= > 291904&r2=291905&view=diff > ============================================================ > ================== > --- cfe/trunk/test/CXX/expr/expr.prim/expr.prim.lambda/p18.cpp (original) > +++ cfe/trunk/test/CXX/expr/expr.prim/expr.prim.lambda/p18.cpp Fri Jan 13 > 09:01:06 2017 > @@ -1,4 +1,4 @@ > -// RUN: %clang_cc1 -std=c++11 %s -Wunused -verify > +// RUN: %clang_cc1 -std=c++11 %s -Wunused -Wno-unused-lambda-capture > -verify > // expected-no-diagnostics > > template<typename T, typename U> > > Modified: cfe/trunk/test/CXX/expr/expr.prim/expr.prim.lambda/p19.cpp > URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/CXX/ > expr/expr.prim/expr.prim.lambda/p19.cpp?rev=291905&r1= > 291904&r2=291905&view=diff > ============================================================ > ================== > --- cfe/trunk/test/CXX/expr/expr.prim/expr.prim.lambda/p19.cpp (original) > +++ cfe/trunk/test/CXX/expr/expr.prim/expr.prim.lambda/p19.cpp Fri Jan 13 > 09:01:06 2017 > @@ -1,4 +1,4 @@ > -// RUN: %clang_cc1 -std=c++11 %s -Wunused -verify > +// RUN: %clang_cc1 -std=c++11 %s -Wunused -Wno-unused-lambda-capture > -verify > > struct MoveOnly { > MoveOnly(MoveOnly&&); > > Modified: cfe/trunk/test/SemaCXX/uninitialized.cpp > URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/ > SemaCXX/uninitialized.cpp?rev=291905&r1=291904&r2=291905&view=diff > ============================================================ > ================== > --- cfe/trunk/test/SemaCXX/uninitialized.cpp (original) > +++ cfe/trunk/test/SemaCXX/uninitialized.cpp Fri Jan 13 09:01:06 2017 > @@ -1,4 +1,4 @@ > -// RUN: %clang_cc1 -fsyntax-only -Wall -Wuninitialized -Wno-unused-value > -std=c++11 -verify %s > +// RUN: %clang_cc1 -fsyntax-only -Wall -Wuninitialized -Wno-unused-value > -Wno-unused-lambda-capture -std=c++11 -verify %s > > // definitions for std::move > namespace std { > > Added: cfe/trunk/test/SemaCXX/warn-unused-lambda-capture.cpp > URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/ > SemaCXX/warn-unused-lambda-capture.cpp?rev=291905&view=auto > ============================================================ > ================== > --- cfe/trunk/test/SemaCXX/warn-unused-lambda-capture.cpp (added) > +++ cfe/trunk/test/SemaCXX/warn-unused-lambda-capture.cpp Fri Jan 13 > 09:01:06 2017 > @@ -0,0 +1,110 @@ > +// RUN: %clang_cc1 -fsyntax-only -Wunused-lambda-capture > -Wused-but-marked-unused -Wno-uninitialized -verify -std=c++14 %s > + > +class NonTrivialConstructor { > +public: > + NonTrivialConstructor() {} > +}; > + > +class NonTrivialDestructor { > +public: > + ~NonTrivialDestructor() {} > +}; > + > +class Trivial { > +public: > + Trivial() = default; > + Trivial(int a) {} > +}; > + > +int side_effect() { > + return 42; > +} > + > +void test() { > + int i = 0; > + > + auto captures_nothing = [] {}; > + > + auto captures_nothing_by_value = [=] {}; > + auto captures_nothing_by_reference = [&] {}; > + > + auto implicit_by_value = [=]() mutable { i++; }; > + auto implicit_by_reference = [&] { i++; }; > + > + auto explicit_by_value_used = [i] { return i + 1; }; > + auto explicit_by_value_used_void = [i] { (void)i; }; > + auto explicit_by_value_unused = [i] {}; // expected-warning{{lambda > capture 'i' is not used}} > + auto explicit_by_value_unused_sizeof = [i] { return sizeof(i); }; // > expected-warning{{lambda capture 'i' is not required to be captured for use > in an unevaluated context}} > + auto explicit_by_value_unused_decltype = [i] { decltype(i) j = 0; }; > // expected-warning{{lambda capture 'i' is not required to be captured for > use in an unevaluated context}} > + > + auto explicit_by_reference_used = [&i] { i++; }; > + auto explicit_by_reference_unused = [&i] {}; // > expected-warning{{lambda capture 'i' is not used}} > + > + auto explicit_initialized_reference_used = [&j = i] { return j + 1; }; > + auto explicit_initialized_reference_unused = [&j = i]{}; // > expected-warning{{lambda capture 'j' is not used}} > + > + auto explicit_initialized_value_used = [j = 1] { return j + 1; }; > + auto explicit_initialized_value_unused = [j = 1] {}; // > expected-warning{{lambda capture 'j' is not used}} > + auto explicit_initialized_value_non_trivial_constructor = [j = > NonTrivialConstructor()]{}; > + auto explicit_initialized_value_non_trivial_destructor = [j = > NonTrivialDestructor()]{}; > + auto explicit_initialized_value_trivial_init = [j = Trivial()]{}; // > expected-warning{{lambda capture 'j' is not used}} > + auto explicit_initialized_value_non_trivial_init = [j = Trivial(42)]{}; > + auto explicit_initialized_value_with_side_effect = [j = > side_effect()]{}; > + > + auto nested = [&i] { > + auto explicit_by_value_used = [i] { return i + 1; }; > + auto explicit_by_value_unused = [i] {}; // expected-warning{{lambda > capture 'i' is not used}} > + }; > +} > + > +class Foo > +{ > + void test() { > + auto explicit_this_used = [this] { return i; }; > + auto explicit_this_used_void = [this] { (void)this; }; > + auto explicit_this_unused = [this] {}; // expected-warning{{lambda > capture 'this' is not used}} > + } > + int i; > +}; > + > +template <typename T> > +void test_templated() { > + int i = 0; > + > + auto captures_nothing = [] {}; > + > + auto captures_nothing_by_value = [=] {}; > + auto captures_nothing_by_reference = [&] {}; > + > + auto implicit_by_value = [=]() mutable { i++; }; > + auto implicit_by_reference = [&] { i++; }; > + > + auto explicit_by_value_used = [i] { return i + 1; }; > + auto explicit_by_value_used_void = [i] { (void)i; }; > + auto explicit_by_value_unused = [i] {}; // expected-warning{{lambda > capture 'i' is not used}} > + auto explicit_by_value_unused_sizeof = [i] { return sizeof(i); }; // > expected-warning{{lambda capture 'i' is not required to be captured for use > in an unevaluated context}} > + auto explicit_by_value_unused_decltype = [i] { decltype(i) j = 0; }; > // expected-warning{{lambda capture 'i' is not used}} > + > + auto explicit_by_reference_used = [&i] { i++; }; > + auto explicit_by_reference_unused = [&i] {}; // > expected-warning{{lambda capture 'i' is not used}} > + > + auto explicit_initialized_reference_used = [&j = i] { return j + 1; }; > + auto explicit_initialized_reference_unused = [&j = i]{}; // > expected-warning{{lambda capture 'j' is not used}} > + > + auto explicit_initialized_value_used = [j = 1] { return j + 1; }; > + auto explicit_initialized_value_unused = [j = 1] {}; // > expected-warning{{lambda capture 'j' is not used}} > + auto explicit_initialized_value_non_trivial_constructor = [j = > NonTrivialConstructor()]{}; > + auto explicit_initialized_value_non_trivial_destructor = [j = > NonTrivialDestructor()]{}; > + auto explicit_initialized_value_trivial_init = [j = Trivial()]{}; // > expected-warning{{lambda capture 'j' is not used}} > + auto explicit_initialized_value_non_trivial_init = [j = Trivial(42)]{}; > + auto explicit_initialized_value_with_side_effect = [j = > side_effect()]{}; > + > + auto nested = [&i] { > + auto explicit_by_value_used = [i] { return i + 1; }; > + auto explicit_by_value_unused = [i] {}; // expected-warning{{lambda > capture 'i' is not used}} > + }; > +} > + > +void test_use_template() { > + test_templated<int>(); // expected-note{{in instantiation of function > template specialization 'test_templated<int>' requested here}} > +} > > > _______________________________________________ > 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