Hi dblaikie, delesley, aaron.ballman,

The TestedVarsVisitor was folded into the ConsumedStmtVisitor.  The 
VarTestResult class was updated to allow these changes.  As well, the 
PropagationInfo class was updated for the same reasons.

http://llvm-reviews.chandlerc.com/D1480

Files:
  include/clang/Analysis/Analyses/Consumed.h
  lib/Analysis/Consumed.cpp
Index: include/clang/Analysis/Analyses/Consumed.h
===================================================================
--- include/clang/Analysis/Analyses/Consumed.h
+++ include/clang/Analysis/Analyses/Consumed.h
@@ -25,6 +25,8 @@
 namespace clang {
 namespace consumed {
 
+  class ConsumedStmtVisitor;
+  
   typedef SmallVector<PartialDiagnosticAt, 1> OptionalNotes;
   typedef std::pair<PartialDiagnosticAt, OptionalNotes> DelayedDiag;
   typedef std::list<DelayedDiag> DiagList;
@@ -90,11 +92,11 @@
 
   enum ConsumedState {
     // No state information for the given variable.
-    CS_None,
+    CS_None = 0,
     
-    CS_Unknown,
-    CS_Unconsumed,
-    CS_Consumed
+    CS_Unknown    = 1,
+    CS_Unconsumed = 2,
+    CS_Consumed   = 3
   };
 
   class ConsumedStateMap {
@@ -144,18 +146,6 @@
     
     void markVisited(const CFGBlock *Block);
   };
-  
-  struct VarTestResult {
-    const VarDecl *Var;
-    SourceLocation Loc;
-    bool UnconsumedInTrueBranch;
-    
-    VarTestResult() : Var(NULL), Loc(), UnconsumedInTrueBranch(true) {}
-    
-    VarTestResult(const VarDecl *Var, SourceLocation Loc,
-                  bool UnconsumedInTrueBranch)
-      : Var(Var), Loc(Loc), UnconsumedInTrueBranch(UnconsumedInTrueBranch) {}
-  };
 
   /// A class that handles the analysis of uniqueness violations.
   class ConsumedAnalyzer {
@@ -169,7 +159,8 @@
     CacheMapType ConsumableTypeCache;
     
     bool hasConsumableAttributes(const CXXRecordDecl *RD);
-    void splitState(const CFGBlock *CurrBlock, const IfStmt *Terminator);
+    void splitState(const ConsumedStmtVisitor &Visitor,
+                    const CFGBlock *CurrBlock, const IfStmt *Terminator);
     
   public:
     
Index: lib/Analysis/Consumed.cpp
===================================================================
--- lib/Analysis/Consumed.cpp
+++ lib/Analysis/Consumed.cpp
@@ -32,6 +32,8 @@
 
 // TODO: Mark variables as Unknown going into while- or for-loops only if they
 //       are referenced inside that block. (Deferred)
+// TODO: Handle variable definitions, e.g. bool valid = x.isValid();
+//       if (valid) ...; (Deferred)
 // TODO: Add a method(s) to identify which method calls perform what state
 //       transitions. (Deferred)
 // TODO: Take notes on state transitions to provide better warning messages.
@@ -41,6 +43,8 @@
 // TODO: Test IsFalseVisitor with values in the unknown state. (Deferred)
 // TODO: Look into combining IsFalseVisitor and TestedVarsVisitor. (Deferred)
 
+#define INVERT_CONSUMED_UNCONSUMED(State) static_cast<ConsumedState>(State ^ 1)
+
 using namespace clang;
 using namespace consumed;
 
@@ -69,40 +73,79 @@
 }
 
 namespace {
+struct VarTestResult {
+  const VarDecl *Var;
+  SourceLocation Loc;
+  ConsumedState TrueBranchState;
+  
+  VarTestResult() : Var(NULL), Loc(), TrueBranchState(CS_None) {}
+  
+  VarTestResult(const VarDecl *Var, SourceLocation Loc,
+                ConsumedState TrueBranchState)
+    : Var(Var), Loc(Loc), TrueBranchState(TrueBranchState) {}
+};
+} // end anonymous::VarTestResult
+
+namespace clang {
+namespace consumed {
 class ConsumedStmtVisitor : public ConstStmtVisitor<ConsumedStmtVisitor> {
   
-  union PropagationUnion {
-    ConsumedState State;
-    const VarDecl *Var;
+  enum ConstantInfo {
+    CV_None,
+    CV_True,
+    CV_False
   };
   
-  class PropagationInfo {
-    PropagationUnion StateOrVar;
+  struct RangeInfo {
+    unsigned Begin, End;
+    ConstantInfo ConstantValue;
+  };
   
-  public:
-    bool IsVar;
+  class PropagationInfo {
+    union PropagationUnion {
+      ConsumedState State;
+      RangeInfo Range;
+      const VarDecl *Var;
+    } InfoUnion;
     
-    PropagationInfo() : IsVar(false) {
-      StateOrVar.State = consumed::CS_None;
+  public:
+    enum {
+      IT_None,
+      IT_State,
+      IT_Range,
+      IT_Var
+    } InfoType;
+    
+    PropagationInfo() : InfoType(IT_None) {}
+    
+    PropagationInfo(unsigned RBegin, unsigned REnd) : InfoType(IT_Range) {
+      InfoUnion.Range.Begin = RBegin;
+      InfoUnion.Range.End   = REnd;
+      InfoUnion.Range.ConstantValue = CV_None;
     }
     
-    PropagationInfo(ConsumedState State) : IsVar(false) {
-      StateOrVar.State = State;
+    PropagationInfo(ConsumedState State) : InfoType(IT_State) {
+      InfoUnion.State = State;
     }
     
-    PropagationInfo(const VarDecl *Var) : IsVar(true) {
-      StateOrVar.Var = Var;
+    PropagationInfo(const VarDecl *Var) : InfoType(IT_Var) {
+      InfoUnion.Var = Var;
     }
     
-    ConsumedState getState() const { return StateOrVar.State; }
+    const ConsumedState & getState() const { return InfoUnion.State; }
+    const RangeInfo     & getRange() const { return InfoUnion.Range; }
+    const VarDecl       * getVar()   const { return InfoUnion.Var; }
     
-    const VarDecl * getVar() const { return IsVar ? StateOrVar.Var : NULL; }
+    bool isState() const { return InfoType == IT_State; }
+    bool isRange() const { return InfoType == IT_Range; }
+    bool isVar()   const { return InfoType == IT_Var; }
   };
   
   typedef llvm::DenseMap<const Stmt *, PropagationInfo> MapType;
   typedef std::pair<const Stmt *, PropagationInfo> PairType;
   typedef MapType::iterator InfoEntry;
-
+  typedef MapType::const_iterator ConstInfoEntry;
+  
   AnalysisDeclContext &AC;
   ConsumedAnalyzer &Analyzer;
   ConsumedStateMap *StateMap;
@@ -115,6 +158,8 @@
   bool isLikeMoveAssignment(const CXXMethodDecl *MethodDecl);
   
 public:
+
+  llvm::SmallVector<VarTestResult, 5> TestedVars;
   
   void Visit(const Stmt *StmtNode);
   
@@ -134,22 +179,34 @@
   ConsumedStmtVisitor(AnalysisDeclContext &AC, ConsumedAnalyzer &Analyzer,
                       ConsumedStateMap *StateMap)
       : AC(AC), Analyzer(Analyzer), StateMap(StateMap) {}
-
+  
+  std::pair<unsigned, unsigned> getTestRange(const Stmt *StmtNode) const {
+    ConstInfoEntry Entry = PropagationMap.find(StmtNode);
+    
+    if (Entry != PropagationMap.end() && Entry->second.isRange()) {
+      return std::make_pair(Entry->second.getRange().Begin,
+                            Entry->second.getRange().End);
+    } else {
+      return std::make_pair(0, 0);
+    }
+  }
+  
   void reset() {
     PropagationMap.clear();
+    TestedVars.clear();
   }
 };
 
 // TODO: When we support CallableWhenConsumed this will have to check for
 //       the different attributes and change the behavior bellow. (Deferred)
-void ConsumedStmtVisitor::checkCallability(const PropagationInfo &PState,
+void ConsumedStmtVisitor::checkCallability(const PropagationInfo &PInfo,
                                            const FunctionDecl *FunDecl,
                                            const CallExpr *Call) {
   
   if (!FunDecl->hasAttr<CallableWhenUnconsumedAttr>()) return;
   
-  if (PState.IsVar) {
-    const VarDecl *Var = PState.getVar();
+  if (PInfo.isVar()) {
+    const VarDecl *Var = PInfo.getVar();
     
     switch (StateMap->getState(Var)) {
     case CS_Consumed:
@@ -170,7 +227,7 @@
     }
     
   } else {
-    switch (PState.getState()) {
+    switch (PInfo.getState()) {
     case CS_Consumed:
       Analyzer.WarningsHandler.warnUseOfTempWhileConsumed(
         FunDecl->getNameAsString(), Call->getExprLoc());
@@ -250,24 +307,24 @@
       
       InfoEntry Entry = PropagationMap.find(Call->getArg(Index));
       
-      if (Entry == PropagationMap.end() || !Entry->second.IsVar) {
+      if (Entry == PropagationMap.end() || !Entry->second.isVar()) {
         continue;
       }
       
-      PropagationInfo PState = Entry->second;
+      PropagationInfo PInfo = Entry->second;
       
       if (ParamType->isRValueReferenceType() ||
           (ParamType->isLValueReferenceType() &&
            !cast<LValueReferenceType>(*ParamType).isSpelledAsLValue())) {
         
-        StateMap->setState(PState.getVar(), consumed::CS_Consumed);
+        StateMap->setState(PInfo.getVar(), consumed::CS_Consumed);
         
       } else if (!(ParamType.isConstQualified() ||
                    ((ParamType->isReferenceType() ||
                      ParamType->isPointerType()) &&
                     ParamType->getPointeeType().isConstQualified()))) {
         
-        StateMap->setState(PState.getVar(), consumed::CS_Unknown);
+        StateMap->setState(PInfo.getVar(), consumed::CS_Unknown);
       }
     }
   }
@@ -295,11 +352,11 @@
       
     } else if (Constructor->isMoveConstructor()) {
       
-      PropagationInfo PState =
+      PropagationInfo PInfo =
         PropagationMap.find(Call->getArg(0))->second;
       
-      if (PState.IsVar) {
-        const VarDecl* Var = PState.getVar();
+      if (PInfo.isVar()) {
+        const VarDecl* Var = PInfo.getVar();
         
         PropagationMap.insert(PairType(Call,
           PropagationInfo(StateMap->getState(Var))));
@@ -307,7 +364,7 @@
         StateMap->setState(Var, consumed::CS_Consumed);
         
       } else {
-        PropagationMap.insert(PairType(Call, PState));
+        PropagationMap.insert(PairType(Call, PInfo));
       }
         
     } else if (Constructor->isCopyConstructor()) {
@@ -331,16 +388,27 @@
   InfoEntry Entry = PropagationMap.find(Call->getCallee()->IgnoreParens());
   
   if (Entry != PropagationMap.end()) {
-    PropagationInfo PState = Entry->second;
+    PropagationInfo PInfo = Entry->second;
     const CXXMethodDecl *MethodDecl = Call->getMethodDecl();
     
-    checkCallability(PState, MethodDecl, Call);
+    checkCallability(PInfo, MethodDecl, Call);
     
-    if (PState.IsVar) {
-      if (MethodDecl->hasAttr<ConsumesAttr>())
-        StateMap->setState(PState.getVar(), consumed::CS_Consumed);
-      else if (!MethodDecl->isConst())
-        StateMap->setState(PState.getVar(), consumed::CS_Unknown);
+    if (PInfo.isVar()) {
+      if (isTestingFunction(MethodDecl)) {
+        unsigned short CurrIndex = TestedVars.size();
+        
+        PropagationMap.insert(PairType(Call,
+          PropagationInfo(CurrIndex, CurrIndex + 1)));
+        
+        TestedVars.push_back(
+          VarTestResult(PInfo.getVar(), Call->getExprLoc(), CS_Unconsumed));
+        
+      } else if (MethodDecl->hasAttr<ConsumesAttr>()) {
+        StateMap->setState(PInfo.getVar(), consumed::CS_Consumed);
+        
+      } else if (!MethodDecl->isConst()) {
+        StateMap->setState(PInfo.getVar(), consumed::CS_Unknown);
+      }
     }
   }
 }
@@ -359,46 +427,46 @@
     InfoEntry LEntry = PropagationMap.find(Call->getArg(0));
     InfoEntry REntry = PropagationMap.find(Call->getArg(1));
     
-    PropagationInfo LPState, RPState;
+    PropagationInfo LPInfo, RPInfo;
     
     if (LEntry != PropagationMap.end() &&
         REntry != PropagationMap.end()) {
       
-      LPState = LEntry->second;
-      RPState = REntry->second;
+      LPInfo = LEntry->second;
+      RPInfo = REntry->second;
       
-      if (LPState.IsVar && RPState.IsVar) {
-        StateMap->setState(LPState.getVar(),
-          StateMap->getState(RPState.getVar()));
+      if (LPInfo.isVar() && RPInfo.isVar()) {
+        StateMap->setState(LPInfo.getVar(),
+          StateMap->getState(RPInfo.getVar()));
         
-        StateMap->setState(RPState.getVar(), consumed::CS_Consumed);
+        StateMap->setState(RPInfo.getVar(), consumed::CS_Consumed);
         
-        PropagationMap.insert(PairType(Call, LPState));
+        PropagationMap.insert(PairType(Call, LPInfo));
         
-      } else if (LPState.IsVar && !RPState.IsVar) {
-        StateMap->setState(LPState.getVar(), RPState.getState());
+      } else if (LPInfo.isVar() && !RPInfo.isVar()) {
+        StateMap->setState(LPInfo.getVar(), RPInfo.getState());
         
-        PropagationMap.insert(PairType(Call, LPState));
+        PropagationMap.insert(PairType(Call, LPInfo));
         
-      } else if (!LPState.IsVar && RPState.IsVar) {
+      } else if (!LPInfo.isVar() && RPInfo.isVar()) {
         PropagationMap.insert(PairType(Call,
-          PropagationInfo(StateMap->getState(RPState.getVar()))));
+          PropagationInfo(StateMap->getState(RPInfo.getVar()))));
         
-        StateMap->setState(RPState.getVar(), consumed::CS_Consumed);
+        StateMap->setState(RPInfo.getVar(), consumed::CS_Consumed);
         
       } else {
-        PropagationMap.insert(PairType(Call, RPState));
+        PropagationMap.insert(PairType(Call, RPInfo));
       }
       
     } else if (LEntry != PropagationMap.end() &&
                REntry == PropagationMap.end()) {
       
-      LPState = LEntry->second;
+      LPInfo = LEntry->second;
       
-      if (LPState.IsVar) {
-        StateMap->setState(LPState.getVar(), consumed::CS_Unknown);
+      if (LPInfo.isVar()) {
+        StateMap->setState(LPInfo.getVar(), consumed::CS_Unknown);
         
-        PropagationMap.insert(PairType(Call, LPState));
+        PropagationMap.insert(PairType(Call, LPInfo));
         
       } else {
         PropagationMap.insert(PairType(Call,
@@ -408,10 +476,10 @@
     } else if (LEntry == PropagationMap.end() &&
                REntry != PropagationMap.end()) {
       
-      RPState = REntry->second;
+      RPInfo = REntry->second;
       
-      if (RPState.IsVar) {
-        const VarDecl *Var = RPState.getVar();
+      if (RPInfo.isVar()) {
+        const VarDecl *Var = RPInfo.getVar();
         
         PropagationMap.insert(PairType(Call,
           PropagationInfo(StateMap->getState(Var))));
@@ -419,7 +487,7 @@
         StateMap->setState(Var, consumed::CS_Consumed);
         
       } else {
-        PropagationMap.insert(PairType(Call, RPState));
+        PropagationMap.insert(PairType(Call, RPInfo));
       }
     }
     
@@ -430,20 +498,30 @@
     InfoEntry Entry = PropagationMap.find(Call->getArg(0));
     
     if (Entry != PropagationMap.end()) {
-      PropagationInfo PState = Entry->second;
+      PropagationInfo PInfo = Entry->second;
       
-      checkCallability(PState, FunDecl, Call);
+      checkCallability(PInfo, FunDecl, Call);
       
-      if (PState.IsVar) {
-        if (FunDecl->hasAttr<ConsumesAttr>()) {
+      if (PInfo.isVar()) {
+        if (isTestingFunction(FunDecl)) {
+          unsigned short CurrIndex = TestedVars.size();
+                    
+          PropagationMap.insert(PairType(Call,
+            PropagationInfo(CurrIndex, CurrIndex + 1)));
+          
+          TestedVars.push_back(
+            VarTestResult(PInfo.getVar(), Call->getExprLoc(), CS_Unconsumed));
+          
+        } else if (FunDecl->hasAttr<ConsumesAttr>()) {
           // Handle consuming operators.
-          StateMap->setState(PState.getVar(), consumed::CS_Consumed);
+          StateMap->setState(PInfo.getVar(), consumed::CS_Consumed);
+          
         } else if (const CXXMethodDecl *MethodDecl =
           dyn_cast_or_null<CXXMethodDecl>(FunDecl)) {
           
           // Handle non-constant member operators.
           if (!MethodDecl->isConst())
-            StateMap->setState(PState.getVar(), consumed::CS_Unknown);
+            StateMap->setState(PInfo.getVar(), consumed::CS_Unknown);
         }
       }
     }
@@ -482,84 +560,42 @@
 }
 
 void ConsumedStmtVisitor::VisitUnaryOperator(const UnaryOperator *UOp) {
-  if (UOp->getOpcode() == UO_AddrOf) {
-    InfoEntry Entry = PropagationMap.find(UOp->getSubExpr());
-    
-    if (Entry != PropagationMap.end())
-      PropagationMap.insert(PairType(UOp, Entry->second));
-  }
-}
-
-void ConsumedStmtVisitor::VisitVarDecl(const VarDecl *Var) {
-  if (Analyzer.isConsumableType(Var->getType())) {
-    PropagationInfo PState =
-      PropagationMap.find(Var->getInit())->second;
-    
-    StateMap->setState(Var, PState.IsVar ?
-      StateMap->getState(PState.getVar()) : PState.getState());
-  }
-}
-} // end anonymous::ConsumedStmtVisitor
-
-namespace {
-
-// TODO: Handle variable definitions, e.g. bool valid = x.isValid();
-//       if (valid) ...; (Deferred)
-class TestedVarsVisitor : public RecursiveASTVisitor<TestedVarsVisitor> {
-  
-  bool Invert;
-  SourceLocation CurrTestLoc;
+  InfoEntry Entry = PropagationMap.find(UOp->getSubExpr());
+  if (Entry == PropagationMap.end()) return;
   
-  ConsumedStateMap *StateMap;
-  
-public:
-  bool IsUsefulConditional;
-  VarTestResult Test;
-  
-  TestedVarsVisitor(ConsumedStateMap *StateMap) : Invert(false),
-    StateMap(StateMap), IsUsefulConditional(false) {}
+  switch (UOp->getOpcode()) {
+  case UO_AddrOf:
+    PropagationMap.insert(PairType(UOp, Entry->second));
+    break;
   
-  bool VisitCallExpr(CallExpr *Call);
-  bool VisitDeclRefExpr(DeclRefExpr *DeclRef);
-  bool VisitUnaryOperator(UnaryOperator *UnaryOp);
-};
-
-bool TestedVarsVisitor::VisitCallExpr(CallExpr *Call) {
-  if (const FunctionDecl *FunDecl =
-    dyn_cast_or_null<FunctionDecl>(Call->getDirectCallee())) {
-    
-    if (isTestingFunction(FunDecl)) {
-      CurrTestLoc = Call->getExprLoc();
-      IsUsefulConditional = true;
-      return true;
+  case UO_LNot:
+    if (Entry->second.isRange()) {
+      const RangeInfo &Range = Entry->second.getRange();
+      
+      for (unsigned index = Range.Begin; index < Range.End; ++index) {
+        ConsumedState &TestState  = TestedVars[index].TrueBranchState;
+        TestState = INVERT_CONSUMED_UNCONSUMED(TestState);
+      }
+      
+      PropagationMap.insert(PairType(UOp, PropagationInfo(Entry->second)));
     }
-    
-    IsUsefulConditional = false;
-  }
-  
-  return false;
-}
-
-bool TestedVarsVisitor::VisitDeclRefExpr(DeclRefExpr *DeclRef) {
-  if (const VarDecl *Var = dyn_cast_or_null<VarDecl>(DeclRef->getDecl()))
-    if (StateMap->getState(Var) != consumed::CS_None)
-      Test = VarTestResult(Var, CurrTestLoc, !Invert);
+    break;
   
-  return true;
+  default:
+    break;
+  }
 }
 
-bool TestedVarsVisitor::VisitUnaryOperator(UnaryOperator *UnaryOp) {
-  if (UnaryOp->getOpcode() == UO_LNot) {
-    Invert = true;
-    TraverseStmt(UnaryOp->getSubExpr());
+void ConsumedStmtVisitor::VisitVarDecl(const VarDecl *Var) {
+  if (Analyzer.isConsumableType(Var->getType())) {
+    PropagationInfo PInfo =
+      PropagationMap.find(Var->getInit())->second;
     
-  } else {
-    IsUsefulConditional = false;
+    StateMap->setState(Var, PInfo.isVar() ?
+      StateMap->getState(PInfo.getVar()) : PInfo.getState());
   }
-  
-  return false;
 }
-} // end anonymouse::TestedVarsVisitor
+}} // end clang::consumed::ConsumedStmtVisitor
 
 namespace clang {
 namespace consumed {
@@ -696,33 +732,37 @@
 
 // TODO: Handle other forms of branching with precision, including while- and
 //       for-loops. (Deferred)
-void ConsumedAnalyzer::splitState(const CFGBlock *CurrBlock,
+void ConsumedAnalyzer::splitState(const ConsumedStmtVisitor &Visitor,
+                                  const CFGBlock *CurrBlock,
                                   const IfStmt *Terminator) {
   
-  TestedVarsVisitor Visitor(CurrStates);
-  Visitor.TraverseStmt(const_cast<Expr*>(Terminator->getCond()));
+  bool HasElse                        = Terminator->getElse() != NULL;
+  ConsumedStateMap *ElseOrMergeStates = new ConsumedStateMap(*CurrStates);
   
-  bool HasElse = Terminator->getElse() != NULL;
+  std::pair<unsigned, unsigned> TestRange =
+    Visitor.getTestRange(Terminator->getCond());
   
-  ConsumedStateMap *ElseOrMergeStates = new ConsumedStateMap(*CurrStates);
+  Terminator->getCond()->dump();
   
-  if (Visitor.IsUsefulConditional) {
-    ConsumedState VarState = CurrStates->getState(Visitor.Test.Var);
+  // When there are no valid tests the start and end index will both be 0.
+  while (TestRange.first < TestRange.second) {
+    const VarTestResult &Test = Visitor.TestedVars[TestRange.first++];
+    ConsumedState VarState    = CurrStates->getState(Test.Var);
     
     if (VarState != CS_Unknown) {
       // FIXME: Make this not warn if the test is from a macro expansion.
       //        (Deferred)
-      WarningsHandler.warnUnnecessaryTest(Visitor.Test.Var->getNameAsString(),
-        stateToString(VarState), Visitor.Test.Loc);
+      WarningsHandler.warnUnnecessaryTest(Test.Var->getNameAsString(),
+        stateToString(VarState), Test.Loc);
     }
     
-    if (Visitor.Test.UnconsumedInTrueBranch) {
-      CurrStates->setState(Visitor.Test.Var, CS_Unconsumed);
-      if (HasElse) ElseOrMergeStates->setState(Visitor.Test.Var, CS_Consumed);
+    if (Test.TrueBranchState == CS_Unconsumed) {
+      CurrStates->setState(Test.Var, CS_Unconsumed);
+      if (HasElse) ElseOrMergeStates->setState(Test.Var, CS_Consumed);
       
     } else {
-      CurrStates->setState(Visitor.Test.Var, CS_Consumed);
-      if (HasElse) ElseOrMergeStates->setState(Visitor.Test.Var, CS_Unconsumed);
+      CurrStates->setState(Test.Var, CS_Consumed);
+      if (HasElse) ElseOrMergeStates->setState(Test.Var, CS_Unconsumed);
     }
   }
     
@@ -773,7 +813,7 @@
     if (const IfStmt *Terminator =
       dyn_cast_or_null<IfStmt>(CurrBlock->getTerminator().getStmt())) {
       
-      splitState(CurrBlock, Terminator);
+      splitState(Visitor, CurrBlock, Terminator);
       CurrStates = NULL;
     
     } else if (CurrBlock->succ_size() > 1) {
_______________________________________________
cfe-commits mailing list
[email protected]
http://lists.cs.uiuc.edu/mailman/listinfo/cfe-commits

Reply via email to