https://github.com/el-ev updated 
https://github.com/llvm/llvm-project/pull/136854

>From 9e6c30658f628e736567f57589a6534cfe060902 Mon Sep 17 00:00:00 2001
From: Iris Shi <0...@owo.li>
Date: Thu, 8 May 2025 23:40:15 +0800
Subject: [PATCH 1/2] [CIR] Cleanup support for C functions

---
 clang/lib/CIR/CodeGen/CIRGenCall.cpp       | 52 ++++++++++--
 clang/lib/CIR/CodeGen/CIRGenFunctionInfo.h | 97 ++++++++++++++++++----
 clang/lib/CIR/CodeGen/CIRGenModule.cpp     | 18 +++-
 clang/lib/CIR/CodeGen/CIRGenTypes.cpp      | 38 ++++-----
 clang/lib/CIR/CodeGen/CIRGenTypes.h        | 10 ++-
 clang/lib/CIR/CodeGen/TargetInfo.cpp       |  8 --
 clang/test/CIR/CodeGen/basic.c             | 13 +++
 7 files changed, 183 insertions(+), 53 deletions(-)

diff --git a/clang/lib/CIR/CodeGen/CIRGenCall.cpp 
b/clang/lib/CIR/CodeGen/CIRGenCall.cpp
index 70d45dc383fd1..5c65a43641844 100644
--- a/clang/lib/CIR/CodeGen/CIRGenCall.cpp
+++ b/clang/lib/CIR/CodeGen/CIRGenCall.cpp
@@ -13,6 +13,7 @@
 
 #include "CIRGenCall.h"
 #include "CIRGenFunction.h"
+#include "CIRGenFunctionInfo.h"
 #include "clang/CIR/MissingFeatures.h"
 
 using namespace clang;
@@ -20,25 +21,43 @@ using namespace clang::CIRGen;
 
 CIRGenFunctionInfo *
 CIRGenFunctionInfo::create(CanQualType resultType,
-                           llvm::ArrayRef<CanQualType> argTypes) {
+                           llvm::ArrayRef<CanQualType> argTypes,
+                           RequiredArgs required) {
   // The first slot allocated for ArgInfo is for the return value.
   void *buffer = operator new(totalSizeToAlloc<ArgInfo>(argTypes.size() + 1));
 
+  assert(!cir::MissingFeatures::opCallCIRGenFuncInfoParamInfo());
+
   CIRGenFunctionInfo *fi = new (buffer) CIRGenFunctionInfo();
-  fi->numArgs = argTypes.size();
 
-  assert(!cir::MissingFeatures::opCallCIRGenFuncInfoParamInfo());
+  fi->required = required;
+  fi->numArgs = argTypes.size();
 
   ArgInfo *argsBuffer = fi->getArgsBuffer();
   (argsBuffer++)->type = resultType;
   for (CanQualType ty : argTypes)
     (argsBuffer++)->type = ty;
-
   assert(!cir::MissingFeatures::opCallCIRGenFuncInfoExtParamInfo());
 
   return fi;
 }
 
+cir::FuncType CIRGenTypes::getFunctionType(const CIRGenFunctionInfo &fi) {
+  mlir::Type resultType = convertType(fi.getReturnType());
+
+  SmallVector<mlir::Type, 8> argTypes(fi.getNumRequiredArgs());
+
+  unsigned argNo = 0;
+  llvm::ArrayRef<CIRGenFunctionInfoArgInfo> argInfos(fi.argInfoBegin(),
+                                                     fi.getNumRequiredArgs());
+  for (const auto &argInfo : argInfos)
+    argTypes[argNo++] = convertType(argInfo.type);
+
+  return cir::FuncType::get(argTypes,
+                            (resultType ? resultType : builder.getVoidTy()),
+                            fi.isVariadic());
+}
+
 CIRGenCallee CIRGenCallee::prepareConcreteCallee(CIRGenFunction &cgf) const {
   assert(!cir::MissingFeatures::opCallVirtual());
   return *this;
@@ -48,6 +67,9 @@ static const CIRGenFunctionInfo &
 arrangeFreeFunctionLikeCall(CIRGenTypes &cgt, CIRGenModule &cgm,
                             const CallArgList &args,
                             const FunctionType *fnType) {
+
+  RequiredArgs required = RequiredArgs::All;
+
   if (const auto *proto = dyn_cast<FunctionProtoType>(fnType)) {
     if (proto->isVariadic())
       cgm.errorNYI("call to variadic function");
@@ -64,7 +86,7 @@ arrangeFreeFunctionLikeCall(CIRGenTypes &cgt, CIRGenModule 
&cgm,
   CanQualType retType = fnType->getReturnType()
                             ->getCanonicalTypeUnqualified()
                             .getUnqualifiedType();
-  return cgt.arrangeCIRFunctionInfo(retType, argTypes);
+  return cgt.arrangeCIRFunctionInfo(retType, argTypes, required);
 }
 
 const CIRGenFunctionInfo &
@@ -88,6 +110,23 @@ emitCallLikeOp(CIRGenFunction &cgf, mlir::Location callLoc,
   return builder.createCallOp(callLoc, directFuncOp, cirCallArgs);
 }
 
+const CIRGenFunctionInfo &
+CIRGenTypes::arrangeFreeFunctionType(CanQual<FunctionProtoType> fpt) {
+  SmallVector<CanQualType, 8> argTypes;
+  for (unsigned i = 0, e = fpt->getNumParams(); i != e; ++i)
+    argTypes.push_back(fpt->getParamType(i));
+  RequiredArgs required = RequiredArgs::forPrototypePlus(fpt);
+
+  CanQualType resultType = fpt->getReturnType().getUnqualifiedType();
+  return arrangeCIRFunctionInfo(resultType, argTypes, required);
+}
+
+const CIRGenFunctionInfo &
+CIRGenTypes::arrangeFreeFunctionType(CanQual<FunctionNoProtoType> fnpt) {
+  CanQualType resultType = fnpt->getReturnType().getUnqualifiedType();
+  return arrangeCIRFunctionInfo(resultType, {}, RequiredArgs(0));
+}
+
 RValue CIRGenFunction::emitCall(const CIRGenFunctionInfo &funcInfo,
                                 const CIRGenCallee &callee,
                                 ReturnValueSlot returnValue,
@@ -102,7 +141,8 @@ RValue CIRGenFunction::emitCall(const CIRGenFunctionInfo 
&funcInfo,
 
   // Translate all of the arguments as necessary to match the CIR lowering.
   for (auto [argNo, arg, argInfo] :
-       llvm::enumerate(args, funcInfo.arguments())) {
+       llvm::enumerate(args, funcInfo.argInfos())) {
+
     // Insert a padding argument to ensure proper alignment.
     assert(!cir::MissingFeatures::opCallPaddingArgs());
 
diff --git a/clang/lib/CIR/CodeGen/CIRGenFunctionInfo.h 
b/clang/lib/CIR/CodeGen/CIRGenFunctionInfo.h
index 645e6b23c4f76..0556408fb98d1 100644
--- a/clang/lib/CIR/CodeGen/CIRGenFunctionInfo.h
+++ b/clang/lib/CIR/CodeGen/CIRGenFunctionInfo.h
@@ -25,20 +25,68 @@ struct CIRGenFunctionInfoArgInfo {
   CanQualType type;
 };
 
+/// A class for recording the number of arguments that a function signature
+/// requires.
+class RequiredArgs {
+  /// The number of required arguments, or ~0 if the signature does not permit
+  /// optional arguments.
+  unsigned numRequired;
+
+public:
+  enum All_t { All };
+
+  RequiredArgs(All_t _) : numRequired(~0U) {}
+  explicit RequiredArgs(unsigned n) : numRequired(n) { assert(n != ~0U); }
+
+  unsigned getOpaqueData() const { return numRequired; }
+
+  bool allowsOptionalArgs() const { return numRequired != ~0U; }
+
+  /// Compute the arguments required by the given formal prototype, given that
+  /// there may be some additional, non-formal arguments in play.
+  ///
+  /// If FD is not null, this will consider pass_object_size params in FD.
+  static RequiredArgs
+  forPrototypePlus(const clang::FunctionProtoType *prototype) {
+    if (!prototype->isVariadic())
+      return All;
+
+    if (prototype->hasExtParameterInfos())
+      llvm_unreachable("NYI");
+
+    return RequiredArgs(prototype->getNumParams());
+  }
+
+  static RequiredArgs
+  forPrototypePlus(clang::CanQual<clang::FunctionProtoType> prototype) {
+    return forPrototypePlus(prototype.getTypePtr());
+  }
+
+  unsigned getNumRequiredArgs() const {
+    assert(allowsOptionalArgs());
+    return numRequired;
+  }
+};
+
 class CIRGenFunctionInfo final
     : public llvm::FoldingSetNode,
       private llvm::TrailingObjects<CIRGenFunctionInfo,
                                     CIRGenFunctionInfoArgInfo> {
   using ArgInfo = CIRGenFunctionInfoArgInfo;
 
+  RequiredArgs required;
+
   unsigned numArgs;
 
   ArgInfo *getArgsBuffer() { return getTrailingObjects<ArgInfo>(); }
   const ArgInfo *getArgsBuffer() const { return getTrailingObjects<ArgInfo>(); 
}
 
+  CIRGenFunctionInfo() : required(RequiredArgs::All) {}
+
 public:
   static CIRGenFunctionInfo *create(CanQualType resultType,
-                                    llvm::ArrayRef<CanQualType> argTypes);
+                                    llvm::ArrayRef<CanQualType> argTypes,
+                                    RequiredArgs required);
 
   void operator delete(void *p) { ::operator delete(p); }
 
@@ -51,30 +99,45 @@ class CIRGenFunctionInfo final
 
   // This function has to be CamelCase because llvm::FoldingSet requires so.
   // NOLINTNEXTLINE(readability-identifier-naming)
-  static void Profile(llvm::FoldingSetNodeID &id, CanQualType resultType,
-                      llvm::ArrayRef<clang::CanQualType> argTypes) {
+  static void Profile(llvm::FoldingSetNodeID &id, RequiredArgs required,
+                      CanQualType resultType,
+                      llvm::ArrayRef<CanQualType> argTypes) {
+    id.AddBoolean(required.getOpaqueData());
     resultType.Profile(id);
-    for (auto i : argTypes)
-      i.Profile(id);
+    for (const CanQualType &arg : argTypes)
+      arg.Profile(id);
   }
 
-  void Profile(llvm::FoldingSetNodeID &id) { getReturnType().Profile(id); }
-
-  llvm::MutableArrayRef<ArgInfo> arguments() {
-    return llvm::MutableArrayRef<ArgInfo>(arg_begin(), numArgs);
+  // NOLINTNEXTLINE(readability-identifier-naming)
+  void Profile(llvm::FoldingSetNodeID &id) {
+    id.AddBoolean(required.getOpaqueData());
+    getReturnType().Profile(id);
   }
-  llvm::ArrayRef<ArgInfo> arguments() const {
-    return llvm::ArrayRef<ArgInfo>(arg_begin(), numArgs);
+
+  CanQualType getReturnType() const { return getArgsBuffer()[0].type; }
+
+  const_arg_iterator argInfoBegin() const { return getArgsBuffer() + 1; }
+  const_arg_iterator argInfoEnd() const {
+    return getArgsBuffer() + 1 + numArgs;
   }
+  arg_iterator argInfoBegin() { return getArgsBuffer() + 1; }
+  arg_iterator argInfoEnd() { return getArgsBuffer() + 1 + numArgs; }
 
-  const_arg_iterator arg_begin() const { return getArgsBuffer() + 1; }
-  const_arg_iterator arg_end() const { return getArgsBuffer() + 1 + numArgs; }
-  arg_iterator arg_begin() { return getArgsBuffer() + 1; }
-  arg_iterator arg_end() { return getArgsBuffer() + 1 + numArgs; }
+  unsigned argInfoSize() const { return numArgs; }
 
-  unsigned arg_size() const { return numArgs; }
+  llvm::MutableArrayRef<ArgInfo> argInfos() {
+    return llvm::MutableArrayRef<ArgInfo>(argInfoBegin(), numArgs);
+  }
+  llvm::ArrayRef<ArgInfo> argInfos() const {
+    return llvm::ArrayRef<ArgInfo>(argInfoBegin(), numArgs);
+  }
 
-  CanQualType getReturnType() const { return getArgsBuffer()[0].type; }
+  bool isVariadic() const { return required.allowsOptionalArgs(); }
+  RequiredArgs getRequiredArgs() const { return required; }
+  unsigned getNumRequiredArgs() const {
+    return isVariadic() ? getRequiredArgs().getNumRequiredArgs()
+                        : argInfoSize();
+  }
 };
 
 } // namespace clang::CIRGen
diff --git a/clang/lib/CIR/CodeGen/CIRGenModule.cpp 
b/clang/lib/CIR/CodeGen/CIRGenModule.cpp
index 6899e49d990db..157ea1fd87287 100644
--- a/clang/lib/CIR/CodeGen/CIRGenModule.cpp
+++ b/clang/lib/CIR/CodeGen/CIRGenModule.cpp
@@ -23,6 +23,7 @@
 #include "clang/CIR/Dialect/IR/CIRDialect.h"
 #include "clang/CIR/MissingFeatures.h"
 
+#include "CIRGenFunctionInfo.h"
 #include "mlir/IR/BuiltinOps.h"
 #include "mlir/IR/Location.h"
 #include "mlir/IR/MLIRContext.h"
@@ -247,8 +248,21 @@ void 
CIRGenModule::emitGlobalFunctionDefinition(clang::GlobalDecl gd,
              "function definition with a non-identifier for a name");
     return;
   }
-  cir::FuncType funcType =
-      cast<cir::FuncType>(convertType(funcDecl->getType()));
+
+  cir::FuncType funcType;
+  // TODO: Move this to arrangeFunctionDeclaration when it is
+  // implemented.
+  // When declaring a function without a prototype, always use a
+  // non-variadic type.
+  if (CanQual<FunctionNoProtoType> noProto =
+          funcDecl->getType()
+              ->getCanonicalTypeUnqualified()
+              .getAs<FunctionNoProtoType>()) {
+    const CIRGenFunctionInfo &fi = getTypes().arrangeCIRFunctionInfo(
+        noProto->getReturnType(), {}, RequiredArgs::All);
+    funcType = getTypes().getFunctionType(fi);
+  } else
+    funcType = cast<cir::FuncType>(convertType(funcDecl->getType()));
 
   cir::FuncOp funcOp = dyn_cast_if_present<cir::FuncOp>(op);
   if (!funcOp || funcOp.getFunctionType() != funcType) {
diff --git a/clang/lib/CIR/CodeGen/CIRGenTypes.cpp 
b/clang/lib/CIR/CodeGen/CIRGenTypes.cpp
index eecd29cf953cf..097d14b370940 100644
--- a/clang/lib/CIR/CodeGen/CIRGenTypes.cpp
+++ b/clang/lib/CIR/CodeGen/CIRGenTypes.cpp
@@ -1,5 +1,6 @@
 #include "CIRGenTypes.h"
 
+#include "CIRGenFunctionInfo.h"
 #include "CIRGenModule.h"
 
 #include "clang/AST/ASTContext.h"
@@ -73,21 +74,19 @@ mlir::Type 
CIRGenTypes::convertFunctionTypeInternal(QualType qft) {
     return cir::FuncType::get(SmallVector<mlir::Type, 1>{}, cgm.VoidTy);
   }
 
-  // TODO(CIR): This is a stub of what the final code will be.  See the
-  // implementation of this function and the implementation of class
-  // CIRGenFunction in the ClangIR incubator project.
-
+  const CIRGenFunctionInfo *fi;
   if (const auto *fpt = dyn_cast<FunctionProtoType>(ft)) {
-    SmallVector<mlir::Type> mlirParamTypes;
-    for (unsigned i = 0; i < fpt->getNumParams(); ++i) {
-      mlirParamTypes.push_back(convertType(fpt->getParamType(i)));
-    }
-    return cir::FuncType::get(
-        mlirParamTypes, convertType(fpt->getReturnType().getUnqualifiedType()),
-        fpt->isVariadic());
+    fi = &arrangeFreeFunctionType(
+        CanQual<FunctionProtoType>::CreateUnsafe(QualType(fpt, 0)));
+  } else {
+    const FunctionNoProtoType *fnpt = cast<FunctionNoProtoType>(ft);
+    fi = &arrangeFreeFunctionType(
+        CanQual<FunctionNoProtoType>::CreateUnsafe(QualType(fnpt, 0)));
   }
-  cgm.errorNYI(SourceLocation(), "non-prototype function type", qft);
-  return cir::FuncType::get(SmallVector<mlir::Type, 1>{}, cgm.VoidTy);
+
+  mlir::Type resultType = getFunctionType(*fi);
+
+  return resultType;
 }
 
 // This is CIR's version of CodeGenTypes::addRecordTypeName. It isn't shareable
@@ -531,14 +530,15 @@ bool CIRGenTypes::isZeroInitializable(const RecordDecl 
*rd) {
   return getCIRGenRecordLayout(rd).isZeroInitializable();
 }
 
-const CIRGenFunctionInfo &CIRGenTypes::arrangeCIRFunctionInfo(
-    CanQualType returnType, llvm::ArrayRef<clang::CanQualType> argTypes) {
+const CIRGenFunctionInfo &
+CIRGenTypes::arrangeCIRFunctionInfo(CanQualType returnType,
+                                    llvm::ArrayRef<CanQualType> argTypes,
+                                    RequiredArgs required) {
   assert(llvm::all_of(argTypes,
-                      [](CanQualType T) { return T.isCanonicalAsParam(); }));
-
+                      [](CanQualType t) { return t.isCanonicalAsParam(); }));
   // Lookup or create unique function info.
   llvm::FoldingSetNodeID id;
-  CIRGenFunctionInfo::Profile(id, returnType, argTypes);
+  CIRGenFunctionInfo::Profile(id, required, returnType, argTypes);
 
   void *insertPos = nullptr;
   CIRGenFunctionInfo *fi = functionInfos.FindNodeOrInsertPos(id, insertPos);
@@ -548,7 +548,7 @@ const CIRGenFunctionInfo 
&CIRGenTypes::arrangeCIRFunctionInfo(
   assert(!cir::MissingFeatures::opCallCallConv());
 
   // Construction the function info. We co-allocate the ArgInfos.
-  fi = CIRGenFunctionInfo::create(returnType, argTypes);
+  fi = CIRGenFunctionInfo::create(returnType, argTypes, required);
   functionInfos.InsertNode(fi, insertPos);
 
   return *fi;
diff --git a/clang/lib/CIR/CodeGen/CIRGenTypes.h 
b/clang/lib/CIR/CodeGen/CIRGenTypes.h
index cf94375d17e12..ff8ce3f87f362 100644
--- a/clang/lib/CIR/CodeGen/CIRGenTypes.h
+++ b/clang/lib/CIR/CodeGen/CIRGenTypes.h
@@ -127,7 +127,15 @@ class CIRGenTypes {
 
   const CIRGenFunctionInfo &
   arrangeCIRFunctionInfo(CanQualType returnType,
-                         llvm::ArrayRef<clang::CanQualType> argTypes);
+                         llvm::ArrayRef<CanQualType> argTypes,
+                         RequiredArgs required);
+
+  const CIRGenFunctionInfo &
+  arrangeFreeFunctionType(CanQual<FunctionProtoType> fpt);
+  const CIRGenFunctionInfo &
+  arrangeFreeFunctionType(CanQual<FunctionNoProtoType> fnpt);
+
+  cir::FuncType getFunctionType(const CIRGenFunctionInfo &fi);
 };
 
 } // namespace clang::CIRGen
diff --git a/clang/lib/CIR/CodeGen/TargetInfo.cpp 
b/clang/lib/CIR/CodeGen/TargetInfo.cpp
index 4a4edb4248447..551341ff20c00 100644
--- a/clang/lib/CIR/CodeGen/TargetInfo.cpp
+++ b/clang/lib/CIR/CodeGen/TargetInfo.cpp
@@ -1,16 +1,8 @@
 #include "TargetInfo.h"
 #include "ABIInfo.h"
-#include "CIRGenFunctionInfo.h"
-#include "clang/CIR/MissingFeatures.h"
 
 using namespace clang;
 using namespace clang::CIRGen;
-
-static bool testIfIsVoidTy(QualType ty) {
-  const auto *builtinTy = ty->getAs<BuiltinType>();
-  return builtinTy && builtinTy->getKind() == BuiltinType::Void;
-}
-
 namespace {
 
 class X8664ABIInfo : public ABIInfo {
diff --git a/clang/test/CIR/CodeGen/basic.c b/clang/test/CIR/CodeGen/basic.c
index 916246eb6e661..5f5c15a923313 100644
--- a/clang/test/CIR/CodeGen/basic.c
+++ b/clang/test/CIR/CodeGen/basic.c
@@ -233,6 +233,19 @@ int f8(int *p) {
 // OGCG:   %[[P2:.*]] = load ptr, ptr %[[P_PTR]], align 8
 // OGCG:   %[[STAR_P:.*]] = load i32, ptr %[[P2]], align 4
 
+
+void f9() {}
+
+//      CIR: cir.func @f9()
+// CIR-NEXT:   cir.return
+
+//      LLVM: define void @f9()
+// LLVM-NEXT:   ret void
+
+//      OGCG: define{{.*}} void @f9()
+// OGCG-NEXT: entry:
+// OGCG-NEXT:   ret void
+
 typedef unsigned long size_type;
 typedef unsigned long _Tp;
 

>From f17a38e6dc1096594b62ff2dfb0ac90bca22424d Mon Sep 17 00:00:00 2001
From: Iris Shi <0...@owo.li>
Date: Tue, 13 May 2025 15:29:27 +0800
Subject: [PATCH 2/2] Address review comments

---
 clang/lib/CIR/CodeGen/CIRGenModule.cpp |  3 ++-
 clang/test/CIR/CodeGen/basic.c         | 18 ++++++++++++++++++
 2 files changed, 20 insertions(+), 1 deletion(-)

diff --git a/clang/lib/CIR/CodeGen/CIRGenModule.cpp 
b/clang/lib/CIR/CodeGen/CIRGenModule.cpp
index 157ea1fd87287..b4e27bc5fec6a 100644
--- a/clang/lib/CIR/CodeGen/CIRGenModule.cpp
+++ b/clang/lib/CIR/CodeGen/CIRGenModule.cpp
@@ -261,8 +261,9 @@ void 
CIRGenModule::emitGlobalFunctionDefinition(clang::GlobalDecl gd,
     const CIRGenFunctionInfo &fi = getTypes().arrangeCIRFunctionInfo(
         noProto->getReturnType(), {}, RequiredArgs::All);
     funcType = getTypes().getFunctionType(fi);
-  } else
+  } else {
     funcType = cast<cir::FuncType>(convertType(funcDecl->getType()));
+  }
 
   cir::FuncOp funcOp = dyn_cast_if_present<cir::FuncOp>(op);
   if (!funcOp || funcOp.getFunctionType() != funcType) {
diff --git a/clang/test/CIR/CodeGen/basic.c b/clang/test/CIR/CodeGen/basic.c
index 5f5c15a923313..d0e241cdc5ae9 100644
--- a/clang/test/CIR/CodeGen/basic.c
+++ b/clang/test/CIR/CodeGen/basic.c
@@ -246,6 +246,24 @@ void f9() {}
 // OGCG-NEXT: entry:
 // OGCG-NEXT:   ret void
 
+void f10(int arg0, ...) {}
+
+//      CIR: cir.func @f10(%[[ARG0:.*]]: !s32i loc({{.*}}), ...)
+// CIR-NEXT:   %[[ARG0_PTR:.*]] = cir.alloca !s32i, !cir.ptr<!s32i>, ["arg0", 
init] {alignment = 4 : i64}
+// CIR-NEXT:   cir.store %[[ARG0]], %[[ARG0_PTR]] : !s32i, !cir.ptr<!s32i>
+// CIR-NEXT:   cir.return
+
+//      LLVM: define void @f10(i32 %[[ARG0:.*]], ...)
+// LLVM-NEXT:   %[[ARG0_PTR:.*]] = alloca i32, i64 1, align 4
+// LLVM-NEXT:   store i32 %[[ARG0]], ptr %[[ARG0_PTR]], align 4
+// LLVM-NEXT:   ret void
+
+//      OGCG: define{{.*}} void @f10(i32 noundef %[[ARG0:.*]], ...)
+// OGCG-NEXT: entry:
+// OGCG-NEXT:   %[[ARG0_PTR:.*]] = alloca i32, align 4
+// OGCG-NEXT:   store i32 %[[ARG0]], ptr %[[ARG0_PTR]], align 4
+// OGCG-NEXT:   ret void
+
 typedef unsigned long size_type;
 typedef unsigned long _Tp;
 

_______________________________________________
cfe-commits mailing list
cfe-commits@lists.llvm.org
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits

Reply via email to