[cfe-commits] r125778 - in /cfe/trunk: include/clang/Driver/CC1Options.td include/clang/Frontend/Analyses.def include/clang/StaticAnalyzer/Checkers/LocalCheckers.h include/clang/StaticAnalyzer/Core/CheckerManager.h include/clang/StaticAnalyzer/Core/CheckerV2.h lib/StaticAnalyzer/Checkers/Checkers.td lib/StaticAnalyzer/Checkers/LLVMConventionsChecker.cpp lib/StaticAnalyzer/Core/CheckerManager.cpp lib/StaticAnalyzer/Frontend/AnalysisConsumer.cpp
Argyrios Kyrtzidis
akyrtzi at gmail.com
Thu Feb 17 13:39:24 PST 2011
Author: akirtzidis
Date: Thu Feb 17 15:39:24 2011
New Revision: 125778
URL: http://llvm.org/viewvc/llvm-project?rev=125778&view=rev
Log:
[analyzer]
-Introduce CheckerV2, a set of templates for convenient declaration & registration of checkers.
Currently useful just for checkers working on the AST not the path-sensitive ones.
-Enhance CheckerManager to actually collect the checkers and turn it into the entry point for
running the checkers.
-Use the new mechanism for the LLVMConventionsChecker.
Added:
cfe/trunk/include/clang/StaticAnalyzer/Core/CheckerV2.h
Modified:
cfe/trunk/include/clang/Driver/CC1Options.td
cfe/trunk/include/clang/Frontend/Analyses.def
cfe/trunk/include/clang/StaticAnalyzer/Checkers/LocalCheckers.h
cfe/trunk/include/clang/StaticAnalyzer/Core/CheckerManager.h
cfe/trunk/lib/StaticAnalyzer/Checkers/Checkers.td
cfe/trunk/lib/StaticAnalyzer/Checkers/LLVMConventionsChecker.cpp
cfe/trunk/lib/StaticAnalyzer/Core/CheckerManager.cpp
cfe/trunk/lib/StaticAnalyzer/Frontend/AnalysisConsumer.cpp
Modified: cfe/trunk/include/clang/Driver/CC1Options.td
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/include/clang/Driver/CC1Options.td?rev=125778&r1=125777&r2=125778&view=diff
==============================================================================
--- cfe/trunk/include/clang/Driver/CC1Options.td (original)
+++ cfe/trunk/include/clang/Driver/CC1Options.td Thu Feb 17 15:39:24 2011
@@ -48,8 +48,6 @@
HelpText<"Add C++ initializers to CFGs for all analyses">;
def analysis_DisplayLiveVariables : Flag<"-dump-live-variables">,
HelpText<"Print results of live variable analysis">;
-def analysis_LLVMConventionChecker : Flag<"-analyzer-check-llvm-conventions">,
- HelpText<"Check code for LLVM codebase conventions (domain-specific)">;
def analysis_SecuritySyntacticChecks : Flag<"-analyzer-check-security-syntactic">,
HelpText<"Perform quick security checks that require no data flow">;
def analysis_WarnDeadStores : Flag<"-analyzer-check-dead-stores">,
Modified: cfe/trunk/include/clang/Frontend/Analyses.def
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/include/clang/Frontend/Analyses.def?rev=125778&r1=125777&r2=125778&view=diff
==============================================================================
--- cfe/trunk/include/clang/Frontend/Analyses.def (original)
+++ cfe/trunk/include/clang/Frontend/Analyses.def Thu Feb 17 15:39:24 2011
@@ -27,10 +27,6 @@
ANALYSIS(SecuritySyntacticChecks, "analyzer-check-security-syntactic",
"Perform quick security checks that require no data flow", Code)
-ANALYSIS(LLVMConventionChecker, "analyzer-check-llvm-conventions",
- "Check code for LLVM codebase conventions (domain-specific)",
- TranslationUnit)
-
ANALYSIS(WarnDeadStores, "analyzer-check-dead-stores",
"Warn about stores to dead variables", Code)
Modified: cfe/trunk/include/clang/StaticAnalyzer/Checkers/LocalCheckers.h
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/include/clang/StaticAnalyzer/Checkers/LocalCheckers.h?rev=125778&r1=125777&r2=125778&view=diff
==============================================================================
--- cfe/trunk/include/clang/StaticAnalyzer/Checkers/LocalCheckers.h (original)
+++ cfe/trunk/include/clang/StaticAnalyzer/Checkers/LocalCheckers.h Thu Feb 17 15:39:24 2011
@@ -53,7 +53,6 @@
void RegisterExperimentalChecks(ExprEngine &Eng);
void RegisterExperimentalInternalChecks(ExprEngine &Eng);
-void CheckLLVMConventions(TranslationUnitDecl &TU, BugReporter &BR);
void CheckSecuritySyntaxOnly(const Decl *D, BugReporter &BR);
void CheckSizeofPointer(const Decl *D, BugReporter &BR);
Modified: cfe/trunk/include/clang/StaticAnalyzer/Core/CheckerManager.h
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/include/clang/StaticAnalyzer/Core/CheckerManager.h?rev=125778&r1=125777&r2=125778&view=diff
==============================================================================
--- cfe/trunk/include/clang/StaticAnalyzer/Core/CheckerManager.h (original)
+++ cfe/trunk/include/clang/StaticAnalyzer/Core/CheckerManager.h Thu Feb 17 15:39:24 2011
@@ -15,24 +15,91 @@
#define LLVM_CLANG_SA_CORE_CHECKERMANAGER_H
#include "llvm/ADT/SmallVector.h"
+#include "llvm/ADT/DenseMap.h"
+#include <vector>
namespace clang {
+ class Decl;
namespace ento {
class ExprEngine;
+ class AnalysisManager;
+ class BugReporter;
class CheckerManager {
public:
- typedef void (*RegisterToEngFunc)(ExprEngine &Eng);
+ ~CheckerManager();
+
+ typedef void *CheckerRef;
+//===----------------------------------------------------------------------===//
+// registerChecker
+//===----------------------------------------------------------------------===//
+
+ /// \brief Used to register checkers.
+ template <typename CHECKER>
+ void registerChecker() {
+ CHECKER *checker = new CHECKER();
+ Checkers.push_back(std::make_pair(checker, destruct<CHECKER>));
+ CHECKER::_register(checker, *this);
+ }
+
+ typedef void (*RegisterToEngFunc)(ExprEngine &Eng);
void addCheckerRegisterFunction(RegisterToEngFunc fn) {
Funcs.push_back(fn);
}
+
+//===----------------------------------------------------------------------===//
+// Functions for running checkers.
+//===----------------------------------------------------------------------===//
+
+ /// \brief Run checkers handling Decls.
+ void runCheckersOnASTDecl(const Decl *D, AnalysisManager& mgr,
+ BugReporter &BR);
+
+ /// \brief Run checkers handling Decls containing a Stmt body.
+ void runCheckersOnASTBody(const Decl *D, AnalysisManager& mgr,
+ BugReporter &BR);
+
+//===----------------------------------------------------------------------===//
+// Internal registration functions.
+//===----------------------------------------------------------------------===//
+
+ // Functions used by the registration mechanism, checkers should not touch
+ // these directly.
+
+ typedef void (*CheckDeclFunc)(CheckerRef checker, const Decl *D,
+ AnalysisManager& mgr, BugReporter &BR);
+ typedef bool (*HandlesDeclFunc)(const Decl *D);
+ void _registerForDecl(CheckerRef checker, CheckDeclFunc checkfn,
+ HandlesDeclFunc isForDeclFn);
+
+ void _registerForBody(CheckerRef checker, CheckDeclFunc checkfn);
void registerCheckersToEngine(ExprEngine &eng);
private:
- llvm::SmallVector<RegisterToEngFunc, 8> Funcs;
+ template <typename CHECKER>
+ static void destruct(void *obj) { delete static_cast<CHECKER *>(obj); }
+
+ std::vector<RegisterToEngFunc> Funcs;
+
+ struct DeclCheckerInfo {
+ CheckerRef Checker;
+ CheckDeclFunc CheckFn;
+ HandlesDeclFunc IsForDeclFn;
+ };
+ std::vector<DeclCheckerInfo> DeclCheckers;
+
+ std::vector<std::pair<CheckerRef, CheckDeclFunc> > BodyCheckers;
+
+ typedef void (*Dtor)(void *);
+ std::vector<std::pair<CheckerRef, Dtor> > Checkers;
+
+ typedef llvm::SmallVector<std::pair<CheckerRef, CheckDeclFunc>, 4>
+ CachedDeclCheckers;
+ typedef llvm::DenseMap<unsigned, CachedDeclCheckers> CachedDeclCheckersMapTy;
+ CachedDeclCheckersMapTy CachedDeclCheckersMap;
};
} // end ento namespace
Added: cfe/trunk/include/clang/StaticAnalyzer/Core/CheckerV2.h
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/include/clang/StaticAnalyzer/Core/CheckerV2.h?rev=125778&view=auto
==============================================================================
--- cfe/trunk/include/clang/StaticAnalyzer/Core/CheckerV2.h (added)
+++ cfe/trunk/include/clang/StaticAnalyzer/Core/CheckerV2.h Thu Feb 17 15:39:24 2011
@@ -0,0 +1,93 @@
+//== CheckerV2.h - Registration mechanism for checkers -----------*- C++ -*--=//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+//
+// This file defines CheckerV2, used to create and register checkers.
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef LLVM_CLANG_SA_CORE_CHECKERV2
+#define LLVM_CLANG_SA_CORE_CHECKERV2
+
+#include "clang/StaticAnalyzer/Core/CheckerManager.h"
+#include "llvm/Support/Casting.h"
+
+namespace clang {
+namespace ento {
+ class BugReporter;
+
+namespace check {
+
+struct _VoidCheck {
+ static void _register(void *checker, CheckerManager &mgr) { }
+};
+
+template <typename DECL>
+class ASTDecl {
+ template <typename CHECKER>
+ static void _checkDecl(void *checker, const Decl *D, AnalysisManager& mgr,
+ BugReporter &BR) {
+ ((const CHECKER *)checker)->checkASTDecl(llvm::cast<DECL>(D), mgr, BR);
+ }
+
+ static bool _handlesDecl(const Decl *D) {
+ return llvm::isa<DECL>(D);
+ }
+public:
+ template <typename CHECKER>
+ static void _register(CHECKER *checker, CheckerManager &mgr) {
+ mgr._registerForDecl(checker, _checkDecl<CHECKER>, _handlesDecl);
+ }
+};
+
+class ASTCodeBody {
+ template <typename CHECKER>
+ static void _checkBody(void *checker, const Decl *D, AnalysisManager& mgr,
+ BugReporter &BR) {
+ ((const CHECKER *)checker)->checkASTCodeBody(D, mgr, BR);
+ }
+
+public:
+ template <typename CHECKER>
+ static void _register(CHECKER *checker, CheckerManager &mgr) {
+ mgr._registerForBody(checker, _checkBody<CHECKER>);
+ }
+};
+
+} // end check namespace
+
+template <typename CHECK1, typename CHECK2=check::_VoidCheck,
+ typename CHECK3=check::_VoidCheck, typename CHECK4=check::_VoidCheck,
+ typename CHECK5=check::_VoidCheck, typename CHECK6=check::_VoidCheck,
+ typename CHECK7=check::_VoidCheck, typename CHECK8=check::_VoidCheck,
+ typename CHECK9=check::_VoidCheck, typename CHECK10=check::_VoidCheck,
+ typename CHECK11=check::_VoidCheck,typename CHECK12=check::_VoidCheck>
+class CheckerV2 {
+public:
+ template <typename CHECKER>
+ static void _register(CHECKER *checker, CheckerManager &mgr) {
+ CHECK1::_register(checker, mgr);
+ CHECK2::_register(checker, mgr);
+ CHECK3::_register(checker, mgr);
+ CHECK4::_register(checker, mgr);
+ CHECK5::_register(checker, mgr);
+ CHECK6::_register(checker, mgr);
+ CHECK7::_register(checker, mgr);
+ CHECK8::_register(checker, mgr);
+ CHECK9::_register(checker, mgr);
+ CHECK10::_register(checker, mgr);
+ CHECK11::_register(checker, mgr);
+ CHECK12::_register(checker, mgr);
+ }
+};
+
+} // end ento namespace
+
+} // end clang namespace
+
+#endif
Modified: cfe/trunk/lib/StaticAnalyzer/Checkers/Checkers.td
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/StaticAnalyzer/Checkers/Checkers.td?rev=125778&r1=125777&r2=125778&view=diff
==============================================================================
--- cfe/trunk/lib/StaticAnalyzer/Checkers/Checkers.td (original)
+++ cfe/trunk/lib/StaticAnalyzer/Checkers/Checkers.td Thu Feb 17 15:39:24 2011
@@ -24,6 +24,8 @@
def UnixExperimental : Package<"experimental">,
InPackage<Unix>, Hidden;
+def LLVM : Package<"llvm">;
+
//===----------------------------------------------------------------------===//
// Groups.
//===----------------------------------------------------------------------===//
@@ -84,6 +86,11 @@
HelpText<"Check for null arguments to CFRetain/CFRelease">,
DescFile<"BasicObjCFoundationChecks.cpp">;
+def LLVMConventionsChecker : Checker<"Conventions">,
+ InPackage<LLVM>,
+ HelpText<"Check code for LLVM codebase conventions">,
+ DescFile<"LLVMConventionsChecker.cpp">;
+
//===----------------------------------------------------------------------===//
// Hidden experimental checkers.
//===----------------------------------------------------------------------===//
Modified: cfe/trunk/lib/StaticAnalyzer/Checkers/LLVMConventionsChecker.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/StaticAnalyzer/Checkers/LLVMConventionsChecker.cpp?rev=125778&r1=125777&r2=125778&view=diff
==============================================================================
--- cfe/trunk/lib/StaticAnalyzer/Checkers/LLVMConventionsChecker.cpp (original)
+++ cfe/trunk/lib/StaticAnalyzer/Checkers/LLVMConventionsChecker.cpp Thu Feb 17 15:39:24 2011
@@ -12,10 +12,12 @@
//
//===----------------------------------------------------------------------===//
-#include "clang/AST/DeclTemplate.h"
-#include "clang/AST/StmtVisitor.h"
+#include "ClangSACheckers.h"
+#include "clang/StaticAnalyzer/Core/CheckerV2.h"
#include "clang/StaticAnalyzer/Checkers/LocalCheckers.h"
#include "clang/StaticAnalyzer/Core/BugReporter/BugReporter.h"
+#include "clang/AST/DeclTemplate.h"
+#include "clang/AST/StmtVisitor.h"
#include <string>
#include "llvm/ADT/StringRef.h"
@@ -210,10 +212,10 @@
namespace {
class ASTFieldVisitor {
llvm::SmallVector<FieldDecl*, 10> FieldChain;
- CXXRecordDecl *Root;
+ const CXXRecordDecl *Root;
BugReporter &BR;
public:
- ASTFieldVisitor(CXXRecordDecl *root, BugReporter &br)
+ ASTFieldVisitor(const CXXRecordDecl *root, BugReporter &br)
: Root(root), BR(br) {}
void Visit(FieldDecl *D);
@@ -221,7 +223,7 @@
};
} // end anonymous namespace
-static void CheckASTMemory(CXXRecordDecl *R, BugReporter &BR) {
+static void CheckASTMemory(const CXXRecordDecl *R, BugReporter &BR) {
if (!IsPartOfAST(R))
return;
@@ -283,29 +285,27 @@
}
//===----------------------------------------------------------------------===//
-// Entry point for all checks.
+// LLVMConventionsChecker
//===----------------------------------------------------------------------===//
-static void ScanCodeDecls(DeclContext *DC, BugReporter &BR) {
- for (DeclContext::decl_iterator I=DC->decls_begin(), E=DC->decls_end();
- I!=E ; ++I) {
-
- Decl *D = *I;
-
- if (D->hasBody())
- CheckStringRefAssignedTemporary(D, BR);
-
- if (CXXRecordDecl *R = dyn_cast<CXXRecordDecl>(D))
- if (R->isDefinition())
- CheckASTMemory(R, BR);
+namespace {
+class LLVMConventionsChecker : public CheckerV2<
+ check::ASTDecl<CXXRecordDecl>,
+ check::ASTCodeBody > {
+public:
+ void checkASTDecl(const CXXRecordDecl *R, AnalysisManager& mgr,
+ BugReporter &BR) const {
+ if (R->isDefinition())
+ CheckASTMemory(R, BR);
+ }
- if (DeclContext *DC_child = dyn_cast<DeclContext>(D))
- ScanCodeDecls(DC_child, BR);
+ void checkASTCodeBody(const Decl *D, AnalysisManager& mgr,
+ BugReporter &BR) const {
+ CheckStringRefAssignedTemporary(D, BR);
}
+};
}
-void ento::CheckLLVMConventions(TranslationUnitDecl &TU,
- BugReporter &BR) {
- ScanCodeDecls(&TU, BR);
+void ento::registerLLVMConventionsChecker(CheckerManager &mgr) {
+ mgr.registerChecker<LLVMConventionsChecker>();
}
-
Modified: cfe/trunk/lib/StaticAnalyzer/Core/CheckerManager.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/StaticAnalyzer/Core/CheckerManager.cpp?rev=125778&r1=125777&r2=125778&view=diff
==============================================================================
--- cfe/trunk/lib/StaticAnalyzer/Core/CheckerManager.cpp (original)
+++ cfe/trunk/lib/StaticAnalyzer/Core/CheckerManager.cpp Thu Feb 17 15:39:24 2011
@@ -13,14 +13,73 @@
#include "clang/StaticAnalyzer/Core/CheckerManager.h"
#include "clang/StaticAnalyzer/Core/CheckerProvider.h"
+#include "clang/AST/DeclBase.h"
using namespace clang;
using namespace ento;
+void CheckerManager::runCheckersOnASTDecl(const Decl *D, AnalysisManager& mgr,
+ BugReporter &BR) {
+ assert(D);
+
+ unsigned DeclKind = D->getKind();
+ CachedDeclCheckers *checkers = 0;
+ CachedDeclCheckersMapTy::iterator CCI = CachedDeclCheckersMap.find(DeclKind);
+ if (CCI != CachedDeclCheckersMap.end()) {
+ checkers = &(CCI->second);
+ } else {
+ // Find the checkers that should run for this Decl and cache them.
+ checkers = &CachedDeclCheckersMap[DeclKind];
+ for (unsigned i = 0, e = DeclCheckers.size(); i != e; ++i) {
+ DeclCheckerInfo &info = DeclCheckers[i];
+ if (info.IsForDeclFn(D))
+ checkers->push_back(std::make_pair(info.Checker, info.CheckFn));
+ }
+ }
+
+ assert(checkers);
+ for (CachedDeclCheckers::iterator
+ I = checkers->begin(), E = checkers->end(); I != E; ++I) {
+ CheckerRef checker = I->first;
+ CheckDeclFunc fn = I->second;
+ fn(checker, D, mgr, BR);
+ }
+}
+
+void CheckerManager::runCheckersOnASTBody(const Decl *D, AnalysisManager& mgr,
+ BugReporter &BR) {
+ assert(D && D->hasBody());
+
+ for (unsigned i = 0, e = BodyCheckers.size(); i != e; ++i) {
+ CheckerRef checker = BodyCheckers[i].first;
+ CheckDeclFunc fn = BodyCheckers[i].second;
+ fn(checker, D, mgr, BR);
+ }
+}
+
+void CheckerManager::_registerForDecl(CheckerRef checker, CheckDeclFunc checkfn,
+ HandlesDeclFunc isForDeclFn) {
+ DeclCheckerInfo info = { checker, checkfn, isForDeclFn };
+ DeclCheckers.push_back(info);
+}
+
+void CheckerManager::_registerForBody(CheckerRef checker,
+ CheckDeclFunc checkfn) {
+ BodyCheckers.push_back(std::make_pair(checker, checkfn));
+}
+
void CheckerManager::registerCheckersToEngine(ExprEngine &eng) {
for (unsigned i = 0, e = Funcs.size(); i != e; ++i)
Funcs[i](eng);
}
+CheckerManager::~CheckerManager() {
+ for (unsigned i = 0, e = Checkers.size(); i != e; ++i) {
+ CheckerRef checker = Checkers[i].first;
+ Dtor dtor = Checkers[i].second;
+ dtor(checker);
+ }
+}
+
// Anchor for the vtable.
CheckerProvider::~CheckerProvider() { }
Modified: cfe/trunk/lib/StaticAnalyzer/Frontend/AnalysisConsumer.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/StaticAnalyzer/Frontend/AnalysisConsumer.cpp?rev=125778&r1=125777&r2=125778&view=diff
==============================================================================
--- cfe/trunk/lib/StaticAnalyzer/Frontend/AnalysisConsumer.cpp (original)
+++ cfe/trunk/lib/StaticAnalyzer/Frontend/AnalysisConsumer.cpp Thu Feb 17 15:39:24 2011
@@ -82,7 +82,6 @@
Actions ObjCMethodActions;
Actions ObjCImplementationActions;
Actions CXXMethodActions;
- TUActions TranslationUnitActions; // Remove this.
public:
ASTContext* Ctx;
@@ -170,10 +169,6 @@
CXXMethodActions.push_back(action);
}
- void addTranslationUnitAction(TUAction action) {
- TranslationUnitActions.push_back(action);
- }
-
void addObjCImplementationAction(CodeAction action) {
ObjCImplementationActions.push_back(action);
}
@@ -207,10 +202,12 @@
//===----------------------------------------------------------------------===//
void AnalysisConsumer::HandleDeclContext(ASTContext &C, DeclContext *dc) {
+ BugReporter BR(*Mgr);
for (DeclContext::decl_iterator I = dc->decls_begin(), E = dc->decls_end();
I != E; ++I) {
Decl *D = *I;
-
+ checkerMgr->runCheckersOnASTDecl(D, *Mgr, BR);
+
switch (D->getKind()) {
case Decl::Namespace: {
HandleDeclContext(C, cast<NamespaceDecl>(D));
@@ -259,14 +256,11 @@
}
void AnalysisConsumer::HandleTranslationUnit(ASTContext &C) {
+ BugReporter BR(*Mgr);
TranslationUnitDecl *TU = C.getTranslationUnitDecl();
+ checkerMgr->runCheckersOnASTDecl(TU, *Mgr, BR);
HandleDeclContext(C, TU);
- for (TUActions::iterator I = TranslationUnitActions.begin(),
- E = TranslationUnitActions.end(); I != E; ++I) {
- (*I)(*this, *Mgr, *TU);
- }
-
// Explicitly destroy the PathDiagnosticClient. This will flush its output.
// FIXME: This should be replaced with something that doesn't rely on
// side-effects in PathDiagnosticClient's destructor. This is required when
@@ -308,6 +302,12 @@
if (D->hasBody() && Opts.AnalyzeNestedBlocks)
FindBlocks(cast<DeclContext>(D), WL);
+ BugReporter BR(*Mgr);
+ for (llvm::SmallVectorImpl<Decl*>::iterator WI=WL.begin(), WE=WL.end();
+ WI != WE; ++WI)
+ if ((*WI)->hasBody())
+ checkerMgr->runCheckersOnASTBody(*WI, *Mgr, BR);
+
for (Actions::iterator I = actions.begin(), E = actions.end(); I != E; ++I)
for (llvm::SmallVectorImpl<Decl*>::iterator WI=WL.begin(), WE=WL.end();
WI != WE; ++WI)
@@ -440,13 +440,6 @@
CheckSecuritySyntaxOnly(D, BR);
}
-static void ActionLLVMConventionChecker(AnalysisConsumer &C,
- AnalysisManager &mgr,
- TranslationUnitDecl &TU) {
- BugReporter BR(mgr);
- CheckLLVMConventions(TU, BR);
-}
-
static void ActionWarnObjCDealloc(AnalysisConsumer &C, AnalysisManager& mgr,
Decl *D) {
if (mgr.getLangOptions().getGCMode() == LangOptions::GCOnly)
More information about the cfe-commits
mailing list