https://github.com/whitequark created https://github.com/llvm/llvm-project/pull/92677
This patch is the first in a series that makes it possible to build LLVM, Clang, and LLD for WASI/WebAssembly. This patch does not introduce conditionals of the form `defined(__wasi__)` or `defined(__wasm__)`; instead it detects these APIs like any other platform features. While some features are never present in WASI and the feature check is functionally identical to a platform check, some may be conditionally present if emulation is turned on, e.g. `getpid`. The complete list of feature tests introduced is: * `HAVE_ALARM`: WebAssembly does not support delivery of asynchronous signals. * `HAVE_GETHOSTNAME`: WASI does not provide `gethostname`. * `HAVE_GETPID`: WASI does not have process IDs. However, it ships with a polyfill (`-D_WASI_EMULATED_GETPID`). The final behavior is the same either way. * `HAVE_FCHOWN`: WASI likely will never support UNIX ownership model. * `HAVE_PWD_H`: WASI likely will never support UNIX password databases. * `HAVE_RAISE`: WASI does not support delivey of asynchronous signals. However, it ships with a polyfill (`-D_WASI_EMULATED_SIGNAL`). This polyfill implements `raise` but not `sigaction` (only `signal`) and as a result it is not currently useful for LLVM. If `sigaction` is implemented in wasi-libc then `raise(SIGABRT);` would be able to invoke the handler. * `HAVE_SETJMP`: WebAssembly implements SjLj using exception handling. Exception handling has not been stabilized in Wasm yet. In addition, it significantly increases deployment complexity. Building with `-mllvm -wasm-enable-sjlj` enables the use of SjLj. * `HAVE_SOCKET`: WASIp1 does not provide the Berkeley socket API. WASIp2 does provide it. It will likely remain desirable to target WASIp1 for a long time. * `HAVE_SYS_WAIT_H`: WASI does not have subprocess management. * `HAVE_UMASK`: WASI likely will never support UNIX permission model, but `umask` might eventually be added in a polyfill. >From 289750cd78979e4811d6fd943c0a6c3b5bd3b5dd Mon Sep 17 00:00:00 2001 From: Catherine <whitequ...@whitequark.org> Date: Sun, 19 May 2024 04:41:27 +0000 Subject: [PATCH] Conditionalize use of POSIX features missing on WASI/WebAssembly. This patch is the first in a series that makes it possible to build LLVM, Clang, and LLD for WASI/WebAssembly. This patch does not introduce conditionals of the form `defined(__wasi__)` or `defined(__wasm__)`; instead it detects these APIs like any other platform features. While some features are never present in WASI and the feature check is functionally identical to a platform check, some may be conditionally present if emulation is turned on, e.g. `getpid`. The complete list of feature tests introduced is: * `HAVE_ALARM`: WebAssembly does not support delivery of asynchronous signals. * `HAVE_GETHOSTNAME`: WASI does not provide `gethostname`. * `HAVE_GETPID`: WASI does not have process IDs. However, it ships with a polyfill (`-D_WASI_EMULATED_GETPID`). The final behavior is the same either way. * `HAVE_FCHOWN`: WASI likely will never support UNIX ownership model. * `HAVE_PWD_H`: WASI likely will never support UNIX password databases. * `HAVE_RAISE`: WASI does not support delivey of asynchronous signals. However, it ships with a polyfill (`-D_WASI_EMULATED_SIGNAL`). This polyfill implements `raise` but not `sigaction` (only `signal`) and as a result it is not currently useful for LLVM. If `sigaction` is implemented in wasi-libc then `raise(SIGABRT);` would be able to invoke the handler. * `HAVE_SETJMP`: WebAssembly implements SjLj using exception handling. Exception handling has not been stabilized in Wasm yet. In addition, it significantly increases deployment complexity. Building with `-mllvm -wasm-enable-sjlj` enables the use of SjLj. * `HAVE_SOCKET`: WASIp1 does not provide the Berkeley socket API. WASIp2 does provide it. It will likely remain desirable to target WASIp1 for a long time. * `HAVE_SYS_WAIT_H`: WASI does not have subprocess management. * `HAVE_UMASK`: WASI likely will never support UNIX permission model, but `umask` might eventually be added in a polyfill. --- clang/lib/Driver/Driver.cpp | 6 ++-- llvm/cmake/config-ix.cmake | 15 +++++++++ llvm/include/llvm/Config/config.h.cmake | 33 +++++++++++++++++++ .../Interpreter/ExternalFunctions.cpp | 6 ++++ llvm/lib/Support/CrashRecoveryContext.cpp | 15 ++++++++- llvm/lib/Support/LockFileManager.cpp | 2 +- llvm/lib/Support/Unix/Path.inc | 30 +++++++++++++++++ llvm/lib/Support/Unix/Process.inc | 4 +++ llvm/lib/Support/Unix/Unix.h | 5 ++- llvm/lib/Support/Unix/Watchdog.inc | 4 +-- llvm/lib/Support/raw_socket_stream.cpp | 4 +++ 11 files changed, 116 insertions(+), 8 deletions(-) diff --git a/clang/lib/Driver/Driver.cpp b/clang/lib/Driver/Driver.cpp index 2868b4f2b02e9..f8b7c76e6439d 100644 --- a/clang/lib/Driver/Driver.cpp +++ b/clang/lib/Driver/Driver.cpp @@ -99,8 +99,8 @@ #include <optional> #include <set> #include <utility> -#if LLVM_ON_UNIX -#include <unistd.h> // getpid +#if HAVE_GETPID +#include <unistd.h> #endif using namespace clang::driver; @@ -1577,7 +1577,7 @@ bool Driver::getCrashDiagnosticFile(StringRef ReproCrashFilename, CrashDiagDir = "/"; path::append(CrashDiagDir, "Library/Logs/DiagnosticReports"); int PID = -#if LLVM_ON_UNIX +#if HAVE_GETPID getpid(); #else 0; diff --git a/llvm/cmake/config-ix.cmake b/llvm/cmake/config-ix.cmake index bf1b110245bb2..a1a76bb6241db 100644 --- a/llvm/cmake/config-ix.cmake +++ b/llvm/cmake/config-ix.cmake @@ -49,6 +49,7 @@ check_include_file(malloc/malloc.h HAVE_MALLOC_MALLOC_H) if( NOT PURE_WINDOWS ) check_include_file(pthread.h HAVE_PTHREAD_H) endif() +check_include_file(pwd.h HAVE_PWD_H) check_include_file(signal.h HAVE_SIGNAL_H) check_include_file(sys/ioctl.h HAVE_SYS_IOCTL_H) check_include_file(sys/mman.h HAVE_SYS_MMAN_H) @@ -57,6 +58,7 @@ check_include_file(sys/resource.h HAVE_SYS_RESOURCE_H) check_include_file(sys/stat.h HAVE_SYS_STAT_H) check_include_file(sys/time.h HAVE_SYS_TIME_H) check_include_file(sys/types.h HAVE_SYS_TYPES_H) +check_include_file(sys/wait.h HAVE_SYS_WAIT_H) check_include_file(sysexits.h HAVE_SYSEXITS_H) check_include_file(termios.h HAVE_TERMIOS_H) check_include_file(unistd.h HAVE_UNISTD_H) @@ -276,11 +278,15 @@ check_symbol_exists(__deregister_frame "${CMAKE_CURRENT_LIST_DIR}/unwind.h" HAVE check_symbol_exists(__unw_add_dynamic_fde "${CMAKE_CURRENT_LIST_DIR}/unwind.h" HAVE_UNW_ADD_DYNAMIC_FDE) check_symbol_exists(_Unwind_Backtrace "unwind.h" HAVE__UNWIND_BACKTRACE) +check_symbol_exists(alarm unistd.h HAVE_ALARM) +check_symbol_exists(gethostname unistd.h HAVE_GETHOSTNAME) check_symbol_exists(getpagesize unistd.h HAVE_GETPAGESIZE) +check_symbol_exists(getpid unistd.h HAVE_GETPID) check_symbol_exists(sysconf unistd.h HAVE_SYSCONF) check_symbol_exists(getrusage sys/resource.h HAVE_GETRUSAGE) check_symbol_exists(setrlimit sys/resource.h HAVE_SETRLIMIT) check_symbol_exists(isatty unistd.h HAVE_ISATTY) +check_symbol_exists(fchown unistd.h HAVE_FCHOWN) check_symbol_exists(futimens sys/stat.h HAVE_FUTIMENS) check_symbol_exists(futimes sys/time.h HAVE_FUTIMES) # AddressSanitizer conflicts with lib/Support/Unix/Signals.inc @@ -298,10 +304,14 @@ check_symbol_exists(malloc_zone_statistics malloc/malloc.h check_symbol_exists(getrlimit "sys/types.h;sys/time.h;sys/resource.h" HAVE_GETRLIMIT) check_symbol_exists(posix_spawn spawn.h HAVE_POSIX_SPAWN) check_symbol_exists(pread unistd.h HAVE_PREAD) +check_symbol_exists(raise signal.h HAVE_RAISE) check_symbol_exists(sbrk unistd.h HAVE_SBRK) +check_symbol_exists(setjmp setjmp.h HAVE_SETJMP) +check_symbol_exists(socket sys/socket.h HAVE_SOCKET) check_symbol_exists(strerror_r string.h HAVE_STRERROR_R) check_symbol_exists(strerror_s string.h HAVE_DECL_STRERROR_S) check_symbol_exists(setenv stdlib.h HAVE_SETENV) +check_symbol_exists(umask sys/stat.h HAVE_UMASK) if( PURE_WINDOWS ) check_symbol_exists(_chsize_s io.h HAVE__CHSIZE_S) @@ -327,6 +337,11 @@ if( PURE_WINDOWS ) check_function_exists(__cmpdi2 HAVE___CMPDI2) endif() +check_c_source_compiles(" + struct flock lk; + int main(void) { return 0; }" + HAVE_FLOCK) + CHECK_STRUCT_HAS_MEMBER("struct stat" st_mtimespec.tv_nsec "sys/types.h;sys/stat.h" HAVE_STRUCT_STAT_ST_MTIMESPEC_TV_NSEC) if (UNIX AND ${CMAKE_SYSTEM_NAME} MATCHES "AIX") diff --git a/llvm/include/llvm/Config/config.h.cmake b/llvm/include/llvm/Config/config.h.cmake index 977c182e9d2b0..8cbefffb2121d 100644 --- a/llvm/include/llvm/Config/config.h.cmake +++ b/llvm/include/llvm/Config/config.h.cmake @@ -23,6 +23,9 @@ backslashes. */ #cmakedefine01 LLVM_WINDOWS_PREFER_FORWARD_SLASH +/* Define to 1 if you have the `alarm' function. */ +#cmakedefine HAVE_ALARM ${HAVE_ALARM} + /* Define to 1 if you have the `backtrace' function. */ #cmakedefine HAVE_BACKTRACE ${HAVE_BACKTRACE} @@ -71,6 +74,12 @@ /* Define to 1 if you have the <errno.h> header file. */ #cmakedefine HAVE_ERRNO_H ${HAVE_ERRNO_H} +/* Define to 1 if you have the `flock' structure. */ +#cmakedefine HAVE_FLOCK ${HAVE_FLOCK} + +/* Define to 1 if you have the `fchown' function. */ +#cmakedefine HAVE_FCHOWN ${HAVE_FCHOWN} + /* Define to 1 if you have the <fcntl.h> header file. */ #cmakedefine HAVE_FCNTL_H ${HAVE_FCNTL_H} @@ -92,9 +101,15 @@ /* Define to 1 if you have the `futimes' function. */ #cmakedefine HAVE_FUTIMES ${HAVE_FUTIMES} +/* Define to 1 if you have the `gethostname' function. */ +#cmakedefine HAVE_GETHOSTNAME ${HAVE_GETHOSTNAME} + /* Define to 1 if you have the `getpagesize' function. */ #cmakedefine HAVE_GETPAGESIZE ${HAVE_GETPAGESIZE} +/* Define to 1 if you have the `getpid' function. */ +#cmakedefine HAVE_GETPID ${HAVE_GETPID} + /* Define to 1 if you have the `getrlimit' function. */ #cmakedefine HAVE_GETRLIMIT ${HAVE_GETRLIMIT} @@ -161,9 +176,21 @@ /* Have pthread_rwlock_init */ #cmakedefine HAVE_PTHREAD_RWLOCK_INIT ${HAVE_PTHREAD_RWLOCK_INIT} +/* Define to 1 if you have the <pwd.h> header file. */ +#cmakedefine HAVE_PWD_H ${HAVE_PWD_H} + +/* Define to 1 if you have the `raise' function. */ +#cmakedefine HAVE_RAISE ${HAVE_RAISE} + /* Define to 1 if you have the `sbrk' function. */ #cmakedefine HAVE_SBRK ${HAVE_SBRK} +/* Define to 1 if you have the `setjmp' function. */ +#cmakedefine HAVE_SETJMP ${HAVE_SETJMP} + +/* Define to 1 if you have the `socket' function. */ +#cmakedefine HAVE_SOCKET ${HAVE_SOCKET} + /* Define to 1 if you have the `setenv' function. */ #cmakedefine HAVE_SETENV ${HAVE_SETENV} @@ -209,12 +236,18 @@ /* Define to 1 if you have the <sys/types.h> header file. */ #cmakedefine HAVE_SYS_TYPES_H ${HAVE_SYS_TYPES_H} +/* Define to 1 if you have the <sys/wait.h> header file. */ +#cmakedefine HAVE_SYS_WAIT_H ${HAVE_SYS_WAIT_H} + /* Define if the setupterm() function is supported this platform. */ #cmakedefine LLVM_ENABLE_TERMINFO ${LLVM_ENABLE_TERMINFO} /* Define to 1 if you have the <termios.h> header file. */ #cmakedefine HAVE_TERMIOS_H ${HAVE_TERMIOS_H} +/* Define to 1 if you have the `umask' function. */ +#cmakedefine HAVE_UMASK ${HAVE_UMASK} + /* Define to 1 if you have the <unistd.h> header file. */ #cmakedefine HAVE_UNISTD_H ${HAVE_UNISTD_H} diff --git a/llvm/lib/ExecutionEngine/Interpreter/ExternalFunctions.cpp b/llvm/lib/ExecutionEngine/Interpreter/ExternalFunctions.cpp index 4f8f883a75f32..345a80e70f241 100644 --- a/llvm/lib/ExecutionEngine/Interpreter/ExternalFunctions.cpp +++ b/llvm/lib/ExecutionEngine/Interpreter/ExternalFunctions.cpp @@ -34,7 +34,9 @@ #include "llvm/Support/raw_ostream.h" #include <cassert> #include <cmath> +#if HAVE_RAISE #include <csignal> +#endif #include <cstdint> #include <cstdio> #include <cstring> @@ -340,7 +342,11 @@ static GenericValue lle_X_exit(FunctionType *FT, ArrayRef<GenericValue> Args) { static GenericValue lle_X_abort(FunctionType *FT, ArrayRef<GenericValue> Args) { //FIXME: should we report or raise here? //report_fatal_error("Interpreted program raised SIGABRT"); +#if HAVE_RAISE raise (SIGABRT); +#else + abort(); +#endif return GenericValue(); } diff --git a/llvm/lib/Support/CrashRecoveryContext.cpp b/llvm/lib/Support/CrashRecoveryContext.cpp index f53aea177d612..d25590d4ff3a6 100644 --- a/llvm/lib/Support/CrashRecoveryContext.cpp +++ b/llvm/lib/Support/CrashRecoveryContext.cpp @@ -13,8 +13,13 @@ #include "llvm/Support/Signals.h" #include "llvm/Support/thread.h" #include <cassert> +#if HAVE_RAISE +#include <csignal> +#endif #include <mutex> +#if HAVE_SETJMP #include <setjmp.h> +#endif using namespace llvm; @@ -31,7 +36,9 @@ struct CrashRecoveryContextImpl { const CrashRecoveryContextImpl *Next; CrashRecoveryContext *CRC; +#ifdef HAVE_SETJMP ::jmp_buf JumpBuffer; +#endif volatile unsigned Failed : 1; unsigned SwitchedThread : 1; unsigned ValidJumpBuffer : 1; @@ -72,9 +79,11 @@ struct CrashRecoveryContextImpl { CRC->RetCode = RetCode; +#if HAVE_SETJMP // Jump back to the RunSafely we were called under. if (ValidJumpBuffer) longjmp(JumpBuffer, 1); +#endif // Otherwise let the caller decide of the outcome of the crash. Currently // this occurs when using SEH on Windows with MSVC or clang-cl. @@ -417,10 +426,12 @@ bool CrashRecoveryContext::RunSafely(function_ref<void()> Fn) { CrashRecoveryContextImpl *CRCI = new CrashRecoveryContextImpl(this); Impl = CRCI; +#if HAVE_SETJMP CRCI->ValidJumpBuffer = true; if (setjmp(CRCI->JumpBuffer) != 0) { return false; } +#endif } Fn(); @@ -469,9 +480,11 @@ bool CrashRecoveryContext::throwIfCrash(int RetCode) { return false; #if defined(_WIN32) ::RaiseException(RetCode, 0, 0, NULL); -#else +#elif HAVE_RAISE llvm::sys::unregisterHandlers(); raise(RetCode - 128); +#else + abort(); #endif return true; } diff --git a/llvm/lib/Support/LockFileManager.cpp b/llvm/lib/Support/LockFileManager.cpp index 083f8d7b37be3..edfa8825b3337 100644 --- a/llvm/lib/Support/LockFileManager.cpp +++ b/llvm/lib/Support/LockFileManager.cpp @@ -94,7 +94,7 @@ static std::error_code getHostID(SmallVectorImpl<char> &HostID) { StringRef UUIDRef(UUIDStr); HostID.append(UUIDRef.begin(), UUIDRef.end()); -#elif LLVM_ON_UNIX +#elif HAVE_GETHOSTNAME char HostName[256]; HostName[255] = 0; HostName[0] = 0; diff --git a/llvm/lib/Support/Unix/Path.inc b/llvm/lib/Support/Unix/Path.inc index 6e679f74869f0..250e946781446 100644 --- a/llvm/lib/Support/Unix/Path.inc +++ b/llvm/lib/Support/Unix/Path.inc @@ -32,7 +32,9 @@ #endif #include <dirent.h> +#ifdef HAVE_PWD_H #include <pwd.h> +#endif #include <sys/file.h> #ifdef __APPLE__ @@ -673,6 +675,11 @@ static void expandTildeExpr(SmallVectorImpl<char> &Path) { return; } +#if !defined(HAVE_PWD_H) + // No access to password database, return back the original path. + (void)Remainder; + return; +#else // This is a string of the form ~username/, look up this user's entry in the // password database. std::unique_ptr<char[]> Buf; @@ -694,6 +701,7 @@ static void expandTildeExpr(SmallVectorImpl<char> &Path) { Path.clear(); Path.append(Entry->pw_dir, Entry->pw_dir + strlen(Entry->pw_dir)); llvm::sys::path::append(Path, Storage); +#endif } void expand_tilde(const Twine &path, SmallVectorImpl<char> &dest) { @@ -770,11 +778,15 @@ std::error_code status(int FD, file_status &Result) { } unsigned getUmask() { +#if HAVE_UMASK // Chose arbitary new mask and reset the umask to the old mask. // umask(2) never fails so ignore the return of the second call. unsigned Mask = ::umask(0); (void)::umask(Mask); return Mask; +#else + return 0022; +#endif } std::error_code setPermissions(const Twine &Path, perms Permissions) { @@ -1224,6 +1236,7 @@ Expected<size_t> readNativeFileSlice(file_t FD, MutableArrayRef<char> Buf, } std::error_code tryLockFile(int FD, std::chrono::milliseconds Timeout) { +#if HAVE_FLOCK auto Start = std::chrono::steady_clock::now(); auto End = Start + Timeout; do { @@ -1241,9 +1254,13 @@ std::error_code tryLockFile(int FD, std::chrono::milliseconds Timeout) { usleep(1000); } while (std::chrono::steady_clock::now() < End); return make_error_code(errc::no_lock_available); +#else + return std::error_code(ENOSYS, std::generic_category()); +#endif } std::error_code lockFile(int FD) { +#if HAVE_FLOCK struct flock Lock; memset(&Lock, 0, sizeof(Lock)); Lock.l_type = F_WRLCK; @@ -1253,9 +1270,13 @@ std::error_code lockFile(int FD) { if (::fcntl(FD, F_SETLKW, &Lock) != -1) return std::error_code(); return errnoAsErrorCode(); +#else + return std::error_code(ENOSYS, std::generic_category()); +#endif } std::error_code unlockFile(int FD) { +#if HAVE_FLOCK struct flock Lock; Lock.l_type = F_UNLCK; Lock.l_whence = SEEK_SET; @@ -1264,6 +1285,9 @@ std::error_code unlockFile(int FD) { if (::fcntl(FD, F_SETLK, &Lock) != -1) return std::error_code(); return errnoAsErrorCode(); +#else + return std::error_code(ENOSYS, std::generic_category()); +#endif } std::error_code closeFile(file_t &F) { @@ -1335,11 +1359,15 @@ std::error_code real_path(const Twine &path, SmallVectorImpl<char> &dest, } std::error_code changeFileOwnership(int FD, uint32_t Owner, uint32_t Group) { +#if HAVE_FCHOWN auto FChown = [&]() { return ::fchown(FD, Owner, Group); }; // Retry if fchown call fails due to interruption. if ((sys::RetryAfterSignal(-1, FChown)) < 0) return errnoAsErrorCode(); return std::error_code(); +#else + return std::error_code(ENOSYS, std::generic_category()); +#endif } } // end namespace fs @@ -1349,6 +1377,7 @@ namespace path { bool home_directory(SmallVectorImpl<char> &result) { std::unique_ptr<char[]> Buf; char *RequestedDir = getenv("HOME"); +#if HAVE_PWD_H if (!RequestedDir) { long BufSize = sysconf(_SC_GETPW_R_SIZE_MAX); if (BufSize <= 0) @@ -1360,6 +1389,7 @@ bool home_directory(SmallVectorImpl<char> &result) { if (pw && pw->pw_dir) RequestedDir = pw->pw_dir; } +#endif if (!RequestedDir) return false; diff --git a/llvm/lib/Support/Unix/Process.inc b/llvm/lib/Support/Unix/Process.inc index ae90924cae1b9..02f984820590a 100644 --- a/llvm/lib/Support/Unix/Process.inc +++ b/llvm/lib/Support/Unix/Process.inc @@ -72,7 +72,11 @@ getRUsageTimes() { Process::Pid Process::getProcessId() { static_assert(sizeof(Pid) >= sizeof(pid_t), "Process::Pid should be big enough to store pid_t"); +#if HAVE_GETPID return Pid(::getpid()); +#else + return Pid(0); +#endif } // On Cygwin, getpagesize() returns 64k(AllocationGranularity) and diff --git a/llvm/lib/Support/Unix/Unix.h b/llvm/lib/Support/Unix/Unix.h index 1599241a344af..b6988b34832b3 100644 --- a/llvm/lib/Support/Unix/Unix.h +++ b/llvm/lib/Support/Unix/Unix.h @@ -30,7 +30,10 @@ #include <cstring> #include <string> #include <sys/types.h> -#include <sys/wait.h> + +#ifdef HAVE_SYS_WAIT_H +# include <sys/wait.h> +#endif #ifdef HAVE_UNISTD_H #include <unistd.h> diff --git a/llvm/lib/Support/Unix/Watchdog.inc b/llvm/lib/Support/Unix/Watchdog.inc index b33e52d88500d..dd65028769d37 100644 --- a/llvm/lib/Support/Unix/Watchdog.inc +++ b/llvm/lib/Support/Unix/Watchdog.inc @@ -19,13 +19,13 @@ namespace llvm { namespace sys { Watchdog::Watchdog(unsigned int seconds) { -#ifdef HAVE_UNISTD_H +#ifdef HAVE_ALARM alarm(seconds); #endif } Watchdog::~Watchdog() { -#ifdef HAVE_UNISTD_H +#ifdef HAVE_ALARM alarm(0); #endif } diff --git a/llvm/lib/Support/raw_socket_stream.cpp b/llvm/lib/Support/raw_socket_stream.cpp index 14e2308df4d7e..ae3fba3593d8e 100644 --- a/llvm/lib/Support/raw_socket_stream.cpp +++ b/llvm/lib/Support/raw_socket_stream.cpp @@ -41,6 +41,8 @@ using namespace llvm; +#if defined(_WIN32) || HAVE_SOCKET + #ifdef _WIN32 WSABalancer::WSABalancer() { WSADATA WsaData; @@ -304,3 +306,5 @@ raw_socket_stream::createConnectedUnix(StringRef SocketPath) { } raw_socket_stream::~raw_socket_stream() {} + +#endif _______________________________________________ cfe-commits mailing list cfe-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits