From f6d4b19ab126c85ba41476495971e7bda95d6e2a Mon Sep 17 00:00:00 2001 From: firewave Date: Sat, 14 Mar 2026 22:17:25 +0100 Subject: [PATCH 01/11] clang-tidy.yml: updated to Clang 23 --- .github/workflows/clang-tidy.yml | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/.github/workflows/clang-tidy.yml b/.github/workflows/clang-tidy.yml index 333672d7..932a0d72 100644 --- a/.github/workflows/clang-tidy.yml +++ b/.github/workflows/clang-tidy.yml @@ -33,19 +33,19 @@ jobs: run: | wget https://apt.llvm.org/llvm.sh chmod +x llvm.sh - sudo ./llvm.sh 22 - sudo apt-get install clang-tidy-22 + sudo ./llvm.sh 23 + sudo apt-get install clang-tidy-23 - name: Verify clang-tidy configuration run: | - clang-tidy-22 --verify-config + clang-tidy-23 --verify-config - name: Prepare CMake run: | cmake -S . -B cmake.output -Werror=dev --warn-uninitialized -DCMAKE_CXX_STANDARD=23 -DCMAKE_COMPILE_WARNING_AS_ERROR=On -DCMAKE_EXPORT_COMPILE_COMMANDS=ON env: - CXX: clang-22 + CXX: clang-23 - name: Clang-Tidy run: | - run-clang-tidy-22 -q -j $(nproc) -enable-check-profile -p=cmake.output + run-clang-tidy-23 -q -j $(nproc) -enable-check-profile -p=cmake.output From fcd3aabda1fddd33c286f95f9d5d1feba6cb9dfe Mon Sep 17 00:00:00 2001 From: firewave Date: Sat, 14 Mar 2026 22:21:41 +0100 Subject: [PATCH 02/11] fixed `misc-const-correctness` clang-tidy warnings s fixed `misc-const-correctness` clang-tidy warnings --- main.cpp | 2 +- simplecpp.cpp | 14 +++++++------- test.cpp | 20 ++++++++++---------- 3 files changed, 18 insertions(+), 18 deletions(-) diff --git a/main.cpp b/main.cpp index 5c48f830..5456a6ab 100644 --- a/main.cpp +++ b/main.cpp @@ -24,7 +24,7 @@ static bool isDir(const std::string& path) return (file_stat.st_mode & S_IFMT) == S_IFDIR; } -int main(int argc, char **argv) +int main(int argc, char *argv[]) { bool error = false; const char *filename = nullptr; diff --git a/simplecpp.cpp b/simplecpp.cpp index a7ced05a..a61760a3 100644 --- a/simplecpp.cpp +++ b/simplecpp.cpp @@ -150,12 +150,12 @@ static bool endsWith(const std::string &s, const std::string &e) return (s.size() >= e.size()) && std::equal(e.rbegin(), e.rend(), s.rbegin()); } -static bool sameline(const simplecpp::Token *tok1, const simplecpp::Token *tok2) +static bool sameline(const simplecpp::Token * const tok1, const simplecpp::Token * const tok2) { return tok1 && tok2 && tok1->location.sameline(tok2->location); } -static bool isAlternativeBinaryOp(const simplecpp::Token *tok, const std::string &alt) +static bool isAlternativeBinaryOp(const simplecpp::Token * const tok, const std::string &alt) { return (tok->name && tok->str() == alt && @@ -165,7 +165,7 @@ static bool isAlternativeBinaryOp(const simplecpp::Token *tok, const std::string (tok->next->number || tok->next->name || tok->next->op == '(')); } -static bool isAlternativeUnaryOp(const simplecpp::Token *tok, const std::string &alt) +static bool isAlternativeUnaryOp(const simplecpp::Token * const tok, const std::string &alt) { return ((tok->name && tok->str() == alt) && (!tok->previous || tok->previous->op == '(') && @@ -998,7 +998,7 @@ void simplecpp::TokenList::constFold() } } -static bool isFloatSuffix(const simplecpp::Token *tok) +static bool isFloatSuffix(const simplecpp::Token * const tok) { if (!tok || tok->str().size() != 1U) return false; @@ -1009,7 +1009,7 @@ static bool isFloatSuffix(const simplecpp::Token *tok) static const std::string AND("and"); static const std::string BITAND("bitand"); static const std::string BITOR("bitor"); -static bool isAlternativeAndBitandBitor(const simplecpp::Token* tok) +static bool isAlternativeAndBitandBitor(const simplecpp::Token * const tok) { return isAlternativeBinaryOp(tok, AND) || isAlternativeBinaryOp(tok, BITAND) || isAlternativeBinaryOp(tok, BITOR); } @@ -3310,14 +3310,14 @@ static void getLocaltime(struct tm <ime) #endif } -static std::string getDateDefine(const struct tm *timep) +static std::string getDateDefine(const struct tm * const timep) { char buf[] = "??? ?? ????"; strftime(buf, sizeof(buf), "%b %d %Y", timep); return std::string("\"").append(buf).append("\""); } -static std::string getTimeDefine(const struct tm *timep) +static std::string getTimeDefine(const struct tm * const timep) { char buf[] = "??:??:??"; strftime(buf, sizeof(buf), "%H:%M:%S", timep); diff --git a/test.cpp b/test.cpp index bc8cb4d5..15d099ef 100644 --- a/test.cpp +++ b/test.cpp @@ -66,7 +66,7 @@ static void assertThrowFailed(int line) std::cerr << "exception not thrown" << std::endl; } -static void testcase(const std::string &name, void (*f)(), int argc, char * const *argv) +static void testcase(const std::string &name, void (*const f)(), int argc, char *argv[]) { if (argc == 1) { f(); @@ -81,30 +81,30 @@ static void testcase(const std::string &name, void (*f)(), int argc, char * cons #define TEST_CASE(F) (testcase(#F, F, argc, argv)) -static simplecpp::TokenList makeTokenList(const char code[], std::size_t size, std::vector &filenames, const std::string &filename=std::string(), simplecpp::OutputList *outputList=nullptr) +static simplecpp::TokenList makeTokenList(const char code[], std::size_t size, std::vector &filenames, const std::string &filename=std::string(), simplecpp::OutputList * const outputList=nullptr) { std::istringstream istr(std::string(code, size)); return {istr,filenames,filename,outputList}; } -static simplecpp::TokenList makeTokenList(const char code[], std::vector &filenames, const std::string &filename=std::string(), simplecpp::OutputList *outputList=nullptr) +static simplecpp::TokenList makeTokenList(const char code[], std::vector &filenames, const std::string &filename=std::string(), simplecpp::OutputList * const outputList=nullptr) { return makeTokenList(code, strlen(code), filenames, filename, outputList); } -static std::string readfile(const char code[], simplecpp::OutputList *outputList=nullptr) +static std::string readfile(const char code[], simplecpp::OutputList * const outputList=nullptr) { std::vector files; return makeTokenList(code,files,std::string(),outputList).stringify(); } -static std::string readfile(const char code[], std::size_t size, simplecpp::OutputList *outputList=nullptr) +static std::string readfile(const char code[], std::size_t size, simplecpp::OutputList * const outputList=nullptr) { std::vector files; return makeTokenList(code,size,files,std::string(),outputList).stringify(); } -static std::string preprocess(const char code[], const simplecpp::DUI &dui, simplecpp::OutputList *outputList, std::list *macroUsage = nullptr, std::list *ifCond = nullptr, const std::string &file = std::string()) +static std::string preprocess(const char code[], const simplecpp::DUI &dui, simplecpp::OutputList * const outputList, std::list * const macroUsage = nullptr, std::list * const ifCond = nullptr, const std::string &file = std::string()) { std::vector files; simplecpp::FileDataCache cache; @@ -132,17 +132,17 @@ static std::string preprocess(const char code[], const simplecpp::DUI &dui) return preprocess(code, dui, nullptr); } -static std::string preprocess(const char code[], simplecpp::OutputList *outputList) +static std::string preprocess(const char code[], simplecpp::OutputList * const outputList) { return preprocess(code, simplecpp::DUI(), outputList); } -static std::string preprocess(const char code[], std::list *ifCond) +static std::string preprocess(const char code[], std::list * const ifCond) { return preprocess(code, simplecpp::DUI(), nullptr, nullptr, ifCond); } -static std::string preprocess(const char code[], std::list *macroUsage) +static std::string preprocess(const char code[], std::list * const macroUsage) { return preprocess(code, simplecpp::DUI(), nullptr, macroUsage); } @@ -3619,7 +3619,7 @@ static void leak() } } -int main(int argc, char **argv) +int main(int argc, char *argv[]) { TEST_CASE(backslash); From a67a7e3e14f5b2b224a05b982fbbbb9bdc0604bf Mon Sep 17 00:00:00 2001 From: firewave Date: Sat, 14 Mar 2026 22:22:10 +0100 Subject: [PATCH 03/11] .clang-tidy: disabled `readability-trailing-comma` clang-tidy check --- .clang-tidy | 1 + 1 file changed, 1 insertion(+) diff --git a/.clang-tidy b/.clang-tidy index e0b384bf..3cbfd6df 100644 --- a/.clang-tidy +++ b/.clang-tidy @@ -42,6 +42,7 @@ Checks: > -readability-isolate-declaration, -readability-magic-numbers, -readability-redundant-inline-specifier, + -readability-trailing-comma, -readability-use-concise-preprocessor-directives, -readability-uppercase-literal-suffix, -performance-avoid-endl, From ac4b16bfcacc38888f4c07451991ab28e18c6892 Mon Sep 17 00:00:00 2001 From: firewave Date: Sat, 14 Mar 2026 22:28:30 +0100 Subject: [PATCH 04/11] fixed `-Wlifetime-safety-intra-tu-suggestions` Clang warnings --- CMakeLists.txt | 8 ++++++++ simplecpp.cpp | 16 +++++++++++++--- simplecpp.h | 28 ++++++++++++++++++++-------- 3 files changed, 41 insertions(+), 11 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index 0a90efae..59944b4b 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -73,6 +73,13 @@ elseif (CMAKE_CXX_COMPILER_ID MATCHES "Clang") add_compile_options_safe(-Wno-thread-safety-negative) add_compile_options_safe(-Wno-thread-safety-beta) + # TODO: check for proper AppleClang version + # we do not add the annotation until C++20 + # the warning was introduced with Clang 23 + if(CMAKE_CXX_STANDARD LESS 20) + add_compile_options_safe(-Wno-lifetime-safety-intra-tu-suggestions) + endif() + # TODO: fix these? add_compile_options(-Wno-padded) add_compile_options(-Wno-sign-conversion) @@ -83,6 +90,7 @@ elseif (CMAKE_CXX_COMPILER_ID MATCHES "Clang") # we are not interested in these set_source_files_properties(test.cpp PROPERTIES COMPILE_FLAGS "-Wno-multichar -Wno-four-char-constants") + # TODO: check for proper AppleClang version if (CMAKE_CXX_COMPILER_VERSION VERSION_EQUAL 14 OR CMAKE_CXX_COMPILER_VERSION VERSION_GREATER 14) # TODO: verify this regression still exists in clang-15 if (CMAKE_BUILD_TYPE STREQUAL "Release" OR CMAKE_BUILD_TYPE STREQUAL "RelWithDebInfo") diff --git a/simplecpp.cpp b/simplecpp.cpp index a61760a3..f09a899a 100644 --- a/simplecpp.cpp +++ b/simplecpp.cpp @@ -57,6 +57,16 @@ # include #endif +#if defined(__has_cpp_attribute) +# if __has_cpp_attribute (clang::lifetimebound) +# define SIMPLECPP_LIFETIMEBOUND [[clang::lifetimebound]] +# else +# define SIMPLECPP_LIFETIMEBOUND +# endif +#else +# define SIMPLECPP_LIFETIMEBOUND +#endif + static bool isHex(const std::string &s) { return s.size()>2 && (s.compare(0,2,"0x")==0 || s.compare(0,2,"0X")==0); @@ -1679,7 +1689,7 @@ namespace simplecpp { } /** how has this macro been used so far */ - const std::list &usage() const { + const std::list &usage() const SIMPLECPP_LIFETIMEBOUND { return usageList; } @@ -1869,7 +1879,7 @@ namespace simplecpp { const Token *appendTokens(TokenList &tokens, const Location &rawloc, - const Token * const lpar, + const Token * const lpar SIMPLECPP_LIFETIMEBOUND, const MacroMap ¯os, const std::set &expandedmacros, const std::vector ¶metertokens) const { @@ -2999,7 +3009,7 @@ static long long evaluate(simplecpp::TokenList &expr, const simplecpp::DUI &dui, return expr.cfront() && expr.cfront() == expr.cback() && expr.cfront()->number ? stringToLL(expr.cfront()->str()) : 0LL; } -static const simplecpp::Token *gotoNextLine(const simplecpp::Token *tok) +static const simplecpp::Token *gotoNextLine(const simplecpp::Token *tok SIMPLECPP_LIFETIMEBOUND) { const unsigned int line = tok->location.line; const unsigned int file = tok->location.fileIndex; diff --git a/simplecpp.h b/simplecpp.h index f29166ff..65335607 100644 --- a/simplecpp.h +++ b/simplecpp.h @@ -45,6 +45,16 @@ # include #endif +#if defined(__has_cpp_attribute) +# if __has_cpp_attribute (clang::lifetimebound) +# define SIMPLECPP_LIFETIMEBOUND [[clang::lifetimebound]] +# else +# define SIMPLECPP_LIFETIMEBOUND +# endif +#else +# define SIMPLECPP_LIFETIMEBOUND +#endif + #if defined(_MSC_VER) # pragma warning(push) // suppress warnings about "conversion from 'type1' to 'type2', possible loss of data" @@ -163,7 +173,7 @@ namespace simplecpp { Token &operator=(const Token &tok) = delete; - const TokenString& str() const { + const TokenString& str() const SIMPLECPP_LIFETIMEBOUND { return string; } void setstr(const std::string &s) { @@ -483,25 +493,25 @@ namespace simplecpp { using const_iterator = container_type::const_iterator; using size_type = container_type::size_type; - size_type size() const { + size_type size() const SIMPLECPP_LIFETIMEBOUND { return mData.size(); } - iterator begin() { + iterator begin() SIMPLECPP_LIFETIMEBOUND { return mData.begin(); } - iterator end() { + iterator end() SIMPLECPP_LIFETIMEBOUND { return mData.end(); } - const_iterator begin() const { + const_iterator begin() const SIMPLECPP_LIFETIMEBOUND { return mData.begin(); } - const_iterator end() const { + const_iterator end() const SIMPLECPP_LIFETIMEBOUND { return mData.end(); } - const_iterator cbegin() const { + const_iterator cbegin() const SIMPLECPP_LIFETIMEBOUND { return mData.cbegin(); } - const_iterator cend() const { + const_iterator cend() const SIMPLECPP_LIFETIMEBOUND { return mData.cend(); } @@ -634,6 +644,8 @@ namespace simplecpp { # pragma warning(pop) #endif +#undef SIMPLECPP_LIFETIMEBOUND + #undef SIMPLECPP_LIB #endif From 26c64d33acc07467da0cdd0f8353c0bfaa9e57a7 Mon Sep 17 00:00:00 2001 From: firewave Date: Sat, 14 Mar 2026 22:39:36 +0100 Subject: [PATCH 05/11] remove --- .github/workflows/CI-mingw.yml | 141 ---------------------- .github/workflows/CI-unixish.yml | 194 ------------------------------- .github/workflows/CI-windows.yml | 82 ------------- .github/workflows/format.yml | 62 ---------- 4 files changed, 479 deletions(-) delete mode 100644 .github/workflows/CI-mingw.yml delete mode 100644 .github/workflows/CI-unixish.yml delete mode 100644 .github/workflows/CI-windows.yml delete mode 100644 .github/workflows/format.yml diff --git a/.github/workflows/CI-mingw.yml b/.github/workflows/CI-mingw.yml deleted file mode 100644 index 390de83d..00000000 --- a/.github/workflows/CI-mingw.yml +++ /dev/null @@ -1,141 +0,0 @@ -name: CI-mingw - -on: [push, pull_request] - -permissions: - contents: read - -defaults: - run: - shell: msys2 {0} - -jobs: - build: - - strategy: - matrix: - compiler: [g++, clang++] - # TODO: add MSYS after #556 is fixed - msystem: [MINGW32, MINGW64, CLANG64] - include: - #- msystem: MSYS - # pkg-prefix: '' - - msystem: MINGW32 - pkg-prefix: 'mingw-w64-i686-' - - msystem: MINGW64 - pkg-prefix: 'mingw-w64-x86_64-' - - msystem: CLANG64 - pkg-prefix: 'mingw-w64-clang-x86_64-' - - compiler: g++ - compiler-pkg: gcc - - compiler: clang++ - compiler-pkg: clang - exclude: - - msystem: CLANG64 - compiler: g++ - # the mingw-w64-i686-clang package is no longer available - - msystem: MINGW32 - compiler: clang++ - fail-fast: false - - runs-on: windows-2025 - - env: - CXX: ${{ matrix.compiler }} - - steps: - - uses: actions/checkout@v4 - with: - persist-credentials: false - - - name: Set up MSYS2 - uses: msys2/setup-msys2@v2 - with: - release: false # use pre-installed - msystem: ${{ matrix.msystem }} - # TODO: install mingw-w64-x86_64-make and use mingw32.make instead - currently fails with "Windows Subsystem for Linux has no installed distributions." - # TODO: also run tests with non-prefixed Python? - install: >- - make - ${{ matrix.pkg-prefix }}cmake - ${{ matrix.pkg-prefix }}python - ${{ matrix.pkg-prefix }}python-pytest - - - name: install compiler - run: | - pacman -S --noconfirm ${{ matrix.pkg-prefix }}${{ matrix.compiler-pkg }} - ${CXX} -v - - - name: make simplecpp - run: | - make -j$(nproc) CXXOPTS="-Werror" - - # gcc *and* clang are required to run-tests.py - # install it at this point since it has gcc as dependency which might interfere with the build - - name: install compiler (clang) - if: matrix.compiler == 'g++' - run: | - pacman -S --noconfirm clang - - - name: install compiler (gcc) - if: matrix.compiler == 'clang++' - run: | - pacman -S --noconfirm gcc - - - name: make test - run: | - # TODO: run tests with Windows paths - make -j$(nproc) test - - - name: selfcheck - run: | - # TODO: run tests with Windows paths - make -j$(nproc) selfcheck - - - name: make (c++14) - run: | - make clean - make -j$(nproc) CXXOPTS="-Werror -std=c++14" - - - name: make (c++17) - run: | - make clean - make -j$(nproc) CXXOPTS="-Werror -std=c++17" - - - name: make (c++20) - run: | - make clean - make -j$(nproc) CXXOPTS="-Werror -std=c++20" - - - name: make (c++23) - run: | - make clean - make -j$(nproc) CXXOPTS="-Werror -std=c++23" - - - name: Run CMake - run: | - cmake -S . -B cmake.output -DCMAKE_COMPILE_WARNING_AS_ERROR=On - - - name: CMake simplecpp - run: | - cmake --build cmake.output --target simplecpp -- -j $(nproc) - - - name: CMake testrunner - run: | - cmake --build cmake.output --target testrunner -- -j $(nproc) - - - name: Run testrunner - run: | - ./cmake.output/testrunner - - - name: Run with libstdc++ debug mode - if: matrix.compiler == 'g++' - run: | - make clean - make -j$(nproc) test selfcheck CXXOPTS="-Werror -g3 -D_GLIBCXX_DEBUG" - - - name: Run with libc++ hardening mode - if: matrix.compiler == 'clang++' && matrix.msystem == 'CLANG64' - run: | - make clean - make -j$(nproc) test selfcheck CXXOPTS="-Werror -stdlib=libc++ -g3 -D_LIBCPP_HARDENING_MODE=_LIBCPP_HARDENING_MODE_DEBUG" LDOPTS="-lc++" diff --git a/.github/workflows/CI-unixish.yml b/.github/workflows/CI-unixish.yml deleted file mode 100644 index 1a4ce649..00000000 --- a/.github/workflows/CI-unixish.yml +++ /dev/null @@ -1,194 +0,0 @@ -name: CI-unixish - -on: [push, pull_request] - -permissions: - contents: read - -jobs: - build: - - strategy: - matrix: - os: [ubuntu-22.04, ubuntu-22.04-arm, ubuntu-24.04, ubuntu-24.04-arm, macos-14, macos-15, macos-15-intel, macos-26, macos-26-intel] - compiler: [clang++] - include: - - os: ubuntu-22.04 - compiler: g++ - - os: ubuntu-24.04 - compiler: g++ - fail-fast: false - - runs-on: ${{ matrix.os }} - - env: - CXX: ${{ matrix.compiler }} - - steps: - - uses: actions/checkout@v6 - with: - persist-credentials: false - - # the man-db trigger causes package installations to stall for several minutes at times. so just drop the package. - # see https://github.com/actions/runner/issues/4030 - - name: Remove man-db package on ubuntu - if: matrix.os == 'ubuntu-24.04' - run: | - sudo apt-get update - sudo apt-get remove man-db - - - name: Install missing software on ubuntu - if: matrix.os == 'ubuntu-24.04' - run: | - sudo apt-get update - sudo apt-get install valgrind - - # llvm contains llvm-profdata - - name: Install missing software on ubuntu (clang++) - if: contains(matrix.os, 'ubuntu') && matrix.compiler == 'clang++' - run: | - sudo apt-get update - sudo apt-get install libc++-dev llvm - - # coreutils contains "nproc" - - name: Install missing software on macos - if: contains(matrix.os, 'macos') - run: | - brew install coreutils - - - name: Install missing Python packages - run: | - python3 -m pip config set global.break-system-packages true - python3 -m pip install pytest - - - name: make simplecpp - run: make -j$(nproc) CXXOPTS="-Werror" - - - name: make test - run: make -j$(nproc) test CXXOPTS="-Werror" - - - name: selfcheck - run: | - make -j$(nproc) selfcheck - - - name: make (c++14) - run: | - make clean - make -j$(nproc) CXXOPTS="-Werror -std=c++14" - - - name: make (c++17) - run: | - make clean - make -j$(nproc) CXXOPTS="-Werror -std=c++17" - - - name: make (c++20) - run: | - make clean - make -j$(nproc) CXXOPTS="-Werror -std=c++20" - - - name: make (c++23) - run: | - make clean - # ubuntu-22.04 and macos-14 do not support c++23 yet - make -j$(nproc) CXXOPTS="-Werror -std=c++2b" - - - name: Run CMake - run: | - cmake -S . -B cmake.output -Werror=dev --warn-uninitialized -DCMAKE_COMPILE_WARNING_AS_ERROR=On - - - name: CMake simplecpp - run: | - cmake --build cmake.output --target simplecpp -- -j $(nproc) - - - name: CMake testrunner - run: | - cmake --build cmake.output --target testrunner -- -j $(nproc) - ./cmake.output/testrunner - # Re-run tests from within the build directory to validate that - # SIMPLECPP_TEST_SOURCE_DIR is correctly defined and resolved - (cd cmake.output && ./testrunner) - - - name: Run valgrind - if: matrix.os == 'ubuntu-24.04' - run: | - make clean - make -j$(nproc) CXXOPTS="-O1" - valgrind --leak-check=full --num-callers=50 --show-reachable=yes --track-origins=yes --gen-suppressions=all --error-exitcode=42 ./testrunner - # TODO: run Python tests with valgrind - VALGRIND_TOOL=memcheck ./selfcheck.sh - - - name: Run with libstdc++ debug mode - if: matrix.os == 'ubuntu-24.04' && matrix.compiler == 'g++' - run: | - make clean - make -j$(nproc) test selfcheck CXXOPTS="-Werror -g3 -D_GLIBCXX_DEBUG" - - - name: Run with libc++ hardening mode - if: matrix.os == 'ubuntu-24.04' && matrix.compiler == 'clang++' - run: | - make clean - make -j$(nproc) test selfcheck CXXOPTS="-Werror -stdlib=libc++ -g3 -D_LIBCPP_HARDENING_MODE=_LIBCPP_HARDENING_MODE_DEBUG" LDOPTS="-lc++" - - - name: Run AddressSanitizer - if: matrix.os == 'ubuntu-24.04' || matrix.os == 'macos-26' - run: | - make clean - make -j$(nproc) test selfcheck CXXOPTS="-Werror -O2 -g3 -fsanitize=address" LDOPTS="-fsanitize=address" - env: - ASAN_OPTIONS: detect_stack_use_after_return=1 - - - name: Run UndefinedBehaviorSanitizer - if: matrix.os == 'ubuntu-24.04' || matrix.os == 'macos-26' - run: | - make clean - make -j$(nproc) test selfcheck CXXOPTS="-Werror -O2 -g3 -fsanitize=undefined -fno-sanitize=signed-integer-overflow" LDOPTS="-fsanitize=undefined -fno-sanitize=signed-integer-overflow" - env: - UBSAN_OPTIONS: print_stacktrace=1:halt_on_error=1:report_error_type=1 - - # TODO: requires instrumented libc++ - - name: Run MemorySanitizer - if: false && matrix.os == 'ubuntu-24.04' && matrix.compiler == 'clang++' - run: | - make clean - make -j$(nproc) test selfcheck CXXOPTS="-Werror -O2 -g3 -stdlib=libc++ -fsanitize=memory" LDOPTS="-lc++ -fsanitize=memory" - - - name: Run callgrind - if: matrix.os == 'ubuntu-24.04' - run: | - wget https://github.com/danmar/simplecpp/archive/refs/tags/1.5.1.tar.gz - tar xvf 1.5.1.tar.gz - rm -f 1.5.1.tar.gz - - make clean - make -j$(nproc) CXXOPTS="-O2 -g3" simplecpp - VALGRIND_TOOL=callgrind SIMPLECPP_PATH=simplecpp-1.5.1 ./selfcheck.sh >callgrind.log || (cat callgrind.log && false) - cat callgrind.log - - # PGO - start - make clean - make -j$(nproc) CXXOPTS="-O2 -g3 -fprofile-generate" LDOPTS="-fprofile-generate" simplecpp - SIMPLECPP_PATH=simplecpp-1.5.1 ./selfcheck.sh >/dev/null - - if compgen -G "default_*.profraw" > /dev/null; then - llvm-profdata merge -output=default.profdata default_*.profraw - fi - - make clean - make -j$(nproc) CXXOPTS="-O2 -g3 -fprofile-use" LDOPTS="-fprofile-use" simplecpp - VALGRIND_TOOL=callgrind SIMPLECPP_PATH=simplecpp-1.5.1 ./selfcheck.sh >callgrind_pgo.log || (cat callgrind_pgo.log && false) - cat callgrind_pgo.log - # PGO - end - - for f in callgrind.out.*; - do - callgrind_annotate --auto=no $f > $f.annotated.log - head -50 $f.annotated.log - done - rm -rf simplecpp-1.5.1 - - - uses: actions/upload-artifact@v4 - if: matrix.os == 'ubuntu-24.04' - with: - name: Callgrind Output - ${{ matrix.compiler }} - path: | - ./callgrind.* diff --git a/.github/workflows/CI-windows.yml b/.github/workflows/CI-windows.yml deleted file mode 100644 index cfced0d2..00000000 --- a/.github/workflows/CI-windows.yml +++ /dev/null @@ -1,82 +0,0 @@ -# Some convenient links: -# - https://github.com/actions/virtual-environments/blob/master/images/win/Windows2019-Readme.md -# - -name: CI-windows - -on: [push,pull_request] - -permissions: - contents: read - -defaults: - run: - shell: cmd - -jobs: - - build: - strategy: - matrix: - os: [windows-2022, windows-2025, windows-11-arm] - config: [Release, Debug] - fail-fast: false - - runs-on: ${{ matrix.os }} - - steps: - - uses: actions/checkout@v6 - with: - persist-credentials: false - - - name: Setup msbuild.exe - uses: microsoft/setup-msbuild@v2 - - - name: Set up Python - uses: actions/setup-python@v6 - with: - python-version: '3.14' - check-latest: true - - - name: Install missing Python packages - run: | - python -m pip install pip --upgrade || exit /b !errorlevel! - python -m pip install pytest || exit /b !errorlevel! - - - name: Run CMake - run: | - cmake -G "Visual Studio 17 2022" -A x64 -Werror=dev --warn-uninitialized -DCMAKE_COMPILE_WARNING_AS_ERROR=On . || exit /b !errorlevel! - - - name: Build - run: | - msbuild -m simplecpp.sln /p:Configuration=${{ matrix.config }} /p:Platform=x64 || exit /b !errorlevel! - - - name: Test - run: | - .\${{ matrix.config }}\testrunner.exe || exit /b !errorlevel! - - - name: Selfcheck - run: | - .\${{ matrix.config }}\simplecpp.exe simplecpp.cpp -e || exit /b !errorlevel! - - - name: integration test - run: | - set SIMPLECPP_EXE_PATH=.\${{ matrix.config }}\simplecpp.exe - python -m pytest integration_test.py -vv || exit /b !errorlevel! - - - name: Run CMake (c++17) - run: | - cmake -S . -B build.cxx17 -G "Visual Studio 17 2022" -A x64 -Werror=dev --warn-uninitialized -DCMAKE_CXX_STANDARD=17 -DCMAKE_COMPILE_WARNING_AS_ERROR=On || exit /b !errorlevel! - - - name: Build (c++17) - run: | - msbuild -m build.cxx17\simplecpp.sln /p:Configuration=${{ matrix.config }} /p:Platform=x64 || exit /b !errorlevel! - - - name: Run CMake (c++20) - run: | - cmake -S . -B build.cxx20 -G "Visual Studio 17 2022" -A x64 -Werror=dev --warn-uninitialized -DCMAKE_CXX_STANDARD=20 -DCMAKE_COMPILE_WARNING_AS_ERROR=On || exit /b !errorlevel! - - - name: Build (c++20) - run: | - msbuild -m build.cxx20\simplecpp.sln /p:Configuration=${{ matrix.config }} /p:Platform=x64 || exit /b !errorlevel! - diff --git a/.github/workflows/format.yml b/.github/workflows/format.yml deleted file mode 100644 index e9f1361d..00000000 --- a/.github/workflows/format.yml +++ /dev/null @@ -1,62 +0,0 @@ -# Syntax reference https://help.github.com/en/actions/reference/workflow-syntax-for-github-actions -# Environment reference https://help.github.com/en/actions/reference/virtual-environments-for-github-hosted-runners -name: format - -on: - push: - branches: - - 'master' - - 'releases/**' - - '1.*' - tags: - - '1.*' - pull_request: - -permissions: - contents: read - -jobs: - format: - - runs-on: ubuntu-22.04 - - defaults: - run: - shell: bash -euo pipefail {0} - - env: - UNCRUSTIFY_INSTALL_DIR: ${{ github.workspace }}/runformat-uncrustify - - steps: - - uses: actions/checkout@v6 - with: - persist-credentials: false - - - name: Determine uncrustify version - id: get-uncrustify-version - run: | - version="$(./runformat --expected-uncrustify-version)" - echo "Expected uncrustify version: $version" - echo "version=$version" >> "$GITHUB_OUTPUT" - - - name: Set UNCRUSTIFY_VERSION env variable - run: | - version=$(./runformat --expected-uncrustify-version) - echo "version [$version]" - echo "UNCRUSTIFY_VERSION=${version}" >> "$GITHUB_ENV" - - - name: Cache uncrustify - uses: actions/cache@v4 - id: cache-uncrustify - with: - path: ${{ env.UNCRUSTIFY_INSTALL_DIR }} - key: ${{ runner.os }}-uncrustify-${{ steps.get-uncrustify-version.outputs.version }} - - - name: Install uncrustify - if: steps.cache-uncrustify.outputs.cache-hit != 'true' - run: | - ./runformat --install --install-dir "${UNCRUSTIFY_INSTALL_DIR}" - - - name: Uncrustify check - run: | - ./runformat From 6d91da30b44b9cc045337c2e48758c8efda11157 Mon Sep 17 00:00:00 2001 From: firewave Date: Fri, 20 Mar 2026 14:26:49 +0100 Subject: [PATCH 06/11] .clang-tidy: set `bugprone-exception-escape.TreatFunctionsWithoutSpecificationAsThrowing` to `OnlyUndefined` --- .clang-tidy | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/.clang-tidy b/.clang-tidy index 3cbfd6df..c9eba89d 100644 --- a/.clang-tidy +++ b/.clang-tidy @@ -55,4 +55,6 @@ CheckOptions: - key: misc-const-correctness.WarnPointersAsValues value: '1' - key: misc-const-correctness.TransformPointersAsValues - value: '1' \ No newline at end of file + value: '1' + - key: bugprone-exception-escape.TreatFunctionsWithoutSpecificationAsThrowing + value: OnlyUndefined \ No newline at end of file From eddfd36080bd4197f9466fa686386c6ad6a604a6 Mon Sep 17 00:00:00 2001 From: firewave Date: Thu, 16 Apr 2026 13:56:33 +0200 Subject: [PATCH 07/11] .clang-tidy: disabled `bugprone-signed-bitwise` for now --- .clang-tidy | 1 + 1 file changed, 1 insertion(+) diff --git a/.clang-tidy b/.clang-tidy index c9eba89d..ae313aa0 100644 --- a/.clang-tidy +++ b/.clang-tidy @@ -21,6 +21,7 @@ Checks: > -bugprone-branch-clone, -bugprone-easily-swappable-parameters, -bugprone-narrowing-conversions, + -bugprone-signed-bitwise, -bugprone-switch-missing-default-case, -bugprone-throwing-static-initialization, -bugprone-unchecked-string-to-number-conversion, From 4353cb3b5f54045915748f532afcea07636313a3 Mon Sep 17 00:00:00 2001 From: firewave Date: Thu, 16 Apr 2026 13:58:49 +0200 Subject: [PATCH 08/11] fixed `readability-redundant-parentheses` clang-tidy warnings --- simplecpp.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/simplecpp.cpp b/simplecpp.cpp index f09a899a..6aff2351 100644 --- a/simplecpp.cpp +++ b/simplecpp.cpp @@ -808,7 +808,7 @@ void simplecpp::TokenList::readfile(Stream &stream, const std::string &filename, if (ch == '\\') { TokenString tmp; char tmp_ch = ch; - while ((stream.good()) && (tmp_ch == '\\' || tmp_ch == ' ' || tmp_ch == '\t')) { + while (stream.good() && (tmp_ch == '\\' || tmp_ch == ' ' || tmp_ch == '\t')) { tmp += tmp_ch; tmp_ch = stream.readChar(); } From de9b0348dc7c348c0913cd3dd5da6378a600c308 Mon Sep 17 00:00:00 2001 From: firewave Date: Thu, 16 Apr 2026 14:02:35 +0200 Subject: [PATCH 09/11] fixed `-Wlifetime-safety-cross-tu-suggestions` Clang warnings --- CMakeLists.txt | 3 ++- simplecpp.cpp | 6 +++--- simplecpp.h | 14 +++++++------- test.cpp | 12 +++++++++++- 4 files changed, 23 insertions(+), 12 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index 59944b4b..eb3f959f 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -75,9 +75,10 @@ elseif (CMAKE_CXX_COMPILER_ID MATCHES "Clang") # TODO: check for proper AppleClang version # we do not add the annotation until C++20 - # the warning was introduced with Clang 23 + # the warnings was introduced with Clang 23 if(CMAKE_CXX_STANDARD LESS 20) add_compile_options_safe(-Wno-lifetime-safety-intra-tu-suggestions) + add_compile_options_safe(-Wno-lifetime-safety-cross-tu-suggestions) endif() # TODO: fix these? diff --git a/simplecpp.cpp b/simplecpp.cpp index 6aff2351..6b57952d 100644 --- a/simplecpp.cpp +++ b/simplecpp.cpp @@ -389,7 +389,7 @@ namespace { class StdCharBufStream : public simplecpp::TokenList::Stream { public: // cppcheck-suppress uninitDerivedMemberVar - we call Stream::init() to initialize the private members - StdCharBufStream(const unsigned char* str, std::size_t size) + StdCharBufStream(const unsigned char* str SIMPLECPP_LIFETIMEBOUND, std::size_t size) : str(str) , size(size) { @@ -1508,12 +1508,12 @@ namespace simplecpp { class Macro { public: - explicit Macro(std::vector &f) : nameTokDef(nullptr), valueToken(nullptr), endToken(nullptr), files(f), tokenListDefine(f), variadic(false), variadicOpt(false), valueDefinedInCode_(false) {} + explicit Macro(std::vector &f SIMPLECPP_LIFETIMEBOUND) : nameTokDef(nullptr), valueToken(nullptr), endToken(nullptr), files(f), tokenListDefine(f), variadic(false), variadicOpt(false), valueDefinedInCode_(false) {} /** * @throws std::runtime_error thrown on bad macro syntax */ - Macro(const Token *tok, std::vector &f) : nameTokDef(nullptr), files(f), tokenListDefine(f), valueDefinedInCode_(true) { + Macro(const Token *tok, std::vector &f SIMPLECPP_LIFETIMEBOUND) : nameTokDef(nullptr), files(f), tokenListDefine(f), valueDefinedInCode_(true) { if (sameline(tok->previousSkipComments(), tok)) throw std::runtime_error("bad macro syntax"); if (tok->op != '#') diff --git a/simplecpp.h b/simplecpp.h index 65335607..0fc44d2c 100644 --- a/simplecpp.h +++ b/simplecpp.h @@ -88,20 +88,20 @@ namespace simplecpp { struct View { // cppcheck-suppress noExplicitConstructor - View(const char* data) + View(const char* data SIMPLECPP_LIFETIMEBOUND) : mData(data) , mSize(strlen(data)) {} // only provide when std::span is not available so using untyped initialization won't use View #if !defined(__cpp_lib_span) - View(const char* data, std::size_t size) + View(const char* data SIMPLECPP_LIFETIMEBOUND, std::size_t size) : mData(data) , mSize(size) {} // cppcheck-suppress noExplicitConstructor - View(const std::string& str) + View(const std::string& str SIMPLECPP_LIFETIMEBOUND) : mData(str.data()) , mSize(str.size()) {} @@ -269,9 +269,9 @@ namespace simplecpp { public: class Stream; - explicit TokenList(std::vector &filenames); + explicit TokenList(std::vector &filenames SIMPLECPP_LIFETIMEBOUND); /** generates a token list from the given std::istream parameter */ - TokenList(std::istream &istr, std::vector &filenames, const std::string &filename=std::string(), OutputList *outputList = nullptr); + TokenList(std::istream &istr, std::vector &filenames SIMPLECPP_LIFETIMEBOUND, const std::string &filename=std::string(), OutputList *outputList = nullptr); /** generates a token list from the given buffer */ template TokenList(const char (&data)[size], std::vector &filenames, const std::string &filename=std::string(), OutputList *outputList = nullptr) @@ -309,7 +309,7 @@ namespace simplecpp { #endif // __cpp_lib_span /** generates a token list from the given filename parameter */ - TokenList(const std::string &filename, std::vector &filenames, OutputList *outputList = nullptr); + TokenList(const std::string &filename, std::vector &filenames SIMPLECPP_LIFETIMEBOUND, OutputList *outputList = nullptr); TokenList(const TokenList &other); TokenList(TokenList &&other); ~TokenList(); @@ -389,7 +389,7 @@ namespace simplecpp { const std::string& file(const Location& loc) const; private: - TokenList(const unsigned char* data, std::size_t size, std::vector &filenames, const std::string &filename, OutputList *outputList, int /*unused*/); + TokenList(const unsigned char* data, std::size_t size, std::vector &filenames SIMPLECPP_LIFETIMEBOUND, const std::string &filename, OutputList *outputList, int /*unused*/); void combineOperators(); diff --git a/test.cpp b/test.cpp index 15d099ef..ef8129e8 100644 --- a/test.cpp +++ b/test.cpp @@ -21,6 +21,16 @@ #error "SIMPLECPP_TEST_SOURCE_DIR is not defined." #endif +#if defined(__has_cpp_attribute) +# if __has_cpp_attribute (clang::lifetimebound) +# define SIMPLECPP_LIFETIMEBOUND [[clang::lifetimebound]] +# else +# define SIMPLECPP_LIFETIMEBOUND +# endif +#else +# define SIMPLECPP_LIFETIMEBOUND +#endif + #define STRINGIZE_(x) #x #define STRINGIZE(x) STRINGIZE_(x) @@ -81,7 +91,7 @@ static void testcase(const std::string &name, void (*const f)(), int argc, char #define TEST_CASE(F) (testcase(#F, F, argc, argv)) -static simplecpp::TokenList makeTokenList(const char code[], std::size_t size, std::vector &filenames, const std::string &filename=std::string(), simplecpp::OutputList * const outputList=nullptr) +static simplecpp::TokenList makeTokenList(const char code[], std::size_t size, std::vector &filenames, const std::string &filename=std::string(), simplecpp::OutputList * const outputList SIMPLECPP_LIFETIMEBOUND = nullptr) { std::istringstream istr(std::string(code, size)); return {istr,filenames,filename,outputList}; From 969e96244a19377698147a7187736f238ae2ad4b Mon Sep 17 00:00:00 2001 From: firewave Date: Thu, 16 Apr 2026 14:03:06 +0200 Subject: [PATCH 10/11] .clang-tidy: disabled `bugprone-std-exception-baseclass` for now --- .clang-tidy | 1 + 1 file changed, 1 insertion(+) diff --git a/.clang-tidy b/.clang-tidy index ae313aa0..76c54ece 100644 --- a/.clang-tidy +++ b/.clang-tidy @@ -22,6 +22,7 @@ Checks: > -bugprone-easily-swappable-parameters, -bugprone-narrowing-conversions, -bugprone-signed-bitwise, + -bugprone-std-exception-baseclass, -bugprone-switch-missing-default-case, -bugprone-throwing-static-initialization, -bugprone-unchecked-string-to-number-conversion, From a96025324e56ba9942ee7329fe11f323c8b1b672 Mon Sep 17 00:00:00 2001 From: firewave Date: Thu, 16 Apr 2026 14:05:18 +0200 Subject: [PATCH 11/11] main.cpp: fixed `misc-include-cleaner` clang-tidy warning --- main.cpp | 1 - 1 file changed, 1 deletion(-) diff --git a/main.cpp b/main.cpp index 5456a6ab..74e9efd1 100644 --- a/main.cpp +++ b/main.cpp @@ -6,7 +6,6 @@ #define SIMPLECPP_TOKENLIST_ALLOW_PTR 0 #include "simplecpp.h" -#include #include #include #include